[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:
parent
ccc6745afa
commit
fb9ca1bfab
169
src/hb-view.c
169
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue