gmessages.c 21.7 KB
Newer Older
Owen Taylor's avatar
Owen Taylor committed
1 2 3 4
/* GLIB - Library of useful routines for C programming
 * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
Owen Taylor's avatar
Owen Taylor committed
6 7 8 9 10
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * 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.
Owen Taylor's avatar
Owen Taylor committed
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
Owen Taylor's avatar
Owen Taylor committed
15 16 17 18
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
19

20
/*
21
 * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
22 23 24 25 26
 * file for a list of people on the GLib Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GLib at ftp://ftp.gtk.org/pub/gtk/. 
 */

27 28 29 30
/* 
 * MT safe
 */

31
#include "config.h"
32

33
#include <stdlib.h>
Owen Taylor's avatar
Owen Taylor committed
34 35 36
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
37 38 39
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
40
#include <signal.h>
41 42
#include <locale.h>
#include <errno.h>
43 44

#include "glib.h"
45
#include "gdebug.h"
46
#include "gprintfint.h"
47
#include "gthreadinit.h"
48

49
#ifdef G_OS_WIN32
50
#include <io.h>
51 52 53 54
typedef FILE* GFileDescriptor;
#else
typedef gint GFileDescriptor;
#endif
Owen Taylor's avatar
Owen Taylor committed
55

56 57 58 59
/* --- structures --- */
typedef struct _GLogDomain	GLogDomain;
typedef struct _GLogHandler	GLogHandler;
struct _GLogDomain
Owen Taylor's avatar
Owen Taylor committed
60
{
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
  gchar		*log_domain;
  GLogLevelFlags fatal_mask;
  GLogHandler	*handlers;
  GLogDomain	*next;
};
struct _GLogHandler
{
  guint		 id;
  GLogLevelFlags log_level;
  GLogFunc	 log_func;
  gpointer	 data;
  GLogHandler	*next;
};


/* --- variables --- */
77
static GMutex        *g_messages_lock = NULL;
78
static GLogDomain    *g_log_domains = NULL;
79
static GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK;
80 81
static GPrintFunc     glib_print_func = NULL;
static GPrintFunc     glib_printerr_func = NULL;
82 83
static GPrivate	     *g_log_depth = NULL;
static GLogLevelFlags g_log_msg_prefix = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG;
84

85

86
/* --- functions --- */
87 88 89
#ifdef G_OS_WIN32
#  define STRICT
#  include <windows.h>
90
#  undef STRICT
91
#  include <process.h>          /* For _getpid() */
92
static gboolean win32_keep_fatal_message = FALSE;
93 94 95

/* This default message will usually be overwritten. */
/* Yes, a fixed size buffer is bad. So sue me. But g_error is never
96 97 98 99
 * with huge strings, is it?
 */
static gchar  fatal_msg_buf[1000] = "Unspecified fatal error encountered, aborting.";
static gchar *fatal_msg_ptr = fatal_msg_buf;
100

101 102 103
/* Just use stdio. If we're out of memory, we're hosed anyway. */
#undef write
static inline int
104
dowrite (GFileDescriptor fd,
105 106
	 const void  *buf,
	 unsigned int len)
107
{
108
  if (win32_keep_fatal_message)
109 110 111 112 113 114 115
    {
      memcpy (fatal_msg_ptr, buf, len);
      fatal_msg_ptr += len;
      *fatal_msg_ptr = 0;
      return len;
    }

116
  fwrite (buf, len, 1, fd);
117
  fflush (fd);
118 119 120

  return len;
}
121 122
#define write(fd, buf, len) dowrite(fd, buf, len)

123 124 125
static void
ensure_stdout_valid (void)
{
126
  static gboolean alloc_console_called = FALSE;
127 128
  HANDLE handle;

129
  if (win32_keep_fatal_message)
130 131
    return;

132
  if (!alloc_console_called)
133
    {
134
      handle = (HANDLE) _get_osfhandle (fileno (stdout)); 
135 136 137 138 139 140 141
  
      if (handle == INVALID_HANDLE_VALUE)
	{
	  AllocConsole ();
	  alloc_console_called = TRUE;
	  freopen ("CONOUT$", "w", stdout);
	}
142 143
    }
}
144 145 146 147

