Merge in current Win32 version. Almost no Unix code touched.
[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 #endif /* NATIVE_WIN32 */
54
55 static void
56 ensure_stdout_valid (void)
57 {
58 #ifdef NATIVE_WIN32
59   HANDLE handle;
60
61   handle = GetStdHandle (STD_OUTPUT_HANDLE);
62   
63   if (handle == INVALID_HANDLE_VALUE)
64     {
65       AllocConsole ();
66       freopen ("CONOUT$", "w", stdout);
67     }
68 #endif
69 }
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   ensure_stdout_valid ();
433 #else
434   fd = (log_level >= G_LOG_LEVEL_MESSAGE) ? 1 : 2;
435 #endif
436   
437   g_mutex_lock (g_messages_lock);
438   local_glib_error_func = glib_error_func;
439   local_glib_warning_func = glib_warning_func;
440   local_glib_message_func = glib_message_func;
441   g_mutex_unlock (g_messages_lock);
442
443   switch (log_level)
444     {
445     case G_LOG_LEVEL_ERROR:
446       if (!log_domain && local_glib_error_func)
447         {
448           /* compatibility code */
449           local_glib_error_func (message);  
450           return;
451         }
452       /* use write(2) for output, in case we are out of memeory */
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       if (log_domain)
473         {
474           write (fd, "\n", 1);
475           write (fd, log_domain, strlen (log_domain));
476           write (fd, "-", 1);
477         }
478       else
479         write (fd, "\n** ", 4);
480       if (in_recursion)
481         write (fd, "CRITICAL (recursed) **: ", 24);
482       else
483         write (fd, "CRITICAL **: ", 13);
484       write (fd, message, strlen(message));
485       if (is_fatal)
486         write (fd, "\naborting...\n", 13);
487       else
488         write (fd, "\n", 1);
489       break;
490     case G_LOG_LEVEL_WARNING:
491       if (!log_domain && local_glib_warning_func)
492         {
493           /* compatibility code */
494           local_glib_warning_func (message);
495           return;
496         }
497       if (log_domain)
498         {
499           write (fd, "\n", 1);
500           write (fd, log_domain, strlen (log_domain));
501           write (fd, "-", 1);
502         }
503       else
504         write (fd, "\n** ", 4);
505       if (in_recursion)
506         write (fd, "WARNING (recursed) **: ", 23);
507       else
508         write (fd, "WARNING **: ", 12);
509       write (fd, message, strlen(message));
510       if (is_fatal)
511         write (fd, "\naborting...\n", 13);
512       else
513         write (fd, "\n", 1);
514       break;
515     case G_LOG_LEVEL_MESSAGE:
516       if (!log_domain && local_glib_message_func)
517         {
518           /* compatibility code */
519           local_glib_message_func (message);
520           return;
521         }
522       if (log_domain)
523         {
524           write (fd, log_domain, strlen (log_domain));
525           write (fd, "-", 1);
526         }
527       if (in_recursion)
528         write (fd, "Message (recursed): ", 20);
529       else
530         write (fd, "Message: ", 9);
531       write (fd, message, strlen(message));
532       if (is_fatal)
533         write (fd, "\naborting...\n", 13);
534       else
535         write (fd, "\n", 1);
536       break;
537     case G_LOG_LEVEL_INFO:
538       if (log_domain)
539         {
540           write (fd, log_domain, strlen (log_domain));
541           write (fd, "-", 1);
542         }
543       if (in_recursion)
544         write (fd, "INFO (recursed): ", 17);
545       else
546         write (fd, "INFO: ", 6);
547       write (fd, message, strlen(message));
548       if (is_fatal)
549         write (fd, "\naborting...\n", 13);
550       else
551         write (fd, "\n", 1);
552       break;
553     case G_LOG_LEVEL_DEBUG:
554       if (log_domain)
555         {
556           write (fd, log_domain, strlen (log_domain));
557           write (fd, "-", 1);
558         }
559       if (in_recursion)
560         write (fd, "DEBUG (recursed): ", 18);
561       else
562         write (fd, "DEBUG: ", 7);
563       write (fd, message, strlen(message));
564       if (is_fatal)
565         write (fd, "\naborting...\n", 13);
566       else
567         write (fd, "\n", 1);
568       break;
569     default:
570       /* we are used for a log level that is not defined by GLib itself,
571        * try to make the best out of it.
572        */
573       if (log_domain)
574         {
575           write (fd, log_domain, strlen (log_domain));
576           if (in_recursion)
577             write (fd, "-LOG (recursed:", 15);
578           else
579             write (fd, "-LOG (", 6);
580         }
581       else if (in_recursion)
582         write (fd, "LOG (recursed:", 14);
583       else
584         write (fd, "LOG (", 5);
585       if (log_level)
586         {
587           gchar string[] = "0x00): ";
588           gchar *p = string + 2;
589           guint i;
590           
591           i = g_bit_nth_msf (log_level, -1);
592           *p = i >> 4;
593           p++;
594           *p = '0' + (i & 0xf);
595           if (*p > '9')
596             *p += 'A' - '9' - 1;
597           
598           write (fd, string, 7);
599         }
600       else
601         write (fd, "): ", 3);
602       write (fd, message, strlen(message));
603       if (is_fatal)
604         write (fd, "\naborting...\n", 13);
605       else
606         write (fd, "\n", 1);
607       break;
608     }
609 }
610
611 GPrintFunc
612 g_set_print_handler (GPrintFunc func)
613 {
614   GPrintFunc old_print_func;
615   
616   g_mutex_lock (g_messages_lock);
617   old_print_func = glib_print_func;
618   glib_print_func = func;
619   g_mutex_unlock (g_messages_lock);
620   
621   return old_print_func;
622 }
623
624 void
625 g_print (const gchar *format,
626          ...)
627 {
628   va_list args;
629   gchar *string;
630   GPrintFunc local_glib_print_func;
631   
632   g_return_if_fail (format != NULL);
633   
634   va_start (args, format);
635   string = g_strdup_vprintf (format, args);
636   va_end (args);
637   
638   g_mutex_lock (g_messages_lock);
639   local_glib_print_func = glib_print_func;
640   g_mutex_unlock (g_messages_lock);
641
642   if (local_glib_print_func)
643     local_glib_print_func (string);
644   else
645     {
646       ensure_stdout_valid ();
647       fputs (string, stdout);
648       fflush (stdout);
649     }
650   g_free (string);
651 }
652
653 GPrintFunc
654 g_set_printerr_handler (GPrintFunc func)
655 {
656   GPrintFunc old_printerr_func;
657   
658   g_mutex_lock (g_messages_lock);
659   old_printerr_func = glib_printerr_func;
660   glib_printerr_func = func;
661   g_mutex_unlock (g_messages_lock);
662   
663   return old_printerr_func;
664 }
665
666 void
667 g_printerr (const gchar *format,
668             ...)
669 {
670   va_list args;
671   gchar *string;
672   GPrintFunc local_glib_printerr_func;
673   
674   g_return_if_fail (format != NULL);
675   
676   va_start (args, format);
677   string = g_strdup_vprintf (format, args);
678   va_end (args);
679   
680   g_mutex_lock (g_messages_lock);
681   local_glib_printerr_func = glib_printerr_func;
682   g_mutex_unlock (g_messages_lock);
683
684   if (local_glib_printerr_func)
685     local_glib_printerr_func (string);
686   else
687     {
688       fputs (string, stderr);
689       fflush (stderr);
690     }
691   g_free (string);
692 }
693
694 /* compatibility code */
695 GErrorFunc
696 g_set_error_handler (GErrorFunc func)
697 {
698   GErrorFunc old_error_func;
699   
700   g_mutex_lock (g_messages_lock);
701   old_error_func = glib_error_func;
702   glib_error_func = func;
703   g_mutex_unlock (g_messages_lock);
704  
705   return old_error_func;
706 }
707
708 /* compatibility code */
709 GWarningFunc
710 g_set_warning_handler (GWarningFunc func)
711 {
712   GWarningFunc old_warning_func;
713   
714   g_mutex_lock (g_messages_lock);
715   old_warning_func = glib_warning_func;
716   glib_warning_func = func;
717   g_mutex_unlock (g_messages_lock);
718   
719   return old_warning_func;
720 }
721
722 /* compatibility code */
723 GPrintFunc
724 g_set_message_handler (GPrintFunc func)
725 {
726   GPrintFunc old_message_func;
727   
728   g_mutex_lock (g_messages_lock);
729   old_message_func = glib_message_func;
730   glib_message_func = func;
731   g_mutex_unlock (g_messages_lock);
732   
733   return old_message_func;
734 }
735
736 void
737 g_messages_init (void)
738 {
739   g_messages_lock = g_mutex_new();
740   g_log_depth = g_private_new(NULL);
741 }