[gjs] gjs_value_debug_string: Always return UTF-8



commit 52593563c9e9873231f5fdae3dc1668460bee37e
Author: Colin Walters <walters verbum org>
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.

 gjs/jsapi-util.c |   33 +++++++++++++++++++++++++--------
 gjs/jsapi-util.h |    2 +-
 util/glib.c      |   44 +++++++++++++++++++++++++++++++++++++++++++-
 util/glib.h      |    2 ++
 4 files changed, 71 insertions(+), 10 deletions(-)
---
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 <config.h>
+#include <string.h>
 
 #include "glib.h"
 
+#include <config.h>
+
 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);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]