Add test case for the g_qsort_with_data func. It works. This fixes bug
[glib.git] / gmessages.c
blobd99413ddc0d63f961b003a5359edae6f7f466b78
1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser 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.
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 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser 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.
21 * Modified by the GLib Team and others 1997-2000. 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/.
27 /*
28 * MT safe
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
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 #include <signal.h>
44 #include <locale.h>
45 #include <errno.h>
47 #ifdef G_OS_WIN32
48 typedef FILE* GFileDescriptor;
49 #else
50 typedef gint GFileDescriptor;
51 #endif
53 /* --- structures --- */
54 typedef struct _GLogDomain GLogDomain;
55 typedef struct _GLogHandler GLogHandler;
56 struct _GLogDomain
58 gchar *log_domain;
59 GLogLevelFlags fatal_mask;
60 GLogHandler *handlers;
61 GLogDomain *next;
63 struct _GLogHandler
65 guint id;
66 GLogLevelFlags log_level;
67 GLogFunc log_func;
68 gpointer data;
69 GLogHandler *next;
73 /* --- prototypes --- */
74 static inline guint printf_string_upper_bound (const gchar *format,
75 gboolean may_warn,
76 va_list args);
79 /* --- variables --- */
81 static GMutex* g_messages_lock = NULL;
83 const gchar *g_log_domain_glib = "GLib";
84 static GLogDomain *g_log_domains = NULL;
85 static GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK;
86 static GPrintFunc glib_print_func = NULL;
87 static GPrintFunc glib_printerr_func = NULL;
88 static GErrorFunc glib_error_func = NULL;
89 static GWarningFunc glib_warning_func = NULL;
90 static GPrintFunc glib_message_func = NULL;
92 static GPrivate* g_log_depth = NULL;
94 /* --- functions --- */
95 #ifdef G_OS_WIN32
96 # define STRICT
97 # include <windows.h>
98 # undef STRICT
99 # include <process.h> /* For _getpid() */
101 static gboolean alloc_console_called = FALSE;
103 static gboolean gonna_abort = FALSE;
105 /* This default message will usually be overwritten. */
106 /* Yes, a fixed size buffer is bad. So sue me. But g_error is never
107 * with huge strings, is it? */
108 static char fatal_msg_buf[1000] = "Unspecified fatal error encountered, aborting.";
109 static char *fatal_msg_ptr = fatal_msg_buf;
111 /* Just use stdio. If we're out of memory, we're hosed anyway. */
112 #undef write
113 static inline int
114 dowrite (GFileDescriptor fd,
115 const void *buf,
116 unsigned int len)
118 if (gonna_abort)
120 memcpy (fatal_msg_ptr, buf, len);
121 fatal_msg_ptr += len;
122 *fatal_msg_ptr = 0;
123 return len;
126 fwrite (buf, len, 1, fd);
127 fflush (fd);
129 return len;
132 #define write(fd, buf, len) dowrite(fd, buf, len)
134 static void
135 ensure_stdout_valid (void)
137 HANDLE handle;
139 if (gonna_abort)
140 return;
142 if (!alloc_console_called)
144 handle = GetStdHandle (STD_OUTPUT_HANDLE);
146 if (handle == INVALID_HANDLE_VALUE)
148 AllocConsole ();
149 alloc_console_called = TRUE;
150 freopen ("CONOUT$", "w", stdout);
154 #else
155 #define ensure_stdout_valid() /* Define as empty */
156 #endif
158 static void
159 write_unsigned (GFileDescriptor fd,
160 gulong num,
161 guint radix)
163 char buffer[64];
164 gulong tmp;
165 char c;
166 int i, n;
168 g_return_if_fail (radix >= 2 && radix <= 36);
170 if (!num)
172 write (fd, "0", 1);
173 return;
176 if (radix == 16)
177 write (fd, "0x", 2);
178 else if (radix == 8)
179 write (fd, "0", 1);
181 n = 0;
182 tmp = num;
183 while (tmp)
185 tmp /= radix;
186 n++;
189 i = n;
190 while (num)
192 i--;
193 c = (num % radix);
194 if (c < 10)
195 buffer[i] = c + '0';
196 else
197 buffer[i] = c + 'a' - 10;
198 num /= radix;
201 write (fd, buffer, n);
204 static void
205 write_string (GFileDescriptor fd,
206 gchar *string)
208 write (fd, string, strlen (string));
211 static void
212 g_log_write_prefix (GFileDescriptor fd,
213 GLogLevelFlags mask)
215 static GLogLevelFlags g_log_msg_prefix = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG;
216 static gboolean initialized = FALSE;
218 g_mutex_lock (g_messages_lock);
220 if (!initialized)
222 const gchar *val;
223 initialized = TRUE;
225 val = g_getenv ("G_MESSAGES_PREFIXED");
227 if (val)
229 static const GDebugKey keys[] = {
230 { "error", G_LOG_LEVEL_ERROR },
231 { "critical", G_LOG_LEVEL_CRITICAL },
232 { "warning", G_LOG_LEVEL_WARNING },
233 { "message", G_LOG_LEVEL_MESSAGE },
234 { "info", G_LOG_LEVEL_INFO },
235 { "debug", G_LOG_LEVEL_DEBUG }
238 g_log_msg_prefix = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
242 g_mutex_unlock (g_messages_lock);
244 if ((g_log_msg_prefix & mask) == mask)
246 gchar *prg_name;
248 prg_name = g_get_prgname ();
250 if (!prg_name)
251 write_string (fd, "(process:");
252 else
254 write_string (fd, prg_name);
255 write_string (fd, " (pid:");
258 write_unsigned (fd, getpid (), 10);
259 write_string (fd, "): ");
263 static inline GLogDomain*
264 g_log_find_domain (const gchar *log_domain)
266 register GLogDomain *domain;
268 g_mutex_lock (g_messages_lock);
269 domain = g_log_domains;
270 while (domain)
272 if (strcmp (domain->log_domain, log_domain) == 0)
274 g_mutex_unlock (g_messages_lock);
275 return domain;
277 domain = domain->next;
279 g_mutex_unlock (g_messages_lock);
280 return NULL;
283 static inline GLogDomain*
284 g_log_domain_new (const gchar *log_domain)
286 register GLogDomain *domain;
288 domain = g_new (GLogDomain, 1);
289 domain->log_domain = g_strdup (log_domain);
290 domain->fatal_mask = G_LOG_FATAL_MASK;
291 domain->handlers = NULL;
293 g_mutex_lock (g_messages_lock);
294 domain->next = g_log_domains;
295 g_log_domains = domain;
296 g_mutex_unlock (g_messages_lock);
298 return domain;
301 static inline void
302 g_log_domain_check_free (GLogDomain *domain)
304 if (domain->fatal_mask == G_LOG_FATAL_MASK &&
305 domain->handlers == NULL)
307 register GLogDomain *last, *work;
309 last = NULL;
311 g_mutex_lock (g_messages_lock);
312 work = g_log_domains;
313 while (work)
315 if (work == domain)
317 if (last)
318 last->next = domain->next;
319 else
320 g_log_domains = domain->next;
321 g_free (domain->log_domain);
322 g_free (domain);
323 break;
325 last = work;
326 work = last->next;
328 g_mutex_unlock (g_messages_lock);
332 static inline GLogFunc
333 g_log_domain_get_handler (GLogDomain *domain,
334 GLogLevelFlags log_level,
335 gpointer *data)
337 if (domain && log_level)
339 register GLogHandler *handler;
341 handler = domain->handlers;
342 while (handler)
344 if ((handler->log_level & log_level) == log_level)
346 *data = handler->data;
347 return handler->log_func;
349 handler = handler->next;
352 return g_log_default_handler;
355 GLogLevelFlags
356 g_log_set_always_fatal (GLogLevelFlags fatal_mask)
358 GLogLevelFlags old_mask;
360 /* restrict the global mask to levels that are known to glib */
361 fatal_mask &= (1 << G_LOG_LEVEL_USER_SHIFT) - 1;
362 /* force errors to be fatal */
363 fatal_mask |= G_LOG_LEVEL_ERROR;
364 /* remove bogus flag */
365 fatal_mask &= ~G_LOG_FLAG_FATAL;
367 g_mutex_lock (g_messages_lock);
368 old_mask = g_log_always_fatal;
369 g_log_always_fatal = fatal_mask;
370 g_mutex_unlock (g_messages_lock);
372 return old_mask;
375 GLogLevelFlags
376 g_log_set_fatal_mask (const gchar *log_domain,
377 GLogLevelFlags fatal_mask)
379 GLogLevelFlags old_flags;
380 register GLogDomain *domain;
382 if (!log_domain)
383 log_domain = "";
385 /* force errors to be fatal */
386 fatal_mask |= G_LOG_LEVEL_ERROR;
387 /* remove bogus flag */
388 fatal_mask &= ~G_LOG_FLAG_FATAL;
390 domain = g_log_find_domain (log_domain);
391 if (!domain)
392 domain = g_log_domain_new (log_domain);
393 old_flags = domain->fatal_mask;
395 domain->fatal_mask = fatal_mask;
396 g_log_domain_check_free (domain);
398 return old_flags;
401 guint
402 g_log_set_handler (const gchar *log_domain,
403 GLogLevelFlags log_levels,
404 GLogFunc log_func,
405 gpointer user_data)
407 register GLogDomain *domain;
408 register GLogHandler *handler;
409 static guint handler_id = 0;
411 g_return_val_if_fail ((log_levels & G_LOG_LEVEL_MASK) != 0, 0);
412 g_return_val_if_fail (log_func != NULL, 0);
414 if (!log_domain)
415 log_domain = "";
417 domain = g_log_find_domain (log_domain);
418 if (!domain)
419 domain = g_log_domain_new (log_domain);
421 handler = g_new (GLogHandler, 1);
422 g_mutex_lock (g_messages_lock);
423 handler->id = ++handler_id;
424 g_mutex_unlock (g_messages_lock);
425 handler->log_level = log_levels;
426 handler->log_func = log_func;
427 handler->data = user_data;
428 handler->next = domain->handlers;
429 domain->handlers = handler;
431 return handler_id;
434 void
435 g_log_remove_handler (const gchar *log_domain,
436 guint handler_id)
438 register GLogDomain *domain;
440 g_return_if_fail (handler_id > 0);
442 if (!log_domain)
443 log_domain = "";
445 domain = g_log_find_domain (log_domain);
446 if (domain)
448 register GLogHandler *work, *last;
450 last = NULL;
451 work = domain->handlers;
452 while (work)
454 if (work->id == handler_id)
456 if (last)
457 last->next = work->next;
458 else
459 domain->handlers = work->next;
460 g_free (work);
461 g_log_domain_check_free (domain);
462 return;
464 last = work;
465 work = last->next;
468 g_warning ("g_log_remove_handler(): could not find handler with id `%d' for domain \"%s\"",
469 handler_id,
470 log_domain);
473 void
474 g_logv (const gchar *log_domain,
475 GLogLevelFlags log_level,
476 const gchar *format,
477 va_list args1)
479 va_list args2;
480 gchar buffer[1025];
481 register gint i;
483 log_level &= G_LOG_LEVEL_MASK;
484 if (!log_level)
485 return;
487 /* we use a stack buffer of fixed size, because we might get called
488 * recursively.
490 G_VA_COPY (args2, args1);
491 if (printf_string_upper_bound (format, FALSE, args1) < 1024)
492 vsprintf (buffer, format, args2);
493 else
495 /* since we might be out of memory, we can't use g_vsnprintf(). */
496 #ifdef HAVE_VSNPRINTF
497 vsnprintf (buffer, 1024, format, args2);
498 #else /* !HAVE_VSNPRINTF */
499 /* we are out of luck here */
500 strncpy (buffer, format, 1024);
501 #endif /* !HAVE_VSNPRINTF */
502 buffer[1024] = 0;
504 va_end (args2);
506 for (i = g_bit_nth_msf (log_level, -1); i >= 0; i = g_bit_nth_msf (log_level, i))
508 register GLogLevelFlags test_level;
510 test_level = 1 << i;
511 if (log_level & test_level)
513 guint depth = GPOINTER_TO_UINT (g_private_get (g_log_depth));
514 GLogDomain *domain;
515 GLogFunc log_func;
516 gpointer data = NULL;
518 domain = g_log_find_domain (log_domain ? log_domain : "");
520 if (depth)
521 test_level |= G_LOG_FLAG_RECURSION;
523 depth++;
524 g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
526 g_mutex_lock (g_messages_lock);
527 if ((((domain ? domain->fatal_mask : G_LOG_FATAL_MASK) |
528 g_log_always_fatal) & test_level) != 0)
529 test_level |= G_LOG_FLAG_FATAL;
530 g_mutex_unlock (g_messages_lock);
532 log_func = g_log_domain_get_handler (domain, test_level, &data);
533 log_func (log_domain, test_level, buffer, data);
535 /* *domain can be cluttered now */
537 if (test_level & G_LOG_FLAG_FATAL)
539 #if defined (G_ENABLE_DEBUG) && defined (SIGTRAP)
540 if (!(test_level & G_LOG_FLAG_RECURSION))
541 raise (SIGTRAP);
542 else
543 abort ();
544 #else /* !G_ENABLE_DEBUG || !SIGTRAP */
545 #ifdef G_OS_WIN32
546 MessageBox (NULL, fatal_msg_buf, NULL, MB_OK);
547 #endif
548 # if defined (_MSC_VER) && defined (_DEBUG)
549 /* let's see the call stack ... */
550 __asm int 3
551 # endif
552 abort ();
553 #endif /* !G_ENABLE_DEBUG || !SIGTRAP */
556 depth--;
557 g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
562 void
563 g_log (const gchar *log_domain,
564 GLogLevelFlags log_level,
565 const gchar *format,
566 ...)
568 va_list args;
570 va_start (args, format);
571 g_logv (log_domain, log_level, format, args);
572 va_end (args);
575 void
576 g_log_default_handler (const gchar *log_domain,
577 GLogLevelFlags log_level,
578 const gchar *message,
579 gpointer unused_data)
581 GFileDescriptor fd;
582 gboolean in_recursion;
583 gboolean is_fatal;
584 GErrorFunc local_glib_error_func;
585 GWarningFunc local_glib_warning_func;
586 GPrintFunc local_glib_message_func;
588 in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
589 is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
590 log_level &= G_LOG_LEVEL_MASK;
592 if (!message)
593 message = "g_log_default_handler(): (NULL) message";
595 #ifdef G_OS_WIN32
596 /* Use just stdout as stderr is hard to get redirected from the
597 * DOS prompt.
599 fd = stdout;
600 gonna_abort = is_fatal;
601 #else
602 fd = (log_level > G_LOG_LEVEL_MESSAGE) ? 1 : 2;
603 #endif
605 g_mutex_lock (g_messages_lock);
606 local_glib_error_func = glib_error_func;
607 local_glib_warning_func = glib_warning_func;
608 local_glib_message_func = glib_message_func;
609 g_mutex_unlock (g_messages_lock);
611 switch (log_level)
613 case G_LOG_LEVEL_ERROR:
614 if (!log_domain && local_glib_error_func)
616 /* compatibility code */
617 local_glib_error_func (message);
618 return;
620 /* use write(2) for output, in case we are out of memeory */
621 ensure_stdout_valid ();
622 write (fd, "\n", 1);
623 g_log_write_prefix (fd, log_level);
625 if (log_domain)
627 write (fd, log_domain, strlen (log_domain));
628 write (fd, "-", 1);
630 else
631 write (fd, "** ", 3);
632 if (in_recursion)
633 write (fd, "ERROR (recursed) **: ", 21);
634 else
635 write (fd, "ERROR **: ", 10);
636 write (fd, message, strlen (message));
637 if (is_fatal)
638 write (fd, "\naborting...\n", 13);
639 else
640 write (fd, "\n", 1);
641 break;
642 case G_LOG_LEVEL_CRITICAL:
643 ensure_stdout_valid ();
644 write (fd, "\n", 1);
645 g_log_write_prefix (fd, log_level);
647 if (log_domain)
649 write (fd, log_domain, strlen (log_domain));
650 write (fd, "-", 1);
652 else
653 write (fd, "** ", 3);
654 if (in_recursion)
655 write (fd, "CRITICAL (recursed) **: ", 24);
656 else
657 write (fd, "CRITICAL **: ", 13);
658 write (fd, message, strlen (message));
659 if (is_fatal)
660 write (fd, "\naborting...\n", 13);
661 else
662 write (fd, "\n", 1);
663 break;
664 case G_LOG_LEVEL_WARNING:
665 if (!log_domain && local_glib_warning_func)
667 /* compatibility code */
668 local_glib_warning_func (message);
669 return;
671 ensure_stdout_valid ();
672 write (fd, "\n", 1);
673 g_log_write_prefix (fd, log_level);
675 if (log_domain)
677 write (fd, log_domain, strlen (log_domain));
678 write (fd, "-", 1);
680 else
681 write (fd, "** ", 3);
682 if (in_recursion)
683 write (fd, "WARNING (recursed) **: ", 23);
684 else
685 write (fd, "WARNING **: ", 12);
686 write (fd, message, strlen (message));
687 if (is_fatal)
688 write (fd, "\naborting...\n", 13);
689 else
690 write (fd, "\n", 1);
691 break;
692 case G_LOG_LEVEL_MESSAGE:
693 if (!log_domain && local_glib_message_func)
695 /* compatibility code */
696 local_glib_message_func (message);
697 return;
699 ensure_stdout_valid ();
701 g_log_write_prefix (fd, log_level);
703 if (log_domain)
705 write (fd, log_domain, strlen (log_domain));
706 write (fd, "-", 1);
708 if (in_recursion)
709 write (fd, "Message (recursed): ", 20);
710 else
711 write (fd, "Message: ", 9);
712 write (fd, message, strlen (message));
713 if (is_fatal)
714 write (fd, "\naborting...\n", 13);
715 else
716 write (fd, "\n", 1);
717 break;
718 case G_LOG_LEVEL_INFO:
719 ensure_stdout_valid ();
721 g_log_write_prefix (fd, log_level);
723 if (log_domain)
725 write (fd, log_domain, strlen (log_domain));
726 write (fd, "-", 1);
728 if (in_recursion)
729 write (fd, "INFO (recursed): ", 17);
730 else
731 write (fd, "INFO: ", 6);
732 write (fd, message, strlen (message));
733 if (is_fatal)
734 write (fd, "\naborting...\n", 13);
735 else
736 write (fd, "\n", 1);
737 break;
738 case G_LOG_LEVEL_DEBUG:
739 ensure_stdout_valid ();
741 g_log_write_prefix (fd, log_level);
743 if (log_domain)
745 write (fd, log_domain, strlen (log_domain));
746 write (fd, "-", 1);
748 if (in_recursion)
749 write (fd, "DEBUG (recursed): ", 18);
750 else
751 write (fd, "DEBUG: ", 7);
752 write (fd, message, strlen (message));
753 if (is_fatal)
754 write (fd, "\naborting...\n", 13);
755 else
756 write (fd, "\n", 1);
757 break;
758 default:
759 /* we are used for a log level that is not defined by GLib itself,
760 * try to make the best out of it.
762 ensure_stdout_valid ();
764 g_log_write_prefix (fd, log_level);
766 if (log_domain)
768 write (fd, log_domain, strlen (log_domain));
769 if (in_recursion)
770 write (fd, "-LOG (recursed:", 15);
771 else
772 write (fd, "-LOG (", 6);
774 else if (in_recursion)
775 write (fd, "LOG (recursed:", 14);
776 else
777 write (fd, "LOG (", 5);
778 if (log_level)
780 gchar string[] = "0x00): ";
781 gchar *p = string + 2;
782 guint i;
784 i = g_bit_nth_msf (log_level, -1);
785 *p = i >> 4;
786 p++;
787 *p = '0' + (i & 0xf);
788 if (*p > '9')
789 *p += 'A' - '9' - 1;
791 write (fd, string, 7);
793 else
794 write (fd, "): ", 3);
795 write (fd, message, strlen (message));
796 if (is_fatal)
797 write (fd, "\naborting...\n", 13);
798 else
799 write (fd, "\n", 1);
800 break;
804 GPrintFunc
805 g_set_print_handler (GPrintFunc func)
807 GPrintFunc old_print_func;
809 g_mutex_lock (g_messages_lock);
810 old_print_func = glib_print_func;
811 glib_print_func = func;
812 g_mutex_unlock (g_messages_lock);
814 return old_print_func;
817 void
818 g_print (const gchar *format,
819 ...)
821 va_list args;
822 gchar *string;
823 GPrintFunc local_glib_print_func;
825 g_return_if_fail (format != NULL);
827 va_start (args, format);
828 string = g_strdup_vprintf (format, args);
829 va_end (args);
831 g_mutex_lock (g_messages_lock);
832 local_glib_print_func = glib_print_func;
833 g_mutex_unlock (g_messages_lock);
835 if (local_glib_print_func)
836 local_glib_print_func (string);
837 else
839 ensure_stdout_valid ();
840 fputs (string, stdout);
841 fflush (stdout);
843 g_free (string);
846 GPrintFunc
847 g_set_printerr_handler (GPrintFunc func)
849 GPrintFunc old_printerr_func;
851 g_mutex_lock (g_messages_lock);
852 old_printerr_func = glib_printerr_func;
853 glib_printerr_func = func;
854 g_mutex_unlock (g_messages_lock);
856 return old_printerr_func;
859 void
860 g_printerr (const gchar *format,
861 ...)
863 va_list args;
864 gchar *string;
865 GPrintFunc local_glib_printerr_func;
867 g_return_if_fail (format != NULL);
869 va_start (args, format);
870 string = g_strdup_vprintf (format, args);
871 va_end (args);
873 g_mutex_lock (g_messages_lock);
874 local_glib_printerr_func = glib_printerr_func;
875 g_mutex_unlock (g_messages_lock);
877 if (local_glib_printerr_func)
878 local_glib_printerr_func (string);
879 else
881 fputs (string, stderr);
882 fflush (stderr);
884 g_free (string);
887 /* compatibility code */
888 GErrorFunc
889 g_set_error_handler (GErrorFunc func)
891 GErrorFunc old_error_func;
893 g_mutex_lock (g_messages_lock);
894 old_error_func = glib_error_func;
895 glib_error_func = func;
896 g_mutex_unlock (g_messages_lock);
898 return old_error_func;
901 /* compatibility code */
902 GWarningFunc
903 g_set_warning_handler (GWarningFunc func)
905 GWarningFunc old_warning_func;
907 g_mutex_lock (g_messages_lock);
908 old_warning_func = glib_warning_func;
909 glib_warning_func = func;
910 g_mutex_unlock (g_messages_lock);
912 return old_warning_func;
915 /* compatibility code */
916 GPrintFunc
917 g_set_message_handler (GPrintFunc func)
919 GPrintFunc old_message_func;
921 g_mutex_lock (g_messages_lock);
922 old_message_func = glib_message_func;
923 glib_message_func = func;
924 g_mutex_unlock (g_messages_lock);
926 return old_message_func;
929 #ifndef MB_LEN_MAX
930 # define MB_LEN_MAX 8
931 #endif
933 typedef struct
935 guint min_width;
936 guint precision;
937 gboolean alternate_format, zero_padding, adjust_left, locale_grouping;
938 gboolean add_space, add_sign, possible_sign, seen_precision;
939 gboolean mod_half, mod_long, mod_extra_long;
940 } PrintfArgSpec;
942 static inline guint
943 printf_string_upper_bound (const gchar *format,
944 gboolean may_warn,
945 va_list args)
947 static const gboolean honour_longs = SIZEOF_LONG > 4 || SIZEOF_VOID_P > 4;
948 guint len = 1;
950 if (!format)
951 return len;
953 while (*format)
955 register gchar c = *format++;
957 if (c != '%')
958 len += 1;
959 else /* (c == '%') */
961 PrintfArgSpec spec = { 0, };
962 gboolean seen_l = FALSE, conv_done = FALSE;
963 guint conv_len = 0;
964 const gchar *spec_start = format;
968 c = *format++;
969 switch (c)
971 GDoubleIEEE754 u_double;
972 guint v_uint;
973 gint v_int;
974 const gchar *v_string;
976 /* beware of positional parameters
978 case '$':
979 if (may_warn)
980 g_warning (G_GNUC_PRETTY_FUNCTION
981 "(): unable to handle positional parameters (%%n$)");
982 len += 1024; /* try adding some safety padding */
983 break;
985 /* parse flags
987 case '#':
988 spec.alternate_format = TRUE;
989 break;
990 case '0':
991 spec.zero_padding = TRUE;
992 break;
993 case '-':
994 spec.adjust_left = TRUE;
995 break;
996 case ' ':
997 spec.add_space = TRUE;
998 break;
999 case '+':
1000 spec.add_sign = TRUE;
1001 break;
1002 case '\'':
1003 spec.locale_grouping = TRUE;
1004 break;
1006 /* parse output size specifications
1008 case '.':
1009 spec.seen_precision = TRUE;
1010 break;
1011 case '1':
1012 case '2':
1013 case '3':
1014 case '4':
1015 case '5':
1016 case '6':
1017 case '7':
1018 case '8':
1019 case '9':
1020 v_uint = c - '0';
1021 c = *format;
1022 while (c >= '0' && c <= '9')
1024 format++;
1025 v_uint = v_uint * 10 + c - '0';
1026 c = *format;
1028 if (spec.seen_precision)
1029 spec.precision = MAX (spec.precision, v_uint);
1030 else
1031 spec.min_width = MAX (spec.min_width, v_uint);
1032 break;
1033 case '*':
1034 v_int = va_arg (args, int);
1035 if (spec.seen_precision)
1037 /* forget about negative precision */
1038 if (v_int >= 0)
1039 spec.precision = MAX (spec.precision, v_int);
1041 else
1043 if (v_int < 0)
1045 v_int = - v_int;
1046 spec.adjust_left = TRUE;
1048 spec.min_width = MAX (spec.min_width, v_int);
1050 break;
1052 /* parse type modifiers
1054 case 'h':
1055 spec.mod_half = TRUE;
1056 break;
1057 case 'l':
1058 if (!seen_l)
1060 spec.mod_long = TRUE;
1061 seen_l = TRUE;
1062 break;
1064 /* else, fall through */
1065 case 'L':
1066 case 'q':
1067 spec.mod_long = TRUE;
1068 spec.mod_extra_long = TRUE;
1069 break;
1070 case 'z':
1071 case 'Z':
1072 #if GLIB_SIZEOF_SIZE_T > 4
1073 spec.mod_long = TRUE;
1074 spec.mod_extra_long = TRUE;
1075 #endif /* GLIB_SIZEOF_SIZE_T > 4 */
1076 break;
1077 case 't':
1078 #if GLIB_SIZEOF_PTRDIFF_T > 4
1079 spec.mod_long = TRUE;
1080 spec.mod_extra_long = TRUE;
1081 #endif /* GLIB_SIZEOF_PTRDIFF_T > 4 */
1082 break;
1083 case 'j':
1084 #if GLIB_SIZEOF_INTMAX_T > 4
1085 spec.mod_long = TRUE;
1086 spec.mod_extra_long = TRUE;
1087 #endif /* GLIB_SIZEOF_INTMAX_T > 4 */
1088 break;
1090 /* parse output conversions
1092 case '%':
1093 conv_len += 1;
1094 break;
1095 case 'O':
1096 case 'D':
1097 case 'I':
1098 case 'U':
1099 /* some C libraries feature long variants for these as well? */
1100 spec.mod_long = TRUE;
1101 /* fall through */
1102 case 'o':
1103 conv_len += 2;
1104 /* fall through */
1105 case 'd':
1106 case 'i':
1107 conv_len += 1; /* sign */
1108 /* fall through */
1109 case 'u':
1110 conv_len += 4;
1111 /* fall through */
1112 case 'x':
1113 case 'X':
1114 spec.possible_sign = TRUE;
1115 conv_len += 10;
1116 if (spec.mod_long && honour_longs)
1117 conv_len *= 2;
1118 if (spec.mod_extra_long)
1119 conv_len *= 2;
1120 if (spec.mod_extra_long)
1122 #ifdef G_HAVE_GINT64
1123 (void) va_arg (args, gint64);
1124 #else /* !G_HAVE_GINT64 */
1125 (void) va_arg (args, long);
1126 #endif /* !G_HAVE_GINT64 */
1128 else if (spec.mod_long)
1129 (void) va_arg (args, long);
1130 else
1131 (void) va_arg (args, int);
1132 break;
1133 case 'A':
1134 case 'a':
1135 /* 0x */
1136 conv_len += 2;
1137 /* fall through */
1138 case 'g':
1139 case 'G':
1140 case 'e':
1141 case 'E':
1142 case 'f':
1143 spec.possible_sign = TRUE;
1144 /* n . dddddddddddddddddddddddd E +- eeee */
1145 conv_len += 1 + 1 + MAX (24, spec.precision) + 1 + 1 + 4;
1146 if (may_warn && spec.mod_extra_long)
1147 g_warning (G_GNUC_PRETTY_FUNCTION
1148 "(): unable to handle long double, collecting double only");
1149 #ifdef HAVE_LONG_DOUBLE
1150 #error need to implement special handling for long double
1151 #endif
1152 u_double.v_double = va_arg (args, double);
1153 /* %f can expand up to all significant digits before '.' (308) */
1154 if (c == 'f' &&
1155 u_double.mpn.biased_exponent > 0 && u_double.mpn.biased_exponent < 2047)
1157 gint exp = u_double.mpn.biased_exponent;
1159 exp -= G_IEEE754_DOUBLE_BIAS;
1160 exp = exp * G_LOG_2_BASE_10 + 1;
1161 conv_len += exp;
1163 /* some printf() implementations require extra padding for rounding */
1164 conv_len += 2;
1165 /* we can't really handle locale specific grouping here */
1166 if (spec.locale_grouping)
1167 conv_len *= 2;
1168 break;
1169 case 'C':
1170 spec.mod_long = TRUE;
1171 /* fall through */
1172 case 'c':
1173 conv_len += spec.mod_long ? MB_LEN_MAX : 1;
1174 (void) va_arg (args, int);
1175 break;
1176 case 'S':
1177 spec.mod_long = TRUE;
1178 /* fall through */
1179 case 's':
1180 v_string = va_arg (args, char*);
1181 if (!v_string)
1182 conv_len += 8; /* hold "(null)" */
1183 else if (spec.seen_precision)
1184 conv_len += spec.precision;
1185 else
1186 conv_len += strlen (v_string);
1187 conv_done = TRUE;
1188 if (spec.mod_long)
1190 if (may_warn)
1191 g_warning (G_GNUC_PRETTY_FUNCTION
1192 "(): unable to handle wide char strings");
1193 len += 1024; /* try adding some safety padding */
1195 break;
1196 case 'P': /* do we actually need this? */
1197 /* fall through */
1198 case 'p':
1199 spec.alternate_format = TRUE;
1200 conv_len += 10;
1201 if (honour_longs)
1202 conv_len *= 2;
1203 /* fall through */
1204 case 'n':
1205 conv_done = TRUE;
1206 (void) va_arg (args, void*);
1207 break;
1208 case 'm':
1209 /* there's not much we can do to be clever */
1210 v_string = g_strerror (errno);
1211 v_uint = v_string ? strlen (v_string) : 0;
1212 conv_len += MAX (256, v_uint);
1213 break;
1215 /* handle invalid cases
1217 case '\000':
1218 /* no conversion specification, bad bad */
1219 conv_len += format - spec_start;
1220 break;
1221 default:
1222 if (may_warn)
1223 g_warning (G_GNUC_PRETTY_FUNCTION
1224 "(): unable to handle `%c' while parsing format",
1226 break;
1228 conv_done |= conv_len > 0;
1230 while (!conv_done);
1231 /* handle width specifications */
1232 conv_len = MAX (conv_len, MAX (spec.precision, spec.min_width));
1233 /* handle flags */
1234 conv_len += spec.alternate_format ? 2 : 0;
1235 conv_len += (spec.add_space || spec.add_sign || spec.possible_sign);
1236 /* finally done */
1237 len += conv_len;
1238 } /* else (c == '%') */
1239 } /* while (*format) */
1241 return len;
1244 guint
1245 g_printf_string_upper_bound (const gchar *format,
1246 va_list args)
1248 return printf_string_upper_bound (format, TRUE, args);
1251 void
1252 g_messages_init (void)
1254 g_messages_lock = g_mutex_new();
1255 g_log_depth = g_private_new(NULL);