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.
26 #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)
82 if (!FcConfigSetCache (config, (FcChar8 *) ("~/" FC_USER_CACHE_FILE)))
86 if (config->cache == 0)
88 /* If no home, use the temp folder. */
90 int templen = GetTempPath (1, dummy);
91 FcChar8 *temp = malloc (templen + 1);
97 GetTempPath (templen + 1, temp);
98 cache_dir = FcStrPlus (temp, FC_USER_CACHE_FILE);
100 if (!FcConfigSetCache (config, cache_dir))
102 FcStrFree (cache_dir);
105 FcStrFree (cache_dir);
112 config->substPattern = 0;
113 config->substFont = 0;
114 config->maxObjects = 0;
115 for (set = FcSetSystem; set <= FcSetApplication; set++)
116 config->fonts[set] = 0;
118 config->rescanTime = time(0);
119 config->rescanInterval = 30;
124 FcFontSetDestroy (config->rejectPatterns);
126 FcFontSetDestroy (config->acceptPatterns);
128 FcStrSetDestroy (config->rejectGlobs);
130 FcStrSetDestroy (config->acceptGlobs);
132 FcStrSetDestroy (config->fontDirs);
134 FcStrSetDestroy (config->configFiles);
136 FcStrSetDestroy (config->configDirs);
139 FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
145 FcConfigNewestFile (FcStrSet *files)
147 FcStrList *list = FcStrListCreate (files);
148 FcFileTime newest = { 0, FcFalse };
154 while ((file = FcStrListNext (list)))
155 if (stat ((char *) file, &statb) == 0)
156 if (!newest.set || statb.st_mtime - newest.time > 0)
159 newest.time = statb.st_mtime;
161 FcStrListDone (list);
167 FcConfigModifiedTime (FcConfig *config)
171 FcFileTime v = { 0, FcFalse };
172 config = FcConfigGetCurrent ();
176 return FcConfigNewestFile (config->configFiles);
180 FcConfigUptoDate (FcConfig *config)
182 FcFileTime config_time, font_time;
183 time_t now = time(0);
186 config = FcConfigGetCurrent ();
190 config_time = FcConfigNewestFile (config->configFiles);
191 font_time = FcConfigNewestFile (config->fontDirs);
192 if ((config_time.set && config_time.time - config->rescanTime > 0) ||
193 (font_time.set && (font_time.time - config->rescanTime) > 0))
197 config->rescanTime = now;
202 FcSubstDestroy (FcSubst *s)
210 FcTestDestroy (s->test);
212 FcEditDestroy (s->edit);
214 FcMemFree (FC_MEM_SUBST, sizeof (FcSubst));
220 FcConfigDestroy (FcConfig *config)
224 if (config == _fcConfig)
227 FcStrSetDestroy (config->configDirs);
228 FcStrSetDestroy (config->fontDirs);
229 FcStrSetDestroy (config->configFiles);
230 FcStrSetDestroy (config->acceptGlobs);
231 FcStrSetDestroy (config->rejectGlobs);
232 FcFontSetDestroy (config->acceptPatterns);
233 FcFontSetDestroy (config->rejectPatterns);
236 FcBlanksDestroy (config->blanks);
239 FcStrFree (config->cache);
241 FcSubstDestroy (config->substPattern);
242 FcSubstDestroy (config->substFont);
243 for (set = FcSetSystem; set <= FcSetApplication; set++)
244 if (config->fonts[set])
245 FcFontSetDestroy (config->fonts[set]);
248 FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
252 * Scan the current list of directories in the configuration
253 * and build the set of available fonts. Update the
254 * per-user cache file to reflect the new configuration
258 FcConfigBuildFonts (FcConfig *config)
260 FcFontSet *fonts, *cached_fonts;
261 FcGlobalCache *cache;
266 fonts = FcFontSetCreate ();
270 cache = FcGlobalCacheCreate ();
274 oldDirs = FcStrSetCreate ();
279 FcGlobalCacheLoad (cache, oldDirs, config->cache, config);
281 cached_fonts = FcCacheRead(config, cache);
284 list = FcConfigGetFontDirs (config);
288 while ((dir = FcStrListNext (list)))
290 if (FcDebug () & FC_DBG_FONTSET)
291 printf ("build scan dir %s\n", dir);
292 FcDirScanConfig (fonts, config->fontDirs, cache,
293 config->blanks, dir, FcFalse, config);
296 FcStrListDone (list);
302 for (i = 0; i < oldDirs->num; i++)
304 if (FcDebug () & FC_DBG_FONTSET)
305 printf ("scan dir %s\n", oldDirs->strs[i]);
306 FcDirScanConfig (fonts, config->fontDirs, cache,
307 config->blanks, oldDirs->strs[i],
311 for (i = 0; i < cached_fonts->nfont; i++)
314 FcPatternGetString (cached_fonts->fonts[i], FC_FILE, 0, &cfn);
316 if (FcConfigAcceptFont (config, cached_fonts->fonts[i]) &&
317 (cfn && FcConfigAcceptFilename (config, cfn)))
318 FcFontSetAdd (fonts, cached_fonts->fonts[i]);
320 cached_fonts->fonts[i] = 0; /* prevent free in FcFontSetDestroy */
322 cached_fonts->nfont = 0;
323 FcFontSetDestroy (cached_fonts);
326 if (FcDebug () & FC_DBG_FONTSET)
327 FcFontSetPrint (fonts);
330 FcGlobalCacheSave (cache, config->cache, config);
331 FcGlobalCacheDestroy (cache);
332 FcStrSetDestroy (oldDirs);
334 FcConfigSetFonts (config, fonts, FcSetSystem);
338 FcStrSetDestroy (oldDirs);
340 FcFontSetDestroy (fonts);
346 FcConfigSetCurrent (FcConfig *config)
349 if (!FcConfigBuildFonts (config))
353 FcConfigDestroy (_fcConfig);
359 FcConfigGetCurrent (void)
368 FcConfigAddConfigDir (FcConfig *config,
371 return FcStrSetAddFilename (config->configDirs, d);
375 FcConfigGetConfigDirs (FcConfig *config)
379 config = FcConfigGetCurrent ();
383 return FcStrListCreate (config->configDirs);
387 FcConfigAddFontDir (FcConfig *config,
390 return FcStrSetAddFilename (config->fontDirs, d);
394 FcConfigAddFontDirSubdirs (FcConfig *config,
401 if (!(dir = opendir ((char *) d)))
403 if (!(subdir = (FcChar8 *) malloc (strlen ((char *) d) + FC_MAX_FILE_LEN + 2)))
405 fprintf (stderr, "out of memory");
408 while ((e = readdir (dir)))
410 if (strcmp (e->d_name, ".") && strcmp (e->d_name, "..") &&
411 strlen (e->d_name) < FC_MAX_FILE_LEN)
413 strcpy ((char *)subdir, (char *)d);
414 strcat ((char *)subdir, "/");
415 strcat ((char *)subdir, e->d_name);
416 if (FcFileIsDir (subdir))
418 FcConfigAddFontDir (config, subdir);
419 FcConfigAddFontDirSubdirs (config, subdir);
429 FcConfigNormalizeFontDir (FcConfig *config,
432 /* If this is a bottleneck, we can cache the fontDir inodes. */
438 if (stat ((char *)d, &s) == -1)
440 di = s.st_ino; dd = s.st_dev;
442 for (n = 0; n < config->fontDirs->num; n++)
444 if (stat ((char *)config->fontDirs->strs[n], &s) == -1)
446 if (di == s.st_ino && dd == s.st_dev)
447 return config->fontDirs->strs[n];
450 /* Ok, we didn't find it in fontDirs; let's add subdirs.... */
451 for (n = 0, n0 = config->fontDirs->num; n < n0; n++)
452 FcConfigAddFontDirSubdirs (config, config->fontDirs->strs[n]);
454 /* ... and try again. */
455 for (n = 0; n < config->fontDirs->num; n++)
457 if (stat ((char *)config->fontDirs->strs[n], &s) == -1)
459 if (di == s.st_ino && dd == s.st_dev)
460 return config->fontDirs->strs[n];
463 /* if it fails, then really give up. */
468 FcConfigAddDir (FcConfig *config,
471 return (FcConfigAddConfigDir (config, d) &&
472 FcConfigAddFontDir (config, d));
476 FcConfigGetFontDirs (FcConfig *config)
480 config = FcConfigGetCurrent ();
484 return FcStrListCreate (config->fontDirs);
488 FcConfigAddConfigFile (FcConfig *config,
492 FcChar8 *file = FcConfigFilename (f);
497 ret = FcStrSetAdd (config->configFiles, file);
503 FcConfigGetConfigFiles (FcConfig *config)
507 config = FcConfigGetCurrent ();
511 return FcStrListCreate (config->configFiles);
515 FcConfigSetCache (FcConfig *config,
518 FcChar8 *new = FcStrCopyFilename (c);
523 FcStrFree (config->cache);
529 FcConfigGetCache (FcConfig *config)
533 config = FcConfigGetCurrent ();
537 return config->cache;
541 FcConfigGetFonts (FcConfig *config,
546 config = FcConfigGetCurrent ();
550 return config->fonts[set];
554 FcConfigSetFonts (FcConfig *config,
558 if (config->fonts[set])
559 FcFontSetDestroy (config->fonts[set]);
560 config->fonts[set] = fonts;
566 FcConfigGetBlanks (FcConfig *config)
570 config = FcConfigGetCurrent ();
574 return config->blanks;
578 FcConfigAddBlank (FcConfig *config,
586 b = FcBlanksCreate ();
590 if (!FcBlanksAdd (b, blank))
597 FcConfigGetRescanInverval (FcConfig *config)
601 config = FcConfigGetCurrent ();
605 return config->rescanInterval;
609 FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
613 config = FcConfigGetCurrent ();
617 config->rescanInterval = rescanInterval;
622 FcConfigAddEdit (FcConfig *config,
627 FcSubst *subst, **prev;
631 subst = (FcSubst *) malloc (sizeof (FcSubst));
634 FcMemAlloc (FC_MEM_SUBST, sizeof (FcSubst));
635 if (kind == FcMatchPattern)
636 prev = &config->substPattern;
638 prev = &config->substFont;
639 for (; *prev; prev = &(*prev)->next);
645 for (t = test; t; t = t->next)
647 if (t->kind == FcMatchDefault)
651 if (config->maxObjects < num)
652 config->maxObjects = num;
653 if (FcDebug () & FC_DBG_EDIT)
655 printf ("Add Subst ");
656 FcSubstPrint (subst);
661 typedef struct _FcSubState {
667 FcConfigPromote (FcValue v, FcValue u)
669 if (v.type == FcTypeInteger)
671 v.type = FcTypeDouble;
672 v.u.d = (double) v.u.i;
674 else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
676 v.u.m = &FcIdentityMatrix;
677 v.type = FcTypeMatrix;
679 else if (v.type == FcTypeString && u.type == FcTypeLangSet)
681 v.u.l = FcLangSetPromote (v.u.s);
682 v.type = FcTypeLangSet;
688 FcConfigCompareValue (const FcValue *left_o,
690 const FcValue *right_o)
692 FcValue left = FcValueCanonicalize(left_o);
693 FcValue right = FcValueCanonicalize(right_o);
694 FcBool ret = FcFalse;
696 left = FcConfigPromote (left, right);
697 right = FcConfigPromote (right, left);
698 if (left.type == right.type)
702 break; /* FcConfigPromote prevents this from happening */
708 ret = left.u.d == right.u.d;
711 case FcOpNotContains:
712 ret = left.u.d != right.u.d;
715 ret = left.u.d < right.u.d;
718 ret = left.u.d <= right.u.d;
721 ret = left.u.d > right.u.d;
724 ret = left.u.d >= right.u.d;
735 ret = left.u.b == right.u.b;
738 case FcOpNotContains:
739 ret = left.u.b != right.u.b;
749 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
752 ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
755 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
757 case FcOpNotContains:
758 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
769 ret = FcMatrixEqual (left.u.m, right.u.m);
772 case FcOpNotContains:
773 ret = !FcMatrixEqual (left.u.m, right.u.m);
783 /* left contains right if right is a subset of left */
784 ret = FcCharSetIsSubset (right.u.c, left.u.c);
786 case FcOpNotContains:
787 /* left contains right if right is a subset of left */
788 ret = !FcCharSetIsSubset (right.u.c, left.u.c);
791 ret = FcCharSetEqual (left.u.c, right.u.c);
794 ret = !FcCharSetEqual (left.u.c, right.u.c);
804 ret = FcLangSetContains (left.u.l, right.u.l);
806 case FcOpNotContains:
807 ret = !FcLangSetContains (left.u.l, right.u.l);
810 ret = FcLangSetEqual (left.u.l, right.u.l);
813 ret = !FcLangSetEqual (left.u.l, right.u.l);
835 ret = left.u.f == right.u.f;
838 case FcOpNotContains:
839 ret = left.u.f != right.u.f;
849 if (op == FcOpNotEqual || op == FcOpNotContains)
856 #define _FcDoubleFloor(d) ((int) (d))
857 #define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
858 #define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
859 #define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
860 #define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5)
861 #define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
864 FcConfigEvaluate (FcPattern *p, FcExpr *e)
872 v.type = FcTypeInteger;
876 v.type = FcTypeDouble;
880 v.type = FcTypeString;
881 v.u.s = FcStrStaticName(e->u.sval);
884 v.type = FcTypeMatrix;
889 v.type = FcTypeCharSet;
898 r = FcPatternGet (p, e->u.field, 0, &v);
899 if (r != FcResultMatch)
904 if (FcNameConstant (e->u.constant, &v.u.i))
905 v.type = FcTypeInteger;
910 vl = FcConfigEvaluate (p, e->u.tree.left);
911 if (vl.type == FcTypeBool)
914 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
916 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
929 case FcOpNotContains:
931 vl = FcConfigEvaluate (p, e->u.tree.left);
932 vr = FcConfigEvaluate (p, e->u.tree.right);
934 v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
944 vl = FcConfigEvaluate (p, e->u.tree.left);
945 vr = FcConfigEvaluate (p, e->u.tree.right);
946 vl = FcConfigPromote (vl, vr);
947 vr = FcConfigPromote (vr, vl);
948 if (vl.type == vr.type)
954 v.type = FcTypeDouble;
955 v.u.d = vl.u.d + vr.u.d;
958 v.type = FcTypeDouble;
959 v.u.d = vl.u.d - vr.u.d;
962 v.type = FcTypeDouble;
963 v.u.d = vl.u.d * vr.u.d;
966 v.type = FcTypeDouble;
967 v.u.d = vl.u.d / vr.u.d;
973 if (v.type == FcTypeDouble &&
974 v.u.d == (double) (int) v.u.d)
976 v.type = FcTypeInteger;
984 v.u.b = vl.u.b || vr.u.b;
988 v.u.b = vl.u.b && vr.u.b;
998 v.type = FcTypeString;
999 v.u.s = FcStrStaticName (FcStrPlus (vl.u.s, vr.u.s));
1002 v.type = FcTypeVoid;
1005 v.type = FcTypeVoid;
1012 v.type = FcTypeMatrix;
1013 m = malloc (sizeof (FcMatrix));
1016 FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
1017 FcMatrixMultiply (m, vl.u.m, vr.u.m);
1022 v.type = FcTypeVoid;
1026 v.type = FcTypeVoid;
1031 v.type = FcTypeVoid;
1036 v.type = FcTypeVoid;
1037 FcValueDestroy (vl);
1038 FcValueDestroy (vr);
1041 vl = FcConfigEvaluate (p, e->u.tree.left);
1044 v.type = FcTypeBool;
1048 v.type = FcTypeVoid;
1051 FcValueDestroy (vl);
1054 vl = FcConfigEvaluate (p, e->u.tree.left);
1060 v.type = FcTypeInteger;
1061 v.u.i = FcDoubleFloor (vl.u.d);
1064 v.type = FcTypeVoid;
1067 FcValueDestroy (vl);
1070 vl = FcConfigEvaluate (p, e->u.tree.left);
1076 v.type = FcTypeInteger;
1077 v.u.i = FcDoubleCeil (vl.u.d);
1080 v.type = FcTypeVoid;
1083 FcValueDestroy (vl);
1086 vl = FcConfigEvaluate (p, e->u.tree.left);
1092 v.type = FcTypeInteger;
1093 v.u.i = FcDoubleRound (vl.u.d);
1096 v.type = FcTypeVoid;
1099 FcValueDestroy (vl);
1102 vl = FcConfigEvaluate (p, e->u.tree.left);
1108 v.type = FcTypeInteger;
1109 v.u.i = FcDoubleTrunc (vl.u.d);
1112 v.type = FcTypeVoid;
1115 FcValueDestroy (vl);
1118 v.type = FcTypeVoid;
1124 static FcValueList *
1125 FcConfigMatchValueList (FcPattern *p,
1127 FcValueList *values)
1129 FcValueList *ret = 0;
1130 FcExpr *e = t->expr;
1136 /* Compute the value of the match expression */
1137 if (e->op == FcOpComma)
1139 value = FcConfigEvaluate (p, e->u.tree.left);
1140 e = e->u.tree.right;
1144 value = FcConfigEvaluate (p, e);
1148 for (v = values; v; v = FcValueListPtrU(v->next))
1150 /* Compare the pattern value to the match expression value */
1151 if (FcConfigCompareValue (&v->value, t->op, &value))
1158 if (t->qual == FcQualAll)
1165 FcValueDestroy (value);
1170 static FcValueList *
1171 FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding)
1177 l = (FcValueList *) malloc (sizeof (FcValueList));
1180 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
1181 if (e->op == FcOpComma)
1183 l->value = FcConfigEvaluate (p, e->u.tree.left);
1184 l->next = FcValueListPtrCreateDynamic(FcConfigValues (p, e->u.tree.right, binding));
1188 l->value = FcConfigEvaluate (p, e);
1189 l->next = FcValueListPtrCreateDynamic(0);
1191 l->binding = binding;
1192 if (l->value.type == FcTypeVoid)
1194 FcValueList *next = FcValueListPtrU(l->next);
1196 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
1205 FcConfigAdd (FcValueListPtr *head,
1206 FcValueList *position,
1210 FcValueListPtr *prev, last, v;
1211 FcValueBinding sameBinding;
1214 sameBinding = position->binding;
1216 sameBinding = FcValueBindingWeak;
1217 for (v = FcValueListPtrCreateDynamic(new); FcValueListPtrU(v);
1218 v = FcValueListPtrU(v)->next)
1219 if (FcValueListPtrU(v)->binding == FcValueBindingSame)
1220 FcValueListPtrU(v)->binding = sameBinding;
1224 prev = &position->next;
1226 for (prev = head; FcValueListPtrU(*prev);
1227 prev = &(FcValueListPtrU(*prev)->next))
1234 for (prev = head; FcValueListPtrU(*prev);
1235 prev = &(FcValueListPtrU(*prev)->next))
1237 if (FcValueListPtrU(*prev) == position)
1244 if (FcDebug () & FC_DBG_EDIT)
1246 if (!FcValueListPtrU(*prev))
1247 printf ("position not on list\n");
1251 if (FcDebug () & FC_DBG_EDIT)
1253 printf ("%s list before ", append ? "Append" : "Prepend");
1254 FcValueListPrint (*head);
1260 last = FcValueListPtrCreateDynamic(new);
1261 while (FcValueListPtrU(FcValueListPtrU(last)->next))
1262 last = FcValueListPtrU(last)->next;
1264 FcValueListPtrU(last)->next = *prev;
1265 *prev = FcValueListPtrCreateDynamic(new);
1268 if (FcDebug () & FC_DBG_EDIT)
1270 printf ("%s list after ", append ? "Append" : "Prepend");
1271 FcValueListPrint (*head);
1279 FcConfigDel (FcValueListPtr *head,
1280 FcValueList *position)
1282 FcValueListPtr *prev;
1284 for (prev = head; FcValueListPtrU(*prev);
1285 prev = &(FcValueListPtrU(*prev)->next))
1287 if (FcValueListPtrU(*prev) == position)
1289 *prev = position->next;
1290 position->next = FcValueListPtrCreateDynamic(0);
1291 FcValueListDestroy (FcValueListPtrCreateDynamic(position));
1298 FcConfigPatternAdd (FcPattern *p,
1305 FcPatternElt *e = FcPatternInsertElt (p, object);
1309 FcConfigAdd (&e->values, 0, append, list);
1314 * Delete all values associated with a field
1317 FcConfigPatternDel (FcPattern *p,
1320 FcPatternElt *e = FcPatternFindElt (p, object);
1323 while (FcValueListPtrU(e->values))
1324 FcConfigDel (&e->values, FcValueListPtrU(e->values));
1328 FcConfigPatternCanon (FcPattern *p,
1331 FcPatternElt *e = FcPatternFindElt (p, object);
1334 if (!FcValueListPtrU(e->values))
1335 FcPatternDel (p, object);
1339 FcConfigSubstituteWithPat (FcConfig *config,
1354 config = FcConfigGetCurrent ();
1359 st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
1360 if (!st && config->maxObjects)
1362 FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1364 if (FcDebug () & FC_DBG_EDIT)
1366 printf ("FcConfigSubstitute ");
1369 if (kind == FcMatchPattern)
1370 s = config->substPattern;
1372 s = config->substFont;
1373 for (; s; s = s->next)
1376 * Check the tests to see if
1377 * they all match the pattern
1379 for (t = s->test, i = 0; t; t = t->next, i++)
1381 if (FcDebug () & FC_DBG_EDIT)
1383 printf ("FcConfigSubstitute test ");
1387 if (kind == FcMatchFont && t->kind == FcMatchPattern)
1392 st[i].elt = FcPatternFindElt (m, t->field);
1396 * If there's no such field in the font,
1397 * then FcQualAll matches while FcQualAny does not
1401 if (t->qual == FcQualAll)
1410 * Check to see if there is a match, mark the location
1411 * to apply match-relative edits
1413 st[i].value = FcConfigMatchValueList (m, t, FcValueListPtrU(st[i].elt->values));
1416 if (t->qual == FcQualFirst && st[i].value != FcValueListPtrU(st[i].elt->values))
1418 if (t->qual == FcQualNotFirst && st[i].value == FcValueListPtrU(st[i].elt->values))
1423 if (FcDebug () & FC_DBG_EDIT)
1424 printf ("No match\n");
1427 if (FcDebug () & FC_DBG_EDIT)
1429 printf ("Substitute ");
1432 for (e = s->edit; e; e = e->next)
1435 * Evaluate the list of expressions
1437 l = FcConfigValues (p, e->expr, e->binding);
1439 * Locate any test associated with this field, skipping
1440 * tests associated with the pattern when substituting in
1443 for (t = s->test, i = 0; t; t = t->next, i++)
1445 if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
1446 !FcStrCmpIgnoreCase ((FcChar8 *) t->field,
1447 (FcChar8 *) e->field))
1450 * KLUDGE - the pattern may have been reallocated or
1451 * things may have been inserted or deleted above
1452 * this element by other edits. Go back and find
1455 if (e != s->edit && st[i].elt)
1456 st[i].elt = FcPatternFindElt (p, t->field);
1465 * If there was a test, then replace the matched
1466 * value with the new list of values
1470 FcValueList *thisValue = st[i].value;
1471 FcValueList *nextValue = thisValue ? FcValueListPtrU(thisValue->next) : 0;
1474 * Append the new list of values after the current value
1476 FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
1478 * Delete the marked value
1480 FcConfigDel (&st[i].elt->values, thisValue);
1482 * Adjust any pointers into the value list to ensure
1483 * future edits occur at the same place
1485 for (t = s->test, i = 0; t; t = t->next, i++)
1487 if (st[i].value == thisValue)
1488 st[i].value = nextValue;
1492 /* fall through ... */
1493 case FcOpAssignReplace:
1495 * Delete all of the values and insert
1498 FcConfigPatternDel (p, e->field);
1499 FcConfigPatternAdd (p, e->field, l, FcTrue);
1501 * Adjust any pointers into the value list as they no
1502 * longer point to anything valid
1506 FcPatternElt *thisElt = st[i].elt;
1507 for (t = s->test, i = 0; t; t = t->next, i++)
1509 if (st[i].elt == thisElt)
1517 FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
1520 /* fall through ... */
1521 case FcOpPrependFirst:
1522 FcConfigPatternAdd (p, e->field, l, FcFalse);
1527 FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
1530 /* fall through ... */
1531 case FcOpAppendLast:
1532 FcConfigPatternAdd (p, e->field, l, FcTrue);
1539 * Now go through the pattern and eliminate
1540 * any properties without data
1542 for (e = s->edit; e; e = e->next)
1543 FcConfigPatternCanon (p, e->field);
1545 if (FcDebug () & FC_DBG_EDIT)
1547 printf ("FcConfigSubstitute edit");
1551 FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1553 if (FcDebug () & FC_DBG_EDIT)
1555 printf ("FcConfigSubstitute done");
1562 FcConfigSubstitute (FcConfig *config,
1566 return FcConfigSubstituteWithPat (config, p, 0, kind);
1569 #if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT))
1571 static FcChar8 fontconfig_path[1000] = "";
1574 DllMain (HINSTANCE hinstDLL,
1580 switch (fdwReason) {
1581 case DLL_PROCESS_ATTACH:
1582 if (!GetModuleFileName ((HMODULE) hinstDLL, fontconfig_path,
1583 sizeof (fontconfig_path)))
1586 /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
1587 * assume it's a Unix-style installation tree, and use
1588 * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
1589 * folder where the DLL is as FONTCONFIG_PATH.
1591 p = strrchr (fontconfig_path, '\\');
1595 p = strrchr (fontconfig_path, '\\');
1596 if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 ||
1597 FcStrCmpIgnoreCase (p + 1, "lib") == 0))
1599 strcat (fontconfig_path, "\\etc\\fonts");
1602 fontconfig_path[0] = '\0';
1610 #undef FONTCONFIG_PATH
1611 #define FONTCONFIG_PATH fontconfig_path
1613 #else /* !(_WIN32 && PIC) */
1615 #endif /* !(_WIN32 && PIC) */
1617 #ifndef FONTCONFIG_FILE
1618 #define FONTCONFIG_FILE "fonts.conf"
1622 FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
1627 dir = (FcChar8 *) "";
1628 path = malloc (strlen ((char *) dir) + 1 + strlen ((char *) file) + 1);
1632 strcpy ((char *) path, (const char *) dir);
1633 /* make sure there's a single separator */
1635 if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
1636 path[strlen((char *) path)-1] != '\\')) &&
1639 (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
1640 strcat ((char *) path, "\\");
1642 if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
1643 strcat ((char *) path, "/");
1645 strcat ((char *) path, (char *) file);
1647 FcMemAlloc (FC_MEM_STRING, strlen ((char *) path) + 1);
1648 if (access ((char *) path, R_OK) == 0)
1656 FcConfigGetPath (void)
1659 FcChar8 *env, *e, *colon;
1664 npath = 2; /* default dir + null */
1665 env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
1671 if (*e++ == FC_SEARCH_PATH_SEPARATOR)
1674 path = calloc (npath, sizeof (FcChar8 *));
1684 colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
1686 colon = e + strlen ((char *) e);
1687 path[i] = malloc (colon - e + 1);
1690 strncpy ((char *) path[i], (const char *) e, colon - e);
1691 path[i][colon - e] = '\0';
1700 dir = (FcChar8 *) FONTCONFIG_PATH;
1701 path[i] = malloc (strlen ((char *) dir) + 1);
1704 strcpy ((char *) path[i], (const char *) dir);
1708 for (i = 0; path[i]; i++)
1716 FcConfigFreePath (FcChar8 **path)
1720 for (p = path; *p; p++)
1725 static FcBool _FcConfigHomeEnabled = FcTrue;
1730 if (_FcConfigHomeEnabled)
1732 char *home = getenv ("HOME");
1736 home = getenv ("USERPROFILE");
1739 return (FcChar8 *) home;
1745 FcConfigEnableHome (FcBool enable)
1747 FcBool prev = _FcConfigHomeEnabled;
1748 _FcConfigHomeEnabled = enable;
1753 FcConfigFilename (const FcChar8 *url)
1755 FcChar8 *file, *dir, **path, **p;
1759 url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
1761 url = (FcChar8 *) FONTCONFIG_FILE;
1766 if (isalpha (*url) &&
1768 (url[2] == '/' || url[2] == '\\'))
1774 dir = FcConfigHome ();
1776 file = FcConfigFileExists (dir, url + 1);
1785 file = FcConfigFileExists (0, url);
1788 path = FcConfigGetPath ();
1791 for (p = path; *p; p++)
1793 file = FcConfigFileExists (*p, url);
1797 FcConfigFreePath (path);
1804 * Manage the application-specific fonts
1808 FcConfigAppFontAddFile (FcConfig *config,
1809 const FcChar8 *file)
1818 config = FcConfigGetCurrent ();
1823 subdirs = FcStrSetCreate ();
1827 set = FcConfigGetFonts (config, FcSetApplication);
1830 set = FcFontSetCreate ();
1833 FcStrSetDestroy (subdirs);
1836 FcConfigSetFonts (config, set, FcSetApplication);
1839 if (!FcFileScanConfig (set, subdirs, 0, config->blanks, file, FcFalse, config))
1841 FcStrSetDestroy (subdirs);
1844 if ((sublist = FcStrListCreate (subdirs)))
1846 while ((subdir = FcStrListNext (sublist)))
1848 FcConfigAppFontAddDir (config, subdir);
1850 FcStrListDone (sublist);
1852 FcStrSetDestroy (subdirs);
1857 FcConfigAppFontAddDir (FcConfig *config,
1867 config = FcConfigGetCurrent ();
1871 subdirs = FcStrSetCreate ();
1875 set = FcConfigGetFonts (config, FcSetApplication);
1878 set = FcFontSetCreate ();
1881 FcStrSetDestroy (subdirs);
1884 FcConfigSetFonts (config, set, FcSetApplication);
1887 if (!FcDirScanConfig (set, subdirs, 0, config->blanks, dir, FcFalse, config))
1889 FcStrSetDestroy (subdirs);
1892 if ((sublist = FcStrListCreate (subdirs)))
1894 while ((subdir = FcStrListNext (sublist)))
1896 FcConfigAppFontAddDir (config, subdir);
1898 FcStrListDone (sublist);
1900 FcStrSetDestroy (subdirs);
1905 FcConfigAppFontClear (FcConfig *config)
1909 config = FcConfigGetCurrent ();
1914 FcConfigSetFonts (config, 0, FcSetApplication);
1918 * Manage filename-based font source selectors
1922 FcConfigGlobAdd (FcConfig *config,
1923 const FcChar8 *glob,
1926 FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs;
1928 return FcStrSetAdd (set, glob);
1932 FcConfigGlobMatch (const FcChar8 *glob,
1933 const FcChar8 *string)
1937 while ((c = *glob++))
1941 /* short circuit common case */
1944 /* short circuit another common case */
1945 if (strchr ((char *) glob, '*') == 0)
1946 string += strlen ((char *) string) - strlen ((char *) glob);
1949 if (FcConfigGlobMatch (glob, string))
1955 if (*string++ == '\0')
1964 return *string == '\0';
1968 FcConfigGlobsMatch (const FcStrSet *globs,
1969 const FcChar8 *string)
1973 for (i = 0; i < globs->num; i++)
1974 if (FcConfigGlobMatch (globs->strs[i], string))
1980 FcConfigAcceptFilename (FcConfig *config,
1981 const FcChar8 *filename)
1983 if (FcConfigGlobsMatch (config->acceptGlobs, filename))
1985 if (FcConfigGlobsMatch (config->rejectGlobs, filename))
1991 * Manage font-pattern based font source selectors
1995 FcConfigPatternsAdd (FcConfig *config,
1999 FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns;
2001 return FcFontSetAdd (set, pattern);
2005 FcConfigPatternsMatch (const FcFontSet *patterns,
2006 const FcPattern *font)
2010 for (i = 0; i < patterns->nfont; i++)
2011 if (FcListPatternMatchAny (patterns->fonts[i], font))
2017 FcConfigAcceptFont (FcConfig *config,
2018 const FcPattern *font)
2020 if (FcConfigPatternsMatch (config->acceptPatterns, font))
2022 if (FcConfigPatternsMatch (config->rejectPatterns, font))