[API] Make all _from_string() functions take a len parameter
authorBehdad Esfahbod <behdad@behdad.org>
Fri, 26 Aug 2011 07:18:53 +0000 (09:18 +0200)
committerBehdad Esfahbod <behdad@behdad.org>
Fri, 26 Aug 2011 07:22:12 +0000 (09:22 +0200)
Can be -1 for NUL-terminated string.  This is useful for passing parts
of a larger string to a function without having to copy or modify the
string first.

Affected functions:

hb_tag_t hb_tag_from_string()
hb_direction_from_string()
hb_language_from_string()
hb_script_from_string()

src/hb-common.cc
src/hb-common.h
src/hb-graphite2.cc
src/hb-icu.cc
src/hb-ot-tag.cc
test/test-buffer.c
test/test-common.c
test/test-ot-tag.c
util/hb-view.cc
util/options.cc

index 48382ca..6093289 100644 (file)
 /* hb_tag_t */
 
 hb_tag_t
-hb_tag_from_string (const char *s)
+hb_tag_from_string (const char *s, int len)
 {
   char tag[4];
   unsigned int i;
 
-  if (!s || !*s)
+  if (!s || !len || !*s)
     return HB_TAG_NONE;
 
-  for (i = 0; i < 4 && s[i]; i++)
+  if (len < 0 || len > 4)
+    len = 4;
+  for (i = 0; i < (unsigned) len && s[i]; i++)
     tag[i] = s[i];
   for (; i < 4; i++)
     tag[i] = ' ';
@@ -67,9 +69,9 @@ const char direction_strings[][4] = {
 };
 
 hb_direction_t
-hb_direction_from_string (const char *str)
+hb_direction_from_string (const char *str, int len)
 {
-  if (unlikely (!str || !*str))
+  if (unlikely (!str || !len || !*str))
     return HB_DIRECTION_INVALID;
 
   /* Lets match loosely: just match the first letter, such that
@@ -167,11 +169,18 @@ static struct hb_static_lang_set_t : hb_lockable_set_t<hb_language_item_t, hb_st
 } langs;
 
 hb_language_t
-hb_language_from_string (const char *str)
+hb_language_from_string (const char *str, int len)
 {
-  if (!str || !*str)
+  if (!str || !len || !*str)
     return HB_LANGUAGE_INVALID;
 
+  char strbuf[32];
+  if (len >= 0) {
+    len = MIN (len, (int) sizeof (strbuf) - 1);
+    str = (char *) memcpy (strbuf, str, len);
+    strbuf[len] = '\0';
+  }
+
   hb_language_item_t *item = langs.find_or_insert (str, langs.lock);
 
   return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
@@ -197,7 +206,7 @@ hb_language_get_default (void)
     /* I hear that setlocale() doesn't honor env vars on Windows,
      * but for now we ignore that. */
 
-    default_language = hb_language_from_string (setlocale (LC_CTYPE, NULL));
+    default_language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1);
   }
 
   return default_language;
@@ -241,9 +250,9 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
 }
 
 hb_script_t
-hb_script_from_string (const char *s)
+hb_script_from_string (const char *s, int len)
 {
-  return hb_script_from_iso15924_tag (hb_tag_from_string (s));
+  return hb_script_from_iso15924_tag (hb_tag_from_string (s, len));
 }
 
 hb_tag_t
index e4f1991..b7fef32 100644 (file)
@@ -89,7 +89,8 @@ typedef uint32_t hb_tag_t;
 
 #define HB_TAG_NONE HB_TAG(0,0,0,0)
 
-hb_tag_t hb_tag_from_string (const char *s);
+/* len=-1 means s is NUL-terminated */
+hb_tag_t hb_tag_from_string (const char *s, int len);
 
 
 /* hb_direction_t */
@@ -102,8 +103,9 @@ typedef enum {
   HB_DIRECTION_BTT
 } hb_direction_t;
 
+/* len=-1 means s is NUL-terminated */
 hb_direction_t
-hb_direction_from_string (const char *str);
+hb_direction_from_string (const char *str, int len);
 
 const char *
 hb_direction_to_string (hb_direction_t direction);
@@ -119,8 +121,9 @@ hb_direction_to_string (hb_direction_t direction);
 
 typedef struct _hb_language_t *hb_language_t;
 
+/* len=-1 means s is NUL-terminated */
 hb_language_t
-hb_language_from_string (const char *str);
+hb_language_from_string (const char *str, int len);
 
 const char *
 hb_language_to_string (hb_language_t language);
