summaryrefslogtreecommitdiff
path: root/glib/gmessages.c
diff options
context:
space:
mode:
Diffstat (limited to 'glib/gmessages.c')
-rw-r--r--glib/gmessages.c322
1 files changed, 166 insertions, 156 deletions
diff --git a/glib/gmessages.c b/glib/gmessages.c
index 97c5b31b1..541b08130 100644
--- a/glib/gmessages.c
+++ b/glib/gmessages.c
@@ -192,6 +192,7 @@
#include "gcharset.h"
#include "gconvert.h"
#include "genviron.h"
+#include "glib-private.h"
#include "gmain.h"
#include "gmem.h"
#include "gprintfint.h"
@@ -202,6 +203,10 @@
#include "gpattern.h"
#include "gthreadprivate.h"
+#if defined(__linux__) && !defined(__BIONIC__)
+#include "gjournal-private.h"
+#endif
+
#ifdef G_OS_UNIX
#include <unistd.h>
#endif
@@ -215,22 +220,6 @@
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#endif
-#if defined (_MSC_VER) && (_MSC_VER >=1400)
-/* This is ugly, but we need it for isatty() in case we have bad fd's,
- * otherwise Windows will abort() the program on msvcrt80.dll and later
- */
-#include <crtdbg.h>
-
-_GLIB_EXTERN void
-myInvalidParameterHandler(const wchar_t *expression,
- const wchar_t *function,
- const wchar_t *file,
- unsigned int line,
- uintptr_t pReserved)
-{
-}
-#endif
-
#include "gwin32.h"
#endif
@@ -512,12 +501,14 @@ struct _GLogHandler
GLogHandler *next;
};
+static void g_default_print_func (const gchar *string);
+static void g_default_printerr_func (const gchar *string);
/* --- variables --- */
static GMutex g_messages_lock;
static GLogDomain *g_log_domains = NULL;
-static GPrintFunc glib_print_func = NULL;
-static GPrintFunc glib_printerr_func = NULL;
+static GPrintFunc glib_print_func = g_default_print_func;
+static GPrintFunc glib_printerr_func = g_default_printerr_func;
static GPrivate g_log_depth;
static GPrivate g_log_structured_depth;
static GLogFunc default_log_func = g_log_default_handler;
@@ -532,6 +523,11 @@ static gboolean g_log_debug_enabled = FALSE; /* (atomic) */
/* --- functions --- */
static void _g_log_abort (gboolean breakpoint);
+static inline const char * format_string (const char *format,
+ va_list args,
+ char **out_allocated_string)
+ G_GNUC_PRINTF (1, 0);
+static inline FILE * log_level_to_file (GLogLevelFlags log_level);
static void
_g_log_abort (gboolean breakpoint)
@@ -597,7 +593,12 @@ static void
write_string (FILE *stream,
const gchar *string)
{
- fputs (string, stream);
+ if (fputs (string, stream) == EOF)
+ {
+ /* Something failed, but it's not an error we can handle at glib level
+ * so let's just continue without the compiler blaming us
+ */
+ }
}
static void
@@ -608,8 +609,12 @@ write_string_sized (FILE *stream,
/* Is it nul-terminated? */
if (length < 0)
write_string (stream, string);
- else
- fwrite (string, 1, length, stream);
+ else if (fwrite (string, 1, length, stream) < (size_t) length)
+ {
+ /* Something failed, but it's not an error we can handle at glib level
+ * so let's just continue without the compiler blaming us
+ */
+ }
}
static GLogDomain*
@@ -1204,8 +1209,6 @@ mklevel_prefix (gchar level_prefix[STRING_BUFFER_SIZE],
GLogLevelFlags log_level,
gboolean use_color)
{
- gboolean to_stdout = !gmessages_use_stderr;
-
/* we may not call _any_ GLib functions here */
strcpy (level_prefix, log_level_to_color (log_level, use_color));
@@ -1214,19 +1217,15 @@ mklevel_prefix (gchar level_prefix[STRING_BUFFER_SIZE],
{
case G_LOG_LEVEL_ERROR:
strcat (level_prefix, "ERROR");
- to_stdout = FALSE;
break;
case G_LOG_LEVEL_CRITICAL:
strcat (level_prefix, "CRITICAL");
- to_stdout = FALSE;
break;
case G_LOG_LEVEL_WARNING:
strcat (level_prefix, "WARNING");
- to_stdout = FALSE;
break;
case G_LOG_LEVEL_MESSAGE:
strcat (level_prefix, "Message");
- to_stdout = FALSE;
break;
case G_LOG_LEVEL_INFO:
strcat (level_prefix, "INFO");
@@ -1256,7 +1255,7 @@ mklevel_prefix (gchar level_prefix[STRING_BUFFER_SIZE],
if ((log_level & G_LOG_FLAG_FATAL) != 0 && !g_test_initialized ())
win32_keep_fatal_message = TRUE;
#endif
- return to_stdout ? stdout : stderr;
+ return log_level_to_file (log_level);
}
typedef struct {
@@ -1296,7 +1295,8 @@ g_logv (const gchar *log_domain,
{
gboolean was_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
gboolean was_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
- gchar buffer[1025], *msg, *msg_alloc = NULL;
+ char buffer[1025], *msg_alloc = NULL;
+ const char *msg;
gint i;
log_level &= G_LOG_LEVEL_MASK;
@@ -1314,7 +1314,9 @@ g_logv (const gchar *log_domain,
msg = buffer;
}
else
- msg = msg_alloc = g_strdup_vprintf (format, args);
+ {
+ msg = format_string (format, args, &msg_alloc);
+ }
if (expected_messages)
{
@@ -1482,7 +1484,7 @@ log_level_to_priority (GLogLevelFlags log_level)
return "5";
}
-static FILE *
+static inline FILE *
log_level_to_file (GLogLevelFlags log_level)
{
if (gmessages_use_stderr)
@@ -1638,6 +1640,12 @@ done_query:
* the code which sets them. For example, custom keys from GLib all have a
* `GLIB_` prefix.
*
+ * Note that keys that expect UTF-8 strings (specifically `"MESSAGE"` and
+ * `"GLIB_DOMAIN"`) must be passed as NUL-terminated UTF-8 strings until GLib
+ * version 2.74.1 because the default log handler did not consider the length of
+ * the `GLogField`. Starting with GLib 2.74.1 this is fixed and
+ * non-NUL-terminated UTF-8 strings can be passed with their correct length.
+ *
* The @log_domain will be converted into a `GLIB_DOMAIN` field. @log_level will
* be converted into a
* [`PRIORITY`](https://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html#PRIORITY=)
@@ -1779,7 +1787,7 @@ g_log_structured (const gchar *log_domain,
}
else
{
- message = message_allocated = g_strdup_vprintf (format, args);
+ message = format_string (format, args, &message_allocated);
}
/* Add MESSAGE, PRIORITY and GLIB_DOMAIN. */
@@ -2023,7 +2031,7 @@ g_log_structured_standard (const gchar *log_domain,
}
else
{
- fields[4].value = message_allocated = g_strdup_vprintf (message_format, args);
+ fields[4].value = format_string (message_format, args, &message_allocated);
}
va_end (args);
@@ -2092,12 +2100,7 @@ g_log_writer_supports_color (gint output_fd)
{
#ifdef G_OS_WIN32
gboolean result = FALSE;
-
-#if (defined (_MSC_VER) && _MSC_VER >= 1400)
- _invalid_parameter_handler oldHandler, newHandler;
- int prev_report_mode = 0;
-#endif
-
+ GWin32InvalidParameterHandler handler;
#endif
g_return_val_if_fail (output_fd >= 0, FALSE);
@@ -2124,17 +2127,7 @@ g_log_writer_supports_color (gint output_fd)
*/
#ifdef G_OS_WIN32
-#if (defined (_MSC_VER) && _MSC_VER >= 1400)
- /* Set up our empty invalid parameter handler, for isatty(),
- * in case of bad fd's passed in for isatty(), so that
- * msvcrt80.dll+ won't abort the program
- */
- newHandler = myInvalidParameterHandler;
- oldHandler = _set_invalid_parameter_handler (newHandler);
-
- /* Disable the message box for assertions. */
- prev_report_mode = _CrtSetReportMode(_CRT_ASSERT, 0);
-#endif
+ g_win32_push_empty_invalid_parameter_handler (&handler);
if (g_win32_check_windows_version (10, 0, 0, G_WIN32_OS_ANY))
{
@@ -2166,10 +2159,7 @@ g_log_writer_supports_color (gint output_fd)
result = win32_is_pipe_tty (output_fd);
reset_invalid_param_handler:
-#if defined (_MSC_VER) && (_MSC_VER >= 1400)
- _CrtSetReportMode(_CRT_ASSERT, prev_report_mode);
- _set_invalid_parameter_handler (oldHandler);
-#endif
+ g_win32_pop_invalid_parameter_handler (&handler);
return result;
#else
@@ -2223,32 +2213,10 @@ gboolean
g_log_writer_is_journald (gint output_fd)
{
#if defined(__linux__) && !defined(__BIONIC__)
- /* FIXME: Use the new journal API for detecting whether we’re writing to the
- * journal. See: https://github.com/systemd/systemd/issues/2473
- */
- union {
- struct sockaddr_storage storage;
- struct sockaddr sa;
- struct sockaddr_un un;
- } addr;
- socklen_t addr_len;
- int err;
-
- if (output_fd < 0)
- return FALSE;
-
- /* Namespaced journals start with `/run/systemd/journal.${name}/` (see
- * `RuntimeDirectory=systemd/journal.%i` in `systemd-journald@.service`. The
- * default journal starts with `/run/systemd/journal/`. */
- memset (&addr, 0, sizeof (addr));
- addr_len = sizeof(addr);
- err = getpeername (output_fd, &addr.sa, &addr_len);
- if (err == 0 && addr.storage.ss_family == AF_UNIX)
- return (g_str_has_prefix (addr.un.sun_path, "/run/systemd/journal/") ||
- g_str_has_prefix (addr.un.sun_path, "/run/systemd/journal."));
-#endif
-
+ return _g_fd_is_journal (output_fd);
+#else
return FALSE;
+#endif
}
static void escape_string (GString *string);
@@ -2286,6 +2254,8 @@ g_log_writer_format_fields (GLogLevelFlags log_level,
gsize i;
const gchar *message = NULL;
const gchar *log_domain = NULL;
+ gssize message_length = -1;
+ gssize log_domain_length = -1;
gchar level_prefix[STRING_BUFFER_SIZE];
GString *gstring;
gint64 now;
@@ -2299,9 +2269,15 @@ g_log_writer_format_fields (GLogLevelFlags log_level,
const GLogField *field = &fields[i];
if (g_strcmp0 (field->key, "MESSAGE") == 0)
- message = field->value;
+ {
+ message = field->value;
+ message_length = field->length;
+ }
else if (g_strcmp0 (field->key, "GLIB_DOMAIN") == 0)
- log_domain = field->value;
+ {
+ log_domain = field->value;
+ log_domain_length = field->length;
+ }
}
/* Format things. */
@@ -2327,7 +2303,7 @@ g_log_writer_format_fields (GLogLevelFlags log_level,
if (log_domain != NULL)
{
- g_string_append (gstring, log_domain);
+ g_string_append_len (gstring, log_domain, log_domain_length);
g_string_append_c (gstring, '-');
}
g_string_append (gstring, level_prefix);
@@ -2357,7 +2333,7 @@ g_log_writer_format_fields (GLogLevelFlags log_level,
GString *msg;
const gchar *charset;
- msg = g_string_new (message);
+ msg = g_string_new_len (message, message_length);
escape_string (msg);
if (g_get_console_charset (&charset))
@@ -3163,6 +3139,7 @@ _g_log_fallback_handler (const gchar *log_domain,
write_string (stream, level_prefix);
write_string (stream, ": ");
write_string (stream, message);
+ write_string (stream, "\n");
}
static void
@@ -3309,29 +3286,95 @@ g_log_default_handler (const gchar *log_domain,
/**
* g_set_print_handler:
- * @func: the new print handler
+ * @func: (nullable): the new print handler or %NULL to
+ * reset to the default
*
- * Sets the print handler.
+ * Sets the print handler to @func, or resets it to the
+ * default GLib handler if %NULL.
*
* Any messages passed to g_print() will be output via
- * the new handler. The default handler simply outputs
- * the message to stdout. By providing your own handler
+ * the new handler. The default handler outputs
+ * the encoded message to stdout. By providing your own handler
* you can redirect the output, to a GTK+ widget or a
* log file for example.
*
- * Returns: the old print handler
+ * Since 2.76 this functions always returns a valid
+ * #GPrintFunc, and never returns %NULL. If no custom
+ * print handler was set, it will return the GLib
+ * default print handler and that can be re-used to
+ * decorate its output and/or to write to stderr
+ * in all platforms. Before GLib 2.76, this was %NULL.
+ *
+ * Returns: (not nullable): the old print handler
*/
GPrintFunc
g_set_print_handler (GPrintFunc func)
{
- GPrintFunc old_print_func;
+ return g_atomic_pointer_exchange (&glib_print_func,
+ func ? func : g_default_print_func);
+}
+
+static void
+print_string (FILE *stream,
+ const gchar *string)
+{
+ const gchar *charset;
+ int ret;
- g_mutex_lock (&g_messages_lock);
- old_print_func = glib_print_func;
- glib_print_func = func;
- g_mutex_unlock (&g_messages_lock);
+ if (g_get_console_charset (&charset))
+ {
+ /* charset is UTF-8 already */
+ ret = fputs (string, stream);
+ }
+ else
+ {
+ gchar *converted_string = strdup_convert (string, charset);
+
+ ret = fputs (converted_string, stream);
+ g_free (converted_string);
+ }
+
+ /* In case of failure we can just return early, but there's nothing else
+ * we can do at this level
+ */
+ if (ret == EOF)
+ return;
+
+ fflush (stream);
+}
+
+G_ALWAYS_INLINE static inline const char *
+format_string (const char *format,
+ va_list args,
+ char **out_allocated_string)
+{
+#ifdef G_ENABLE_DEBUG
+ g_assert (out_allocated_string != NULL);
+#endif
- return old_print_func;
+ /* If there is no formatting to be done, avoid an allocation */
+ if (strchr (format, '%') == NULL)
+ {
+ *out_allocated_string = NULL;
+ return format;
+ }
+ else
+ {
+ *out_allocated_string = g_strdup_vprintf (format, args);
+ return *out_allocated_string;
+ }
+}
+
+static void
+g_default_print_func (const gchar *string)
+{
+ print_string (stdout, string);
+}
+
+static void
+g_default_printerr_func (const gchar *string)
+{
+ print_string (stderr, string);
}
/**
@@ -3340,7 +3383,7 @@ g_set_print_handler (GPrintFunc func)
* @...: the parameters to insert into the format string
*
* Outputs a formatted message via the print handler.
- * The default print handler simply outputs the message to stdout, without
+ * The default print handler outputs the encoded message to stdout, without
* appending a trailing new-line character. Typically, @format should end with
* its own new-line character.
*
@@ -3355,64 +3398,49 @@ g_print (const gchar *format,
...)
{
va_list args;
- gchar *string;
+ const gchar *string;
+ gchar *free_me = NULL;
GPrintFunc local_glib_print_func;
g_return_if_fail (format != NULL);
va_start (args, format);
- string = g_strdup_vprintf (format, args);
+ string = format_string (format, args, &free_me);
va_end (args);
- g_mutex_lock (&g_messages_lock);
- local_glib_print_func = glib_print_func;
- g_mutex_unlock (&g_messages_lock);
-
- if (local_glib_print_func)
- local_glib_print_func (string);
- else
- {
- const gchar *charset;
-
- if (g_get_console_charset (&charset))
- fputs (string, stdout); /* charset is UTF-8 already */
- else
- {
- gchar *lstring = strdup_convert (string, charset);
-
- fputs (lstring, stdout);
- g_free (lstring);
- }
- fflush (stdout);
- }
- g_free (string);
+ local_glib_print_func = g_atomic_pointer_get (&glib_print_func);
+ local_glib_print_func (string);
+ g_free (free_me);
}
/**
* g_set_printerr_handler:
- * @func: the new error message handler
+ * @func: (nullable): he new error message handler or %NULL
+ * to reset to the default
*
- * Sets the handler for printing error messages.
+ * Sets the handler for printing error messages to @func,
+ * or resets it to the default GLib handler if %NULL.
*
* Any messages passed to g_printerr() will be output via
- * the new handler. The default handler simply outputs the
+ * the new handler. The default handler outputs the encoded
* message to stderr. By providing your own handler you can
* redirect the output, to a GTK+ widget or a log file for
* example.
*
- * Returns: the old error message handler
+ * Since 2.76 this functions always returns a valid
+ * #GPrintFunc, and never returns %NULL. If no custom error
+ * print handler was set, it will return the GLib default
+ * error print handler and that can be re-used to decorate
+ * its output and/or to write to stderr in all platforms.
+ * Before GLib 2.76, this was %NULL.
+ *
+ * Returns: (not nullable): the old error message handler
*/
GPrintFunc
g_set_printerr_handler (GPrintFunc func)
{
- GPrintFunc old_printerr_func;
-
- g_mutex_lock (&g_messages_lock);
- old_printerr_func = glib_printerr_func;
- glib_printerr_func = func;
- g_mutex_unlock (&g_messages_lock);
-
- return old_printerr_func;
+ return g_atomic_pointer_exchange (&glib_printerr_func,
+ func ? func : g_default_printerr_func);
}
/**
@@ -3421,7 +3449,7 @@ g_set_printerr_handler (GPrintFunc func)
* @...: the parameters to insert into the format string
*
* Outputs a formatted message via the error message handler.
- * The default handler simply outputs the message to stderr, without appending
+ * The default handler outputs the encoded message to stderr, without appending
* a trailing new-line character. Typically, @format should end with its own
* new-line character.
*
@@ -3434,37 +3462,19 @@ g_printerr (const gchar *format,
...)
{
va_list args;
- gchar *string;
+ const char *string;
+ char *free_me = NULL;
GPrintFunc local_glib_printerr_func;
g_return_if_fail (format != NULL);
va_start (args, format);
- string = g_strdup_vprintf (format, args);
+ string = format_string (format, args, &free_me);
va_end (args);
- g_mutex_lock (&g_messages_lock);
- local_glib_printerr_func = glib_printerr_func;
- g_mutex_unlock (&g_messages_lock);
-
- if (local_glib_printerr_func)
- local_glib_printerr_func (string);
- else
- {
- const gchar *charset;
-
- if (g_get_console_charset (&charset))
- fputs (string, stderr); /* charset is UTF-8 already */
- else
- {
- gchar *lstring = strdup_convert (string, charset);
-
- fputs (lstring, stderr);
- g_free (lstring);
- }
- fflush (stderr);
- }
- g_free (string);
+ local_glib_printerr_func = g_atomic_pointer_get (&glib_printerr_func);
+ local_glib_printerr_func (string);
+ g_free (free_me);
}
/**