From: Behdad Esfahbod Date: Fri, 13 Feb 2009 03:48:22 +0000 (-0600) Subject: [fcformat] Implement array enumeration X-Git-Tag: 2.7.0~84 X-Git-Url: https://git.wh0rd.org/?p=fontconfig.git;a=commitdiff_plain;h=cdfb76585e7afbe739d00ed83a029ce1f909142f [fcformat] Implement array enumeration The format '%{[]family,familylang{expr}}' expands expr once for the first value of family and familylang, then for the second, etc, until both lists are exhausted. --- diff --git a/src/fcformat.c b/src/fcformat.c index f91b6e0..5aa1977 100644 --- a/src/fcformat.c +++ b/src/fcformat.c @@ -31,7 +31,6 @@ /* * Some ideas for future syntax extensions: * - * - array enumeration using '%{[]family,familylang{expr}|decorator}' * - langset enumeration using same syntax as array enumeration * - allow indexing subexprs using '%{[idx]elt1,elt2{subexpr}}' * - conditional/filtering/deletion on binding (using '(w)'/'(s)'/'(=)' notation) @@ -476,9 +475,8 @@ interpret_cond (FcFormatContext *c, pass = pass && (negate ^ - (FcResultMatch == FcPatternGet (pat, - (const char *) c->word, - 0, &v))); + (FcResultMatch == + FcPatternGet (pat, (const char *) c->word, 0, &v))); } while (consume_char (c, ',')); @@ -532,6 +530,86 @@ interpret_count (FcFormatContext *c, return FcTrue; } +static FcBool +interpret_array (FcFormatContext *c, + FcPattern *pat, + FcStrBuf *buf) +{ + FcObjectSet *os; + FcPattern *subpat; + const FcChar8 *format_save; + int idx; + FcBool ret, done; + + if (!expect_char (c, '[') || + !expect_char (c, ']')) + return FcFalse; + + os = FcObjectSetCreate (); + if (!os) + return FcFalse; + + ret = FcTrue; + + do + { + if (!read_word (c) || + !FcObjectSetAdd (os, (const char *) c->word)) + { + FcObjectSetDestroy (os); + return FcFalse; + } + } + while (consume_char (c, ',')); + + subpat = FcPatternDuplicate (pat); + if (!subpat) + goto bail0; + + format_save = c->format; + idx = 0; + do + { + int i; + + done = FcTrue; + + for (i = 0; i < os->nobject; i++) + { + FcValue v; + + /* XXX this can be optimized by accessing valuelist linked lists + * directly and remembering where we were. Most (all) value lists + * in normal uses are pretty short though (language tags are + * stored as a LangSet, not separate values.). */ + FcPatternDel (subpat, os->objects[i]); + if (FcResultMatch == + FcPatternGet (pat, os->objects[i], idx, &v)) + { + FcPatternAdd (subpat, os->objects[i], v, FcFalse); + done = FcFalse; + } + } + + if (!done) + { + c->format = format_save; + ret = interpret_subexpr (c, subpat, buf); + if (!ret) + goto bail; + } + + idx++; + } while (!done); + +bail: + FcPatternDestroy (subpat); +bail0: + FcObjectSetDestroy (os); + + return ret; +} + static FcBool interpret_simple (FcFormatContext *c, FcPattern *pat, @@ -559,7 +637,8 @@ interpret_simple (FcFormatContext *c, c->format-1 - c->format_orig + 1); return FcFalse; } - expect_char (c, ']'); + if (!expect_char (c, ']')) + return FcFalse; } if (consume_char (c, '=')) @@ -969,6 +1048,7 @@ interpret_percent (FcFormatContext *c, case '-': ret = interpret_delete (c, pat, buf); break; case '?': ret = interpret_cond (c, pat, buf); break; case '#': ret = interpret_count (c, pat, buf); break; + case '[': ret = interpret_array (c, pat, buf); break; default: ret = interpret_simple (c, pat, buf); break; }