[fcformat] Add simple converters

The format '%{family|downcase}' for example prints the lowercase of
the family element.  Three converters are defined right now:
'downcase', 'basename', and 'dirname'.
This commit is contained in:
Behdad Esfahbod 2009-02-10 03:38:22 -05:00
parent 7717b25ffd
commit 2017a5eb79
1 changed files with 131 additions and 93 deletions

View File

@ -28,6 +28,14 @@
#include <stdarg.h> #include <stdarg.h>
/*
* Some ideas for future syntax extensions:
*
* - allow indexing subexprs using '%{[idx]elt1,elt2{subexpr}}'
* - allow indexing simple tags using '%{elt[idx]}'
* - conditional/filtering/deletion on binding (using '(w)'/'(s)' notation)
*/
static void static void
message (const char *fmt, ...) message (const char *fmt, ...)
{ {
@ -45,7 +53,7 @@ typedef struct _FcFormatContext
const FcChar8 *format_orig; const FcChar8 *format_orig;
const FcChar8 *format; const FcChar8 *format;
int format_len; int format_len;
FcChar8 *scratch; FcChar8 *word;
} FcFormatContext; } FcFormatContext;
static FcBool static FcBool
@ -54,9 +62,9 @@ FcFormatContextInit (FcFormatContext *c,
{ {
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->word = malloc (c->format_len + 1);
return c->scratch != NULL; return c->word != NULL;
} }
static void static void
@ -64,7 +72,7 @@ FcFormatContextDone (FcFormatContext *c)
{ {
if (c) if (c)
{ {
free (c->scratch); free (c->word);
} }
} }
@ -117,11 +125,11 @@ FcCharIsPunct (const FcChar8 c)
} }
static FcBool static FcBool
read_elt_name_to_scratch (FcFormatContext *c) read_word (FcFormatContext *c)
{ {
FcChar8 *p; FcChar8 *p;
p = c->scratch; p = c->word;
while (*c->format) while (*c->format)
{ {
@ -139,7 +147,7 @@ read_elt_name_to_scratch (FcFormatContext *c)
} }
*p = '\0'; *p = '\0';
if (p == c->scratch) if (p == c->word)
{ {
message ("expected element name at %d", message ("expected element name at %d",
c->format - c->format_orig + 1); c->format - c->format_orig + 1);
@ -181,11 +189,13 @@ skip_subexpr (FcFormatContext *c);
static FcBool static FcBool
skip_percent (FcFormatContext *c) skip_percent (FcFormatContext *c)
{ {
int width;
if (!expect_char (c, '%')) if (!expect_char (c, '%'))
return FcFalse; return FcFalse;
/* skip an optional width specifier */ /* skip an optional width specifier */
strtol ((const char *) c->format, (char **) &c->format, 10); width = strtol ((const char *) c->format, (char **) &c->format, 10);
if (!expect_char (c, '{')) if (!expect_char (c, '{'))
return FcFalse; return FcFalse;
@ -250,7 +260,7 @@ maybe_skip_subexpr (FcFormatContext *c)
} }
static FcBool static FcBool
interpret_simple_tag (FcFormatContext *c, interpret_simple (FcFormatContext *c,
FcPattern *pat, FcPattern *pat,
FcStrBuf *buf) FcStrBuf *buf)
{ {
@ -261,14 +271,14 @@ interpret_simple_tag (FcFormatContext *c,
if (consume_char (c, ':')) if (consume_char (c, ':'))
add_colon = FcTrue; add_colon = FcTrue;
if (!read_elt_name_to_scratch (c)) if (!read_word (c))
return FcFalse; return FcFalse;
if (consume_char (c, '=')) if (consume_char (c, '='))
add_elt_name = FcTrue; add_elt_name = FcTrue;
e = FcPatternObjectFindElt (pat, e = FcPatternObjectFindElt (pat,
FcObjectFromName ((const char *) c->scratch)); FcObjectFromName ((const char *) c->word));
if (e) if (e)
{ {
FcValueListPtr l; FcValueListPtr l;
@ -277,7 +287,7 @@ interpret_simple_tag (FcFormatContext *c,
FcStrBufChar (buf, ':'); FcStrBufChar (buf, ':');
if (add_elt_name) if (add_elt_name)
{ {
FcStrBufString (buf, c->scratch); FcStrBufString (buf, c->word);
FcStrBufChar (buf, '='); FcStrBufChar (buf, '=');
} }
@ -305,8 +315,8 @@ interpret_filter (FcFormatContext *c,
do do
{ {
if (!read_elt_name_to_scratch (c) || if (!read_word (c) ||
!FcObjectSetAdd (os, (const char *) c->scratch)) !FcObjectSetAdd (os, (const char *) c->word))
{ {
FcObjectSetDestroy (os); FcObjectSetDestroy (os);
return FcFalse; return FcFalse;
@ -341,13 +351,13 @@ interpret_delete (FcFormatContext *c,
do do
{ {
if (!read_elt_name_to_scratch (c)) if (!read_word (c))
{ {
FcPatternDestroy (subpat); FcPatternDestroy (subpat);
return FcFalse; return FcFalse;
} }
FcPatternDel (subpat, (const char *) c->scratch); FcPatternDel (subpat, (const char *) c->word);
} }
while (consume_char (c, ',')); while (consume_char (c, ','));
@ -359,7 +369,7 @@ interpret_delete (FcFormatContext *c,
} }
static FcBool static FcBool
interpret_conditional (FcFormatContext *c, interpret_cond (FcFormatContext *c,
FcPattern *pat, FcPattern *pat,
FcStrBuf *buf) FcStrBuf *buf)
{ {
@ -377,14 +387,14 @@ interpret_conditional (FcFormatContext *c,
negate = consume_char (c, '!'); negate = consume_char (c, '!');
if (!read_elt_name_to_scratch (c)) if (!read_word (c))
return FcFalse; return FcFalse;
pass = pass && pass = pass &&
(negate ^ (negate ^
FcResultMatch == FcPatternGet (pat, (FcResultMatch == FcPatternGet (pat,
(const char *) c->scratch, (const char *) c->word,
0, &v)); 0, &v)));
} }
while (consume_char (c, ',')); while (consume_char (c, ','));
@ -404,12 +414,96 @@ interpret_conditional (FcFormatContext *c,
return FcTrue; return FcTrue;
} }
static FcChar8 *
convert (FcFormatContext *c,
const FcChar8 *str)
{
if (!read_word (c))
return NULL;
else if (0 == strcmp ((const char *) c->word, "downcase"))
return FcStrDowncase (str);
else if (0 == strcmp ((const char *) c->word, "basename"))
return FcStrBasename (str);
else if (0 == strcmp ((const char *) c->word, "dirname"))
return FcStrDirname (str);
message ("unknown converter \"%s\"",
c->word);
return NULL;
}
static FcBool
maybe_interpret_converts (FcFormatContext *c,
FcStrBuf *buf,
int start)
{
while (consume_char (c, '|'))
{
const FcChar8 *str;
FcChar8 *new_str;
/* nul-terminate the buffer */
FcStrBufChar (buf, '\0');
if (buf->failed)
return FcFalse;
str = buf->buf + start;
if (!(new_str = convert (c, str)))
return FcFalse;
/* replace in the buffer */
buf->len = start;
FcStrBufString (buf, new_str);
free (new_str);
}
return FcTrue;
}
static FcBool
align_to_width (FcStrBuf *buf,
int start,
int width)
{
int len;
if (buf->failed)
return FcFalse;
len = buf->len - start;
if (len < -width)
{
/* left align */
while (len++ < -width)
FcStrBufChar (buf, ' ');
}
else if (len < width)
{
int old_len;
old_len = len;
/* right align */
while (len++ < width)
FcStrBufChar (buf, ' ');
if (buf->failed)
return FcFalse;
len = old_len;
memmove (buf->buf + buf->len - len,
buf->buf + buf->len - width,
len);
memset (buf->buf + buf->len - width,
' ',
width - len);
}
return !buf->failed;
}
static FcBool static FcBool
interpret_percent (FcFormatContext *c, interpret_percent (FcFormatContext *c,
FcPattern *pat, FcPattern *pat,
FcStrBuf *buf) FcStrBuf *buf)
{ {
int width, before; int width, start;
FcBool ret;
if (!expect_char (c, '%')) if (!expect_char (c, '%'))
return FcFalse; return FcFalse;
@ -423,79 +517,23 @@ interpret_percent (FcFormatContext *c,
/* parse an optional width specifier */ /* parse an optional width specifier */
width = strtol ((const char *) c->format, (char **) &c->format, 10); width = strtol ((const char *) c->format, (char **) &c->format, 10);
before = buf->len;
if (!expect_char (c, '{')) if (!expect_char (c, '{'))
return FcFalse; return FcFalse;
start = buf->len;
switch (*c->format) { switch (*c->format) {
case '{': ret = interpret_subexpr (c, pat, buf); break;
case '{': case '+': ret = interpret_filter (c, pat, buf); break;
/* subexpression */ case '-': ret = interpret_delete (c, pat, buf); break;
if (!interpret_subexpr (c, pat, buf)) case '?': ret = interpret_cond (c, pat, buf); break;
return FcFalse; default: ret = interpret_simple (c, pat, buf); break;
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;
case '?':
/* conditional on pattern elements */
if (!interpret_conditional (c, pat, buf))
return FcFalse;
break;
default:
/* simple tag */
if (!interpret_simple_tag (c, pat, buf))
return FcFalse;
break;
} }
/* handle filters, if any */ return ret &&
/* XXX */ maybe_interpret_converts (c, buf, start) &&
align_to_width (buf, start, width) &&
/* align to width */ expect_char (c, '}');
if (!buf->failed)
{
int after, len;
after = buf->len;
len = after - before;
if (len < -width)
{
/* left align */
while (len++ < -width)
FcStrBufChar (buf, ' ');
}
else if (len < width)
{
/* right align */
while (len++ < width)
FcStrBufChar (buf, ' ');
len = after - before;
memmove (buf->buf + buf->len - len,
buf->buf + buf->len - width,
len);
memset (buf->buf + buf->len - width,
' ',
width - len);
}
}
return expect_char (c, '}');
} }
static char escaped_char(const char ch) static char escaped_char(const char ch)