gmessages.c 28.5 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 32 33 34
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

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

48 49 50 51 52
#ifdef G_OS_WIN32
typedef FILE* GFileDescriptor;
#else
typedef gint GFileDescriptor;
#endif
Owen Taylor's avatar
Owen Taylor committed
53

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


74
/* --- prototypes --- */
75
#ifndef HAVE_C99_VSNPRINTF
76
static gsize printf_string_upper_bound (const gchar *format,
77 78
					gboolean     may_warn,
					va_list      args);
79
#endif /* !HAVE_C99_VSNPRINTF */
80 81


82
/* --- variables --- */
83
static GMutex        *g_messages_lock = NULL;
84
static GLogDomain    *g_log_domains = NULL;
85
static GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK;
86 87
static GPrintFunc     glib_print_func = NULL;
static GPrintFunc     glib_printerr_func = NULL;
88 89
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;
90

91

92
/* --- functions --- */
93 94 95
#ifdef G_OS_WIN32
#  define STRICT
#  include <windows.h>
96
#  undef STRICT
97
#  include <process.h>          /* For _getpid() */
98
static gboolean alloc_console_called = FALSE;
99
static gboolean win32_keep_fatal_message = FALSE;
100 101 102

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

108 109 110
/* Just use stdio. If we're out of memory, we're hosed anyway. */
#undef write
static inline int
111
dowrite (GFileDescriptor fd,
112 113
	 const void  *buf,
	 unsigned int len)
114
{
115
  if (win32_keep_fatal_message)
116 117 118 119 120 121 122
    {
      memcpy (fatal_msg_ptr, buf, len);
      fatal_msg_ptr += len;
      *fatal_msg_ptr = 0;
      return len;
    }

123
  fwrite (buf, len, 1, fd);
124
  fflush (fd);
125 126 127

  return len;
}
128 129
#define write(fd, buf, len) dowrite(fd, buf, len)

130 131 132 133 134
static void
ensure_stdout_valid (void)
{
  HANDLE handle;

135
  if (win32_keep_fatal_message)
136 137
    return;

138
  if (!alloc_console_called)
139
    {
140 141 142 143 144 145 146 147
      handle = GetStdHandle (STD_OUTPUT_HANDLE);
  
      if (handle == INVALID_HANDLE_VALUE)
	{
	  AllocConsole ();
	  alloc_console_called = TRUE;
	  freopen ("CONOUT$", "w", stdout);
	}
148 149 150 151 152
    }
}
#else
#define ensure_stdout_valid()	/* Define as empty */
#endif
153

154
static void
155
write_string (GFileDescriptor fd,
156
	      const gchar    *string)
157 158 159 160
{
  write (fd, string, strlen (string));
}

161 162
static void
g_messages_prefixed_init (void)
163 164 165
{
  static gboolean initialized = FALSE;

166
  if (!initialized)
167
    {
168
      const gchar *val;
169

170 171 172 173
      initialized = TRUE;
      val = g_getenv ("G_MESSAGES_PREFIXED");
      
      if (val)
174
	{
175 176 177 178 179 180 181 182 183 184
	  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));
185
	}
186 187 188
    }
}

189 190
static GLogDomain*
g_log_find_domain_L (const gchar *log_domain)
191 192
{
  register GLogDomain *domain;
193
  
194 195
  domain = g_log_domains;
  while (domain)
Owen Taylor's avatar
Owen Taylor committed
196
    {
197
      if (strcmp (domain->log_domain, log_domain) == 0)
198
	return domain;
199
      domain = domain->next;
Owen Taylor's avatar
Owen Taylor committed
200
    }
201 202 203
  return NULL;
}

204 205
static GLogDomain*
g_log_domain_new_L (const gchar *log_domain)
206 207
{
  register GLogDomain *domain;
208

209 210 211 212
  domain = g_new (GLogDomain, 1);
  domain->log_domain = g_strdup (log_domain);
  domain->fatal_mask = G_LOG_FATAL_MASK;
  domain->handlers = NULL;
213
  
214 215 216 217 218
  domain->next = g_log_domains;
  g_log_domains = domain;
  
  return domain;
}
Owen Taylor's avatar
Owen Taylor committed
219