static void
ensure_stderr_valid (void)
{
148
  static gboolean alloc_console_called = FALSE;
149 150 151 152 153 154 155
  HANDLE handle;

  if (win32_keep_fatal_message)
    return;

  if (!alloc_console_called)
    {
156 157
      handle = (HANDLE) _get_osfhandle (fileno (stderr)); 

158 159 160 161 162 163 164 165 166
      if (handle == INVALID_HANDLE_VALUE)
	{
	  AllocConsole ();
	  alloc_console_called = TRUE;
	  freopen ("CONOUT$", "w", stderr);
	}
    }
}

167 168
#else
#define ensure_stdout_valid()	/* Define as empty */
169
#define ensure_stderr_valid()
170
#endif
171

172
static void
173
write_string (GFileDescriptor fd,
174
	      const gchar    *string)
175 176 177 178
{
  write (fd, string, strlen (string));
}

179 180
static void
g_messages_prefixed_init (void)
181 182 183
{
  static gboolean initialized = FALSE;

184
  if (!initialized)
185
    {
186
      const gchar *val;
187

188 189 190 191
      initialized = TRUE;
      val = g_getenv ("G_MESSAGES_PREFIXED");
      
      if (val)
192
	{
193 194 195 196 197 198 199 200 201 202
	  static const GDebugKey keys[] = {
	    { "error", G_LOG_LEVEL_ERROR },
	    { "critical", G_LOG_LEVEL_CRITICAL },
	    { "warning", G_LOG_LEVEL_WARNING },
	    { "message", G_LOG_LEVEL_MESSAGE },
	    { "info", G_LOG_LEVEL_INFO },
	    { "debug", G_LOG_LEVEL_DEBUG }
	  };
	  
	  g_log_msg_prefix = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
203
	}
204 205 206
    }
}

207 208
static GLogDomain*
g_log_find_domain_L (const gchar *log_domain)
209 210
{
  register GLogDomain *domain;
211
  
212 213
  domain = g_log_domains;
  while (domain)
Owen Taylor's avatar
Owen Taylor committed
214
    {
215
      if (strcmp (domain->log_domain, log_domain) == 0)
216
	return domain;
217
      domain = domain->next;
Owen Taylor's avatar
Owen Taylor committed
218
    }
219 220 221
  return NULL;
}

222 223
static GLogDomain*
g_log_domain_new_L (const gchar *log_domain)
224 225
{
  register GLogDomain *domain;
226

227 228 229 230
  domain = g_new (GLogDomain, 1);
  domain->log_domain = g_strdup (log_domain);
  domain->fatal_mask = G_LOG_FATAL_MASK;
  domain->handlers = NULL;
231
  
232 233 234 235 236
  domain->next = g_log_domains;
  g_log_domains = domain;
  
  return domain;
}
Owen Taylor's avatar
Owen Taylor committed
237

238 239
static void
g_log_domain_check_free_L (GLogDomain *domain)
240 241 242
{
  if (domain->fatal_mask == G_LOG_FATAL_MASK &&
      domain->handlers == NULL)
Owen Taylor's avatar
Owen Taylor committed
243
    {
244 245
      register GLogDomain *last, *work;
      
246 247
      last = NULL;  

248 249 250 251 252 253 254 255 256 257 258 259 260
      work = g_log_domains;
      while (work)
	{
	  if (work == domain)
	    {
	      if (last)
		last->next = domain->next;
	      else
		g_log_domains = domain->next;
	      g_free (domain->log_domain);
	      g_free (domain);
	      break;
	    }
261 262
	  last = work;
	  work = last->next;
263
	}  
Owen Taylor's avatar
Owen Taylor committed
264
    }
265 266
}

