From 7717b25ffdd9507b0d73ef60b70b692f7286c0a2 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 10 Feb 2009 00:15:08 -0500 Subject: [PATCH] [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. --- src/fcformat.c | 158 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 147 insertions(+), 11 deletions(-) diff --git a/src/fcformat.c b/src/fcformat.c index 31f3a74..e1e05ee 100644 --- a/src/fcformat.c +++ b/src/fcformat.c @@ -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; -- 2.39.2