220 221
static void
g_log_domain_check_free_L (GLogDomain *domain)
222 223 224
{
  if (domain->fatal_mask == G_LOG_FATAL_MASK &&
      domain->handlers == NULL)
Owen Taylor's avatar
Owen Taylor committed
225
    {
226 227
      register GLogDomain *last, *work;
      
228 229
      last = NULL;  

230 231 232 233 234 235 236 237 238 239 240 241 242
      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;
	    }
243 244
	  last = work;
	  work = last->next;
245
	}  
Owen Taylor's avatar
Owen Taylor committed
246
    }
247 248
}

249 250 251 252
static GLogFunc
g_log_domain_get_handler_L (GLogDomain	*domain,
			    GLogLevelFlags log_level,
			    gpointer	*data)
253 254
{
  if (domain && log_level)
Owen Taylor's avatar
Owen Taylor committed
255
    {
256 257 258 259 260 261 262 263 264 265 266 267
      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
268
    }
269 270 271
  return g_log_default_handler;
}

272 273 274 275 276
GLogLevelFlags
g_log_set_always_fatal (GLogLevelFlags fatal_mask)
{
  GLogLevelFlags old_mask;

277 278 279
  /* restrict the global mask to levels that are known to glib
   * since this setting applies to all domains
   */
280 281 282 283 284 285
  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;

286
  g_mutex_lock (g_messages_lock);
287 288
  old_mask = g_log_always_fatal;
  g_log_always_fatal = fatal_mask;
289
  g_mutex_unlock (g_messages_lock);
290 291 292 293

  return old_mask;
}

294
GLogLevelFlags
295 296
g_log_set_fatal_mask (const gchar   *log_domain,
		      GLogLevelFlags fatal_mask)
297 298 299 300 301 302 303 304 305 306 307 308
{
  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;
  
309 310
  g_mutex_lock (g_messages_lock);

311
  domain = g_log_find_domain_L (log_domain);
312
  if (!domain)
313
    domain = g_log_domain_new_L (log_domain);
314 315 316
  old_flags = domain->fatal_mask;
  
  domain->fatal_mask = fatal_mask;
317
  g_log_domain_check_free_L (domain);
318 319 320

  g_mutex_unlock (g_messages_lock);

321 322
  return old_flags;
}
Owen Taylor's avatar
Owen Taylor committed
323

324
guint
325 326 327 328
g_log_set_handler (const gchar	 *log_domain,
		   GLogLevelFlags log_levels,
		   GLogFunc	  log_func,
		   gpointer	  user_data)
329 330
{
  static guint handler_id = 0;
331 332
  GLogDomain *domain;
  GLogHandler *handler;
333 334 335 336 337 338
  
  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 = "";
339 340 341

  handler = g_new (GLogHandler, 1);

342 343
  g_mutex_lock (g_messages_lock);

344
  domain = g_log_find_domain_L (log_domain);
345
  if (!domain)
346
    domain = g_log_domain_new_L (log_domain);
347 348 349 350 351 352 353
  
  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;
354 355

  g_mutex_unlock (g_messages_lock);
356 357
  
  return handler_id;
Owen Taylor's avatar
Owen Taylor committed
358 359 360
}

void
361 362
g_log_remove_handler (const gchar *log_domain,
		      guint	   handler_id)
Owen Taylor's avatar
Owen Taylor committed
363
{
364 365 366 367 368 369 370
  register GLogDomain *domain;
  
  g_return_if_fail (handler_id > 0);
  
  if (!log_domain)
    log_domain = "";
  
371
  g_mutex_lock (g_messages_lock);
372
  domain = g_log_find_domain_L (log_domain);
373 374
  if (domain)
    {
375
      GLogHandler *work, *last;
376 377 378 379 380 381 382 383 384 385 386
      
      last = NULL;
      work = domain->handlers;
      while (work)
	{
	  if (work->id == handler_id)
	    {
	      if (last)
		last->next = work->next;
	      else
		domain->handlers = work->next;
387
	      g_log_domain_check_free_L (domain); 
388
	      g_mutex_unlock (g_messages_lock);
389
	      g_free (work);
390 391
	      return;
	    }
392 393
	  last = work;
	  work = last->next;
394
	}
395 396
    } 
  g_mutex_unlock (g_messages_lock);
397 398
  g_warning ("%s: could not find handler with id `%d' for domain \"%s\"",
	     G_STRLOC, handler_id, log_domain);
399
}
Owen Taylor's avatar
Owen Taylor committed
400

