fix negative exponent handling (numbers<0).
[platform/upstream/glib.git] / glib / gmessages.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GLib Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 /* 
28  * MT safe
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #include <stdlib.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include "glib.h"
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 #include <signal.h>
44 #include <locale.h>
45 #include <errno.h>
46
47 #ifdef G_OS_WIN32
48 typedef FILE* GFileDescriptor;
49 #else
50 typedef gint GFileDescriptor;
51 #endif
52
53 /* --- structures --- */
54 typedef struct _GLogDomain      GLogDomain;
55 typedef struct _GLogHandler     GLogHandler;
56 struct _GLogDomain
57 {
58   gchar         *log_domain;
59   GLogLevelFlags fatal_mask;
60   GLogHandler   *handlers;
61   GLogDomain    *next;
62 };
63 struct _GLogHandler
64 {
65   guint          id;
66   GLogLevelFlags log_level;
67   GLogFunc       log_func;
68   gpointer       data;
69   GLogHandler   *next;
70 };
71
72
73 /* --- prototypes --- */
74 static guint printf_string_upper_bound (const gchar *format,
75                                         gboolean     may_warn,
76                                         va_list      args);
77
78
79 /* --- variables --- */
80
81 static GMutex* g_messages_lock = NULL;
82
83 const gchar          *g_log_domain_glib = "GLib";
84 static GLogDomain    *g_log_domains = NULL;
85 static GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK;
86 static GPrintFunc     glib_print_func = NULL;
87 static GPrintFunc     glib_printerr_func = NULL;
88 static GErrorFunc     glib_error_func = NULL;
89 static GWarningFunc   glib_warning_func = NULL;
90 static GPrintFunc     glib_message_func = NULL;
91
92 static GPrivate* g_log_depth = NULL;
93
94 /* --- functions --- */
95 #ifdef G_OS_WIN32
96 #  define STRICT
97 #  include <windows.h>
98 #  undef STRICT
99 #  include <process.h>          /* For _getpid() */
100
101 static gboolean alloc_console_called = FALSE;
102
103 static gboolean gonna_abort = FALSE;
104
105 /* This default message will usually be overwritten. */
106 /* Yes, a fixed size buffer is bad. So sue me. But g_error is never
107  * with huge strings, is it? */
108 static char fatal_msg_buf[1000] = "Unspecified fatal error encountered, aborting.";
109 static char *fatal_msg_ptr = fatal_msg_buf;
110
111 /* Just use stdio. If we're out of memory, we're hosed anyway. */
112 #undef write
113 static inline int
114 dowrite (GFileDescriptor fd,
115          const void  *buf,
116          unsigned int len)
117 {
118   if (gonna_abort)
119     {
120       memcpy (fatal_msg_ptr, buf, len);
121       fatal_msg_ptr += len;
122       *fatal_msg_ptr = 0;
123       return len;
124     }
125
126   fwrite (buf, len, 1, fd);
127   fflush (fd);
128
129   return len;
130 }
131
132 #define write(fd, buf, len) dowrite(fd, buf, len)
133
134 static void
135 ensure_stdout_valid (void)
136 {
137   HANDLE handle;
138
139   if (gonna_abort)
140     return;
141
142   if (!alloc_console_called)
143     {
144       handle = GetStdHandle (STD_OUTPUT_HANDLE);
145   
146       if (handle == INVALID_HANDLE_VALUE)
147         {
148           AllocConsole ();
149           alloc_console_called = TRUE;
150           freopen ("CONOUT$", "w", stdout);
151         }
152     }
153 }
154 #else
155 #define ensure_stdout_valid()   /* Define as empty */
156 #endif
157
158 static void
159 write_unsigned (GFileDescriptor fd,
160                 gulong          num,
161                 guint           radix)
162 {
163   char buffer[64];
164   gulong tmp;
165   char c;
166   int i, n;
167
168   g_return_if_fail (radix >= 2 && radix <= 36);
169   
170   if (!num)
171     {
172       write (fd, "0", 1);
173       return;
174     } 
175   
176   if (radix == 16)
177     write (fd, "0x", 2);
178   else if (radix == 8)
179     write (fd, "0", 1);
180         
181   n = 0;
182   tmp = num;
183   while (tmp)
184     {
185       tmp /= radix;
186       n++;
187     }
188
189   i = n;
190   while (num)
191     {
192       i--;
193       c = (num % radix);
194       if (c < 10)
195         buffer[i] = c + '0';
196       else
197         buffer[i] = c + 'a' - 10;
198       num /= radix;
199     }
200   
201   write (fd, buffer, n);
202 }
203
204 static void
205 write_string (GFileDescriptor fd,
206               gchar *string)
207 {
208   write (fd, string, strlen (string));
209 }
210
211 static void
212 g_log_write_prefix (GFileDescriptor fd,
213                     GLogLevelFlags mask)
214 {
215   static GLogLevelFlags g_log_msg_prefix = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG;
216   static gboolean initialized = FALSE;
217   
218   g_mutex_lock (g_messages_lock);
219
220   if (!initialized)
221     {
222       const gchar *val;
223       initialized = TRUE;
224
225       val = g_getenv ("G_MESSAGES_PREFIXED");
226       
227       if (val)
228         {
229           static const GDebugKey keys[] = {
230             { "error", G_LOG_LEVEL_ERROR },
231             { "critical", G_LOG_LEVEL_CRITICAL },
232             { "warning", G_LOG_LEVEL_WARNING },
233             { "message", G_LOG_LEVEL_MESSAGE },
234             { "info", G_LOG_LEVEL_INFO },
235             { "debug", G_LOG_LEVEL_DEBUG }
236           };
237           
238           g_log_msg_prefix = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
239         }
240     }
241   
242   g_mutex_unlock (g_messages_lock);
243   
244   if ((g_log_msg_prefix & mask) == mask)
245     {
246       gchar *prg_name;
247
248       prg_name = g_get_prgname ();
249
250       if (!prg_name)
251         write_string (fd, "(process:");
252       else
253         {
254           write_string (fd, prg_name);
255           write_string (fd, " (pid:");
256         }
257
258       write_unsigned (fd, getpid (), 10);
259       write_string (fd, "): ");
260     }
261 }
262
263 static inline GLogDomain*
264 g_log_find_domain (const gchar *log_domain)
265 {
266   register GLogDomain *domain;
267   
268   g_mutex_lock (g_messages_lock);
269   domain = g_log_domains;
270   while (domain)
271     {
272       if (strcmp (domain->log_domain, log_domain) == 0)
273         {
274           g_mutex_unlock (g_messages_lock);
275           return domain;
276         }
277       domain = domain->next;
278     }
279   g_mutex_unlock (g_messages_lock);
280   return NULL;
281 }
282
283 static inline GLogDomain*
284 g_log_domain_new (const gchar *log_domain)
285 {
286   register GLogDomain *domain;
287
288   domain = g_new (GLogDomain, 1);
289   domain->log_domain = g_strdup (log_domain);
290   domain->fatal_mask = G_LOG_FATAL_MASK;
291   domain->handlers = NULL;
292   
293   g_mutex_lock (g_messages_lock);
294   domain->next = g_log_domains;
295   g_log_domains = domain;
296   g_mutex_unlock (g_messages_lock);
297   
298   return domain;
299 }
300
301 static inline void
302 g_log_domain_check_free (GLogDomain *domain)
303 {
304   if (domain->fatal_mask == G_LOG_FATAL_MASK &&
305       domain->handlers == NULL)
306     {
307       register GLogDomain *last, *work;
308       
309       last = NULL;  
310
311       g_mutex_lock (g_messages_lock);
312       work = g_log_domains;
313       while (work)
314         {
315           if (work == domain)
316             {
317               if (last)
318                 last->next = domain->next;
319               else
320                 g_log_domains = domain->next;
321               g_free (domain->log_domain);
322               g_free (domain);
323               break;
324             }
325           last = work;
326           work = last->next;
327         }  
328       g_mutex_unlock (g_messages_lock);
329     }
330 }
331
332 static inline GLogFunc
333 g_log_domain_get_handler (GLogDomain    *domain,
334                           GLogLevelFlags log_level,
335                           gpointer      *data)
336 {
337   if (domain && log_level)
338     {
339       register GLogHandler *handler;
340       
341       handler = domain->handlers;
342       while (handler)
343         {
344           if ((handler->log_level & log_level) == log_level)
345             {
346               *data = handler->data;
347               return handler->log_func;
348             }
349           handler = handler->next;
350         }
351     }
352   return g_log_default_handler;
353 }
354
355 GLogLevelFlags
356 g_log_set_always_fatal (GLogLevelFlags fatal_mask)
357 {
358   GLogLevelFlags old_mask;
359
360   /* restrict the global mask to levels that are known to glib */
361   fatal_mask &= (1 << G_LOG_LEVEL_USER_SHIFT) - 1;
362   /* force errors to be fatal */
363   fatal_mask |= G_LOG_LEVEL_ERROR;
364   /* remove bogus flag */
365   fatal_mask &= ~G_LOG_FLAG_FATAL;
366
367   g_mutex_lock (g_messages_lock);
368   old_mask = g_log_always_fatal;
369   g_log_always_fatal = fatal_mask;
370   g_mutex_unlock (g_messages_lock);
371
372   return old_mask;
373 }
374
375 GLogLevelFlags
376 g_log_set_fatal_mask (const gchar    *log_domain,
377                       GLogLevelFlags  fatal_mask)
378 {
379   GLogLevelFlags old_flags;
380   register GLogDomain *domain;
381   
382   if (!log_domain)
383     log_domain = "";
384   
385   /* force errors to be fatal */
386   fatal_mask |= G_LOG_LEVEL_ERROR;
387   /* remove bogus flag */
388   fatal_mask &= ~G_LOG_FLAG_FATAL;
389   
390   domain = g_log_find_domain (log_domain);
391   if (!domain)
392     domain = g_log_domain_new (log_domain);
393   old_flags = domain->fatal_mask;
394   
395   domain->fatal_mask = fatal_mask;
396   g_log_domain_check_free (domain);
397   
398   return old_flags;
399 }
400
401 guint
402 g_log_set_handler (const gchar    *log_domain,
403                    GLogLevelFlags  log_levels,
404                    GLogFunc        log_func,
405                    gpointer        user_data)
406 {
407   register GLogDomain *domain;
408   register GLogHandler *handler;
409   static guint handler_id = 0;
410   
411   g_return_val_if_fail ((log_levels & G_LOG_LEVEL_MASK) != 0, 0);
412   g_return_val_if_fail (log_func != NULL, 0);
413   
414   if (!log_domain)
415     log_domain = "";
416   
417   domain = g_log_find_domain (log_domain);
418   if (!domain)
419     domain = g_log_domain_new (log_domain);
420   
421   handler = g_new (GLogHandler, 1);
422   g_mutex_lock (g_messages_lock);
423   handler->id = ++handler_id;
424   g_mutex_unlock (g_messages_lock);
425   handler->log_level = log_levels;
426   handler->log_func = log_func;
427   handler->data = user_data;
428   handler->next = domain->handlers;
429   domain->handlers = handler;
430   
431   return handler_id;
432 }
433
434 void
435 g_log_remove_handler (const gchar *log_domain,
436                       guint        handler_id)
437 {
438   register GLogDomain *domain;
439   
440   g_return_if_fail (handler_id > 0);
441   
442   if (!log_domain)
443     log_domain = "";
444   
445   domain = g_log_find_domain (log_domain);
446   if (domain)
447     {
448       register GLogHandler *work, *last;
449       
450       last = NULL;
451       work = domain->handlers;
452       while (work)
453         {
454           if (work->id == handler_id)
455             {
456               if (last)
457                 last->next = work->next;
458               else
459                 domain->handlers = work->next;
460               g_free (work);
461               g_log_domain_check_free (domain);
462               return;
463             }
464           last = work;
465           work = last->next;
466         }
467     }
468   g_warning ("g_log_remove_handler(): could not find handler with id `%d' for domain \"%s\"",
469              handler_id,
470              log_domain);
471 }
472
473 void
474 g_logv (const gchar   *log_domain,
475         GLogLevelFlags log_level,
476         const gchar   *format,
477         va_list        args1)
478 {
479   va_list args2;
480   gchar buffer[1025];
481   register gint i;
482   
483   log_level &= G_LOG_LEVEL_MASK;
484   if (!log_level)
485     return;
486   
487   /* we use a stack buffer of fixed size, because we might get called
488    * recursively.
489    */
490   G_VA_COPY (args2, args1);
491   if (printf_string_upper_bound (format, FALSE, args1) < 1024)
492     vsprintf (buffer, format, args2);
493   else
494     {
495       /* since we might be out of memory, we can't use g_vsnprintf(). */
496 #ifdef  HAVE_VSNPRINTF
497       vsnprintf (buffer, 1024, format, args2);
498 #else   /* !HAVE_VSNPRINTF */
499       /* we are out of luck here */
500       strncpy (buffer, format, 1024);
501 #endif  /* !HAVE_VSNPRINTF */
502       buffer[1024] = 0;
503     }
504   va_end (args2);
505   
506   for (i = g_bit_nth_msf (log_level, -1); i >= 0; i = g_bit_nth_msf (log_level, i))
507     {
508       register GLogLevelFlags test_level;
509       
510       test_level = 1 << i;
511       if (log_level & test_level)
512         {
513           guint depth = GPOINTER_TO_UINT (g_private_get (g_log_depth));
514           GLogDomain *domain;
515           GLogFunc log_func;
516           gpointer data = NULL;
517           
518           domain = g_log_find_domain (log_domain ? log_domain : "");
519           
520           if (depth)
521             test_level |= G_LOG_FLAG_RECURSION;
522           
523           depth++;
524           g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
525
526           g_mutex_lock (g_messages_lock);
527           if ((((domain ? domain->fatal_mask : G_LOG_FATAL_MASK) | 
528                 g_log_always_fatal) & test_level) != 0)
529             test_level |= G_LOG_FLAG_FATAL;  
530           g_mutex_unlock (g_messages_lock);
531
532           log_func = g_log_domain_get_handler (domain, test_level, &data);
533           log_func (log_domain, test_level, buffer, data);
534           
535           /* *domain can be cluttered now */
536           
537           if (test_level & G_LOG_FLAG_FATAL)
538             {
539 #if defined (G_ENABLE_DEBUG) && defined (SIGTRAP)
540               if (!(test_level & G_LOG_FLAG_RECURSION))
541                 G_BREAKPOINT ();
542               else
543                 abort ();
544 #else /* !G_ENABLE_DEBUG || !SIGTRAP */
545 #ifdef G_OS_WIN32
546               MessageBox (NULL, fatal_msg_buf, NULL, MB_OK);
547 #endif
548 # if defined (_MSC_VER) && defined (_DEBUG)
549               /* let's see the call stack ... */
550               __asm int 3
551 # endif
552               abort ();
553 #endif /* !G_ENABLE_DEBUG || !SIGTRAP */
554             }
555           
556           depth--;
557           g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
558         }
559     }
560 }
561
562 void
563 g_log (const gchar    *log_domain,
564        GLogLevelFlags  log_level,
565        const gchar    *format,
566        ...)
567 {
568   va_list args;
569   
570   va_start (args, format);
571   g_logv (log_domain, log_level, format, args);
572   va_end (args);
573 }
574
575 void
576 g_log_default_handler (const gchar    *log_domain,
577                        GLogLevelFlags  log_level,
578                        const gchar    *message,
579                        gpointer        unused_data)
580 {
581   GFileDescriptor fd;
582   gboolean in_recursion;
583   gboolean is_fatal;  
584   GErrorFunc local_glib_error_func;
585   GWarningFunc local_glib_warning_func;
586   GPrintFunc local_glib_message_func;
587   
588   in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
589   is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
590   log_level &= G_LOG_LEVEL_MASK;
591   
592   if (!message)
593     message = "g_log_default_handler(): (NULL) message";
594   
595 #ifdef G_OS_WIN32
596   /* Use just stdout as stderr is hard to get redirected from the
597    * DOS prompt.
598    */
599   fd = stdout;
600   gonna_abort = is_fatal;
601 #else
602   fd = (log_level > G_LOG_LEVEL_MESSAGE) ? 1 : 2;
603 #endif
604   
605   g_mutex_lock (g_messages_lock);
606   local_glib_error_func = glib_error_func;
607   local_glib_warning_func = glib_warning_func;
608   local_glib_message_func = glib_message_func;
609   g_mutex_unlock (g_messages_lock);
610
611   switch (log_level)
612     {
613     case G_LOG_LEVEL_ERROR:
614       if (!log_domain && local_glib_error_func)
615         {
616           /* compatibility code */
617           local_glib_error_func (message);  
618           return;
619         }
620       /* use write(2) for output, in case we are out of memeory */
621       ensure_stdout_valid ();
622       write (fd, "\n", 1);
623       g_log_write_prefix (fd, log_level);
624
625       if (log_domain)
626         {
627           write (fd, log_domain, strlen (log_domain));
628           write (fd, "-", 1);
629         }
630       else
631         write (fd, "** ", 3);
632       if (in_recursion)
633         write (fd, "ERROR (recursed) **: ", 21);
634       else
635         write (fd, "ERROR **: ", 10);
636       write (fd, message, strlen (message));
637       if (is_fatal)
638         write (fd, "\naborting...\n", 13);
639       else
640         write (fd, "\n", 1);
641       break;
642     case G_LOG_LEVEL_CRITICAL:
643       ensure_stdout_valid ();
644       write (fd, "\n", 1);
645       g_log_write_prefix (fd, log_level);
646
647       if (log_domain)
648         {
649           write (fd, log_domain, strlen (log_domain));
650           write (fd, "-", 1);
651         }
652       else
653         write (fd, "** ", 3);
654       if (in_recursion)
655         write (fd, "CRITICAL (recursed) **: ", 24);
656       else
657         write (fd, "CRITICAL **: ", 13);
658       write (fd, message, strlen (message));
659       if (is_fatal)
660         write (fd, "\naborting...\n", 13);
661       else
662         write (fd, "\n", 1);
663       break;
664     case G_LOG_LEVEL_WARNING:
665       if (!log_domain && local_glib_warning_func)
666         {
667           /* compatibility code */
668           local_glib_warning_func (message);
669           return;
670         }
671       ensure_stdout_valid ();
672       write (fd, "\n", 1);
673       g_log_write_prefix (fd, log_level);
674
675       if (log_domain)
676         {
677           write (fd, log_domain, strlen (log_domain));
678           write (fd, "-", 1);
679         }
680       else
681         write (fd, "** ", 3);
682       if (in_recursion)
683         write (fd, "WARNING (recursed) **: ", 23);
684       else
685         write (fd, "WARNING **: ", 12);
686       write (fd, message, strlen (message));
687       if (is_fatal)
688         write (fd, "\naborting...\n", 13);
689       else
690         write (fd, "\n", 1);
691       break;
692     case G_LOG_LEVEL_MESSAGE:
693       if (!log_domain && local_glib_message_func)
694         {
695           /* compatibility code */
696           local_glib_message_func (message);
697           return;
698         }
699       ensure_stdout_valid ();
700
701       g_log_write_prefix (fd, log_level);
702
703       if (log_domain)
704         {
705           write (fd, log_domain, strlen (log_domain));
706           write (fd, "-", 1);
707         }
708       if (in_recursion)
709         write (fd, "Message (recursed): ", 20);
710       else
711         write (fd, "Message: ", 9);
712       write (fd, message, strlen (message));
713       if (is_fatal)
714         write (fd, "\naborting...\n", 13);
715       else
716         write (fd, "\n", 1);
717       break;
718     case G_LOG_LEVEL_INFO:
719       ensure_stdout_valid ();
720
721       g_log_write_prefix (fd, log_level);
722
723       if (log_domain)
724         {
725           write (fd, log_domain, strlen (log_domain));
726           write (fd, "-", 1);
727         }
728       if (in_recursion)
729         write (fd, "INFO (recursed): ", 17);
730       else
731         write (fd, "INFO: ", 6);
732       write (fd, message, strlen (message));
733       if (is_fatal)
734         write (fd, "\naborting...\n", 13);
735       else
736         write (fd, "\n", 1);
737       break;
738     case G_LOG_LEVEL_DEBUG:
739       ensure_stdout_valid ();
740
741       g_log_write_prefix (fd, log_level);
742
743       if (log_domain)
744         {
745           write (fd, log_domain, strlen (log_domain));
746           write (fd, "-", 1);
747         }
748       if (in_recursion)
749         write (fd, "DEBUG (recursed): ", 18);
750       else
751         write (fd, "DEBUG: ", 7);
752       write (fd, message, strlen (message));
753       if (is_fatal)
754         write (fd, "\naborting...\n", 13);
755       else
756         write (fd, "\n", 1);
757       break;
758     default:
759       /* we are used for a log level that is not defined by GLib itself,
760        * try to make the best out of it.
761        */
762       ensure_stdout_valid ();
763
764       g_log_write_prefix (fd, log_level);
765
766       if (log_domain)
767         {
768           write (fd, log_domain, strlen (log_domain));
769           if (in_recursion)
770             write (fd, "-LOG (recursed:", 15);
771           else
772             write (fd, "-LOG (", 6);
773         }
774       else if (in_recursion)
775         write (fd, "LOG (recursed:", 14);
776       else
777         write (fd, "LOG (", 5);
778       if (log_level)
779         {
780           gchar string[] = "0x00): ";
781           gchar *p = string + 2;
782           guint i;
783           
784           i = g_bit_nth_msf (log_level, -1);
785           *p = i >> 4;
786           p++;
787           *p = '0' + (i & 0xf);
788           if (*p > '9')
789             *p += 'A' - '9' - 1;
790           
791           write (fd, string, 7);
792         }
793       else
794         write (fd, "): ", 3);
795       write (fd, message, strlen (message));
796       if (is_fatal)
797         write (fd, "\naborting...\n", 13);
798       else
799         write (fd, "\n", 1);
800       break;
801     }
802 }
803
804 GPrintFunc
805 g_set_print_handler (GPrintFunc func)
806 {
807   GPrintFunc old_print_func;
808   
809   g_mutex_lock (g_messages_lock);
810   old_print_func = glib_print_func;
811   glib_print_func = func;
812   g_mutex_unlock (g_messages_lock);
813   
814   return old_print_func;
815 }
816
817 void
818 g_print (const gchar *format,
819          ...)
820 {
821   va_list args;
822   gchar *string;
823   GPrintFunc local_glib_print_func;
824   
825   g_return_if_fail (format != NULL);
826   
827   va_start (args, format);
828   string = g_strdup_vprintf (format, args);
829   va_end (args);
830   
831   g_mutex_lock (g_messages_lock);
832   local_glib_print_func = glib_print_func;
833   g_mutex_unlock (g_messages_lock);
834
835   if (local_glib_print_func)
836     local_glib_print_func (string);
837   else
838     {
839       ensure_stdout_valid ();
840       fputs (string, stdout);
841       fflush (stdout);
842     }
843   g_free (string);
844 }
845
846 GPrintFunc
847 g_set_printerr_handler (GPrintFunc func)
848 {
849   GPrintFunc old_printerr_func;
850   
851   g_mutex_lock (g_messages_lock);
852   old_printerr_func = glib_printerr_func;
853   glib_printerr_func = func;
854   g_mutex_unlock (g_messages_lock);
855   
856   return old_printerr_func;
857 }
858
859 void
860 g_printerr (const gchar *format,
861             ...)
862 {
863   va_list args;
864   gchar *string;
865   GPrintFunc local_glib_printerr_func;
866   
867   g_return_if_fail (format != NULL);
868   
869   va_start (args, format);
870   string = g_strdup_vprintf (format, args);
871   va_end (args);
872   
873   g_mutex_lock (g_messages_lock);
874   local_glib_printerr_func = glib_printerr_func;
875   g_mutex_unlock (g_messages_lock);
876
877   if (local_glib_printerr_func)
878     local_glib_printerr_func (string);
879   else
880     {
881       fputs (string, stderr);
882       fflush (stderr);
883     }
884   g_free (string);
885 }
886
887 /* compatibility code */
888 GErrorFunc
889 g_set_error_handler (GErrorFunc func)
890 {
891   GErrorFunc old_error_func;
892   
893   g_mutex_lock (g_messages_lock);
894   old_error_func = glib_error_func;
895   glib_error_func = func;
896   g_mutex_unlock (g_messages_lock);
897  
898   return old_error_func;
899 }
900
901 /* compatibility code */
902 GWarningFunc
903 g_set_warning_handler (GWarningFunc func)
904 {
905   GWarningFunc old_warning_func;
906   
907   g_mutex_lock (g_messages_lock);
908   old_warning_func = glib_warning_func;
909   glib_warning_func = func;
910   g_mutex_unlock (g_messages_lock);
911   
912   return old_warning_func;
913 }
914
915 /* compatibility code */
916 GPrintFunc
917 g_set_message_handler (GPrintFunc func)
918 {
919   GPrintFunc old_message_func;
920   
921   g_mutex_lock (g_messages_lock);
922   old_message_func = glib_message_func;
923   glib_message_func = func;
924   g_mutex_unlock (g_messages_lock);
925   
926   return old_message_func;
927 }
928
929 #ifndef MB_LEN_MAX
930 #  define MB_LEN_MAX 8
931 #endif
932
933 typedef struct
934 {
935   guint min_width;
936   guint precision;
937   gboolean alternate_format, zero_padding, adjust_left, locale_grouping;
938   gboolean add_space, add_sign, possible_sign, seen_precision;
939   gboolean mod_half, mod_long, mod_extra_long;
940 } PrintfArgSpec;
941
942 static gsize
943 printf_string_upper_bound (const gchar *format,
944                            gboolean     may_warn,
945                            va_list      args)
946 {
947   static const gboolean honour_longs = SIZEOF_LONG > 4 || SIZEOF_VOID_P > 4;
948   gsize len = 1;
949
950   if (!format)
951     return len;
952
953   while (*format)
954     {
955       register gchar c = *format++;
956
957       if (c != '%')
958         len += 1;
959       else /* (c == '%') */
960         {
961           PrintfArgSpec spec = { 0, };
962           gboolean seen_l = FALSE, conv_done = FALSE;
963           gsize conv_len = 0;
964           const gchar *spec_start = format;
965
966           do
967             {
968               c = *format++;
969               switch (c)
970                 {
971                   GDoubleIEEE754 u_double;
972                   guint v_uint;
973                   gint v_int;
974                   const gchar *v_string;
975
976                   /* beware of positional parameters
977                    */
978                 case '$':
979                   if (may_warn)
980                     g_warning (G_GNUC_PRETTY_FUNCTION
981                                "(): unable to handle positional parameters (%%n$)");
982                   len += 1024; /* try adding some safety padding */
983                   break;
984
985                   /* parse flags
986                    */
987                 case '#':
988                   spec.alternate_format = TRUE;
989                   break;
990                 case '0':
991                   spec.zero_padding = TRUE;
992                   break;
993                 case '-':
994                   spec.adjust_left = TRUE;
995                   break;
996                 case ' ':
997                   spec.add_space = TRUE;
998                   break;
999                 case '+':
1000                   spec.add_sign = TRUE;
1001                   break;
1002                 case '\'':
1003                   spec.locale_grouping = TRUE;
1004                   break;
1005
1006                   /* parse output size specifications
1007                    */
1008                 case '.':
1009                   spec.seen_precision = TRUE;
1010                   break;
1011                 case '1':
1012                 case '2':
1013                 case '3':
1014                 case '4':
1015                 case '5':
1016                 case '6':
1017                 case '7':
1018                 case '8':
1019                 case '9':
1020                   v_uint = c - '0';
1021                   c = *format;
1022                   while (c >= '0' && c <= '9')
1023                     {
1024                       format++;
1025                       v_uint = v_uint * 10 + c - '0';
1026                       c = *format;
1027                     }
1028                   if (spec.seen_precision)
1029                     spec.precision = MAX (spec.precision, v_uint);
1030                   else
1031                     spec.min_width = MAX (spec.min_width, v_uint);
1032                   break;
1033                 case '*':
1034                   v_int = va_arg (args, int);
1035                   if (spec.seen_precision)
1036                     {
1037                       /* forget about negative precision */
1038                       if (v_int >= 0)
1039                         spec.precision = MAX (spec.precision, v_int);
1040                     }
1041                   else
1042                     {
1043                       if (v_int < 0)
1044                         {
1045                           v_int = - v_int;
1046                           spec.adjust_left = TRUE;
1047                         }
1048                       spec.min_width = MAX (spec.min_width, v_int);
1049                     }
1050                   break;
1051
1052                   /* parse type modifiers
1053                    */
1054                 case 'h':
1055                   spec.mod_half = TRUE;
1056                   break;
1057                 case 'l':
1058                   if (!seen_l)
1059                     {
1060                       spec.mod_long = TRUE;
1061                       seen_l = TRUE;
1062                       break;
1063                     }
1064                   /* else, fall through */
1065                 case 'L':
1066                 case 'q':
1067                   spec.mod_long = TRUE;
1068                   spec.mod_extra_long = TRUE;
1069                   break;
1070                 case 'z':
1071                 case 'Z':
1072 #if GLIB_SIZEOF_SIZE_T > 4
1073                   spec.mod_long = TRUE;
1074                   spec.mod_extra_long = TRUE;
1075 #endif /* GLIB_SIZEOF_SIZE_T > 4 */
1076                   break;
1077                 case 't':
1078 #if GLIB_SIZEOF_PTRDIFF_T > 4
1079                   spec.mod_long = TRUE;
1080                   spec.mod_extra_long = TRUE;
1081 #endif /* GLIB_SIZEOF_PTRDIFF_T > 4 */
1082                   break;
1083                 case 'j':
1084 #if GLIB_SIZEOF_INTMAX_T > 4
1085                   spec.mod_long = TRUE;
1086                   spec.mod_extra_long = TRUE;
1087 #endif /* GLIB_SIZEOF_INTMAX_T > 4 */
1088                   break;
1089
1090                   /* parse output conversions
1091                    */
1092                 case '%':
1093                   conv_len += 1;
1094                   break;
1095                 case 'O':
1096                 case 'D':
1097                 case 'I':
1098                 case 'U':
1099                   /* some C libraries feature long variants for these as well? */
1100                   spec.mod_long = TRUE;
1101                   /* fall through */
1102                 case 'o':
1103                   conv_len += 2;
1104                   /* fall through */
1105                 case 'd':
1106                 case 'i':
1107                   conv_len += 1; /* sign */
1108                   /* fall through */
1109                 case 'u':
1110                   conv_len += 4;
1111                   /* fall through */
1112                 case 'x':
1113                 case 'X':
1114                   spec.possible_sign = TRUE;
1115                   conv_len += 10;
1116                   if (spec.mod_long && honour_longs)
1117                     conv_len *= 2;
1118                   if (spec.mod_extra_long)
1119                     conv_len *= 2;
1120                   if (spec.mod_extra_long)
1121                     {
1122 #ifdef G_HAVE_GINT64
1123                       (void) va_arg (args, gint64);
1124 #else /* !G_HAVE_GINT64 */
1125                       (void) va_arg (args, long);
1126 #endif /* !G_HAVE_GINT64 */
1127                     }
1128                   else if (spec.mod_long)
1129                     (void) va_arg (args, long);
1130                   else
1131                     (void) va_arg (args, int);
1132                   break;
1133                 case 'A':
1134                 case 'a':
1135                   /*          0x */
1136                   conv_len += 2;
1137                   /* fall through */
1138                 case 'g':
1139                 case 'G':
1140                 case 'e':
1141                 case 'E':
1142                 case 'f':
1143                   spec.possible_sign = TRUE;
1144                   /*          n   .   dddddddddddddddddddddddd   E   +-  eeee */
1145                   conv_len += 1 + 1 + MAX (24, spec.precision) + 1 + 1 + 4;
1146                   if (may_warn && spec.mod_extra_long)
1147                     g_warning (G_GNUC_PRETTY_FUNCTION
1148                                "(): unable to handle long double, collecting double only");
1149 #ifdef HAVE_LONG_DOUBLE
1150 #error need to implement special handling for long double
1151 #endif
1152                   u_double.v_double = va_arg (args, double);
1153                   /* %f can expand up to all significant digits before '.' (308) */
1154                   if (c == 'f' &&
1155                       u_double.mpn.biased_exponent > 0 && u_double.mpn.biased_exponent < 2047)
1156                     {
1157                       gint exp = u_double.mpn.biased_exponent;
1158
1159                       exp -= G_IEEE754_DOUBLE_BIAS;
1160                       exp = exp * G_LOG_2_BASE_10 + 1;
1161                       conv_len += ABS (exp);    /* exp can be <0 */
1162                     }
1163                   /* some printf() implementations require extra padding for rounding */
1164                   conv_len += 2;
1165                   /* we can't really handle locale specific grouping here */
1166                   if (spec.locale_grouping)
1167                     conv_len *= 2;
1168                   break;
1169                 case 'C':
1170                   spec.mod_long = TRUE;
1171                   /* fall through */
1172                 case 'c':
1173                   conv_len += spec.mod_long ? MB_LEN_MAX : 1;
1174                   (void) va_arg (args, int);
1175                   break;
1176                 case 'S':
1177                   spec.mod_long = TRUE;
1178                   /* fall through */
1179                 case 's':
1180                   v_string = va_arg (args, char*);
1181                   if (!v_string)
1182                     conv_len += 8; /* hold "(null)" */
1183                   else if (spec.seen_precision)
1184                     conv_len += spec.precision;
1185                   else
1186                     conv_len += strlen (v_string);
1187                   conv_done = TRUE;
1188                   if (spec.mod_long)
1189                     {
1190                       if (may_warn)
1191                         g_warning (G_GNUC_PRETTY_FUNCTION
1192                                    "(): unable to handle wide char strings");
1193                       len += 1024; /* try adding some safety padding */
1194                     }
1195                   break;
1196                 case 'P': /* do we actually need this? */
1197                   /* fall through */
1198                 case 'p':
1199                   spec.alternate_format = TRUE;
1200                   conv_len += 10;
1201                   if (honour_longs)
1202                     conv_len *= 2;
1203                   /* fall through */
1204                 case 'n':
1205                   conv_done = TRUE;
1206                   (void) va_arg (args, void*);
1207                   break;
1208                 case 'm':
1209                   /* there's not much we can do to be clever */
1210                   v_string = g_strerror (errno);
1211                   v_uint = v_string ? strlen (v_string) : 0;
1212                   conv_len += MAX (256, v_uint);
1213                   break;
1214
1215                   /* handle invalid cases
1216                    */
1217                 case '\000':
1218                   /* no conversion specification, bad bad */
1219                   conv_len += format - spec_start;
1220                   break;
1221                 default:
1222                   if (may_warn)
1223                     g_warning (G_GNUC_PRETTY_FUNCTION
1224                                "(): unable to handle `%c' while parsing format",
1225                                c);
1226                   break;
1227                 }
1228               conv_done |= conv_len > 0;
1229             }
1230           while (!conv_done);
1231           /* handle width specifications */
1232           conv_len = MAX (conv_len, MAX (spec.precision, spec.min_width));
1233           /* handle flags */
1234           conv_len += spec.alternate_format ? 2 : 0;
1235           conv_len += (spec.add_space || spec.add_sign || spec.possible_sign);
1236           /* finally done */
1237           len += conv_len;
1238         } /* else (c == '%') */
1239     } /* while (*format) */
1240
1241   return len;
1242 }
1243
1244 gsize
1245 g_printf_string_upper_bound (const gchar *format,
1246                              va_list      args)
1247 {
1248   return printf_string_upper_bound (format, TRUE, args);
1249 }
1250
1251 void
1252 g_messages_init (void)
1253 {
1254   g_messages_lock = g_mutex_new();
1255   g_log_depth = g_private_new(NULL);
1256 }