@@ -293,8 +296,9 @@ hb_script_t
 hb_script_from_iso15924_tag (hb_tag_t tag);
 
 /* suger for tag_from_string() then script_from_iso15924_tag */
+/* len=-1 means s is NUL-terminated */
 hb_script_t
-hb_script_from_string (const char *s);
+hb_script_from_string (const char *s, int len);
 
 hb_tag_t
 hb_script_to_iso15924_tag (hb_script_t script);
index dfeab9f..76b8a2f 100644 (file)
@@ -238,7 +238,7 @@ hb_graphite_shape (hb_font_t          *font,
 
   /* XXX(behdad): Do we need OT lang tag here? */
   const char *lang = hb_language_to_string (hb_buffer_get_language (buffer));
-  gr_feature_val *feats = gr_face_featureval_for_lang (data->grface, lang ? hb_tag_from_string (lang) : 0);
+  gr_feature_val *feats = gr_face_featureval_for_lang (data->grface, lang ? hb_tag_from_string (lang, -1) : 0);
 
   while (num_features--)
   {
index 82e4989..0f5ed1c 100644 (file)
@@ -46,7 +46,7 @@ hb_icu_script_to_script (UScriptCode script)
   if (unlikely (script == USCRIPT_INVALID_CODE))
     return HB_SCRIPT_INVALID;
 
-  return hb_script_from_string (uscript_getShortName (script));
+  return hb_script_from_string (uscript_getShortName (script), -1);
 }
 
 UScriptCode
index e910f95..dcae8f1 100644 (file)
@@ -664,12 +664,12 @@ hb_ot_tag_to_language (hb_tag_t tag)
 
   for (i = 0; i < ARRAY_LENGTH (ot_languages); i++)
     if (ot_languages[i].tag == tag)
-      return hb_language_from_string (ot_languages[i].language);
+      return hb_language_from_string (ot_languages[i].language, -1);
 
   /* If tag starts with ZH, it's Chinese */
   if ((tag & 0xFFFF0000)  == 0x5A480000) {
     switch (tag) {
-      case HB_TAG('Z','H','H',' '): return hb_language_from_string ("zh-hk"); /* Hong Kong */
+      case HB_TAG('Z','H','H',' '): return hb_language_from_string ("zh-hk", -1); /* Hong Kong */
       default: {
         /* Encode the tag... */
        unsigned char buf[14] = "zh-x-hbot";
@@ -680,7 +680,7 @@ hb_ot_tag_to_language (hb_tag_t tag)
        if (buf[12] == 0x20)
          buf[12] = '\0';
        buf[13] = '\0';
-       return hb_language_from_string ((char *) buf);
+       return hb_language_from_string ((char *) buf, -1);
       }
     }
   }
@@ -695,7 +695,7 @@ hb_ot_tag_to_language (hb_tag_t tag)
     if (buf[9] == 0x20)
       buf[9] = '\0';
     buf[10] = '\0';
-    return hb_language_from_string ((char *) buf);
+    return hb_language_from_string ((char *) buf, -1);
   }
 }
 
index ec32e15..ab818d0 100644 (file)
@@ -124,8 +124,8 @@ test_buffer_properties (fixture_t *fixture, gconstpointer user_data)
   hb_buffer_set_script (b, HB_SCRIPT_ARABIC);
   g_assert (hb_buffer_get_script (b) == HB_SCRIPT_ARABIC);
 
-  hb_buffer_set_language (b, hb_language_from_string ("fa"));
-  g_assert (hb_buffer_get_language (b) == hb_language_from_string ("Fa"));
+  hb_buffer_set_language (b, hb_language_from_string ("fa", -1));
+  g_assert (hb_buffer_get_language (b) == hb_language_from_string ("Fa", -1));
 
 
   /* test reset clears properties */
index d5cbfc7..e00e601 100644 (file)
@@ -79,14 +79,15 @@ test_types_direction (void)
   g_assert_cmpint (HB_DIRECTION_REVERSE (HB_DIRECTION_TTB), ==, HB_DIRECTION_BTT);
   g_assert_cmpint (HB_DIRECTION_REVERSE (HB_DIRECTION_BTT), ==, HB_DIRECTION_TTB);
 
