Add hb_feature_to/from_string()
authorBehdad Esfahbod <behdad@behdad.org>
Fri, 7 Sep 2012 02:09:06 +0000 (22:09 -0400)
committerBehdad Esfahbod <behdad@behdad.org>
Fri, 7 Sep 2012 02:09:06 +0000 (22:09 -0400)
TODO
src/hb-common.cc
src/hb-common.h
src/hb-shape.cc
src/hb-shape.h
util/options.cc

diff --git a/TODO b/TODO
index 1ca2480..be3c7c6 100644 (file)
--- a/TODO
+++ b/TODO
@@ -41,8 +41,6 @@ API additions
 
 - Buffer (de)serialize API ala hb-shape?
 
-- Move feature parsing from util into the library
-
 - Add hb-cairo glue
 
 - Add sanitize API (and a cached version, that saves result on blob user-data)
@@ -91,3 +89,5 @@ Tests to write:
 - hb_set_t
 
 - hb_cache_t and relatives
+
+- hb_feature_to/from_string
index 1301ab2..33a514d 100644 (file)
@@ -58,6 +58,15 @@ hb_tag_from_string (const char *s, int len)
   return HB_TAG_CHAR4 (tag);
 }
 
+void
+hb_tag_to_string (hb_tag_t tag, char *buf)
+{
+  buf[0] = (char) (uint8_t) (tag >> 24);
+  buf[1] = (char) (uint8_t) (tag >> 16);
+  buf[2] = (char) (uint8_t) (tag >>  8);
+  buf[3] = (char) (uint8_t) (tag >>  0);
+}
+
 
 /* hb_direction_t */
 
index 920bd32..cc221d3 100644 (file)
@@ -95,10 +95,14 @@ typedef uint32_t hb_tag_t;
 
 #define HB_TAG_NONE HB_TAG(0,0,0,0)
 
-/* len=-1 means str is NUL-terminated */
+/* len=-1 means str is NUL-terminated. */
 hb_tag_t
 hb_tag_from_string (const char *str, int len);
 
+/* buf should have 4 bytes. */
+void
+hb_tag_to_string (hb_tag_t tag, char *buf);
+
 
 /* hb_direction_t */
 
index 5aa587b..6619c19 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -22,6 +23,7 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-private.hh"
 #include "hb-font-private.hh"
 
 
+static void
+parse_space (const char **pp, const char *end)
+{
+  char c;
+#define ISSPACE(c) ((c)==' '||(c)=='\f'||(c)=='\n'||(c)=='\r'||(c)=='\t'||(c)=='\v')
+  while (*pp < end && (c = **pp, ISSPACE (c)))
+    (*pp)++;
+#undef ISSPACE
+}
+
+static hb_bool_t
+parse_char (const char **pp, const char *end, char c)
+{
+  parse_space (pp, end);
+
+  if (*pp == end || **pp != c)
+    return false;
+
+  (*pp)++;
+  return true;
+}
+
+static hb_bool_t
+parse_uint (const char **pp, const char *end, unsigned int *pv)
+{
+  char buf[32];
+  strncpy (buf, *pp, end - *pp);
+  buf[ARRAY_LENGTH (buf) - 1] = '\0';
+
+  char *p = buf;
+  char *pend = p;
+  unsigned int v;
+
+  v = strtol (p, &pend, 0);
+
+  if (p == pend)
+    return false;
+
+  *pv = v;
+  *pp += pend - p;
+  return true;
+}
+
+static hb_bool_t
+parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
+{
+  if (parse_char (pp, end, '-'))
+    feature->value = 0;
+  else {
+    parse_char (pp, end, '+');
+    feature->value = 1;
+  }
+
+  return true;
+}
+
+static hb_bool_t
+parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature)
+{
+  const char *p = *pp;
+  char c;
+
+  parse_space (pp, end);
+
+#define ISALNUM(c) (('a' <= (c) && (c) <= 'z') || ('A' <= (c) && (c) <= 'Z') || ('0' <= (c) && (c) <= '9'))
+  while (*pp < end && (c = **pp, ISALNUM(c)))
+    (*pp)++;
+#undef ISALNUM
+
+  if (p == *pp)
+    return false;
+
+  feature->tag = hb_tag_from_string (p, *pp - p);
+  return true;
+}
+
+static hb_bool_t
+parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
+{
+  parse_space (pp, end);
+
+  hb_bool_t has_start;
+
+  feature->start = 0;
+  feature->end = (unsigned int) -1;
+
+  if (!parse_char (pp, end, '['))
+    return true;
+
+  has_start = parse_uint (pp, end, &feature->start);
+
+  if (parse_char (pp, end, ':')) {
+    parse_uint (pp, end, &feature->end);
+  } else {
+    if (has_start)
+      feature->end = feature->start + 1;
+  }
+
+  return parse_char (pp, end, ']');
+}
+
+static hb_bool_t
+parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
+{
+  return !parse_char (pp, end, '=') || parse_uint (pp, end, &feature->value);
+}
+
+
+static hb_bool_t
+parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
+{
+  return parse_feature_value_prefix (pp, end, feature) &&
+        parse_feature_tag (pp, end, feature) &&
+        parse_feature_indices (pp, end, feature) &&
+        parse_feature_value_postfix (pp, end, feature) &&
+        *pp == end;
+}
+
+hb_bool_t
+hb_feature_from_string (const char *str, int len,
+                       hb_feature_t *feature)
+{
+  if (len < 0)
+    len = strlen (str);
+
+  return parse_one_feature (&str, str + len, feature);
+}
+
+void
+hb_feature_to_string (hb_feature_t *feature,
+                     char *buf, unsigned int size)
+{
+  if (unlikely (!size)) return;
+
+  char s[128];
+  unsigned int len = 0;
+  if (feature->value == 0)
+    s[len++] = '-';
+  hb_tag_to_string (feature->tag, s + len);
+  len += 4;
+  while (len && s[len - 1] == ' ')
+    len--;
+  if (feature->start != 0 || feature->start != (unsigned int) -1)
+  {
+    s[len++] = '[';
+    if (feature->start)
+      len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->start);
+    if (feature->end != feature->start + 1) {
+      s[len++] = ':';
+      if (feature->end != (unsigned int) -1)
+       len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->end);
+    }
+    s[len++] = ']';
+  }
+  if (feature->value > 1)
+  {
+    s[len++] = '=';
+    len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->value);
+  }
+  assert (len < ARRAY_LENGTH (s));
+  len = MIN (len, size - 1);
+  memcpy (buf, s, len);
+  s[len] = '\0';
+}
+
+
 static const char **static_shaper_list;
 
 static
