Don't call ensure_stdout_valid (which would open an unneeded console
[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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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  * MT safe
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include "glib.h"
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36
37 #ifdef NATIVE_WIN32
38 #define STRICT
39 #include <windows.h>
40
41 /* Just use stdio. If we're out of memory, we're hosed anyway. */
42 #undef write
43
44 static inline int
45 write (FILE       *fd,
46        const char *buf,
47        int         len)
48 {
49   fwrite (buf, len, 1, fd);
50
51   return len;
52 }
53
54 static void
55 ensure_stdout_valid (void)
56 {
57   HANDLE handle;
58
59   handle = GetStdHandle (STD_OUTPUT_HANDLE);
60   
61   if (handle == INVALID_HANDLE_VALUE)
62     {
63       AllocConsole ();
64       freopen ("CONOUT$", "w", stdout);
65     }
66 }
67 #else
68 #define ensure_stdout_valid()   /* Define as empty */
69 #endif
70         
71
72 /* --- structures --- */
73 typedef struct _GLogDomain      GLogDomain;
74 typedef struct _GLogHandler     GLogHandler;
75 struct _GLogDomain
76 {
77   gchar         *log_domain;
78   GLogLevelFlags fatal_mask;
79   GLogHandler   *handlers;
80   GLogDomain    *next;
81 };
82 struct _GLogHandler
83 {
84   guint          id;
85   GLogLevelFlags log_level;
86   GLogFunc       log_func;
87   gpointer       data;
88   GLogHandler   *next;
89 };
90
91
92 /* --- variables --- */
93
94 static GMutex* g_messages_lock = NULL;
95
96 const gchar          *g_log_domain_glib = "GLib";
97 static GLogDomain    *g_log_domains = NULL;
98 static GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK;
99 static GPrintFunc     glib_print_func = NULL;
100 static GPrintFunc     glib_printerr_func = NULL;
101 static GErrorFunc     glib_error_func = NULL;
102 static GWarningFunc   glib_warning_func = NULL;
103 static GPrintFunc     glib_message_func = NULL;
104
105 static GPrivate* g_log_depth = NULL;
106
107
108 /* --- functions --- */
109 static inline GLogDomain*
110 g_log_find_domain (const gchar    *log_domain)
111 {
112   register GLogDomain *domain;
113   
114   g_mutex_lock (g_messages_lock);
115   domain = g_log_domains;
116   while (domain)
117     {
118       if (strcmp (domain->log_domain, log_domain) == 0)
119         {
120           g_mutex_unlock (g_messages_lock);
121           return domain;
122         }
123       domain = domain->next;
124     }
125   g_mutex_unlock (g_messages_lock);
126   return NULL;
127 }
128
129 static inline GLogDomain*
130 g_log_domain_new (const gchar *log_domain)
131 {
132   register GLogDomain *domain;
133
134   domain = g_new (GLogDomain, 1);
135   domain->log_domain = g_strdup (log_domain);
136   domain->fatal_mask = G_LOG_FATAL_MASK;
137   domain->handlers = NULL;
138   
139   g_mutex_lock (g_messages_lock);
140   domain->next = g_log_domains;
141   g_log_domains = domain;
142   g_mutex_unlock (g_messages_lock);
143   
144   return domain;
145 }
146
147 static inline void
148 g_log_domain_check_free (GLogDomain *domain)
149 {
150   if (domain->fatal_mask == G_LOG_FATAL_MASK &&
151       domain->handlers == NULL)
152     {
153       register GLogDomain *last, *work;
154       
155       last = NULL;  
156
157       g_mutex_lock (g_messages_lock);
158       work = g_log_domains;
159       while (work)
160         {
161           if (work == domain)
162             {
163               if (last)
164                 last->next = domain->next;
165               else
166                 g_log_domains = domain->next;
167               g_free (domain->log_domain);
168               g_free (domain);
169               break;
170             }
171           work = work->next;
172         }  
173       g_mutex_unlock (g_messages_lock);
174     }
175 }
176
177 static inline GLogFunc
178 g_log_domain_get_handler (GLogDomain    *domain,
179                           GLogLevelFlags log_level,
180                           gpointer      *data)
181 {
182   if (domain && log_level)
183     {
184       register GLogHandler *handler;
185       
186       handler = domain->handlers;
187       while (handler)
188         {
189           if ((handler->log_level & log_level) == log_level)
190             {
191               *data = handler->data;
192               return handler->log_func;
193             }
194           handler = handler->next;
195         }
196     }
197   return g_log_default_handler;
198 }
199
200 GLogLevelFlags
201 g_log_set_always_fatal (GLogLevelFlags fatal_mask)
202 {
203   GLogLevelFlags old_mask;
204
205   /* restrict the global mask to levels that are known to glib */
206   fatal_mask &= (1 << G_LOG_LEVEL_USER_SHIFT) - 1;
207   /* force errors to be fatal */
208   fatal_mask |= G_LOG_LEVEL_ERROR;
209   /* remove bogus flag */
210   fatal_mask &= ~G_LOG_FLAG_FATAL;
211
212   g_mutex_lock (g_messages_lock);
213   old_mask = g_log_always_fatal;
214   g_log_always_fatal = fatal_mask;
215   g_mutex_unlock (g_messages_lock);
216
217   return old_mask;
218 }
219
220 GLogLevelFlags
221 g_log_set_fatal_mask (const gchar    *log_domain,
222                       GLogLevelFlags  fatal_mask)
223 {
224   GLogLevelFlags old_flags;
225   register GLogDomain *domain;
226   
227   if (!log_domain)
228     log_domain = "";
229   
230   /* force errors to be fatal */
231   fatal_mask |= G_LOG_LEVEL_ERROR;
232   /* remove bogus flag */
233   fatal_mask &= ~G_LOG_FLAG_FATAL;
234   
235   domain = g_log_find_domain (log_domain);
236   if (!domain)
237     domain = g_log_domain_new (log_domain);
238   old_flags = domain->fatal_mask;
239   
240   domain->fatal_mask = fatal_mask;
241   g_log_domain_check_free (domain);
242   
243   return old_flags;
244 }
245
246 guint
247 g_log_set_handler (const gchar    *log_domain,
248                    GLogLevelFlags  log_levels,
249                    GLogFunc        log_func,
250                    gpointer        user_data)
251 {
252   register GLogDomain *domain;
253   register GLogHandler *handler;
254   static guint handler_id = 0;
255   
256   g_return_val_if_fail ((log_levels & G_LOG_LEVEL_MASK) != 0, 0);
257   g_return_val_if_fail (log_func != NULL, 0);
258   
259   if (!log_domain)
260     log_domain = "";
261   
262   domain = g_log_find_domain (log_domain);
263   if (!domain)
264     domain = g_log_domain_new (log_domain);
265   
266   handler = g_new (GLogHandler, 1);
267   g_mutex_lock (g_messages_lock);
268   handler->id = ++handler_id;
269   g_mutex_unlock (g_messages_lock);
270   handler->log_level = log_levels;
271   handler->log_func = log_func;
272   handler->data = user_data;
273   handler->next = domain->handlers;
274   domain->handlers = handler;
275   
276   return handler_id;
277 }
278
279 void
280 g_log_remove_handler (const gchar    *log_domain,
281                       guint           handler_id)
282 {
283   register GLogDomain *domain;
284   
285   g_return_if_fail (handler_id > 0);
286   
287   if (!log_domain)
288     log_domain = "";
289   
290   domain = g_log_find_domain (log_domain);
291   if (domain)
292     {
293       register GLogHandler *work, *last;
294       
295       last = NULL;
296       work = domain->handlers;
297       while (work)
298         {
299           if (work->id == handler_id)
300             {
301               if (last)
302                 last->next = work->next;
303               else
304                 domain->handlers = work->next;
305               g_free (work);
306               g_log_domain_check_free (domain);
307               return;
308             }
309           work = work->next;
310         }
311     }
312   g_warning ("g_log_remove_handler(): could not find handler with id `%d' for domain \"%s\"",
313              handler_id,
314              log_domain);
315 }
316
317 void
318 g_logv (const gchar    *log_domain,
319         GLogLevelFlags  log_level,
320         const gchar    *format,
321         va_list         args1)
322 {
323   va_list args2;
324   gchar buffer[1025];
325   register gint i;
326   
327   log_level &= G_LOG_LEVEL_MASK;
328   if (!log_level)
329     return;
330   
331   /* we use a stack buffer of fixed size, because we might get called
332    * recursively.
333    */
334   G_VA_COPY (args2, args1);
335   if (g_printf_string_upper_bound (format, args1) < 1024)
336     vsprintf (buffer, format, args2);
337   else
338     {
339       /* since we might be out of memory, we can't use g_vsnprintf(). */
340 #ifdef  HAVE_VSNPRINTF
341       vsnprintf (buffer, 1024, format, args2);
342 #else   /* !HAVE_VSNPRINTF */
343       /* we are out of luck here */
344       strncpy (buffer, format, 1024);
345 #endif  /* !HAVE_VSNPRINTF */
346       buffer[1024] = 0;
347     }
348   va_end (args2);
349   
350   for (i = g_bit_nth_msf (log_level, -1); i >= 0; i = g_bit_nth_msf (log_level, i))
351     {
352       register GLogLevelFlags test_level;
353       
354       test_level = 1 << i;
355       if (log_level & test_level)
356         {
357           guint depth = GPOINTER_TO_UINT (g_private_get (g_log_depth));
358           GLogDomain *domain;
359           GLogFunc log_func;
360           gpointer data = NULL;
361           
362           domain = g_log_find_domain (log_domain ? log_domain : "");
363           
364           if (depth)
365             test_level |= G_LOG_FLAG_RECURSION;
366           
367           depth++;
368           g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
369
370           g_mutex_lock (g_messages_lock);
371           if ((((domain ? domain->fatal_mask : G_LOG_FATAL_MASK) | 
372                 g_log_always_fatal) & test_level) != 0)
373             test_level |= G_LOG_FLAG_FATAL;  
374           g_mutex_unlock (g_messages_lock);
375
376           log_func = g_log_domain_get_handler (domain, test_level, &data);
377           log_func (log_domain, test_level, buffer, data);
378           
379           /* *domain can be cluttered now */
380           
381           if (test_level & G_LOG_FLAG_FATAL)
382             abort ();
383           
384           depth--;
385           g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
386         }
387     }
388 }
389
390 void
391 g_log (const gchar    *log_domain,
392        GLogLevelFlags  log_level,
393        const gchar    *format,
394        ...)
395 {
396   va_list args;
397   
398   va_start (args, format);
399   g_logv (log_domain, log_level, format, args);
400   va_end (args);
401 }
402
403 void
404 g_log_default_handler (const gchar    *log_domain,
405                        GLogLevelFlags  log_level,
406                        const gchar    *message,
407                        gpointer        unused_data)
408 {
409 #ifdef NATIVE_WIN32
410   FILE *fd;
411 #else
412   gint fd;
413 #endif
414   gboolean in_recursion;
415   gboolean is_fatal;  
416   GErrorFunc     local_glib_error_func;
417   GWarningFunc   local_glib_warning_func;
418   GPrintFunc     local_glib_message_func;
419
420   in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
421   is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
422   log_level &= G_LOG_LEVEL_MASK;
423   
424   if (!message)
425     message = "g_log_default_handler(): (NULL) message";
426   
427 #ifdef NATIVE_WIN32
428   /* Use just stdout as stderr is hard to get redirected from the
429    * DOS prompt.
430    */
431   fd = stdout;
432 #else
433   fd = (log_level >= G_LOG_LEVEL_MESSAGE) ? 1 : 2;
434 #endif
435   
436   g_mutex_lock (g_messages_lock);
437   local_glib_error_func = glib_error_func;
438   local_glib_warning_func = glib_warning_func;
439   local_glib_message_func = glib_message_func;
440   g_mutex_unlock (g_messages_lock);
441
442   switch (log_level)
443     {
444     case G_LOG_LEVEL_ERROR:
445       if (!log_domain && local_glib_error_func)
446         {
447           /* compatibility code */
448           local_glib_error_func (message);  
449           return;
450         }
451       /* use write(2) for output, in case we are out of memeory */
452       ensure_stdout_valid ();
453       if (log_domain)
454         {
455           write (fd, "\n", 1);
456           write (fd, log_domain, strlen (log_domain));
457           write (fd, "-", 1);
458         }
459       else
460         write (fd, "\n** ", 4);
461       if (in_recursion)
462         write (fd, "ERROR (recursed) **: ", 21);
463       else
464         write (fd, "ERROR **: ", 10);
465       write (fd, message, strlen(message));
466       if (is_fatal)
467         write (fd, "\naborting...\n", 13);
468       else
469         write (fd, "\n", 1);
470       break;
471     case G_LOG_LEVEL_CRITICAL:
472       ensure_stdout_valid ();
473       if (log_domain)
474         {
475           write (fd, "\n", 1);
476           write (fd, log_domain, strlen (log_domain));
477           write (fd, "-", 1);
478         }
479       else
480         write (fd, "\n** ", 4);
481       if (in_recursion)
482         write (fd, "CRITICAL (recursed) **: ", 24);
483       else
484         write (fd, "CRITICAL **: ", 13);
485       write (fd, message, strlen(message));
486       if (is_fatal)
487         write (fd, "\naborting...\n", 13);
488       else
489         write (fd, "\n", 1);
490       break;
491     case G_LOG_LEVEL_WARNING:
492       if (!log_domain && local_glib_warning_func)
493         {
494           /* compatibility code */
495           local_glib_warning_func (message);
496           return;
497         }
498       ensure_stdout_valid ();
499       if (log_domain)
500         {
501           write (fd, "\n", 1);
502           write (fd, log_domain, strlen (log_domain));
503           write (fd, "-", 1);
504         }
505       else
506         write (fd, "\n** ", 4);
507       if (in_recursion)
508         write (fd, "WARNING (recursed) **: ", 23);
509       else
510         write (fd, "WARNING **: ", 12);
511       write (fd, message, strlen(message));
512       if (is_fatal)
513         write (fd, "\naborting...\n", 13);
514       else
515         write (fd, "\n", 1);
516       break;
517     case G_LOG_LEVEL_MESSAGE:
518       if (!log_domain && local_glib_message_func)
519         {
520           /* compatibility code */
521           local_glib_message_func (message);
522           return;
523         }
524       ensure_stdout_valid ();
525       if (log_domain)
526         {
527           write (fd, log_domain, strlen (log_domain));
528           write (fd, "-", 1);
529         }
530       if (in_recursion)
531         write (fd, "Message (recursed): ", 20);
532       else
533         write (fd, "Message: ", 9);
534       write (fd, message, strlen(message));
535       if (is_fatal)
536         write (fd, "\naborting...\n", 13);
537       else
538         write (fd, "\n", 1);
539       break;
540     case G_LOG_LEVEL_INFO:
541       ensure_stdout_valid ();
542       if (log_domain)
543         {
544           write (fd, log_domain, strlen (log_domain));
545           write (fd, "-", 1);
546         }
547       if (in_recursion)
548         write (fd, "INFO (recursed): ", 17);
549       else
550         write (fd, "INFO: ", 6);
551       write (fd, message, strlen(message));
552       if (is_fatal)
553         write (fd, "\naborting...\n", 13);
554       else
555         write (fd, "\n", 1);
556       break;
557     case G_LOG_LEVEL_DEBUG:
558       ensure_stdout_valid ();
559       if (log_domain)
560         {
561           write (fd, log_domain, strlen (log_domain));
562           write (fd, "-", 1);
563         }
564       if (in_recursion)
565         write (fd, "DEBUG (recursed): ", 18);
566       else
567         write (fd, "DEBUG: ", 7);
568       write (fd, message, strlen(message));
569       if (is_fatal)
570         write (fd, "\naborting...\n", 13);
571       else
572         write (fd, "\n", 1);
573       break;
574     default:
575       /* we are used for a log level that is not defined by GLib itself,
576        * try to make the best out of it.
577        */
578       ensure_stdout_valid ();
579       if (log_domain)
580         {
581           write (fd, log_domain, strlen (log_domain));
582           if (in_recursion)
583             write (fd, "-LOG (recursed:", 15);
584           else
585             write (fd, "-LOG (", 6);
586         }
587       else if (in_recursion)
588         write (fd, "LOG (recursed:", 14);
589       else
590         write (fd, "LOG (", 5);
591       if (log_level)
592         {
593           gchar string[] = "0x00): ";
594           gchar *p = string + 2;
595           guint i;
596           
597           i = g_bit_nth_msf (log_level, -1);
598           *p = i >> 4;
599           p++;
600           *p = '0' + (i & 0xf);
601           if (*p > '9')
602             *p += 'A' - '9' - 1;
603           
604           write (fd, string, 7);
605         }
606       else
607         write (fd, "): ", 3);
608       write (fd, message, strlen(message));
609       if (is_fatal)
610         write (fd, "\naborting...\n", 13);
611       else
612         write (fd, "\n", 1);
613       break;
614     }
615 }
616
617 GPrintFunc
618 g_set_print_handler (GPrintFunc func)
619 {
620   GPrintFunc old_print_func;
621   
622   g_mutex_lock (g_messages_lock);
623   old_print_func = glib_print_func;
624   glib_print_func = func;
625   g_mutex_unlock (g_messages_lock);
626   
627   return old_print_func;
628 }
629
630 void
631 g_print (const gchar *format,
632          ...)
633 {
634   va_list args;
635   gchar *string;
636   GPrintFunc local_glib_print_func;
637   
638   g_return_if_fail (format != NULL);
639   
640   va_start (args, format);
641   string = g_strdup_vprintf (format, args);
642   va_end (args);
643   
644   g_mutex_lock (g_messages_lock);
645   local_glib_print_func = glib_print_func;
646   g_mutex_unlock (g_messages_lock);
647
648   if (local_glib_print_func)
649     local_glib_print_func (string);
650   else
651     {
652       ensure_stdout_valid ();
653       fputs (string, stdout);
654       fflush (stdout);
655     }
656   g_free (string);
657 }
658
659 GPrintFunc
660 g_set_printerr_handler (GPrintFunc func)
661 {
662   GPrintFunc old_printerr_func;
663   
664   g_mutex_lock (g_messages_lock);
665   old_printerr_func = glib_printerr_func;
666   glib_printerr_func = func;
667   g_mutex_unlock (g_messages_lock);
668   
669   return old_printerr_func;
670 }
671
672 void
673 g_printerr (const gchar *format,
674             ...)
675 {
676   va_list args;
677   gchar *string;
678   GPrintFunc local_glib_printerr_func;
679   
680   g_return_if_fail (format != NULL);
681   
682   va_start (args, format);
683   string = g_strdup_vprintf (format, args);
684   va_end (args);
685   
686   g_mutex_lock (g_messages_lock);
687   local_glib_printerr_func = glib_printerr_func;
688   g_mutex_unlock (g_messages_lock);
689
690   if (local_glib_printerr_func)
691     local_glib_printerr_func (string);
692   else
693     {
694       fputs (string, stderr);
695       fflush (stderr);
696     }
697   g_free (string);
698 }
699
700 /* compatibility code */
701 GErrorFunc
702 g_set_error_handler (GErrorFunc func)
703 {
704   GErrorFunc old_error_func;
705   
706   g_mutex_lock (g_messages_lock);
707   old_error_func = glib_error_func;
708   glib_error_func = func;
709   g_mutex_unlock (g_messages_lock);
710  
711   return old_error_func;
712 }
713
714 /* compatibility code */
715 GWarningFunc
716 g_set_warning_handler (GWarningFunc func)
717 {
718   GWarningFunc old_warning_func;
719   
720   g_mutex_lock (g_messages_lock);
721   old_warning_func = glib_warning_func;
722   glib_warning_func = func;
723   g_mutex_unlock (g_messages_lock);
724   
725   return old_warning_func;
726 }
727
728 /* compatibility code */
729 GPrintFunc
730 g_set_message_handler (GPrintFunc func)
731 {
732   GPrintFunc old_message_func;
733   
734   g_mutex_lock (g_messages_lock);
735   old_message_func = glib_message_func;
736   glib_message_func = func;
737   g_mutex_unlock (g_messages_lock);
738   
739   return old_message_func;
740 }
741
742 void
743 g_messages_init (void)
744 {
745   g_messages_lock = g_mutex_new();
746   g_log_depth = g_private_new(NULL);
747 }