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