Strip the prefix "IA__" from function names, since that is what GTK+ uses
[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 #include "config.h"
32
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <string.h>
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40 #include <signal.h>
41 #include <locale.h>
42 #include <errno.h>
43
44 #include "glib.h"
45 #include "gdebug.h"
46 #include "gprintfint.h"
47 #include "gthreadinit.h"
48
49 #ifdef G_OS_WIN32
50 #include <io.h>
51 typedef FILE* GFileDescriptor;
52 #else
53 typedef gint GFileDescriptor;
54 #endif
55
56 /* --- structures --- */
57 typedef struct _GLogDomain      GLogDomain;
58 typedef struct _GLogHandler     GLogHandler;
59 struct _GLogDomain
60 {
61   gchar         *log_domain;
62   GLogLevelFlags fatal_mask;
63   GLogHandler   *handlers;
64   GLogDomain    *next;
65 };
66 struct _GLogHandler
67 {
68   guint          id;
69   GLogLevelFlags log_level;
70   GLogFunc       log_func;
71   gpointer       data;
72   GLogHandler   *next;
73 };
74
75
76 /* --- variables --- */
77 static GMutex        *g_messages_lock = NULL;
78 static GLogDomain    *g_log_domains = NULL;
79 static GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK;
80 static GPrintFunc     glib_print_func = NULL;
81 static GPrintFunc     glib_printerr_func = NULL;
82 static GPrivate      *g_log_depth = NULL;
83 static GLogLevelFlags g_log_msg_prefix = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG;
84 static GLogFunc       default_log_func = g_log_default_handler;
85 static gpointer       default_log_data = NULL;
86
87 /* --- functions --- */
88 #ifdef G_OS_WIN32
89 #  define STRICT
90 #  include <windows.h>
91 #  undef STRICT
92 #  include <process.h>          /* For _getpid() */
93 static gboolean win32_keep_fatal_message = FALSE;
94
95 /* This default message will usually be overwritten. */
96 /* Yes, a fixed size buffer is bad. So sue me. But g_error is never
97  * with huge strings, is it?
98  */
99 static gchar  fatal_msg_buf[1000] = "Unspecified fatal error encountered, aborting.";
100 static gchar *fatal_msg_ptr = fatal_msg_buf;
101
102 /* Just use stdio. If we're out of memory, we're hosed anyway. */
103 #undef write
104 static inline int
105 dowrite (GFileDescriptor fd,
106          const void  *buf,
107          unsigned int len)
108 {
109   if (win32_keep_fatal_message)
110     {
111       memcpy (fatal_msg_ptr, buf, len);
112       fatal_msg_ptr += len;
113       *fatal_msg_ptr = 0;
114       return len;
115     }
116
117   fwrite (buf, len, 1, fd);
118   fflush (fd);
119
120   return len;
121 }
122 #define write(fd, buf, len) dowrite(fd, buf, len)
123
124 static void
125 ensure_stdout_valid (void)
126 {
127   static gboolean alloc_console_called = FALSE;
128   HANDLE handle;
129
130   if (win32_keep_fatal_message)
131     return;
132
133   if (!alloc_console_called)
134     {
135       handle = (HANDLE) _get_osfhandle (fileno (stdout)); 
136   
137       if (handle == INVALID_HANDLE_VALUE)
138         {
139           AllocConsole ();
140           alloc_console_called = TRUE;
141           freopen ("CONOUT$", "w", stdout);
142         }
143     }
144 }
145
146 static void
147 ensure_stderr_valid (void)
148 {
149   static gboolean alloc_console_called = FALSE;
150   HANDLE handle;
151
152   if (win32_keep_fatal_message)
153     return;
154
155   if (!alloc_console_called)
156     {
157       handle = (HANDLE) _get_osfhandle (fileno (stderr)); 
158
159       if (handle == INVALID_HANDLE_VALUE)
160         {
161           AllocConsole ();
162           alloc_console_called = TRUE;
163           freopen ("CONOUT$", "w", stderr);
164         }
165     }
166 }
167
168 #else
169 #define ensure_stdout_valid()   /* Define as empty */
170 #define ensure_stderr_valid()
171 #endif
172
173 static void
174 write_string (GFileDescriptor fd,
175               const gchar    *string)
176 {
177   write (fd, string, strlen (string));
178 }
179
180 static void
181 g_messages_prefixed_init (void)
182 {
183   static gboolean initialized = FALSE;
184
185   if (!initialized)
186     {
187       const gchar *val;
188
189       initialized = TRUE;
190       val = g_getenv ("G_MESSAGES_PREFIXED");
191       
192       if (val)
193         {
194           static const GDebugKey keys[] = {
195             { "error", G_LOG_LEVEL_ERROR },
196             { "critical", G_LOG_LEVEL_CRITICAL },
197             { "warning", G_LOG_LEVEL_WARNING },
198             { "message", G_LOG_LEVEL_MESSAGE },
199             { "info", G_LOG_LEVEL_INFO },
200             { "debug", G_LOG_LEVEL_DEBUG }
201           };
202           
203           g_log_msg_prefix = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
204         }
205     }
206 }
207
208 static GLogDomain*
209 g_log_find_domain_L (const gchar *log_domain)
210 {
211   register GLogDomain *domain;
212   
213   domain = g_log_domains;
214   while (domain)
215     {
216       if (strcmp (domain->log_domain, log_domain) == 0)
217         return domain;
218       domain = domain->next;
219     }
220   return NULL;
221 }
222
223 static GLogDomain*
224 g_log_domain_new_L (const gchar *log_domain)
225 {
226   register GLogDomain *domain;
227
228   domain = g_new (GLogDomain, 1);
229   domain->log_domain = g_strdup (log_domain);
230   domain->fatal_mask = G_LOG_FATAL_MASK;
231   domain->handlers = NULL;
232   
233   domain->next = g_log_domains;
234   g_log_domains = domain;
235   
236   return domain;
237 }
238
239 static void
240 g_log_domain_check_free_L (GLogDomain *domain)
241 {
242   if (domain->fatal_mask == G_LOG_FATAL_MASK &&
243       domain->handlers == NULL)
244     {
245       register GLogDomain *last, *work;
246       
247       last = NULL;  
248
249       work = g_log_domains;
250       while (work)
251         {
252           if (work == domain)
253             {
254               if (last)
255                 last->next = domain->next;
256               else
257                 g_log_domains = domain->next;
258               g_free (domain->log_domain);
259               g_free (domain);
260               break;
261             }
262           last = work;
263           work = last->next;
264         }  
265     }
266 }
267
268 static GLogFunc
269 g_log_domain_get_handler_L (GLogDomain  *domain,
270                             GLogLevelFlags log_level,
271                             gpointer    *data)
272 {
273   if (domain && log_level)
274     {
275       register GLogHandler *handler;
276       
277       handler = domain->handlers;
278       while (handler)
279         {
280           if ((handler->log_level & log_level) == log_level)
281             {
282               *data = handler->data;
283               return handler->log_func;
284             }
285           handler = handler->next;
286         }
287     }
288
289   *data = default_log_data;
290   return default_log_func;
291 }
292
293 GLogLevelFlags
294 g_log_set_always_fatal (GLogLevelFlags fatal_mask)
295 {
296   GLogLevelFlags old_mask;
297
298   /* restrict the global mask to levels that are known to glib
299    * since this setting applies to all domains
300    */
301   fatal_mask &= (1 << G_LOG_LEVEL_USER_SHIFT) - 1;
302   /* force errors to be fatal */
303   fatal_mask |= G_LOG_LEVEL_ERROR;
304   /* remove bogus flag */
305   fatal_mask &= ~G_LOG_FLAG_FATAL;
306
307   g_mutex_lock (g_messages_lock);
308   old_mask = g_log_always_fatal;
309   g_log_always_fatal = fatal_mask;
310   g_mutex_unlock (g_messages_lock);
311
312   return old_mask;
313 }
314
315 GLogLevelFlags
316 g_log_set_fatal_mask (const gchar   *log_domain,
317                       GLogLevelFlags fatal_mask)
318 {
319   GLogLevelFlags old_flags;
320   register GLogDomain *domain;
321   
322   if (!log_domain)
323     log_domain = "";
324   
325   /* force errors to be fatal */
326   fatal_mask |= G_LOG_LEVEL_ERROR;
327   /* remove bogus flag */
328   fatal_mask &= ~G_LOG_FLAG_FATAL;
329   
330   g_mutex_lock (g_messages_lock);
331
332   domain = g_log_find_domain_L (log_domain);
333   if (!domain)
334     domain = g_log_domain_new_L (log_domain);
335   old_flags = domain->fatal_mask;
336   
337   domain->fatal_mask = fatal_mask;
338   g_log_domain_check_free_L (domain);
339
340   g_mutex_unlock (g_messages_lock);
341
342   return old_flags;
343 }
344
345 guint
346 g_log_set_handler (const gchar   *log_domain,
347                    GLogLevelFlags log_levels,
348                    GLogFunc       log_func,
349                    gpointer       user_data)
350 {
351   static guint handler_id = 0;
352   GLogDomain *domain;
353   GLogHandler *handler;
354   
355   g_return_val_if_fail ((log_levels & G_LOG_LEVEL_MASK) != 0, 0);
356   g_return_val_if_fail (log_func != NULL, 0);
357   
358   if (!log_domain)
359     log_domain = "";
360
361   handler = g_new (GLogHandler, 1);
362
363   g_mutex_lock (g_messages_lock);
364
365   domain = g_log_find_domain_L (log_domain);
366   if (!domain)
367     domain = g_log_domain_new_L (log_domain);
368   
369   handler->id = ++handler_id;
370   handler->log_level = log_levels;
371   handler->log_func = log_func;
372   handler->data = user_data;
373   handler->next = domain->handlers;
374   domain->handlers = handler;
375
376   g_mutex_unlock (g_messages_lock);
377   
378   return handler_id;
379 }
380
381 GLogFunc
382 g_log_set_default_handler (GLogFunc log_func,
383                            gpointer user_data)
384 {
385   GLogFunc old_log_func;
386   
387   g_mutex_lock (g_messages_lock);
388   old_log_func = default_log_func;
389   default_log_func = log_func;
390   default_log_data = user_data;
391   g_mutex_unlock (g_messages_lock);
392   
393   return old_log_func;
394 }
395
396 void
397 g_log_remove_handler (const gchar *log_domain,
398                       guint        handler_id)
399 {
400   register GLogDomain *domain;
401   
402   g_return_if_fail (handler_id > 0);
403   
404   if (!log_domain)
405     log_domain = "";
406   
407   g_mutex_lock (g_messages_lock);
408   domain = g_log_find_domain_L (log_domain);
409   if (domain)
410     {
411       GLogHandler *work, *last;
412       
413       last = NULL;
414       work = domain->handlers;
415       while (work)
416         {
417           if (work->id == handler_id)
418             {
419               if (last)
420                 last->next = work->next;
421               else
422                 domain->handlers = work->next;
423               g_log_domain_check_free_L (domain); 
424               g_mutex_unlock (g_messages_lock);
425               g_free (work);
426               return;
427             }
428           last = work;
429           work = last->next;
430         }
431     } 
432   g_mutex_unlock (g_messages_lock);
433   g_warning ("%s: could not find handler with id `%d' for domain \"%s\"",
434              G_STRLOC, handler_id, log_domain);
435 }
436
437 void
438 g_logv (const gchar   *log_domain,
439         GLogLevelFlags log_level,
440         const gchar   *format,
441         va_list        args1)
442 {
443   gboolean was_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
444   gboolean was_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
445   gint i;
446
447   log_level &= G_LOG_LEVEL_MASK;
448   if (!log_level)
449     return;
450   
451   for (i = g_bit_nth_msf (log_level, -1); i >= 0; i = g_bit_nth_msf (log_level, i))
452     {
453       register GLogLevelFlags test_level;
454       
455       test_level = 1 << i;
456       if (log_level & test_level)
457         {
458           guint depth = GPOINTER_TO_UINT (g_private_get (g_log_depth));
459           GLogDomain *domain;
460           GLogFunc log_func;
461           guint domain_fatal_mask;
462           gpointer data = NULL;
463
464           if (was_fatal)
465             test_level |= G_LOG_FLAG_FATAL;
466           if (was_recursion)
467             test_level |= G_LOG_FLAG_RECURSION;
468
469           /* check recursion and lookup handler */
470           g_mutex_lock (g_messages_lock);
471           domain = g_log_find_domain_L (log_domain ? log_domain : "");
472           if (depth)
473             test_level |= G_LOG_FLAG_RECURSION;
474           depth++;
475           domain_fatal_mask = domain ? domain->fatal_mask : G_LOG_FATAL_MASK;
476           if ((domain_fatal_mask | g_log_always_fatal) & test_level)
477             test_level |= G_LOG_FLAG_FATAL;
478           if (test_level & G_LOG_FLAG_RECURSION)
479             log_func = _g_log_fallback_handler;
480           else
481             log_func = g_log_domain_get_handler_L (domain, test_level, &data);
482           domain = NULL;
483           g_mutex_unlock (g_messages_lock);
484
485           g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
486
487           /* had to defer debug initialization until we can keep track of recursion */
488           if (!(test_level & G_LOG_FLAG_RECURSION) && !_g_debug_initialized)
489             {
490               guint orig_test_level = test_level;
491
492               _g_debug_init ();
493               if ((domain_fatal_mask | g_log_always_fatal) & test_level)
494                 test_level |= G_LOG_FLAG_FATAL;
495               if (test_level != orig_test_level)
496                 {
497                   /* need a relookup, not nice, but not too bad either */
498                   g_mutex_lock (g_messages_lock);
499                   domain = g_log_find_domain_L (log_domain ? log_domain : "");
500                   log_func = g_log_domain_get_handler_L (domain, test_level, &data);
501                   domain = NULL;
502                   g_mutex_unlock (g_messages_lock);
503                 }
504             }
505
506           if (test_level & G_LOG_FLAG_RECURSION)
507             {
508               /* we use a stack buffer of fixed size, since we're likely
509                * in an out-of-memory situation
510                */
511               gchar buffer[1025];
512               gint size;
513               size = _g_vsnprintf (buffer, 1024, format, args1);
514
515               log_func (log_domain, test_level, buffer, data);
516             }
517           else
518             {
519               gchar *msg = g_strdup_vprintf (format, args1);
520
521               log_func (log_domain, test_level, msg, data);
522
523               g_free (msg);
524             }
525
526           if (test_level & G_LOG_FLAG_FATAL)
527             {
528 #ifdef G_OS_WIN32
529               gchar *locale_msg = g_locale_from_utf8 (fatal_msg_buf, -1, NULL, NULL, NULL);
530               
531               MessageBox (NULL, locale_msg, NULL,
532                           MB_ICONERROR|MB_SETFOREGROUND);
533 #endif
534 #if defined (G_ENABLE_DEBUG) && (defined (SIGTRAP) || defined (G_OS_WIN32))
535               if (!(test_level & G_LOG_FLAG_RECURSION))
536                 G_BREAKPOINT ();
537               else
538                 abort ();
539 #else /* !G_ENABLE_DEBUG || !(SIGTRAP || G_OS_WIN32) */
540               abort ();
541 #endif /* !G_ENABLE_DEBUG || !(SIGTRAP || G_OS_WIN32) */
542             }
543           
544           depth--;
545           g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
546         }
547     }
548 }
549
550 void
551 g_log (const gchar   *log_domain,
552        GLogLevelFlags log_level,
553        const gchar   *format,
554        ...)
555 {
556   va_list args;
557   
558   va_start (args, format);
559   g_logv (log_domain, log_level, format, args);
560   va_end (args);
561 }
562
563 void
564 g_return_if_fail_warning (const char *log_domain,
565                           const char *pretty_function,
566                           const char *expression)
567 {
568   /*
569    * Omit the prefix used by the PLT-reduction
570    * technique used in GTK+. 
571    */
572   if (g_str_has_prefix (pretty_function, "IA__"))
573     pretty_function += 4;
574   g_log (log_domain,
575          G_LOG_LEVEL_CRITICAL,
576          "%s: assertion `%s' failed",
577          pretty_function,
578          expression);
579 }
580
581 #define CHAR_IS_SAFE(wc) (!((wc < 0x20 && wc != '\t' && wc != '\n' && wc != '\r') || \
582                             (wc == 0x7f) || \
583                             (wc >= 0x80 && wc < 0xa0)))
584      
585 static gchar*
586 strdup_convert (const gchar *string,
587                 const gchar *charset)
588 {
589   if (!g_utf8_validate (string, -1, NULL))
590     {
591       GString *gstring = g_string_new ("[Invalid UTF-8] ");
592       guchar *p;
593
594       for (p = (guchar *)string; *p; p++)
595         {
596           if (CHAR_IS_SAFE(*p) &&
597               !(*p == '\r' && *(p + 1) != '\n') &&
598               *p < 0x80)
599             g_string_append_c (gstring, *p);
600           else
601             g_string_append_printf (gstring, "\\x%02x", (guint)(guchar)*p);
602         }
603       
604       return g_string_free (gstring, FALSE);
605     }
606   else
607     {
608       GError *err = NULL;
609       
610       gchar *result = g_convert_with_fallback (string, -1, charset, "UTF-8", "?", NULL, NULL, &err);
611       if (result)
612         return result;
613       else
614         {
615           /* Not thread-safe, but doesn't matter if we print the warning twice
616            */
617           static gboolean warned = FALSE; 
618           if (!warned)
619             {
620               warned = TRUE;
621               ensure_stderr_valid ();
622               _g_fprintf (stderr, "GLib: Cannot convert message: %s\n", err->message);
623             }
624           g_error_free (err);
625           
626           return g_strdup (string);
627         }
628     }
629 }
630
631 /* For a radix of 8 we need at most 3 output bytes for 1 input
632  * byte. Additionally we might need up to 2 output bytes for the
633  * readix prefix and 1 byte for the trailing NULL.
634  */
635 #define FORMAT_UNSIGNED_BUFSIZE ((GLIB_SIZEOF_LONG * 3) + 3)
636
637 static void
638 format_unsigned (gchar  *buf,
639                  gulong  num,
640                  guint   radix)
641 {
642   gulong tmp;
643   gchar c;
644   gint i, n;
645
646   /* we may not call _any_ GLib functions here (or macros like g_return_if_fail()) */
647
648   if (radix != 8 && radix != 10 && radix != 16)
649     {
650       *buf = '\000';
651       return;
652     }
653   
654   if (!num)
655     {
656       *buf++ = '0';
657       *buf = '\000';
658       return;
659     } 
660   
661   if (radix == 16)
662     {
663       *buf++ = '0';
664       *buf++ = 'x';
665     }
666   else if (radix == 8)
667     {
668       *buf++ = '0';
669     }
670         
671   n = 0;
672   tmp = num;
673   while (tmp)
674     {
675       tmp /= radix;
676       n++;
677     }
678
679   i = n;
680
681   /* Again we can't use g_assert; actually this check should _never_ fail. */
682   if (n > FORMAT_UNSIGNED_BUFSIZE - 3)
683     {
684       *buf = '\000';
685       return;
686     }
687
688   while (num)
689     {
690       i--;
691       c = (num % radix);
692       if (c < 10)
693         buf[i] = c + '0';
694       else
695         buf[i] = c + 'a' - 10;
696       num /= radix;
697     }
698   
699   buf[n] = '\000';
700 }
701
702 /* string size big enough to hold level prefix */
703 #define STRING_BUFFER_SIZE      (FORMAT_UNSIGNED_BUFSIZE + 32)
704
705 #define ALERT_LEVELS            (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING)
706
707 static GFileDescriptor
708 mklevel_prefix (gchar level_prefix[STRING_BUFFER_SIZE],
709                 guint log_level)
710 {
711   gboolean to_stdout = TRUE;
712
713   /* we may not call _any_ GLib functions here */
714
715   switch (log_level & G_LOG_LEVEL_MASK)
716     {
717     case G_LOG_LEVEL_ERROR:
718       strcpy (level_prefix, "ERROR");
719       to_stdout = FALSE;
720       break;
721     case G_LOG_LEVEL_CRITICAL:
722       strcpy (level_prefix, "CRITICAL");
723       to_stdout = FALSE;
724       break;
725     case G_LOG_LEVEL_WARNING:
726       strcpy (level_prefix, "WARNING");
727       to_stdout = FALSE;
728       break;
729     case G_LOG_LEVEL_MESSAGE:
730       strcpy (level_prefix, "Message");
731       to_stdout = FALSE;
732       break;
733     case G_LOG_LEVEL_INFO:
734       strcpy (level_prefix, "INFO");
735       break;
736     case G_LOG_LEVEL_DEBUG:
737       strcpy (level_prefix, "DEBUG");
738       break;
739     default:
740       if (log_level)
741         {
742           strcpy (level_prefix, "LOG-");
743           format_unsigned (level_prefix + 4, log_level & G_LOG_LEVEL_MASK, 16);
744         }
745       else
746         strcpy (level_prefix, "LOG");
747       break;
748     }
749   if (log_level & G_LOG_FLAG_RECURSION)
750     strcat (level_prefix, " (recursed)");
751   if (log_level & ALERT_LEVELS)
752     strcat (level_prefix, " **");
753
754 #ifdef G_OS_WIN32
755   win32_keep_fatal_message = (log_level & G_LOG_FLAG_FATAL) != 0;
756
757   if (to_stdout)
758     {
759       ensure_stdout_valid ();
760       return stdout;
761     }
762   else
763     {
764       ensure_stderr_valid ();
765       return stderr;
766     }
767 #else
768   return to_stdout ? 1 : 2;
769 #endif
770 }
771
772 void
773 _g_log_fallback_handler (const gchar   *log_domain,
774                          GLogLevelFlags log_level,
775                          const gchar   *message,
776                          gpointer       unused_data)
777 {
778   gchar level_prefix[STRING_BUFFER_SIZE], pid_string[FORMAT_UNSIGNED_BUFSIZE];
779   gboolean is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
780   GFileDescriptor fd;
781
782   /* we can not call _any_ GLib functions in this fallback handler,
783    * which is why we skip UTF-8 conversion, etc.
784    * since we either recursed or ran out of memory, we're in a pretty
785    * pathologic situation anyways, what we can do is giving the
786    * the process ID unconditionally however.
787    */
788
789   fd = mklevel_prefix (level_prefix, log_level);
790   if (!message)
791     message = "(NULL) message";
792
793   format_unsigned (pid_string, getpid (), 10);
794
795   if (log_domain)
796     write_string (fd, "\n");
797   else
798     write_string (fd, "\n** ");
799   write_string (fd, "(process:");
800   write_string (fd, pid_string);
801   write_string (fd, "): ");
802   if (log_domain)
803     {
804       write_string (fd, log_domain);
805       write_string (fd, "-");
806     }
807   write_string (fd, level_prefix);
808   write_string (fd, ": ");
809   write_string (fd, message);
810   if (is_fatal)
811     write_string (fd, "\naborting...\n");
812   else
813     write_string (fd, "\n");
814 }
815
816 static void
817 escape_string (GString *string)
818 {
819   const char *p = string->str;
820   gunichar wc;
821
822   while (p < string->str + string->len)
823     {
824       gboolean safe;
825             
826       wc = g_utf8_get_char_validated (p, -1);
827       if (wc == (gunichar)-1 || wc == (gunichar)-2)  
828         {
829           gchar *tmp;
830           guint pos;
831
832           pos = p - string->str;
833
834           /* Emit invalid UTF-8 as hex escapes 
835            */
836           tmp = g_strdup_printf ("\\x%02x", (guint)(guchar)*p);
837           g_string_erase (string, pos, 1);
838           g_string_insert (string, pos, tmp);
839
840           p = string->str + (pos + 4); /* Skip over escape sequence */
841
842           g_free (tmp);
843           continue;
844         }
845       if (wc == '\r')
846         {
847           safe = *(p + 1) == '\n';
848         }
849       else
850         {
851           safe = CHAR_IS_SAFE (wc);
852         }
853       
854       if (!safe)
855         {
856           gchar *tmp;
857           guint pos;
858
859           pos = p - string->str;
860           
861           /* Largest char we escape is 0x0a, so we don't have to worry
862            * about 8-digit \Uxxxxyyyy
863            */
864           tmp = g_strdup_printf ("\\u%04x", wc); 
865           g_string_erase (string, pos, g_utf8_next_char (p) - p);
866           g_string_insert (string, pos, tmp);
867           g_free (tmp);
868
869           p = string->str + (pos + 6); /* Skip over escape sequence */
870         }
871       else
872         p = g_utf8_next_char (p);
873     }
874 }
875
876 void
877 g_log_default_handler (const gchar   *log_domain,
878                        GLogLevelFlags log_level,
879                        const gchar   *message,
880                        gpointer       unused_data)
881 {
882   gboolean is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
883   gchar level_prefix[STRING_BUFFER_SIZE], *string;
884   GString *gstring;
885   GFileDescriptor fd;
886
887   /* we can be called externally with recursion for whatever reason */
888   if (log_level & G_LOG_FLAG_RECURSION)
889     {
890       _g_log_fallback_handler (log_domain, log_level, message, unused_data);
891       return;
892     }
893
894   g_messages_prefixed_init ();
895
896   fd = mklevel_prefix (level_prefix, log_level);
897
898   gstring = g_string_new (NULL);
899   if (log_level & ALERT_LEVELS)
900     g_string_append (gstring, "\n");
901   if (!log_domain)
902     g_string_append (gstring, "** ");
903
904   if ((g_log_msg_prefix & log_level) == log_level)
905     {
906       const gchar *prg_name = g_get_prgname ();
907       
908       if (!prg_name)
909         g_string_append_printf (gstring, "(process:%lu): ", (gulong)getpid ());
910       else
911         g_string_append_printf (gstring, "(%s:%lu): ", prg_name, (gulong)getpid ());
912     }
913
914   if (log_domain)
915     {
916       g_string_append (gstring, log_domain);
917       g_string_append_c (gstring, '-');
918     }
919   g_string_append (gstring, level_prefix);
920
921   g_string_append (gstring, ": ");
922   if (!message)
923     g_string_append (gstring, "(NULL) message");
924   else
925     {
926       GString *msg;
927       const gchar *charset;
928
929       msg = g_string_new (message);
930       escape_string (msg);
931
932       if (g_get_charset (&charset))
933         g_string_append (gstring, msg->str);    /* charset is UTF-8 already */
934       else
935         {
936           string = strdup_convert (msg->str, charset);
937           g_string_append (gstring, string);
938           g_free (string);
939         }
940
941       g_string_free (msg, TRUE);
942     }
943   if (is_fatal)
944     g_string_append (gstring, "\naborting...\n");
945   else
946     g_string_append (gstring, "\n");
947
948   string = g_string_free (gstring, FALSE);
949
950   write_string (fd, string);
951   g_free (string);
952 }
953
954 GPrintFunc
955 g_set_print_handler (GPrintFunc func)
956 {
957   GPrintFunc old_print_func;
958   
959   g_mutex_lock (g_messages_lock);
960   old_print_func = glib_print_func;
961   glib_print_func = func;
962   g_mutex_unlock (g_messages_lock);
963   
964   return old_print_func;
965 }
966
967 void
968 g_print (const gchar *format,
969          ...)
970 {
971   va_list args;
972   gchar *string;
973   GPrintFunc local_glib_print_func;
974   
975   g_return_if_fail (format != NULL);
976   
977   va_start (args, format);
978   string = g_strdup_vprintf (format, args);
979   va_end (args);
980   
981   g_mutex_lock (g_messages_lock);
982   local_glib_print_func = glib_print_func;
983   g_mutex_unlock (g_messages_lock);
984   
985   if (local_glib_print_func)
986     local_glib_print_func (string);
987   else
988     {
989       const gchar *charset;
990
991       ensure_stdout_valid ();
992       if (g_get_charset (&charset))
993         fputs (string, stdout); /* charset is UTF-8 already */
994       else
995         {
996           gchar *lstring = strdup_convert (string, charset);
997
998           fputs (lstring, stdout);
999           g_free (lstring);
1000         }
1001       fflush (stdout);
1002     }
1003   g_free (string);
1004 }
1005
1006 GPrintFunc
1007 g_set_printerr_handler (GPrintFunc func)
1008 {
1009   GPrintFunc old_printerr_func;
1010   
1011   g_mutex_lock (g_messages_lock);
1012   old_printerr_func = glib_printerr_func;
1013   glib_printerr_func = func;
1014   g_mutex_unlock (g_messages_lock);
1015   
1016   return old_printerr_func;
1017 }
1018
1019 void
1020 g_printerr (const gchar *format,
1021             ...)
1022 {
1023   va_list args;
1024   gchar *string;
1025   GPrintFunc local_glib_printerr_func;
1026   
1027   g_return_if_fail (format != NULL);
1028   
1029   va_start (args, format);
1030   string = g_strdup_vprintf (format, args);
1031   va_end (args);
1032   
1033   g_mutex_lock (g_messages_lock);
1034   local_glib_printerr_func = glib_printerr_func;
1035   g_mutex_unlock (g_messages_lock);
1036   
1037   if (local_glib_printerr_func)
1038     local_glib_printerr_func (string);
1039   else
1040     {
1041       const gchar *charset;
1042
1043       ensure_stderr_valid ();
1044       if (g_get_charset (&charset))
1045         fputs (string, stderr); /* charset is UTF-8 already */
1046       else
1047         {
1048           gchar *lstring = strdup_convert (string, charset);
1049
1050           fputs (lstring, stderr);
1051           g_free (lstring);
1052         }
1053       fflush (stderr);
1054     }
1055   g_free (string);
1056 }
1057
1058 gsize
1059 g_printf_string_upper_bound (const gchar *format,
1060                              va_list      args)
1061 {
1062   gchar c;
1063   return _g_vsnprintf (&c, 1, format, args) + 1;
1064 }
1065
1066 void
1067 _g_messages_thread_init (void)
1068 {
1069   g_messages_lock = g_mutex_new ();
1070   g_messages_prefixed_init ();
1071   _g_debug_init ();
1072 }
1073
1074 void
1075 _g_messages_thread_private_init (void)
1076 {
1077   g_assert (g_log_depth == NULL);
1078   g_log_depth = g_private_new (NULL);
1079 }
1080
1081 gboolean _g_debug_initialized = FALSE;
1082 guint _g_debug_flags = 0;
1083
1084 void
1085 _g_debug_init (void) 
1086 {
1087   const gchar *val;
1088   
1089   _g_debug_initialized = TRUE;
1090   
1091   val = g_getenv ("G_DEBUG");
1092   if (val != NULL)
1093     {
1094       static const GDebugKey keys[] = {
1095         {"fatal_warnings", G_DEBUG_FATAL_WARNINGS}
1096       };
1097       
1098       _g_debug_flags = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
1099     }
1100   
1101   if (_g_debug_flags & G_DEBUG_FATAL_WARNINGS) 
1102     {
1103       GLogLevelFlags fatal_mask;
1104       
1105       fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
1106       fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
1107       g_log_set_always_fatal (fatal_mask);
1108     }
1109 }