267 268 269 270
static GLogFunc
g_log_domain_get_handler_L (GLogDomain	*domain,
			    GLogLevelFlags log_level,
			    gpointer	*data)
271 272
{
  if (domain && log_level)
Owen Taylor's avatar
Owen Taylor committed
273
    {
274 275 276 277 278 279 280 281 282 283 284 285
      register GLogHandler *handler;
      
      handler = domain->handlers;
      while (handler)
	{
	  if ((handler->log_level & log_level) == log_level)
	    {
	      *data = handler->data;
	      return handler->log_func;
	    }
	  handler = handler->next;
	}
Owen Taylor's avatar
Owen Taylor committed
286
    }
287 288 289
  return g_log_default_handler;
}

290 291 292 293 294
GLogLevelFlags
g_log_set_always_fatal (GLogLevelFlags fatal_mask)
{
  GLogLevelFlags old_mask;

295 296 297
  /* restrict the global mask to levels that are known to glib
   * since this setting applies to all domains
   */
298 299 300 301 302 303
  fatal_mask &= (1 << G_LOG_LEVEL_USER_SHIFT) - 1;
  /* force errors to be fatal */
  fatal_mask |= G_LOG_LEVEL_ERROR;
  /* remove bogus flag */
  fatal_mask &= ~G_LOG_FLAG_FATAL;

304
  g_mutex_lock (g_messages_lock);
305 306
  old_mask = g_log_always_fatal;
  g_log_always_fatal = fatal_mask;
307
  g_mutex_unlock (g_messages_lock);
308 309 310 311

  return old_mask;
}

312
GLogLevelFlags
313 314
g_log_set_fatal_mask (const gchar   *log_domain,
		      GLogLevelFlags fatal_mask)
315 316 317 318 319 320 321 322 323 324 325 326
{
  GLogLevelFlags old_flags;
  register GLogDomain *domain;
  
  if (!log_domain)
    log_domain = "";
  
  /* force errors to be fatal */
  fatal_mask |= G_LOG_LEVEL_ERROR;
  /* remove bogus flag */
  fatal_mask &= ~G_LOG_FLAG_FATAL;
  
327 328
  g_mutex_lock (g_messages_lock);

329
  domain = g_log_find_domain_L (log_domain);
330
  if (!domain)
331
    domain = g_log_domain_new_L (log_domain);
332 333 334
  old_flags = domain->fatal_mask;
  
  domain->fatal_mask = fatal_mask;
335
  g_log_domain_check_free_L (domain);
336 337 338

  g_mutex_unlock (g_messages_lock);

339 340
  return old_flags;
}
Owen Taylor's avatar
Owen Taylor committed
341

342
guint
343 344 345 346
g_log_set_handler (const gchar	 *log_domain,
		   GLogLevelFlags log_levels,
		   GLogFunc	  log_func,
		   gpointer	  user_data)
347 348
{
  static guint handler_id = 0;
349 350
  GLogDomain *domain;
  GLogHandler *handler;
351 352 353 354 355 356
  
  g_return_val_if_fail ((log_levels & G_LOG_LEVEL_MASK) != 0, 0);
  g_return_val_if_fail (log_func != NULL, 0);
  
  if (!log_domain)
    log_domain = "";
357 358 359

  handler = g_new (GLogHandler, 1);

360 361
  g_mutex_lock (g_messages_lock);

362
  domain = g_log_find_domain_L (log_domain);
363
  if (!domain)
364
    domain = g_log_domain_new_L (log_domain);
365 366 367 368 369 370 371
  
  handler->id = ++handler_id;
  handler->log_level = log_levels;
  handler->log_func = log_func;
  handler->data = user_data;
  handler->next = domain->handlers;
  domain->handlers = handler;
372 373

  g_mutex_unlock (g_messages_lock);
374 375
  
  return handler_id;
Owen Taylor's avatar
Owen Taylor committed
376 377 378
}

void
379 380
g_log_remove_handler (const gchar *log_domain,
		      guint	   handler_id)