-  g_assert_cmpint (HB_DIRECTION_INVALID, ==, hb_direction_from_string (NULL));
-  g_assert_cmpint (HB_DIRECTION_INVALID, ==, hb_direction_from_string (""));
-  g_assert_cmpint (HB_DIRECTION_INVALID, ==, hb_direction_from_string ("x"));
-  g_assert_cmpint (HB_DIRECTION_RTL, ==, hb_direction_from_string ("r"));
-  g_assert_cmpint (HB_DIRECTION_RTL, ==, hb_direction_from_string ("rtl"));
-  g_assert_cmpint (HB_DIRECTION_RTL, ==, hb_direction_from_string ("RtL"));
-  g_assert_cmpint (HB_DIRECTION_RTL, ==, hb_direction_from_string ("right-to-left"));
-  g_assert_cmpint (HB_DIRECTION_TTB, ==, hb_direction_from_string ("ttb"));
+  g_assert_cmpint (HB_DIRECTION_INVALID, ==, hb_direction_from_string (NULL, -1));
+  g_assert_cmpint (HB_DIRECTION_INVALID, ==, hb_direction_from_string ("", -1));
+  g_assert_cmpint (HB_DIRECTION_INVALID, ==, hb_direction_from_string ("t", 0));
+  g_assert_cmpint (HB_DIRECTION_INVALID, ==, hb_direction_from_string ("x", -1));
+  g_assert_cmpint (HB_DIRECTION_RTL, ==, hb_direction_from_string ("r", -1));
+  g_assert_cmpint (HB_DIRECTION_RTL, ==, hb_direction_from_string ("rtl", -1));
+  g_assert_cmpint (HB_DIRECTION_RTL, ==, hb_direction_from_string ("RtL", -1));
+  g_assert_cmpint (HB_DIRECTION_RTL, ==, hb_direction_from_string ("right-to-left", -1));
+  g_assert_cmpint (HB_DIRECTION_TTB, ==, hb_direction_from_string ("ttb", -1));
 
   g_assert (0 == strcmp ("ltr", hb_direction_to_string (HB_DIRECTION_LTR)));
   g_assert (0 == strcmp ("rtl", hb_direction_to_string (HB_DIRECTION_RTL)));
@@ -102,14 +103,20 @@ test_types_tag (void)
 
   g_assert_cmphex (HB_TAG ('a','B','c','D'), ==, 0x61426344);
 
-  g_assert_cmphex (hb_tag_from_string ("aBcDe"), ==, 0x61426344);
-  g_assert_cmphex (hb_tag_from_string ("aBcD"),  ==, 0x61426344);
-  g_assert_cmphex (hb_tag_from_string ("aBc"),   ==, 0x61426320);
-  g_assert_cmphex (hb_tag_from_string ("aB"),    ==, 0x61422020);
-  g_assert_cmphex (hb_tag_from_string ("a"),     ==, 0x61202020);
-
-  g_assert_cmphex (hb_tag_from_string (""),      ==, HB_TAG_NONE);
-  g_assert_cmphex (hb_tag_from_string (NULL),    ==, HB_TAG_NONE);
+  g_assert_cmphex (hb_tag_from_string ("aBcDe", -1), ==, 0x61426344);
+  g_assert_cmphex (hb_tag_from_string ("aBcD", -1),  ==, 0x61426344);
+  g_assert_cmphex (hb_tag_from_string ("aBc", -1),   ==, 0x61426320);
+  g_assert_cmphex (hb_tag_from_string ("aB", -1),    ==, 0x61422020);
+  g_assert_cmphex (hb_tag_from_string ("a", -1),     ==, 0x61202020);
+  g_assert_cmphex (hb_tag_from_string ("aBcDe",  1), ==, 0x61202020);
+  g_assert_cmphex (hb_tag_from_string ("aBcDe",  2), ==, 0x61422020);
+  g_assert_cmphex (hb_tag_from_string ("aBcDe",  3), ==, 0x61426320);
+  g_assert_cmphex (hb_tag_from_string ("aBcDe",  4), ==, 0x61426344);
+  g_assert_cmphex (hb_tag_from_string ("aBcDe",  4), ==, 0x61426344);
+
+  g_assert_cmphex (hb_tag_from_string ("", -1),      ==, HB_TAG_NONE);
+  g_assert_cmphex (hb_tag_from_string ("x", 0),      ==, HB_TAG_NONE);
+  g_assert_cmphex (hb_tag_from_string (NULL, -1),    ==, HB_TAG_NONE);
 }
 
 static void
@@ -127,23 +134,26 @@ test_types_script (void)
   g_assert_cmpint (HB_SCRIPT_INVALID, ==, (hb_script_t) HB_TAG_NONE);
   g_assert_cmphex (HB_SCRIPT_ARABIC, !=, HB_SCRIPT_LATIN);
 
