From fb9ca1bfabde7da0c274e7a1bd12bffaf7949c18 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 4 Apr 2011 14:50:09 -0400 Subject: [PATCH] [hb-view] Rewrite --features parsing, with range support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The --features parsing handles errors now. More importantly, it allos limiting individual features to specific byte ranges. The format is Python-esque. Here is how it all works: Syntax: Value: Start: End: Setting value: "kern" 1 0 ∞ # Turn feature on "+kern" 1 0 ∞ # Turn feature off "-kern" 0 0 ∞ # Turn feature off "kern=0" 0 0 ∞ # Turn feature off "kern=1" 1 0 ∞ # Turn feature on "kern=2" 2 0 ∞ # Choose 2nd alternate Setting index: "kern[]" 1 0 ∞ # Turn feature on "kern[:]" 1 0 ∞ # Turn feature on "kern[5:]" 1 5 ∞ # Turn feature on, partial "kern[:5]" 1 0 5 # Turn feature on, partial "kern[3:5]" 1 3 5 # Turn feature on, range "kern[3]" 1 3 3+1 # Turn feature on, single char Mixing it all: "kern[3:5]=0" 1 3 5 # Turn feature off for range --- src/hb-view.c | 169 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 132 insertions(+), 37 deletions(-) diff --git a/src/hb-view.c b/src/hb-view.c index c4b942f60..b82d27438 100644 --- a/src/hb-view.c +++ b/src/hb-view.c @@ -171,10 +171,134 @@ parse_opts (int argc, char **argv) text = argv[optind++]; } + +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 ISALPHA(c) (('a' <= (c) && (c) <= 'z') || ('A' <= (c) && (c) <= 'Z')) + while (c = **pp, ISALPHA(c)) + (*pp)++; +#undef ISALPHA + + if (p == *pp) + return FALSE; + + **pp = '\0'; + feature->tag = hb_tag_from_string (p); + **pp = c; + + return TRUE; +} + +static hb_bool_t +parse_feature_indices (char **pp, hb_feature_t *feature) +{ + 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 void parse_features (char *s) { char *p; - unsigned int i; num_features = 0; features = NULL; @@ -188,48 +312,19 @@ static void parse_features (char *s) num_features++; p = strchr (p, ','); if (p) - p++; /* skip the comma */ + p++; } while (p); features = calloc (num_features, sizeof (*features)); /* now do the actual parsing */ p = s; - for (i = 0; i < num_features; i++) { - hb_feature_t *feature = &features[i]; - char *end, *eq, sign; - unsigned int value; - - end = strchr (p, ','); - if (!end) - end = p + strlen (p); - - *end = '\0'; /* isolate it */ - - while (*p == ' ') - p++; - - sign = *p; - if (sign == '-' || sign == '+') - p++; - - value = 1; - eq = strchr (p, '='); - if (eq) { - *eq = '\0'; - value = atoi (eq + 1); - } - - /* let a '-' sign override '=' */ - if (sign == '-') - value = 0; - - feature->tag = hb_tag_from_string (p); - feature->value = value; - feature->start = 0; - feature->end = (unsigned int) -1; - - p = end + 1; + num_features = 0; + while (*p) { + if (parse_one_feature (&p, &features[num_features])) + num_features++; + else + skip_one_feature (&p); } }