[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.
This commit is contained in:
Behdad Esfahbod 2009-02-09 23:08:08 -05:00
parent d6506ff6ee
commit 8c31a2434d
6 changed files with 183 additions and 60 deletions

View File

@ -413,5 +413,5 @@ pattern, use the format "%{family} %{style}\n".
There can be an option width specifier after the percent sign and before 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 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 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.
@@ @@

View File

@ -178,8 +178,11 @@ main (int argc, char **argv)
FcChar8 *s; FcChar8 *s;
s = FcPatternFormat (fs->fonts[j], format); s = FcPatternFormat (fs->fonts[j], format);
printf ("%s", s); if (s)
free (s); {
printf ("%s", s);
free (s);
}
} }
else else
{ {

View File

@ -214,7 +214,11 @@ main (int argc, char **argv)
FcChar8 *s; FcChar8 *s;
s = FcPatternFormat (font, format); s = FcPatternFormat (font, format);
free (s); if (s)
{
printf ("%s", s);
free (s);
}
} }
else if (os) else if (os)
{ {

View File

@ -162,8 +162,11 @@ main (int argc, char **argv)
FcChar8 *s; FcChar8 *s;
s = FcPatternFormat (pat, format); s = FcPatternFormat (pat, format);
printf ("%s", s); if (s)
free (s); {
printf ("%s", s);
free (s);
}
} }
else else
{ {

View File

@ -165,8 +165,11 @@ main (int argc, char **argv)
FcChar8 *s; FcChar8 *s;
s = FcPatternFormat (pat, format); s = FcPatternFormat (pat, format);
printf ("%s", s); if (s)
free (s); {
printf ("%s", s);
free (s);
}
} }
else else
{ {

View File

@ -33,7 +33,7 @@ message (const char *fmt, ...)
{ {
va_list args; va_list args;
va_start (args, fmt); va_start (args, fmt);
fprintf (stderr, "Fontconfig: Pattern format error:"); fprintf (stderr, "Fontconfig: Pattern format error: ");
vfprintf (stderr, fmt, args); vfprintf (stderr, fmt, args);
fprintf (stderr, ".\n"); fprintf (stderr, ".\n");
va_end (args); va_end (args);
@ -48,13 +48,15 @@ typedef struct _FcFormatContext
FcChar8 *scratch; FcChar8 *scratch;
} FcFormatContext; } FcFormatContext;
static void static FcBool
FcFormatContextInit (FcFormatContext *c, FcFormatContextInit (FcFormatContext *c,
const FcChar8 *format) const FcChar8 *format)
{ {
c->format_orig = c->format = format; c->format_orig = c->format = format;
c->format_len = strlen ((const char *) format); c->format_len = strlen ((const char *) format);
c->scratch = malloc (c->format_len + 1); c->scratch = malloc (c->format_len + 1);
return c->scratch != NULL;
} }
static void static void
@ -147,60 +149,36 @@ read_elt_name_to_scratch (FcFormatContext *c)
return FcTrue; return FcTrue;
} }
static void static FcBool
interpret (FcFormatContext *c, interpret (FcFormatContext *c,
FcPattern *pat, FcPattern *pat,
FcStrBuf *buf, FcStrBuf *buf,
FcChar8 term); FcChar8 term);
static void static FcBool
interpret_percent (FcFormatContext *c, interpret_subexpr (FcFormatContext *c,
FcPattern *pat, FcPattern *pat,
FcStrBuf *buf) FcStrBuf *buf)
{ {
int width, before; return expect_char (c, '{') &&
FcChar8 *p; interpret (c, pat, buf, '}') &&
FcPatternElt *e; 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_colon = FcFalse;
FcBool add_elt_name = FcFalse; FcBool add_elt_name = FcFalse;
if (!expect_char (c, '%')) if (consume_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 ':':
add_colon = FcTrue; add_colon = FcTrue;
consume_char (c, ':');
break;
}
parse_tag:
if (!read_elt_name_to_scratch (c)) if (!read_elt_name_to_scratch (c))
goto bail; return FcFalse;
if (consume_char (c, '=')) if (consume_char (c, '='))
add_elt_name = FcTrue; add_elt_name = FcTrue;
@ -223,7 +201,131 @@ parse_tag:
FcNameUnparseValueList (buf, l, '\0'); 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 */ /* handle filters, if any */
/* XXX */ /* XXX */
@ -257,11 +359,7 @@ filter:
} }
} }
expect_char (c, '}'); return expect_char (c, '}');
bail:
if (subpat != pat)
FcPatternDestroy (subpat);
} }
static char escaped_char(const char ch) 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, interpret (FcFormatContext *c,
FcPattern *pat, FcPattern *pat,
FcStrBuf *buf, FcStrBuf *buf,
@ -294,11 +392,13 @@ interpret (FcFormatContext *c,
FcStrBufChar (buf, escaped_char (*c->format++)); FcStrBufChar (buf, escaped_char (*c->format++));
continue; continue;
case '%': case '%':
interpret_percent (c, pat, buf); if (!interpret_percent (c, pat, buf))
return FcFalse;
continue; continue;
} }
FcStrBufChar (buf, *c->format++); FcStrBufChar (buf, *c->format++);
} }
return FcTrue;
} }
FcChar8 * FcChar8 *
@ -306,14 +406,24 @@ FcPatternFormat (FcPattern *pat, const FcChar8 *format)
{ {
FcStrBuf buf; FcStrBuf buf;
FcFormatContext c; FcFormatContext c;
FcBool ret;
FcStrBufInit (&buf, 0, 0); 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); FcFormatContextDone (&c);
return FcStrBufDone (&buf); if (ret)
return FcStrBufDone (&buf);
else
{
FcStrBufDestroy (&buf);
return NULL;
}
} }
#define __fcformat__ #define __fcformat__