|
Packit |
352660 |
/*
|
|
Packit |
352660 |
* Copyright © 2008,2009 Red Hat, Inc.
|
|
Packit |
352660 |
*
|
|
Packit |
352660 |
* Red Hat Author(s): Behdad Esfahbod
|
|
Packit |
352660 |
*
|
|
Packit |
352660 |
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
Packit |
352660 |
* documentation for any purpose is hereby granted without fee, provided that
|
|
Packit |
352660 |
* the above copyright notice appear in all copies and that both that
|
|
Packit |
352660 |
* copyright notice and this permission notice appear in supporting
|
|
Packit |
352660 |
* documentation, and that the name of the author(s) not be used in
|
|
Packit |
352660 |
* advertising or publicity pertaining to distribution of the software without
|
|
Packit |
352660 |
* specific, written prior permission. The authors make no
|
|
Packit |
352660 |
* representations about the suitability of this software for any purpose. It
|
|
Packit |
352660 |
* is provided "as is" without express or implied warranty.
|
|
Packit |
352660 |
*
|
|
Packit |
352660 |
* THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
Packit |
352660 |
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
Packit |
352660 |
* EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
Packit |
352660 |
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
Packit |
352660 |
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
Packit |
352660 |
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
Packit |
352660 |
* PERFORMANCE OF THIS SOFTWARE.
|
|
Packit |
352660 |
*/
|
|
Packit |
352660 |
|
|
Packit |
352660 |
#include "fcint.h"
|
|
Packit |
352660 |
#include <stdlib.h>
|
|
Packit |
352660 |
#include <string.h>
|
|
Packit |
352660 |
#include <stdarg.h>
|
|
Packit |
352660 |
|
|
Packit |
352660 |
|
|
Packit |
352660 |
/* The language is documented in doc/fcformat.fncs
|
|
Packit |
352660 |
* These are the features implemented:
|
|
Packit |
352660 |
*
|
|
Packit |
352660 |
* simple %{elt}
|
|
Packit |
352660 |
* width %width{elt}
|
|
Packit |
352660 |
* index %{elt[idx]}
|
|
Packit |
352660 |
* name= %{elt=}
|
|
Packit |
352660 |
* :name= %{:elt}
|
|
Packit |
352660 |
* default %{elt:-word}
|
|
Packit |
352660 |
* count %{#elt}
|
|
Packit |
352660 |
* subexpr %{{expr}}
|
|
Packit |
352660 |
* filter-out %{-elt1,elt2,elt3{expr}}
|
|
Packit |
352660 |
* filter-in %{+elt1,elt2,elt3{expr}}
|
|
Packit |
352660 |
* conditional %{?elt1,elt2,!elt3{}{}}
|
|
Packit |
352660 |
* enumerate %{[]elt1,elt2{expr}}
|
|
Packit |
352660 |
* langset langset enumeration using the same syntax
|
|
Packit |
352660 |
* builtin %{=blt}
|
|
Packit |
352660 |
* convert %{elt|conv1|conv2|conv3}
|
|
Packit |
352660 |
*
|
|
Packit |
352660 |
* converters:
|
|
Packit |
352660 |
* basename FcStrBasename
|
|
Packit |
352660 |
* dirname FcStrDirname
|
|
Packit |
352660 |
* downcase FcStrDowncase
|
|
Packit |
352660 |
* shescape
|
|
Packit |
352660 |
* cescape
|
|
Packit |
352660 |
* xmlescape
|
|
Packit |
352660 |
* delete delete chars
|
|
Packit |
352660 |
* escape escape chars
|
|
Packit |
352660 |
* translate translate chars
|
|
Packit |
352660 |
*
|
|
Packit |
352660 |
* builtins:
|
|
Packit |
352660 |
* unparse FcNameUnparse
|
|
Packit |
352660 |
* fcmatch fc-match default
|
|
Packit |
352660 |
* fclist fc-list default
|
|
Packit |
352660 |
* fccat fc-cat default
|
|
Packit |
352660 |
* pkgkit PackageKit package tag format
|
|
Packit |
352660 |
*
|
|
Packit |
352660 |
*
|
|
Packit |
352660 |
* Some ideas for future syntax extensions:
|
|
Packit |
352660 |
*
|
|
Packit |
352660 |
* - verbose builtin that is like FcPatternPrint
|
|
Packit |
352660 |
* - allow indexing subexprs using '%{[idx]elt1,elt2{subexpr}}'
|
|
Packit |
352660 |
* - allow indexing in +, -, ? filtering?
|
|
Packit |
352660 |
* - conditional/filtering/deletion on binding (using '(w)'/'(s)'/'(=)' notation)
|
|
Packit |
352660 |
*/
|
|
Packit |
352660 |
|
|
Packit |
352660 |
|
|
Packit |
352660 |
#define FCCAT_FORMAT "\"%{file|basename|cescape}\" %{index} \"%{-file{%{=unparse|cescape}}}\""
|
|
Packit |
352660 |
#define FCMATCH_FORMAT "%{file:-<unknown filename>|basename}: \"%{family[0]:-<unknown family>}\" \"%{style[0]:-<unknown style>}\""
|
|
Packit |
352660 |
#define FCLIST_FORMAT "%{?file{%{file}: }}%{-file{%{=unparse}}}"
|
|
Packit |
352660 |
#define PKGKIT_FORMAT "%{[]family{font(%{family|downcase|delete( )})\n}}%{[]lang{font(:lang=%{lang|downcase|translate(_,-)})\n}}"
|
|
Packit |
352660 |
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static void
|
|
Packit |
352660 |
message (const char *fmt, ...)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
va_list args;
|
|
Packit |
352660 |
va_start (args, fmt);
|
|
Packit |
352660 |
fprintf (stderr, "Fontconfig: Pattern format error: ");
|
|
Packit |
352660 |
vfprintf (stderr, fmt, args);
|
|
Packit |
352660 |
fprintf (stderr, ".\n");
|
|
Packit |
352660 |
va_end (args);
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
|
|
Packit |
352660 |
typedef struct _FcFormatContext
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
const FcChar8 *format_orig;
|
|
Packit |
352660 |
const FcChar8 *format;
|
|
Packit |
352660 |
int format_len;
|
|
Packit |
352660 |
FcChar8 *word;
|
|
Packit |
352660 |
FcBool word_allocated;
|
|
Packit |
352660 |
} FcFormatContext;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
FcFormatContextInit (FcFormatContext *c,
|
|
Packit |
352660 |
const FcChar8 *format,
|
|
Packit |
352660 |
FcChar8 *scratch,
|
|
Packit |
352660 |
int scratch_len)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
c->format_orig = c->format = format;
|
|
Packit |
352660 |
c->format_len = strlen ((const char *) format);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (c->format_len < scratch_len)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
c->word = scratch;
|
|
Packit |
352660 |
c->word_allocated = FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
c->word = malloc (c->format_len + 1);
|
|
Packit |
352660 |
c->word_allocated = FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return c->word != NULL;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static void
|
|
Packit |
352660 |
FcFormatContextDone (FcFormatContext *c)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (c && c->word_allocated)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
free (c->word);
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
consume_char (FcFormatContext *c,
|
|
Packit |
352660 |
FcChar8 term)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (*c->format != term)
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
c->format++;
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
expect_char (FcFormatContext *c,
|
|
Packit |
352660 |
FcChar8 term)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcBool res = consume_char (c, term);
|
|
Packit |
352660 |
if (!res)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (c->format == c->format_orig + c->format_len)
|
|
Packit |
352660 |
message ("format ended while expecting '%c'",
|
|
Packit |
352660 |
term);
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
message ("expected '%c' at %d",
|
|
Packit |
352660 |
term, c->format - c->format_orig + 1);
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
return res;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
FcCharIsPunct (const FcChar8 c)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (c < '0')
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
if (c <= '9')
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
if (c < 'A')
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
if (c <= 'Z')
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
if (c < 'a')
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
if (c <= 'z')
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
if (c <= '~')
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static char escaped_char(const char ch)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
switch (ch) {
|
|
Packit |
352660 |
case 'a': return '\a';
|
|
Packit |
352660 |
case 'b': return '\b';
|
|
Packit |
352660 |
case 'f': return '\f';
|
|
Packit |
352660 |
case 'n': return '\n';
|
|
Packit |
352660 |
case 'r': return '\r';
|
|
Packit |
352660 |
case 't': return '\t';
|
|
Packit |
352660 |
case 'v': return '\v';
|
|
Packit |
352660 |
default: return ch;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
read_word (FcFormatContext *c)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcChar8 *p;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
p = c->word;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
while (*c->format)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (*c->format == '\\')
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
c->format++;
|
|
Packit |
352660 |
if (*c->format)
|
|
Packit |
352660 |
*p++ = escaped_char (*c->format++);
|
|
Packit |
352660 |
continue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
else if (FcCharIsPunct (*c->format))
|
|
Packit |
352660 |
break;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
*p++ = *c->format++;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
*p = '\0';
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (p == c->word)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
message ("expected identifier at %d",
|
|
Packit |
352660 |
c->format - c->format_orig + 1);
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
read_chars (FcFormatContext *c,
|
|
Packit |
352660 |
FcChar8 term)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcChar8 *p;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
p = c->word;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
while (*c->format && *c->format != '}' && *c->format != term)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (*c->format == '\\')
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
c->format++;
|
|
Packit |
352660 |
if (*c->format)
|
|
Packit |
352660 |
*p++ = escaped_char (*c->format++);
|
|
Packit |
352660 |
continue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
*p++ = *c->format++;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
*p = '\0';
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (p == c->word)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
message ("expected character data at %d",
|
|
Packit |
352660 |
c->format - c->format_orig + 1);
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
FcPatternFormatToBuf (FcPattern *pat,
|
|
Packit |
352660 |
const FcChar8 *format,
|
|
Packit |
352660 |
FcStrBuf *buf);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
interpret_builtin (FcFormatContext *c,
|
|
Packit |
352660 |
FcPattern *pat,
|
|
Packit |
352660 |
FcStrBuf *buf)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcChar8 *new_str;
|
|
Packit |
352660 |
FcBool ret;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!expect_char (c, '=') ||
|
|
Packit |
352660 |
!read_word (c))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
/* try simple builtins first */
|
|
Packit |
352660 |
if (0) { }
|
|
Packit |
352660 |
#define BUILTIN(name, func) \
|
|
Packit |
352660 |
else if (0 == strcmp ((const char *) c->word, name))\
|
|
Packit |
352660 |
do { new_str = func (pat); ret = FcTrue; } while (0)
|
|
Packit |
352660 |
BUILTIN ("unparse", FcNameUnparse);
|
|
Packit |
352660 |
/* BUILTIN ("verbose", FcPatternPrint); XXX */
|
|
Packit |
352660 |
#undef BUILTIN
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
ret = FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (ret)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (new_str)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcStrBufString (buf, new_str);
|
|
Packit |
352660 |
FcStrFree (new_str);
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
/* now try our custom formats */
|
|
Packit |
352660 |
if (0) { }
|
|
Packit |
352660 |
#define BUILTIN(name, format) \
|
|
Packit |
352660 |
else if (0 == strcmp ((const char *) c->word, name))\
|
|
Packit |
352660 |
ret = FcPatternFormatToBuf (pat, (const FcChar8 *) format, buf)
|
|
Packit |
352660 |
BUILTIN ("fccat", FCCAT_FORMAT);
|
|
Packit |
352660 |
BUILTIN ("fcmatch", FCMATCH_FORMAT);
|
|
Packit |
352660 |
BUILTIN ("fclist", FCLIST_FORMAT);
|
|
Packit |
352660 |
BUILTIN ("pkgkit", PKGKIT_FORMAT);
|
|
Packit |
352660 |
#undef BUILTIN
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
ret = FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!ret)
|
|
Packit |
352660 |
message ("unknown builtin \"%s\"",
|
|
Packit |
352660 |
c->word);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return ret;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
interpret_expr (FcFormatContext *c,
|
|
Packit |
352660 |
FcPattern *pat,
|
|
Packit |
352660 |
FcStrBuf *buf,
|
|
Packit |
352660 |
FcChar8 term);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
interpret_subexpr (FcFormatContext *c,
|
|
Packit |
352660 |
FcPattern *pat,
|
|
Packit |
352660 |
FcStrBuf *buf)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
return expect_char (c, '{') &&
|
|
Packit |
352660 |
interpret_expr (c, pat, buf, '}') &&
|
|
Packit |
352660 |
expect_char (c, '}');
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
maybe_interpret_subexpr (FcFormatContext *c,
|
|
Packit |
352660 |
FcPattern *pat,
|
|
Packit |
352660 |
FcStrBuf *buf)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
return (*c->format == '{') ?
|
|
Packit |
352660 |
interpret_subexpr (c, pat, buf) :
|
|
Packit |
352660 |
FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
skip_subexpr (FcFormatContext *c);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
skip_percent (FcFormatContext *c)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (!expect_char (c, '%'))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
/* skip an optional width specifier */
|
|
Packit |
352660 |
if (strtol ((const char *) c->format, (char **) &c->format, 10))
|
|
Packit |
352660 |
{/* don't care */}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!expect_char (c, '{'))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
while(*c->format && *c->format != '}')
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
switch (*c->format)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
case '\\':
|
|
Packit |
352660 |
c->format++; /* skip over '\\' */
|
|
Packit |
352660 |
if (*c->format)
|
|
Packit |
352660 |
c->format++;
|
|
Packit |
352660 |
continue;
|
|
Packit |
352660 |
case '{':
|
|
Packit |
352660 |
if (!skip_subexpr (c))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
continue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
c->format++;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return expect_char (c, '}');
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
skip_expr (FcFormatContext *c)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
while(*c->format && *c->format != '}')
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
switch (*c->format)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
case '\\':
|
|
Packit |
352660 |
c->format++; /* skip over '\\' */
|
|
Packit |
352660 |
if (*c->format)
|
|
Packit |
352660 |
c->format++;
|
|
Packit |
352660 |
continue;
|
|
Packit |
352660 |
case '%':
|
|
Packit |
352660 |
if (!skip_percent (c))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
continue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
c->format++;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
skip_subexpr (FcFormatContext *c)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
return expect_char (c, '{') &&
|
|
Packit |
352660 |
skip_expr (c) &&
|
|
Packit |
352660 |
expect_char (c, '}');
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
maybe_skip_subexpr (FcFormatContext *c)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
return (*c->format == '{') ?
|
|
Packit |
352660 |
skip_subexpr (c) :
|
|
Packit |
352660 |
FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
interpret_filter_in (FcFormatContext *c,
|
|
Packit |
352660 |
FcPattern *pat,
|
|
Packit |
352660 |
FcStrBuf *buf)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcObjectSet *os;
|
|
Packit |
352660 |
FcPattern *subpat;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!expect_char (c, '+'))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
os = FcObjectSetCreate ();
|
|
Packit |
352660 |
if (!os)
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
do
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
/* XXX binding */
|
|
Packit |
352660 |
if (!read_word (c) ||
|
|
Packit |
352660 |
!FcObjectSetAdd (os, (const char *) c->word))
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcObjectSetDestroy (os);
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
while (consume_char (c, ','));
|
|
Packit |
352660 |
|
|
Packit |
352660 |
subpat = FcPatternFilter (pat, os);
|
|
Packit |
352660 |
FcObjectSetDestroy (os);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!subpat ||
|
|
Packit |
352660 |
!interpret_subexpr (c, subpat, buf))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
FcPatternDestroy (subpat);
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
interpret_filter_out (FcFormatContext *c,
|
|
Packit |
352660 |
FcPattern *pat,
|
|
Packit |
352660 |
FcStrBuf *buf)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcPattern *subpat;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!expect_char (c, '-'))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
subpat = FcPatternDuplicate (pat);
|
|
Packit |
352660 |
if (!subpat)
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
do
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (!read_word (c))
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcPatternDestroy (subpat);
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
FcPatternDel (subpat, (const char *) c->word);
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
while (consume_char (c, ','));
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!interpret_subexpr (c, subpat, buf))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
FcPatternDestroy (subpat);
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
interpret_cond (FcFormatContext *c,
|
|
Packit |
352660 |
FcPattern *pat,
|
|
Packit |
352660 |
FcStrBuf *buf)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcBool pass;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!expect_char (c, '?'))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
pass = FcTrue;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
do
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcBool negate;
|
|
Packit |
352660 |
FcValue v;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
negate = consume_char (c, '!');
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!read_word (c))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
pass = pass &&
|
|
Packit |
352660 |
(negate ^
|
|
Packit |
352660 |
(FcResultMatch ==
|
|
Packit |
352660 |
FcPatternGet (pat, (const char *) c->word, 0, &v)));
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
while (consume_char (c, ','));
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (pass)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (!interpret_subexpr (c, pat, buf) ||
|
|
Packit |
352660 |
!maybe_skip_subexpr (c))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (!skip_subexpr (c) ||
|
|
Packit |
352660 |
!maybe_interpret_subexpr (c, pat, buf))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
interpret_count (FcFormatContext *c,
|
|
Packit |
352660 |
FcPattern *pat,
|
|
Packit |
352660 |
FcStrBuf *buf)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
int count;
|
|
Packit |
352660 |
FcPatternIter iter;
|
|
Packit |
352660 |
FcChar8 buf_static[64];
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!expect_char (c, '#'))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!read_word (c))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
count = 0;
|
|
Packit |
352660 |
if (FcPatternFindIter (pat, &iter, (const char *) c->word))
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
count = FcPatternIterValueCount (pat, &iter);
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
snprintf ((char *) buf_static, sizeof (buf_static), "%d", count);
|
|
Packit |
352660 |
FcStrBufString (buf, buf_static);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
interpret_enumerate (FcFormatContext *c,
|
|
Packit |
352660 |
FcPattern *pat,
|
|
Packit |
352660 |
FcStrBuf *buf)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcObjectSet *os;
|
|
Packit |
352660 |
FcPattern *subpat;
|
|
Packit |
352660 |
const FcChar8 *format_save;
|
|
Packit |
352660 |
int idx;
|
|
Packit |
352660 |
FcBool ret, done;
|
|
Packit |
352660 |
FcStrList *lang_strs;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!expect_char (c, '[') ||
|
|
Packit |
352660 |
!expect_char (c, ']'))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
os = FcObjectSetCreate ();
|
|
Packit |
352660 |
if (!os)
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
ret = FcTrue;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
do
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (!read_word (c) ||
|
|
Packit |
352660 |
!FcObjectSetAdd (os, (const char *) c->word))
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcObjectSetDestroy (os);
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
while (consume_char (c, ','));
|
|
Packit |
352660 |
|
|
Packit |
352660 |
/* If we have one element and it's of type FcLangSet, we want
|
|
Packit |
352660 |
* to enumerate the languages in it. */
|
|
Packit |
352660 |
lang_strs = NULL;
|
|
Packit |
352660 |
if (os->nobject == 1)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcLangSet *langset;
|
|
Packit |
352660 |
if (FcResultMatch ==
|
|
Packit |
352660 |
FcPatternGetLangSet (pat, os->objects[0], 0, &langset))
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcStrSet *ss;
|
|
Packit |
352660 |
if (!(ss = FcLangSetGetLangs (langset)) ||
|
|
Packit |
352660 |
!(lang_strs = FcStrListCreate (ss)))
|
|
Packit |
352660 |
goto bail0;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
subpat = FcPatternDuplicate (pat);
|
|
Packit |
352660 |
if (!subpat)
|
|
Packit |
352660 |
goto bail0;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
format_save = c->format;
|
|
Packit |
352660 |
idx = 0;
|
|
Packit |
352660 |
do
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
int i;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
done = FcTrue;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (lang_strs)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcChar8 *lang;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
FcPatternDel (subpat, os->objects[0]);
|
|
Packit |
352660 |
if ((lang = FcStrListNext (lang_strs)))
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
/* XXX binding? */
|
|
Packit |
352660 |
FcPatternAddString (subpat, os->objects[0], lang);
|
|
Packit |
352660 |
done = FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
for (i = 0; i < os->nobject; i++)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcValue v;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
/* XXX this can be optimized by accessing valuelist linked lists
|
|
Packit |
352660 |
* directly and remembering where we were. Most (all) value lists
|
|
Packit |
352660 |
* in normal uses are pretty short though (language tags are
|
|
Packit |
352660 |
* stored as a LangSet, not separate values.). */
|
|
Packit |
352660 |
FcPatternDel (subpat, os->objects[i]);
|
|
Packit |
352660 |
if (FcResultMatch ==
|
|
Packit |
352660 |
FcPatternGet (pat, os->objects[i], idx, &v))
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
/* XXX binding */
|
|
Packit |
352660 |
FcPatternAdd (subpat, os->objects[i], v, FcFalse);
|
|
Packit |
352660 |
done = FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!done)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
c->format = format_save;
|
|
Packit |
352660 |
ret = interpret_subexpr (c, subpat, buf);
|
|
Packit |
352660 |
if (!ret)
|
|
Packit |
352660 |
goto bail;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
idx++;
|
|
Packit |
352660 |
} while (!done);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (c->format == format_save)
|
|
Packit |
352660 |
skip_subexpr (c);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
bail:
|
|
Packit |
352660 |
FcPatternDestroy (subpat);
|
|
Packit |
352660 |
bail0:
|
|
Packit |
352660 |
if (lang_strs)
|
|
Packit |
352660 |
FcStrListDone (lang_strs);
|
|
Packit |
352660 |
FcObjectSetDestroy (os);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return ret;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
interpret_simple (FcFormatContext *c,
|
|
Packit |
352660 |
FcPattern *pat,
|
|
Packit |
352660 |
FcStrBuf *buf)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcPatternIter iter;
|
|
Packit |
352660 |
FcBool add_colon = FcFalse;
|
|
Packit |
352660 |
FcBool add_elt_name = FcFalse;
|
|
Packit |
352660 |
int idx;
|
|
Packit |
352660 |
FcChar8 *else_string;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (consume_char (c, ':'))
|
|
Packit |
352660 |
add_colon = FcTrue;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!read_word (c))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
idx = -1;
|
|
Packit |
352660 |
if (consume_char (c, '['))
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
idx = strtol ((const char *) c->format, (char **) &c->format, 10);
|
|
Packit |
352660 |
if (idx < 0)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
message ("expected non-negative number at %d",
|
|
Packit |
352660 |
c->format-1 - c->format_orig + 1);
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
if (!expect_char (c, ']'))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (consume_char (c, '='))
|
|
Packit |
352660 |
add_elt_name = FcTrue;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
/* modifiers */
|
|
Packit |
352660 |
else_string = NULL;
|
|
Packit |
352660 |
if (consume_char (c, ':'))
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcChar8 *orig;
|
|
Packit |
352660 |
/* divert the c->word for now */
|
|
Packit |
352660 |
orig = c->word;
|
|
Packit |
352660 |
c->word = c->word + strlen ((const char *) c->word) + 1;
|
|
Packit |
352660 |
/* for now we just support 'default value' */
|
|
Packit |
352660 |
if (!expect_char (c, '-') ||
|
|
Packit |
352660 |
!read_chars (c, '|'))
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
c->word = orig;
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
else_string = c->word;
|
|
Packit |
352660 |
c->word = orig;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (FcPatternFindIter (pat, &iter, (const char *) c->word) || else_string)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcValueListPtr l = NULL;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (add_colon)
|
|
Packit |
352660 |
FcStrBufChar (buf, ':');
|
|
Packit |
352660 |
if (add_elt_name)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcStrBufString (buf, c->word);
|
|
Packit |
352660 |
FcStrBufChar (buf, '=');
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
l = FcPatternIterGetValues (pat, &iter);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (idx != -1)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
while (l && idx > 0)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
l = FcValueListNext(l);
|
|
Packit |
352660 |
idx--;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
if (l && idx == 0)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (!FcNameUnparseValue (buf, &l->value, '\0'))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
else goto notfound;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
else if (l)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcNameUnparseValueList (buf, l, '\0');
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
notfound:
|
|
Packit |
352660 |
if (else_string)
|
|
Packit |
352660 |
FcStrBufString (buf, else_string);
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
cescape (FcFormatContext *c FC_UNUSED,
|
|
Packit |
352660 |
const FcChar8 *str,
|
|
Packit |
352660 |
FcStrBuf *buf)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
/* XXX escape \n etc? */
|
|
Packit |
352660 |
|
|
Packit |
352660 |
while(*str)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
switch (*str)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
case '\\':
|
|
Packit |
352660 |
case '"':
|
|
Packit |
352660 |
FcStrBufChar (buf, '\\');
|
|
Packit |
352660 |
break;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
FcStrBufChar (buf, *str++);
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
shescape (FcFormatContext *c FC_UNUSED,
|
|
Packit |
352660 |
const FcChar8 *str,
|
|
Packit |
352660 |
FcStrBuf *buf)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcStrBufChar (buf, '\'');
|
|
Packit |
352660 |
while(*str)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (*str == '\'')
|
|
Packit |
352660 |
FcStrBufString (buf, (const FcChar8 *) "'\\''");
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
FcStrBufChar (buf, *str);
|
|
Packit |
352660 |
str++;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
FcStrBufChar (buf, '\'');
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
xmlescape (FcFormatContext *c FC_UNUSED,
|
|
Packit |
352660 |
const FcChar8 *str,
|
|
Packit |
352660 |
FcStrBuf *buf)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
/* XXX escape \n etc? */
|
|
Packit |
352660 |
|
|
Packit |
352660 |
while(*str)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
switch (*str)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
case '&': FcStrBufString (buf, (const FcChar8 *) "&"); break;
|
|
Packit |
352660 |
case '<': FcStrBufString (buf, (const FcChar8 *) "<"); break;
|
|
Packit |
352660 |
case '>': FcStrBufString (buf, (const FcChar8 *) ">"); break;
|
|
Packit |
352660 |
default: FcStrBufChar (buf, *str); break;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
str++;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
delete_chars (FcFormatContext *c,
|
|
Packit |
352660 |
const FcChar8 *str,
|
|
Packit |
352660 |
FcStrBuf *buf)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
/* XXX not UTF-8 aware */
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!expect_char (c, '(') ||
|
|
Packit |
352660 |
!read_chars (c, ')') ||
|
|
Packit |
352660 |
!expect_char (c, ')'))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
while(*str)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcChar8 *p;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
p = (FcChar8 *) strpbrk ((const char *) str, (const char *) c->word);
|
|
Packit |
352660 |
if (p)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcStrBufData (buf, str, p - str);
|
|
Packit |
352660 |
str = p + 1;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcStrBufString (buf, str);
|
|
Packit |
352660 |
break;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
escape_chars (FcFormatContext *c,
|
|
Packit |
352660 |
const FcChar8 *str,
|
|
Packit |
352660 |
FcStrBuf *buf)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
/* XXX not UTF-8 aware */
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!expect_char (c, '(') ||
|
|
Packit |
352660 |
!read_chars (c, ')') ||
|
|
Packit |
352660 |
!expect_char (c, ')'))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
while(*str)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcChar8 *p;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
p = (FcChar8 *) strpbrk ((const char *) str, (const char *) c->word);
|
|
Packit |
352660 |
if (p)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcStrBufData (buf, str, p - str);
|
|
Packit |
352660 |
FcStrBufChar (buf, c->word[0]);
|
|
Packit |
352660 |
FcStrBufChar (buf, *p);
|
|
Packit |
352660 |
str = p + 1;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcStrBufString (buf, str);
|
|
Packit |
352660 |
break;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
translate_chars (FcFormatContext *c,
|
|
Packit |
352660 |
const FcChar8 *str,
|
|
Packit |
352660 |
FcStrBuf *buf)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
char *from, *to, repeat;
|
|
Packit |
352660 |
int from_len, to_len;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
/* XXX not UTF-8 aware */
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!expect_char (c, '(') ||
|
|
Packit |
352660 |
!read_chars (c, ',') ||
|
|
Packit |
352660 |
!expect_char (c, ','))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
from = (char *) c->word;
|
|
Packit |
352660 |
from_len = strlen (from);
|
|
Packit |
352660 |
to = from + from_len + 1;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
/* hack: we temporarily divert c->word */
|
|
Packit |
352660 |
c->word = (FcChar8 *) to;
|
|
Packit |
352660 |
if (!read_chars (c, ')'))
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
c->word = (FcChar8 *) from;
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
c->word = (FcChar8 *) from;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
to_len = strlen (to);
|
|
Packit |
352660 |
repeat = to[to_len - 1];
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!expect_char (c, ')'))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
while(*str)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcChar8 *p;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
p = (FcChar8 *) strpbrk ((const char *) str, (const char *) from);
|
|
Packit |
352660 |
if (p)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
int i;
|
|
Packit |
352660 |
FcStrBufData (buf, str, p - str);
|
|
Packit |
352660 |
i = strchr (from, *p) - from;
|
|
Packit |
352660 |
FcStrBufChar (buf, i < to_len ? to[i] : repeat);
|
|
Packit |
352660 |
str = p + 1;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcStrBufString (buf, str);
|
|
Packit |
352660 |
break;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
interpret_convert (FcFormatContext *c,
|
|
Packit |
352660 |
FcStrBuf *buf,
|
|
Packit |
352660 |
int start)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
const FcChar8 *str;
|
|
Packit |
352660 |
FcChar8 *new_str;
|
|
Packit |
352660 |
FcStrBuf new_buf;
|
|
Packit |
352660 |
FcChar8 buf_static[8192];
|
|
Packit |
352660 |
FcBool ret;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!expect_char (c, '|') ||
|
|
Packit |
352660 |
!read_word (c))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
/* prepare the buffer */
|
|
Packit |
352660 |
FcStrBufChar (buf, '\0');
|
|
Packit |
352660 |
if (buf->failed)
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
str = buf->buf + start;
|
|
Packit |
352660 |
buf->len = start;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
/* try simple converters first */
|
|
Packit |
352660 |
if (0) { }
|
|
Packit |
352660 |
#define CONVERTER(name, func) \
|
|
Packit |
352660 |
else if (0 == strcmp ((const char *) c->word, name))\
|
|
Packit |
352660 |
do { new_str = func (str); ret = FcTrue; } while (0)
|
|
Packit |
352660 |
CONVERTER ("downcase", FcStrDowncase);
|
|
Packit |
352660 |
CONVERTER ("basename", FcStrBasename);
|
|
Packit |
352660 |
CONVERTER ("dirname", FcStrDirname);
|
|
Packit |
352660 |
#undef CONVERTER
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
ret = FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (ret)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
if (new_str)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcStrBufString (buf, new_str);
|
|
Packit |
352660 |
FcStrFree (new_str);
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
FcStrBufInit (&new_buf, buf_static, sizeof (buf_static));
|
|
Packit |
352660 |
|
|
Packit |
352660 |
/* now try our custom converters */
|
|
Packit |
352660 |
if (0) { }
|
|
Packit |
352660 |
#define CONVERTER(name, func) \
|
|
Packit |
352660 |
else if (0 == strcmp ((const char *) c->word, name))\
|
|
Packit |
352660 |
ret = func (c, str, &new_buf)
|
|
Packit |
352660 |
CONVERTER ("cescape", cescape);
|
|
Packit |
352660 |
CONVERTER ("shescape", shescape);
|
|
Packit |
352660 |
CONVERTER ("xmlescape", xmlescape);
|
|
Packit |
352660 |
CONVERTER ("delete", delete_chars);
|
|
Packit |
352660 |
CONVERTER ("escape", escape_chars);
|
|
Packit |
352660 |
CONVERTER ("translate", translate_chars);
|
|
Packit |
352660 |
#undef CONVERTER
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
ret = FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (ret)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcStrBufChar (&new_buf, '\0');
|
|
Packit |
352660 |
FcStrBufString (buf, new_buf.buf);
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
message ("unknown converter \"%s\"",
|
|
Packit |
352660 |
c->word);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
FcStrBufDestroy (&new_buf);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return ret;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
maybe_interpret_converts (FcFormatContext *c,
|
|
Packit |
352660 |
FcStrBuf *buf,
|
|
Packit |
352660 |
int start)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
while (*c->format == '|')
|
|
Packit |
352660 |
if (!interpret_convert (c, buf, start))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
align_to_width (FcStrBuf *buf,
|
|
Packit |
352660 |
int start,
|
|
Packit |
352660 |
int width)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
int len;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (buf->failed)
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
len = buf->len - start;
|
|
Packit |
352660 |
if (len < -width)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
/* left align */
|
|
Packit |
352660 |
while (len++ < -width)
|
|
Packit |
352660 |
FcStrBufChar (buf, ' ');
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
else if (len < width)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
int old_len;
|
|
Packit |
352660 |
old_len = len;
|
|
Packit |
352660 |
/* right align */
|
|
Packit |
352660 |
while (len++ < width)
|
|
Packit |
352660 |
FcStrBufChar (buf, ' ');
|
|
Packit |
352660 |
if (buf->failed)
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
len = old_len;
|
|
Packit |
352660 |
memmove (buf->buf + buf->len - len,
|
|
Packit |
352660 |
buf->buf + buf->len - width,
|
|
Packit |
352660 |
len);
|
|
Packit |
352660 |
memset (buf->buf + buf->len - width,
|
|
Packit |
352660 |
' ',
|
|
Packit |
352660 |
width - len);
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return !buf->failed;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
interpret_percent (FcFormatContext *c,
|
|
Packit |
352660 |
FcPattern *pat,
|
|
Packit |
352660 |
FcStrBuf *buf)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
int width, start;
|
|
Packit |
352660 |
FcBool ret;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!expect_char (c, '%'))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (consume_char (c, '%')) /* "%%" */
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcStrBufChar (buf, '%');
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
/* parse an optional width specifier */
|
|
Packit |
352660 |
width = strtol ((const char *) c->format, (char **) &c->format, 10);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!expect_char (c, '{'))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
start = buf->len;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
switch (*c->format) {
|
|
Packit |
352660 |
case '=': ret = interpret_builtin (c, pat, buf); break;
|
|
Packit |
352660 |
case '{': ret = interpret_subexpr (c, pat, buf); break;
|
|
Packit |
352660 |
case '+': ret = interpret_filter_in (c, pat, buf); break;
|
|
Packit |
352660 |
case '-': ret = interpret_filter_out (c, pat, buf); break;
|
|
Packit |
352660 |
case '?': ret = interpret_cond (c, pat, buf); break;
|
|
Packit |
352660 |
case '#': ret = interpret_count (c, pat, buf); break;
|
|
Packit |
352660 |
case '[': ret = interpret_enumerate (c, pat, buf); break;
|
|
Packit |
352660 |
default: ret = interpret_simple (c, pat, buf); break;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return ret &&
|
|
Packit |
352660 |
maybe_interpret_converts (c, buf, start) &&
|
|
Packit |
352660 |
align_to_width (buf, start, width) &&
|
|
Packit |
352660 |
expect_char (c, '}');
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
interpret_expr (FcFormatContext *c,
|
|
Packit |
352660 |
FcPattern *pat,
|
|
Packit |
352660 |
FcStrBuf *buf,
|
|
Packit |
352660 |
FcChar8 term)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
while (*c->format && *c->format != term)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
switch (*c->format)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
case '\\':
|
|
Packit |
352660 |
c->format++; /* skip over '\\' */
|
|
Packit |
352660 |
if (*c->format)
|
|
Packit |
352660 |
FcStrBufChar (buf, escaped_char (*c->format++));
|
|
Packit |
352660 |
continue;
|
|
Packit |
352660 |
case '%':
|
|
Packit |
352660 |
if (!interpret_percent (c, pat, buf))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
continue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
FcStrBufChar (buf, *c->format++);
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
return FcTrue;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
static FcBool
|
|
Packit |
352660 |
FcPatternFormatToBuf (FcPattern *pat,
|
|
Packit |
352660 |
const FcChar8 *format,
|
|
Packit |
352660 |
FcStrBuf *buf)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcFormatContext c;
|
|
Packit |
352660 |
FcChar8 word_static[1024];
|
|
Packit |
352660 |
FcBool ret;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!FcFormatContextInit (&c, format, word_static, sizeof (word_static)))
|
|
Packit |
352660 |
return FcFalse;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
ret = interpret_expr (&c, pat, buf, '\0');
|
|
Packit |
352660 |
|
|
Packit |
352660 |
FcFormatContextDone (&c);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
return ret;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
FcChar8 *
|
|
Packit |
352660 |
FcPatternFormat (FcPattern *pat,
|
|
Packit |
352660 |
const FcChar8 *format)
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcStrBuf buf;
|
|
Packit |
352660 |
FcChar8 buf_static[8192 - 1024];
|
|
Packit |
352660 |
FcPattern *alloced = NULL;
|
|
Packit |
352660 |
FcBool ret;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (!pat)
|
|
Packit |
352660 |
alloced = pat = FcPatternCreate ();
|
|
Packit |
352660 |
|
|
Packit |
352660 |
FcStrBufInit (&buf, buf_static, sizeof (buf_static));
|
|
Packit |
352660 |
|
|
Packit |
352660 |
ret = FcPatternFormatToBuf (pat, format, &buf;;
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (alloced)
|
|
Packit |
352660 |
FcPatternDestroy (alloced);
|
|
Packit |
352660 |
|
|
Packit |
352660 |
if (ret)
|
|
Packit |
352660 |
return FcStrBufDone (&buf;;
|
|
Packit |
352660 |
else
|
|
Packit |
352660 |
{
|
|
Packit |
352660 |
FcStrBufDestroy (&buf;;
|
|
Packit |
352660 |
return NULL;
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
}
|
|
Packit |
352660 |
|
|
Packit |
352660 |
#define __fcformat__
|
|
Packit |
352660 |
#include "fcaliastail.h"
|
|
Packit |
352660 |
#undef __fcformat__
|