Blame src/fcformat.c

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__