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