Owen Taylor's avatar
Owen Taylor committed
381
{
382 383 384 385 386 387 388
  register GLogDomain *domain;
  
  g_return_if_fail (handler_id > 0);
  
  if (!log_domain)
    log_domain = "";
  
389
  g_mutex_lock (g_messages_lock);
390
  domain = g_log_find_domain_L (log_domain);
391 392
  if (domain)
    {
393
      GLogHandler *work, *last;
394 395 396 397 398 399 400 401 402 403 404
      
      last = NULL;
      work = domain->handlers;
      while (work)
	{
	  if (work->id == handler_id)
	    {
	      if (last)
		last->next = work->next;
	      else
		domain->handlers = work->next;
405
	      g_log_domain_check_free_L (domain); 
406
	      g_mutex_unlock (g_messages_lock);
407
	      g_free (work);
408 409
	      return;
	    }
410 411
	  last = work;
	  work = last->next;
412
	}
413 414
    } 
  g_mutex_unlock (g_messages_lock);
415 416
  g_warning ("%s: could not find handler with id `%d' for domain \"%s\"",
	     G_STRLOC, handler_id, log_domain);
417
}
Owen Taylor's avatar
Owen Taylor committed
418

419
void
420 421 422 423
g_logv (const gchar   *log_domain,
	GLogLevelFlags log_level,
	const gchar   *format,
	va_list	       args1)
424 425
{
  gchar buffer[1025];
426 427 428
  gboolean was_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
  gboolean was_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
  gint i;
429

430 431 432 433 434
  log_level &= G_LOG_LEVEL_MASK;
  if (!log_level)
    return;
  
  /* we use a stack buffer of fixed size, because we might get called
435
   * recursively.
436
   */
437
  _g_vsnprintf (buffer, 1024, format, args1);
438 439
  
  for (i = g_bit_nth_msf (log_level, -1); i >= 0; i = g_bit_nth_msf (log_level, i))
Owen Taylor's avatar
Owen Taylor committed
440
    {
441 442 443 444 445
      register GLogLevelFlags test_level;
      
      test_level = 1 << i;
      if (log_level & test_level)
	{
446
	  guint depth = GPOINTER_TO_UINT (g_private_get (g_log_depth));
447 448
	  GLogDomain *domain;
	  GLogFunc log_func;
449
	  guint domain_fatal_mask;
450
	  gpointer data = NULL;
451

452 453 454 455 456 457 458 459
	  if (was_fatal)
	    test_level |= G_LOG_FLAG_FATAL;
	  if (was_recursion)
	    test_level |= G_LOG_FLAG_RECURSION;

	  /* check recursion and lookup handler */
	  g_mutex_lock (g_messages_lock);
	  domain = g_log_find_domain_L (log_domain ? log_domain : "");
460
	  if (depth)
461
	    test_level |= G_LOG_FLAG_RECURSION;
462
	  depth++;
463 464 465 466 467 468 469 470 471 472
	  domain_fatal_mask = domain ? domain->fatal_mask : G_LOG_FATAL_MASK;
	  if ((domain_fatal_mask | g_log_always_fatal) & test_level)
	    test_level |= G_LOG_FLAG_FATAL;
	  if (test_level & G_LOG_FLAG_RECURSION)
	    log_func = _g_log_fallback_handler;
	  else
	    log_func = g_log_domain_get_handler_L (domain, test_level, &data);
	  domain = NULL;
	  g_mutex_unlock (g_messages_lock);

473 474
	  g_private_set (g_log_depth, GUINT_TO_POINTER (depth));

475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
	  /* had to defer debug initialization until we can keep track of recursion */
	  if (!(test_level & G_LOG_FLAG_RECURSION) && !_g_debug_initialized)
	    {
	      guint orig_test_level = test_level;

	      _g_debug_init ();
	      if ((domain_fatal_mask | g_log_always_fatal) & test_level)
		test_level |= G_LOG_FLAG_FATAL;
	      if (test_level != orig_test_level)
		{
		  /* need a relookup, not nice, but not too bad either */
		  g_mutex_lock (g_messages_lock);
		  domain = g_log_find_domain_L (log_domain ? log_domain : "");
		  log_func = g_log_domain_get_handler_L (domain, test_level, &data);
		  domain = NULL;
		  g_mutex_unlock (g_messages_lock);
		}
	    }
493

494
	  log_func (log_domain, test_level, buffer, data);
495

496
	  if (test_level & G_LOG_FLAG_FATAL)
497
	    {
498
#ifdef G_OS_WIN32
499 500 501
	      gchar *locale_msg = g_locale_from_utf8 (fatal_msg_buf, -1, NULL, NULL, NULL);
	      
	      MessageBox (NULL, locale_msg, NULL, MB_OK);
502 503
#endif
#if defined (G_ENABLE_DEBUG) && (defined (SIGTRAP) || defined (G_OS_WIN32))
504
	      if (!(test_level & G_LOG_FLAG_RECURSION))
505
		G_BREAKPOINT ();
506 507
	      else
		abort ();
508
#else /* !G_ENABLE_DEBUG || !(SIGTRAP || G_OS_WIN32) */
509
	      abort ();
510
#endif /* !G_ENABLE_DEBUG || !(SIGTRAP || G_OS_WIN32) */
511
	    }
512
	  
513 514
	  depth--;
	  g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
515
	}
Owen Taylor's avatar
Owen Taylor committed
516
    }
517 518 519
}