401
void
402 403 404 405
g_logv (const gchar   *log_domain,
	GLogLevelFlags log_level,
	const gchar   *format,
	va_list	       args1)
406 407
{
  gchar buffer[1025];
408 409 410
  gboolean was_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
  gboolean was_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
  gint i;
411 412 413

#ifndef  HAVE_VSNPRINTF
  va_list args2;
414
#endif	/* HAVE_VSNPRINTF */
415 416 417 418 419 420
  
  log_level &= G_LOG_LEVEL_MASK;
  if (!log_level)
    return;
  
  /* we use a stack buffer of fixed size, because we might get called
421
   * recursively.
422
   */
423 424 425
#ifdef  HAVE_VSNPRINTF
  vsnprintf (buffer, 1024, format, args1);
#else	/* !HAVE_VSNPRINTF */
426
  G_VA_COPY (args2, args1);
427
  if (printf_string_upper_bound (format, FALSE, args1) < 1024)
428 429 430 431 432 433 434 435 436
    vsprintf (buffer, format, args2);
  else
    {
      /* since we might be out of memory, we can't use g_vsnprintf(). */
      /* we are out of luck here */
      strncpy (buffer, format, 1024);
      buffer[1024] = 0;
    }
  va_end (args2);
437
#endif	/* !HAVE_VSNPRINTF */
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 499 500 501
#ifdef G_OS_WIN32
	      MessageBox (NULL, fatal_msg_buf, NULL, MB_OK);
#endif
#if defined (G_ENABLE_DEBUG) && (defined (SIGTRAP) || defined (G_OS_WIN32))
502
	      if (!(test_level & G_LOG_FLAG_RECURSION))
503
		G_BREAKPOINT ();
504 505
	      else
		abort ();
506
#else /* !G_ENABLE_DEBUG || !(SIGTRAP || G_OS_WIN32) */
507
	      abort ();
508
#endif /* !G_ENABLE_DEBUG || !(SIGTRAP || G_OS_WIN32) */
509
	    }
510
	  
511 512
	  depth--;
	  g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
513
	}
Owen Taylor's avatar
Owen Taylor committed
514
    }
515 516 517
}

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

530 531 532 533 534 535 536 537 538 539
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
    return g_convert_with_fallback (string, -1, charset, "UTF-8", "?", NULL, NULL, NULL);
}