index 84bf3e7..90a188d 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -22,6 +23,7 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_H_IN
@@ -45,6 +47,17 @@ typedef struct hb_feature_t {
   unsigned int  end;
 } hb_feature_t;
 
+/* len=-1 means str is NUL-terminated */
+hb_bool_t
+hb_feature_from_string (const char *str, int len,
+                       hb_feature_t *feature);
+
+/* something like 128 bytes is more than enough.
+ * nul-terminates. */
+void
+hb_feature_to_string (hb_feature_t *feature,
+                     char *buf, unsigned int size);
+
 
 void
 hb_shape (hb_font_t           *font,
index c05cee6..dc7aeed 100644 (file)
@@ -196,130 +196,6 @@ list_shapers (const char *name G_GNUC_UNUSED,
 }
 
 
-
-static void
-parse_space (char **pp)
-{
-  char c;
-#define ISSPACE(c) ((c)==' '||(c)=='\f'||(c)=='\n'||(c)=='\r'||(c)=='\t'||(c)=='\v')
-  while (c = **pp, ISSPACE (c))
-    (*pp)++;
-#undef ISSPACE
-}
-
-static hb_bool_t
-parse_char (char **pp, char c)
-{
-  parse_space (pp);
-
-  if (**pp != c)
-    return false;
-
-  (*pp)++;
-  return true;
-}
-
-static hb_bool_t
-parse_uint (char **pp, unsigned int *pv)
-{
-  char *p = *pp;
-  unsigned int v;
-
-  v = strtol (p, pp, 0);
-
-  if (p == *pp)
-    return false;
-
-  *pv = v;
-  return true;
-}
-
-
-static hb_bool_t
-parse_feature_value_prefix (char **pp, hb_feature_t *feature)
-{
-  if (parse_char (pp, '-'))
-    feature->value = 0;
-  else {
-    parse_char (pp, '+');
-    feature->value = 1;
-  }
-
-  return true;
-}
-
-static hb_bool_t
-parse_feature_tag (char **pp, hb_feature_t *feature)
-{
-  char *p = *pp, c;
-
-  parse_space (pp);
-
-#define ISALNUM(c) (('a' <= (c) && (c) <= 'z') || ('A' <= (c) && (c) <= 'Z') || ('0' <= (c) && (c) <= '9'))
-  while (c = **pp, ISALNUM(c))
-    (*pp)++;
-#undef ISALNUM
-
-  if (p == *pp)
-    return false;
-
-  feature->tag = hb_tag_from_string (p, *pp - p);
-  return true;
-}
-
-static hb_bool_t
-parse_feature_indices (char **pp, hb_feature_t *feature)
-{
-  parse_space (pp);
-
-  hb_bool_t has_start;
-
-  feature->start = 0;
-  feature->end = (unsigned int) -1;
-
-  if (!parse_char (pp, '['))
-    return true;
-
-  has_start = parse_uint (pp, &feature->start);
-
-  if (parse_char (pp, ':')) {
-    parse_uint (pp, &feature->end);
-  } else {
-    if (has_start)
-      feature->end = feature->start + 1;
-  }
-
-  return parse_char (pp, ']');
-}
-
-static hb_bool_t
-parse_feature_value_postfix (char **pp, hb_feature_t *feature)
-{
-  return !parse_char (pp, '=') || parse_uint (pp, &feature->value);
-}
-
-
-static hb_bool_t
-parse_one_feature (char **pp, hb_feature_t *feature)
-{
-  return parse_feature_value_prefix (pp, feature) &&
-        parse_feature_tag (pp, feature) &&
-        parse_feature_indices (pp, feature) &&
-        parse_feature_value_postfix (pp, feature) &&
-        (parse_char (pp, ',') || **pp == '\0');
-}
-
-static void
-skip_one_feature (char **pp)
-{
-  char *e;
-  e = strchr (*pp, ',');
-  if (e)
-    *pp = e + 1;
-  else
-    *pp = *pp + strlen (*pp);
-}
-
 static gboolean
 parse_features (const char *name G_GNUC_UNUSED,
                const char *arg,
@@ -351,11 +227,11 @@ parse_features (const char *name G_GNUC_UNUSED,
   /* now do the actual parsing */
   p = s;
   shape_opts->num_features = 0;
-  while (*p) {
-    if (parse_one_feature (&p, &shape_opts->features[shape_opts->num_features]))
+  while (p && *p) {
+    char *end = strchr (p, ',');
+    if (hb_feature_from_string (p, end ? end - p : -1, &shape_opts->features[shape_opts->num_features]))
       shape_opts->num_features++;
-    else
-      skip_one_feature (&p);
+    p = end ? end + 1 : NULL;
   }
 
   return true;