[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
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.
@@

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
if (ret)
return FcStrBufDone (&buf);
else
{
FcStrBufDestroy (&buf);
return NULL;
}
}
#define __fcformat__