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