[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,10 +150,10 @@ read_elt_name_to_scratch (FcFormatContext *c)
}
static FcBool
interpret (FcFormatContext *c,
FcPattern *pat,
FcStrBuf *buf,
FcChar8 term);
interpret_expr (FcFormatContext *c,
FcPattern *pat,
FcStrBuf *buf,
FcChar8 term);
static FcBool
interpret_subexpr (FcFormatContext *c,
@ -161,10 +161,94 @@ interpret_subexpr (FcFormatContext *c,
FcStrBuf *buf)
{
return expect_char (c, '{') &&
interpret (c, pat, buf, '}') &&
interpret_expr (c, pat, buf, '}') &&
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
interpret_simple_tag (FcFormatContext *c,
FcPattern *pat,
@ -274,6 +358,52 @@ interpret_delete (FcFormatContext *c,
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
interpret_percent (FcFormatContext *c,
FcPattern *pat,
@ -318,6 +448,12 @@ interpret_percent (FcFormatContext *c,
return FcFalse;
break;
case '?':
/* conditional on pattern elements */
if (!interpret_conditional (c, pat, buf))
return FcFalse;
break;
default:
/* simple tag */
if (!interpret_simple_tag (c, pat, buf))
@ -377,12 +513,12 @@ static char escaped_char(const char ch)
}
static FcBool
interpret (FcFormatContext *c,
FcPattern *pat,
FcStrBuf *buf,
FcChar8 term)
interpret_expr (FcFormatContext *c,
FcPattern *pat,
FcStrBuf *buf,
FcChar8 term)
{
for (; *c->format && *c->format != term;)
while (*c->format && *c->format != term)
{
switch (*c->format)
{
@ -412,7 +548,7 @@ FcPatternFormat (FcPattern *pat, const FcChar8 *format)
if (!FcFormatContextInit (&c, format))
return NULL;
ret = interpret (&c, pat, &buf, '\0');
ret = interpret_expr (&c, pat, &buf, '\0');
if (buf.failed)
ret = FcFalse;