540 541 542 543 544 545 546 547 548 549
/* 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)
550
{
551 552 553 554 555 556 557 558 559 560 561
  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;
    }
562
  
563 564 565 566 567 568
  if (!num)
    {
      *buf++ = '0';
      *buf = '\000';
      return;
    } 
569
  
570
  if (radix == 16)
Owen Taylor's avatar
Owen Taylor committed
571
    {
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
      *buf++ = '0';
      *buf++ = 'x';
    }
  else if (radix == 8)
    {
      *buf++ = '0';
    }
	
  n = 0;
  tmp = num;
  while (tmp)
    {
      tmp /= radix;
      n++;
    }
587

588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
  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';
603
      else
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
	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;
629 630
      break;
    case G_LOG_LEVEL_CRITICAL:
631 632
      strcpy (level_prefix, "CRITICAL");
      to_stdout = FALSE;
633 634
      break;
    case G_LOG_LEVEL_WARNING:
635 636
      strcpy (level_prefix, "WARNING");
      to_stdout = FALSE;
637 638
      break;
    case G_LOG_LEVEL_MESSAGE:
639 640
      strcpy (level_prefix, "Message");
      to_stdout = FALSE;
641 642
      break;
    case G_LOG_LEVEL_INFO:
643 644 645 646 647 648 649
      strcpy (level_prefix, "INFO");
      break;
    case G_LOG_LEVEL_DEBUG:
      strcpy (level_prefix, "DEBUG");
      break;
    default:
      if (log_level)
650
	{
651 652
	  strcpy (level_prefix, "LOG-");
	  format_unsigned (level_prefix + 4, log_level & G_LOG_LEVEL_MASK, 16);
653 654
	}
      else
655
	strcpy (level_prefix, "LOG");
656
      break;
657 658 659 660 661
    }
  if (log_level & G_LOG_FLAG_RECURSION)
    strcat (level_prefix, " (recursed)");
  if (log_level & ALERT_LEVELS)
    strcat (level_prefix, " **");
662

663 664 665 666 667 668 669 670 671
  ensure_stdout_valid ();
#ifdef G_OS_WIN32
  win32_keep_fatal_message = (log_level & G_LOG_FLAG_FATAL) != 0;
  /* Use just stdout as stderr is hard to get redirected from the DOS prompt. */
  return stdout;
#else
  return to_stdout ? 1 : 2;
#endif
}
672

673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 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
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)
	g_string_append_printf (gstring, "(process:%u): ", getpid ());
751
      else
752 753
	g_string_append_printf (gstring, "(%s:%u): ", prg_name, getpid ());
    }
754

755 756 757 758 759 760
  if (log_domain)
    {
      g_string_append (gstring, log_domain);
      g_string_append_c (gstring, '-');
    }
  g_string_append (gstring, level_prefix);
761

762 763 764 765 766 767 768 769 770
  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 */
771 772
      else
	{
773 774 775
	  string = strdup_convert (message, charset);
	  g_string_append (gstring, string);
	  g_free (string);
776
	}
Owen Taylor's avatar
Owen Taylor committed
777
    }
778 779 780 781 782 783 784 785 786
  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
787 788
}

789 790 791 792 793
GPrintFunc
g_set_print_handler (GPrintFunc func)
{
  GPrintFunc old_print_func;
  
794
  g_mutex_lock (g_messages_lock);
795 796
  old_print_func = glib_print_func;
  glib_print_func = func;
797
  g_mutex_unlock (g_messages_lock);
798 799 800 801
  
  return old_print_func;
}

Owen Taylor's avatar
Owen Taylor committed
802
void
803 804
g_print (const gchar *format,
	 ...)
Owen Taylor's avatar
Owen Taylor committed
805
{
806 807
  va_list args;
  gchar *string;
808
  GPrintFunc local_glib_print_func;
809 810 811
  
  g_return_if_fail (format != NULL);
  
Owen Taylor's avatar
Owen Taylor committed
812
  va_start (args, format);
813
  string = g_strdup_vprintf (format, args);
Owen Taylor's avatar
Owen Taylor committed
814
  va_end (args);
815
  
816 817 818
  g_mutex_lock (g_messages_lock);
  local_glib_print_func = glib_print_func;
  g_mutex_unlock (g_messages_lock);
819
  
820 821
  if (local_glib_print_func)
    local_glib_print_func (string);
Owen Taylor's avatar
Owen Taylor committed
822 823
  else
    {
824 825
      const gchar *charset;

826
      ensure_stdout_valid ();
827 828 829 830 831 832 833 834 835
      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);
	}
836
      fflush (stdout);
Owen Taylor's avatar
Owen Taylor committed
837
    }
838
  g_free (string);
Owen Taylor's avatar
Owen Taylor committed
839 840
}

841 842 843 844 845
GPrintFunc
g_set_printerr_handler (GPrintFunc func)
{
  GPrintFunc old_printerr_func;
  
846
  g_mutex_lock (g_messages_lock);
847 848
  old_printerr_func = glib_printerr_func;
  glib_printerr_func = func;
849
  g_mutex_unlock (g_messages_lock);
850 851 852 853
  
  return old_printerr_func;
}

