2 * $RCSId: xc/lib/fontconfig/src/fccfg.c,v 1.23 2002/08/31 22:17:32 keithp Exp $
4 * Copyright © 2000 Keith Packard
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 Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Keith Packard makes no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD 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.
27 #include <sys/types.h>
29 #if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT))
35 #if defined (_WIN32) && !defined (R_OK)
47 config = malloc (sizeof (FcConfig));
50 FcMemAlloc (FC_MEM_CONFIG, sizeof (FcConfig));
52 config->configDirs = FcStrSetCreate ();
53 if (!config->configDirs)
56 config->configFiles = FcStrSetCreate ();
57 if (!config->configFiles)
60 config->fontDirs = FcStrSetCreate ();
61 if (!config->fontDirs)
64 config->acceptGlobs = FcStrSetCreate ();
65 if (!config->acceptGlobs)
68 config->rejectGlobs = FcStrSetCreate ();
69 if (!config->rejectGlobs)
72 config->acceptPatterns = FcFontSetCreate ();
73 if (!config->acceptPatterns)
76 config->rejectPatterns = FcFontSetCreate ();
77 if (!config->rejectPatterns)
80 config->cacheDirs = FcStrSetCreate ();
81 if (!config->cacheDirs)
86 config->substPattern = 0;
87 config->substFont = 0;
88 config->maxObjects = 0;
89 for (set = FcSetSystem; set <= FcSetApplication; set++)
90 config->fonts[set] = 0;
92 config->caches = NULL;
94 config->rescanTime = time(0);
95 config->rescanInterval = 30;
100 FcFontSetDestroy (config->rejectPatterns);
102 FcFontSetDestroy (config->acceptPatterns);
104 FcStrSetDestroy (config->rejectGlobs);
106 FcStrSetDestroy (config->acceptGlobs);
108 FcStrSetDestroy (config->fontDirs);
110 FcStrSetDestroy (config->configFiles);
112 FcStrSetDestroy (config->configDirs);
115 FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
121 FcConfigNewestFile (FcStrSet *files)
123 FcStrList *list = FcStrListCreate (files);
124 FcFileTime newest = { 0, FcFalse };
130 while ((file = FcStrListNext (list)))
131 if (stat ((char *) file, &statb) == 0)
132 if (!newest.set || statb.st_mtime - newest.time > 0)
135 newest.time = statb.st_mtime;
137 FcStrListDone (list);
143 FcConfigModifiedTime (FcConfig *config)
147 FcFileTime v = { 0, FcFalse };
148 config = FcConfigGetCurrent ();
152 return FcConfigNewestFile (config->configFiles);
156 FcConfigUptoDate (FcConfig *config)
158 FcFileTime config_time, font_time;
159 time_t now = time(0);
162 config = FcConfigGetCurrent ();
166 config_time = FcConfigNewestFile (config->configFiles);
167 font_time = FcConfigNewestFile (config->fontDirs);
168 if ((config_time.set && config_time.time - config->rescanTime > 0) ||
169 (font_time.set && (font_time.time - config->rescanTime) > 0))
173 config->rescanTime = now;
178 FcSubstDestroy (FcSubst *s)
186 FcTestDestroy (s->test);
188 FcEditDestroy (s->edit);
190 FcMemFree (FC_MEM_SUBST, sizeof (FcSubst));
196 FcConfigDestroy (FcConfig *config)
199 FcCacheList *cl, *cl_next;
201 if (config == _fcConfig)
204 FcStrSetDestroy (config->configDirs);
205 FcStrSetDestroy (config->fontDirs);
206 FcStrSetDestroy (config->cacheDirs);
207 FcStrSetDestroy (config->configFiles);
208 FcStrSetDestroy (config->acceptGlobs);
209 FcStrSetDestroy (config->rejectGlobs);
210 FcFontSetDestroy (config->acceptPatterns);
211 FcFontSetDestroy (config->rejectPatterns);
214 FcBlanksDestroy (config->blanks);
216 FcSubstDestroy (config->substPattern);
217 FcSubstDestroy (config->substFont);
218 for (set = FcSetSystem; set <= FcSetApplication; set++)
219 if (config->fonts[set])
220 FcFontSetDestroy (config->fonts[set]);
222 for (cl = config->caches; cl; cl = cl_next)
225 FcDirCacheUnload (cl->cache);
230 FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
234 * Add cache to configuration, adding fonts and directories
238 FcConfigAddCache (FcConfig *config, FcCache *cache)
240 FcCacheList *cl = malloc (sizeof (FcCacheList));
251 cl->next = config->caches;
257 fs = FcCacheSet (cache);
260 for (i = 0; i < fs->nfont; i++)
262 FcPattern *font = FcFontSetFont (fs, i);
266 * Check to see if font is banned by filename
268 if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
269 0, &font_file) == FcResultMatch &&
270 !FcConfigAcceptFilename (config, font_file))
276 * Check to see if font is banned by pattern
278 if (!FcConfigAcceptFont (config, font))
281 FcFontSetAdd (config->fonts[FcSetSystem], font);
288 dirs = FcCacheDirs (cache);
291 for (i = 0; i < cache->dirs_count; i++)
293 FcChar8 *dir = FcOffsetToPtr (dirs, dirs[i], FcChar8);
294 if (FcConfigAcceptFilename (config, dir))
295 FcConfigAddFontDir (config, dir);
302 * Scan the current list of directories in the configuration
303 * and build the set of available fonts.
307 FcConfigBuildFonts (FcConfig *config)
316 config = FcConfigGetCurrent ();
321 fonts = FcFontSetCreate ();
325 FcConfigSetFonts (config, fonts, FcSetSystem);
327 dirlist = FcStrListCreate (config->fontDirs);
331 while ((dir = FcStrListNext (dirlist)))
333 if (FcDebug () & FC_DBG_FONTSET)
334 printf ("adding fonts from%s\n", dir);
335 cache = FcDirCacheRead (dir, FcFalse, config);
338 FcConfigAddCache (config, cache);
341 FcStrListDone (dirlist);
343 if (FcDebug () & FC_DBG_FONTSET)
344 FcFontSetPrint (fonts);
352 FcConfigSetCurrent (FcConfig *config)
355 if (!FcConfigBuildFonts (config))
359 FcConfigDestroy (_fcConfig);
365 FcConfigGetCurrent (void)
374 FcConfigAddConfigDir (FcConfig *config,
377 return FcStrSetAddFilename (config->configDirs, d);
381 FcConfigGetConfigDirs (FcConfig *config)
385 config = FcConfigGetCurrent ();
389 return FcStrListCreate (config->configDirs);
393 FcConfigAddFontDir (FcConfig *config,
396 return FcStrSetAddFilename (config->fontDirs, d);
400 FcConfigAddDir (FcConfig *config,
403 return (FcConfigAddConfigDir (config, d) &&
404 FcConfigAddFontDir (config, d));
408 FcConfigGetFontDirs (FcConfig *config)
412 config = FcConfigGetCurrent ();
416 return FcStrListCreate (config->fontDirs);
420 FcConfigAddCacheDir (FcConfig *config,
423 return FcStrSetAddFilename (config->cacheDirs, d);
427 FcConfigGetCacheDirs (FcConfig *config)
431 config = FcConfigGetCurrent ();
435 return FcStrListCreate (config->cacheDirs);
439 FcConfigAddConfigFile (FcConfig *config,
443 FcChar8 *file = FcConfigFilename (f);
448 ret = FcStrSetAdd (config->configFiles, file);
454 FcConfigGetConfigFiles (FcConfig *config)
458 config = FcConfigGetCurrent ();
462 return FcStrListCreate (config->configFiles);
466 FcConfigGetCache (FcConfig *config)
472 FcConfigGetFonts (FcConfig *config,
477 config = FcConfigGetCurrent ();
481 return config->fonts[set];
485 FcConfigSetFonts (FcConfig *config,
489 if (config->fonts[set])
490 FcFontSetDestroy (config->fonts[set]);
491 config->fonts[set] = fonts;
495 FcConfigGetBlanks (FcConfig *config)
499 config = FcConfigGetCurrent ();
503 return config->blanks;
507 FcConfigAddBlank (FcConfig *config,
510 FcBlanks *b, *freeme = 0;
515 freeme = b = FcBlanksCreate ();
519 if (!FcBlanksAdd (b, blank))
522 FcBlanksDestroy (freeme);
530 FcConfigGetRescanInverval (FcConfig *config)
534 config = FcConfigGetCurrent ();
538 return config->rescanInterval;
542 FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
546 config = FcConfigGetCurrent ();
550 config->rescanInterval = rescanInterval;
555 FcConfigAddEdit (FcConfig *config,
560 FcSubst *subst, **prev;
564 subst = (FcSubst *) malloc (sizeof (FcSubst));
567 FcMemAlloc (FC_MEM_SUBST, sizeof (FcSubst));
568 if (kind == FcMatchPattern)
569 prev = &config->substPattern;
571 prev = &config->substFont;
572 for (; *prev; prev = &(*prev)->next);
578 for (t = test; t; t = t->next)
580 if (t->kind == FcMatchDefault)
584 if (config->maxObjects < num)
585 config->maxObjects = num;
586 if (FcDebug () & FC_DBG_EDIT)
588 printf ("Add Subst ");
589 FcSubstPrint (subst);
594 typedef struct _FcSubState {
600 FcConfigPromote (FcValue v, FcValue u)
602 if (v.type == FcTypeInteger)
604 v.type = FcTypeDouble;
605 v.u.d = (double) v.u.i;
607 else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
609 v.u.m = &FcIdentityMatrix;
610 v.type = FcTypeMatrix;
612 else if (v.type == FcTypeString && u.type == FcTypeLangSet)
614 v.u.l = FcLangSetPromote (v.u.s);
615 v.type = FcTypeLangSet;
621 FcConfigCompareValue (const FcValue *left_o,
623 const FcValue *right_o)
625 FcValue left = FcValueCanonicalize(left_o);
626 FcValue right = FcValueCanonicalize(right_o);
627 FcBool ret = FcFalse;
629 left = FcConfigPromote (left, right);
630 right = FcConfigPromote (right, left);
631 if (left.type == right.type)
635 break; /* FcConfigPromote prevents this from happening */
641 ret = left.u.d == right.u.d;
644 case FcOpNotContains:
645 ret = left.u.d != right.u.d;
648 ret = left.u.d < right.u.d;
651 ret = left.u.d <= right.u.d;
654 ret = left.u.d > right.u.d;
657 ret = left.u.d >= right.u.d;
668 ret = left.u.b == right.u.b;
671 case FcOpNotContains:
672 ret = left.u.b != right.u.b;
682 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
685 ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
688 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
690 case FcOpNotContains:
691 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
702 ret = FcMatrixEqual (left.u.m, right.u.m);
705 case FcOpNotContains:
706 ret = !FcMatrixEqual (left.u.m, right.u.m);
716 /* left contains right if right is a subset of left */
717 ret = FcCharSetIsSubset (right.u.c, left.u.c);
719 case FcOpNotContains:
720 /* left contains right if right is a subset of left */
721 ret = !FcCharSetIsSubset (right.u.c, left.u.c);
724 ret = FcCharSetEqual (left.u.c, right.u.c);
727 ret = !FcCharSetEqual (left.u.c, right.u.c);
737 ret = FcLangSetContains (left.u.l, right.u.l);
739 case FcOpNotContains:
740 ret = !FcLangSetContains (left.u.l, right.u.l);
743 ret = FcLangSetEqual (left.u.l, right.u.l);
746 ret = !FcLangSetEqual (left.u.l, right.u.l);
768 ret = left.u.f == right.u.f;
771 case FcOpNotContains:
772 ret = left.u.f != right.u.f;
782 if (op == FcOpNotEqual || op == FcOpNotContains)
789 #define _FcDoubleFloor(d) ((int) (d))
790 #define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
791 #define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
792 #define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
793 #define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5)
794 #define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
797 FcConfigEvaluate (FcPattern *p, FcExpr *e)
806 v.type = FcTypeInteger;
810 v.type = FcTypeDouble;
814 v.type = FcTypeString;
815 v.u.s = FcStrStaticName(e->u.sval);
818 v.type = FcTypeMatrix;
823 v.type = FcTypeCharSet;
832 r = FcPatternObjectGet (p, e->u.object, 0, &v);
833 if (r != FcResultMatch)
838 if (FcNameConstant (e->u.constant, &v.u.i))
839 v.type = FcTypeInteger;
844 vl = FcConfigEvaluate (p, e->u.tree.left);
845 if (vl.type == FcTypeBool)
848 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
850 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
863 case FcOpNotContains:
865 vl = FcConfigEvaluate (p, e->u.tree.left);
866 vr = FcConfigEvaluate (p, e->u.tree.right);
868 v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
878 vl = FcConfigEvaluate (p, e->u.tree.left);
879 vr = FcConfigEvaluate (p, e->u.tree.right);
880 vl = FcConfigPromote (vl, vr);
881 vr = FcConfigPromote (vr, vl);
882 if (vl.type == vr.type)
888 v.type = FcTypeDouble;
889 v.u.d = vl.u.d + vr.u.d;
892 v.type = FcTypeDouble;
893 v.u.d = vl.u.d - vr.u.d;
896 v.type = FcTypeDouble;
897 v.u.d = vl.u.d * vr.u.d;
900 v.type = FcTypeDouble;
901 v.u.d = vl.u.d / vr.u.d;
907 if (v.type == FcTypeDouble &&
908 v.u.d == (double) (int) v.u.d)
910 v.type = FcTypeInteger;
918 v.u.b = vl.u.b || vr.u.b;
922 v.u.b = vl.u.b && vr.u.b;
932 v.type = FcTypeString;
933 str = FcStrPlus (vl.u.s, vr.u.s);
934 v.u.s = FcStrStaticName (str);
948 v.type = FcTypeMatrix;
949 m = malloc (sizeof (FcMatrix));
952 FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
953 FcMatrixMultiply (m, vl.u.m, vr.u.m);
977 vl = FcConfigEvaluate (p, e->u.tree.left);
990 vl = FcConfigEvaluate (p, e->u.tree.left);
996 v.type = FcTypeInteger;
997 v.u.i = FcDoubleFloor (vl.u.d);
1000 v.type = FcTypeVoid;
1003 FcValueDestroy (vl);
1006 vl = FcConfigEvaluate (p, e->u.tree.left);
1012 v.type = FcTypeInteger;
1013 v.u.i = FcDoubleCeil (vl.u.d);
1016 v.type = FcTypeVoid;
1019 FcValueDestroy (vl);
1022 vl = FcConfigEvaluate (p, e->u.tree.left);
1028 v.type = FcTypeInteger;
1029 v.u.i = FcDoubleRound (vl.u.d);
1032 v.type = FcTypeVoid;
1035 FcValueDestroy (vl);
1038 vl = FcConfigEvaluate (p, e->u.tree.left);
1044 v.type = FcTypeInteger;
1045 v.u.i = FcDoubleTrunc (vl.u.d);
1048 v.type = FcTypeVoid;
1051 FcValueDestroy (vl);
1054 v.type = FcTypeVoid;
1060 static FcValueList *
1061 FcConfigMatchValueList (FcPattern *p,
1063 FcValueList *values)
1065 FcValueList *ret = 0;
1066 FcExpr *e = t->expr;
1072 /* Compute the value of the match expression */
1073 if (e->op == FcOpComma)
1075 value = FcConfigEvaluate (p, e->u.tree.left);
1076 e = e->u.tree.right;
1080 value = FcConfigEvaluate (p, e);
1084 for (v = values; v; v = FcValueListNext(v))
1086 /* Compare the pattern value to the match expression value */
1087 if (FcConfigCompareValue (&v->value, t->op, &value))
1094 if (t->qual == FcQualAll)
1101 FcValueDestroy (value);
1106 static FcValueList *
1107 FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding)
1113 l = (FcValueList *) malloc (sizeof (FcValueList));
1116 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
1117 if (e->op == FcOpComma)
1119 l->value = FcConfigEvaluate (p, e->u.tree.left);
1120 l->next = FcConfigValues (p, e->u.tree.right, binding);
1124 l->value = FcConfigEvaluate (p, e);
1127 l->binding = binding;
1128 if (l->value.type == FcTypeVoid)
1130 FcValueList *next = FcValueListNext(l);
1132 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
1141 FcConfigAdd (FcValueListPtr *head,
1142 FcValueList *position,
1146 FcValueListPtr *prev, last, v;
1147 FcValueBinding sameBinding;
1150 sameBinding = position->binding;
1152 sameBinding = FcValueBindingWeak;
1153 for (v = new; v != NULL; v = FcValueListNext(v))
1154 if (v->binding == FcValueBindingSame)
1155 v->binding = sameBinding;
1159 prev = &position->next;
1161 for (prev = head; *prev != NULL;
1162 prev = &(*prev)->next)
1169 for (prev = head; *prev != NULL;
1170 prev = &(*prev)->next)
1172 if (*prev == position)
1179 if (FcDebug () & FC_DBG_EDIT)
1182 printf ("position not on list\n");
1186 if (FcDebug () & FC_DBG_EDIT)
1188 printf ("%s list before ", append ? "Append" : "Prepend");
1189 FcValueListPrint (*head);
1196 while (last->next != NULL)
1203 if (FcDebug () & FC_DBG_EDIT)
1205 printf ("%s list after ", append ? "Append" : "Prepend");
1206 FcValueListPrint (*head);
1214 FcConfigDel (FcValueListPtr *head,
1215 FcValueList *position)
1217 FcValueListPtr *prev;
1219 for (prev = head; *prev != NULL; prev = &(*prev)->next)
1221 if (*prev == position)
1223 *prev = position->next;
1224 position->next = NULL;
1225 FcValueListDestroy (position);
1232 FcConfigPatternAdd (FcPattern *p,
1239 FcPatternElt *e = FcPatternObjectInsertElt (p, object);
1243 FcConfigAdd (&e->values, 0, append, list);
1248 * Delete all values associated with a field
1251 FcConfigPatternDel (FcPattern *p,
1254 FcPatternElt *e = FcPatternObjectFindElt (p, object);
1257 while (e->values != NULL)
1258 FcConfigDel (&e->values, e->values);
1262 FcConfigPatternCanon (FcPattern *p,
1265 FcPatternElt *e = FcPatternObjectFindElt (p, object);
1268 if (e->values == NULL)
1269 FcPatternObjectDel (p, object);
1273 FcConfigSubstituteWithPat (FcConfig *config,
1288 config = FcConfigGetCurrent ();
1293 st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
1294 if (!st && config->maxObjects)
1296 FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1298 if (FcDebug () & FC_DBG_EDIT)
1300 printf ("FcConfigSubstitute ");
1303 if (kind == FcMatchPattern)
1304 s = config->substPattern;
1306 s = config->substFont;
1307 for (; s; s = s->next)
1310 * Check the tests to see if
1311 * they all match the pattern
1313 for (t = s->test, i = 0; t; t = t->next, i++)
1315 if (FcDebug () & FC_DBG_EDIT)
1317 printf ("FcConfigSubstitute test ");
1321 if (kind == FcMatchFont && t->kind == FcMatchPattern)
1326 st[i].elt = FcPatternObjectFindElt (m, t->object);
1330 * If there's no such field in the font,
1331 * then FcQualAll matches while FcQualAny does not
1335 if (t->qual == FcQualAll)
1344 * Check to see if there is a match, mark the location
1345 * to apply match-relative edits
1347 st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values);
1350 if (t->qual == FcQualFirst && st[i].value != st[i].elt->values)
1352 if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values)
1357 if (FcDebug () & FC_DBG_EDIT)
1358 printf ("No match\n");
1361 if (FcDebug () & FC_DBG_EDIT)
1363 printf ("Substitute ");
1366 for (e = s->edit; e; e = e->next)
1369 * Evaluate the list of expressions
1371 l = FcConfigValues (p, e->expr, e->binding);
1373 * Locate any test associated with this field, skipping
1374 * tests associated with the pattern when substituting in
1377 for (t = s->test, i = 0; t; t = t->next, i++)
1379 if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
1380 t->object == e->object)
1383 * KLUDGE - the pattern may have been reallocated or
1384 * things may have been inserted or deleted above
1385 * this element by other edits. Go back and find
1388 if (e != s->edit && st[i].elt)
1389 st[i].elt = FcPatternObjectFindElt (p, t->object);
1398 * If there was a test, then replace the matched
1399 * value with the new list of values
1403 FcValueList *thisValue = st[i].value;
1404 FcValueList *nextValue = thisValue;
1407 * Append the new list of values after the current value
1409 FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
1411 * Delete the marked value
1414 FcConfigDel (&st[i].elt->values, thisValue);
1416 * Adjust any pointers into the value list to ensure
1417 * future edits occur at the same place
1419 for (t = s->test, i = 0; t; t = t->next, i++)
1421 if (st[i].value == thisValue)
1422 st[i].value = nextValue;
1426 /* fall through ... */
1427 case FcOpAssignReplace:
1429 * Delete all of the values and insert
1432 FcConfigPatternDel (p, e->object);
1433 FcConfigPatternAdd (p, e->object, l, FcTrue);
1435 * Adjust any pointers into the value list as they no
1436 * longer point to anything valid
1440 FcPatternElt *thisElt = st[i].elt;
1441 for (t = s->test, i = 0; t; t = t->next, i++)
1443 if (st[i].elt == thisElt)
1451 FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
1454 /* fall through ... */
1455 case FcOpPrependFirst:
1456 FcConfigPatternAdd (p, e->object, l, FcFalse);
1461 FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
1464 /* fall through ... */
1465 case FcOpAppendLast:
1466 FcConfigPatternAdd (p, e->object, l, FcTrue);
1469 FcValueListDestroy (l);
1474 * Now go through the pattern and eliminate
1475 * any properties without data
1477 for (e = s->edit; e; e = e->next)
1478 FcConfigPatternCanon (p, e->object);
1480 if (FcDebug () & FC_DBG_EDIT)
1482 printf ("FcConfigSubstitute edit");
1486 FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1488 if (FcDebug () & FC_DBG_EDIT)
1490 printf ("FcConfigSubstitute done");
1497 FcConfigSubstitute (FcConfig *config,
1501 return FcConfigSubstituteWithPat (config, p, 0, kind);
1504 #if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT))
1506 static FcChar8 fontconfig_path[1000] = "";
1509 DllMain (HINSTANCE hinstDLL,
1515 switch (fdwReason) {
1516 case DLL_PROCESS_ATTACH:
1517 if (!GetModuleFileName ((HMODULE) hinstDLL, fontconfig_path,
1518 sizeof (fontconfig_path)))
1521 /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
1522 * assume it's a Unix-style installation tree, and use
1523 * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
1524 * folder where the DLL is as FONTCONFIG_PATH.
1526 p = strrchr (fontconfig_path, '\\');
1530 p = strrchr (fontconfig_path, '\\');
1531 if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 ||
1532 FcStrCmpIgnoreCase (p + 1, "lib") == 0))
1534 strcat (fontconfig_path, "\\etc\\fonts");
1537 fontconfig_path[0] = '\0';
1545 #undef FONTCONFIG_PATH
1546 #define FONTCONFIG_PATH fontconfig_path
1548 #else /* !(_WIN32 && PIC) */
1550 #endif /* !(_WIN32 && PIC) */
1552 #ifndef FONTCONFIG_FILE
1553 #define FONTCONFIG_FILE "fonts.conf"
1557 FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
1562 dir = (FcChar8 *) "";
1563 path = malloc (strlen ((char *) dir) + 1 + strlen ((char *) file) + 1);
1567 strcpy ((char *) path, (const char *) dir);
1568 /* make sure there's a single separator */
1570 if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
1571 path[strlen((char *) path)-1] != '\\')) &&
1574 (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
1575 strcat ((char *) path, "\\");
1577 if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
1578 strcat ((char *) path, "/");
1580 strcat ((char *) path, (char *) file);
1582 FcMemAlloc (FC_MEM_STRING, strlen ((char *) path) + 1);
1583 if (access ((char *) path, R_OK) == 0)
1591 FcConfigGetPath (void)
1594 FcChar8 *env, *e, *colon;
1599 npath = 2; /* default dir + null */
1600 env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
1606 if (*e++ == FC_SEARCH_PATH_SEPARATOR)
1609 path = calloc (npath, sizeof (FcChar8 *));
1619 colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
1621 colon = e + strlen ((char *) e);
1622 path[i] = malloc (colon - e + 1);
1625 strncpy ((char *) path[i], (const char *) e, colon - e);
1626 path[i][colon - e] = '\0';
1635 dir = (FcChar8 *) FONTCONFIG_PATH;
1636 path[i] = malloc (strlen ((char *) dir) + 1);
1639 strcpy ((char *) path[i], (const char *) dir);
1643 for (i = 0; path[i]; i++)
1651 FcConfigFreePath (FcChar8 **path)
1655 for (p = path; *p; p++)
1660 static FcBool _FcConfigHomeEnabled = FcTrue;
1665 if (_FcConfigHomeEnabled)
1667 char *home = getenv ("HOME");
1671 home = getenv ("USERPROFILE");
1674 return (FcChar8 *) home;
1680 FcConfigEnableHome (FcBool enable)
1682 FcBool prev = _FcConfigHomeEnabled;
1683 _FcConfigHomeEnabled = enable;
1688 FcConfigFilename (const FcChar8 *url)
1690 FcChar8 *file, *dir, **path, **p;
1694 url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
1696 url = (FcChar8 *) FONTCONFIG_FILE;
1701 if (isalpha (*url) &&
1703 (url[2] == '/' || url[2] == '\\'))
1709 dir = FcConfigHome ();
1711 file = FcConfigFileExists (dir, url + 1);
1720 file = FcConfigFileExists (0, url);
1723 path = FcConfigGetPath ();
1726 for (p = path; *p; p++)
1728 file = FcConfigFileExists (*p, url);
1732 FcConfigFreePath (path);
1739 * Manage the application-specific fonts
1743 FcConfigAppFontAddFile (FcConfig *config,
1744 const FcChar8 *file)
1753 config = FcConfigGetCurrent ();
1758 subdirs = FcStrSetCreate ();
1762 set = FcConfigGetFonts (config, FcSetApplication);
1765 set = FcFontSetCreate ();
1768 FcStrSetDestroy (subdirs);
1771 FcConfigSetFonts (config, set, FcSetApplication);
1774 if (!FcFileScanConfig (set, subdirs, config->blanks, file, config))
1776 FcStrSetDestroy (subdirs);
1779 if ((sublist = FcStrListCreate (subdirs)))
1781 while ((subdir = FcStrListNext (sublist)))
1783 FcConfigAppFontAddDir (config, subdir);
1785 FcStrListDone (sublist);
1787 FcStrSetDestroy (subdirs);
1792 FcConfigAppFontAddDir (FcConfig *config,
1802 config = FcConfigGetCurrent ();
1806 subdirs = FcStrSetCreate ();
1810 set = FcConfigGetFonts (config, FcSetApplication);
1813 set = FcFontSetCreate ();
1816 FcStrSetDestroy (subdirs);
1819 FcConfigSetFonts (config, set, FcSetApplication);
1822 if (!FcDirScanConfig (set, subdirs, config->blanks, dir, FcFalse, config))
1824 FcStrSetDestroy (subdirs);
1827 if ((sublist = FcStrListCreate (subdirs)))
1829 while ((subdir = FcStrListNext (sublist)))
1831 FcConfigAppFontAddDir (config, subdir);
1833 FcStrListDone (sublist);
1835 FcStrSetDestroy (subdirs);
1840 FcConfigAppFontClear (FcConfig *config)
1844 config = FcConfigGetCurrent ();
1849 FcConfigSetFonts (config, 0, FcSetApplication);
1853 * Manage filename-based font source selectors
1857 FcConfigGlobAdd (FcConfig *config,
1858 const FcChar8 *glob,
1861 FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs;
1863 return FcStrSetAdd (set, glob);
1867 FcConfigGlobMatch (const FcChar8 *glob,
1868 const FcChar8 *string)
1872 while ((c = *glob++))
1876 /* short circuit common case */
1879 /* short circuit another common case */
1880 if (strchr ((char *) glob, '*') == 0)
1881 string += strlen ((char *) string) - strlen ((char *) glob);
1884 if (FcConfigGlobMatch (glob, string))
1890 if (*string++ == '\0')
1899 return *string == '\0';
1903 FcConfigGlobsMatch (const FcStrSet *globs,
1904 const FcChar8 *string)
1908 for (i = 0; i < globs->num; i++)
1909 if (FcConfigGlobMatch (globs->strs[i], string))
1915 FcConfigAcceptFilename (FcConfig *config,
1916 const FcChar8 *filename)
1918 if (FcConfigGlobsMatch (config->acceptGlobs, filename))
1920 if (FcConfigGlobsMatch (config->rejectGlobs, filename))
1926 * Manage font-pattern based font source selectors
1930 FcConfigPatternsAdd (FcConfig *config,
1934 FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns;
1936 return FcFontSetAdd (set, pattern);
1940 FcConfigPatternsMatch (const FcFontSet *patterns,
1941 const FcPattern *font)
1945 for (i = 0; i < patterns->nfont; i++)
1946 if (FcListPatternMatchAny (patterns->fonts[i], font))
1952 FcConfigAcceptFont (FcConfig *config,
1953 const FcPattern *font)
1955 if (FcConfigPatternsMatch (config->acceptPatterns, font))
1957 if (FcConfigPatternsMatch (config->rejectPatterns, font))