Bug 556186 – gpoll.h breaks gmain.h inclusion
[platform/upstream/glib.git] / glib / gmessages.c
index d2b8efb..7b90a02 100644 (file)
 #include "glib.h"
 #include "gdebug.h"
 #include "gprintfint.h"
+#include "gthreadprivate.h"
+#include "galias.h"
 
 #ifdef G_OS_WIN32
-typedef FILE* GFileDescriptor;
-#else
-typedef gint GFileDescriptor;
+#include <process.h>           /* For getpid() */
+#include <io.h>
+#  define STRICT               /* Strict typing, please */
+#  define _WIN32_WINDOWS 0x0401 /* to get IsDebuggerPresent */
+#  include <windows.h>
+#  undef STRICT
 #endif
 
 /* --- structures --- */
@@ -79,27 +84,26 @@ static GPrintFunc     glib_print_func = NULL;
 static GPrintFunc     glib_printerr_func = NULL;
 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;
-
+static GLogFunc       default_log_func = g_log_default_handler;
+static gpointer       default_log_data = NULL;
 
 /* --- functions --- */
 #ifdef G_OS_WIN32
 #  define STRICT
 #  include <windows.h>
 #  undef STRICT
-#  include <process.h>          /* For _getpid() */
 static gboolean win32_keep_fatal_message = FALSE;
 
 /* This default message will usually be overwritten. */
-/* Yes, a fixed size buffer is bad. So sue me. But g_error is never
- * with huge strings, is it?
+/* Yes, a fixed size buffer is bad. So sue me. But g_error() is never
+ * called with huge strings, is it?
  */
 static gchar  fatal_msg_buf[1000] = "Unspecified fatal error encountered, aborting.";
 static gchar *fatal_msg_ptr = fatal_msg_buf;
 
-/* Just use stdio. If we're out of memory, we're hosed anyway. */
 #undef write
 static inline int
