summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBehdad Esfahbod <behdad@behdad.org>2009-02-09 23:08:08 -0500
committerBehdad Esfahbod <behdad@behdad.org>2009-02-15 13:40:26 -0800
commit8c31a2434d5dfa475ef710ad52c992111caac424 (patch)
tree91a60b276619bcd78639b68698c31ea86d54404c
parentd6506ff6eeb4a4cb0bfe827174e474c7b91ff045 (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.
-rw-r--r--doc/fcpattern.fncs2
-rw-r--r--fc-list/fc-list.c7
-rw-r--r--fc-match/fc-match.c6
-rw-r--r--fc-query/fc-query.c7
-rw-r--r--fc-scan/fc-scan.c7
-rw-r--r--src/fcformat.c214
6 files changed, 183 insertions, 60 deletions
diff --git a/doc/fcpattern.fncs b/doc/fcpattern.fncs
index 22a89ad..35ef68b 100644
--- a/doc/fcpattern.fncs
+++ b/doc/fcpattern.fncs
@@ -413,5 +413,5 @@ pattern, use the format "%{family} %{style}\n".
There can be an option width specifier after the percent sign and before
the opening brace. The width modifier acts similar to those in printf.
The return value refers to newly allocated memory which should be freed by the
-caller using free().
+caller using free(), or NULL if <parameter>format</parameter> is invalid.
@@
diff --git a/fc-list/fc-list.c b/fc-list/fc-list.c
index 470b4b9..cbcc3c0 100644
--- a/fc-list/fc-list.c
+++ b/fc-list/fc-list.c
@@ -178,8 +178,11 @@ main (int argc, char **argv)
FcChar8 *s;
s = FcPatternFormat (fs->fonts[j], format);
- printf ("%s", s);
- free (s);
+ if (s)
+ {
+ printf ("%s", s);
+ free (s);
+ }
}
else
{
diff --git a/fc-match/fc-match.c b/fc-match/fc-match.c
index 6f3d2dc..86ff253 100644
--- a/fc-match/fc-match.c
+++ b/fc-match/fc-match.c
@@ -214,7 +214,11 @@ main (int argc, char **argv)
FcChar8 *s;
s = FcPatternFormat (font, format);
- free (s);
+ if (s)
+ {
+ printf ("%s", s);
+ free (s);
+ }
}
else if (os)
{
diff --git a/fc-query/fc-query.c b/fc-query/fc-query.c
index 8c5672c..4d707bc 100644
--- a/fc-query/fc-query.c
+++ b/fc-query/fc-query.c
@@ -162,8 +162,11 @@ main (int argc, char **argv)
FcChar8 *s;
s = FcPatternFormat (pat, format);
- printf ("%s", s);
- free (s);
+ if (s)
+ {
+ printf ("%s", s);
+ free (s);
+ }
}
else
{
diff --git a/fc-scan/fc-scan.c b/fc-scan/fc-scan.c
index 573f7ef..1f023fb 100644
--- a/fc-scan/fc-scan.c
+++ b/fc-scan/fc-scan.c
@@ -165,8 +165,11 @@ main (int argc, char **argv)
FcChar8 *s;
s = FcPatternFormat (pat, format);
- printf ("%s", s);
- free (s);
+ if (s)
+ {
+ printf ("%s", s);
+ free (s);
+ }
}
else
{
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__