commit 52593563c9e9873231f5fdae3dc1668460bee37e Author: Colin Walters Date: Wed Dec 1 17:11:16 2010 -0500 gjs_value_debug_string: Always return UTF-8 Returning whatever JS_GetStringBytes gave us will blow up if the string contains non-UTF8 characters and we're trying to g_print to a UTF-8 terminal (the standard case). Since this is just a debugging string, import a copy of _g_utf8_make_valid which squashes it to UTF-8 in a useful way. diff --git a/gjs/jsapi-util.c b/gjs/jsapi-util.c index 11c890a..714b91e 100644 --- a/gjs/jsapi-util.c +++ b/gjs/jsapi-util.c @@ -755,12 +755,20 @@ gjs_define_string_array(JSContext *context, return array; } -const char* +/** + * gjs_value_debug_string: + * @context: + * @value: Any JavaScript value + * + * Returns: A UTF-8 encoded string describing @value + */ +char* gjs_value_debug_string(JSContext *context, jsval value) { JSString *str; const char *bytes; + char *debugstr; JS_BeginRequest(context); @@ -778,14 +786,14 @@ gjs_value_debug_string(JSContext *context, str = JS_NewStringCopyZ(context, klass->name); JS_ClearPendingException(context); if (str == NULL) { - return "[out of memory copying class name]"; + return g_strdup("[out of memory copying class name]"); } } else { gjs_log_exception(context, NULL); - return "[unknown object]"; + return g_strdup("[unknown object]"); } } else { - return "[unknown non-object]"; + return g_strdup("[unknown non-object]"); } } @@ -795,7 +803,9 @@ gjs_value_debug_string(JSContext *context, JS_EndRequest(context); - return bytes; + debugstr = _gjs_g_utf8_make_valid(bytes); + + return debugstr; } void @@ -829,6 +839,7 @@ gjs_log_object_props(JSContext *context, while (!JSID_IS_VOID(prop_id)) { jsval propval; const char *name; + char *debugstr; if (!gjs_get_string_id(context, prop_id, &name)) goto next; @@ -836,10 +847,12 @@ gjs_log_object_props(JSContext *context, if (!gjs_object_get_property(context, obj, name, &propval)) goto next; + debugstr = gjs_value_debug_string(context, propval); gjs_debug(topic, "%s%s = '%s'", prefix, name, - gjs_value_debug_string(context, propval)); + debugstr); + g_free(debugstr); next: prop_id = JSID_VOID; @@ -859,6 +872,7 @@ gjs_explain_scope(JSContext *context, JSObject *global; JSObject *parent; GString *chain; + char *debugstr; gjs_debug(GJS_DEBUG_SCOPE, "=== %s ===", @@ -874,14 +888,16 @@ gjs_explain_scope(JSContext *context, ""); global = JS_GetGlobalObject(context); + debugstr = gjs_value_debug_string(context, OBJECT_TO_JSVAL(global)); gjs_debug(GJS_DEBUG_SCOPE, " Global: %p %s", - global, gjs_value_debug_string(context, OBJECT_TO_JSVAL(global))); + global, debugstr); + g_free(debugstr); parent = JS_GetScopeChain(context); chain = g_string_new(NULL); while (parent != NULL) { - const char *debug; + char *debug; debug = gjs_value_debug_string(context, OBJECT_TO_JSVAL(parent)); if (chain->len > 0) @@ -889,6 +905,7 @@ gjs_explain_scope(JSContext *context, g_string_append_printf(chain, "%p %s", parent, debug); + g_free(debug); parent = JS_GetParent(context, parent); } gjs_debug(GJS_DEBUG_SCOPE, diff --git a/gjs/jsapi-util.h b/gjs/jsapi-util.h index 424cded..b7c6a8b 100644 --- a/gjs/jsapi-util.h +++ b/gjs/jsapi-util.h @@ -267,7 +267,7 @@ void gjs_log_object_props (JSContext *context, GjsDebugTopic topic, const char *prefix); #endif -const char* gjs_value_debug_string (JSContext *context, +char* gjs_value_debug_string (JSContext *context, jsval value); void gjs_explain_scope (JSContext *context, const char *title); diff --git a/util/glib.c b/util/glib.c index 316e6e0..b79e75f 100644 --- a/util/glib.c +++ b/util/glib.c @@ -21,10 +21,12 @@ * IN THE SOFTWARE. */ -#include +#include #include "glib.h" +#include + typedef struct { void *key; void *value; @@ -125,6 +127,46 @@ gjs_g_strv_concat(char ***strv_array, int len) return (char**)g_ptr_array_free(array, FALSE); } +gchar * +_gjs_g_utf8_make_valid (const gchar *name) +{ + GString *string; + const gchar *remainder, *invalid; + gint remaining_bytes, valid_bytes; + + g_return_val_if_fail (name != NULL, NULL); + + string = NULL; + remainder = name; + remaining_bytes = strlen (name); + + while (remaining_bytes != 0) + { + if (g_utf8_validate (remainder, remaining_bytes, &invalid)) + break; + valid_bytes = invalid - remainder; + + if (string == NULL) + string = g_string_sized_new (remaining_bytes); + + g_string_append_len (string, remainder, valid_bytes); + /* append U+FFFD REPLACEMENT CHARACTER */ + g_string_append (string, "\357\277\275"); + + remaining_bytes -= valid_bytes + 1; + remainder = invalid + 1; + } + + if (string == NULL) + return g_strdup (name); + + g_string_append (string, remainder); + + g_assert (g_utf8_validate (string->str, -1, NULL)); + + return g_string_free (string, FALSE); +} + #if GJS_BUILD_TESTS void diff --git a/util/glib.h b/util/glib.h index 7bdc01a..5be171f 100644 --- a/util/glib.h +++ b/util/glib.h @@ -28,6 +28,8 @@ G_BEGIN_DECLS +gchar * _gjs_g_utf8_make_valid (const gchar *name); + gboolean gjs_g_hash_table_remove_one (GHashTable *hash, void **key_p, void **value_p);