void
520 521 522
g_log (const gchar   *log_domain,
       GLogLevelFlags log_level,
       const gchar   *format,
523 524
       ...)
{
525
  va_list args;
526
  
527 528 529
  va_start (args, format);
  g_logv (log_domain, log_level, format, args);
  va_end (args);
530 531
}

532 533 534 535 536 537 538
static gchar*
strdup_convert (const gchar *string,
		const gchar *charset)
{
  if (!g_utf8_validate (string, -1, NULL))
    return g_strconcat ("[Invalid UTF-8] ", string, NULL);
  else
539 540 541 542 543 544 545 546 547 548 549 550 551 552
    {
      GError *err = NULL;
      
      gchar *result = g_convert_with_fallback (string, -1, charset, "UTF-8", "?", NULL, NULL, &err);
      if (result)
	return result;
      else
	{
	  /* Not thread-safe, but doesn't matter if we print the warning twice
	   */
	  static gboolean warned = FALSE; 
	  if (!warned)
	    {
	      warned = TRUE;
553
	      ensure_stderr_valid ();
554
	      _g_fprintf (stderr, "GLib: Cannot convert message: %s\n", err->message);
555 556 557 558 559 560
	    }
	  g_error_free (err);
	  
	  return g_strdup (string);
	}
    }
561 562
}

563 564 565 566 567 568 569 570 571 572
/* For a radix of 8 we need at most 3 output bytes for 1 input
 * byte. Additionally we might need up to 2 output bytes for the
 * readix prefix and 1 byte for the trailing NULL.
 */
#define FORMAT_UNSIGNED_BUFSIZE ((GLIB_SIZEOF_LONG * 3) + 3)

static void
format_unsigned (gchar  *buf,
		 gulong  num,
		 guint   radix)