Owen Taylor's avatar
Owen Taylor committed
854
void
855 856
g_printerr (const gchar *format,
	    ...)
Owen Taylor's avatar
Owen Taylor committed
857
{
858 859
  va_list args;
  gchar *string;
860
  GPrintFunc local_glib_printerr_func;
861 862 863
  
  g_return_if_fail (format != NULL);
  
Owen Taylor's avatar
Owen Taylor committed
864
  va_start (args, format);
865
  string = g_strdup_vprintf (format, args);
Owen Taylor's avatar
Owen Taylor committed
866
  va_end (args);
867
  
868 869 870
  g_mutex_lock (g_messages_lock);
  local_glib_printerr_func = glib_printerr_func;
  g_mutex_unlock (g_messages_lock);
871
  
872 873
  if (local_glib_printerr_func)
    local_glib_printerr_func (string);
Owen Taylor's avatar
Owen Taylor committed
874 875
  else
    {
876 877 878 879 880 881 882 883 884 885 886
      const gchar *charset;

      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);
	}
887
      fflush (stderr);
Owen Taylor's avatar
Owen Taylor committed
888
    }
889
  g_free (string);
Owen Taylor's avatar
Owen Taylor committed
890 891
}

892 893 894 895
#ifndef MB_LEN_MAX
#  define MB_LEN_MAX 8
#endif

896 897
#ifndef HAVE_C99_VSNPRINTF

898 899 900 901 902 903 904 905 906
typedef struct
{
  guint min_width;
  guint precision;
  gboolean alternate_format, zero_padding, adjust_left, locale_grouping;
  gboolean add_space, add_sign, possible_sign, seen_precision;
  gboolean mod_half, mod_long, mod_extra_long;
} PrintfArgSpec;

