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