[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:
parent
d6506ff6ee
commit
8c31a2434d
|
@ -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.
|
||||||
@@
|
@@
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
214
src/fcformat.c
214
src/fcformat.c
|
@ -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__
|
||||||
|
|
Loading…
Reference in New Issue