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