+ if (!FcConfigAddEdit (parse->config, test, edit, kind))
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+}
+
+static void
+FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
+{
+ FcVStack *vstack;
+
+ while ((vstack = FcVStackPeek (parse)))
+ {
+ switch (vstack->tag) {
+ case FcVStackGlob:
+ if (!FcConfigGlobAdd (parse->config,
+ vstack->u.string,
+ element == FcElementAcceptfont))
+ {
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+ }
+ break;
+ case FcVStackPattern:
+ if (!FcConfigPatternsAdd (parse->config,
+ vstack->u.pattern,
+ element == FcElementAcceptfont))
+ {
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+ }
+ else
+ vstack->tag = FcVStackNone;
+ break;
+ default:
+ FcConfigMessage (parse, FcSevereWarning, "bad font selector");
+ break;
+ }
+ FcVStackPopAndDestroy (parse);
+ }
+}
+
+
+static FcValue
+FcPopValue (FcConfigParse *parse)
+{
+ FcVStack *vstack = FcVStackPeek (parse);
+ FcValue value;
+
+ value.type = FcTypeVoid;
+
+ if (!vstack)
+ return value;
+
+ switch (vstack->tag) {
+ case FcVStackString:
+ value.u.s = FcStrCopy (vstack->u.string);
+ if (value.u.s)
+ value.type = FcTypeString;
+ break;
+ case FcVStackConstant:
+ if (FcNameConstant (vstack->u.string, &value.u.i))
+ value.type = FcTypeInteger;
+ break;
+ case FcVStackInteger:
+ value.u.i = vstack->u.integer;
+ value.type = FcTypeInteger;
+ break;
+ case FcVStackDouble:
+ value.u.d = vstack->u._double;
+ value.type = FcTypeInteger;
+ break;
+ case FcVStackMatrix:
+ value.u.m = FcMatrixCopy (vstack->u.matrix);
+ if (value.u.m)
+ value.type = FcTypeMatrix;
+ break;
+ case FcVStackBool:
+ value.u.b = vstack->u.bool_;
+ value.type = FcTypeBool;
+ break;
+ default:
+ FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
+ vstack->tag);
+ break;
+ }
+ FcVStackPopAndDestroy (parse);
+
+ return value;
+}
+
+static void
+FcParsePatelt (FcConfigParse *parse)
+{
+ FcValue value;
+ FcPattern *pattern = FcPatternCreate ();
+ const char *name;
+
+ if (!pattern)
+ {
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+ return;
+ }
+
+ name = (char *) FcConfigGetAttribute (parse, "name");
+ if (!name)
+ {
+ FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
+ FcPatternDestroy (pattern);
+ return;
+ }
+
+ for (;;)
+ {
+ value = FcPopValue (parse);
+ if (value.type == FcTypeVoid)
+ break;
+ if (!FcPatternAdd (pattern, name, value, FcTrue))
+ {
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+ FcValueDestroy(value);
+ break;
+ }
+ FcValueDestroy(value);
+ }
+
+ FcVStackPushPattern (parse, pattern);
+}
+
+static void
+FcParsePattern (FcConfigParse *parse)
+{
+ FcVStack *vstack;
+ FcPattern *pattern = FcPatternCreate ();
+
+ if (!pattern)
+ {
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+ return;
+ }
+
+ while ((vstack = FcVStackPeek (parse)))
+ {
+ switch (vstack->tag) {
+ case FcVStackPattern:
+ if (!FcPatternAppend (pattern, vstack->u.pattern))
+ {
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+ FcPatternDestroy (pattern);
+ return;
+ }
+ break;
+ default:
+ FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
+ break;
+ }
+ FcVStackPopAndDestroy (parse);
+ }
+
+ FcVStackPushPattern (parse, pattern);
+}
+
+static void
+FcEndElement(void *userData, const XML_Char *name)
+{
+ FcConfigParse *parse = userData;
+ FcChar8 *data;
+
+ if (!parse->pstack)
+ return;
+ switch (parse->pstack->element) {
+ case FcElementNone:
+ break;
+ case FcElementFontconfig:
+ break;
+ case FcElementDir:
+ data = FcStrBufDoneStatic (&parse->pstack->str);
+ if (!data)
+ {
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+ break;
+ }
+#ifdef _WIN32
+ if (strcmp (data, "CUSTOMFONTDIR") == 0)
+ {
+ char *p;
+ FcStrFree (data);
+ data = malloc (1000);
+ if (!data)
+ {
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+ break;
+ }
+ FcMemAlloc (FC_MEM_STRING, 1000);
+ if(!GetModuleFileName(NULL, data, 1000))
+ {
+ FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
+ FcStrFree (data);
+ break;
+ }
+ p = strrchr (data, '\\');
+ if (p) *p = '\0';
+ strcat (data, "\\fonts");
+ }
+ else if (strcmp (data, "APPSHAREFONTDIR") == 0)
+ {
+ char *p;
+ FcStrFree (data);
+ data = malloc (1000);
+ if (!data)
+ {
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+ break;
+ }
+ FcMemAlloc (FC_MEM_STRING, 1000);
+ if(!GetModuleFileName(NULL, data, 1000))
+ {
+ FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
+ FcStrFree (data);
+ break;
+ }
+ p = strrchr (data, '\\');
+ if (p) *p = '\0';
+ strcat (data, "\\..\\share\\fonts");
+ }
+ else if (strcmp (data, "WINDOWSFONTDIR") == 0)
+ {
+ int rc;
+ FcStrFree (data);
+ data = malloc (1000);
+ if (!data)
+ {
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+ break;
+ }
+ FcMemAlloc (FC_MEM_STRING, 1000);
+ rc = GetWindowsDirectory (data, 800);
+ if (rc == 0 || rc > 800)
+ {
+ FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
+ FcStrFree (data);
+ break;
+ }
+ if (data [strlen (data) - 1] != '\\')
+ strcat (data, "\\");
+ strcat (data, "fonts");
+ }
+#endif
+ if (strlen ((char *) data) == 0)
+ FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
+ else if (!FcStrUsesHome (data) || FcConfigHome ())
+ {
+ if (!FcConfigAddDir (parse->config, data))
+ FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
+ }
+ FcStrBufDestroy (&parse->pstack->str);
+ break;
+ case FcElementCacheDir:
+ data = FcStrBufDone (&parse->pstack->str);
+ if (!data)
+ {
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+ break;
+ }
+#ifdef _WIN32
+ if (strcmp (data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
+ {
+ int rc;
+ FcStrFree (data);
+ data = malloc (1000);
+ if (!data)
+ {
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+ break;
+ }
+ FcMemAlloc (FC_MEM_STRING, 1000);
+ rc = GetTempPath (800, data);
+ if (rc == 0 || rc > 800)
+ {
+ FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
+ FcStrFree (data);
+ break;
+ }
+ if (data [strlen (data) - 1] != '\\')
+ strcat (data, "\\");
+ strcat (data, "fontconfig\\cache");
+ }
+#endif
+ if (!FcStrUsesHome (data) || FcConfigHome ())
+ {
+ if (!FcConfigAddCacheDir (parse->config, data))
+ FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
+ }
+ FcStrFree (data);
+ break;
+
+ case FcElementCache:
+ data = FcStrBufDoneStatic (&parse->pstack->str);
+ if (!data)
+ {
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+ break;
+ }
+ /* discard this data; no longer used */
+ FcStrBufDestroy (&parse->pstack->str);
+ break;
+ case FcElementInclude:
+ FcParseInclude (parse);
+ break;
+ case FcElementConfig:
+ break;
+ case FcElementMatch:
+ FcParseMatch (parse);
+ break;
+ case FcElementAlias:
+ FcParseAlias (parse);
+ break;
+
+ case FcElementBlank:
+ FcParseBlank (parse);
+ break;
+ case FcElementRescan:
+ FcParseRescan (parse);
+ break;
+
+ case FcElementPrefer:
+ FcParseFamilies (parse, FcVStackPrefer);
+ break;
+ case FcElementAccept:
+ FcParseFamilies (parse, FcVStackAccept);
+ break;
+ case FcElementDefault:
+ FcParseFamilies (parse, FcVStackDefault);
+ break;
+ case FcElementFamily:
+ FcParseFamily (parse);
+ break;
+
+ case FcElementTest:
+ FcParseTest (parse);
+ break;
+ case FcElementEdit:
+ FcParseEdit (parse);
+ break;
+
+ case FcElementInt:
+ FcParseInt (parse);
+ break;
+ case FcElementDouble:
+ FcParseDouble (parse);
+ break;
+ case FcElementString:
+ FcParseString (parse, FcVStackString);
+ break;
+ case FcElementMatrix:
+ FcParseMatrix (parse);
+ break;
+ case FcElementBool:
+ FcParseBool (parse);
+ break;
+ case FcElementCharset:
+/* FcParseCharset (parse); */
+ break;
+ case FcElementSelectfont:
+ break;
+ case FcElementAcceptfont:
+ case FcElementRejectfont:
+ FcParseAcceptRejectFont (parse, parse->pstack->element);
+ break;
+ case FcElementGlob:
+ FcParseString (parse, FcVStackGlob);
+ break;
+ case FcElementPattern:
+ FcParsePattern (parse);
+ break;
+ case FcElementPatelt:
+ FcParsePatelt (parse);
+ break;
+ case FcElementName:
+ FcParseString (parse, FcVStackField);
+ break;
+ case FcElementConst:
+ FcParseString (parse, FcVStackConstant);
+ break;
+ case FcElementOr:
+ FcParseBinary (parse, FcOpOr);
+ break;
+ case FcElementAnd:
+ FcParseBinary (parse, FcOpAnd);
+ break;
+ case FcElementEq:
+ FcParseBinary (parse, FcOpEqual);
+ break;
+ case FcElementNotEq:
+ FcParseBinary (parse, FcOpNotEqual);
+ break;
+ case FcElementLess:
+ FcParseBinary (parse, FcOpLess);
+ break;
+ case FcElementLessEq:
+ FcParseBinary (parse, FcOpLessEqual);
+ break;
+ case FcElementMore:
+ FcParseBinary (parse, FcOpMore);
+ break;
+ case FcElementMoreEq:
+ FcParseBinary (parse, FcOpMoreEqual);
+ break;
+ case FcElementContains:
+ FcParseBinary (parse, FcOpContains);
+ break;
+ case FcElementNotContains:
+ FcParseBinary (parse, FcOpNotContains);
+ break;
+ case FcElementPlus:
+ FcParseBinary (parse, FcOpPlus);
+ break;
+ case FcElementMinus:
+ FcParseBinary (parse, FcOpMinus);
+ break;
+ case FcElementTimes:
+ FcParseBinary (parse, FcOpTimes);
+ break;
+ case FcElementDivide:
+ FcParseBinary (parse, FcOpDivide);
+ break;
+ case FcElementNot:
+ FcParseUnary (parse, FcOpNot);
+ break;
+ case FcElementIf:
+ FcParseBinary (parse, FcOpQuest);
+ break;
+ case FcElementFloor:
+ FcParseUnary (parse, FcOpFloor);
+ break;
+ case FcElementCeil:
+ FcParseUnary (parse, FcOpCeil);
+ break;
+ case FcElementRound:
+ FcParseUnary (parse, FcOpRound);
+ break;
+ case FcElementTrunc:
+ FcParseUnary (parse, FcOpTrunc);
+ break;
+ case FcElementUnknown:
+ break;
+ }
+ (void) FcPStackPop (parse);
+}
+
+static void
+FcCharacterData (void *userData, const XML_Char *s, int len)
+{
+ FcConfigParse *parse = userData;
+
+ if (!parse->pstack)
+ return;
+ if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+}
+
+static void
+FcStartDoctypeDecl (void *userData,
+ const XML_Char *doctypeName,
+ const XML_Char *sysid,
+ const XML_Char *pubid,
+ int has_internal_subset)
+{
+ FcConfigParse *parse = userData;
+
+ if (strcmp ((char *) doctypeName, "fontconfig") != 0)
+ FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
+}
+
+#ifdef ENABLE_LIBXML2
+
+static void
+FcInternalSubsetDecl (void *userData,
+ const XML_Char *doctypeName,
+ const XML_Char *sysid,
+ const XML_Char *pubid)
+{
+ FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
+}
+
+static void
+FcExternalSubsetDecl (void *userData,
+ const XML_Char *doctypeName,
+ const XML_Char *sysid,
+ const XML_Char *pubid)
+{
+ FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
+}
+
+#else /* ENABLE_LIBXML2 */
+
+static void
+FcEndDoctypeDecl (void *userData)
+{
+}
+
+#endif /* ENABLE_LIBXML2 */
+
+static int
+FcSortCmpStr (const void *a, const void *b)
+{
+ const FcChar8 *as = *((FcChar8 **) a);
+ const FcChar8 *bs = *((FcChar8 **) b);
+ return FcStrCmp (as, bs);
+}
+
+static FcBool
+FcConfigParseAndLoadDir (FcConfig *config,
+ const FcChar8 *name,
+ const FcChar8 *dir,
+ FcBool complain)
+{
+ DIR *d;
+ struct dirent *e;
+ FcBool ret = FcTrue;
+ FcChar8 *file;
+ FcChar8 *base;
+ FcStrSet *files;
+
+ d = opendir ((char *) dir);
+ if (!d)
+ {
+ if (complain)
+ FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
+ name);
+ ret = FcFalse;
+ goto bail0;
+ }
+ /* freed below */
+ file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
+ if (!file)
+ {
+ ret = FcFalse;
+ goto bail1;
+ }
+
+ strcpy ((char *) file, (char *) dir);
+ strcat ((char *) file, "/");
+ base = file + strlen ((char *) file);
+
+ files = FcStrSetCreate ();
+ if (!files)
+ {
+ ret = FcFalse;
+ goto bail2;
+ }
+
+ if (FcDebug () & FC_DBG_CONFIG)
+ printf ("\tScanning config dir %s\n", dir);
+
+ while (ret && (e = readdir (d)))
+ {
+ int d_len;
+#define TAIL ".conf"
+#define TAIL_LEN 5
+ /*
+ * Add all files of the form [0-9]*.conf
+ */
+ if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
+ (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
+ d_len > TAIL_LEN &&
+ strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
+ {
+ strcpy ((char *) base, (char *) e->d_name);
+ if (!FcStrSetAdd (files, file))
+ {
+ ret = FcFalse;
+ goto bail3;
+ }
+ }
+ }
+ if (ret)
+ {
+ int i;
+ qsort (files->strs, files->num, sizeof (FcChar8 *),
+ (int (*)(const void *, const void *)) FcSortCmpStr);
+ for (i = 0; ret && i < files->num; i++)
+ ret = FcConfigParseAndLoad (config, files->strs[i], complain);
+ }
+bail3:
+ FcStrSetDestroy (files);
+bail2:
+ free (file);
+bail1:
+ closedir (d);
+bail0:
+ return ret || !complain;