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 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. |
---|
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 | * Lesser General Public License for more details. |
---|
13 | * |
---|
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. |
---|
18 | */ |
---|
19 | |
---|
20 | /* |
---|
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/. |
---|
25 | */ |
---|
26 | |
---|
27 | /* |
---|
28 | * MT safe |
---|
29 | */ |
---|
30 | |
---|
31 | #include "config.h" |
---|
32 | |
---|
33 | #include <stdlib.h> |
---|
34 | #include <stdarg.h> |
---|
35 | #include <stdio.h> |
---|
36 | #include <string.h> |
---|
37 | #ifdef HAVE_UNISTD_H |
---|
38 | #include <unistd.h> |
---|
39 | #endif |
---|
40 | #include <signal.h> |
---|
41 | #include <locale.h> |
---|
42 | #include <errno.h> |
---|
43 | |
---|
44 | #include "glib.h" |
---|
45 | #include "gdebug.h" |
---|
46 | #include "gprintfint.h" |
---|
47 | |
---|
48 | #ifdef G_OS_WIN32 |
---|
49 | typedef FILE* GFileDescriptor; |
---|
50 | #else |
---|
51 | typedef gint GFileDescriptor; |
---|
52 | #endif |
---|
53 | |
---|
54 | /* --- structures --- */ |
---|
55 | typedef struct _GLogDomain GLogDomain; |
---|
56 | typedef struct _GLogHandler GLogHandler; |
---|
57 | struct _GLogDomain |
---|
58 | { |
---|
59 | gchar *log_domain; |
---|
60 | GLogLevelFlags fatal_mask; |
---|
61 | GLogHandler *handlers; |
---|
62 | GLogDomain *next; |
---|
63 | }; |
---|
64 | struct _GLogHandler |
---|
65 | { |
---|
66 | guint id; |
---|
67 | GLogLevelFlags log_level; |
---|
68 | GLogFunc log_func; |
---|
69 | gpointer data; |
---|
70 | GLogHandler *next; |
---|
71 | }; |
---|
72 | |
---|
73 | |
---|
74 | /* --- variables --- */ |
---|
75 | static GMutex *g_messages_lock = NULL; |
---|
76 | static GLogDomain *g_log_domains = NULL; |
---|
77 | static GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK; |
---|
78 | static GPrintFunc glib_print_func = NULL; |
---|
79 | static GPrintFunc glib_printerr_func = NULL; |
---|
80 | static GPrivate *g_log_depth = NULL; |
---|
81 | static GLogLevelFlags g_log_msg_prefix = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG; |
---|
82 | |
---|
83 | |
---|
84 | /* --- functions --- */ |
---|
85 | #ifdef G_OS_WIN32 |
---|
86 | # define STRICT |
---|
87 | # include <windows.h> |
---|
88 | # undef STRICT |
---|
89 | # include <process.h> /* For _getpid() */ |
---|
90 | static gboolean alloc_console_called = FALSE; |
---|
91 | static gboolean win32_keep_fatal_message = FALSE; |
---|
92 | |
---|
93 | /* This default message will usually be overwritten. */ |
---|
94 | /* Yes, a fixed size buffer is bad. So sue me. But g_error is never |
---|
95 | * with huge strings, is it? |
---|
96 | */ |
---|
97 | static gchar fatal_msg_buf[1000] = "Unspecified fatal error encountered, aborting."; |
---|
98 | static gchar *fatal_msg_ptr = fatal_msg_buf; |
---|
99 | |
---|
100 | /* Just use stdio. If we're out of memory, we're hosed anyway. */ |
---|
101 | #undef write |
---|
102 | static inline int |
---|
103 | dowrite (GFileDescriptor fd, |
---|
104 | const void *buf, |
---|
105 | unsigned int len) |
---|
106 | { |
---|
107 | if (win32_keep_fatal_message) |
---|
108 | { |
---|
109 | memcpy (fatal_msg_ptr, buf, len); |
---|
110 | fatal_msg_ptr += len; |
---|
111 | *fatal_msg_ptr = 0; |
---|
112 | return len; |
---|
113 | } |
---|
114 | |
---|
115 | fwrite (buf, len, 1, fd); |
---|
116 | fflush (fd); |
---|
117 | |
---|
118 | return len; |
---|
119 | } |
---|
120 | #define write(fd, buf, len) dowrite(fd, buf, len) |
---|
121 | |
---|
122 | static void |
---|
123 | ensure_stdout_valid (void) |
---|
124 | { |
---|
125 | HANDLE handle; |
---|
126 | |
---|
127 | if (win32_keep_fatal_message) |
---|
128 | return; |
---|
129 | |
---|
130 | if (!alloc_console_called) |
---|
131 | { |
---|
132 | handle = GetStdHandle (STD_OUTPUT_HANDLE); |
---|
133 | |
---|
134 | if (handle == INVALID_HANDLE_VALUE) |
---|
135 | { |
---|
136 | AllocConsole (); |
---|
137 | alloc_console_called = TRUE; |
---|
138 | freopen ("CONOUT$", "w", stdout); |
---|
139 | } |
---|
140 | } |
---|
141 | } |
---|
142 | #else |
---|
143 | #define ensure_stdout_valid() /* Define as empty */ |
---|
144 | #endif |
---|
145 | |
---|
146 | static void |
---|
147 | write_string (GFileDescriptor fd, |
---|
148 | const gchar *string) |
---|
149 | { |
---|
150 | write (fd, string, strlen (string)); |
---|
151 | } |
---|
152 | |
---|
153 | static void |
---|
154 | g_messages_prefixed_init (void) |
---|
155 | { |
---|
156 | static gboolean initialized = FALSE; |
---|
157 | |
---|
158 | if (!initialized) |
---|
159 | { |
---|
160 | const gchar *val; |
---|
161 | |
---|
162 | initialized = TRUE; |
---|
163 | val = g_getenv ("G_MESSAGES_PREFIXED"); |
---|
164 | |
---|
165 | if (val) |
---|
166 | { |
---|
167 | static const GDebugKey keys[] = { |
---|
168 | { "error", G_LOG_LEVEL_ERROR }, |
---|
169 | { "critical", G_LOG_LEVEL_CRITICAL }, |
---|
170 | { "warning", G_LOG_LEVEL_WARNING }, |
---|
171 | { "message", G_LOG_LEVEL_MESSAGE }, |
---|
172 | { "info", G_LOG_LEVEL_INFO }, |
---|
173 | { "debug", G_LOG_LEVEL_DEBUG } |
---|
174 | }; |
---|
175 | |
---|
176 | g_log_msg_prefix = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys)); |
---|
177 | } |
---|
178 | } |
---|
179 | } |
---|
180 | |
---|
181 | static GLogDomain* |
---|
182 | g_log_find_domain_L (const gchar *log_domain) |
---|
183 | { |
---|
184 | register GLogDomain *domain; |
---|
185 | |
---|
186 | domain = g_log_domains; |
---|
187 | while (domain) |
---|
188 | { |
---|
189 | if (strcmp (domain->log_domain, log_domain) == 0) |
---|
190 | return domain; |
---|
191 | domain = domain->next; |
---|
192 | } |
---|
193 | return NULL; |
---|
194 | } |
---|
195 | |
---|
196 | static GLogDomain* |
---|
197 | g_log_domain_new_L (const gchar *log_domain) |
---|
198 | { |
---|
199 | register GLogDomain *domain; |
---|
200 | |
---|
201 | domain = g_new (GLogDomain, 1); |
---|
202 | domain->log_domain = g_strdup (log_domain); |
---|
203 | domain->fatal_mask = G_LOG_FATAL_MASK; |
---|
204 | domain->handlers = NULL; |
---|
205 | |
---|
206 | domain->next = g_log_domains; |
---|
207 | g_log_domains = domain; |
---|
208 | |
---|
209 | return domain; |
---|
210 | } |
---|
211 | |
---|
212 | static void |
---|
213 | g_log_domain_check_free_L (GLogDomain *domain) |
---|
214 | { |
---|
215 | if (domain->fatal_mask == G_LOG_FATAL_MASK && |
---|
216 | domain->handlers == NULL) |
---|
217 | { |
---|
218 | register GLogDomain *last, *work; |
---|
219 | |
---|
220 | last = NULL; |
---|
221 | |
---|
222 | work = g_log_domains; |
---|
223 | while (work) |
---|
224 | { |
---|
225 | if (work == domain) |
---|
226 | { |
---|
227 | if (last) |
---|
228 | last->next = domain->next; |
---|
229 | else |
---|
230 | g_log_domains = domain->next; |
---|
231 | g_free (domain->log_domain); |
---|
232 | g_free (domain); |
---|
233 | break; |
---|
234 | } |
---|
235 | last = work; |
---|
236 | work = last->next; |
---|
237 | } |
---|
238 | } |
---|
239 | } |
---|
240 | |
---|
241 | static GLogFunc |
---|
242 | g_log_domain_get_handler_L (GLogDomain *domain, |
---|
243 | GLogLevelFlags log_level, |
---|
244 | gpointer *data) |
---|
245 | { |
---|
246 | if (domain && log_level) |
---|
247 | { |
---|
248 | register GLogHandler *handler; |
---|
249 | |
---|
250 | handler = domain->handlers; |
---|
251 | while (handler) |
---|
252 | { |
---|
253 | if ((handler->log_level & log_level) == log_level) |
---|
254 | { |
---|
255 | *data = handler->data; |
---|
256 | return handler->log_func; |
---|
257 | } |
---|
258 | handler = handler->next; |
---|
259 | } |
---|
260 | } |
---|
261 | return g_log_default_handler; |
---|
262 | } |
---|
263 | |
---|
264 | GLogLevelFlags |
---|
265 | g_log_set_always_fatal (GLogLevelFlags fatal_mask) |
---|
266 | { |
---|
267 | GLogLevelFlags old_mask; |
---|
268 | |
---|
269 | /* restrict the global mask to levels that are known to glib |
---|
270 | * since this setting applies to all domains |
---|
271 | */ |
---|
272 | fatal_mask &= (1 << G_LOG_LEVEL_USER_SHIFT) - 1; |
---|
273 | /* force errors to be fatal */ |
---|
274 | fatal_mask |= G_LOG_LEVEL_ERROR; |
---|
275 | /* remove bogus flag */ |
---|
276 | fatal_mask &= ~G_LOG_FLAG_FATAL; |
---|
277 | |
---|
278 | g_mutex_lock (g_messages_lock); |
---|
279 | old_mask = g_log_always_fatal; |
---|
280 | g_log_always_fatal = fatal_mask; |
---|
281 | g_mutex_unlock (g_messages_lock); |
---|
282 | |
---|
283 | return old_mask; |
---|
284 | } |
---|
285 | |
---|
286 | GLogLevelFlags |
---|
287 | g_log_set_fatal_mask (const gchar *log_domain, |
---|
288 | GLogLevelFlags fatal_mask) |
---|
289 | { |
---|
290 | GLogLevelFlags old_flags; |
---|
291 | register GLogDomain *domain; |
---|
292 | |
---|
293 | if (!log_domain) |
---|
294 | log_domain = ""; |
---|
295 | |
---|
296 | /* force errors to be fatal */ |
---|
297 | fatal_mask |= G_LOG_LEVEL_ERROR; |
---|
298 | /* remove bogus flag */ |
---|
299 | fatal_mask &= ~G_LOG_FLAG_FATAL; |
---|
300 | |
---|
301 | g_mutex_lock (g_messages_lock); |
---|
302 | |
---|
303 | domain = g_log_find_domain_L (log_domain); |
---|
304 | if (!domain) |
---|
305 | domain = g_log_domain_new_L (log_domain); |
---|
306 | old_flags = domain->fatal_mask; |
---|
307 | |
---|
308 | domain->fatal_mask = fatal_mask; |
---|
309 | g_log_domain_check_free_L (domain); |
---|
310 | |
---|
311 | g_mutex_unlock (g_messages_lock); |
---|
312 | |
---|
313 | return old_flags; |
---|
314 | } |
---|
315 | |
---|
316 | guint |
---|
317 | g_log_set_handler (const gchar *log_domain, |
---|
318 | GLogLevelFlags log_levels, |
---|
319 | GLogFunc log_func, |
---|
320 | gpointer user_data) |
---|
321 | { |
---|
322 | static guint handler_id = 0; |
---|
323 | GLogDomain *domain; |
---|
324 | GLogHandler *handler; |
---|
325 | |
---|
326 | g_return_val_if_fail ((log_levels & G_LOG_LEVEL_MASK) != 0, 0); |
---|
327 | g_return_val_if_fail (log_func != NULL, 0); |
---|
328 | |
---|
329 | if (!log_domain) |
---|
330 | log_domain = ""; |
---|
331 | |
---|
332 | handler = g_new (GLogHandler, 1); |
---|
333 | |
---|
334 | g_mutex_lock (g_messages_lock); |
---|
335 | |
---|
336 | domain = g_log_find_domain_L (log_domain); |
---|
337 | if (!domain) |
---|
338 | domain = g_log_domain_new_L (log_domain); |
---|
339 | |
---|
340 | handler->id = ++handler_id; |
---|
341 | handler->log_level = log_levels; |
---|
342 | handler->log_func = log_func; |
---|
343 | handler->data = user_data; |
---|
344 | handler->next = domain->handlers; |
---|
345 | domain->handlers = handler; |
---|
346 | |
---|
347 | g_mutex_unlock (g_messages_lock); |
---|
348 | |
---|
349 | return handler_id; |
---|
350 | } |
---|
351 | |
---|
352 | void |
---|
353 | g_log_remove_handler (const gchar *log_domain, |
---|
354 | guint handler_id) |
---|
355 | { |
---|
356 | register GLogDomain *domain; |
---|
357 | |
---|
358 | g_return_if_fail (handler_id > 0); |
---|
359 | |
---|
360 | if (!log_domain) |
---|
361 | log_domain = ""; |
---|
362 | |
---|
363 | g_mutex_lock (g_messages_lock); |
---|
364 | domain = g_log_find_domain_L (log_domain); |
---|
365 | if (domain) |
---|
366 | { |
---|
367 | GLogHandler *work, *last; |
---|
368 | |
---|
369 | last = NULL; |
---|
370 | work = domain->handlers; |
---|
371 | while (work) |
---|
372 | { |
---|
373 | if (work->id == handler_id) |
---|
374 | { |
---|
375 | if (last) |
---|
376 | last->next = work->next; |
---|
377 | else |
---|
378 | domain->handlers = work->next; |
---|
379 | g_log_domain_check_free_L (domain); |
---|
380 | g_mutex_unlock (g_messages_lock); |
---|
381 | g_free (work); |
---|
382 | return; |
---|
383 | } |
---|
384 | last = work; |
---|
385 | work = last->next; |
---|
386 | } |
---|
387 | } |
---|
388 | g_mutex_unlock (g_messages_lock); |
---|
389 | g_warning ("%s: could not find handler with id `%d' for domain \"%s\"", |
---|
390 | G_STRLOC, handler_id, log_domain); |
---|
391 | } |
---|
392 | |
---|
393 | void |
---|
394 | g_logv (const gchar *log_domain, |
---|
395 | GLogLevelFlags log_level, |
---|
396 | const gchar *format, |
---|
397 | va_list args1) |
---|
398 | { |
---|
399 | gchar buffer[1025]; |
---|
400 | gboolean was_fatal = (log_level & G_LOG_FLAG_FATAL) != 0; |
---|
401 | gboolean was_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0; |
---|
402 | gint i; |
---|
403 | |
---|
404 | log_level &= G_LOG_LEVEL_MASK; |
---|
405 | if (!log_level) |
---|
406 | return; |
---|
407 | |
---|
408 | /* we use a stack buffer of fixed size, because we might get called |
---|
409 | * recursively. |
---|
410 | */ |
---|
411 | _g_vsnprintf (buffer, 1024, format, args1); |
---|
412 | |
---|
413 | for (i = g_bit_nth_msf (log_level, -1); i >= 0; i = g_bit_nth_msf (log_level, i)) |
---|
414 | { |
---|
415 | register GLogLevelFlags test_level; |
---|
416 | |
---|
417 | test_level = 1 << i; |
---|
418 | if (log_level & test_level) |
---|
419 | { |
---|
420 | guint depth = GPOINTER_TO_UINT (g_private_get (g_log_depth)); |
---|
421 | GLogDomain *domain; |
---|
422 | GLogFunc log_func; |
---|
423 | guint domain_fatal_mask; |
---|
424 | gpointer data = NULL; |
---|
425 | |
---|
426 | if (was_fatal) |
---|
427 | test_level |= G_LOG_FLAG_FATAL; |
---|
428 | if (was_recursion) |
---|
429 | test_level |= G_LOG_FLAG_RECURSION; |
---|
430 | |
---|
431 | /* check recursion and lookup handler */ |
---|
432 | g_mutex_lock (g_messages_lock); |
---|
433 | domain = g_log_find_domain_L (log_domain ? log_domain : ""); |
---|
434 | if (depth) |
---|
435 | test_level |= G_LOG_FLAG_RECURSION; |
---|
436 | depth++; |
---|
437 | domain_fatal_mask = domain ? domain->fatal_mask : G_LOG_FATAL_MASK; |
---|
438 | if ((domain_fatal_mask | g_log_always_fatal) & test_level) |
---|
439 | test_level |= G_LOG_FLAG_FATAL; |
---|
440 | if (test_level & G_LOG_FLAG_RECURSION) |
---|
441 | log_func = _g_log_fallback_handler; |
---|
442 | else |
---|
443 | log_func = g_log_domain_get_handler_L (domain, test_level, &data); |
---|
444 | domain = NULL; |
---|
445 | g_mutex_unlock (g_messages_lock); |
---|
446 | |
---|
447 | g_private_set (g_log_depth, GUINT_TO_POINTER (depth)); |
---|
448 | |
---|
449 | /* had to defer debug initialization until we can keep track of recursion */ |
---|
450 | if (!(test_level & G_LOG_FLAG_RECURSION) && !_g_debug_initialized) |
---|
451 | { |
---|
452 | guint orig_test_level = test_level; |
---|
453 | |
---|
454 | _g_debug_init (); |
---|
455 | if ((domain_fatal_mask | g_log_always_fatal) & test_level) |
---|
456 | test_level |= G_LOG_FLAG_FATAL; |
---|
457 | if (test_level != orig_test_level) |
---|
458 | { |
---|
459 | /* need a relookup, not nice, but not too bad either */ |
---|
460 | g_mutex_lock (g_messages_lock); |
---|
461 | domain = g_log_find_domain_L (log_domain ? log_domain : ""); |
---|
462 | log_func = g_log_domain_get_handler_L (domain, test_level, &data); |
---|
463 | domain = NULL; |
---|
464 | g_mutex_unlock (g_messages_lock); |
---|
465 | } |
---|
466 | } |
---|
467 | |
---|
468 | log_func (log_domain, test_level, buffer, data); |
---|
469 | |
---|
470 | if (test_level & G_LOG_FLAG_FATAL) |
---|
471 | { |
---|
472 | #ifdef G_OS_WIN32 |
---|
473 | MessageBox (NULL, fatal_msg_buf, NULL, MB_OK); |
---|
474 | #endif |
---|
475 | #if defined (G_ENABLE_DEBUG) && (defined (SIGTRAP) || defined (G_OS_WIN32)) |
---|
476 | if (!(test_level & G_LOG_FLAG_RECURSION)) |
---|
477 | G_BREAKPOINT (); |
---|
478 | else |
---|
479 | abort (); |
---|
480 | #else /* !G_ENABLE_DEBUG || !(SIGTRAP || G_OS_WIN32) */ |
---|
481 | abort (); |
---|
482 | #endif /* !G_ENABLE_DEBUG || !(SIGTRAP || G_OS_WIN32) */ |
---|
483 | } |
---|
484 | |
---|
485 | depth--; |
---|
486 | g_private_set (g_log_depth, GUINT_TO_POINTER (depth)); |
---|
487 | } |
---|
488 | } |
---|
489 | } |
---|
490 | |
---|
491 | void |
---|
492 | g_log (const gchar *log_domain, |
---|
493 | GLogLevelFlags log_level, |
---|
494 | const gchar *format, |
---|
495 | ...) |
---|
496 | { |
---|
497 | va_list args; |
---|
498 | |
---|
499 | va_start (args, format); |
---|
500 | g_logv (log_domain, log_level, format, args); |
---|
501 | va_end (args); |
---|
502 | } |
---|
503 | |
---|
504 | static gchar* |
---|
505 | strdup_convert (const gchar *string, |
---|
506 | const gchar *charset) |
---|
507 | { |
---|
508 | if (!g_utf8_validate (string, -1, NULL)) |
---|
509 | return g_strconcat ("[Invalid UTF-8] ", string, NULL); |
---|
510 | else |
---|
511 | { |
---|
512 | GError *err = NULL; |
---|
513 | |
---|
514 | gchar *result = g_convert_with_fallback (string, -1, charset, "UTF-8", "?", NULL, NULL, &err); |
---|
515 | if (result) |
---|
516 | return result; |
---|
517 | else |
---|
518 | { |
---|
519 | /* Not thread-safe, but doesn't matter if we print the warning twice |
---|
520 | */ |
---|
521 | static gboolean warned = FALSE; |
---|
522 | if (!warned) |
---|
523 | { |
---|
524 | warned = TRUE; |
---|
525 | _g_fprintf (stderr, "GLib: Cannot convert message: %s\n", err->message); |
---|
526 | } |
---|
527 | g_error_free (err); |
---|
528 | |
---|
529 | return g_strdup (string); |
---|
530 | } |
---|
531 | } |
---|
532 | } |
---|
533 | |
---|
534 | /* For a radix of 8 we need at most 3 output bytes for 1 input |
---|
535 | * byte. Additionally we might need up to 2 output bytes for the |
---|
536 | * readix prefix and 1 byte for the trailing NULL. |
---|
537 | */ |
---|
538 | #define FORMAT_UNSIGNED_BUFSIZE ((GLIB_SIZEOF_LONG * 3) + 3) |
---|
539 | |
---|
540 | static void |
---|
541 | format_unsigned (gchar *buf, |
---|
542 | gulong num, |
---|
543 | guint radix) |
---|
544 | { |
---|
545 | gulong tmp; |
---|
546 | gchar c; |
---|
547 | gint i, n; |
---|
548 | |
---|
549 | /* we may not call _any_ GLib functions here (or macros like g_return_if_fail()) */ |
---|
550 | |
---|
551 | if (radix != 8 && radix != 10 && radix != 16) |
---|
552 | { |
---|
553 | *buf = '\000'; |
---|
554 | return; |
---|
555 | } |
---|
556 | |
---|
557 | if (!num) |
---|
558 | { |
---|
559 | *buf++ = '0'; |
---|
560 | *buf = '\000'; |
---|
561 | return; |
---|
562 | } |
---|
563 | |
---|
564 | if (radix == 16) |
---|
565 | { |
---|
566 | *buf++ = '0'; |
---|
567 | *buf++ = 'x'; |
---|
568 | } |
---|
569 | else if (radix == 8) |
---|
570 | { |
---|
571 | *buf++ = '0'; |
---|
572 | } |
---|
573 | |
---|
574 | n = 0; |
---|
575 | tmp = num; |
---|
576 | while (tmp) |
---|
577 | { |
---|
578 | tmp /= radix; |
---|
579 | n++; |
---|
580 | } |
---|
581 | |
---|
582 | i = n; |
---|
583 | |
---|
584 | /* Again we can't use g_assert; actually this check should _never_ fail. */ |
---|
585 | if (n > FORMAT_UNSIGNED_BUFSIZE - 3) |
---|
586 | { |
---|
587 | *buf = '\000'; |
---|
588 | return; |
---|
589 | } |
---|
590 | |
---|
591 | while (num) |
---|
592 | { |
---|
593 | i--; |
---|
594 | c = (num % radix); |
---|
595 | if (c < 10) |
---|
596 | buf[i] = c + '0'; |
---|
597 | else |
---|
598 | buf[i] = c + 'a' - 10; |
---|
599 | num /= radix; |
---|
600 | } |
---|
601 | |
---|
602 | buf[n] = '\000'; |
---|
603 | } |
---|
604 | |
---|
605 | /* string size big enough to hold level prefix */ |
---|
606 | #define STRING_BUFFER_SIZE (FORMAT_UNSIGNED_BUFSIZE + 32) |
---|
607 | |
---|
608 | #define ALERT_LEVELS (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING) |
---|
609 | |
---|
610 | static GFileDescriptor |
---|
611 | mklevel_prefix (gchar level_prefix[STRING_BUFFER_SIZE], |
---|
612 | guint log_level) |
---|
613 | { |
---|
614 | gboolean to_stdout = TRUE; |
---|
615 | |
---|
616 | /* we may not call _any_ GLib functions here */ |
---|
617 | |
---|
618 | switch (log_level & G_LOG_LEVEL_MASK) |
---|
619 | { |
---|
620 | case G_LOG_LEVEL_ERROR: |
---|
621 | strcpy (level_prefix, "ERROR"); |
---|
622 | to_stdout = FALSE; |
---|
623 | break; |
---|
624 | case G_LOG_LEVEL_CRITICAL: |
---|
625 | strcpy (level_prefix, "CRITICAL"); |
---|
626 | to_stdout = FALSE; |
---|
627 | break; |
---|
628 | case G_LOG_LEVEL_WARNING: |
---|
629 | strcpy (level_prefix, "WARNING"); |
---|
630 | to_stdout = FALSE; |
---|
631 | break; |
---|
632 | case G_LOG_LEVEL_MESSAGE: |
---|
633 | strcpy (level_prefix, "Message"); |
---|
634 | to_stdout = FALSE; |
---|
635 | break; |
---|
636 | case G_LOG_LEVEL_INFO: |
---|
637 | strcpy (level_prefix, "INFO"); |
---|
638 | break; |
---|
639 | case G_LOG_LEVEL_DEBUG: |
---|
640 | strcpy (level_prefix, "DEBUG"); |
---|
641 | break; |
---|
642 | default: |
---|
643 | if (log_level) |
---|
644 | { |
---|
645 | strcpy (level_prefix, "LOG-"); |
---|
646 | format_unsigned (level_prefix + 4, log_level & G_LOG_LEVEL_MASK, 16); |
---|
647 | } |
---|
648 | else |
---|
649 | strcpy (level_prefix, "LOG"); |
---|
650 | break; |
---|
651 | } |
---|
652 | if (log_level & G_LOG_FLAG_RECURSION) |
---|
653 | strcat (level_prefix, " (recursed)"); |
---|
654 | if (log_level & ALERT_LEVELS) |
---|
655 | strcat (level_prefix, " **"); |
---|
656 | |
---|
657 | ensure_stdout_valid (); |
---|
658 | #ifdef G_OS_WIN32 |
---|
659 | win32_keep_fatal_message = (log_level & G_LOG_FLAG_FATAL) != 0; |
---|
660 | /* Use just stdout as stderr is hard to get redirected from the DOS prompt. */ |
---|
661 | return stdout; |
---|
662 | #else |
---|
663 | return to_stdout ? 1 : 2; |
---|
664 | #endif |
---|
665 | } |
---|
666 | |
---|
667 | void |
---|
668 | _g_log_fallback_handler (const gchar *log_domain, |
---|
669 | GLogLevelFlags log_level, |
---|
670 | const gchar *message, |
---|
671 | gpointer unused_data) |
---|
672 | { |
---|
673 | gchar level_prefix[STRING_BUFFER_SIZE], pid_string[FORMAT_UNSIGNED_BUFSIZE]; |
---|
674 | gboolean is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0; |
---|
675 | GFileDescriptor fd; |
---|
676 | |
---|
677 | /* we can not call _any_ GLib functions in this fallback handler, |
---|
678 | * which is why we skip UTF-8 conversion, etc. |
---|
679 | * since we either recursed or ran out of memory, we're in a pretty |
---|
680 | * pathologic situation anyways, what we can do is giving the |
---|
681 | * the process ID unconditionally however. |
---|
682 | */ |
---|
683 | |
---|
684 | fd = mklevel_prefix (level_prefix, log_level); |
---|
685 | if (!message) |
---|
686 | message = "(NULL) message"; |
---|
687 | |
---|
688 | format_unsigned (pid_string, getpid (), 10); |
---|
689 | |
---|
690 | if (log_domain) |
---|
691 | write_string (fd, "\n"); |
---|
692 | else |
---|
693 | write_string (fd, "\n** "); |
---|
694 | write_string (fd, "(process:"); |
---|
695 | write_string (fd, pid_string); |
---|
696 | write_string (fd, "): "); |
---|
697 | if (log_domain) |
---|
698 | { |
---|
699 | write_string (fd, log_domain); |
---|
700 | write_string (fd, "-"); |
---|
701 | } |
---|
702 | write_string (fd, level_prefix); |
---|
703 | write_string (fd, ": "); |
---|
704 | write_string (fd, message); |
---|
705 | if (is_fatal) |
---|
706 | write_string (fd, "\naborting...\n"); |
---|
707 | else |
---|
708 | write_string (fd, "\n"); |
---|
709 | } |
---|
710 | |
---|
711 | void |
---|
712 | g_log_default_handler (const gchar *log_domain, |
---|
713 | GLogLevelFlags log_level, |
---|
714 | const gchar *message, |
---|
715 | gpointer unused_data) |
---|
716 | { |
---|
717 | gboolean is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0; |
---|
718 | gchar level_prefix[STRING_BUFFER_SIZE], *string; |
---|
719 | GString *gstring; |
---|
720 | GFileDescriptor fd; |
---|
721 | |
---|
722 | /* we can be called externally with recursion for whatever reason */ |
---|
723 | if (log_level & G_LOG_FLAG_RECURSION) |
---|
724 | { |
---|
725 | _g_log_fallback_handler (log_domain, log_level, message, unused_data); |
---|
726 | return; |
---|
727 | } |
---|
728 | |
---|
729 | g_messages_prefixed_init (); |
---|
730 | |
---|
731 | fd = mklevel_prefix (level_prefix, log_level); |
---|
732 | |
---|
733 | gstring = g_string_new (""); |
---|
734 | if (log_level & ALERT_LEVELS) |
---|
735 | g_string_append (gstring, "\n"); |
---|
736 | if (!log_domain) |
---|
737 | g_string_append (gstring, "** "); |
---|
738 | |
---|
739 | if ((g_log_msg_prefix & log_level) == log_level) |
---|
740 | { |
---|
741 | const gchar *prg_name = g_get_prgname (); |
---|
742 | |
---|
743 | if (!prg_name) |
---|
744 | g_string_append_printf (gstring, "(process:%lu): ", (gulong)getpid ()); |
---|
745 | else |
---|
746 | g_string_append_printf (gstring, "(%s:%lu): ", prg_name, (gulong)getpid ()); |
---|
747 | } |
---|
748 | |
---|
749 | if (log_domain) |
---|
750 | { |
---|
751 | g_string_append (gstring, log_domain); |
---|
752 | g_string_append_c (gstring, '-'); |
---|
753 | } |
---|
754 | g_string_append (gstring, level_prefix); |
---|
755 | |
---|
756 | g_string_append (gstring, ": "); |
---|
757 | if (!message) |
---|
758 | g_string_append (gstring, "(NULL) message"); |
---|
759 | else |
---|
760 | { |
---|
761 | const gchar *charset; |
---|
762 | |
---|
763 | if (g_get_charset (&charset)) |
---|
764 | g_string_append (gstring, message); /* charset is UTF-8 already */ |
---|
765 | else |
---|
766 | { |
---|
767 | string = strdup_convert (message, charset); |
---|
768 | g_string_append (gstring, string); |
---|
769 | g_free (string); |
---|
770 | } |
---|
771 | } |
---|
772 | if (is_fatal) |
---|
773 | g_string_append (gstring, "\naborting...\n"); |
---|
774 | else |
---|
775 | g_string_append (gstring, "\n"); |
---|
776 | |
---|
777 | string = g_string_free (gstring, FALSE); |
---|
778 | |
---|
779 | write_string (fd, string); |
---|
780 | g_free (string); |
---|
781 | } |
---|
782 | |
---|
783 | GPrintFunc |
---|
784 | g_set_print_handler (GPrintFunc func) |
---|
785 | { |
---|
786 | GPrintFunc old_print_func; |
---|
787 | |
---|
788 | g_mutex_lock (g_messages_lock); |
---|
789 | old_print_func = glib_print_func; |
---|
790 | glib_print_func = func; |
---|
791 | g_mutex_unlock (g_messages_lock); |
---|
792 | |
---|
793 | return old_print_func; |
---|
794 | } |
---|
795 | |
---|
796 | void |
---|
797 | g_print (const gchar *format, |
---|
798 | ...) |
---|
799 | { |
---|
800 | va_list args; |
---|
801 | gchar *string; |
---|
802 | GPrintFunc local_glib_print_func; |
---|
803 | |
---|
804 | g_return_if_fail (format != NULL); |
---|
805 | |
---|
806 | va_start (args, format); |
---|
807 | string = g_strdup_vprintf (format, args); |
---|
808 | va_end (args); |
---|
809 | |
---|
810 | g_mutex_lock (g_messages_lock); |
---|
811 | local_glib_print_func = glib_print_func; |
---|
812 | g_mutex_unlock (g_messages_lock); |
---|
813 | |
---|
814 | if (local_glib_print_func) |
---|
815 | local_glib_print_func (string); |
---|
816 | else |
---|
817 | { |
---|
818 | const gchar *charset; |
---|
819 | |
---|
820 | ensure_stdout_valid (); |
---|
821 | if (g_get_charset (&charset)) |
---|
822 | fputs (string, stdout); /* charset is UTF-8 already */ |
---|
823 | else |
---|
824 | { |
---|
825 | gchar *lstring = strdup_convert (string, charset); |
---|
826 | |
---|
827 | fputs (lstring, stdout); |
---|
828 | g_free (lstring); |
---|
829 | } |
---|
830 | fflush (stdout); |
---|
831 | } |
---|
832 | g_free (string); |
---|
833 | } |
---|
834 | |
---|
835 | GPrintFunc |
---|
836 | g_set_printerr_handler (GPrintFunc func) |
---|
837 | { |
---|
838 | GPrintFunc old_printerr_func; |
---|
839 | |
---|
840 | g_mutex_lock (g_messages_lock); |
---|
841 | old_printerr_func = glib_printerr_func; |
---|
842 | glib_printerr_func = func; |
---|
843 | g_mutex_unlock (g_messages_lock); |
---|
844 | |
---|
845 | return old_printerr_func; |
---|
846 | } |
---|
847 | |
---|
848 | void |
---|
849 | g_printerr (const gchar *format, |
---|
850 | ...) |
---|
851 | { |
---|
852 | va_list args; |
---|
853 | gchar *string; |
---|
854 | GPrintFunc local_glib_printerr_func; |
---|
855 | |
---|
856 | g_return_if_fail (format != NULL); |
---|
857 | |
---|
858 | va_start (args, format); |
---|
859 | string = g_strdup_vprintf (format, args); |
---|
860 | va_end (args); |
---|
861 | |
---|
862 | g_mutex_lock (g_messages_lock); |
---|
863 | local_glib_printerr_func = glib_printerr_func; |
---|
864 | g_mutex_unlock (g_messages_lock); |
---|
865 | |
---|
866 | if (local_glib_printerr_func) |
---|
867 | local_glib_printerr_func (string); |
---|
868 | else |
---|
869 | { |
---|
870 | const gchar *charset; |
---|
871 | |
---|
872 | if (g_get_charset (&charset)) |
---|
873 | fputs (string, stderr); /* charset is UTF-8 already */ |
---|
874 | else |
---|
875 | { |
---|
876 | gchar *lstring = strdup_convert (string, charset); |
---|
877 | |
---|
878 | fputs (lstring, stderr); |
---|
879 | g_free (lstring); |
---|
880 | } |
---|
881 | fflush (stderr); |
---|
882 | } |
---|
883 | g_free (string); |
---|
884 | } |
---|
885 | |
---|
886 | gsize |
---|
887 | g_printf_string_upper_bound (const gchar *format, |
---|
888 | va_list args) |
---|
889 | { |
---|
890 | gchar c; |
---|
891 | return _g_vsnprintf (&c, 1, format, args) + 1; |
---|
892 | } |
---|
893 | |
---|
894 | void |
---|
895 | g_messages_init (void) |
---|
896 | { |
---|
897 | g_messages_lock = g_mutex_new (); |
---|
898 | g_log_depth = g_private_new (NULL); |
---|
899 | g_messages_prefixed_init (); |
---|
900 | _g_debug_init (); |
---|
901 | } |
---|
902 | |
---|
903 | gboolean _g_debug_initialized = FALSE; |
---|
904 | guint _g_debug_flags = 0; |
---|
905 | |
---|
906 | void |
---|
907 | _g_debug_init (void) |
---|
908 | { |
---|
909 | const gchar *val; |
---|
910 | |
---|
911 | _g_debug_initialized = TRUE; |
---|
912 | |
---|
913 | val = g_getenv ("G_DEBUG"); |
---|
914 | if (val != NULL) |
---|
915 | { |
---|
916 | static const GDebugKey keys[] = { |
---|
917 | {"fatal_warnings", G_DEBUG_FATAL_WARNINGS} |
---|
918 | }; |
---|
919 | |
---|
920 | _g_debug_flags = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys)); |
---|
921 | } |
---|
922 | |
---|
923 | if (_g_debug_flags & G_DEBUG_FATAL_WARNINGS) |
---|
924 | { |
---|
925 | GLogLevelFlags fatal_mask; |
---|
926 | |
---|
927 | fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK); |
---|
928 | fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL; |
---|
929 | g_log_set_always_fatal (fatal_mask); |
---|
930 | } |
---|
931 | } |
---|