* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Keith Packard not be used in
+ * documentation, and that the name of the author(s) not be used in
* advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
+ * specific, written prior permission. The authors make no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
#include <stdarg.h>
-/* XXX Document the language.
+/* The language is documented in doc/fcformat.fncs
+ * These are the features implemented:
*
- * These are mostly the features implemented but not documented:
+ * simple %{elt}
+ * width %width{elt}
+ * index %{elt[idx]}
+ * name= %{elt=}
+ * :name= %{:elt}
+ * default %{elt:-word}
+ * count %{#elt}
+ * subexpr %{{expr}}
+ * filter-out %{-elt1,elt2,elt3{expr}}
+ * filter-in %{+elt1,elt2,elt3{expr}}
+ * conditional %{?elt1,elt2,!elt3{}{}}
+ * enumerate %{[]elt1,elt2{expr}}
+ * langset langset enumeration using the same syntax
+ * builtin %{=blt}
+ * convert %{elt|conv1|conv2|conv3}
*
- * width %[[-]width]{tag}
- * index %{tag[ids]}
- * name= %{tag=|decorator}
- * :name= %{:tag=|decorator}
- * subexpr %{{expr}|decorator1|decorator2}
- * delete %{-charset,lang{expr}|decorator}
- * filter %{+family,familylang{expr}|decorator}
- * cond %{?tag1,tag2,!tag3{}{}}
- * decorat %{tag|decorator1|decorator2}
- * default %{parameter:-word}
- * array %{[]family,familylang{expr}|decorator}
- * langset enumeration using the same syntax as arrays
- *
- * filters:
- * basename FcStrBasename
- * dirname FcStrDirname
- * downcase FcStrDowncase
+ * converters:
+ * basename FcStrBasename
+ * dirname FcStrDirname
+ * downcase FcStrDowncase
* shescape
* cescape
* xmlescape
- * delete delete chars
- * escape escape chars
- * translate translate chars
+ * delete delete chars
+ * escape escape chars
+ * translate translate chars
*
* builtins:
- * unparse
- * fcmatch
- * fclist
- * pkgkit
- */
-
-/*
+ * unparse FcNameUnparse
+ * fcmatch fc-match default
+ * fclist fc-list default
+ * fccat fc-cat default
+ * pkgkit PackageKit package tag format
+ *
+ *
* Some ideas for future syntax extensions:
*
+ * - verbose builtin that is like FcPatternPrint
* - allow indexing subexprs using '%{[idx]elt1,elt2{subexpr}}'
+ * - allow indexing in +, -, ? filtering?
* - conditional/filtering/deletion on binding (using '(w)'/'(s)'/'(=)' notation)
*/
+#define FCCAT_FORMAT "\"%{file|basename|cescape}\" %{index} \"%{-file{%{=unparse|cescape}}}\""
#define FCMATCH_FORMAT "%{file:-<unknown filename>|basename}: \"%{family[0]:-<unknown family>}\" \"%{style[0]:-<unknown style>}\""
-#define FCLIST_FORMAT "%{?file{%{file}: }}%{=unparse}"
+#define FCLIST_FORMAT "%{?file{%{file}: }}%{-file{%{=unparse}}}"
#define PKGKIT_FORMAT "%{[]family{font(%{family|downcase|delete( )})\n}}%{[]lang{font(:lang=%{lang|downcase|translate(_,-)})\n}}"
#define BUILTIN(name, format) \
else if (0 == strcmp ((const char *) c->word, name))\
ret = FcPatternFormatToBuf (pat, (const FcChar8 *) format, buf)
+ BUILTIN ("fccat", FCCAT_FORMAT);
BUILTIN ("fcmatch", FCMATCH_FORMAT);
BUILTIN ("fclist", FCLIST_FORMAT);
BUILTIN ("pkgkit", PKGKIT_FORMAT);
}
static FcBool
-interpret_filter (FcFormatContext *c,
- FcPattern *pat,
- FcStrBuf *buf)
+interpret_filter_in (FcFormatContext *c,
+ FcPattern *pat,
+ FcStrBuf *buf)
{
FcObjectSet *os;
FcPattern *subpat;
do
{
+ /* XXX binding */
if (!read_word (c) ||
!FcObjectSetAdd (os, (const char *) c->word))
{
}
static FcBool
-interpret_delete (FcFormatContext *c,
- FcPattern *pat,
- FcStrBuf *buf)
+interpret_filter_out (FcFormatContext *c,
+ FcPattern *pat,
+ FcStrBuf *buf)
{
FcPattern *subpat;
}
static FcBool
-interpret_array (FcFormatContext *c,
- FcPattern *pat,
- FcStrBuf *buf)
+interpret_enumerate (FcFormatContext *c,
+ FcPattern *pat,
+ FcStrBuf *buf)
{
FcObjectSet *os;
FcPattern *subpat;
{
FcLangSet *langset;
if (FcResultMatch ==
- FcPatternGetLangSet (pat, os->objects[0], idx, &langset))
+ FcPatternGetLangSet (pat, os->objects[0], 0, &langset))
{
FcStrSet *ss;
if (!(ss = FcLangSetGetLangs (langset)) ||
FcPatternDel (subpat, os->objects[0]);
if ((lang = FcStrListNext (lang_strs)))
{
+ /* XXX binding? */
FcPatternAddString (subpat, os->objects[0], lang);
done = FcFalse;
}
if (FcResultMatch ==
FcPatternGet (pat, os->objects[i], idx, &v))
{
+ /* XXX binding */
FcPatternAdd (subpat, os->objects[i], v, FcFalse);
done = FcFalse;
}
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'))
+ !read_chars (c, '|'))
{
c->word = orig;
return FcFalse;
e = FcPatternObjectFindElt (pat,
FcObjectFromName ((const char *) c->word));
- if (e)
+ if (e || else_string)
{
- FcValueListPtr l;
+ FcValueListPtr l = NULL;
if (add_colon)
FcStrBufChar (buf, ':');
FcStrBufChar (buf, '=');
}
- l = FcPatternEltValues(e);
+ if (e)
+ l = FcPatternEltValues(e);
if (idx != -1)
{
}
else goto notfound;
}
- else
+ else if (l)
{
FcNameUnparseValueList (buf, l, '\0');
}
- }
- else
-notfound:
- {
- if (else_string)
- printf ("%s", else_string);
+ else
+ {
+ notfound:
+ if (else_string)
+ FcStrBufString (buf, else_string);
+ }
}
return FcTrue;
const FcChar8 *str,
FcStrBuf *buf)
{
+ /* XXX escape \n etc? */
+
while(*str)
{
switch (*str)
const FcChar8 *str,
FcStrBuf *buf)
{
+ /* XXX escape \n etc? */
+
while(*str)
{
switch (*str)
start = buf->len;
switch (*c->format) {
- case '=': ret = interpret_builtin (c, pat, buf); break;
- case '{': ret = interpret_subexpr (c, pat, buf); break;
- case '+': ret = interpret_filter (c, pat, buf); break;
- 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;
+ case '=': ret = interpret_builtin (c, pat, buf); break;
+ case '{': ret = interpret_subexpr (c, pat, buf); break;
+ case '+': ret = interpret_filter_in (c, pat, buf); break;
+ case '-': ret = interpret_filter_out (c, pat, buf); break;
+ case '?': ret = interpret_cond (c, pat, buf); break;
+ case '#': ret = interpret_count (c, pat, buf); break;
+ case '[': ret = interpret_enumerate (c, pat, buf); break;
+ default: ret = interpret_simple (c, pat, buf); break;
}
return ret &&