573
{
574 575 576 577 578 579 580 581 582 583 584
  gulong tmp;
  gchar c;
  gint i, n;

  /* we may not call _any_ GLib functions here (or macros like g_return_if_fail()) */

  if (radix != 8 && radix != 10 && radix != 16)
    {
      *buf = '\000';
      return;
    }
585
  
586 587 588 589 590 591
  if (!num)
    {
      *buf++ = '0';
      *buf = '\000';
      return;
    } 
592
  
593
  if (radix == 16)
Owen Taylor's avatar
Owen Taylor committed
594
    {
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
      *buf++ = '0';
      *buf++ = 'x';
    }
  else if (radix == 8)
    {
      *buf++ = '0';
    }
	
  n = 0;
  tmp = num;
  while (tmp)
    {
      tmp /= radix;
      n++;
    }
610

611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
  i = n;

  /* Again we can't use g_assert; actually this check should _never_ fail. */
  if (n > FORMAT_UNSIGNED_BUFSIZE - 3)
    {
      *buf = '\000';
      return;
    }

  while (num)
    {
      i--;
      c = (num % radix);
      if (c < 10)
	buf[i] = c + '0';
626
      else
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651
	buf[i] = c + 'a' - 10;
      num /= radix;
    }
  
  buf[n] = '\000';
}

/* string size big enough to hold level prefix */
#define	STRING_BUFFER_SIZE	(FORMAT_UNSIGNED_BUFSIZE + 32)

#define	ALERT_LEVELS		(G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING)

static GFileDescriptor
mklevel_prefix (gchar level_prefix[STRING_BUFFER_SIZE],
		guint log_level)
{
  gboolean to_stdout = TRUE;

  /* we may not call _any_ GLib functions here */

  switch (log_level & G_LOG_LEVEL_MASK)
    {
    case G_LOG_LEVEL_ERROR:
      strcpy (level_prefix, "ERROR");
      to_stdout = FALSE;
652 653
      break;
    case G_LOG_LEVEL_CRITICAL:
654 655
      strcpy (level_prefix, "CRITICAL");
      to_stdout = FALSE;
656 657
      break;
    case G_LOG_LEVEL_WARNING:
658 659
      strcpy (level_prefix, "WARNING");
      to_stdout = FALSE;
660 661
      break;
    case G_LOG_LEVEL_MESSAGE:
662 663
      strcpy (level_prefix, "Message");
      to_stdout = FALSE;
664 665
      break;
    case G_LOG_LEVEL_INFO:
666 667 668 669 670 671 672
      strcpy (level_prefix, "INFO");
      break;
    case G_LOG_LEVEL_DEBUG:
      strcpy (level_prefix, "DEBUG");
      break;
    default:
      if (log_level)
673
	{
674 675
	  strcpy (level_prefix, "LOG-");
	  format_unsigned (level_prefix + 4, log_level & G_LOG_LEVEL_MASK, 16);
676 677
	}
      else
678
	strcpy (level_prefix, "LOG");
679
      break;
680 681 682 683 684
    }
  if (log_level & G_LOG_FLAG_RECURSION)
    strcat (level_prefix, " (recursed)");
  if (log_level & ALERT_LEVELS)
    strcat (level_prefix, " **");
685

686 687
#ifdef G_OS_WIN32
  win32_keep_fatal_message = (log_level & G_LOG_FLAG_FATAL) != 0;
688 689 690 691 692 693 694 695 696 697 698

  if (to_stdout)
    {
      ensure_stdout_valid ();
      return stdout;
    }
  else
    {
      ensure_stderr_valid ();
      return stderr;
    }
699 700 701 702
#else
  return to_stdout ? 1 : 2;
#endif
}
703

704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
void
_g_log_fallback_handler (const gchar   *log_domain,
			 GLogLevelFlags log_level,
			 const gchar   *message,
			 gpointer       unused_data)
{
  gchar level_prefix[STRING_BUFFER_SIZE], pid_string[FORMAT_UNSIGNED_BUFSIZE];
  gboolean is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
  GFileDescriptor fd;

  /* we can not call _any_ GLib functions in this fallback handler,
   * which is why we skip UTF-8 conversion, etc.
   * since we either recursed or ran out of memory, we're in a pretty
   * pathologic situation anyways, what we can do is giving the
   * the process ID unconditionally however.
   */

  fd = mklevel_prefix (level_prefix, log_level);
  if (!message)
    message = "(NULL) message";

  format_unsigned (pid_string, getpid (), 10);

  if (log_domain)
    write_string (fd, "\n");
  else
    write_string (fd, "\n** ");
  write_string (fd, "(process:");
  write_string (fd, pid_string);
  write_string (fd, "): ");
  if (log_domain)
    {
      write_string (fd, log_domain);
      write_string (fd, "-");
    }
  write_string (fd, level_prefix);
  write_string (fd, ": ");
  write_string (fd, message);
  if (is_fatal)
    write_string (fd, "\naborting...\n");
  else
    write_string (fd, "\n");
}

