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