[fcformat] Add conditionals

The conditional '%{?elt1,elt2,!elt3{expr1}{expr2}}' will evaluate
expr1 if elt1 and elt2 exist in pattern and elt3 doesn't exist, and
expr2 otherwise.  The '{expr2}' part is optional.
This commit is contained in:
Behdad Esfahbod 2009-02-10 00:15:08 -05:00
parent 8c31a2434d
commit 7717b25ffd
1 changed files with 147 additions and 11 deletions

View File

@ -150,7 +150,7 @@ read_elt_name_to_scratch (FcFormatContext *c)
} }
static FcBool static FcBool
interpret (FcFormatContext *c, interpret_expr (FcFormatContext *c,
FcPattern *pat, FcPattern *pat,
FcStrBuf *buf, FcStrBuf *buf,
FcChar8 term); FcChar8 term);
@ -161,10 +161,94 @@ interpret_subexpr (FcFormatContext *c,
FcStrBuf *buf) FcStrBuf *buf)
{ {
return expect_char (c, '{') && return expect_char (c, '{') &&
interpret (c, pat, buf, '}') && interpret_expr (c, pat, buf, '}') &&
expect_char (c, '}'); expect_char (c, '}');
} }
static FcBool
maybe_interpret_subexpr (FcFormatContext *c,
FcPattern *pat,
FcStrBuf *buf)
{
return (*c->format == '{') ?
interpret_subexpr (c, pat, buf) :
FcTrue;
}
static FcBool
skip_subexpr (FcFormatContext *c);
static FcBool
skip_percent (FcFormatContext *c)
{
if (!expect_char (c, '%'))
return FcFalse;
/* skip an optional width specifier */
strtol ((const char *) c->format, (char **) &c->format, 10);
if (!expect_char (c, '{'))
return FcFalse;
while(*c->format && *c->format != '}')
{
switch (*c->format)
{
case '\\':
c->format++; /* skip over '\\' */
if (*c->format)
c->format++;
continue;
case '{':
if (!skip_subexpr (c))
return FcFalse;
continue;
}
c->format++;
}
return expect_char (c, '}');
}
static FcBool
skip_expr (FcFormatContext *c)
{
while(*c->format && *c->format != '}')
{
switch (*c->format)
{
case '\\':
c->format++; /* skip over '\\' */
if (*c->format)
c->format++;
continue;
case '%':
if (!skip_percent (c))
return FcFalse;
continue;
}
c->format++;
}
return FcTrue;
}
static FcBool
skip_subexpr (FcFormatContext *c)
{
return expect_char (c, '{') &&
skip_expr (c) &&
expect_char (c, '}');
}
static FcBool
maybe_skip_subexpr (FcFormatContext *c)
{
return (*c->format == '{') ?
skip_subexpr (c) :
FcTrue;
}
static FcBool static FcBool
interpret_simple_tag (FcFormatContext *c, interpret_simple_tag (FcFormatContext *c,
FcPattern *pat, FcPattern *pat,
@ -274,6 +358,52 @@ interpret_delete (FcFormatContext *c,
return FcTrue; return FcTrue;
} }
static FcBool
interpret_conditional (FcFormatContext *c,
FcPattern *pat,
FcStrBuf *buf)
{
FcBool pass;
if (!expect_char (c, '?'))
return FcFalse;
pass = FcTrue;
do
{
FcBool negate;
FcValue v;
negate = consume_char (c, '!');
if (!read_elt_name_to_scratch (c))
return FcFalse;
pass = pass &&
(negate ^
FcResultMatch == FcPatternGet (pat,
(const char *) c->scratch,
0, &v));
}
while (consume_char (c, ','));
if (pass)
{
if (!interpret_subexpr (c, pat, buf) ||
!maybe_skip_subexpr (c))
return FcFalse;
}
else
{
if (!skip_subexpr (c) ||
!maybe_interpret_subexpr (c, pat, buf))
return FcFalse;
}
return FcTrue;
}
static FcBool static FcBool
interpret_percent (FcFormatContext *c, interpret_percent (FcFormatContext *c,
FcPattern *pat, FcPattern *pat,
@ -318,6 +448,12 @@ interpret_percent (FcFormatContext *c,
return FcFalse; return FcFalse;
break; break;
case '?':
/* conditional on pattern elements */
if (!interpret_conditional (c, pat, buf))
return FcFalse;
break;
default: default:
/* simple tag */ /* simple tag */
if (!interpret_simple_tag (c, pat, buf)) if (!interpret_simple_tag (c, pat, buf))
@ -377,12 +513,12 @@ static char escaped_char(const char ch)
} }
static FcBool static FcBool
interpret (FcFormatContext *c, interpret_expr (FcFormatContext *c,
FcPattern *pat, FcPattern *pat,
FcStrBuf *buf, FcStrBuf *buf,
FcChar8 term) FcChar8 term)
{ {
for (; *c->format && *c->format != term;) while (*c->format && *c->format != term)
{ {
switch (*c->format) switch (*c->format)
{ {
@ -412,7 +548,7 @@ FcPatternFormat (FcPattern *pat, const FcChar8 *format)
if (!FcFormatContextInit (&c, format)) if (!FcFormatContextInit (&c, format))
return NULL; return NULL;
ret = interpret (&c, pat, &buf, '\0'); ret = interpret_expr (&c, pat, &buf, '\0');
if (buf.failed) if (buf.failed)
ret = FcFalse; ret = FcFalse;