-  g_assert_cmphex (HB_SCRIPT_INVALID, ==, hb_script_from_string (NULL));
-  g_assert_cmphex (HB_SCRIPT_INVALID, ==, hb_script_from_string (""));
-  g_assert_cmphex (HB_SCRIPT_UNKNOWN, ==, hb_script_from_string ("x"));
+  g_assert_cmphex (HB_SCRIPT_INVALID, ==, hb_script_from_string (NULL, -1));
+  g_assert_cmphex (HB_SCRIPT_INVALID, ==, hb_script_from_string ("", -1));
+  g_assert_cmphex (HB_SCRIPT_INVALID, ==, hb_script_from_string ("x", 0));
+  g_assert_cmphex (HB_SCRIPT_UNKNOWN, ==, hb_script_from_string ("x", -1));
 
-  g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_string ("arab"));
-  g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_string ("Arab"));
-  g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_string ("ARAB"));
+  g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_string ("arab", -1));
+  g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_string ("Arab", -1));
+  g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_string ("ARAB", -1));
+  g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_string ("Arabic", 6));
+  g_assert_cmphex (HB_SCRIPT_ARABIC, !=, hb_script_from_string ("Arabic", 3));
 
   g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_iso15924_tag (arab));
   g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_iso15924_tag (Arab));
   g_assert_cmphex (HB_SCRIPT_ARABIC, ==, hb_script_from_iso15924_tag (ARAB));
 
   /* Arbitrary tags that look like may be valid ISO 15924 should be preserved. */
-  g_assert_cmphex (HB_SCRIPT_UNKNOWN, !=, hb_script_from_string ("wWyZ"));
+  g_assert_cmphex (HB_SCRIPT_UNKNOWN, !=, hb_script_from_string ("wWyZ", -1));
   g_assert_cmphex (HB_SCRIPT_UNKNOWN, !=, hb_script_from_iso15924_tag (wWyZ));
   /* Otherwise, UNKNOWN should be returned. */
-  g_assert_cmphex (HB_SCRIPT_UNKNOWN, ==, hb_script_from_string ("x123"));
+  g_assert_cmphex (HB_SCRIPT_UNKNOWN, ==, hb_script_from_string ("x123", -1));
   g_assert_cmphex (HB_SCRIPT_UNKNOWN, ==, hb_script_from_iso15924_tag (x123));
 
   g_assert_cmphex (hb_script_to_iso15924_tag (HB_SCRIPT_ARABIC), ==, Arab);
