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;
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);
}
}