[fcformat] Add support for subexpressions
The syntax is '{{expr}}'. Can be used for aligning/justifying an entire subexpr for example.
This commit is contained in:
parent
27b3e2dddf
commit
d6506ff6ee
151
src/fcformat.c
151
src/fcformat.c
|
@ -33,9 +33,9 @@ message (const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start (args, fmt);
|
va_start (args, fmt);
|
||||||
fprintf (stderr, "Fontconfig: ");
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,31 +71,107 @@ consume_char (FcFormatContext *c,
|
||||||
FcChar8 term)
|
FcChar8 term)
|
||||||
{
|
{
|
||||||
if (*c->format != term)
|
if (*c->format != term)
|
||||||
{
|
|
||||||
message ("Pattern format error: expected '%c' at %d",
|
|
||||||
term, c->format - c->format_orig + 1);
|
|
||||||
return FcFalse;
|
return FcFalse;
|
||||||
}
|
|
||||||
|
|
||||||
c->format++;
|
c->format++;
|
||||||
return FcTrue;
|
return FcTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FcBool
|
||||||
|
expect_char (FcFormatContext *c,
|
||||||
|
FcChar8 term)
|
||||||
|
{
|
||||||
|
FcBool res = consume_char (c, term);
|
||||||
|
if (!res)
|
||||||
|
{
|
||||||
|
if (c->format == c->format_orig + c->format_len)
|
||||||
|
message ("format ended while expecting '%c'",
|
||||||
|
term);
|
||||||
|
else
|
||||||
|
message ("expected '%c' at %d",
|
||||||
|
term, c->format - c->format_orig + 1);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FcBool
|
||||||
|
FcCharIsPunct (const FcChar8 c)
|
||||||
|
{
|
||||||
|
if (c < '0')
|
||||||
|
return FcTrue;
|
||||||
|
if (c <= '9')
|
||||||
|
return FcFalse;
|
||||||
|
if (c < 'A')
|
||||||
|
return FcTrue;
|
||||||
|
if (c <= 'Z')
|
||||||
|
return FcFalse;
|
||||||
|
if (c < 'a')
|
||||||
|
return FcTrue;
|
||||||
|
if (c <= 'z')
|
||||||
|
return FcFalse;
|
||||||
|
if (c <= '~')
|
||||||
|
return FcTrue;
|
||||||
|
return FcFalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FcBool
|
||||||
|
read_elt_name_to_scratch (FcFormatContext *c)
|
||||||
|
{
|
||||||
|
FcChar8 *p;
|
||||||
|
|
||||||
|
p = c->scratch;
|
||||||
|
|
||||||
|
while (*c->format)
|
||||||
|
{
|
||||||
|
if (*c->format == '\\')
|
||||||
|
{
|
||||||
|
c->format++;
|
||||||
|
if (*c->format)
|
||||||
|
c->format++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (FcCharIsPunct (*c->format))
|
||||||
|
break;
|
||||||
|
|
||||||
|
*p++ = *c->format++;
|
||||||
|
}
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
if (p == c->scratch)
|
||||||
|
{
|
||||||
|
message ("expected element name at %d",
|
||||||
|
c->format - c->format_orig + 1);
|
||||||
|
return FcFalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FcTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
interpret (FcFormatContext *c,
|
||||||
|
FcPattern *pat,
|
||||||
|
FcStrBuf *buf,
|
||||||
|
FcChar8 term);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
interpret_percent (FcFormatContext *c,
|
interpret_percent (FcFormatContext *c,
|
||||||
FcPattern *pat,
|
FcPattern *pat,
|
||||||
FcStrBuf *buf)
|
FcStrBuf *buf)
|
||||||
{
|
{
|
||||||
int width, before;
|
int width, before;
|
||||||
FcChar8 *p;
|
FcChar8 *p;
|
||||||
FcPatternElt *e;
|
FcPatternElt *e;
|
||||||
|
|
||||||
if (!consume_char (c, '%'))
|
FcPattern *subpat = pat;
|
||||||
|
FcBool add_colon = FcFalse;
|
||||||
|
FcBool add_elt_name = FcFalse;
|
||||||
|
|
||||||
|
if (!expect_char (c, '%'))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (*c->format == '%') /* "%%" */
|
if (consume_char (c, '%')) /* "%%" */
|
||||||
{
|
{
|
||||||
FcStrBufChar (buf, *c->format++);
|
FcStrBufChar (buf, '%');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,29 +180,50 @@ interpret_percent (FcFormatContext *c,
|
||||||
|
|
||||||
before = buf->len;
|
before = buf->len;
|
||||||
|
|
||||||
if (!consume_char (c, '{'))
|
if (!expect_char (c, '{'))
|
||||||
return;
|
goto bail;
|
||||||
|
|
||||||
p = (FcChar8 *) strpbrk ((const char *) c->format, "}" /* "=?:}" */);
|
if (consume_char (c, '{'))
|
||||||
if (!p)
|
|
||||||
{
|
{
|
||||||
message ("Pattern format missing closing brace for opening brace at %d",
|
/* it's just a subexpression. no tag involved */
|
||||||
c->format-1 - c->format_orig + 1);
|
interpret (c, pat, buf, '}');
|
||||||
return;
|
expect_char (c, '}');
|
||||||
|
goto filter;
|
||||||
}
|
}
|
||||||
/* extract the element name */
|
|
||||||
memcpy (c->scratch, c->format, p - c->format);
|
|
||||||
c->scratch[p - c->format] = '\0';
|
|
||||||
c->format = p;
|
|
||||||
|
|
||||||
e = FcPatternObjectFindElt (pat, FcObjectFromName ((const char *) c->scratch));
|
switch (*c->format) {
|
||||||
|
case ':':
|
||||||
|
add_colon = FcTrue;
|
||||||
|
consume_char (c, ':');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_tag:
|
||||||
|
if (!read_elt_name_to_scratch (c))
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
if (consume_char (c, '='))
|
||||||
|
add_elt_name = FcTrue;
|
||||||
|
|
||||||
|
e = FcPatternObjectFindElt (pat,
|
||||||
|
FcObjectFromName ((const char *) c->scratch));
|
||||||
if (e)
|
if (e)
|
||||||
{
|
{
|
||||||
FcValueListPtr l;
|
FcValueListPtr l;
|
||||||
|
|
||||||
|
if (add_colon)
|
||||||
|
FcStrBufChar (buf, ':');
|
||||||
|
if (add_elt_name)
|
||||||
|
{
|
||||||
|
FcStrBufString (buf, c->scratch);
|
||||||
|
FcStrBufChar (buf, '=');
|
||||||
|
}
|
||||||
|
|
||||||
l = FcPatternEltValues(e);
|
l = FcPatternEltValues(e);
|
||||||
FcNameUnparseValueList (buf, l, '\0');
|
FcNameUnparseValueList (buf, l, '\0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filter:
|
||||||
/* handle filters, if any */
|
/* handle filters, if any */
|
||||||
/* XXX */
|
/* XXX */
|
||||||
|
|
||||||
|
@ -160,7 +257,11 @@ interpret_percent (FcFormatContext *c,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
consume_char (c, '}');
|
expect_char (c, '}');
|
||||||
|
|
||||||
|
bail:
|
||||||
|
if (subpat != pat)
|
||||||
|
FcPatternDestroy (subpat);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char escaped_char(const char ch)
|
static char escaped_char(const char ch)
|
||||||
|
@ -198,8 +299,6 @@ interpret (FcFormatContext *c,
|
||||||
}
|
}
|
||||||
FcStrBufChar (buf, *c->format++);
|
FcStrBufChar (buf, *c->format++);
|
||||||
}
|
}
|
||||||
if (*c->format != term)
|
|
||||||
message ("Pattern format ended while looking for '%c'", term);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FcChar8 *
|
FcChar8 *
|
||||||
|
|
Loading…
Reference in New Issue