@@ -157,10 +167,10 @@ test_types_script (void)
 static void
 test_types_language (void)
 {
-  hb_language_t fa = hb_language_from_string ("fa");
-  hb_language_t fa_IR = hb_language_from_string ("fa_IR");
-  hb_language_t fa_ir = hb_language_from_string ("fa-ir");
-  hb_language_t en = hb_language_from_string ("en");
+  hb_language_t fa = hb_language_from_string ("fa", -1);
+  hb_language_t fa_IR = hb_language_from_string ("fa_IR", -1);
+  hb_language_t fa_ir = hb_language_from_string ("fa-ir", -1);
+  hb_language_t en = hb_language_from_string ("en", -1);
 
   g_assert (HB_LANGUAGE_INVALID == NULL);
 
@@ -172,11 +182,14 @@ test_types_language (void)
   g_assert (en != fa);
 
   /* Test recall */
-  g_assert (en == hb_language_from_string ("en"));
-  g_assert (en == hb_language_from_string ("eN"));
-
-  g_assert (HB_LANGUAGE_INVALID == hb_language_from_string (NULL));
-  g_assert (HB_LANGUAGE_INVALID == hb_language_from_string (""));
+  g_assert (en == hb_language_from_string ("en", -1));
+  g_assert (en == hb_language_from_string ("eN", -1));
+  g_assert (en == hb_language_from_string ("Enx", 2));
+
+  g_assert (HB_LANGUAGE_INVALID == hb_language_from_string (NULL, -1));
+  g_assert (HB_LANGUAGE_INVALID == hb_language_from_string ("", -1));
+  g_assert (HB_LANGUAGE_INVALID == hb_language_from_string ("en", 0));
+  g_assert (HB_LANGUAGE_INVALID != hb_language_from_string ("en", 1));
   g_assert (NULL == hb_language_to_string (HB_LANGUAGE_INVALID));
 
   /* Not sure how to test this better.  Setting env vars
index d440dbd..a00799d 100644 (file)
@@ -40,7 +40,7 @@ test_simple_tags (const char *s, hb_script_t script)
   hb_script_t t1, t2;
 
   g_test_message ("Testing script %c%c%c%c: tag %s", HB_UNTAG (hb_script_to_iso15924_tag (script)), s);
-  tag = hb_tag_from_string (s);
+  tag = hb_tag_from_string (s, -1);
 
   hb_ot_tags_from_script (script, &t1, &t2);
 
@@ -57,8 +57,8 @@ test_indic_tags (const char *s1, const char *s2, hb_script_t script)
   hb_script_t t1, t2;
 
   g_test_message ("Testing script %c%c%c%c: new tag %s, old tag %s", HB_UNTAG (hb_script_to_iso15924_tag (script)), s1, s2);
-  tag1 = hb_tag_from_string (s1);
-  tag2 = hb_tag_from_string (s2);
+  tag1 = hb_tag_from_string (s1, -1);
+  tag2 = hb_tag_from_string (s2, -1);
 
   hb_ot_tags_from_script (script, &t1, &t2);
 
@@ -85,14 +85,14 @@ test_ot_tag_script_degenerate (void)
   test_simple_tags ("DFLT", HB_SCRIPT_INVALID);
 
   /* Spaces are replaced */
-  g_assert_cmphex (hb_ot_tag_to_script (HB_TAG_CHAR4 ("be  ")), ==, hb_script_from_string ("Beee"));
+  g_assert_cmphex (hb_ot_tag_to_script (HB_TAG_CHAR4 ("be  ")), ==, hb_script_from_string ("Beee", -1));
 }
 
 static void
 test_ot_tag_script_simple (void)
 {
   /* Arbitrary non-existent script */
-  test_simple_tags ("wwyz", hb_script_from_string ("wWyZ"));
+  test_simple_tags ("wwyz", hb_script_from_string ("wWyZ", -1));
 
   /* These we don't really care about */
   test_simple_tags ("zyyy", HB_SCRIPT_COMMON);
@@ -141,8 +141,8 @@ test_ot_tag_script_indic (void)
 static void
 test_language_two_way (const char *tag_s, const char *lang_s)
 {
-  hb_language_t lang = hb_language_from_string (lang_s);
-  hb_tag_t tag = hb_tag_from_string (tag_s);
+  hb_language_t lang = hb_language_from_string (lang_s, -1);
+  hb_tag_t tag = hb_tag_from_string (tag_s, -1);
 
   g_test_message ("Testing language %s <-> tag %s", lang_s, tag_s);
 
@@ -153,8 +153,8 @@ test_language_two_way (const char *tag_s, const char *lang_s)
 static void
 test_tag_from_language (const char *tag_s, const char *lang_s)
 {
-  hb_language_t lang = hb_language_from_string (lang_s);
-  hb_tag_t tag = hb_tag_from_string (tag_s);
+  hb_language_t lang = hb_language_from_string (lang_s, -1);
+  hb_tag_t tag = hb_tag_from_string (tag_s, -1);
 
   g_test_message ("Testing language %s -> tag %s", lang_s, tag_s);
 
@@ -164,8 +164,8 @@ test_tag_from_language (const char *tag_s, const char *lang_s)
 static void
 test_tag_to_language (const char *tag_s, const char *lang_s)
 {
-  hb_language_t lang = hb_language_from_string (lang_s);
-  hb_tag_t tag = hb_tag_from_string (tag_s);
+  hb_language_t lang = hb_language_from_string (lang_s, -1);
+  hb_tag_t tag = hb_tag_from_string (tag_s, -1);
 
   g_test_message ("Testing tag %s -> language %s", tag_s, lang_s);
 
index cdb90b6..d89835c 100644 (file)
@@ -62,11 +62,11 @@ _hb_cr_text_glyphs (cairo_t *cr,
   hb_buffer = hb_buffer_create ();
 
   if (shape_opts->direction)
-    hb_buffer_set_direction (hb_buffer, hb_direction_from_string (shape_opts->direction));
+    hb_buffer_set_direction (hb_buffer, hb_direction_from_string (shape_opts->direction, -1));
   if (shape_opts->script)
-    hb_buffer_set_script (hb_buffer, hb_script_from_string (shape_opts->script));
+    hb_buffer_set_script (hb_buffer, hb_script_from_string (shape_opts->script, -1));
   if (shape_opts->language)
-    hb_buffer_set_language (hb_buffer, hb_language_from_string (shape_opts->language));
+    hb_buffer_set_language (hb_buffer, hb_language_from_string (shape_opts->language, -1));
 
   if (len < 0)
     len = strlen (utf8);
index d623243..3809b1a 100644 (file)
@@ -133,10 +133,7 @@ parse_feature_tag (char **pp, hb_feature_t *feature)
   if (p == *pp)
     return FALSE;
 
-  **pp = '\0';
-  feature->tag = hb_tag_from_string (p);
-  **pp = c;
-
+  feature->tag = hb_tag_from_string (p, *pp - p);
   return TRUE;
 }