[gjs] Call JS_SetLocaleCallbacks()



commit c1dd7fcfbda1c69e59eecdca4e22b775244edb26
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Thu Apr 30 16:33:51 2009 -0400

    Call JS_SetLocaleCallbacks()
    
    SpiderMonkey doesn't implement locale handling for functions
    like String.toLocaleLowerCase itself; it depends on a set of
    "callbacks" being set on the context.
    
    gjs/context.c: Implement locale callbacks in terms of GLib
    js/testLocale.js: tests for locale handling
    
    http://bugzilla.gnome.org/show_bug.cgi?id=580865
---
 Makefile-test.am      |    1 +
 gjs/context.c         |  118 +++++++++++++++++++++++++++++++++++++++++++++++++
 test/js/testLocale.js |   44 ++++++++++++++++++
 3 files changed, 163 insertions(+), 0 deletions(-)

diff --git a/Makefile-test.am b/Makefile-test.am
index 66495f6..141046b 100644
--- a/Makefile-test.am
+++ b/Makefile-test.am
@@ -112,6 +112,7 @@ EXTRA_DIST +=					\
 	test/js/testGI.js			\
 	test/js/testImporter.js			\
 	test/js/testLang.js			\
+	test/js/testLocale.js			\
 	test/js/testMainloop.js			\
 	test/js/testSignals.js			\
 	test/js/testTweener.js
diff --git a/gjs/context.c b/gjs/context.c
index 5e500b0..ec7013a 100644
--- a/gjs/context.c
+++ b/gjs/context.c
@@ -304,6 +304,122 @@ gjs_context_finalize(GObject *object)
     G_OBJECT_CLASS(gjs_context_parent_class)->finalize(object);
 }
 
+/* Implementations of locale-specific operations; these are used
+ * in the implementation of String.localeCompare(), Date.toLocaleDateString(),
+ * and so forth. We take the straight-forward approach of converting
+ * to UTF-8, using the appropriate GLib functions, and converting
+ * back if necessary.
+ */
+static JSBool
+gjs_locale_to_upper_case (JSContext *context,
+                          JSString  *src,
+                          jsval     *retval)
+{
+    JSBool success = JS_FALSE;
+    char *utf8 = NULL;
+    char *upper_case_utf8 = NULL;
+
+    if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(src), &utf8))
+        goto out;
+
+    upper_case_utf8 = g_utf8_strup (utf8, -1);
+
+    if (!gjs_string_from_utf8(context, upper_case_utf8, -1, retval))
+        goto out;
+
+    success = JS_TRUE;
+
+out:
+    g_free(utf8);
+    g_free(upper_case_utf8);
+
+    return success;
+}
+
+static JSBool
+gjs_locale_to_lower_case (JSContext *context,
+                          JSString  *src,
+                          jsval     *retval)
+{
+    JSBool success = JS_FALSE;
+    char *utf8 = NULL;
+    char *lower_case_utf8 = NULL;
+
+    if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(src), &utf8))
+        goto out;
+
+    lower_case_utf8 = g_utf8_strdown (utf8, -1);
+
+    if (!gjs_string_from_utf8(context, lower_case_utf8, -1, retval))
+        goto out;
+
+    success = JS_TRUE;
+
+out:
+    g_free(utf8);
+    g_free(lower_case_utf8);
+
+    return success;
+}
+
+static JSBool
+gjs_locale_compare (JSContext *context,
+                    JSString  *src_1,
+                    JSString  *src_2,
+                    jsval     *retval)
+{
+    JSBool success = JS_FALSE;
+    char *utf8_1 = NULL, *utf8_2 = NULL;
+    int result;
+
+    if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(src_1), &utf8_1) ||
+        !gjs_string_to_utf8(context, STRING_TO_JSVAL(src_2), &utf8_2))
+        goto out;
+
+    result = g_utf8_collate (utf8_1, utf8_2);
+    *retval = INT_TO_JSVAL(result);
+
+    success = JS_TRUE;
+
+out:
+    g_free(utf8_1);
+    g_free(utf8_2);
+
+    return success;
+}
+
+static JSBool
+gjs_locale_to_unicode (JSContext *context,
+                       char      *src,
+                       jsval     *retval)
+{
+    JSBool success;
+    char *utf8;
+    GError *error = NULL;
+
+    utf8 = g_locale_to_utf8(src, -1, NULL, NULL, &error);
+    if (!utf8) {
+        gjs_throw(context,
+                  "Failed to convert locale string to UTF8: %s",
+                  error->message);
+        g_error_free(error);
+        return JS_FALSE;
+    }
+
+    success = gjs_string_from_utf8(context, utf8, -1, retval);
+    g_free (utf8);
+
+    return success;
+}
+
+static JSLocaleCallbacks gjs_locale_callbacks =
+{
+    gjs_locale_to_upper_case,
+    gjs_locale_to_lower_case,
+    gjs_locale_compare,
+    gjs_locale_to_unicode
+};
+
 static GObject*
 gjs_context_constructor (GType                  type,
                          guint                  n_construct_properties,
@@ -345,6 +461,8 @@ gjs_context_constructor (GType                  type,
                   JSOPTION_DONT_REPORT_UNCAUGHT |
                   JSOPTION_STRICT);
 
+    JS_SetLocaleCallbacks(js_context->context, &gjs_locale_callbacks);
+
     JS_SetErrorReporter(js_context->context, gjs_error_reporter);
 
     /* set ourselves as the private data */
diff --git a/test/js/testLocale.js b/test/js/testLocale.js
new file mode 100644
index 0000000..1984efe
--- /dev/null
+++ b/test/js/testLocale.js
@@ -0,0 +1,44 @@
+// tests for JS_SetLocaleCallbacks().
+
+function testToLocaleDateString() {
+    let date = new Date();
+    // %A is the weekday name, this tests locale_to_unicode
+    // we're basically just testing for a non-crash, since
+    // we'd have to run in a specific locale to have any
+    // idea about the result.
+    date.toLocaleDateString("%A");
+}
+
+function testToLocaleLowerCase() {
+    assertEquals("aaa", "AAA".toLocaleLowerCase());
+
+    // String conversion is implemented internally to GLib,
+    // and is more-or-less independent of locale. (A few
+    // characters are handled specially for a few locales,
+    // like i in Turkish. But not A WITH ACUTE)
+    assertEquals("\u00e1", "\u00c1".toLocaleLowerCase());
+
+    // Unpaired surrogate, can't be converted to UTF-8
+    assertRaises(function() { "\ud800".toLocaleLowerCase(); });
+}
+
+function testToLocaleUpperCase() {
+    assertEquals("AAA", "aaa".toLocaleUpperCase());
+    assertEquals("\u00c1", "\u00e1".toLocaleUpperCase());
+    assertRaises(function() { "\ud800".toLocaleUpperCase(); });
+}
+
+function testToLocaleCompare() {
+    // GLib calls out to libc for collation, so we can't really
+    // assume anything - we could even be running in the
+    // C locale. The below is pretty safe.
+    assertEquals(-1, "a".localeCompare("b"));
+    assertEquals( 0, "a".localeCompare("a"));
+    assertEquals( 1, "b".localeCompare("a"));
+
+    // Again test error handling when conversion fails
+    assertRaises(function() { "\ud800".localeCompare("a"); });
+    assertRaises(function() { "a".localeCompare("\ud800"); });
+}
+
+gjstestRun();



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