diff options
author | Behdad Esfahbod <behdad@behdad.org> | 2009-02-09 23:08:08 -0500 |
---|---|---|
committer | Behdad Esfahbod <behdad@behdad.org> | 2009-02-15 13:40:26 -0800 |
commit | 8c31a2434d5dfa475ef710ad52c992111caac424 (patch) | |
tree | 91a60b276619bcd78639b68698c31ea86d54404c /src | |
parent | d6506ff6eeb4a4cb0bfe827174e474c7b91ff045 (diff) |
[fcformat] Add element filtering and deletion
The filtering, '%{+elt1,elt2,elt3{subexpr}}' will evaluate subexpr
with a pattern only having the listed elements from the surrounding
pattern.
The deletion, '%{-elt1,elt2,elt3{subexpr}}' will evaluate subexpr
with a the surrounding pattern sans the listed elements.
Diffstat (limited to 'src')
-rw-r--r-- | src/fcformat.c | 214 |
1 files changed, 162 insertions, 52 deletions
diff --git a/src/fcformat.c b/src/fcformat.c index 30c5a8d..31f3a74 100644 --- a/src/fcformat.c +++ b/src/fcformat.c @@ -33,7 +33,7 @@ message (const char *fmt, ...) { va_list args; va_start (args, fmt); - fprintf (stderr, "Fontconfig: Pattern format error:"); + fprintf (stderr, "Fontconfig: Pattern format error: "); vfprintf (stderr, fmt, args); fprintf (stderr, ".\n"); va_end (args); @@ -48,13 +48,15 @@ typedef struct _FcFormatContext FcChar8 *scratch; } FcFormatContext; -static void +static FcBool FcFormatContextInit (FcFormatContext *c, const FcChar8 *format) { c->format_orig = c->format = format; c->format_len = strlen ((const char *) format); c->scratch = malloc (c->format_len + 1); + + return c->scratch != NULL; } static void @@ -147,60 +149,36 @@ read_elt_name_to_scratch (FcFormatContext *c) return FcTrue; } -static void +static FcBool interpret (FcFormatContext *c, FcPattern *pat, FcStrBuf *buf, FcChar8 term); -static void -interpret_percent (FcFormatContext *c, +static FcBool +interpret_subexpr (FcFormatContext *c, FcPattern *pat, FcStrBuf *buf) { - int width, before; - FcChar8 *p; - FcPatternElt *e; + return expect_char (c, '{') && + interpret (c, pat, buf, '}') && + expect_char (c, '}'); +} - FcPattern *subpat = pat; +static FcBool +interpret_simple_tag (FcFormatContext *c, + FcPattern *pat, + FcStrBuf *buf) +{ + FcPatternElt *e; FcBool add_colon = FcFalse; FcBool add_elt_name = FcFalse; - if (!expect_char (c, '%')) - return; - - if (consume_char (c, '%')) /* "%%" */ - { - FcStrBufChar (buf, '%'); - return; - } - - /* parse an optional width specifier */ - width = strtol ((const char *) c->format, (char **) &c->format, 10); - - before = buf->len; - - if (!expect_char (c, '{')) - goto bail; - - if (consume_char (c, '{')) - { - /* it's just a subexpression. no tag involved */ - interpret (c, pat, buf, '}'); - expect_char (c, '}'); - goto filter; - } - - switch (*c->format) { - case ':': + if (consume_char (c, ':')) add_colon = FcTrue; - consume_char (c, ':'); - break; - } -parse_tag: if (!read_elt_name_to_scratch (c)) - goto bail; + return FcFalse; if (consume_char (c, '=')) add_elt_name = FcTrue; @@ -223,7 +201,131 @@ parse_tag: FcNameUnparseValueList (buf, l, '\0'); } -filter: + return FcTrue; +} + +static FcBool +interpret_filter (FcFormatContext *c, + FcPattern *pat, + FcStrBuf *buf) +{ + FcObjectSet *os; + FcPattern *subpat; + + if (!expect_char (c, '+')) + return FcFalse; + + os = FcObjectSetCreate (); + if (!os) + return FcFalse; + + do + { + if (!read_elt_name_to_scratch (c) || + !FcObjectSetAdd (os, (const char *) c->scratch)) + { + FcObjectSetDestroy (os); + return FcFalse; + } + } + while (consume_char (c, ',')); + + subpat = FcPatternFilter (pat, os); + FcObjectSetDestroy (os); + + if (!subpat || + !interpret_subexpr (c, subpat, buf)) + return FcFalse; + + FcPatternDestroy (subpat); + return FcTrue; +} + +static FcBool +interpret_delete (FcFormatContext *c, + FcPattern *pat, + FcStrBuf *buf) +{ + FcPattern *subpat; + + if (!expect_char (c, '-')) + return FcFalse; + + subpat = FcPatternDuplicate (pat); + if (!subpat) + return FcFalse; + + do + { + if (!read_elt_name_to_scratch (c)) + { + FcPatternDestroy (subpat); + return FcFalse; + } + + FcPatternDel (subpat, (const char *) c->scratch); + } + while (consume_char (c, ',')); + + if (!interpret_subexpr (c, subpat, buf)) + return FcFalse; + + FcPatternDestroy (subpat); + return FcTrue; +} + +static FcBool +interpret_percent (FcFormatContext *c, + FcPattern *pat, + FcStrBuf *buf) +{ + int width, before; + + if (!expect_char (c, '%')) + return FcFalse; + + if (consume_char (c, '%')) /* "%%" */ + { + FcStrBufChar (buf, '%'); + return FcTrue; + } + + /* parse an optional width specifier */ + width = strtol ((const char *) c->format, (char **) &c->format, 10); + + before = buf->len; + + if (!expect_char (c, '{')) + return FcFalse; + + switch (*c->format) { + + case '{': + /* subexpression */ + if (!interpret_subexpr (c, pat, buf)) + return FcFalse; + break; + + case '+': + /* filtering pattern elements */ + if (!interpret_filter (c, pat, buf)) + return FcFalse; + break; + + case '-': + /* deleting pattern elements */ + if (!interpret_delete (c, pat, buf)) + return FcFalse; + break; + + default: + /* simple tag */ + if (!interpret_simple_tag (c, pat, buf)) + return FcFalse; + break; + + } + /* handle filters, if any */ /* XXX */ @@ -257,11 +359,7 @@ filter: } } - expect_char (c, '}'); - -bail: - if (subpat != pat) - FcPatternDestroy (subpat); + return expect_char (c, '}'); } static char escaped_char(const char ch) @@ -278,7 +376,7 @@ static char escaped_char(const char ch) } } -static void +static FcBool interpret (FcFormatContext *c, FcPattern *pat, FcStrBuf *buf, @@ -294,11 +392,13 @@ interpret (FcFormatContext *c, FcStrBufChar (buf, escaped_char (*c->format++)); continue; case '%': - interpret_percent (c, pat, buf); + if (!interpret_percent (c, pat, buf)) + return FcFalse; continue; } FcStrBufChar (buf, *c->format++); } + return FcTrue; } FcChar8 * @@ -306,14 +406,24 @@ FcPatternFormat (FcPattern *pat, const FcChar8 *format) { FcStrBuf buf; FcFormatContext c; + FcBool ret; FcStrBufInit (&buf, 0, 0); - FcFormatContextInit (&c, format); + if (!FcFormatContextInit (&c, format)) + return NULL; - interpret (&c, pat, &buf, '\0'); + ret = interpret (&c, pat, &buf, '\0'); + if (buf.failed) + ret = FcFalse; FcFormatContextDone (&c); - return FcStrBufDone (&buf); + if (ret) + return FcStrBufDone (&buf); + else + { + FcStrBufDestroy (&buf); + return NULL; + } } #define __fcformat__ |