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