[hb-view] Rewrite --features parsing, with range support

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
This commit is contained in:
Behdad Esfahbod 2011-04-04 14:50:09 -04:00
parent ccc6745afa
commit fb9ca1bfab
1 changed files with 132 additions and 37 deletions

View File

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