Fixed threading issues brought up by #74577. Make g_log_find_domain,
[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 /* HOLDS g_messages_lock */
265 static inline GLogDomain*
266 g_log_find_domain (const gchar *log_domain)
267 {
268   register GLogDomain *domain;
269   
270   domain = g_log_domains;
271   while (domain)
272     {
273       if (strcmp (domain->log_domain, log_domain) == 0)
274         return domain;
275       domain = domain->next;
276     }
277   return NULL;
278 }
279
280 /* HOLDS g_messages_lock */
281 static inline GLogDomain*
282 g_log_domain_new (const gchar *log_domain)
283 {
284   register GLogDomain *domain;
285
286   domain = g_new (GLogDomain, 1);
287   domain->log_domain = g_strdup (log_domain);
288   domain->fatal_mask = G_LOG_FATAL_MASK;
289   domain->handlers = NULL;
290   
291   domain->next = g_log_domains;
292   g_log_domains = domain;
293   
294   return domain;
295 }
296
297 /* HOLDS g_messages_lock */
298 static inline void
299 g_log_domain_check_free (GLogDomain *domain)
300 {
301   if (domain->fatal_mask == G_LOG_FATAL_MASK &&
302       domain->handlers == NULL)
303     {
304       register GLogDomain *last, *work;
305       
306       last = NULL;  
307
308       work = g_log_domains;
309       while (work)
310         {
311           if (work == domain)
312             {
313               if (last)
314                 last->next = domain->next;
315               else
316                 g_log_domains = domain->next;
317               g_free (domain->log_domain);
318               g_free (domain);
319               break;
320             }
321           last = work;
322           work = last->next;
323         }  
324     }
325 }
326
327 /* HOLDS g_messages_lock */
328 static inline GLogFunc
329 g_log_domain_get_handler (GLogDomain    *domain,
330                           GLogLevelFlags log_level,
331                           gpointer      *data)
332 {
333   if (domain && log_level)
334     {
335       register GLogHandler *handler;
336       
337       handler = domain->handlers;
338       while (handler)
339         {
340           if ((handler->log_level & log_level) == log_level)
341             {
342               *data = handler->data;
343               return handler->log_func;
344             }
345           handler = handler->next;
346         }
347     }
348   return g_log_default_handler;
349 }
350
351 GLogLevelFlags
352 g_log_set_always_fatal (GLogLevelFlags fatal_mask)
353 {
354   GLogLevelFlags old_mask;
355
356   /* restrict the global mask to levels that are known to glib */
357   fatal_mask &= (1 << G_LOG_LEVEL_USER_SHIFT) - 1;
358   /* force errors to be fatal */
359   fatal_mask |= G_LOG_LEVEL_ERROR;
360   /* remove bogus flag */
361   fatal_mask &= ~G_LOG_FLAG_FATAL;
362
363   g_mutex_lock (g_messages_lock);
364   old_mask = g_log_always_fatal;
365   g_log_always_fatal = fatal_mask;
366   g_mutex_unlock (g_messages_lock);
367
368   return old_mask;
369 }
370
371 GLogLevelFlags
372 g_log_set_fatal_mask (const gchar    *log_domain,
373                       GLogLevelFlags  fatal_mask)
374 {
375   GLogLevelFlags old_flags;
376   register GLogDomain *domain;
377   
378   if (!log_domain)
379     log_domain = "";
380   
381   /* force errors to be fatal */
382   fatal_mask |= G_LOG_LEVEL_ERROR;
383   /* remove bogus flag */
384   fatal_mask &= ~G_LOG_FLAG_FATAL;
385   
386   g_mutex_lock (g_messages_lock);
387
388   domain = g_log_find_domain (log_domain);
389   if (!domain)
390     domain = g_log_domain_new (log_domain);
391   old_flags = domain->fatal_mask;
392   
393   domain->fatal_mask = fatal_mask;
394   g_log_domain_check_free (domain);
395
396   g_mutex_unlock (g_messages_lock);
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   g_mutex_lock (g_messages_lock);
418
419   domain = g_log_find_domain (log_domain);
420   if (!domain)
421     domain = g_log_domain_new (log_domain);
422   
423   handler = g_new (GLogHandler, 1);
424   handler->id = ++handler_id;
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   g_mutex_unlock (g_messages_lock);
432   
433   return handler_id;
434 }
435
436 void
437 g_log_remove_handler (const gchar *log_domain,
438                       guint        handler_id)
439 {
440   register GLogDomain *domain;
441   
442   g_return_if_fail (handler_id > 0);
443   
444   if (!log_domain)
445     log_domain = "";
446   
447   g_mutex_lock (g_messages_lock);
448
449   domain = g_log_find_domain (log_domain);
450   if (domain)
451     {
452       register GLogHandler *work, *last;
453       
454       last = NULL;
455       work = domain->handlers;
456       while (work)
457         {
458           if (work->id == handler_id)
459             {
460               if (last)
461                 last->next = work->next;
462               else
463                 domain->handlers = work->next;
464               g_free (work);
465               g_log_domain_check_free (domain); 
466
467               g_mutex_unlock (g_messages_lock);
468               return;
469             }
470           last = work;
471           work = last->next;
472         }
473     } 
474   
475   g_mutex_unlock (g_messages_lock);
476   g_warning ("g_log_remove_handler(): could not find handler with id `%d' for domain \"%s\"",
477              handler_id,
478              log_domain);
479 }
480
481 void
482 g_logv (const gchar   *log_domain,
483         GLogLevelFlags log_level,
484         const gchar   *format,
485         va_list        args1)
486 {
487   gchar buffer[1025];
488   register gint i;
489
490 #ifndef  HAVE_VSNPRINTF
491   va_list args2;
492 #endif  /* HAVE_VSNPRINTF */
493   
494   log_level &= G_LOG_LEVEL_MASK;
495   if (!log_level)
496     return;
497   
498   /* we use a stack buffer of fixed size, because we might get called
499    * recursively.
500    */
501 #ifdef  HAVE_VSNPRINTF
502   vsnprintf (buffer, 1024, format, args1);
503 #else   /* !HAVE_VSNPRINTF */
504   G_VA_COPY (args2, args1);
505   if (printf_string_upper_bound (format, FALSE, args1) < 1024)
506     vsprintf (buffer, format, args2);
507   else
508     {
509       /* since we might be out of memory, we can't use g_vsnprintf(). */
510       /* we are out of luck here */
511       strncpy (buffer, format, 1024);
512       buffer[1024] = 0;
513     }
514   va_end (args2);
515 #endif  /* !HAVE_VSNPRINTF */
516   
517   if (!_g_debug_initialized) 
518     _g_debug_init ();
519
520   for (i = g_bit_nth_msf (log_level, -1); i >= 0; i = g_bit_nth_msf (log_level, i))
521     {
522       register GLogLevelFlags test_level;
523       
524       test_level = 1 << i;
525       if (log_level & test_level)
526         {
527           guint depth = GPOINTER_TO_UINT (g_private_get (g_log_depth));
528           GLogDomain *domain;
529           GLogFunc log_func;
530           gpointer data = NULL;
531           
532           g_mutex_lock (g_messages_lock);
533
534           domain = g_log_find_domain (log_domain ? log_domain : "");
535           
536           if (depth)
537             test_level |= G_LOG_FLAG_RECURSION;
538           
539           depth++;
540           g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
541           
542           if ((((domain ? domain->fatal_mask : G_LOG_FATAL_MASK) | 
543                 g_log_always_fatal) & test_level) != 0)
544             test_level |= G_LOG_FLAG_FATAL;  
545
546           log_func = g_log_domain_get_handler (domain, test_level, &data);
547           g_mutex_unlock (g_messages_lock);
548
549           log_func (log_domain, test_level, buffer, data);
550           
551           /* *domain can be cluttered now */
552           
553           if (test_level & G_LOG_FLAG_FATAL)
554             {
555 #ifdef G_OS_WIN32
556               MessageBox (NULL, fatal_msg_buf, NULL, MB_OK);
557 #endif
558 #if defined (G_ENABLE_DEBUG) && (defined (SIGTRAP) || defined (G_OS_WIN32))
559               if (!(test_level & G_LOG_FLAG_RECURSION))
560                 G_BREAKPOINT ();
561               else
562                 abort ();
563 #else /* !G_ENABLE_DEBUG || !(SIGTRAP || G_OS_WIN32) */
564               abort ();
565 #endif /* !G_ENABLE_DEBUG || !(SIGTRAP || G_OS_WIN32) */
566             }
567           
568           depth--;
569           g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
570         }
571     }
572 }
573
574 void
575 g_log (const gchar    *log_domain,
576        GLogLevelFlags  log_level,
577        const gchar    *format,
578        ...)
579 {
580   va_list args;
581   
582   va_start (args, format);
583   g_logv (log_domain, log_level, format, args);
584   va_end (args);
585 }
586
587 void
588 g_log_default_handler (const gchar    *log_domain,
589                        GLogLevelFlags  log_level,
590                        const gchar    *message,
591                        gpointer        unused_data)
592 {
593   GFileDescriptor fd;
594   gboolean in_recursion;
595   gboolean is_fatal;  
596   
597   in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
598   is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
599   log_level &= G_LOG_LEVEL_MASK;
600   
601   if (!message)
602     message = "g_log_default_handler(): (NULL) message";
603   
604 #ifdef G_OS_WIN32
605   /* Use just stdout as stderr is hard to get redirected from the
606    * DOS prompt.
607    */
608   fd = stdout;
609   gonna_abort = is_fatal;
610 #else
611   fd = (log_level > G_LOG_LEVEL_MESSAGE) ? 1 : 2;
612 #endif
613   
614   switch (log_level)
615     {
616     case G_LOG_LEVEL_ERROR:
617       /* use write(2) for output, in case we are out of memeory */
618       ensure_stdout_valid ();
619       write (fd, "\n", 1);
620       g_log_write_prefix (fd, log_level);
621
622       if (log_domain)
623         {
624           write (fd, log_domain, strlen (log_domain));
625           write (fd, "-", 1);
626         }
627       else
628         write (fd, "** ", 3);
629       if (in_recursion)
630         write (fd, "ERROR (recursed) **: ", 21);
631       else
632         write (fd, "ERROR **: ", 10);
633       write (fd, message, strlen (message));
634       if (is_fatal)
635         write (fd, "\naborting...\n", 13);
636       else
637         write (fd, "\n", 1);
638       break;
639     case G_LOG_LEVEL_CRITICAL:
640       ensure_stdout_valid ();
641       write (fd, "\n", 1);
642       g_log_write_prefix (fd, log_level);
643
644       if (log_domain)
645         {
646           write (fd, log_domain, strlen (log_domain));
647           write (fd, "-", 1);
648         }
649       else
650         write (fd, "** ", 3);
651       if (in_recursion)
652         write (fd, "CRITICAL (recursed) **: ", 24);
653       else
654         write (fd, "CRITICAL **: ", 13);
655       write (fd, message, strlen (message));
656       if (is_fatal)
657         write (fd, "\naborting...\n", 13);
658       else
659         write (fd, "\n", 1);
660       break;
661     case G_LOG_LEVEL_WARNING:
662       ensure_stdout_valid ();
663       write (fd, "\n", 1);
664       g_log_write_prefix (fd, log_level);
665
666       if (log_domain)
667         {
668           write (fd, log_domain, strlen (log_domain));
669           write (fd, "-", 1);
670         }
671       else
672         write (fd, "** ", 3);
673       if (in_recursion)
674         write (fd, "WARNING (recursed) **: ", 23);
675       else
676         write (fd, "WARNING **: ", 12);
677       write (fd, message, strlen (message));
678       if (is_fatal)
679         write (fd, "\naborting...\n", 13);
680       else
681         write (fd, "\n", 1);
682       break;
683     case G_LOG_LEVEL_MESSAGE:
684       ensure_stdout_valid ();
685
686       g_log_write_prefix (fd, log_level);
687
688       if (log_domain)
689         {
690           write (fd, log_domain, strlen (log_domain));
691           write (fd, "-", 1);
692         }
693       if (in_recursion)
694         write (fd, "Message (recursed): ", 20);
695       else
696         write (fd, "Message: ", 9);
697       write (fd, message, strlen (message));
698       if (is_fatal)
699         write (fd, "\naborting...\n", 13);
700       else
701         write (fd, "\n", 1);
702       break;
703     case G_LOG_LEVEL_INFO:
704       ensure_stdout_valid ();
705
706       g_log_write_prefix (fd, log_level);
707
708       if (log_domain)
709         {
710           write (fd, log_domain, strlen (log_domain));
711           write (fd, "-", 1);
712         }
713       if (in_recursion)
714         write (fd, "INFO (recursed): ", 17);
715       else
716         write (fd, "INFO: ", 6);
717       write (fd, message, strlen (message));
718       if (is_fatal)
719         write (fd, "\naborting...\n", 13);
720       else
721         write (fd, "\n", 1);
722       break;
723     case G_LOG_LEVEL_DEBUG:
724       ensure_stdout_valid ();
725
726       g_log_write_prefix (fd, log_level);
727
728       if (log_domain)
729         {
730           write (fd, log_domain, strlen (log_domain));
731           write (fd, "-", 1);
732         }
733       if (in_recursion)
734         write (fd, "DEBUG (recursed): ", 18);
735       else
736         write (fd, "DEBUG: ", 7);
737       write (fd, message, strlen (message));
738       if (is_fatal)
739         write (fd, "\naborting...\n", 13);
740       else
741         write (fd, "\n", 1);
742       break;
743     default:
744       /* we are used for a log level that is not defined by GLib itself,
745        * try to make the best out of it.
746        */
747       ensure_stdout_valid ();
748
749       g_log_write_prefix (fd, log_level);
750
751       if (log_domain)
752         {
753           write (fd, log_domain, strlen (log_domain));
754           if (in_recursion)
755             write (fd, "-LOG (recursed:", 15);
756           else
757             write (fd, "-LOG (", 6);
758         }
759       else if (in_recursion)
760         write (fd, "LOG (recursed:", 14);
761       else
762         write (fd, "LOG (", 5);
763       if (log_level)
764         {
765           gchar string[] = "0x00): ";
766           gchar *p = string + 2;
767           guint i;
768           
769           i = g_bit_nth_msf (log_level, -1);
770           *p = i >> 4;
771           p++;
772           *p = '0' + (i & 0xf);
773           if (*p > '9')
774             *p += 'A' - '9' - 1;
775           
776           write (fd, string, 7);
777         }
778       else
779         write (fd, "): ", 3);
780       write (fd, message, strlen (message));
781       if (is_fatal)
782         write (fd, "\naborting...\n", 13);
783       else
784         write (fd, "\n", 1);
785       break;
786     }
787 }
788
789 GPrintFunc
790 g_set_print_handler (GPrintFunc func)
791 {
792   GPrintFunc old_print_func;
793   
794   g_mutex_lock (g_messages_lock);
795   old_print_func = glib_print_func;
796   glib_print_func = func;
797   g_mutex_unlock (g_messages_lock);
798   
799   return old_print_func;
800 }
801
802 void
803 g_print (const gchar *format,
804          ...)
805 {
806   va_list args;
807   gchar *string;
808   GPrintFunc local_glib_print_func;
809   
810   g_return_if_fail (format != NULL);
811   
812   va_start (args, format);
813   string = g_strdup_vprintf (format, args);
814   va_end (args);
815   
816   g_mutex_lock (g_messages_lock);
817   local_glib_print_func = glib_print_func;
818   g_mutex_unlock (g_messages_lock);
819
820   if (local_glib_print_func)
821     local_glib_print_func (string);
822   else
823     {
824       ensure_stdout_valid ();
825       fputs (string, stdout);
826       fflush (stdout);
827     }
828   g_free (string);
829 }
830
831 GPrintFunc
832 g_set_printerr_handler (GPrintFunc func)
833 {
834   GPrintFunc old_printerr_func;
835   
836   g_mutex_lock (g_messages_lock);
837   old_printerr_func = glib_printerr_func;
838   glib_printerr_func = func;
839   g_mutex_unlock (g_messages_lock);
840   
841   return old_printerr_func;
842 }
843
844 void
845 g_printerr (const gchar *format,
846             ...)
847 {
848   va_list args;
849   gchar *string;
850   GPrintFunc local_glib_printerr_func;
851   
852   g_return_if_fail (format != NULL);
853   
854   va_start (args, format);
855   string = g_strdup_vprintf (format, args);
856   va_end (args);
857   
858   g_mutex_lock (g_messages_lock);
859   local_glib_printerr_func = glib_printerr_func;
860   g_mutex_unlock (g_messages_lock);
861
862   if (local_glib_printerr_func)
863     local_glib_printerr_func (string);
864   else
865     {
866       fputs (string, stderr);
867       fflush (stderr);
868     }
869   g_free (string);
870 }
871
872 #ifndef MB_LEN_MAX
873 #  define MB_LEN_MAX 8
874 #endif
875
876 #ifndef HAVE_C99_VSNPRINTF
877
878 typedef struct
879 {
880   guint min_width;
881   guint precision;
882   gboolean alternate_format, zero_padding, adjust_left, locale_grouping;
883   gboolean add_space, add_sign, possible_sign, seen_precision;
884   gboolean mod_half, mod_long, mod_extra_long;
885 } PrintfArgSpec;
886
887 static gsize
888 printf_string_upper_bound (const gchar *format,
889                            gboolean     may_warn,
890                            va_list      args)
891 {
892   static const gboolean honour_longs = SIZEOF_LONG > 4 || SIZEOF_VOID_P > 4;
893   gsize len = 1;
894
895   if (!format)
896     return len;
897
898   while (*format)
899     {
900       register gchar c = *format++;
901
902       if (c != '%')
903         len += 1;
904       else /* (c == '%') */
905         {
906           PrintfArgSpec spec = { 0, };
907           gboolean seen_l = FALSE, conv_done = FALSE;
908           gsize conv_len = 0;
909           const gchar *spec_start = format;
910
911           do
912             {
913               c = *format++;
914               switch (c)
915                 {
916                   GDoubleIEEE754 u_double;
917                   guint v_uint;
918                   gint v_int;
919                   const gchar *v_string;
920
921                   /* beware of positional parameters
922                    */
923                 case '$':
924                   if (may_warn)
925                     g_warning (G_GNUC_PRETTY_FUNCTION
926                                "(): unable to handle positional parameters (%%n$)");
927                   len += 1024; /* try adding some safety padding */
928                   conv_done = TRUE;
929                   break;
930
931                   /* parse flags
932                    */
933                 case '#':
934                   spec.alternate_format = TRUE;
935                   break;
936                 case '0':
937                   spec.zero_padding = TRUE;
938                   break;
939                 case '-':
940                   spec.adjust_left = TRUE;
941                   break;
942                 case ' ':
943                   spec.add_space = TRUE;
944                   break;
945                 case '+':
946                   spec.add_sign = TRUE;
947                   break;
948                 case '\'':
949                   spec.locale_grouping = TRUE;
950                   break;
951
952                   /* parse output size specifications
953                    */
954                 case '.':
955                   spec.seen_precision = TRUE;
956                   break;
957                 case '1':
958                 case '2':
959                 case '3':
960                 case '4':
961                 case '5':
962                 case '6':
963                 case '7':
964                 case '8':
965                 case '9':
966                   v_uint = c - '0';
967                   c = *format;
968                   while (c >= '0' && c <= '9')
969                     {
970                       format++;
971                       v_uint = v_uint * 10 + c - '0';
972                       c = *format;
973                     }
974                   if (spec.seen_precision)
975                     spec.precision = MAX (spec.precision, v_uint);
976                   else
977                     spec.min_width = MAX (spec.min_width, v_uint);
978                   break;
979                 case '*':
980                   v_int = va_arg (args, int);
981                   if (spec.seen_precision)
982                     {
983                       /* forget about negative precision */
984                       if (v_int >= 0)
985                         spec.precision = MAX (spec.precision, v_int);
986                     }
987                   else
988                     {
989                       if (v_int < 0)
990                         {
991                           v_int = - v_int;
992                           spec.adjust_left = TRUE;
993                         }
994                       spec.min_width = MAX (spec.min_width, v_int);
995                     }
996                   break;
997
998                   /* parse type modifiers
999                    */
1000                 case 'h':
1001                   spec.mod_half = TRUE;
1002                   break;
1003                 case 'l':
1004                   if (!seen_l)
1005                     {
1006                       spec.mod_long = TRUE;
1007                       seen_l = TRUE;
1008                       break;
1009                     }
1010                   /* else, fall through */
1011                 case 'L':
1012                 case 'q':
1013                   spec.mod_long = TRUE;
1014                   spec.mod_extra_long = TRUE;
1015                   break;
1016                 case 'z':
1017                 case 'Z':
1018 #if GLIB_SIZEOF_SIZE_T > 4
1019                   spec.mod_long = TRUE;
1020                   spec.mod_extra_long = TRUE;
1021 #endif /* GLIB_SIZEOF_SIZE_T > 4 */
1022                   break;
1023                 case 't':
1024 #if GLIB_SIZEOF_PTRDIFF_T > 4
1025                   spec.mod_long = TRUE;
1026                   spec.mod_extra_long = TRUE;
1027 #endif /* GLIB_SIZEOF_PTRDIFF_T > 4 */
1028                   break;
1029                 case 'j':
1030 #if GLIB_SIZEOF_INTMAX_T > 4
1031                   spec.mod_long = TRUE;
1032                   spec.mod_extra_long = TRUE;
1033 #endif /* GLIB_SIZEOF_INTMAX_T > 4 */
1034                   break;
1035
1036                   /* parse output conversions
1037                    */
1038                 case '%':
1039                   conv_len += 1;
1040                   break;
1041                 case 'O':
1042                 case 'D':
1043                 case 'I':
1044                 case 'U':
1045                   /* some C libraries feature long variants for these as well? */
1046                   spec.mod_long = TRUE;
1047                   /* fall through */
1048                 case 'o':
1049                   conv_len += 2;
1050                   /* fall through */
1051                 case 'd':
1052                 case 'i':
1053                   conv_len += 1; /* sign */
1054                   /* fall through */
1055                 case 'u':
1056                   conv_len += 4;
1057                   /* fall through */
1058                 case 'x':
1059                 case 'X':
1060                   spec.possible_sign = TRUE;
1061                   conv_len += 10;
1062                   if (spec.mod_long && honour_longs)
1063                     conv_len *= 2;
1064                   if (spec.mod_extra_long)
1065                     conv_len *= 2;
1066                   if (spec.mod_extra_long)
1067                     {
1068                       (void) va_arg (args, gint64);
1069                     }
1070                   else if (spec.mod_long)
1071                     (void) va_arg (args, long);
1072                   else
1073                     (void) va_arg (args, int);
1074                   break;
1075                 case 'A':
1076                 case 'a':
1077                   /*          0x */
1078                   conv_len += 2;
1079                   /* fall through */
1080                 case 'g':
1081                 case 'G':
1082                 case 'e':
1083                 case 'E':
1084                 case 'f':
1085                   spec.possible_sign = TRUE;
1086                   /*          n   .   dddddddddddddddddddddddd   E   +-  eeee */
1087                   conv_len += 1 + 1 + MAX (24, spec.precision) + 1 + 1 + 4;
1088                   if (may_warn && spec.mod_extra_long)
1089                     g_warning (G_GNUC_PRETTY_FUNCTION
1090                                "(): unable to handle long double, collecting double only");
1091 #ifdef HAVE_LONG_DOUBLE
1092 #error need to implement special handling for long double
1093 #endif
1094                   u_double.v_double = va_arg (args, double);
1095                   /* %f can expand up to all significant digits before '.' (308) */
1096                   if (c == 'f' &&
1097                       u_double.mpn.biased_exponent > 0 && u_double.mpn.biased_exponent < 2047)
1098                     {
1099                       gint exp = u_double.mpn.biased_exponent;
1100
1101                       exp -= G_IEEE754_DOUBLE_BIAS;
1102                       exp = exp * G_LOG_2_BASE_10 + 1;
1103                       conv_len += ABS (exp);    /* exp can be <0 */
1104                     }
1105                   /* some printf() implementations require extra padding for rounding */
1106                   conv_len += 2;
1107                   /* we can't really handle locale specific grouping here */
1108                   if (spec.locale_grouping)
1109                     conv_len *= 2;
1110                   break;
1111                 case 'C':
1112                   spec.mod_long = TRUE;
1113                   /* fall through */
1114                 case 'c':
1115                   conv_len += spec.mod_long ? MB_LEN_MAX : 1;
1116                   (void) va_arg (args, int);
1117                   break;
1118                 case 'S':
1119                   spec.mod_long = TRUE;
1120                   /* fall through */
1121                 case 's':
1122                   v_string = va_arg (args, char*);
1123                   if (!v_string)
1124                     conv_len += 8; /* hold "(null)" */
1125                   else if (spec.seen_precision)
1126                     conv_len += spec.precision;
1127                   else
1128                     conv_len += strlen (v_string);
1129                   conv_done = TRUE;
1130                   if (spec.mod_long)
1131                     {
1132                       if (may_warn)
1133                         g_warning (G_GNUC_PRETTY_FUNCTION
1134                                    "(): unable to handle wide char strings");
1135                       len += 1024; /* try adding some safety padding */
1136                     }
1137                   break;
1138                 case 'P': /* do we actually need this? */
1139                   /* fall through */
1140                 case 'p':
1141                   spec.alternate_format = TRUE;
1142                   conv_len += 10;
1143                   if (honour_longs)
1144                     conv_len *= 2;
1145                   /* fall through */
1146                 case 'n':
1147                   conv_done = TRUE;
1148                   (void) va_arg (args, void*);
1149                   break;
1150                 case 'm':
1151                   /* there's not much we can do to be clever */
1152                   v_string = g_strerror (errno);
1153                   v_uint = v_string ? strlen (v_string) : 0;
1154                   conv_len += MAX (256, v_uint);
1155                   break;
1156
1157                   /* handle invalid cases
1158                    */
1159                 case '\000':
1160                   /* no conversion specification, bad bad */
1161                   conv_len += format - spec_start;
1162                   break;
1163                 default:
1164                   if (may_warn)
1165                     g_warning (G_GNUC_PRETTY_FUNCTION
1166                                "(): unable to handle `%c' while parsing format",
1167                                c);
1168                   break;
1169                 }
1170               conv_done |= conv_len > 0;
1171             }
1172           while (!conv_done);
1173           /* handle width specifications */
1174           conv_len = MAX (conv_len, MAX (spec.precision, spec.min_width));
1175           /* handle flags */
1176           conv_len += spec.alternate_format ? 2 : 0;
1177           conv_len += (spec.add_space || spec.add_sign || spec.possible_sign);
1178           /* finally done */
1179           len += conv_len;
1180         } /* else (c == '%') */
1181     } /* while (*format) */
1182
1183   return len;
1184 }
1185
1186 #endif /* !HAVE_C99_VSNPRINTF */
1187
1188
1189 gsize
1190 g_printf_string_upper_bound (const gchar *format,
1191                              va_list      args)
1192 {
1193 #if HAVE_C99_VSNPRINTF
1194   gchar c;
1195   return vsnprintf (&c, 1, format, args) + 1;
1196 #else
1197   return printf_string_upper_bound (format, TRUE, args);
1198 #endif
1199 }
1200
1201 void
1202 g_messages_init (void)
1203 {
1204   g_messages_lock = g_mutex_new ();
1205   g_log_depth = g_private_new (NULL);
1206   g_log_msg_prefix_init ();
1207   _g_debug_init ();
1208 }
1209
1210 gboolean _g_debug_initialized = FALSE;
1211 guint _g_debug_flags = 0;
1212
1213 void _g_debug_init () 
1214 {
1215   const gchar *val;
1216   
1217   _g_debug_initialized = TRUE;
1218
1219   val = g_getenv ("G_DEBUG");
1220   if (val != NULL)
1221     {
1222       static const GDebugKey keys[] = {
1223         {"fatal_warnings", G_DEBUG_FATAL_WARNINGS}
1224       };
1225
1226       _g_debug_flags = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
1227     }
1228
1229   if (_g_debug_flags & G_DEBUG_FATAL_WARNINGS) 
1230     {
1231       GLogLevelFlags fatal_mask;
1232       
1233       fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
1234       fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
1235       g_log_set_always_fatal (fatal_mask);
1236     }
1237 }