907
static gsize
908 909 910 911 912
printf_string_upper_bound (const gchar *format,
			   gboolean     may_warn,
			   va_list      args)
{
  static const gboolean honour_longs = SIZEOF_LONG > 4 || SIZEOF_VOID_P > 4;
913
  gsize len = 1;
914
  
915 916
  if (!format)
    return len;
917
  
918 919 920
  while (*format)
    {
      register gchar c = *format++;
921
      
922 923 924 925 926 927
      if (c != '%')
	len += 1;
      else /* (c == '%') */
	{
	  PrintfArgSpec spec = { 0, };
	  gboolean seen_l = FALSE, conv_done = FALSE;
928
	  gsize conv_len = 0;
929
	  const gchar *spec_start = format;
930
	  
931 932 933 934 935 936 937 938
	  do
	    {
	      c = *format++;
	      switch (c)
		{
		  GDoubleIEEE754 u_double;
		  guint v_uint;
		  gint v_int;
Havoc Pennington's avatar
Havoc Pennington committed
939
		  const gchar *v_string;
940
		  
941 942 943 944 945 946 947
		  /* beware of positional parameters
		   */
		case '$':
		  if (may_warn)
		    g_warning (G_GNUC_PRETTY_FUNCTION
			       "(): unable to handle positional parameters (%%n$)");
		  len += 1024; /* try adding some safety padding */
948
		  conv_done = TRUE;
949
		  break;
950
		  
951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970
		  /* parse flags
		   */
		case '#':
		  spec.alternate_format = TRUE;
		  break;
		case '0':
		  spec.zero_padding = TRUE;
		  break;
		case '-':
		  spec.adjust_left = TRUE;
		  break;
		case ' ':
		  spec.add_space = TRUE;
		  break;
		case '+':
		  spec.add_sign = TRUE;
		  break;
		case '\'':
		  spec.locale_grouping = TRUE;
		  break;
971
		  
972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
		  /* parse output size specifications
		   */
		case '.':
		  spec.seen_precision = TRUE;
		  break;
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		  v_uint = c - '0';
		  c = *format;
		  while (c >= '0' && c <= '9')
		    {
		      format++;
		      v_uint = v_uint * 10 + c - '0';
		      c = *format;
		    }
		  if (spec.seen_precision)
		    spec.precision = MAX (spec.precision, v_uint);
		  else
		    spec.min_width = MAX (spec.min_width, v_uint);
		  break;
		case '*':
		  v_int = va_arg (args, int);
		  if (spec.seen_precision)
		    {
		      /* forget about negative precision */
		      if (v_int >= 0)
			spec.precision = MAX (spec.precision, v_int);
		    }
		  else
		    {
		      if (v_int < 0)
			{
			  v_int = - v_int;
			  spec.adjust_left = TRUE;
			}
		      spec.min_width = MAX (spec.min_width, v_int);
		    }
		  break;
1017
		  
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054
		  /* parse type modifiers
		   */
		case 'h':
		  spec.mod_half = TRUE;
		  break;
		case 'l':
		  if (!seen_l)
		    {
		      spec.mod_long = TRUE;
		      seen_l = TRUE;
		      break;
		    }
		  /* else, fall through */
		case 'L':
		case 'q':
		  spec.mod_long = TRUE;
		  spec.mod_extra_long = TRUE;
		  break;
		case 'z':
		case 'Z':
#if GLIB_SIZEOF_SIZE_T > 4
		  spec.mod_long = TRUE;
		  spec.mod_extra_long = TRUE;
#endif /* GLIB_SIZEOF_SIZE_T > 4 */
		  break;
		case 't':
#if GLIB_SIZEOF_PTRDIFF_T > 4
		  spec.mod_long = TRUE;
		  spec.mod_extra_long = TRUE;
#endif /* GLIB_SIZEOF_PTRDIFF_T > 4 */
		  break;
		case 'j':
#if GLIB_SIZEOF_INTMAX_T > 4
		  spec.mod_long = TRUE;
		  spec.mod_extra_long = TRUE;
#endif /* GLIB_SIZEOF_INTMAX_T > 4 */
		  break;
1055
		  
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119
		  /* parse output conversions
		   */
		case '%':
		  conv_len += 1;
		  break;
		case 'O':
		case 'D':
		case 'I':
		case 'U':
		  /* some C libraries feature long variants for these as well? */
		  spec.mod_long = TRUE;
		  /* fall through */
		case 'o':
		  conv_len += 2;
		  /* fall through */
		case 'd':
		case 'i':
		  conv_len += 1; /* sign */
		  /* fall through */
		case 'u':
		  conv_len += 4;
		  /* fall through */
		case 'x':
		case 'X':
		  spec.possible_sign = TRUE;
		  conv_len += 10;
		  if (spec.mod_long && honour_longs)
		    conv_len *= 2;
		  if (spec.mod_extra_long)
		    conv_len *= 2;
		  if (spec.mod_extra_long)
		    {
		      (void) va_arg (args, gint64);
		    }
		  else if (spec.mod_long)
		    (void) va_arg (args, long);
		  else
		    (void) va_arg (args, int);
		  break;
		case 'A':
		case 'a':
		  /*          0x */
		  conv_len += 2;
		  /* fall through */
		case 'g':
		case 'G':
		case 'e':
		case 'E':
		case 'f':
		  spec.possible_sign = TRUE;
		  /*          n   .   dddddddddddddddddddddddd   E   +-  eeee */
		  conv_len += 1 + 1 + MAX (24, spec.precision) + 1 + 1 + 4;
                  if (may_warn && spec.mod_extra_long)
		    g_warning (G_GNUC_PRETTY_FUNCTION
			       "(): unable to handle long double, collecting double only");
#ifdef HAVE_LONG_DOUBLE
#error need to implement special handling for long double
#endif
		  u_double.v_double = va_arg (args, double);
		  /* %f can expand up to all significant digits before '.' (308) */
		  if (c == 'f' &&
		      u_double.mpn.biased_exponent > 0 && u_double.mpn.biased_exponent < 2047)
		    {
		      gint exp = u_double.mpn.biased_exponent;
1120
		      
1121 1122
		      exp -= G_IEEE754_DOUBLE_BIAS;
		      exp = exp * G_LOG_2_BASE_10 + 1;
1123
		      conv_len += ABS (exp);	/* exp can be <0 */
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
		    }
		  /* some printf() implementations require extra padding for rounding */
		  conv_len += 2;
		  /* we can't really handle locale specific grouping here */
		  if (spec.locale_grouping)
		    conv_len *= 2;
		  break;
		case 'C':
		  spec.mod_long = TRUE;
                  /* fall through */
		case 'c':
		  conv_len += spec.mod_long ? MB_LEN_MAX : 1;
		  (void) va_arg (args, int);
		  break;
		case 'S':
		  spec.mod_long = TRUE;
		  /* fall through */
		case 's':
		  v_string = va_arg (args, char*);
		  if (!v_string)
		    conv_len += 8; /* hold "(null)" */
		  else if (spec.seen_precision)
		    conv_len += spec.precision;
		  else
		    conv_len += strlen (v_string);
		  conv_done = TRUE;
		  if (spec.mod_long)
		    {
		      if (may_warn)
			g_warning (G_GNUC_PRETTY_FUNCTION
				   "(): unable to handle wide char strings");
		      len += 1024; /* try adding some safety padding */
		    }
		  break;
		case 'P': /* do we actually need this? */
		  /* fall through */
		case 'p':
		  spec.alternate_format = TRUE;
		  conv_len += 10;
		  if (honour_longs)
		    conv_len *= 2;
		  /* fall through */
		case 'n':
		  conv_done = TRUE;
		  (void) va_arg (args, void*);
		  break;
		case 'm':
		  /* there's not much we can do to be clever */
		  v_string = g_strerror (errno);
		  v_uint = v_string ? strlen (v_string) : 0;
		  conv_len += MAX (256, v_uint);
		  break;
1176
		  
1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
		  /* handle invalid cases
		   */
		case '\000':
		  /* no conversion specification, bad bad */
		  conv_len += format - spec_start;
		  break;
		default:
		  if (may_warn)
		    g_warning (G_GNUC_PRETTY_FUNCTION
			       "(): unable to handle `%c' while parsing format",
			       c);
		  break;
		}
	      conv_done |= conv_len > 0;
	    }
	  while (!conv_done);
	  /* handle width specifications */
	  conv_len = MAX (conv_len, MAX (spec.precision, spec.min_width));
	  /* handle flags */
	  conv_len += spec.alternate_format ? 2 : 0;
	  conv_len += (spec.add_space || spec.add_sign || spec.possible_sign);
	  /* finally done */
	  len += conv_len;
	} /* else (c == '%') */
    } /* while (*format) */
1202
  
1203 1204 1205
  return len;
}