void
g_log_default_handler (const gchar   *log_domain,
		       GLogLevelFlags log_level,
		       const gchar   *message,
		       gpointer	      unused_data)
{
  gboolean is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
  gchar level_prefix[STRING_BUFFER_SIZE], *string;
  GString *gstring;
  GFileDescriptor fd;

  /* we can be called externally with recursion for whatever reason */
  if (log_level & G_LOG_FLAG_RECURSION)
    {
      _g_log_fallback_handler (log_domain, log_level, message, unused_data);
      return;
    }

  g_messages_prefixed_init ();

  fd = mklevel_prefix (level_prefix, log_level);

  gstring = g_string_new ("");
  if (log_level & ALERT_LEVELS)
    g_string_append (gstring, "\n");
  if (!log_domain)
    g_string_append (gstring, "** ");

  if ((g_log_msg_prefix & log_level) == log_level)
    {
      const gchar *prg_name = g_get_prgname ();
      
      if (!prg_name)
781
	g_string_append_printf (gstring, "(process:%lu): ", (gulong)getpid ());
782
      else
783
	g_string_append_printf (gstring, "(%s:%lu): ", prg_name, (gulong)getpid ());
784
    }
785

786 787 788 789 790 791
  if (log_domain)
    {
      g_string_append (gstring, log_domain);
      g_string_append_c (gstring, '-');
    }
  g_string_append (gstring, level_prefix);
792

793 794 795 796 797 798 799 800 801
  g_string_append (gstring, ": ");
  if (!message)
    g_string_append (gstring, "(NULL) message");
  else
    {
      const gchar *charset;

      if (g_get_charset (&charset))
	g_string_append (gstring, message);	/* charset is UTF-8 already */
802 803
      else
	{
804 805 806
	  string = strdup_convert (message, charset);
	  g_string_append (gstring, string);
	  g_free (string);
807
	}
Owen Taylor's avatar
Owen Taylor committed
808
    }
809 810 811 812 813 814 815 816 817
  if (is_fatal)
    g_string_append (gstring, "\naborting...\n");
  else
    g_string_append (gstring, "\n");

  string = g_string_free (gstring, FALSE);

  write_string (fd, string);
  g_free (string);
Owen Taylor's avatar
Owen Taylor committed
818 819
}

820 821 822 823 824
GPrintFunc
g_set_print_handler (GPrintFunc func)
{
  GPrintFunc old_print_func;
  
825
  g_mutex_lock (g_messages_lock);
826 827
  old_print_func = glib_print_func;
  glib_print_func = func;
828
  g_mutex_unlock (g_messages_lock);
829 830 831 832
  
  return old_print_func;
}

Owen Taylor's avatar
Owen Taylor committed
833
void
834 835
g_print (const gchar *format,
	 ...)
Owen Taylor's avatar
Owen Taylor committed
836
{
837 838
  va_list args;
  gchar *string;
839
  GPrintFunc local_glib_print_func;
840 841 842
  
  g_return_if_fail (format != NULL);
  
Owen Taylor's avatar
Owen Taylor committed
843
  va_start (args, format);
844
  string = g_strdup_vprintf (format, args);
Owen Taylor's avatar
Owen Taylor committed
845
  va_end (args);
846
  
847 848 849
  g_mutex_lock (g_messages_lock);
  local_glib_print_func = glib_print_func;
  g_mutex_unlock (g_messages_lock);
850
  
851 852
  if (local_glib_print_func)
    local_glib_print_func (string);
Owen Taylor's avatar
Owen Taylor committed
853 854
  else
    {
855 856
      const gchar *charset;

857
      ensure_stdout_valid ();
858 859 860 861 862 863 864 865 866
      if (g_get_charset (&charset))
	fputs (string, stdout); /* charset is UTF-8 already */
      else
	{
	  gchar *lstring = strdup_convert (string, charset);

	  fputs (lstring, stdout);
	  g_free (lstring);
	}
867
      fflush (stdout);
Owen Taylor's avatar
Owen Taylor committed
868
    }
869
  g_free (string);
Owen Taylor's avatar
Owen Taylor committed
870 871
}

