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