-dowrite (GFileDescriptor fd,
+dowrite (int          fd,
         const void  *buf,
         unsigned int len)
 {
@@ -111,65 +115,17 @@ dowrite (GFileDescriptor fd,
       return len;
     }
 
-  fwrite (buf, len, 1, fd);
-  fflush (fd);
+  write (fd, buf, len);
 
   return len;
 }
 #define write(fd, buf, len) dowrite(fd, buf, len)
 
-static void
-ensure_stdout_valid (void)
-{
-  static gboolean alloc_console_called = FALSE;
-  HANDLE handle;
-
-  if (win32_keep_fatal_message)
-    return;
-
-  if (!alloc_console_called)
-    {
-      handle = GetStdHandle (STD_OUTPUT_HANDLE);
-  
-      if (handle == INVALID_HANDLE_VALUE)
-       {
-         AllocConsole ();
-         alloc_console_called = TRUE;
-         freopen ("CONOUT$", "w", stdout);
-       }
-    }
-}
-
-static void
-ensure_stderr_valid (void)
-{
-  static gboolean alloc_console_called = FALSE;
-  HANDLE handle;
-
-  if (win32_keep_fatal_message)
-    return;
-
-  if (!alloc_console_called)
-    {
-      handle = GetStdHandle (STD_ERROR_HANDLE);
-  
-      if (handle == INVALID_HANDLE_VALUE)
-       {
-         AllocConsole ();
-         alloc_console_called = TRUE;
-         freopen ("CONOUT$", "w", stderr);
-       }
-    }
-}
-
-#else
-#define ensure_stdout_valid()  /* Define as empty */
-#define ensure_stderr_valid()
 #endif
 
 static void
-write_string (GFileDescriptor fd,
-             const gchar    *string)
+write_string (int          fd,
+             const gchar *string)
 {
   write (fd, string, strlen (string));
 }
@@ -188,7 +144,7 @@ g_messages_prefixed_init (void)
       
       if (val)
        {
-         static const GDebugKey keys[] = {
+         const GDebugKey keys[] = {
            { "error", G_LOG_LEVEL_ERROR },
            { "critical", G_LOG_LEVEL_CRITICAL },
            { "warning", G_LOG_LEVEL_WARNING },
@@ -282,7 +238,9 @@ g_log_domain_get_handler_L (GLogDomain      *domain,
          handler = handler->next;
        }
     }
-  return g_log_default_handler;
+
+  *data = default_log_data;
+  return default_log_func;
 }
 
 GLogLevelFlags
@@ -373,6 +331,21 @@ g_log_set_handler (const gchar      *log_domain,
   return handler_id;
 }
 
+GLogFunc
+g_log_set_default_handler (GLogFunc log_func,
+                          gpointer user_data)
+{
+  GLogFunc old_log_func;
+  
+  g_mutex_lock (g_messages_lock);
+  old_log_func = default_log_func;
+  default_log_func = log_func;
+  default_log_data = user_data;
+  g_mutex_unlock (g_messages_lock);
+  
+  return old_log_func;
+}
+
 void
 g_log_remove_handler (const gchar *log_domain,
                      guint        handler_id)
@@ -420,7 +393,6 @@ g_logv (const gchar   *log_domain,
        const gchar   *format,
        va_list        args1)
 {
-  gchar buffer[1025];
   gboolean was_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
   gboolean was_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
   gint i;
@@ -429,11 +401,6 @@ g_logv (const gchar   *log_domain,
   if (!log_level)
     return;
   
-  /* we use a stack buffer of fixed size, because we might get called
-   * recursively.
-   */
-  _g_vsnprintf (buffer, 1024, format, args1);
-  
   for (i = g_bit_nth_msf (log_level, -1); i >= 0; i = g_bit_nth_msf (log_level, i))
     {
       register GLogLevelFlags test_level;
@@ -444,7 +411,7 @@ g_logv (const gchar   *log_domain,
          guint depth = GPOINTER_TO_UINT (g_private_get (g_log_depth));
          GLogDomain *domain;
          GLogFunc log_func;
-         guint domain_fatal_mask;
+         GLogLevelFlags domain_fatal_mask;
          gpointer data = NULL;
 
          if (was_fatal)
@@ -473,7 +440,7 @@ g_logv (const gchar   *log_domain,
          /* 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;
+             GLogLevelFlags orig_test_level = test_level;
 
              _g_debug_init ();
              if ((domain_fatal_mask | g_log_always_fatal) & test_level)
@@ -489,23 +456,47 @@ g_logv (const gchar   *log_domain,
                }
            }
 
-         log_func (log_domain, test_level, buffer, data);
+         if (test_level & G_LOG_FLAG_RECURSION)
+           {
+             /* we use a stack buffer of fixed size, since we're likely
+              * in an out-of-memory situation
+              */
+             gchar buffer[1025];
+             gint size;
+             size = _g_vsnprintf (buffer, 1024, format, args1);
+
+             log_func (log_domain, test_level, buffer, data);
+           }
+         else
+           {
+             gchar *msg = g_strdup_vprintf (format, args1);
+
+             log_func (log_domain, test_level, msg, data);
+
+             g_free (msg);
+           }
 
          if (test_level & G_LOG_FLAG_FATAL)
            {
 #ifdef G_OS_WIN32
              gchar *locale_msg = g_locale_from_utf8 (fatal_msg_buf, -1, NULL, NULL, NULL);
              
-             MessageBox (NULL, locale_msg, NULL, MB_OK);
-#endif
-#if defined (G_ENABLE_DEBUG) && (defined (SIGTRAP) || defined (G_OS_WIN32))
+             MessageBox (NULL, locale_msg, NULL,
+                         MB_ICONERROR|MB_SETFOREGROUND);
+             if (IsDebuggerPresent () && !(test_level & G_LOG_FLAG_RECURSION))
+               G_BREAKPOINT ();
+             else
+               abort ();
+#else
+#if defined (G_ENABLE_DEBUG) && defined (SIGTRAP)
              if (!(test_level & G_LOG_FLAG_RECURSION))
                G_BREAKPOINT ();
              else
                abort ();
-#else /* !G_ENABLE_DEBUG || !(SIGTRAP || G_OS_WIN32) */
+#else /* !G_ENABLE_DEBUG || !SIGTRAP */
              abort ();
-#endif /* !G_ENABLE_DEBUG || !(SIGTRAP || G_OS_WIN32) */
+#endif /* !G_ENABLE_DEBUG || !SIGTRAP */
+#endif /* !G_OS_WIN32 */
            }
          
          depth--;
@@ -527,12 +518,95 @@ g_log (const gchar   *log_domain,
   va_end (args);
 }
 
+void
+g_return_if_fail_warning (const char *log_domain,
+                         const char *pretty_function,
+                         const char *expression)
+{
+  /*
+   * Omit the prefix used by the PLT-reduction
+   * technique used in GTK+. 
+   */
+  if (g_str_has_prefix (pretty_function, "IA__"))
+    pretty_function += 4;
+  g_log (log_domain,
+        G_LOG_LEVEL_CRITICAL,
+        "%s: assertion `%s' failed",
+        pretty_function,
+        expression);
+}
+
+void
+g_warn_message (const char     *domain,
+                const char     *file,
+                int             line,
+                const char     *func,
+                const char     *warnexpr)
+{
+  char *s, lstr[32];
+  g_snprintf (lstr, 32, "%d", line);
+  if (warnexpr)
+    s = g_strconcat ("(", file, ":", lstr, "):",
+                     func, func[0] ? ":" : "",
+                     " runtime check failed: (", warnexpr, ")", NULL);
+  else
+    s = g_strconcat ("(", file, ":", lstr, "):",
+                     func, func[0] ? ":" : "",
+                     " ", "code should not be reached", NULL);
+  g_log (domain, G_LOG_LEVEL_WARNING, "%s", s);
+  g_free (s);
+}
+
+void
+g_assert_warning (const char *log_domain,
+                 const char *file,
+                 const int   line,
+                 const char *pretty_function,
+                 const char *expression)
+{
+  /*
+   * Omit the prefix used by the PLT-reduction
+   * technique used in GTK+. 
+   */
+  if (g_str_has_prefix (pretty_function, "IA__"))
+    pretty_function += 4;
+  g_log (log_domain,
+        G_LOG_LEVEL_ERROR,
+        expression 
+        ? "file %s: line %d (%s): assertion failed: (%s)"
+        : "file %s: line %d (%s): should not be reached",
+        file, 
+        line, 
+        pretty_function,
+        expression);
+  abort ();
+}
+
+#define CHAR_IS_SAFE(wc) (!((wc < 0x20 && wc != '\t' && wc != '\n' && wc != '\r') || \
+                           (wc == 0x7f) || \
+                           (wc >= 0x80 && wc < 0xa0)))
+     
 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);
+    {
+      GString *gstring = g_string_new ("[Invalid UTF-8] ");
+      guchar *p;
+
+      for (p = (guchar *)string; *p; p++)
+       {
+         if (CHAR_IS_SAFE(*p) &&
+             !(*p == '\r' && *(p + 1) != '\n') &&
+             *p < 0x80)
+           g_string_append_c (gstring, *p);
+         else
+           g_string_append_printf (gstring, "\\x%02x", (guint)(guchar)*p);
+       }
+      
+      return g_string_free (gstring, FALSE);
+    }
   else
     {
       GError *err = NULL;
@@ -548,7 +622,6 @@ strdup_convert (const gchar *string,
          if (!warned)
            {
              warned = TRUE;
-             ensure_stderr_valid ();
              _g_fprintf (stderr, "GLib: Cannot convert message: %s\n", err->message);
            }
          g_error_free (err);
@@ -634,9 +707,9 @@ format_unsigned (gchar  *buf,
 
 #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)
+static int
+mklevel_prefix (gchar          level_prefix[STRING_BUFFER_SIZE],
+               GLogLevelFlags log_level)
 {
   gboolean to_stdout = TRUE;
 
@@ -683,20 +756,8 @@ mklevel_prefix (gchar level_prefix[STRING_BUFFER_SIZE],
 
 #ifdef G_OS_WIN32
   win32_keep_fatal_message = (log_level & G_LOG_FLAG_FATAL) != 0;
-
-  if (to_stdout)
-    {
-      ensure_stdout_valid ();
-      return stdout;
-    }
-  else
-    {
-      ensure_stderr_valid ();
-      return stderr;
-    }
-#else
-  return to_stdout ? 1 : 2;
 #endif
+  return to_stdout ? 1 : 2;
 }
 
 void
@@ -705,9 +766,12 @@ _g_log_fallback_handler (const gchar   *log_domain,
                         const gchar   *message,
                         gpointer       unused_data)
 {
-  gchar level_prefix[STRING_BUFFER_SIZE], pid_string[FORMAT_UNSIGNED_BUFSIZE];
+  gchar level_prefix[STRING_BUFFER_SIZE];
+#ifndef G_OS_WIN32
+  gchar pid_string[FORMAT_UNSIGNED_BUFSIZE];
+#endif
   gboolean is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
-  GFileDescriptor fd;
+  int fd;
 
   /* we can not call _any_ GLib functions in this fallback handler,
    * which is why we skip UTF-8 conversion, etc.
@@ -720,15 +784,21 @@ _g_log_fallback_handler (const gchar   *log_domain,
   if (!message)
     message = "(NULL) message";
 
+#ifndef G_OS_WIN32
   format_unsigned (pid_string, getpid (), 10);
+#endif
 
   if (log_domain)
     write_string (fd, "\n");
   else
     write_string (fd, "\n** ");
+
+#ifndef G_OS_WIN32
   write_string (fd, "(process:");
   write_string (fd, pid_string);
   write_string (fd, "): ");
+#endif
+
   if (log_domain)
     {
       write_string (fd, log_domain);
@@ -743,6 +813,66 @@ _g_log_fallback_handler (const gchar   *log_domain,
     write_string (fd, "\n");
 }
 
+static void
+escape_string (GString *string)
+{
+  const char *p = string->str;
+  gunichar wc;
+
+  while (p < string->str + string->len)
+    {
+      gboolean safe;
+           
+      wc = g_utf8_get_char_validated (p, -1);
+      if (wc == (gunichar)-1 || wc == (gunichar)-2)  
+       {
+         gchar *tmp;
+         guint pos;
+
+         pos = p - string->str;
+
+         /* Emit invalid UTF-8 as hex escapes 
+           */
+         tmp = g_strdup_printf ("\\x%02x", (guint)(guchar)*p);
+         g_string_erase (string, pos, 1);
+         g_string_insert (string, pos, tmp);
+
+         p = string->str + (pos + 4); /* Skip over escape sequence */
+
+         g_free (tmp);
+         continue;
+       }
+      if (wc == '\r')
+       {
+         safe = *(p + 1) == '\n';
+       }
+      else
+       {
+         safe = CHAR_IS_SAFE (wc);
+       }
+      
+      if (!safe)
+       {
+         gchar *tmp;
+         guint pos;
+
+         pos = p - string->str;
+         
+         /* Largest char we escape is 0x0a, so we don't have to worry
+          * about 8-digit \Uxxxxyyyy
+          */
+         tmp = g_strdup_printf ("\\u%04x", wc); 
+         g_string_erase (string, pos, g_utf8_next_char (p) - p);
+         g_string_insert (string, pos, tmp);
+         g_free (tmp);
+
+         p = string->str + (pos + 6); /* Skip over escape sequence */
+       }
+      else
+       p = g_utf8_next_char (p);
+    }
+}
+
 void
 g_log_default_handler (const gchar   *log_domain,
                       GLogLevelFlags log_level,
@@ -752,7 +882,7 @@ g_log_default_handler (const gchar   *log_domain,
   gboolean is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
   gchar level_prefix[STRING_BUFFER_SIZE], *string;
   GString *gstring;
-  GFileDescriptor fd;
+  int fd;
 
   /* we can be called externally with recursion for whatever reason */
   if (log_level & G_LOG_FLAG_RECURSION)
@@ -765,7 +895,7 @@ g_log_default_handler (const gchar   *log_domain,
 
   fd = mklevel_prefix (level_prefix, log_level);
 
-  gstring = g_string_new ("");
+  gstring = g_string_new (NULL);
   if (log_level & ALERT_LEVELS)
     g_string_append (gstring, "\n");
   if (!log_domain)
@@ -793,16 +923,22 @@ g_log_default_handler (const gchar   *log_domain,
     g_string_append (gstring, "(NULL) message");
   else
     {
+      GString *msg;
       const gchar *charset;
 
+      msg = g_string_new (message);
+      escape_string (msg);
+
       if (g_get_charset (&charset))
-       g_string_append (gstring, message);     /* charset is UTF-8 already */
+       g_string_append (gstring, msg->str);    /* charset is UTF-8 already */
       else
        {
-         string = strdup_convert (message, charset);
+         string = strdup_convert (msg->str, charset);
          g_string_append (gstring, string);
          g_free (string);
        }
+
+      g_string_free (msg, TRUE);
     }
   if (is_fatal)
     g_string_append (gstring, "\naborting...\n");
@@ -852,7 +988,6 @@ g_print (const gchar *format,
     {
       const gchar *charset;
 
-      ensure_stdout_valid ();
       if (g_get_charset (&charset))
        fputs (string, stdout); /* charset is UTF-8 already */
       else
@@ -904,7 +1039,6 @@ g_printerr (const gchar *format,
     {
       const gchar *charset;
 
-      ensure_stderr_valid ();
       if (g_get_charset (&charset))
        fputs (string, stderr); /* charset is UTF-8 already */
       else
@@ -928,7 +1062,7 @@ g_printf_string_upper_bound (const gchar *format,
 }
 
 void
-g_messages_init (void)
+_g_messages_thread_init_nomessage (void)
 {
   g_messages_lock = g_mutex_new ();
   g_log_depth = g_private_new (NULL);
@@ -949,8 +1083,9 @@ _g_debug_init (void)
   val = g_getenv ("G_DEBUG");
   if (val != NULL)
     {
-      static const GDebugKey keys[] = {
-       {"fatal_warnings", G_DEBUG_FATAL_WARNINGS}
+      const GDebugKey keys[] = {
+       {"fatal_warnings", G_DEBUG_FATAL_WARNINGS},
+       {"fatal_criticals", G_DEBUG_FATAL_CRITICALS}
       };
       
       _g_debug_flags = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
@@ -964,4 +1099,16 @@ _g_debug_init (void)
       fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
       g_log_set_always_fatal (fatal_mask);
     }
+  
+  if (_g_debug_flags & G_DEBUG_FATAL_CRITICALS) 
+    {
+      GLogLevelFlags fatal_mask;
+      
+      fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
+      fatal_mask |= G_LOG_LEVEL_CRITICAL;
+      g_log_set_always_fatal (fatal_mask);
+    }
 }
+
+#define __G_MESSAGES_C__
+#include "galiasdef.c"