872 873 874 875 876
GPrintFunc
g_set_printerr_handler (GPrintFunc func)
{
  GPrintFunc old_printerr_func;
  
877
  g_mutex_lock (g_messages_lock);
878 879
  old_printerr_func = glib_printerr_func;
  glib_printerr_func = func;
880
  g_mutex_unlock (g_messages_lock);
881 882 883 884
  
  return old_printerr_func;
}

Owen Taylor's avatar
Owen Taylor committed
885
void
886 887
g_printerr (const gchar *format,
	    ...)
Owen Taylor's avatar
Owen Taylor committed
888
{
889 890
  va_list args;
  gchar *string;
891
  GPrintFunc local_glib_printerr_func;
892 893 894
  
  g_return_if_fail (format != NULL);
  
Owen Taylor's avatar
Owen Taylor committed
895
  va_start (args, format);
896
  string = g_strdup_vprintf (format, args);
Owen Taylor's avatar
Owen Taylor committed
897
  va_end (args);
898
  
899 900 901
  g_mutex_lock (g_messages_lock);
  local_glib_printerr_func = glib_printerr_func;
  g_mutex_unlock (g_messages_lock);
902
  
903 904
  if (local_glib_printerr_func)
    local_glib_printerr_func (string);
Owen Taylor's avatar
Owen Taylor committed
905 906
  else
    {
907 908
      const gchar *charset;

909
      ensure_stderr_valid ();
910 911 912 913 914 915 916 917 918
      if (g_get_charset (&charset))
	fputs (string, stderr); /* charset is UTF-8 already */
      else
	{
	  gchar *lstring = strdup_convert (string, charset);

	  fputs (lstring, stderr);
	  g_free (lstring);
	}
919
      fflush (stderr);
Owen Taylor's avatar
Owen Taylor committed
920
    }
921
  g_free (string);
Owen Taylor's avatar
Owen Taylor committed
922 923
}

924
gsize
925 926 927
g_printf_string_upper_bound (const gchar *format,
			     va_list      args)
{
928
  gchar c;
929
  return _g_vsnprintf (&c, 1, format, args) + 1;
930 931
}

932
void
933
_g_messages_thread_init (void)
934
{
935
  g_messages_lock = g_mutex_new ();
936
  g_messages_prefixed_init ();
937 938 939
  _g_debug_init ();
}

940 941 942 943 944 945 946
void
_g_messages_thread_private_init (void)
{
  g_assert (g_log_depth == NULL);
  g_log_depth = g_private_new (NULL);
}

947 948 949
gboolean _g_debug_initialized = FALSE;
guint _g_debug_flags = 0;

950 951
void
_g_debug_init (void) 
952 953 954 955
{
  const gchar *val;
  
  _g_debug_initialized = TRUE;
956
  
957 958 959 960 961 962
  val = g_getenv ("G_DEBUG");
  if (val != NULL)
    {
      static const GDebugKey keys[] = {
	{"fatal_warnings", G_DEBUG_FATAL_WARNINGS}
      };
963
      
964 965
      _g_debug_flags = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
    }
966
  
967 968 969 970 971 972 973 974
  if (_g_debug_flags & G_DEBUG_FATAL_WARNINGS) 
    {
      GLogLevelFlags fatal_mask;
      
      fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
      fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
      g_log_set_always_fatal (fatal_mask);
    }
975
}