1206 1207 1208
#endif /* !HAVE_C99_VSNPRINTF */


1209
gsize
1210 1211 1212
g_printf_string_upper_bound (const gchar *format,
			     va_list      args)
{
1213 1214
#if HAVE_C99_VSNPRINTF
  gchar c;
1215
  return vsnprintf (&c, 1, format, args) + 1;
1216
#else
1217
  return printf_string_upper_bound (format, TRUE, args);
1218
#endif
1219 1220
}

1221 1222 1223
void
g_messages_init (void)
{
1224 1225
  g_messages_lock = g_mutex_new ();
  g_log_depth = g_private_new (NULL);
1226
  g_messages_prefixed_init ();
1227 1228 1229 1230 1231 1232
  _g_debug_init ();
}

gboolean _g_debug_initialized = FALSE;
guint _g_debug_flags = 0;

1233 1234
void
_g_debug_init (void) 
1235 1236 1237 1238
{
  const gchar *val;
  
  _g_debug_initialized = TRUE;
1239
  
1240 1241 1242 1243 1244 1245
  val = g_getenv ("G_DEBUG");
  if (val != NULL)
    {
      static const GDebugKey keys[] = {
	{"fatal_warnings", G_DEBUG_FATAL_WARNINGS}
      };
1246
      
1247 1248
      _g_debug_flags = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
    }
1249
  
1250 1251 1252 1253 1254 1255 1256 1257
  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);
    }
1258
}