Home | History | Annotate | Line # | Download | only in src
      1 /*
      2  * fontconfig/src/fcxml.c
      3  *
      4  * Copyright  2002 Keith Packard
      5  *
      6  * Permission to use, copy, modify, distribute, and sell this software and its
      7  * documentation for any purpose is hereby granted without fee, provided that
      8  * the above copyright notice appear in all copies and that both that
      9  * copyright notice and this permission notice appear in supporting
     10  * documentation, and that the name of the author(s) not be used in
     11  * advertising or publicity pertaining to distribution of the software without
     12  * specific, written prior permission.  The authors make no
     13  * representations about the suitability of this software for any purpose.  It
     14  * is provided "as is" without express or implied warranty.
     15  *
     16  * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     18  * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     22  * PERFORMANCE OF THIS SOFTWARE.
     23  */
     24 
     25 #include "fcint.h"
     26 #include <string.h>
     27 #include <fcntl.h>
     28 #include <stdarg.h>
     29 
     30 #ifdef HAVE_DIRENT_H
     31 #include <dirent.h>
     32 #endif
     33 
     34 #ifdef ENABLE_LIBXML2
     35 
     36 #include <libxml/parser.h>
     37 
     38 #define XML_Char			xmlChar
     39 #define XML_Parser			xmlParserCtxtPtr
     40 #define XML_ParserFree			xmlFreeParserCtxt
     41 #define XML_GetCurrentLineNumber	xmlSAX2GetLineNumber
     42 #define XML_GetErrorCode		xmlCtxtGetLastError
     43 #define XML_ErrorString(Error)		(Error)->message
     44 
     45 #else /* ENABLE_LIBXML2 */
     46 
     47 #ifndef HAVE_XMLPARSE_H
     48 #define HAVE_XMLPARSE_H 0
     49 #endif
     50 
     51 #if HAVE_XMLPARSE_H
     52 #include <xmlparse.h>
     53 #else
     54 #include <expat.h>
     55 #endif
     56 
     57 #endif /* ENABLE_LIBXML2 */
     58 
     59 #ifdef _WIN32
     60 #include <mbstring.h>
     61 extern FcChar8 fontconfig_instprefix[];
     62 pfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
     63 pfnSHGetFolderPathA pSHGetFolderPathA = NULL;
     64 static void
     65 _ensureWin32GettersReady();
     66 #endif
     67 
     68 static FcChar8  *__fc_userdir = NULL;
     69 static FcChar8  *__fc_userconf = NULL;
     70 
     71 static void
     72 FcExprDestroy (FcExpr *e);
     73 static FcBool
     74 _FcConfigParse (FcConfig	*config,
     75 		const FcChar8	*name,
     76 		FcBool		complain,
     77 		FcBool		load);
     78 
     79 void
     80 FcTestDestroy (FcTest *test)
     81 {
     82     FcExprDestroy (test->expr);
     83     free (test);
     84 }
     85 
     86 void
     87 FcRuleDestroy (FcRule *rule)
     88 {
     89     FcRule *n = rule->next;
     90 
     91     switch (rule->type) {
     92     case FcRuleTest:
     93 	FcTestDestroy (rule->u.test);
     94 	break;
     95     case FcRuleEdit:
     96 	FcEditDestroy (rule->u.edit);
     97 	break;
     98     case FcRuleUnknown:
     99     default:
    100 	break;
    101     }
    102     free (rule);
    103     if (n)
    104 	FcRuleDestroy (n);
    105 }
    106 
    107 static FcExpr *
    108 FcExprCreateInteger (FcConfig *config, int i)
    109 {
    110     FcExpr *e = FcConfigAllocExpr (config);
    111     if (e)
    112     {
    113 	e->op = FcOpInteger;
    114 	e->u.ival = i;
    115     }
    116     return e;
    117 }
    118 
    119 static FcExpr *
    120 FcExprCreateDouble (FcConfig *config, double d)
    121 {
    122     FcExpr *e = FcConfigAllocExpr (config);
    123     if (e)
    124     {
    125 	e->op = FcOpDouble;
    126 	e->u.dval = d;
    127     }
    128     return e;
    129 }
    130 
    131 static FcExpr *
    132 FcExprCreateString (FcConfig *config, const FcChar8 *s)
    133 {
    134     FcExpr *e = FcConfigAllocExpr (config);
    135     if (e)
    136     {
    137 	e->op = FcOpString;
    138 	e->u.sval = FcStrdup (s);
    139     }
    140     return e;
    141 }
    142 
    143 static FcExprMatrix *
    144 FcExprMatrixCopyShallow (const FcExprMatrix *matrix)
    145 {
    146   FcExprMatrix *m = malloc (sizeof (FcExprMatrix));
    147   if (m)
    148   {
    149     *m = *matrix;
    150   }
    151   return m;
    152 }
    153 
    154 static void
    155 FcExprMatrixFreeShallow (FcExprMatrix *m)
    156 {
    157   if (!m)
    158     return;
    159 
    160   free (m);
    161 }
    162 
    163 static void
    164 FcExprMatrixFree (FcExprMatrix *m)
    165 {
    166   if (!m)
    167     return;
    168 
    169   FcExprDestroy (m->xx);
    170   FcExprDestroy (m->xy);
    171   FcExprDestroy (m->yx);
    172   FcExprDestroy (m->yy);
    173 
    174   free (m);
    175 }
    176 
    177 static FcExpr *
    178 FcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix)
    179 {
    180     FcExpr *e = FcConfigAllocExpr (config);
    181     if (e)
    182     {
    183 	e->op = FcOpMatrix;
    184 	e->u.mexpr = FcExprMatrixCopyShallow (matrix);
    185     }
    186     return e;
    187 }
    188 
    189 static FcExpr *
    190 FcExprCreateRange (FcConfig *config, FcRange *range)
    191 {
    192     FcExpr *e = FcConfigAllocExpr (config);
    193     if (e)
    194     {
    195 	e->op = FcOpRange;
    196 	e->u.rval = FcRangeCopy (range);
    197     }
    198     return e;
    199 }
    200 
    201 static FcExpr *
    202 FcExprCreateBool (FcConfig *config, FcBool b)
    203 {
    204     FcExpr *e = FcConfigAllocExpr (config);
    205     if (e)
    206     {
    207 	e->op = FcOpBool;
    208 	e->u.bval = b;
    209     }
    210     return e;
    211 }
    212 
    213 static FcExpr *
    214 FcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
    215 {
    216     FcExpr *e = FcConfigAllocExpr (config);
    217     if (e)
    218     {
    219 	e->op = FcOpCharSet;
    220 	e->u.cval = FcCharSetCopy (charset);
    221     }
    222     return e;
    223 }
    224 
    225 static FcExpr *
    226 FcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
    227 {
    228     FcExpr *e = FcConfigAllocExpr (config);
    229     if (e)
    230     {
    231 	e->op = FcOpLangSet;
    232 	e->u.lval = FcLangSetCopy (langset);
    233     }
    234     return e;
    235 }
    236 
    237 static FcExpr *
    238 FcExprCreateName (FcConfig *config, FcExprName name)
    239 {
    240     FcExpr *e = FcConfigAllocExpr (config);
    241     if (e)
    242     {
    243 	e->op = FcOpField;
    244 	e->u.name = name;
    245     }
    246     return e;
    247 }
    248 
    249 static FcExpr *
    250 FcExprCreateConst (FcConfig *config, const FcChar8 *constant)
    251 {
    252     FcExpr *e = FcConfigAllocExpr (config);
    253     if (e)
    254     {
    255 	e->op = FcOpConst;
    256 	e->u.constant = FcStrdup (constant);
    257     }
    258     return e;
    259 }
    260 
    261 static FcExpr *
    262 FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
    263 {
    264     FcExpr *e = FcConfigAllocExpr (config);
    265     if (e)
    266     {
    267 	e->op = op;
    268 	e->u.tree.left = left;
    269 	e->u.tree.right = right;
    270     }
    271     return e;
    272 }
    273 
    274 static void
    275 FcExprDestroy (FcExpr *e)
    276 {
    277     if (!e)
    278 	return;
    279     switch (FC_OP_GET_OP (e->op)) {
    280     case FcOpInteger:
    281 	break;
    282     case FcOpDouble:
    283 	break;
    284     case FcOpString:
    285 	FcFree (e->u.sval);
    286 	break;
    287     case FcOpMatrix:
    288 	FcExprMatrixFree (e->u.mexpr);
    289 	break;
    290     case FcOpRange:
    291 	FcRangeDestroy (e->u.rval);
    292 	break;
    293     case FcOpCharSet:
    294 	FcCharSetDestroy (e->u.cval);
    295 	break;
    296     case FcOpLangSet:
    297 	FcLangSetDestroy (e->u.lval);
    298 	break;
    299     case FcOpBool:
    300 	break;
    301     case FcOpField:
    302 	break;
    303     case FcOpConst:
    304 	FcFree (e->u.constant);
    305 	break;
    306     case FcOpAssign:
    307     case FcOpAssignReplace:
    308     case FcOpPrepend:
    309     case FcOpPrependFirst:
    310     case FcOpAppend:
    311     case FcOpAppendLast:
    312     case FcOpDelete:
    313     case FcOpDeleteAll:
    314 	break;
    315     case FcOpOr:
    316     case FcOpAnd:
    317     case FcOpEqual:
    318     case FcOpNotEqual:
    319     case FcOpLess:
    320     case FcOpLessEqual:
    321     case FcOpMore:
    322     case FcOpMoreEqual:
    323     case FcOpContains:
    324     case FcOpListing:
    325     case FcOpNotContains:
    326     case FcOpPlus:
    327     case FcOpMinus:
    328     case FcOpTimes:
    329     case FcOpDivide:
    330     case FcOpQuest:
    331     case FcOpComma:
    332 	FcExprDestroy (e->u.tree.right);
    333 	/* fall through */
    334     case FcOpNot:
    335     case FcOpFloor:
    336     case FcOpCeil:
    337     case FcOpRound:
    338     case FcOpTrunc:
    339 	FcExprDestroy (e->u.tree.left);
    340 	break;
    341     case FcOpNil:
    342     case FcOpInvalid:
    343 	break;
    344     }
    345 
    346     e->op = FcOpNil;
    347 }
    348 
    349 void
    350 FcEditDestroy (FcEdit *e)
    351 {
    352     if (e->expr)
    353 	FcExprDestroy (e->expr);
    354     free (e);
    355 }
    356 
    357 typedef enum _FcElement {
    358     FcElementNone,
    359     FcElementFontconfig,
    360     FcElementDir,
    361     FcElementCacheDir,
    362     FcElementCache,
    363     FcElementInclude,
    364     FcElementConfig,
    365     FcElementMatch,
    366     FcElementAlias,
    367     FcElementDescription,
    368     FcElementRemapDir,
    369     FcElementResetDirs,
    370 
    371     FcElementRescan,
    372 
    373     FcElementPrefer,
    374     FcElementAccept,
    375     FcElementDefault,
    376     FcElementFamily,
    377 
    378     FcElementSelectfont,
    379     FcElementAcceptfont,
    380     FcElementRejectfont,
    381     FcElementGlob,
    382     FcElementPattern,
    383     FcElementPatelt,
    384 
    385     FcElementTest,
    386     FcElementEdit,
    387     FcElementInt,
    388     FcElementDouble,
    389     FcElementString,
    390     FcElementMatrix,
    391     FcElementRange,
    392     FcElementBool,
    393     FcElementCharSet,
    394     FcElementLangSet,
    395     FcElementName,
    396     FcElementConst,
    397     FcElementOr,
    398     FcElementAnd,
    399     FcElementEq,
    400     FcElementNotEq,
    401     FcElementLess,
    402     FcElementLessEq,
    403     FcElementMore,
    404     FcElementMoreEq,
    405     FcElementContains,
    406     FcElementNotContains,
    407     FcElementPlus,
    408     FcElementMinus,
    409     FcElementTimes,
    410     FcElementDivide,
    411     FcElementNot,
    412     FcElementIf,
    413     FcElementFloor,
    414     FcElementCeil,
    415     FcElementRound,
    416     FcElementTrunc,
    417     FcElementUnknown
    418 } FcElement;
    419 
    420 static const struct {
    421     const char  name[16];
    422     FcElement   element;
    423 } fcElementMap[] = {
    424     { "fontconfig",	FcElementFontconfig },
    425     { "dir",		FcElementDir },
    426     { "cachedir",	FcElementCacheDir },
    427     { "cache",		FcElementCache },
    428     { "include",	FcElementInclude },
    429     { "config",		FcElementConfig },
    430     { "match",		FcElementMatch },
    431     { "alias",		FcElementAlias },
    432     { "description",	FcElementDescription },
    433     { "remap-dir",	FcElementRemapDir },
    434     { "reset-dirs",	FcElementResetDirs },
    435 
    436     { "rescan",		FcElementRescan },
    437 
    438     { "prefer",		FcElementPrefer },
    439     { "accept",		FcElementAccept },
    440     { "default",	FcElementDefault },
    441     { "family",		FcElementFamily },
    442 
    443     { "selectfont",	FcElementSelectfont },
    444     { "acceptfont",	FcElementAcceptfont },
    445     { "rejectfont",	FcElementRejectfont },
    446     { "glob",		FcElementGlob },
    447     { "pattern",	FcElementPattern },
    448     { "patelt",		FcElementPatelt },
    449 
    450     { "test",		FcElementTest },
    451     { "edit",		FcElementEdit },
    452     { "int",		FcElementInt },
    453     { "double",		FcElementDouble },
    454     { "string",		FcElementString },
    455     { "matrix",		FcElementMatrix },
    456     { "range",		FcElementRange },
    457     { "bool",		FcElementBool },
    458     { "charset",	FcElementCharSet },
    459     { "langset",	FcElementLangSet },
    460     { "name",		FcElementName },
    461     { "const",		FcElementConst },
    462     { "or",		FcElementOr },
    463     { "and",		FcElementAnd },
    464     { "eq",		FcElementEq },
    465     { "not_eq",		FcElementNotEq },
    466     { "less",		FcElementLess },
    467     { "less_eq",	FcElementLessEq },
    468     { "more",		FcElementMore },
    469     { "more_eq",	FcElementMoreEq },
    470     { "contains",	FcElementContains },
    471     { "not_contains",	FcElementNotContains },
    472     { "plus",		FcElementPlus },
    473     { "minus",		FcElementMinus },
    474     { "times",		FcElementTimes },
    475     { "divide",		FcElementDivide },
    476     { "not",		FcElementNot },
    477     { "if",		FcElementIf },
    478     { "floor",		FcElementFloor },
    479     { "ceil",		FcElementCeil },
    480     { "round",		FcElementRound },
    481     { "trunc",		FcElementTrunc },
    482 };
    483 #define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
    484 
    485 static const char *fcElementIgnoreName[16] = {
    486     "its:",
    487     NULL
    488 };
    489 
    490 static FcElement
    491 FcElementMap (const XML_Char *name)
    492 {
    493 
    494     int	    i;
    495     for (i = 0; i < NUM_ELEMENT_MAPS; i++)
    496 	if (!strcmp ((char *) name, fcElementMap[i].name))
    497 	    return fcElementMap[i].element;
    498     for (i = 0; fcElementIgnoreName[i] != NULL; i++)
    499 	if (!strncmp ((char *) name, fcElementIgnoreName[i], strlen (fcElementIgnoreName[i])))
    500 	    return FcElementNone;
    501     return FcElementUnknown;
    502 }
    503 
    504 static const char *
    505 FcElementReverseMap (FcElement e)
    506 {
    507     int i;
    508 
    509     for (i = 0; i < NUM_ELEMENT_MAPS; i++)
    510 	if (fcElementMap[i].element == e)
    511 	    return fcElementMap[i].name;
    512 
    513     return NULL;
    514 }
    515 
    516 
    517 typedef struct _FcPStack {
    518     struct _FcPStack   *prev;
    519     FcElement		element;
    520     FcChar8		**attr;
    521     FcStrBuf		str;
    522     FcChar8            *attr_buf_static[16];
    523 } FcPStack;
    524 
    525 typedef enum _FcVStackTag {
    526     FcVStackNone,
    527 
    528     FcVStackString,
    529     FcVStackFamily,
    530     FcVStackConstant,
    531     FcVStackGlob,
    532     FcVStackName,
    533     FcVStackPattern,
    534 
    535     FcVStackPrefer,
    536     FcVStackAccept,
    537     FcVStackDefault,
    538 
    539     FcVStackInteger,
    540     FcVStackDouble,
    541     FcVStackMatrix,
    542     FcVStackRange,
    543     FcVStackBool,
    544     FcVStackCharSet,
    545     FcVStackLangSet,
    546 
    547     FcVStackTest,
    548     FcVStackExpr,
    549     FcVStackEdit
    550 } FcVStackTag;
    551 
    552 typedef struct _FcVStack {
    553     struct _FcVStack	*prev;
    554     FcPStack		*pstack;	/* related parse element */
    555     FcVStackTag		tag;
    556     union {
    557 	FcChar8		*string;
    558 
    559 	int		integer;
    560 	double		_double;
    561 	FcExprMatrix	*matrix;
    562 	FcRange		*range;
    563 	FcBool		bool_;
    564 	FcCharSet	*charset;
    565 	FcLangSet	*langset;
    566 	FcExprName	name;
    567 
    568 	FcTest		*test;
    569 	FcQual		qual;
    570 	FcOp		op;
    571 	FcExpr		*expr;
    572 	FcEdit		*edit;
    573 
    574 	FcPattern	*pattern;
    575     } u;
    576 } FcVStack;
    577 
    578 typedef struct _FcConfigParse {
    579     FcPStack	    *pstack;
    580     FcVStack	    *vstack;
    581     FcBool	    error;
    582     const FcChar8   *name;
    583     FcConfig	    *config;
    584     FcRuleSet	    *ruleset;
    585     XML_Parser	    parser;
    586     unsigned int    pstack_static_used;
    587     FcPStack        pstack_static[8];
    588     unsigned int    vstack_static_used;
    589     FcVStack        vstack_static[64];
    590     FcBool          scanOnly;
    591 } FcConfigParse;
    592 
    593 typedef enum _FcConfigSeverity {
    594     FcSevereInfo, FcSevereWarning, FcSevereError
    595 } FcConfigSeverity;
    596 
    597 static void
    598 FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
    599 {
    600     const char	*s = "unknown";
    601     va_list	args;
    602 
    603     va_start (args, fmt);
    604 
    605     switch (severe) {
    606     case FcSevereInfo: s = "info"; break;
    607     case FcSevereWarning: s = "warning"; break;
    608     case FcSevereError: s = "error"; break;
    609     }
    610     if (parse)
    611     {
    612 	if (parse->name)
    613 	    fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
    614 		     parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
    615 	else
    616 	    fprintf (stderr, "Fontconfig %s: line %d: ", s,
    617 		     (int)XML_GetCurrentLineNumber (parse->parser));
    618 	if (severe >= FcSevereError)
    619 	    parse->error = FcTrue;
    620     }
    621     else
    622 	fprintf (stderr, "Fontconfig %s: ", s);
    623     vfprintf (stderr, fmt, args);
    624     fprintf (stderr, "\n");
    625     va_end (args);
    626 }
    627 
    628 
    629 static FcExpr *
    630 FcPopExpr (FcConfigParse *parse);
    631 
    632 
    633 static const char *
    634 FcTypeName (FcType type)
    635 {
    636     switch (type) {
    637     case FcTypeVoid:
    638 	return "void";
    639     case FcTypeInteger:
    640     case FcTypeDouble:
    641 	return "number";
    642     case FcTypeString:
    643 	return "string";
    644     case FcTypeBool:
    645 	return "bool";
    646     case FcTypeMatrix:
    647 	return "matrix";
    648     case FcTypeCharSet:
    649 	return "charset";
    650     case FcTypeFTFace:
    651 	return "FT_Face";
    652     case FcTypeLangSet:
    653 	return "langset";
    654     case FcTypeRange:
    655 	return "range";
    656     case FcTypeUnknown:
    657     default:
    658 	return "unknown";
    659     }
    660 }
    661 
    662 static void
    663 FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
    664 {
    665     if (value == FcTypeInteger)
    666 	value = FcTypeDouble;
    667     if (type == FcTypeInteger)
    668 	type = FcTypeDouble;
    669     if (value != type)
    670     {
    671 	if ((value == FcTypeLangSet && type == FcTypeString) ||
    672 	    (value == FcTypeString && type == FcTypeLangSet) ||
    673 	    (value == FcTypeDouble && type == FcTypeRange))
    674 	    return;
    675 	if (type ==  FcTypeUnknown)
    676 	    return;
    677 	/* It's perfectly fine to use user-define elements in expressions,
    678 	 * so don't warn in that case. */
    679 	if (value == FcTypeUnknown)
    680 	    return;
    681 	FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
    682 			 FcTypeName (value), FcTypeName (type));
    683     }
    684 }
    685 
    686 static void
    687 FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
    688 {
    689     const FcObjectType	*o;
    690     const FcConstant	*c;
    691 
    692     /* If parsing the expression failed, some nodes may be NULL */
    693     if (!expr)
    694 	return;
    695 
    696     switch (FC_OP_GET_OP (expr->op)) {
    697     case FcOpInteger:
    698     case FcOpDouble:
    699 	FcTypecheckValue (parse, FcTypeDouble, type);
    700 	break;
    701     case FcOpString:
    702 	FcTypecheckValue (parse, FcTypeString, type);
    703 	break;
    704     case FcOpMatrix:
    705 	FcTypecheckValue (parse, FcTypeMatrix, type);
    706 	break;
    707     case FcOpBool:
    708 	FcTypecheckValue (parse, FcTypeBool, type);
    709 	break;
    710     case FcOpCharSet:
    711 	FcTypecheckValue (parse, FcTypeCharSet, type);
    712 	break;
    713     case FcOpLangSet:
    714 	FcTypecheckValue (parse, FcTypeLangSet, type);
    715 	break;
    716     case FcOpRange:
    717 	FcTypecheckValue (parse, FcTypeRange, type);
    718 	break;
    719     case FcOpNil:
    720 	break;
    721     case FcOpField:
    722 	o = FcNameGetObjectType (FcObjectName (expr->u.name.object));
    723 	if (o)
    724 	    FcTypecheckValue (parse, o->type, type);
    725 	break;
    726     case FcOpConst:
    727 	c = FcNameGetConstant (expr->u.constant);
    728 	if (c)
    729 	{
    730 	    o = FcNameGetObjectType (c->object);
    731 	    if (o)
    732 		FcTypecheckValue (parse, o->type, type);
    733 	}
    734 	else
    735             FcConfigMessage (parse, FcSevereWarning,
    736                              "invalid constant used : %s",
    737                              expr->u.constant);
    738 	break;
    739     case FcOpQuest:
    740 	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
    741 	FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
    742 	FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
    743 	break;
    744     case FcOpAssign:
    745     case FcOpAssignReplace:
    746 	break;
    747     case FcOpEqual:
    748     case FcOpNotEqual:
    749     case FcOpLess:
    750     case FcOpLessEqual:
    751     case FcOpMore:
    752     case FcOpMoreEqual:
    753     case FcOpContains:
    754     case FcOpNotContains:
    755     case FcOpListing:
    756 	FcTypecheckValue (parse, FcTypeBool, type);
    757 	break;
    758     case FcOpComma:
    759     case FcOpOr:
    760     case FcOpAnd:
    761     case FcOpPlus:
    762     case FcOpMinus:
    763     case FcOpTimes:
    764     case FcOpDivide:
    765 	FcTypecheckExpr (parse, expr->u.tree.left, type);
    766 	FcTypecheckExpr (parse, expr->u.tree.right, type);
    767 	break;
    768     case FcOpNot:
    769 	FcTypecheckValue (parse, FcTypeBool, type);
    770 	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
    771 	break;
    772     case FcOpFloor:
    773     case FcOpCeil:
    774     case FcOpRound:
    775     case FcOpTrunc:
    776 	FcTypecheckValue (parse, FcTypeDouble, type);
    777 	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
    778 	break;
    779     default:
    780 	break;
    781     }
    782 }
    783 
    784 static FcTest *
    785 FcTestCreate (FcConfigParse *parse,
    786 	      FcMatchKind   kind,
    787 	      FcQual	    qual,
    788 	      const FcChar8 *field,
    789 	      unsigned int  compare,
    790 	      FcExpr	    *expr)
    791 {
    792     FcTest	*test = (FcTest *) malloc (sizeof (FcTest));
    793 
    794     if (test)
    795     {
    796 	const FcObjectType	*o;
    797 
    798 	test->kind = kind;
    799 	test->qual = qual;
    800 	test->object = FcObjectFromName ((const char *) field);
    801 	test->op = compare;
    802 	test->expr = expr;
    803 	o = FcNameGetObjectType (FcObjectName (test->object));
    804 	if (o)
    805 	    FcTypecheckExpr (parse, expr, o->type);
    806     }
    807     return test;
    808 }
    809 
    810 static FcEdit *
    811 FcEditCreate (FcConfigParse	*parse,
    812 	      FcObject		object,
    813 	      FcOp		op,
    814 	      FcExpr		*expr,
    815 	      FcValueBinding	binding)
    816 {
    817     FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
    818 
    819     if (e)
    820     {
    821 	const FcObjectType	*o;
    822 
    823 	e->object = object;
    824 	e->op = op;
    825 	e->expr = expr;
    826 	e->binding = binding;
    827 	o = FcNameGetObjectType (FcObjectName (e->object));
    828 	if (o)
    829 	    FcTypecheckExpr (parse, expr, o->type);
    830     }
    831     return e;
    832 }
    833 
    834 static FcRule *
    835 FcRuleCreate (FcRuleType type,
    836 	      void       *p)
    837 {
    838     FcRule *r = (FcRule *) malloc (sizeof (FcRule));
    839 
    840     if (!r)
    841 	return NULL;
    842 
    843     r->next = NULL;
    844     r->type = type;
    845     switch (type)
    846     {
    847     case FcRuleTest:
    848 	r->u.test = (FcTest *) p;
    849 	break;
    850     case FcRuleEdit:
    851 	r->u.edit = (FcEdit *) p;
    852 	break;
    853     case FcRuleUnknown:
    854     default:
    855 	free (r);
    856 	r = NULL;
    857 	break;
    858     }
    859 
    860     return r;
    861 }
    862 
    863 static FcVStack *
    864 FcVStackCreateAndPush (FcConfigParse *parse)
    865 {
    866     FcVStack    *new;
    867 
    868     if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
    869 	new = &parse->vstack_static[parse->vstack_static_used++];
    870     else
    871     {
    872 	new = malloc (sizeof (FcVStack));
    873 	if (!new)
    874 	    return 0;
    875     }
    876     new->tag = FcVStackNone;
    877     new->prev = 0;
    878 
    879     new->prev = parse->vstack;
    880     new->pstack = parse->pstack ? parse->pstack->prev : 0;
    881     parse->vstack = new;
    882 
    883     return new;
    884 }
    885 
    886 static FcBool
    887 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
    888 {
    889     FcVStack    *vstack = FcVStackCreateAndPush (parse);
    890     if (!vstack)
    891 	return FcFalse;
    892     vstack->u.string = string;
    893     vstack->tag = tag;
    894     return FcTrue;
    895 }
    896 
    897 static FcBool
    898 FcVStackPushInteger (FcConfigParse *parse, int integer)
    899 {
    900     FcVStack    *vstack = FcVStackCreateAndPush (parse);
    901     if (!vstack)
    902 	return FcFalse;
    903     vstack->u.integer = integer;
    904     vstack->tag = FcVStackInteger;
    905     return FcTrue;
    906 }
    907 
    908 static FcBool
    909 FcVStackPushDouble (FcConfigParse *parse, double _double)
    910 {
    911     FcVStack    *vstack = FcVStackCreateAndPush (parse);
    912     if (!vstack)
    913 	return FcFalse;
    914     vstack->u._double = _double;
    915     vstack->tag = FcVStackDouble;
    916     return FcTrue;
    917 }
    918 
    919 static FcBool
    920 FcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix)
    921 {
    922     FcVStack    *vstack;
    923     vstack = FcVStackCreateAndPush (parse);
    924     if (!vstack)
    925 	return FcFalse;
    926     vstack->u.matrix = FcExprMatrixCopyShallow (matrix);
    927     vstack->tag = FcVStackMatrix;
    928     return FcTrue;
    929 }
    930 
    931 static FcBool
    932 FcVStackPushRange (FcConfigParse *parse, FcRange *range)
    933 {
    934     FcVStack 	*vstack = FcVStackCreateAndPush (parse);
    935     if (!vstack)
    936 	return FcFalse;
    937     vstack->u.range = range;
    938     vstack->tag = FcVStackRange;
    939     return FcTrue;
    940 }
    941 
    942 static FcBool
    943 FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
    944 {
    945     FcVStack    *vstack = FcVStackCreateAndPush (parse);
    946     if (!vstack)
    947 	return FcFalse;
    948     vstack->u.bool_ = bool_;
    949     vstack->tag = FcVStackBool;
    950     return FcTrue;
    951 }
    952 
    953 static FcBool
    954 FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
    955 {
    956     FcVStack	*vstack;
    957     if (!charset)
    958 	return FcFalse;
    959     vstack = FcVStackCreateAndPush (parse);
    960     if (!vstack)
    961 	return FcFalse;
    962     vstack->u.charset = charset;
    963     vstack->tag = FcVStackCharSet;
    964     return FcTrue;
    965 }
    966 
    967 static FcBool
    968 FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
    969 {
    970     FcVStack	*vstack;
    971     if (!langset)
    972 	return FcFalse;
    973     vstack = FcVStackCreateAndPush (parse);
    974     if (!vstack)
    975 	return FcFalse;
    976     vstack->u.langset = langset;
    977     vstack->tag = FcVStackLangSet;
    978     return FcTrue;
    979 }
    980 
    981 static FcBool
    982 FcVStackPushName (FcConfigParse *parse, FcMatchKind kind, FcObject object)
    983 {
    984     FcVStack    *vstack = FcVStackCreateAndPush (parse);
    985     if (!vstack)
    986 	return FcFalse;
    987     vstack->u.name.object = object;
    988     vstack->u.name.kind = kind;
    989     vstack->tag = FcVStackName;
    990     return FcTrue;
    991 }
    992 
    993 static FcBool
    994 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
    995 {
    996     FcVStack    *vstack = FcVStackCreateAndPush (parse);
    997     if (!vstack)
    998 	return FcFalse;
    999     vstack->u.test = test;
   1000     vstack->tag = FcVStackTest;
   1001     return FcTrue;
   1002 }
   1003 
   1004 static FcBool
   1005 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
   1006 {
   1007     FcVStack    *vstack = FcVStackCreateAndPush (parse);
   1008     if (!vstack)
   1009 	return FcFalse;
   1010     vstack->u.expr = expr;
   1011     vstack->tag = tag;
   1012     return FcTrue;
   1013 }
   1014 
   1015 static FcBool
   1016 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
   1017 {
   1018     FcVStack    *vstack = FcVStackCreateAndPush (parse);
   1019     if (!vstack)
   1020 	return FcFalse;
   1021     vstack->u.edit = edit;
   1022     vstack->tag = FcVStackEdit;
   1023     return FcTrue;
   1024 }
   1025 
   1026 static FcBool
   1027 FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
   1028 {
   1029     FcVStack    *vstack = FcVStackCreateAndPush (parse);
   1030     if (!vstack)
   1031 	return FcFalse;
   1032     vstack->u.pattern = pattern;
   1033     vstack->tag = FcVStackPattern;
   1034     return FcTrue;
   1035 }
   1036 
   1037 static FcVStack *
   1038 FcVStackFetch (FcConfigParse *parse, int off)
   1039 {
   1040     FcVStack    *vstack;
   1041 
   1042     for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
   1043     return vstack;
   1044 }
   1045 
   1046 static FcVStack *
   1047 FcVStackPeek (FcConfigParse *parse)
   1048 {
   1049     FcVStack	*vstack = parse->vstack;
   1050 
   1051     return vstack && vstack->pstack == parse->pstack ? vstack : 0;
   1052 }
   1053 
   1054 static void
   1055 FcVStackPopAndDestroy (FcConfigParse *parse)
   1056 {
   1057     FcVStack	*vstack = parse->vstack;
   1058 
   1059     if (!vstack || vstack->pstack != parse->pstack)
   1060 	return;
   1061 
   1062     parse->vstack = vstack->prev;
   1063 
   1064     switch (vstack->tag) {
   1065     case FcVStackNone:
   1066 	break;
   1067     case FcVStackName:
   1068 	break;
   1069     case FcVStackFamily:
   1070 	break;
   1071     case FcVStackString:
   1072     case FcVStackConstant:
   1073     case FcVStackGlob:
   1074 	FcStrFree (vstack->u.string);
   1075 	break;
   1076     case FcVStackPattern:
   1077 	FcPatternDestroy (vstack->u.pattern);
   1078 	break;
   1079     case FcVStackInteger:
   1080     case FcVStackDouble:
   1081 	break;
   1082     case FcVStackMatrix:
   1083 	FcExprMatrixFreeShallow (vstack->u.matrix);
   1084 	break;
   1085     case FcVStackBool:
   1086 	break;
   1087     case FcVStackRange:
   1088 	FcRangeDestroy (vstack->u.range);
   1089 	break;
   1090     case FcVStackCharSet:
   1091 	FcCharSetDestroy (vstack->u.charset);
   1092 	break;
   1093     case FcVStackLangSet:
   1094 	FcLangSetDestroy (vstack->u.langset);
   1095 	break;
   1096     case FcVStackTest:
   1097 	FcTestDestroy (vstack->u.test);
   1098 	break;
   1099     case FcVStackExpr:
   1100     case FcVStackPrefer:
   1101     case FcVStackAccept:
   1102     case FcVStackDefault:
   1103 	FcExprDestroy (vstack->u.expr);
   1104 	break;
   1105     case FcVStackEdit:
   1106 	FcEditDestroy (vstack->u.edit);
   1107 	break;
   1108     }
   1109 
   1110     if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
   1111 	parse->vstack_static_used--;
   1112     else
   1113 	free (vstack);
   1114 }
   1115 
   1116 static void
   1117 FcVStackClear (FcConfigParse *parse)
   1118 {
   1119     while (FcVStackPeek (parse))
   1120 	FcVStackPopAndDestroy (parse);
   1121 }
   1122 
   1123 static int
   1124 FcVStackElements (FcConfigParse *parse)
   1125 {
   1126     int		h = 0;
   1127     FcVStack	*vstack = parse->vstack;
   1128     while (vstack && vstack->pstack == parse->pstack)
   1129     {
   1130 	h++;
   1131 	vstack = vstack->prev;
   1132     }
   1133     return h;
   1134 }
   1135 
   1136 static FcChar8 **
   1137 FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
   1138 {
   1139     int		slen;
   1140     int		i;
   1141     FcChar8	**new;
   1142     FcChar8	*s;
   1143 
   1144     if (!attr)
   1145 	return 0;
   1146     slen = 0;
   1147     for (i = 0; attr[i]; i++)
   1148 	slen += strlen ((char *) attr[i]) + 1;
   1149     if (i == 0)
   1150 	return 0;
   1151     slen += (i + 1) * sizeof (FcChar8 *);
   1152     if (slen <= size_bytes)
   1153 	new = buf;
   1154     else
   1155     {
   1156 	new = malloc (slen);
   1157 	if (!new)
   1158 	{
   1159 	    FcConfigMessage (0, FcSevereError, "out of memory");
   1160 	    return 0;
   1161 	}
   1162     }
   1163     s = (FcChar8 *) (new + (i + 1));
   1164     for (i = 0; attr[i]; i++)
   1165     {
   1166 	new[i] = s;
   1167 	strcpy ((char *) s, (char *) attr[i]);
   1168 	s += strlen ((char *) s) + 1;
   1169     }
   1170     new[i] = 0;
   1171     return new;
   1172 }
   1173 
   1174 static FcBool
   1175 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
   1176 {
   1177     FcPStack   *new;
   1178 
   1179     if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
   1180 	new = &parse->pstack_static[parse->pstack_static_used++];
   1181     else
   1182     {
   1183 	new = malloc (sizeof (FcPStack));
   1184 	if (!new)
   1185 	    return FcFalse;
   1186     }
   1187 
   1188     new->prev = parse->pstack;
   1189     new->element = element;
   1190     new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
   1191     FcStrBufInit (&new->str, 0, 0);
   1192     parse->pstack = new;
   1193     return FcTrue;
   1194 }
   1195 
   1196 static FcBool
   1197 FcPStackPop (FcConfigParse *parse)
   1198 {
   1199     FcPStack   *old;
   1200 
   1201     if (!parse->pstack)
   1202     {
   1203 	FcConfigMessage (parse, FcSevereError, "mismatching element");
   1204 	return FcFalse;
   1205     }
   1206 
   1207     /* Don't check the attributes for FcElementNone */
   1208     if (parse->pstack->element != FcElementNone &&
   1209 	parse->pstack->attr)
   1210     {
   1211 	/* Warn about unused attrs. */
   1212 	FcChar8 **attrs = parse->pstack->attr;
   1213 	while (*attrs)
   1214 	{
   1215 	    if (attrs[0][0])
   1216 	    {
   1217 		FcConfigMessage (parse, FcSevereWarning, "invalid attribute '%s'", attrs[0]);
   1218 	    }
   1219 	    attrs += 2;
   1220 	}
   1221     }
   1222 
   1223     FcVStackClear (parse);
   1224     old = parse->pstack;
   1225     parse->pstack = old->prev;
   1226     FcStrBufDestroy (&old->str);
   1227 
   1228     if (old->attr && old->attr != old->attr_buf_static)
   1229 	free (old->attr);
   1230 
   1231     if (old == &parse->pstack_static[parse->pstack_static_used - 1])
   1232 	parse->pstack_static_used--;
   1233     else
   1234 	free (old);
   1235     return FcTrue;
   1236 }
   1237 
   1238 static FcBool
   1239 FcConfigParseInit (FcConfigParse	*parse,
   1240 		   const FcChar8	*name,
   1241 		   FcConfig		*config,
   1242 		   XML_Parser		parser,
   1243 		   FcBool		enabled)
   1244 {
   1245     parse->pstack = 0;
   1246     parse->pstack_static_used = 0;
   1247     parse->vstack = 0;
   1248     parse->vstack_static_used = 0;
   1249     parse->error = FcFalse;
   1250     parse->name = name;
   1251     parse->config = config;
   1252     parse->ruleset = FcRuleSetCreate (name);
   1253     parse->parser = parser;
   1254     parse->scanOnly = !enabled;
   1255     FcRuleSetEnable (parse->ruleset, enabled);
   1256 
   1257     return FcTrue;
   1258 }
   1259 
   1260 static void
   1261 FcConfigCleanup (FcConfigParse	*parse)
   1262 {
   1263     while (parse->pstack)
   1264 	FcPStackPop (parse);
   1265     FcRuleSetDestroy (parse->ruleset);
   1266     parse->ruleset = NULL;
   1267 }
   1268 
   1269 static const FcChar8 *
   1270 FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
   1271 {
   1272     FcChar8 **attrs;
   1273     if (!parse->pstack)
   1274 	return 0;
   1275 
   1276     attrs = parse->pstack->attr;
   1277     if (!attrs)
   1278         return 0;
   1279 
   1280     while (*attrs)
   1281     {
   1282 	if (!strcmp ((char *) *attrs, attr))
   1283 	{
   1284 	    attrs[0][0] = '\0'; /* Mark as used. */
   1285 	    return attrs[1];
   1286 	}
   1287 	attrs += 2;
   1288     }
   1289     return 0;
   1290 }
   1291 
   1292 static FcStrSet *
   1293 _get_real_paths_from_prefix(FcConfigParse *parse, const FcChar8 *path, const FcChar8 *prefix)
   1294 {
   1295 #ifdef _WIN32
   1296     FcChar8 buffer[1000] = { 0 };
   1297 #endif
   1298     FcChar8 *parent = NULL, *retval = NULL;
   1299     FcStrSet *e = NULL;
   1300 
   1301     if (prefix)
   1302     {
   1303 	if (FcStrCmp (prefix, (const FcChar8 *) "xdg") == 0)
   1304 	{
   1305 	    parent = FcConfigXdgDataHome ();
   1306 	    if (!parent)
   1307 	    {
   1308 		/* Home directory might be disabled */
   1309 		return NULL;
   1310 	    }
   1311 	    e = FcConfigXdgDataDirs ();
   1312 	    if (!e)
   1313 	    {
   1314 		FcStrFree (parent);
   1315 		return NULL;
   1316 	    }
   1317 	}
   1318 	else if (FcStrCmp (prefix, (const FcChar8 *) "default") == 0 ||
   1319 		 FcStrCmp (prefix, (const FcChar8 *) "cwd") == 0)
   1320 	{
   1321 	    /* Nothing to do */
   1322 	}
   1323 	else if (FcStrCmp (prefix, (const FcChar8 *) "relative") == 0)
   1324 	{
   1325 	    FcChar8 *p = FcStrRealPath (parse->name);
   1326 
   1327 	    if (!p)
   1328 		return NULL;
   1329 	    parent = FcStrDirname (p);
   1330 	    if (!parent)
   1331 	    {
   1332 		free (p);
   1333 		return NULL;
   1334 	    }
   1335 	}
   1336     }
   1337 #ifndef _WIN32
   1338     /* For Win32, check this later for dealing with special cases */
   1339     else
   1340     {
   1341 	if (!FcStrIsAbsoluteFilename (path) && path[0] != '~')
   1342 	    FcConfigMessage (parse, FcSevereWarning, "Use of ambiguous path in <%s> element. please add prefix=\"cwd\" if current behavior is desired.", FcElementReverseMap (parse->pstack->element));
   1343     }
   1344 #else
   1345     if (strcmp ((const char *) path, "CUSTOMFONTDIR") == 0)
   1346     {
   1347 	FcChar8 *p;
   1348 	path = buffer;
   1349 	if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
   1350 	{
   1351 	    FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
   1352 	    return NULL;
   1353 	}
   1354 	/*
   1355 	 * Must use the multi-byte aware function to search
   1356 	 * for backslash because East Asian double-byte code
   1357 	 * pages have characters with backslash as the second
   1358 	 * byte.
   1359 	 */
   1360 	p = _mbsrchr (path, '\\');
   1361 	if (p) *p = '\0';
   1362 	strcat ((char *) path, "\\fonts");
   1363     }
   1364     else if (strcmp ((const char *) path, "APPSHAREFONTDIR") == 0)
   1365     {
   1366 	FcChar8 *p;
   1367 	path = buffer;
   1368 	if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
   1369 	{
   1370 	    FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
   1371 	    return NULL;
   1372 	}
   1373 	p = _mbsrchr (path, '\\');
   1374 	if (p) *p = '\0';
   1375 	strcat ((char *) path, "\\..\\share\\fonts");
   1376     }
   1377     else if (strcmp ((const char *) path, "WINDOWSUSERFONTDIR") == 0)
   1378     {
   1379         path = buffer;
   1380         if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, (char *) buffer))))
   1381         {
   1382             FcConfigMessage(parse, FcSevereError, "SHGetFolderPathA failed");
   1383             return NULL;
   1384         }
   1385         strcat((char *) path, "\\Microsoft\\Windows\\Fonts");
   1386     }
   1387     else if (strcmp ((const char *) path, "WINDOWSFONTDIR") == 0)
   1388     {
   1389 	int rc;
   1390 	path = buffer;
   1391 	_ensureWin32GettersReady();
   1392 	rc = pGetSystemWindowsDirectory ((LPSTR) buffer, sizeof (buffer) - 20);
   1393 	if (rc == 0 || rc > sizeof (buffer) - 20)
   1394 	{
   1395 	    FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
   1396 	    return NULL;
   1397 	}
   1398 	if (path [strlen ((const char *) path) - 1] != '\\')
   1399 	    strcat ((char *) path, "\\");
   1400 	strcat ((char *) path, "fonts");
   1401     }
   1402     else
   1403     {
   1404 	if (!prefix)
   1405 	{
   1406 	    if (!FcStrIsAbsoluteFilename (path) && path[0] != '~')
   1407 		FcConfigMessage (parse, FcSevereWarning, "Use of ambiguous path in <%s> element. please add prefix=\"cwd\" if current behavior is desired.", FcElementReverseMap (parse->pstack->element));
   1408 	}
   1409     }
   1410 #endif
   1411     if (parent)
   1412     {
   1413 	retval = FcStrBuildFilename (parent, path, NULL);
   1414 	FcStrFree (parent);
   1415     }
   1416     else
   1417     {
   1418 	retval = FcStrdup (path);
   1419     }
   1420     if (!e)
   1421 	e = FcStrSetCreate ();
   1422     else
   1423     {
   1424 	FcChar8 *s;
   1425 	int i;
   1426 
   1427 	for (i = 0; i < e->num; i++)
   1428 	{
   1429 	    s = FcStrBuildFilename (e->strs[i], path, NULL);
   1430 	    FcStrFree (e->strs[i]);
   1431 	    e->strs[i] = s;
   1432 	}
   1433     }
   1434     if (!FcStrSetInsert (e, retval, 0))
   1435     {
   1436 	FcStrSetDestroy (e);
   1437 	e = NULL;
   1438     }
   1439     FcStrFree (retval);
   1440 
   1441     return e;
   1442 }
   1443 
   1444 static void
   1445 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
   1446 {
   1447     FcConfigParse   *parse = userData;
   1448     FcElement	    element;
   1449 
   1450     element = FcElementMap (name);
   1451     if (element == FcElementUnknown)
   1452 	FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
   1453 
   1454     if (!FcPStackPush (parse, element, attr))
   1455     {
   1456 	FcConfigMessage (parse, FcSevereError, "out of memory");
   1457 	return;
   1458     }
   1459     return;
   1460 }
   1461 
   1462 static void
   1463 FcParseRescan (FcConfigParse *parse)
   1464 {
   1465     int	    n = FcVStackElements (parse);
   1466     while (n-- > 0)
   1467     {
   1468 	FcVStack    *v = FcVStackFetch (parse, n);
   1469 	if (v->tag != FcVStackInteger)
   1470 	    FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
   1471 	else
   1472 	    parse->config->rescanInterval = v->u.integer;
   1473     }
   1474 }
   1475 
   1476 static void
   1477 FcParseInt (FcConfigParse *parse)
   1478 {
   1479     FcChar8 *s, *end;
   1480     int	    l;
   1481 
   1482     if (!parse->pstack)
   1483 	return;
   1484     s = FcStrBufDoneStatic (&parse->pstack->str);
   1485     if (!s)
   1486     {
   1487 	FcConfigMessage (parse, FcSevereError, "out of memory");
   1488 	return;
   1489     }
   1490     end = 0;
   1491     l = (int) strtol ((char *) s, (char **)&end, 0);
   1492     if (end != s + strlen ((char *) s))
   1493 	FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
   1494     else
   1495 	FcVStackPushInteger (parse, l);
   1496     FcStrBufDestroy (&parse->pstack->str);
   1497 }
   1498 
   1499 /*
   1500  * idea copied from glib g_ascii_strtod with
   1501  * permission of the author (Alexander Larsson)
   1502  */
   1503 
   1504 #include <locale.h>
   1505 
   1506 static double
   1507 FcStrtod (char *s, char **end)
   1508 {
   1509 #ifndef __BIONIC__
   1510     struct lconv    *locale_data;
   1511 #endif
   1512     const char	    *decimal_point;
   1513     int		    dlen;
   1514     char	    *dot;
   1515     double	    v;
   1516 
   1517     /*
   1518      * Have to swap the decimal point to match the current locale
   1519      * if that locale doesn't use 0x2e
   1520      */
   1521 #ifndef __BIONIC__
   1522     locale_data = localeconv ();
   1523     decimal_point = locale_data->decimal_point;
   1524     dlen = strlen (decimal_point);
   1525 #else
   1526     decimal_point = ".";
   1527     dlen = 1;
   1528 #endif
   1529 
   1530     if ((dot = strchr (s, 0x2e)) &&
   1531 	(decimal_point[0] != 0x2e ||
   1532 	 decimal_point[1] != 0))
   1533     {
   1534 	char	buf[128];
   1535 	int	slen = strlen (s);
   1536 
   1537 	if (slen + dlen > (int) sizeof (buf))
   1538 	{
   1539 	    if (end)
   1540 		*end = s;
   1541 	    v = 0;
   1542 	}
   1543 	else
   1544 	{
   1545 	    char	*buf_end;
   1546 	    /* mantissa */
   1547 	    strncpy (buf, s, dot - s);
   1548 	    /* decimal point */
   1549 	    strcpy (buf + (dot - s), decimal_point);
   1550 	    /* rest of number */
   1551 	    strcpy (buf + (dot - s) + dlen, dot + 1);
   1552 	    buf_end = 0;
   1553 	    v = strtod (buf, &buf_end);
   1554 	    if (buf_end) {
   1555 		buf_end = s + (buf_end - buf);
   1556 		if (buf_end > dot)
   1557 		    buf_end -= dlen - 1;
   1558 	    }
   1559 	    if (end)
   1560 		*end = buf_end;
   1561 	}
   1562     }
   1563     else
   1564 	v = strtod (s, end);
   1565     return v;
   1566 }
   1567 
   1568 static void
   1569 FcParseDouble (FcConfigParse *parse)
   1570 {
   1571     FcChar8 *s, *end;
   1572     double  d;
   1573 
   1574     if (!parse->pstack)
   1575 	return;
   1576     s = FcStrBufDoneStatic (&parse->pstack->str);
   1577     if (!s)
   1578     {
   1579 	FcConfigMessage (parse, FcSevereError, "out of memory");
   1580 	return;
   1581     }
   1582     end = 0;
   1583     d = FcStrtod ((char *) s, (char **)&end);
   1584     if (end != s + strlen ((char *) s))
   1585 	FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
   1586     else
   1587 	FcVStackPushDouble (parse, d);
   1588     FcStrBufDestroy (&parse->pstack->str);
   1589 }
   1590 
   1591 static void
   1592 FcParseString (FcConfigParse *parse, FcVStackTag tag)
   1593 {
   1594     FcChar8 *s;
   1595 
   1596     if (!parse->pstack)
   1597 	return;
   1598     s = FcStrBufDone (&parse->pstack->str);
   1599     if (!s)
   1600     {
   1601 	FcConfigMessage (parse, FcSevereError, "out of memory");
   1602 	return;
   1603     }
   1604     if (!FcVStackPushString (parse, tag, s))
   1605 	FcStrFree (s);
   1606 }
   1607 
   1608 static void
   1609 FcParseName (FcConfigParse *parse)
   1610 {
   1611     const FcChar8   *kind_string;
   1612     FcMatchKind	    kind;
   1613     FcChar8 *s;
   1614     FcObject object;
   1615 
   1616     kind_string = FcConfigGetAttribute (parse, "target");
   1617     if (!kind_string)
   1618 	kind = FcMatchDefault;
   1619     else
   1620     {
   1621 	if (!strcmp ((char *) kind_string, "pattern"))
   1622 	    kind = FcMatchPattern;
   1623 	else if (!strcmp ((char *) kind_string, "font"))
   1624 	    kind = FcMatchFont;
   1625 	else if (!strcmp ((char *) kind_string, "default"))
   1626 	    kind = FcMatchDefault;
   1627 	else
   1628 	{
   1629 	    FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string);
   1630 	    return;
   1631 	}
   1632     }
   1633 
   1634     if (!parse->pstack)
   1635 	return;
   1636     s = FcStrBufDone (&parse->pstack->str);
   1637     if (!s)
   1638     {
   1639 	FcConfigMessage (parse, FcSevereError, "out of memory");
   1640 	return;
   1641     }
   1642     object = FcObjectFromName ((const char *) s);
   1643 
   1644     FcVStackPushName (parse, kind, object);
   1645 
   1646     FcStrFree (s);
   1647 }
   1648 
   1649 static void
   1650 FcParseMatrix (FcConfigParse *parse)
   1651 {
   1652     FcExprMatrix m;
   1653 
   1654     m.yy = FcPopExpr (parse);
   1655     m.yx = FcPopExpr (parse);
   1656     m.xy = FcPopExpr (parse);
   1657     m.xx = FcPopExpr (parse);
   1658 
   1659     if (!m.yy || !m.yx || !m.xy || !m.xx)
   1660     {
   1661 	FcConfigMessage (parse, FcSevereWarning, "Missing values in matrix element");
   1662 	return;
   1663     }
   1664     if (FcPopExpr (parse))
   1665       FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
   1666     else
   1667       FcVStackPushMatrix (parse, &m);
   1668 }
   1669 
   1670 static void
   1671 FcParseRange (FcConfigParse *parse)
   1672 {
   1673     FcVStack	*vstack;
   1674     FcRange	*r;
   1675     FcChar32	n[2] = {0, 0};
   1676     int		count = 1;
   1677     double	d[2] = {0.0L, 0.0L};
   1678     FcBool	dflag = FcFalse;
   1679 
   1680     while ((vstack = FcVStackPeek (parse)))
   1681     {
   1682 	if (count < 0)
   1683 	{
   1684 	    FcConfigMessage (parse, FcSevereError, "too many elements in range");
   1685 	    return;
   1686 	}
   1687 	switch ((int) vstack->tag) {
   1688 	case FcVStackInteger:
   1689 	    if (dflag)
   1690 		d[count] = (double)vstack->u.integer;
   1691 	    else
   1692 		n[count] = vstack->u.integer;
   1693 	    break;
   1694 	case FcVStackDouble:
   1695 	    if (count == 0 && !dflag)
   1696 		d[1] = (double)n[1];
   1697 	    d[count] = vstack->u._double;
   1698 	    dflag = FcTrue;
   1699 	    break;
   1700 	default:
   1701 	    FcConfigMessage (parse, FcSevereError, "invalid element in range");
   1702 	    if (dflag)
   1703 		d[count] = 0.0L;
   1704 	    else
   1705 		n[count] = 0;
   1706 	    break;
   1707 	}
   1708 	count--;
   1709 	FcVStackPopAndDestroy (parse);
   1710     }
   1711     if (count >= 0)
   1712     {
   1713 	FcConfigMessage (parse, FcSevereError, "invalid range");
   1714 	return;
   1715     }
   1716     if (dflag)
   1717     {
   1718 	if (d[0] > d[1])
   1719 	{
   1720 	    FcConfigMessage (parse, FcSevereError, "invalid range");
   1721 	    return;
   1722 	}
   1723 	r = FcRangeCreateDouble (d[0], d[1]);
   1724     }
   1725     else
   1726     {
   1727 	if (n[0] > n[1])
   1728 	{
   1729 	    FcConfigMessage (parse, FcSevereError, "invalid range");
   1730 	    return;
   1731 	}
   1732 	r = FcRangeCreateInteger (n[0], n[1]);
   1733     }
   1734     FcVStackPushRange (parse, r);
   1735 }
   1736 
   1737 static FcBool
   1738 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
   1739 {
   1740     FcBool  result = FcFalse;
   1741 
   1742     if (!FcNameBool (bool_, &result))
   1743 	FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
   1744 			 bool_);
   1745     return result;
   1746 }
   1747 
   1748 static void
   1749 FcParseBool (FcConfigParse *parse)
   1750 {
   1751     FcChar8 *s;
   1752 
   1753     if (!parse->pstack)
   1754 	return;
   1755     s = FcStrBufDoneStatic (&parse->pstack->str);
   1756     if (!s)
   1757     {
   1758 	FcConfigMessage (parse, FcSevereError, "out of memory");
   1759 	return;
   1760     }
   1761     FcVStackPushBool (parse, FcConfigLexBool (parse, s));
   1762     FcStrBufDestroy (&parse->pstack->str);
   1763 }
   1764 
   1765 static void
   1766 FcParseCharSet (FcConfigParse *parse)
   1767 {
   1768     FcVStack	*vstack;
   1769     FcCharSet	*charset = FcCharSetCreate ();
   1770     FcChar32	i, begin, end;
   1771     int n = 0;
   1772 
   1773     while ((vstack = FcVStackPeek (parse)))
   1774     {
   1775 	switch ((int) vstack->tag) {
   1776 	case FcVStackInteger:
   1777 	    if (!FcCharSetAddChar (charset, vstack->u.integer))
   1778 	    {
   1779 		FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
   1780 	    }
   1781 	    else
   1782 		n++;
   1783 	    break;
   1784 	case FcVStackRange:
   1785 	    begin = (FcChar32) vstack->u.range->begin;
   1786 	    end = (FcChar32) vstack->u.range->end;
   1787 
   1788 	    if (begin <= end)
   1789 	    {
   1790 	      for (i = begin; i <= end; i++)
   1791 	      {
   1792 		  if (!FcCharSetAddChar (charset, i))
   1793 		  {
   1794 		      FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
   1795 		  }
   1796 		  else
   1797 		      n++;
   1798 	      }
   1799 	    }
   1800 	    break;
   1801 	default:
   1802 		FcConfigMessage (parse, FcSevereError, "invalid element in charset");
   1803 		break;
   1804 	}
   1805 	FcVStackPopAndDestroy (parse);
   1806     }
   1807     if (n > 0)
   1808 	    FcVStackPushCharSet (parse, charset);
   1809     else
   1810 	    FcCharSetDestroy (charset);
   1811 }
   1812 
   1813 static void
   1814 FcParseLangSet (FcConfigParse *parse)
   1815 {
   1816     FcVStack	*vstack;
   1817     FcLangSet	*langset = FcLangSetCreate ();
   1818     int n = 0;
   1819 
   1820     while ((vstack = FcVStackPeek (parse)))
   1821     {
   1822 	switch ((int) vstack->tag) {
   1823 	case FcVStackString:
   1824 	    if (!FcLangSetAdd (langset, vstack->u.string))
   1825 	    {
   1826 		FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
   1827 	    }
   1828 	    else
   1829 		n++;
   1830 	    break;
   1831 	default:
   1832 		FcConfigMessage (parse, FcSevereError, "invalid element in langset");
   1833 		break;
   1834 	}
   1835 	FcVStackPopAndDestroy (parse);
   1836     }
   1837     if (n > 0)
   1838 	    FcVStackPushLangSet (parse, langset);
   1839     else
   1840 	    FcLangSetDestroy (langset);
   1841 }
   1842 
   1843 static FcBool
   1844 FcConfigLexBinding (FcConfigParse   *parse,
   1845 		    const FcChar8   *binding_string,
   1846 		    FcValueBinding  *binding_ret)
   1847 {
   1848     FcValueBinding binding;
   1849 
   1850     if (!binding_string)
   1851 	binding = FcValueBindingWeak;
   1852     else
   1853     {
   1854 	if (!strcmp ((char *) binding_string, "weak"))
   1855 	    binding = FcValueBindingWeak;
   1856 	else if (!strcmp ((char *) binding_string, "strong"))
   1857 	    binding = FcValueBindingStrong;
   1858 	else if (!strcmp ((char *) binding_string, "same"))
   1859 	    binding = FcValueBindingSame;
   1860 	else
   1861 	{
   1862 	    FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
   1863 	    return FcFalse;
   1864 	}
   1865     }
   1866     *binding_ret = binding;
   1867     return FcTrue;
   1868 }
   1869 
   1870 static void
   1871 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
   1872 {
   1873     FcVStack	*vstack;
   1874     FcExpr	*left, *expr = 0, *new;
   1875 
   1876     while ((vstack = FcVStackPeek (parse)))
   1877     {
   1878 	if (vstack->tag != FcVStackFamily)
   1879 	{
   1880 	    FcConfigMessage (parse, FcSevereWarning, "non-family");
   1881 	    FcVStackPopAndDestroy (parse);
   1882 	    continue;
   1883 	}
   1884 	left = vstack->u.expr;
   1885 	vstack->tag = FcVStackNone;
   1886 	FcVStackPopAndDestroy (parse);
   1887 	if (expr)
   1888 	{
   1889 	    new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
   1890 	    if (!new)
   1891 	    {
   1892 		FcConfigMessage (parse, FcSevereError, "out of memory");
   1893 		FcExprDestroy (left);
   1894 		FcExprDestroy (expr);
   1895 		break;
   1896 	    }
   1897 	    expr = new;
   1898 	}
   1899 	else
   1900 	    expr = left;
   1901     }
   1902     if (expr)
   1903     {
   1904 	if (!FcVStackPushExpr (parse, tag, expr))
   1905 	{
   1906 	    FcConfigMessage (parse, FcSevereError, "out of memory");
   1907             FcExprDestroy (expr);
   1908 	}
   1909     }
   1910 }
   1911 
   1912 static void
   1913 FcParseFamily (FcConfigParse *parse)
   1914 {
   1915     FcChar8 *s;
   1916     FcExpr  *expr;
   1917 
   1918     if (!parse->pstack)
   1919 	return;
   1920     s = FcStrBufDoneStatic (&parse->pstack->str);
   1921     if (!s)
   1922     {
   1923 	FcConfigMessage (parse, FcSevereError, "out of memory");
   1924 	return;
   1925     }
   1926     expr = FcExprCreateString (parse->config, s);
   1927     FcStrBufDestroy (&parse->pstack->str);
   1928     if (expr)
   1929 	FcVStackPushExpr (parse, FcVStackFamily, expr);
   1930 }
   1931 
   1932 static void
   1933 FcParseAlias (FcConfigParse *parse)
   1934 {
   1935     FcExpr	*family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
   1936     FcEdit	*edit = 0;
   1937     FcVStack	*vstack;
   1938     FcRule	*rule = NULL, *r;
   1939     FcValueBinding  binding;
   1940     int		    n;
   1941 
   1942     if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
   1943 	return;
   1944     while ((vstack = FcVStackPeek (parse)))
   1945     {
   1946 	switch ((int) vstack->tag) {
   1947 	case FcVStackFamily:
   1948 	    if (family)
   1949 	    {
   1950 		FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected");
   1951 		new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
   1952 		if (!new)
   1953 		    FcConfigMessage (parse, FcSevereError, "out of memory");
   1954 		else
   1955 		    family = new;
   1956 	    }
   1957 	    else
   1958 		new = vstack->u.expr;
   1959 	    if (new)
   1960 	    {
   1961 		family = new;
   1962 		vstack->tag = FcVStackNone;
   1963 	    }
   1964 	    break;
   1965 	case FcVStackPrefer:
   1966 	    if (prefer)
   1967 		FcExprDestroy (prefer);
   1968 	    prefer = vstack->u.expr;
   1969 	    vstack->tag = FcVStackNone;
   1970 	    break;
   1971 	case FcVStackAccept:
   1972 	    if (accept)
   1973 		FcExprDestroy (accept);
   1974 	    accept = vstack->u.expr;
   1975 	    vstack->tag = FcVStackNone;
   1976 	    break;
   1977 	case FcVStackDefault:
   1978 	    if (def)
   1979 		FcExprDestroy (def);
   1980 	    def = vstack->u.expr;
   1981 	    vstack->tag = FcVStackNone;
   1982 	    break;
   1983 	case FcVStackTest:
   1984 	    if (rule)
   1985 	    {
   1986 		r = FcRuleCreate (FcRuleTest, vstack->u.test);
   1987 		r->next = rule;
   1988 		rule = r;
   1989 	    }
   1990 	    else
   1991 		rule = FcRuleCreate (FcRuleTest, vstack->u.test);
   1992 	    vstack->tag = FcVStackNone;
   1993 	    break;
   1994 	default:
   1995 	    FcConfigMessage (parse, FcSevereWarning, "bad alias");
   1996 	    break;
   1997 	}
   1998 	FcVStackPopAndDestroy (parse);
   1999     }
   2000     if (!family)
   2001     {
   2002 	FcConfigMessage (parse, FcSevereError, "missing family in alias");
   2003 	if (prefer)
   2004 	    FcExprDestroy (prefer);
   2005 	if (accept)
   2006 	    FcExprDestroy (accept);
   2007 	if (def)
   2008 	    FcExprDestroy (def);
   2009 	if (rule)
   2010 	    FcRuleDestroy (rule);
   2011 	return;
   2012     }
   2013     if (!prefer &&
   2014 	!accept &&
   2015 	!def)
   2016     {
   2017 	FcExprDestroy (family);
   2018 	if (rule)
   2019 	    FcRuleDestroy (rule);
   2020 	return;
   2021     }
   2022     else
   2023     {
   2024 	FcTest *t = FcTestCreate (parse, FcMatchPattern,
   2025 				  FcQualAny,
   2026 				  (FcChar8 *) FC_FAMILY,
   2027 				  FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
   2028 				  family);
   2029 	if (rule)
   2030 	{
   2031 	    for (r = rule; r->next; r = r->next);
   2032 	    r->next = FcRuleCreate (FcRuleTest, t);
   2033 	    r = r->next;
   2034 	}
   2035 	else
   2036 	{
   2037 	    r = rule = FcRuleCreate (FcRuleTest, t);
   2038 	}
   2039     }
   2040     if (prefer)
   2041     {
   2042 	edit = FcEditCreate (parse,
   2043 			     FC_FAMILY_OBJECT,
   2044 			     FcOpPrepend,
   2045 			     prefer,
   2046 			     binding);
   2047 	if (!edit)
   2048 	    FcExprDestroy (prefer);
   2049 	else
   2050 	{
   2051 	    r->next = FcRuleCreate (FcRuleEdit, edit);
   2052 	    r = r->next;
   2053 	}
   2054     }
   2055     if (accept)
   2056     {
   2057 	edit = FcEditCreate (parse,
   2058 			     FC_FAMILY_OBJECT,
   2059 			     FcOpAppend,
   2060 			     accept,
   2061 			     binding);
   2062 	if (!edit)
   2063 	    FcExprDestroy (accept);
   2064 	else
   2065 	{
   2066 	    r->next = FcRuleCreate (FcRuleEdit, edit);
   2067 	    r = r->next;
   2068 	}
   2069     }
   2070     if (def)
   2071     {
   2072 	edit = FcEditCreate (parse,
   2073 			     FC_FAMILY_OBJECT,
   2074 			     FcOpAppendLast,
   2075 			     def,
   2076 			     binding);
   2077 	if (!edit)
   2078 	    FcExprDestroy (def);
   2079 	else
   2080 	{
   2081 	    r->next = FcRuleCreate (FcRuleEdit, edit);
   2082 	    r = r->next;
   2083 	}
   2084     }
   2085     if ((n = FcRuleSetAdd (parse->ruleset, rule, FcMatchPattern)) == -1)
   2086 	FcRuleDestroy (rule);
   2087     else
   2088 	if (parse->config->maxObjects < n)
   2089 	    parse->config->maxObjects = n;
   2090 }
   2091 
   2092 static void
   2093 FcParseDescription (FcConfigParse *parse)
   2094 {
   2095     const FcChar8 *domain;
   2096     FcChar8 *desc;
   2097 
   2098     domain = FcConfigGetAttribute (parse, "domain");
   2099     desc = FcStrBufDone (&parse->pstack->str);
   2100     if (!desc)
   2101     {
   2102 	FcConfigMessage (parse, FcSevereError, "out of memory");
   2103 	return;
   2104     }
   2105     FcRuleSetAddDescription (parse->ruleset, domain, desc);
   2106 
   2107     FcStrFree (desc);
   2108 }
   2109 
   2110 static void
   2111 FcParseRemapDir (FcConfigParse *parse)
   2112 {
   2113     const FcChar8 *path, *attr, *data, *salt;
   2114     FcStrSet *prefix_dirs = NULL;
   2115 
   2116     data = FcStrBufDoneStatic (&parse->pstack->str);
   2117     if (!data)
   2118     {
   2119 	FcConfigMessage (parse, FcSevereError, "out of memory");
   2120 	return;
   2121     }
   2122     if (data[0] == 0)
   2123     {
   2124 	FcConfigMessage (parse, FcSevereWarning, "empty font directory name for remap ignored");
   2125 	return;
   2126     }
   2127     path = FcConfigGetAttribute (parse, "as-path");
   2128     if (!path)
   2129     {
   2130 	FcConfigMessage (parse, FcSevereWarning, "Missing as-path in remap-dir");
   2131 	return;
   2132     }
   2133     attr = FcConfigGetAttribute (parse, "prefix");
   2134     salt = FcConfigGetAttribute (parse, "salt");
   2135     prefix_dirs = _get_real_paths_from_prefix (parse, data, attr);
   2136     if (prefix_dirs)
   2137     {
   2138 	FcStrList *l = FcStrListCreate (prefix_dirs);
   2139 	FcChar8 *prefix;
   2140 
   2141 	FcStrSetDestroy (prefix_dirs);
   2142 	while ((prefix = FcStrListNext (l)))
   2143 	{
   2144 	    if (!prefix || prefix[0] == 0)
   2145 	    {
   2146 		/* nop */
   2147 	    }
   2148 	    else if (!parse->scanOnly && (!FcStrUsesHome (prefix) || FcConfigHome ()))
   2149 	    {
   2150 		if (!FcConfigAddFontDir (parse->config, prefix, path, salt))
   2151 		    FcConfigMessage (parse, FcSevereError, "out of memory; cannot create remap data for %s as %s", prefix, path);
   2152 	    }
   2153 	    FcStrBufDestroy (&parse->pstack->str);
   2154 	}
   2155 	FcStrListDone (l);
   2156     }
   2157 }
   2158 
   2159 static void
   2160 FcParseResetDirs (FcConfigParse *parse)
   2161 {
   2162     if (!parse->scanOnly)
   2163     {
   2164 	if (!FcConfigResetFontDirs (parse->config))
   2165 	    FcConfigMessage (parse, FcSevereError, "Unable to reset fonts dirs");
   2166     }
   2167 }
   2168 
   2169 static FcExpr *
   2170 FcPopExpr (FcConfigParse *parse)
   2171 {
   2172     FcVStack	*vstack = FcVStackPeek (parse);
   2173     FcExpr	*expr = 0;
   2174     if (!vstack)
   2175 	return 0;
   2176     switch ((int) vstack->tag) {
   2177     case FcVStackNone:
   2178 	break;
   2179     case FcVStackString:
   2180     case FcVStackFamily:
   2181 	expr = FcExprCreateString (parse->config, vstack->u.string);
   2182 	break;
   2183     case FcVStackName:
   2184 	expr = FcExprCreateName (parse->config, vstack->u.name);
   2185 	break;
   2186     case FcVStackConstant:
   2187 	expr = FcExprCreateConst (parse->config, vstack->u.string);
   2188 	break;
   2189     case FcVStackGlob:
   2190 	/* XXX: What's the correct action here? (CDW) */
   2191 	break;
   2192     case FcVStackPrefer:
   2193     case FcVStackAccept:
   2194     case FcVStackDefault:
   2195 	expr = vstack->u.expr;
   2196 	vstack->tag = FcVStackNone;
   2197 	break;
   2198     case FcVStackInteger:
   2199 	expr = FcExprCreateInteger (parse->config, vstack->u.integer);
   2200 	break;
   2201     case FcVStackDouble:
   2202 	expr = FcExprCreateDouble (parse->config, vstack->u._double);
   2203 	break;
   2204     case FcVStackMatrix:
   2205 	expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
   2206 	break;
   2207     case FcVStackRange:
   2208 	expr = FcExprCreateRange (parse->config, vstack->u.range);
   2209 	break;
   2210     case FcVStackBool:
   2211 	expr = FcExprCreateBool (parse->config, vstack->u.bool_);
   2212 	break;
   2213     case FcVStackCharSet:
   2214 	expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
   2215 	break;
   2216     case FcVStackLangSet:
   2217 	expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
   2218 	break;
   2219     case FcVStackTest:
   2220 	break;
   2221     case FcVStackExpr:
   2222 	expr = vstack->u.expr;
   2223 	vstack->tag = FcVStackNone;
   2224 	break;
   2225     case FcVStackEdit:
   2226 	break;
   2227     default:
   2228 	break;
   2229     }
   2230     FcVStackPopAndDestroy (parse);
   2231     return expr;
   2232 }
   2233 
   2234 /*
   2235  * This builds a tree of binary operations.  Note
   2236  * that every operator is defined so that if only
   2237  * a single operand is contained, the value of the
   2238  * whole expression is the value of the operand.
   2239  *
   2240  * This code reduces in that case to returning that
   2241  * operand.
   2242  */
   2243 static FcExpr *
   2244 FcPopBinary (FcConfigParse *parse, FcOp op)
   2245 {
   2246     FcExpr  *left, *expr = 0, *new;
   2247 
   2248     while ((left = FcPopExpr (parse)))
   2249     {
   2250 	if (expr)
   2251 	{
   2252 	    new = FcExprCreateOp (parse->config, left, op, expr);
   2253 	    if (!new)
   2254 	    {
   2255 		FcConfigMessage (parse, FcSevereError, "out of memory");
   2256 		FcExprDestroy (left);
   2257 		FcExprDestroy (expr);
   2258 		return 0;
   2259 	    }
   2260 	    expr = new;
   2261 	}
   2262 	else
   2263 	    expr = left;
   2264     }
   2265     return expr;
   2266 }
   2267 
   2268 static void
   2269 FcParseBinary (FcConfigParse *parse, FcOp op)
   2270 {
   2271     FcExpr  *expr = FcPopBinary (parse, op);
   2272     if (expr)
   2273 	FcVStackPushExpr (parse, FcVStackExpr, expr);
   2274 }
   2275 
   2276 /*
   2277  * This builds a a unary operator, it consumes only
   2278  * a single operand
   2279  */
   2280 
   2281 static FcExpr *
   2282 FcPopUnary (FcConfigParse *parse, FcOp op)
   2283 {
   2284     FcExpr  *operand, *new = 0;
   2285 
   2286     if ((operand = FcPopExpr (parse)))
   2287     {
   2288 	new = FcExprCreateOp (parse->config, operand, op, 0);
   2289 	if (!new)
   2290 	{
   2291 	    FcExprDestroy (operand);
   2292 	    FcConfigMessage (parse, FcSevereError, "out of memory");
   2293 	}
   2294     }
   2295     return new;
   2296 }
   2297 
   2298 static void
   2299 FcParseUnary (FcConfigParse *parse, FcOp op)
   2300 {
   2301     FcExpr  *expr = FcPopUnary (parse, op);
   2302     if (expr)
   2303 	FcVStackPushExpr (parse, FcVStackExpr, expr);
   2304 }
   2305 
   2306 static void
   2307 FcParseDir (FcConfigParse *parse)
   2308 {
   2309     const FcChar8 *attr, *data, *salt;
   2310     FcStrSet *prefix_dirs = NULL;
   2311 
   2312     data = FcStrBufDoneStatic (&parse->pstack->str);
   2313     if (!data)
   2314     {
   2315 	FcConfigMessage (parse, FcSevereError, "out of memory");
   2316 	return;
   2317     }
   2318     if (data[0] == 0)
   2319     {
   2320 	FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
   2321 	return;
   2322     }
   2323     attr = FcConfigGetAttribute (parse, "prefix");
   2324     salt = FcConfigGetAttribute (parse, "salt");
   2325     prefix_dirs = _get_real_paths_from_prefix (parse, data, attr);
   2326     if (prefix_dirs)
   2327     {
   2328 	FcStrList *l = FcStrListCreate (prefix_dirs);
   2329 	FcChar8 *prefix;
   2330 
   2331 	FcStrSetDestroy (prefix_dirs);
   2332 	while ((prefix = FcStrListNext (l)))
   2333 	{
   2334 	    if (!prefix || prefix[0] == 0)
   2335 	    {
   2336 		/* nop */
   2337 	    }
   2338 	    else if (!parse->scanOnly && (!FcStrUsesHome (prefix) || FcConfigHome ()))
   2339 	    {
   2340 		if (!FcConfigAddFontDir (parse->config, prefix, NULL, salt))
   2341 		    FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", prefix);
   2342 	    }
   2343 	    FcStrBufDestroy (&parse->pstack->str);
   2344 	}
   2345 	FcStrListDone (l);
   2346     }
   2347 }
   2348 
   2349 static void
   2350 FcParseCacheDir (FcConfigParse *parse)
   2351 {
   2352     const FcChar8 *attr;
   2353     FcChar8 *prefix = NULL, *p, *data = NULL;
   2354 
   2355     attr = FcConfigGetAttribute (parse, "prefix");
   2356     if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
   2357     {
   2358 	prefix = FcConfigXdgCacheHome ();
   2359 	/* home directory might be disabled.
   2360 	 * simply ignore this element.
   2361 	 */
   2362 	if (!prefix)
   2363 	    goto bail;
   2364     }
   2365     data = FcStrBufDone (&parse->pstack->str);
   2366     if (!data)
   2367     {
   2368 	FcConfigMessage (parse, FcSevereError, "out of memory");
   2369 	data = prefix;
   2370 	goto bail;
   2371     }
   2372     if (data[0] == 0)
   2373     {
   2374 	FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
   2375 	FcStrFree (data);
   2376 	data = prefix;
   2377 	goto bail;
   2378     }
   2379     if (prefix)
   2380     {
   2381 	size_t plen = strlen ((const char *)prefix);
   2382 	size_t dlen = strlen ((const char *)data);
   2383 
   2384 	p = realloc (prefix, plen + 1 + dlen + 1);
   2385 	if (!p)
   2386 	{
   2387 	    FcConfigMessage (parse, FcSevereError, "out of memory");
   2388 	    FcStrFree (prefix);
   2389 	    goto bail;
   2390 	}
   2391 	prefix = p;
   2392 	prefix[plen] = FC_DIR_SEPARATOR;
   2393 	memcpy (&prefix[plen + 1], data, dlen);
   2394 	prefix[plen + 1 + dlen] = 0;
   2395 	FcStrFree (data);
   2396 	data = prefix;
   2397     }
   2398 #ifdef _WIN32
   2399     else if (data[0] == '/' && fontconfig_instprefix[0] != '\0')
   2400     {
   2401 	size_t plen = strlen ((const char *)fontconfig_instprefix);
   2402 	size_t dlen = strlen ((const char *)data);
   2403 
   2404 	prefix = malloc (plen + 1 + dlen + 1);
   2405 	if (!prefix)
   2406 	{
   2407 	    FcConfigMessage (parse, FcSevereError, "out of memory");
   2408 	    goto bail;
   2409 	}
   2410 	strcpy ((char *) prefix, (char *) fontconfig_instprefix);
   2411 	prefix[plen] = FC_DIR_SEPARATOR;
   2412 	memcpy (&prefix[plen + 1], data, dlen);
   2413 	prefix[plen + 1 + dlen] = 0;
   2414 	FcStrFree (data);
   2415 	data = prefix;
   2416     }
   2417     else if (strcmp ((const char *) data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
   2418     {
   2419 	int rc;
   2420 
   2421 	FcStrFree (data);
   2422 	data = malloc (1000);
   2423 	if (!data)
   2424 	{
   2425 	    FcConfigMessage (parse, FcSevereError, "out of memory");
   2426 	    goto bail;
   2427 	}
   2428 	rc = GetTempPath (800, (LPSTR) data);
   2429 	if (rc == 0 || rc > 800)
   2430 	{
   2431 	    FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
   2432 	    goto bail;
   2433 	}
   2434 	if (data [strlen ((const char *) data) - 1] != '\\')
   2435 	    strcat ((char *) data, "\\");
   2436 	strcat ((char *) data, "fontconfig\\cache");
   2437     }
   2438     else if (strcmp ((const char *) data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0)
   2439     {
   2440 	char szFPath[MAX_PATH + 1];
   2441 	size_t len;
   2442 
   2443 	if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath))))
   2444 	{
   2445 	    FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
   2446 	    goto bail;
   2447 	}
   2448 	strncat(szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen(szFPath));
   2449 	len = strlen(szFPath) + 1;
   2450 	FcStrFree (data);
   2451 	data = malloc(len);
   2452 	if (!data)
   2453 	{
   2454 	    FcConfigMessage (parse, FcSevereError, "out of memory");
   2455 	    goto bail;
   2456 	}
   2457 	strncpy((char *) data, szFPath, len);
   2458     }
   2459 #endif
   2460     if (strlen ((char *) data) == 0)
   2461 	FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
   2462     else if (!parse->scanOnly && (!FcStrUsesHome (data) || FcConfigHome ()))
   2463     {
   2464 	if (!FcConfigAddCacheDir (parse->config, data))
   2465 	    FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
   2466     }
   2467     FcStrBufDestroy (&parse->pstack->str);
   2468 
   2469   bail:
   2470     if (data)
   2471 	FcStrFree (data);
   2472 }
   2473 
   2474 void
   2475 FcConfigPathFini (void)
   2476 {
   2477     FcChar8 *s;
   2478 
   2479 retry_dir:
   2480     s = fc_atomic_ptr_get (&__fc_userdir);
   2481     if (!fc_atomic_ptr_cmpexch (&__fc_userdir, s, NULL))
   2482 	goto retry_dir;
   2483     free (s);
   2484 
   2485 retry_conf:
   2486     s = fc_atomic_ptr_get (&__fc_userconf);
   2487     if (!fc_atomic_ptr_cmpexch (&__fc_userconf, s, NULL))
   2488 	goto retry_conf;
   2489     free (s);
   2490 }
   2491 
   2492 static void
   2493 FcParseInclude (FcConfigParse *parse)
   2494 {
   2495     FcChar8	    *s;
   2496     const FcChar8   *attr;
   2497     FcBool	    ignore_missing = FcFalse;
   2498 #ifndef _WIN32
   2499     FcBool	    deprecated = FcFalse;
   2500 #endif
   2501     FcChar8	    *prefix = NULL, *p;
   2502     FcChar8	    *userdir = NULL, *userconf = NULL;
   2503     FcRuleSet	    *ruleset;
   2504     FcMatchKind	    k;
   2505 
   2506     s = FcStrBufDoneStatic (&parse->pstack->str);
   2507     if (!s)
   2508     {
   2509 	FcConfigMessage (parse, FcSevereError, "out of memory");
   2510 	goto bail;
   2511     }
   2512     attr = FcConfigGetAttribute (parse, "ignore_missing");
   2513     if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
   2514 	ignore_missing = FcTrue;
   2515     attr = FcConfigGetAttribute (parse, "deprecated");
   2516 #ifndef _WIN32
   2517     if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
   2518         deprecated = FcTrue;
   2519 #endif
   2520     attr = FcConfigGetAttribute (parse, "prefix");
   2521     if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
   2522     {
   2523 	prefix = FcConfigXdgConfigHome ();
   2524 	/* home directory might be disabled.
   2525 	 * simply ignore this element.
   2526 	 */
   2527 	if (!prefix)
   2528 	    goto bail;
   2529     }
   2530     if (prefix)
   2531     {
   2532 	size_t plen = strlen ((const char *)prefix);
   2533 	size_t dlen = strlen ((const char *)s);
   2534 	FcChar8 *u;
   2535 
   2536 	p = realloc (prefix, plen + 1 + dlen + 1);
   2537 	if (!p)
   2538 	{
   2539 	    FcConfigMessage (parse, FcSevereError, "out of memory");
   2540 	    goto bail;
   2541 	}
   2542 	prefix = p;
   2543 	prefix[plen] = FC_DIR_SEPARATOR;
   2544 	memcpy (&prefix[plen + 1], s, dlen);
   2545 	prefix[plen + 1 + dlen] = 0;
   2546 	s = prefix;
   2547 	if (FcFileIsDir (s))
   2548 	{
   2549 	userdir:
   2550 	    userdir = fc_atomic_ptr_get (&__fc_userdir);
   2551 	    if (!userdir)
   2552 	    {
   2553 		u = FcStrdup (s);
   2554 		if (!fc_atomic_ptr_cmpexch (&__fc_userdir, userdir, u))
   2555 		{
   2556 		    free (u);
   2557 		    goto userdir;
   2558 		}
   2559 		userdir = u;
   2560 	    }
   2561 	}
   2562 	else if (FcFileIsFile (s))
   2563 	{
   2564 	userconf:
   2565 	    userconf = fc_atomic_ptr_get (&__fc_userconf);
   2566 	    if (!userconf)
   2567 	    {
   2568 		u = FcStrdup (s);
   2569 		if (!fc_atomic_ptr_cmpexch (&__fc_userconf, userconf, u))
   2570 		{
   2571 		    free (u);
   2572 		    goto userconf;
   2573 		}
   2574 		userconf = u;
   2575 	    }
   2576 	}
   2577 	else
   2578 	{
   2579 	    /* No config dir nor file on the XDG directory spec compliant place
   2580 	     * so need to guess what it is supposed to be.
   2581 	     */
   2582 	    if (FcStrStr (s, (const FcChar8 *)"conf.d") != NULL)
   2583 		goto userdir;
   2584 	    else
   2585 		goto userconf;
   2586 	}
   2587     }
   2588     /* flush the ruleset into the queue */
   2589     ruleset = parse->ruleset;
   2590     parse->ruleset = FcRuleSetCreate (ruleset->name);
   2591     FcRuleSetEnable (parse->ruleset, ruleset->enabled);
   2592     FcRuleSetAddDescription (parse->ruleset, ruleset->domain, ruleset->description);
   2593     for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
   2594     {
   2595 	FcPtrListIter iter;
   2596 
   2597 	FcPtrListIterInit (ruleset->subst[k], &iter);
   2598 	if (FcPtrListIterIsValid (ruleset->subst[k], &iter))
   2599 	{
   2600 	    FcPtrListIterInitAtLast (parse->config->subst[k], &iter);
   2601 	    FcRuleSetReference (ruleset);
   2602 	    FcPtrListIterAdd (parse->config->subst[k], &iter, ruleset);
   2603 	}
   2604     }
   2605     FcRuleSetDestroy (ruleset);
   2606     if (!_FcConfigParse (parse->config, s, !ignore_missing, !parse->scanOnly))
   2607 	parse->error = FcTrue;
   2608 #ifndef _WIN32
   2609     else
   2610     {
   2611         FcChar8 *filename;
   2612 	static FcBool warn_conf = FcFalse, warn_confd = FcFalse;
   2613 
   2614         filename = FcConfigGetFilename(parse->config, s);
   2615 	if (deprecated == FcTrue &&
   2616 	    filename != NULL &&
   2617 	    userdir != NULL &&
   2618 	    !FcFileIsLink (filename))
   2619 	{
   2620 	    if (FcFileIsDir (filename))
   2621 	    {
   2622 		FcChar8 *parent = FcStrDirname (userdir);
   2623 
   2624 		if (!FcFileIsDir (parent))
   2625 		    FcMakeDirectory (parent);
   2626 		FcStrFree (parent);
   2627 		if (FcFileIsDir (userdir) ||
   2628 		    rename ((const char *)filename, (const char *)userdir) != 0 ||
   2629 		    symlink ((const char *)userdir, (const char *)filename) != 0)
   2630 		{
   2631 		    if (!warn_confd)
   2632 		    {
   2633 			FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userdir);
   2634 			warn_confd = FcTrue;
   2635 		    }
   2636 		}
   2637 	    }
   2638 	    else
   2639 	    {
   2640 		FcChar8 *parent = FcStrDirname (userconf);
   2641 
   2642 		if (!FcFileIsDir (parent))
   2643 		    FcMakeDirectory (parent);
   2644 		FcStrFree (parent);
   2645 		if (FcFileIsFile (userconf) ||
   2646 		    rename ((const char *)filename, (const char *)userconf) != 0 ||
   2647 		    symlink ((const char *)userconf, (const char *)filename) != 0)
   2648 		{
   2649 		    if (!warn_conf)
   2650 		    {
   2651 			FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userconf);
   2652 			warn_conf = FcTrue;
   2653 		    }
   2654 		}
   2655 	    }
   2656         }
   2657         if(filename)
   2658             FcStrFree(filename);
   2659     }
   2660 #endif
   2661     FcStrBufDestroy (&parse->pstack->str);
   2662 
   2663   bail:
   2664     if (prefix)
   2665 	FcStrFree (prefix);
   2666 }
   2667 
   2668 typedef struct _FcOpMap {
   2669     char    name[16];
   2670     FcOp    op;
   2671 } FcOpMap;
   2672 
   2673 static FcOp
   2674 FcConfigLexOp (const FcChar8 *op, const FcOpMap	*map, int nmap)
   2675 {
   2676     int	i;
   2677 
   2678     for (i = 0; i < nmap; i++)
   2679 	if (!strcmp ((char *) op, map[i].name))
   2680 	    return map[i].op;
   2681     return FcOpInvalid;
   2682 }
   2683 
   2684 static const FcOpMap fcCompareOps[] = {
   2685     { "eq",		FcOpEqual	    },
   2686     { "not_eq",		FcOpNotEqual	    },
   2687     { "less",		FcOpLess	    },
   2688     { "less_eq",	FcOpLessEqual	    },
   2689     { "more",		FcOpMore	    },
   2690     { "more_eq",	FcOpMoreEqual	    },
   2691     { "contains",	FcOpContains	    },
   2692     { "not_contains",	FcOpNotContains	    }
   2693 };
   2694 
   2695 #define NUM_COMPARE_OPS	(int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
   2696 
   2697 static FcOp
   2698 FcConfigLexCompare (const FcChar8 *compare)
   2699 {
   2700     return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
   2701 }
   2702 
   2703 static void
   2704 FcParseTest (FcConfigParse *parse)
   2705 {
   2706     const FcChar8   *kind_string;
   2707     FcMatchKind	    kind;
   2708     const FcChar8   *qual_string;
   2709     FcQual	    qual;
   2710     const FcChar8   *name;
   2711     const FcChar8   *compare_string;
   2712     FcOp	    compare;
   2713     FcExpr	    *expr;
   2714     FcTest	    *test;
   2715     const FcChar8   *iblanks_string;
   2716     int              flags = 0;
   2717 
   2718     kind_string = FcConfigGetAttribute (parse, "target");
   2719     if (!kind_string)
   2720 	kind = FcMatchDefault;
   2721     else
   2722     {
   2723 	if (!strcmp ((char *) kind_string, "pattern"))
   2724 	    kind = FcMatchPattern;
   2725 	else if (!strcmp ((char *) kind_string, "font"))
   2726 	    kind = FcMatchFont;
   2727 	else if (!strcmp ((char *) kind_string, "scan"))
   2728 	    kind = FcMatchScan;
   2729 	else if (!strcmp ((char *) kind_string, "default"))
   2730 	    kind = FcMatchDefault;
   2731 	else
   2732 	{
   2733 	    FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
   2734 	    return;
   2735 	}
   2736     }
   2737     qual_string = FcConfigGetAttribute (parse, "qual");
   2738     if (!qual_string)
   2739 	qual = FcQualAny;
   2740     else
   2741     {
   2742 	if (!strcmp ((char *) qual_string, "any"))
   2743 	    qual = FcQualAny;
   2744 	else if (!strcmp ((char *) qual_string, "all"))
   2745 	    qual = FcQualAll;
   2746 	else if (!strcmp ((char *) qual_string, "first"))
   2747 	    qual = FcQualFirst;
   2748 	else if (!strcmp ((char *) qual_string, "not_first"))
   2749 	    qual = FcQualNotFirst;
   2750 	else
   2751 	{
   2752 	    FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
   2753 	    return;
   2754 	}
   2755     }
   2756     name = FcConfigGetAttribute (parse, "name");
   2757     if (!name)
   2758     {
   2759 	FcConfigMessage (parse, FcSevereWarning, "missing test name");
   2760 	return;
   2761     }
   2762     compare_string = FcConfigGetAttribute (parse, "compare");
   2763     if (!compare_string)
   2764 	compare = FcOpEqual;
   2765     else
   2766     {
   2767 	compare = FcConfigLexCompare (compare_string);
   2768 	if (compare == FcOpInvalid)
   2769 	{
   2770 	    FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
   2771 	    return;
   2772 	}
   2773     }
   2774     iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
   2775     if (iblanks_string)
   2776     {
   2777 	FcBool f = FcFalse;
   2778 
   2779 	if (!FcNameBool (iblanks_string, &f))
   2780 	{
   2781 	    FcConfigMessage (parse,
   2782 			     FcSevereWarning,
   2783 			     "invalid test ignore-blanks \"%s\"", iblanks_string);
   2784 	}
   2785 	if (f)
   2786 	    flags |= FcOpFlagIgnoreBlanks;
   2787     }
   2788     expr = FcPopBinary (parse, FcOpComma);
   2789     if (!expr)
   2790     {
   2791 	FcConfigMessage (parse, FcSevereWarning, "missing test expression");
   2792 	return;
   2793     }
   2794     if (expr->op == FcOpComma)
   2795     {
   2796 	FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
   2797     }
   2798     test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
   2799     if (!test)
   2800     {
   2801 	FcConfigMessage (parse, FcSevereError, "out of memory");
   2802 	return;
   2803     }
   2804     FcVStackPushTest (parse, test);
   2805 }
   2806 
   2807 static const FcOpMap fcModeOps[] = {
   2808     { "assign",		FcOpAssign	    },
   2809     { "assign_replace",	FcOpAssignReplace   },
   2810     { "prepend",	FcOpPrepend	    },
   2811     { "prepend_first",	FcOpPrependFirst    },
   2812     { "append",		FcOpAppend	    },
   2813     { "append_last",	FcOpAppendLast	    },
   2814     { "delete",		FcOpDelete	    },
   2815     { "delete_all",	FcOpDeleteAll	    },
   2816 };
   2817 
   2818 #define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
   2819 
   2820 static FcOp
   2821 FcConfigLexMode (const FcChar8 *mode)
   2822 {
   2823     return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
   2824 }
   2825 
   2826 static void
   2827 FcParseEdit (FcConfigParse *parse)
   2828 {
   2829     const FcChar8   *name;
   2830     const FcChar8   *mode_string;
   2831     FcOp	    mode;
   2832     FcValueBinding  binding;
   2833     FcExpr	    *expr;
   2834     FcEdit	    *edit;
   2835 
   2836     name = FcConfigGetAttribute (parse, "name");
   2837     if (!name)
   2838     {
   2839 	FcConfigMessage (parse, FcSevereWarning, "missing edit name");
   2840 	return;
   2841     }
   2842     mode_string = FcConfigGetAttribute (parse, "mode");
   2843     if (!mode_string)
   2844 	mode = FcOpAssign;
   2845     else
   2846     {
   2847 	mode = FcConfigLexMode (mode_string);
   2848 	if (mode == FcOpInvalid)
   2849 	{
   2850 	    FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
   2851 	    return;
   2852 	}
   2853     }
   2854     if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
   2855 	return;
   2856 
   2857     expr = FcPopBinary (parse, FcOpComma);
   2858     if ((mode == FcOpDelete || mode == FcOpDeleteAll) &&
   2859 	expr != NULL)
   2860     {
   2861 	FcConfigMessage (parse, FcSevereWarning, "Expression doesn't take any effects for delete and delete_all");
   2862 	FcExprDestroy (expr);
   2863 	expr = NULL;
   2864     }
   2865     edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
   2866 			 mode, expr, binding);
   2867     if (!edit)
   2868     {
   2869 	FcConfigMessage (parse, FcSevereError, "out of memory");
   2870 	FcExprDestroy (expr);
   2871 	return;
   2872     }
   2873     if (!FcVStackPushEdit (parse, edit))
   2874 	FcEditDestroy (edit);
   2875 }
   2876 
   2877 static void
   2878 FcParseMatch (FcConfigParse *parse)
   2879 {
   2880     const FcChar8   *kind_name;
   2881     FcMatchKind	    kind;
   2882     FcVStack	    *vstack;
   2883     FcRule	    *rule = NULL, *r;
   2884     int		    n;
   2885 
   2886     kind_name = FcConfigGetAttribute (parse, "target");
   2887     if (!kind_name)
   2888 	kind = FcMatchPattern;
   2889     else
   2890     {
   2891 	if (!strcmp ((char *) kind_name, "pattern"))
   2892 	    kind = FcMatchPattern;
   2893 	else if (!strcmp ((char *) kind_name, "font"))
   2894 	    kind = FcMatchFont;
   2895 	else if (!strcmp ((char *) kind_name, "scan"))
   2896 	    kind = FcMatchScan;
   2897 	else
   2898 	{
   2899 	    FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
   2900 	    return;
   2901 	}
   2902     }
   2903     while ((vstack = FcVStackPeek (parse)))
   2904     {
   2905 	switch ((int) vstack->tag) {
   2906 	case FcVStackTest:
   2907 	    r = FcRuleCreate (FcRuleTest, vstack->u.test);
   2908 	    if (rule)
   2909 		r->next = rule;
   2910 	    rule = r;
   2911 	    vstack->tag = FcVStackNone;
   2912 	    break;
   2913 	case FcVStackEdit:
   2914 	    if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT)
   2915 	    {
   2916 		FcConfigMessage (parse, FcSevereError,
   2917 				 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
   2918 				 FcObjectName(vstack->u.edit->object));
   2919 		if (rule)
   2920 		    FcRuleDestroy (rule);
   2921 		return;
   2922 	    }
   2923 	    r = FcRuleCreate (FcRuleEdit, vstack->u.edit);
   2924 	    if (rule)
   2925 		r->next = rule;
   2926 	    rule = r;
   2927 	    vstack->tag = FcVStackNone;
   2928 	    break;
   2929 	default:
   2930 	    FcConfigMessage (parse, FcSevereWarning, "invalid match element");
   2931 	    break;
   2932 	}
   2933 	FcVStackPopAndDestroy (parse);
   2934     }
   2935     if (!rule)
   2936     {
   2937 	FcConfigMessage (parse, FcSevereWarning, "No <test> nor <edit> elements in <match>");
   2938 	return;
   2939     }
   2940     if ((n = FcRuleSetAdd (parse->ruleset, rule, kind)) == -1)
   2941     {
   2942 	FcConfigMessage (parse, FcSevereError, "out of memory");
   2943 	FcRuleDestroy (rule);
   2944     }
   2945     else
   2946 	if (parse->config->maxObjects < n)
   2947 	    parse->config->maxObjects = n;
   2948 }
   2949 
   2950 static void
   2951 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
   2952 {
   2953     FcVStack	*vstack;
   2954 
   2955     while ((vstack = FcVStackPeek (parse)))
   2956     {
   2957 	switch ((int) vstack->tag) {
   2958 	case FcVStackGlob:
   2959 	    if (!parse->scanOnly && !FcConfigGlobAdd (parse->config,
   2960 						      vstack->u.string,
   2961 						      element == FcElementAcceptfont))
   2962 	    {
   2963 			if (FcStrUsesHome(vstack->u.string) && FcConfigHome() == NULL)
   2964 				FcConfigMessage (parse, FcSevereWarning, "Home is disabled");
   2965 			else
   2966 				FcConfigMessage (parse, FcSevereError, "out of memory");
   2967 	    }
   2968 	    else
   2969 	    {
   2970 		if (parse->scanOnly && vstack->u.string)
   2971 		{
   2972 		    FcStrFree (vstack->u.string);
   2973 		    vstack->tag = FcVStackNone;
   2974 		}
   2975 	    }
   2976 	    break;
   2977 	case FcVStackPattern:
   2978 	    if (!parse->scanOnly && !FcConfigPatternsAdd (parse->config,
   2979 							  vstack->u.pattern,
   2980 							  element == FcElementAcceptfont))
   2981 	    {
   2982 		FcConfigMessage (parse, FcSevereError, "out of memory");
   2983 	    }
   2984 	    else
   2985 	    {
   2986 		if (parse->scanOnly && vstack->u.pattern)
   2987 		    FcPatternDestroy (vstack->u.pattern);
   2988 		vstack->tag = FcVStackNone;
   2989 	    }
   2990 	    break;
   2991 	default:
   2992 	    FcConfigMessage (parse, FcSevereWarning, "bad font selector");
   2993 	    break;
   2994 	}
   2995 	FcVStackPopAndDestroy (parse);
   2996     }
   2997 }
   2998 
   2999 
   3000 static FcValue
   3001 FcPopValue (FcConfigParse *parse)
   3002 {
   3003     FcVStack	*vstack = FcVStackPeek (parse);
   3004     FcValue	value;
   3005 
   3006     value.type = FcTypeVoid;
   3007 
   3008     if (!vstack)
   3009 	return value;
   3010 
   3011     switch ((int) vstack->tag) {
   3012     case FcVStackString:
   3013 	value.u.s = FcStrdup (vstack->u.string);
   3014 	if (value.u.s)
   3015 	    value.type = FcTypeString;
   3016 	break;
   3017     case FcVStackConstant:
   3018 	if (FcNameConstant (vstack->u.string, &value.u.i))
   3019 	    value.type = FcTypeInteger;
   3020 	break;
   3021     case FcVStackInteger:
   3022 	value.u.i = vstack->u.integer;
   3023 	value.type = FcTypeInteger;
   3024 	break;
   3025     case FcVStackDouble:
   3026 	value.u.d = vstack->u._double;
   3027 	value.type = FcTypeDouble;
   3028 	break;
   3029     case FcVStackBool:
   3030 	value.u.b = vstack->u.bool_;
   3031 	value.type = FcTypeBool;
   3032 	break;
   3033     case FcVStackCharSet:
   3034 	value.u.c = FcCharSetCopy (vstack->u.charset);
   3035 	if (value.u.c)
   3036 	    value.type = FcTypeCharSet;
   3037 	break;
   3038     case FcVStackLangSet:
   3039 	value.u.l = FcLangSetCopy (vstack->u.langset);
   3040 	if (value.u.l)
   3041 	    value.type = FcTypeLangSet;
   3042 	break;
   3043     case FcVStackRange:
   3044 	value.u.r = FcRangeCopy (vstack->u.range);
   3045 	if (value.u.r)
   3046 	    value.type = FcTypeRange;
   3047 	break;
   3048     default:
   3049 	FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
   3050 			 vstack->tag);
   3051 	break;
   3052     }
   3053     FcVStackPopAndDestroy (parse);
   3054 
   3055     return value;
   3056 }
   3057 
   3058 static void
   3059 FcParsePatelt (FcConfigParse *parse)
   3060 {
   3061     FcValue	value;
   3062     FcPattern	*pattern = FcPatternCreate ();
   3063     const char	*name;
   3064 
   3065     if (!pattern)
   3066     {
   3067 	FcConfigMessage (parse, FcSevereError, "out of memory");
   3068 	return;
   3069     }
   3070 
   3071     name = (char *) FcConfigGetAttribute (parse, "name");
   3072     if (!name)
   3073     {
   3074 	FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
   3075 	FcPatternDestroy (pattern);
   3076 	return;
   3077     }
   3078 
   3079     for (;;)
   3080     {
   3081 	value = FcPopValue (parse);
   3082 	if (value.type == FcTypeVoid)
   3083 	    break;
   3084 	if (!FcPatternAdd (pattern, name, value, FcTrue))
   3085 	{
   3086 	    FcConfigMessage (parse, FcSevereError, "out of memory");
   3087             FcValueDestroy(value);
   3088 	    break;
   3089 	}
   3090         FcValueDestroy(value);
   3091     }
   3092 
   3093     FcVStackPushPattern (parse, pattern);
   3094 }
   3095 
   3096 static void
   3097 FcParsePattern (FcConfigParse *parse)
   3098 {
   3099     FcVStack	*vstack;
   3100     FcPattern	*pattern = FcPatternCreate ();
   3101 
   3102     if (!pattern)
   3103     {
   3104 	FcConfigMessage (parse, FcSevereError, "out of memory");
   3105 	return;
   3106     }
   3107 
   3108     while ((vstack = FcVStackPeek (parse)))
   3109     {
   3110 	switch ((int) vstack->tag) {
   3111 	case FcVStackPattern:
   3112 	    if (!FcPatternAppend (pattern, vstack->u.pattern))
   3113 	    {
   3114 		FcConfigMessage (parse, FcSevereError, "out of memory");
   3115 		FcPatternDestroy (pattern);
   3116 		return;
   3117 	    }
   3118 	    break;
   3119 	default:
   3120 	    FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
   3121 	    break;
   3122 	}
   3123 	FcVStackPopAndDestroy (parse);
   3124     }
   3125 
   3126     FcVStackPushPattern (parse, pattern);
   3127 }
   3128 
   3129 static void
   3130 FcEndElement(void *userData, const XML_Char *name FC_UNUSED)
   3131 {
   3132     FcConfigParse   *parse = userData;
   3133     FcChar8	    *data;
   3134 
   3135     if (!parse->pstack)
   3136 	return;
   3137     switch (parse->pstack->element) {
   3138     case FcElementNone:
   3139 	break;
   3140     case FcElementFontconfig:
   3141 	break;
   3142     case FcElementDir:
   3143 	FcParseDir (parse);
   3144 	break;
   3145     case FcElementCacheDir:
   3146 	FcParseCacheDir (parse);
   3147 	break;
   3148     case FcElementCache:
   3149 	data = FcStrBufDoneStatic (&parse->pstack->str);
   3150 	if (!data)
   3151 	{
   3152 	    FcConfigMessage (parse, FcSevereError, "out of memory");
   3153 	    break;
   3154 	}
   3155 	/* discard this data; no longer used */
   3156 	FcStrBufDestroy (&parse->pstack->str);
   3157 	break;
   3158     case FcElementInclude:
   3159 	FcParseInclude (parse);
   3160 	break;
   3161     case FcElementConfig:
   3162 	break;
   3163     case FcElementMatch:
   3164 	FcParseMatch (parse);
   3165 	break;
   3166     case FcElementAlias:
   3167 	FcParseAlias (parse);
   3168 	break;
   3169     case FcElementDescription:
   3170 	FcParseDescription (parse);
   3171 	break;
   3172     case FcElementRemapDir:
   3173 	FcParseRemapDir (parse);
   3174 	break;
   3175     case FcElementResetDirs:
   3176 	FcParseResetDirs (parse);
   3177 	break;
   3178 
   3179     case FcElementRescan:
   3180 	FcParseRescan (parse);
   3181 	break;
   3182 
   3183     case FcElementPrefer:
   3184 	FcParseFamilies (parse, FcVStackPrefer);
   3185 	break;
   3186     case FcElementAccept:
   3187 	FcParseFamilies (parse, FcVStackAccept);
   3188 	break;
   3189     case FcElementDefault:
   3190 	FcParseFamilies (parse, FcVStackDefault);
   3191 	break;
   3192     case FcElementFamily:
   3193 	FcParseFamily (parse);
   3194 	break;
   3195 
   3196     case FcElementTest:
   3197 	FcParseTest (parse);
   3198 	break;
   3199     case FcElementEdit:
   3200 	FcParseEdit (parse);
   3201 	break;
   3202 
   3203     case FcElementInt:
   3204 	FcParseInt (parse);
   3205 	break;
   3206     case FcElementDouble:
   3207 	FcParseDouble (parse);
   3208 	break;
   3209     case FcElementString:
   3210 	FcParseString (parse, FcVStackString);
   3211 	break;
   3212     case FcElementMatrix:
   3213 	FcParseMatrix (parse);
   3214 	break;
   3215     case FcElementRange:
   3216 	FcParseRange (parse);
   3217 	break;
   3218     case FcElementBool:
   3219 	FcParseBool (parse);
   3220 	break;
   3221     case FcElementCharSet:
   3222 	FcParseCharSet (parse);
   3223 	break;
   3224     case FcElementLangSet:
   3225 	FcParseLangSet (parse);
   3226 	break;
   3227     case FcElementSelectfont:
   3228 	break;
   3229     case FcElementAcceptfont:
   3230     case FcElementRejectfont:
   3231 	FcParseAcceptRejectFont (parse, parse->pstack->element);
   3232 	break;
   3233     case FcElementGlob:
   3234 	FcParseString (parse, FcVStackGlob);
   3235 	break;
   3236     case FcElementPattern:
   3237 	FcParsePattern (parse);
   3238 	break;
   3239     case FcElementPatelt:
   3240 	FcParsePatelt (parse);
   3241 	break;
   3242     case FcElementName:
   3243 	FcParseName (parse);
   3244 	break;
   3245     case FcElementConst:
   3246 	FcParseString (parse, FcVStackConstant);
   3247 	break;
   3248     case FcElementOr:
   3249 	FcParseBinary (parse, FcOpOr);
   3250 	break;
   3251     case FcElementAnd:
   3252 	FcParseBinary (parse, FcOpAnd);
   3253 	break;
   3254     case FcElementEq:
   3255 	FcParseBinary (parse, FcOpEqual);
   3256 	break;
   3257     case FcElementNotEq:
   3258 	FcParseBinary (parse, FcOpNotEqual);
   3259 	break;
   3260     case FcElementLess:
   3261 	FcParseBinary (parse, FcOpLess);
   3262 	break;
   3263     case FcElementLessEq:
   3264 	FcParseBinary (parse, FcOpLessEqual);
   3265 	break;
   3266     case FcElementMore:
   3267 	FcParseBinary (parse, FcOpMore);
   3268 	break;
   3269     case FcElementMoreEq:
   3270 	FcParseBinary (parse, FcOpMoreEqual);
   3271 	break;
   3272     case FcElementContains:
   3273 	FcParseBinary (parse, FcOpContains);
   3274 	break;
   3275     case FcElementNotContains:
   3276 	FcParseBinary (parse, FcOpNotContains);
   3277 	break;
   3278     case FcElementPlus:
   3279 	FcParseBinary (parse, FcOpPlus);
   3280 	break;
   3281     case FcElementMinus:
   3282 	FcParseBinary (parse, FcOpMinus);
   3283 	break;
   3284     case FcElementTimes:
   3285 	FcParseBinary (parse, FcOpTimes);
   3286 	break;
   3287     case FcElementDivide:
   3288 	FcParseBinary (parse, FcOpDivide);
   3289 	break;
   3290     case FcElementNot:
   3291 	FcParseUnary (parse, FcOpNot);
   3292 	break;
   3293     case FcElementIf:
   3294 	FcParseBinary (parse, FcOpQuest);
   3295 	break;
   3296     case FcElementFloor:
   3297 	FcParseUnary (parse, FcOpFloor);
   3298 	break;
   3299     case FcElementCeil:
   3300 	FcParseUnary (parse, FcOpCeil);
   3301 	break;
   3302     case FcElementRound:
   3303 	FcParseUnary (parse, FcOpRound);
   3304 	break;
   3305     case FcElementTrunc:
   3306 	FcParseUnary (parse, FcOpTrunc);
   3307 	break;
   3308     case FcElementUnknown:
   3309 	break;
   3310     }
   3311     (void) FcPStackPop (parse);
   3312 }
   3313 
   3314 static void
   3315 FcCharacterData (void *userData, const XML_Char *s, int len)
   3316 {
   3317     FcConfigParse   *parse = userData;
   3318 
   3319     if (!parse->pstack)
   3320 	return;
   3321     if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
   3322 	FcConfigMessage (parse, FcSevereError, "out of memory");
   3323 }
   3324 
   3325 static void
   3326 FcStartDoctypeDecl (void	    *userData,
   3327 		    const XML_Char  *doctypeName,
   3328 		    const XML_Char  *sysid FC_UNUSED,
   3329 		    const XML_Char  *pubid FC_UNUSED,
   3330 		    int		    has_internal_subset FC_UNUSED)
   3331 {
   3332     FcConfigParse   *parse = userData;
   3333 
   3334     if (strcmp ((char *) doctypeName, "fontconfig") != 0)
   3335 	FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
   3336 }
   3337 
   3338 #ifdef ENABLE_LIBXML2
   3339 
   3340 static void
   3341 FcInternalSubsetDecl (void            *userData,
   3342 		      const XML_Char  *doctypeName,
   3343 		      const XML_Char  *sysid,
   3344 		      const XML_Char  *pubid)
   3345 {
   3346     FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
   3347 }
   3348 
   3349 static void
   3350 FcExternalSubsetDecl (void            *userData,
   3351 		      const XML_Char  *doctypeName,
   3352 		      const XML_Char  *sysid,
   3353 		      const XML_Char  *pubid)
   3354 {
   3355     FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
   3356 }
   3357 
   3358 #else /* ENABLE_LIBXML2 */
   3359 
   3360 static void
   3361 FcEndDoctypeDecl (void *userData FC_UNUSED)
   3362 {
   3363 }
   3364 
   3365 #endif /* ENABLE_LIBXML2 */
   3366 
   3367 static int
   3368 FcSortCmpStr (const void *a, const void *b)
   3369 {
   3370     const FcChar8    *as = *((FcChar8 **) a);
   3371     const FcChar8    *bs = *((FcChar8 **) b);
   3372     return FcStrCmp (as, bs);
   3373 }
   3374 
   3375 static FcBool
   3376 FcConfigParseAndLoadDir (FcConfig	*config,
   3377 			 const FcChar8	*name,
   3378 			 const FcChar8	*dir,
   3379 			 FcBool		complain,
   3380 			 FcBool		load)
   3381 {
   3382     DIR		    *d;
   3383     struct dirent   *e;
   3384     FcBool	    ret = FcTrue;
   3385     FcChar8	    *file;
   3386     FcChar8	    *base;
   3387     FcStrSet	    *files;
   3388 
   3389     d = opendir ((char *) dir);
   3390     if (!d)
   3391     {
   3392 	if (complain)
   3393 	    FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
   3394 			     name);
   3395 	ret = FcFalse;
   3396 	goto bail0;
   3397     }
   3398     /* freed below */
   3399     file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
   3400     if (!file)
   3401     {
   3402 	ret = FcFalse;
   3403 	goto bail1;
   3404     }
   3405 
   3406     strcpy ((char *) file, (char *) dir);
   3407     strcat ((char *) file, "/");
   3408     base = file + strlen ((char *) file);
   3409 
   3410     files = FcStrSetCreateEx (FCSS_GROW_BY_64);
   3411     if (!files)
   3412     {
   3413 	ret = FcFalse;
   3414 	goto bail2;
   3415     }
   3416 
   3417     if (FcDebug () & FC_DBG_CONFIG)
   3418 	printf ("\tScanning config dir %s\n", dir);
   3419 
   3420     if (load)
   3421 	FcConfigAddConfigDir (config, dir);
   3422 
   3423     while (ret && (e = readdir (d)))
   3424     {
   3425 	int d_len;
   3426 #define TAIL	    ".conf"
   3427 #define TAIL_LEN    5
   3428 	/*
   3429 	 * Add all files of the form [0-9]*.conf
   3430 	 */
   3431 	d_len = strlen (e->d_name);
   3432 	if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
   3433 	    d_len > TAIL_LEN &&
   3434 	    strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
   3435 	{
   3436 	    strcpy ((char *) base, (char *) e->d_name);
   3437 	    if (!FcStrSetAdd (files, file))
   3438 	    {
   3439 		ret = FcFalse;
   3440 		goto bail3;
   3441 	    }
   3442 	}
   3443     }
   3444     if (ret)
   3445     {
   3446 	int i;
   3447 	qsort (files->strs, files->num, sizeof (FcChar8 *),
   3448 	       (int (*)(const void *, const void *)) FcSortCmpStr);
   3449 	for (i = 0; ret && i < files->num; i++)
   3450 	    ret = _FcConfigParse (config, files->strs[i], complain, load);
   3451     }
   3452 bail3:
   3453     FcStrSetDestroy (files);
   3454 bail2:
   3455     free (file);
   3456 bail1:
   3457     closedir (d);
   3458 bail0:
   3459     return ret || !complain;
   3460 }
   3461 
   3462 static FcBool
   3463 FcConfigParseAndLoadFromMemoryInternal (FcConfig       *config,
   3464 					const FcChar8  *filename,
   3465 					const FcChar8  *buffer,
   3466 					FcBool         complain,
   3467 					FcBool         load)
   3468 {
   3469 
   3470     XML_Parser	    p;
   3471     size_t	    len;
   3472     FcConfigParse   parse;
   3473     FcBool	    error = FcTrue;
   3474     FcMatchKind	    k;
   3475     FcPtrListIter   liter;
   3476 
   3477 #ifdef ENABLE_LIBXML2
   3478     xmlSAXHandler   sax;
   3479 #else
   3480     void            *buf;
   3481     const FcChar8   *s;
   3482     size_t	    buflen;
   3483 #endif
   3484 
   3485     if (!buffer)
   3486 	return FcFalse;
   3487     len = strlen ((const char *) buffer);
   3488     if (FcDebug () & FC_DBG_CONFIG)
   3489 	printf ("\t%s config file from %s\n", load ? "Loading" : "Scanning", filename);
   3490 
   3491 #ifdef ENABLE_LIBXML2
   3492     memset(&sax, 0, sizeof(sax));
   3493 
   3494     sax.internalSubset = FcInternalSubsetDecl;
   3495     sax.externalSubset = FcExternalSubsetDecl;
   3496     sax.startElement = FcStartElement;
   3497     sax.endElement = FcEndElement;
   3498     sax.characters = FcCharacterData;
   3499 
   3500     p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
   3501 #else
   3502     p = XML_ParserCreate ("UTF-8");
   3503 #endif
   3504 
   3505     if (!p)
   3506 	goto bail1;
   3507 
   3508     if (!FcConfigParseInit (&parse, filename, config, p, load))
   3509 	goto bail2;
   3510 
   3511 #ifndef ENABLE_LIBXML2
   3512 
   3513     XML_SetUserData (p, &parse);
   3514 
   3515     XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
   3516     XML_SetElementHandler (p, FcStartElement, FcEndElement);
   3517     XML_SetCharacterDataHandler (p, FcCharacterData);
   3518 
   3519 #endif /* ENABLE_LIBXML2 */
   3520 
   3521 #ifndef ENABLE_LIBXML2
   3522     s = buffer;
   3523     do {
   3524 	buf = XML_GetBuffer (p, BUFSIZ);
   3525 	if (!buf)
   3526 	{
   3527 	    FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
   3528 	    goto bail3;
   3529 	}
   3530 	if (len > BUFSIZ)
   3531 	{
   3532 	    buflen = BUFSIZ;
   3533 	    len -= BUFSIZ;
   3534 	}
   3535 	else
   3536 	{
   3537 	    buflen = len;
   3538 	    len = 0;
   3539 	}
   3540 	memcpy (buf, s, buflen);
   3541 	s = s + buflen;
   3542 #endif
   3543 
   3544 #ifdef ENABLE_LIBXML2
   3545 	if (xmlParseChunk (p, (const char *)buffer, len, len == 0))
   3546 #else
   3547 	if (!XML_ParseBuffer (p, buflen, buflen == 0))
   3548 #endif
   3549 	{
   3550 	    FcConfigMessage (&parse, FcSevereError, "%s",
   3551 			   XML_ErrorString (XML_GetErrorCode (p)));
   3552 	    goto bail3;
   3553 	}
   3554 #ifndef ENABLE_LIBXML2
   3555     } while (buflen != 0);
   3556 #endif
   3557     error = parse.error;
   3558     if (load)
   3559     {
   3560 	for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
   3561 	{
   3562 	    FcPtrListIter iter;
   3563 
   3564 	    FcPtrListIterInit (parse.ruleset->subst[k], &iter);
   3565 	    if (FcPtrListIterIsValid (parse.ruleset->subst[k], &iter))
   3566 	    {
   3567 		FcPtrListIterInitAtLast (parse.config->subst[k], &iter);
   3568 		FcRuleSetReference (parse.ruleset);
   3569 		FcPtrListIterAdd (parse.config->subst[k], &iter, parse.ruleset);
   3570 	    }
   3571 	}
   3572     }
   3573     FcPtrListIterInitAtLast (parse.config->rulesetList, &liter);
   3574     FcRuleSetReference (parse.ruleset);
   3575     FcPtrListIterAdd (parse.config->rulesetList, &liter, parse.ruleset);
   3576 bail3:
   3577     FcConfigCleanup (&parse);
   3578 bail2:
   3579     XML_ParserFree (p);
   3580 bail1:
   3581     if (error && complain)
   3582     {
   3583 	FcConfigMessage (0, FcSevereError, "Cannot %s config file from %s", load ? "load" : "scan", filename);
   3584 	return FcFalse;
   3585     }
   3586     if (FcDebug () & FC_DBG_CONFIG)
   3587 	printf ("\t%s config file from %s done\n", load ? "Loading" : "Scanning", filename);
   3588     return FcTrue;
   3589 }
   3590 
   3591 static FcBool
   3592 _FcConfigParse (FcConfig	*config,
   3593 		const FcChar8	*name,
   3594 		FcBool		complain,
   3595 		FcBool		load)
   3596 {
   3597     FcChar8	    *filename = NULL, *realfilename = NULL;
   3598     int		    fd;
   3599     int		    len;
   3600     FcStrBuf	    sbuf;
   3601     char            buf[BUFSIZ];
   3602     FcBool	    ret = FcFalse, complain_again = complain;
   3603     FcStrBuf	    reason;
   3604 
   3605     FcStrBufInit (&reason, NULL, 0);
   3606 #ifdef _WIN32
   3607     _ensureWin32GettersReady();
   3608 #endif
   3609 
   3610     filename = FcConfigGetFilename (config, name);
   3611     if (!filename)
   3612     {
   3613 	FcStrBufString (&reason, (FcChar8 *)"No such file: ");
   3614 	FcStrBufString (&reason, name ? name : (FcChar8 *)"(null)");
   3615 	goto bail0;
   3616     }
   3617     realfilename = FcConfigRealFilename (config, name);
   3618     if (!realfilename)
   3619     {
   3620 	FcStrBufString (&reason, (FcChar8 *)"No such realfile: ");
   3621 	FcStrBufString (&reason, name ? name : (FcChar8 *)"(null)");
   3622 	goto bail0;
   3623     }
   3624     if (FcStrSetMember (config->availConfigFiles, realfilename))
   3625     {
   3626         FcStrFree (filename);
   3627 	FcStrFree (realfilename);
   3628         return FcTrue;
   3629     }
   3630 
   3631     if (load)
   3632     {
   3633 	if (!FcStrSetAdd (config->configFiles, filename))
   3634 	    goto bail0;
   3635     }
   3636     if (!FcStrSetAdd (config->availConfigFiles, realfilename))
   3637 	goto bail0;
   3638 
   3639     if (FcFileIsDir (realfilename))
   3640     {
   3641 	ret = FcConfigParseAndLoadDir (config, name, realfilename, complain, load);
   3642 	FcStrFree (filename);
   3643 	FcStrFree (realfilename);
   3644 	return ret;
   3645     }
   3646 
   3647     FcStrBufInit (&sbuf, NULL, 0);
   3648 
   3649     fd = FcOpen ((char *) realfilename, O_RDONLY);
   3650     if (fd == -1)
   3651     {
   3652 	FcStrBufString (&reason, (FcChar8 *)"Unable to open ");
   3653 	FcStrBufString (&reason, realfilename);
   3654 	goto bail1;
   3655     }
   3656 
   3657     do {
   3658 	len = read (fd, buf, BUFSIZ);
   3659 	if (len < 0)
   3660 	{
   3661 	    int errno_ = errno;
   3662 	    char ebuf[BUFSIZ+1];
   3663 
   3664 #if HAVE_STRERROR_R
   3665 	    strerror_r (errno_, ebuf, BUFSIZ);
   3666 #elif HAVE_STRERROR
   3667 	    char *tmp = strerror (errno_);
   3668 	    size_t len = strlen (tmp);
   3669 	    memcpy (ebuf, tmp, FC_MIN (BUFSIZ, len));
   3670 	    ebuf[FC_MIN (BUFSIZ, len)] = 0;
   3671 #else
   3672 	    ebuf[0] = 0;
   3673 #endif
   3674 	    FcConfigMessage (0, FcSevereError, "failed reading config file: %s: %s (errno %d)", realfilename, ebuf, errno_);
   3675 	    close (fd);
   3676 	    goto bail1;
   3677 	}
   3678 	FcStrBufData (&sbuf, (const FcChar8 *)buf, len);
   3679     } while (len != 0);
   3680     close (fd);
   3681 
   3682     ret = FcConfigParseAndLoadFromMemoryInternal (config, filename, FcStrBufDoneStatic (&sbuf), complain, load);
   3683     complain_again = FcFalse; /* no need to reclaim here */
   3684 bail1:
   3685     FcStrBufDestroy (&sbuf);
   3686 bail0:
   3687     if (filename)
   3688 	FcStrFree (filename);
   3689     if (realfilename)
   3690 	FcStrFree (realfilename);
   3691     if (!complain)
   3692     {
   3693 	FcStrBufDestroy (&reason);
   3694 	return FcTrue;
   3695     }
   3696     if (!ret && complain_again)
   3697     {
   3698 	if (name)
   3699 	    FcConfigMessage (0, FcSevereError, "Cannot %s config file \"%s\": %s", load ? "load" : "scan", name, FcStrBufDoneStatic (&reason));
   3700 	else
   3701 	    FcConfigMessage (0, FcSevereError, "Cannot %s default config file: %s", load ? "load" : "scan", FcStrBufDoneStatic (&reason));
   3702 	FcStrBufDestroy (&reason);
   3703 	return FcFalse;
   3704     }
   3705     FcStrBufDestroy (&reason);
   3706     return ret;
   3707 }
   3708 
   3709 FcBool
   3710 FcConfigParseOnly (FcConfig		*config,
   3711 		   const FcChar8	*name,
   3712 		   FcBool		complain)
   3713 {
   3714     return _FcConfigParse (config, name, complain, FcFalse);
   3715 }
   3716 
   3717 FcBool
   3718 FcConfigParseAndLoad (FcConfig	    *config,
   3719 		      const FcChar8 *name,
   3720 		      FcBool	    complain)
   3721 {
   3722     return _FcConfigParse (config, name, complain, FcTrue);
   3723 }
   3724 
   3725 FcBool
   3726 FcConfigParseAndLoadFromMemory (FcConfig       *config,
   3727 				const FcChar8  *buffer,
   3728 				FcBool         complain)
   3729 {
   3730     return FcConfigParseAndLoadFromMemoryInternal (config, (const FcChar8 *)"memory", buffer, complain, FcTrue);
   3731 }
   3732 
   3733 #ifdef _WIN32
   3734 static void
   3735 _ensureWin32GettersReady()
   3736 {
   3737     if (!pGetSystemWindowsDirectory)
   3738     {
   3739         HMODULE hk32 = GetModuleHandleA("kernel32.dll");
   3740         if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory)GetProcAddress(hk32, "GetSystemWindowsDirectoryA")))
   3741             pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory)GetWindowsDirectory;
   3742     }
   3743     if (!pSHGetFolderPathA)
   3744     {
   3745         HMODULE hSh = LoadLibraryA("shfolder.dll");
   3746         /* the check is done later, because there is no provided fallback */
   3747         if (hSh)
   3748             pSHGetFolderPathA = (pfnSHGetFolderPathA)GetProcAddress(hSh, "SHGetFolderPathA");
   3749     }
   3750 }
   3751 #endif // _WIN32
   3752 
   3753 #define __fcxml__
   3754 #include "fcaliastail.h"
   3755 #undef __fcxml__
   3756