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