/*
* Some ideas for future syntax extensions:
*
- * - array enumeration using '%{[]family,familylang{expr}|decorator}'
* - langset enumeration using same syntax as array enumeration
- * - allow indexing simple tags using '%{elt[idx]}'
* - allow indexing subexprs using '%{[idx]elt1,elt2{subexpr}}'
* - conditional/filtering/deletion on binding (using '(w)'/'(s)'/'(=)' notation)
*/
-/* fc-match needs '<unknown filename>', etc handling. */
-#define FCMATCH_FORMAT "%{file|basename}: \"%{family[0]}\" \"%{style[0]}\""
+#define FCMATCH_FORMAT "%{file:-<unknown filename>|basename}: \"%{family[0]:-<unknown family>}\" \"%{style[0]:-<unknown style>}\""
#define FCLIST_FORMAT "%{?file{%{file}: }}%{=unparse}"
else if (0 == strcmp ((const char *) c->word, name))\
do { new_str = func (pat); ret = FcTrue; } while (0)
BUILTIN ("unparse", FcNameUnparse);
- /* BUILTIN ("verbose", FcPatternPrint); */
+ /* BUILTIN ("verbose", FcPatternPrint); XXX */
#undef BUILTIN
else
ret = FcFalse;
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, ','));
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,
FcBool add_colon = FcFalse;
FcBool add_elt_name = FcFalse;
int idx;
+ FcChar8 *else_string;
if (consume_char (c, ':'))
add_colon = FcTrue;
c->format-1 - c->format_orig + 1);
return FcFalse;
}
- expect_char (c, ']');
+ if (!expect_char (c, ']'))
+ return FcFalse;
}
if (consume_char (c, '='))
add_elt_name = FcTrue;
+ /* modifiers */
+ else_string = NULL;
+ if (consume_char (c, ':'))
+ {
+ FcChar8 *orig;
+ /* divert the c->word for now */
+ orig = c->word;
+ c->word = c->word + strlen ((const char *) c->word) + 1;
+ /* for now we just support 'default value' */
+ if (!expect_char (c, '-') ||
+ !read_chars (c, '\0'))
+ {
+ c->word = orig;
+ return FcFalse;
+ }
+ else_string = c->word;
+ c->word = orig;
+ }
+
e = FcPatternObjectFindElt (pat,
FcObjectFromName ((const char *) c->word));
if (e)
else
notfound:
{
+ if (else_string)
+ printf ("%s", else_string);
}
return FcTrue;
from_len = strlen (from);
to = from + from_len + 1;
- /* hack: we temporarily diverge c->word */
+ /* hack: we temporarily divert c->word */
c->word = (FcChar8 *) to;
if (!read_chars (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;
}