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 FcConfigInodeMatchFontDir (FcConfig *config, const FcChar8 *d)
394 /* first we do string matches rather than file accesses */
395 /* FcStrSetMember doesn't tell us the index so that we can return
396 * the config-owned copy. */
397 for (n = 0; n < config->fontDirs->num; n++)
399 if (!FcStrCmp (config->fontDirs->strs[n], d))
400 return config->fontDirs->strs[n];
403 /* If this is a bottleneck, we can cache the fontDir inodes. */
404 if (stat ((char *)d, &s) == -1)
406 di = s.st_ino; dd = s.st_dev;
408 for (n = 0; n < config->fontDirs->num; n++)
410 if (stat ((char *)config->fontDirs->strs[n], &s) == -1)
412 if (di == s.st_ino && dd == s.st_dev)
413 return config->fontDirs->strs[n];
419 FcConfigAddFontDir (FcConfig *config,
422 /* Avoid adding d if it's an alias of something else, too. */
423 if (FcConfigInodeMatchFontDir(config, d))
425 return FcStrSetAddFilename (config->fontDirs, d);
429 FcConfigAddFontDirSubdirs (FcConfig *config,
435 FcBool added = FcFalse;
437 if (!(dir = opendir ((char *) d)))
439 if (!(subdir = (FcChar8 *) malloc (strlen ((char *) d) + FC_MAX_FILE_LEN + 2)))
441 fprintf (stderr, "out of memory");
444 while ((e = readdir (dir)))
446 if (strcmp (e->d_name, ".") && strcmp (e->d_name, "..") &&
447 strlen (e->d_name) < FC_MAX_FILE_LEN)
449 strcpy ((char *)subdir, (char *)d);
450 strcat ((char *)subdir, "/");
451 strcat ((char *)subdir, e->d_name);
452 if (FcFileIsDir (subdir))
454 if (FcConfigInodeMatchFontDir(config, subdir))
455 continue; /* already added */
456 FcStrSetAddFilename (config->fontDirs, subdir);
457 FcConfigAddFontDirSubdirs (config, subdir);
468 FcConfigNormalizeFontDir (FcConfig *config,
473 FcBool added = FcFalse;
475 d0 = FcConfigInodeMatchFontDir(config, d);
479 /* Ok, we didn't find it in fontDirs; let's add subdirs.... */
480 for (n = 0, n0 = config->fontDirs->num; n < n0; n++)
482 if (FcConfigAddFontDirSubdirs (config, config->fontDirs->strs[n]))
486 /* ... and try again. */
488 return FcConfigInodeMatchFontDir(config, d);
494 FcConfigAddDir (FcConfig *config,
497 return (FcConfigAddConfigDir (config, d) &&
498 FcConfigAddFontDir (config, d));
502 FcConfigGetFontDirs (FcConfig *config)
506 config = FcConfigGetCurrent ();
510 return FcStrListCreate (config->fontDirs);
514 FcConfigAddConfigFile (FcConfig *config,
518 FcChar8 *file = FcConfigFilename (f);
523 ret = FcStrSetAdd (config->configFiles, file);
529 FcConfigGetConfigFiles (FcConfig *config)
533 config = FcConfigGetCurrent ();
537 return FcStrListCreate (config->configFiles);
541 FcConfigSetCache (FcConfig *config,
544 FcChar8 *new = FcStrCopyFilename (c);
549 FcStrFree (config->cache);
555 FcConfigGetCache (FcConfig *config)
559 config = FcConfigGetCurrent ();
563 return config->cache;
567 FcConfigGetFonts (FcConfig *config,
572 config = FcConfigGetCurrent ();
576 return config->fonts[set];
580 FcConfigSetFonts (FcConfig *config,
584 if (config->fonts[set])
585 FcFontSetDestroy (config->fonts[set]);
586 config->fonts[set] = fonts;
592 FcConfigGetBlanks (FcConfig *config)
596 config = FcConfigGetCurrent ();
600 return config->blanks;
604 FcConfigAddBlank (FcConfig *config,
612 b = FcBlanksCreate ();
616 if (!FcBlanksAdd (b, blank))
623 FcConfigGetRescanInverval (FcConfig *config)
627 config = FcConfigGetCurrent ();
631 return config->rescanInterval;
635 FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
639 config = FcConfigGetCurrent ();
643 config->rescanInterval = rescanInterval;
648 FcConfigAddEdit (FcConfig *config,
653 FcSubst *subst, **prev;
657 subst = (FcSubst *) malloc (sizeof (FcSubst));
660 FcMemAlloc (FC_MEM_SUBST, sizeof (FcSubst));
661 if (kind == FcMatchPattern)
662 prev = &config->substPattern;
664 prev = &config->substFont;
665 for (; *prev; prev = &(*prev)->next);
671 for (t = test; t; t = t->next)
673 if (t->kind == FcMatchDefault)
677 if (config->maxObjects < num)
678 config->maxObjects = num;
679 if (FcDebug () & FC_DBG_EDIT)
681 printf ("Add Subst ");
682 FcSubstPrint (subst);
687 typedef struct _FcSubState {
693 FcConfigPromote (FcValue v, FcValue u)
695 if (v.type == FcTypeInteger)
697 v.type = FcTypeDouble;
698 v.u.d = (double) v.u.i;
700 else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
702 v.u.m = &FcIdentityMatrix;
703 v.type = FcTypeMatrix;
705 else if (v.type == FcTypeString && u.type == FcTypeLangSet)
707 v.u.l = FcLangSetPromote (v.u.s);
708 v.type = FcTypeLangSet;
714 FcConfigCompareValue (const FcValue *left_o,
716 const FcValue *right_o)
718 FcValue left = FcValueCanonicalize(left_o);
719 FcValue right = FcValueCanonicalize(right_o);
720 FcBool ret = FcFalse;
722 left = FcConfigPromote (left, right);
723 right = FcConfigPromote (right, left);
724 if (left.type == right.type)
728 break; /* FcConfigPromote prevents this from happening */
734 ret = left.u.d == right.u.d;
737 case FcOpNotContains:
738 ret = left.u.d != right.u.d;
741 ret = left.u.d < right.u.d;
744 ret = left.u.d <= right.u.d;
747 ret = left.u.d > right.u.d;
750 ret = left.u.d >= right.u.d;
761 ret = left.u.b == right.u.b;
764 case FcOpNotContains:
765 ret = left.u.b != right.u.b;
775 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
778 ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
781 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
783 case FcOpNotContains:
784 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
795 ret = FcMatrixEqual (left.u.m, right.u.m);
798 case FcOpNotContains:
799 ret = !FcMatrixEqual (left.u.m, right.u.m);
809 /* left contains right if right is a subset of left */
810 ret = FcCharSetIsSubset (right.u.c, left.u.c);
812 case FcOpNotContains:
813 /* left contains right if right is a subset of left */
814 ret = !FcCharSetIsSubset (right.u.c, left.u.c);
817 ret = FcCharSetEqual (left.u.c, right.u.c);
820 ret = !FcCharSetEqual (left.u.c, right.u.c);
830 ret = FcLangSetContains (left.u.l, right.u.l);
832 case FcOpNotContains:
833 ret = !FcLangSetContains (left.u.l, right.u.l);
836 ret = FcLangSetEqual (left.u.l, right.u.l);
839 ret = !FcLangSetEqual (left.u.l, right.u.l);
861 ret = left.u.f == right.u.f;
864 case FcOpNotContains:
865 ret = left.u.f != right.u.f;
875 if (op == FcOpNotEqual || op == FcOpNotContains)
882 #define _FcDoubleFloor(d) ((int) (d))
883 #define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
884 #define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
885 #define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
886 #define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5)
887 #define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
890 FcConfigEvaluate (FcPattern *p, FcExpr *e)
898 v.type = FcTypeInteger;
902 v.type = FcTypeDouble;
906 v.type = FcTypeString;
907 v.u.s = FcStrStaticName(e->u.sval);
910 v.type = FcTypeMatrix;
915 v.type = FcTypeCharSet;
924 r = FcPatternGet (p, e->u.field, 0, &v);
925 if (r != FcResultMatch)
930 if (FcNameConstant (e->u.constant, &v.u.i))
931 v.type = FcTypeInteger;
936 vl = FcConfigEvaluate (p, e->u.tree.left);
937 if (vl.type == FcTypeBool)
940 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
942 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
955 case FcOpNotContains:
957 vl = FcConfigEvaluate (p, e->u.tree.left);
958 vr = FcConfigEvaluate (p, e->u.tree.right);
960 v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
970 vl = FcConfigEvaluate (p, e->u.tree.left);
971 vr = FcConfigEvaluate (p, e->u.tree.right);
972 vl = FcConfigPromote (vl, vr);
973 vr = FcConfigPromote (vr, vl);
974 if (vl.type == vr.type)
980 v.type = FcTypeDouble;
981 v.u.d = vl.u.d + vr.u.d;
984 v.type = FcTypeDouble;
985 v.u.d = vl.u.d - vr.u.d;
988 v.type = FcTypeDouble;
989 v.u.d = vl.u.d * vr.u.d;
992 v.type = FcTypeDouble;
993 v.u.d = vl.u.d / vr.u.d;
999 if (v.type == FcTypeDouble &&
1000 v.u.d == (double) (int) v.u.d)
1002 v.type = FcTypeInteger;
1003 v.u.i = (int) v.u.d;
1009 v.type = FcTypeBool;
1010 v.u.b = vl.u.b || vr.u.b;
1013 v.type = FcTypeBool;
1014 v.u.b = vl.u.b && vr.u.b;
1017 v.type = FcTypeVoid;
1024 v.type = FcTypeString;
1025 v.u.s = FcStrStaticName (FcStrPlus (vl.u.s, vr.u.s));
1028 v.type = FcTypeVoid;
1031 v.type = FcTypeVoid;
1038 v.type = FcTypeMatrix;
1039 m = malloc (sizeof (FcMatrix));
1042 FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
1043 FcMatrixMultiply (m, vl.u.m, vr.u.m);
1048 v.type = FcTypeVoid;
1052 v.type = FcTypeVoid;
1057 v.type = FcTypeVoid;
1062 v.type = FcTypeVoid;
1063 FcValueDestroy (vl);
1064 FcValueDestroy (vr);
1067 vl = FcConfigEvaluate (p, e->u.tree.left);
1070 v.type = FcTypeBool;
1074 v.type = FcTypeVoid;
1077 FcValueDestroy (vl);
1080 vl = FcConfigEvaluate (p, e->u.tree.left);
1086 v.type = FcTypeInteger;
1087 v.u.i = FcDoubleFloor (vl.u.d);
1090 v.type = FcTypeVoid;
1093 FcValueDestroy (vl);
1096 vl = FcConfigEvaluate (p, e->u.tree.left);
1102 v.type = FcTypeInteger;
1103 v.u.i = FcDoubleCeil (vl.u.d);
1106 v.type = FcTypeVoid;
1109 FcValueDestroy (vl);
1112 vl = FcConfigEvaluate (p, e->u.tree.left);
1118 v.type = FcTypeInteger;
1119 v.u.i = FcDoubleRound (vl.u.d);
1122 v.type = FcTypeVoid;
1125 FcValueDestroy (vl);
1128 vl = FcConfigEvaluate (p, e->u.tree.left);
1134 v.type = FcTypeInteger;
1135 v.u.i = FcDoubleTrunc (vl.u.d);
1138 v.type = FcTypeVoid;
1141 FcValueDestroy (vl);
1144 v.type = FcTypeVoid;
1150 static FcValueList *
1151 FcConfigMatchValueList (FcPattern *p,
1153 FcValueList *values)
1155 FcValueList *ret = 0;
1156 FcExpr *e = t->expr;
1162 /* Compute the value of the match expression */
1163 if (e->op == FcOpComma)
1165 value = FcConfigEvaluate (p, e->u.tree.left);
1166 e = e->u.tree.right;
1170 value = FcConfigEvaluate (p, e);
1174 for (v = values; v; v = FcValueListPtrU(v->next))
1176 /* Compare the pattern value to the match expression value */
1177 if (FcConfigCompareValue (&v->value, t->op, &value))
1184 if (t->qual == FcQualAll)
1191 FcValueDestroy (value);
1196 static FcValueList *
1197 FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding)
1203 l = (FcValueList *) malloc (sizeof (FcValueList));
1206 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
1207 if (e->op == FcOpComma)
1209 l->value = FcConfigEvaluate (p, e->u.tree.left);
1210 l->next = FcValueListPtrCreateDynamic(FcConfigValues (p, e->u.tree.right, binding));
1214 l->value = FcConfigEvaluate (p, e);
1215 l->next = FcValueListPtrCreateDynamic(0);
1217 l->binding = binding;
1218 if (l->value.type == FcTypeVoid)
1220 FcValueList *next = FcValueListPtrU(l->next);
1222 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
1231 FcConfigAdd (FcValueListPtr *head,
1232 FcValueList *position,
1236 FcValueListPtr *prev, last, v;
1237 FcValueBinding sameBinding;
1240 sameBinding = position->binding;
1242 sameBinding = FcValueBindingWeak;
1243 for (v = FcValueListPtrCreateDynamic(new); FcValueListPtrU(v);
1244 v = FcValueListPtrU(v)->next)
1245 if (FcValueListPtrU(v)->binding == FcValueBindingSame)
1246 FcValueListPtrU(v)->binding = sameBinding;
1250 prev = &position->next;
1252 for (prev = head; FcValueListPtrU(*prev);
1253 prev = &(FcValueListPtrU(*prev)->next))
1260 for (prev = head; FcValueListPtrU(*prev);
1261 prev = &(FcValueListPtrU(*prev)->next))
1263 if (FcValueListPtrU(*prev) == position)
1270 if (FcDebug () & FC_DBG_EDIT)
1272 if (!FcValueListPtrU(*prev))
1273 printf ("position not on list\n");
1277 if (FcDebug () & FC_DBG_EDIT)
1279 printf ("%s list before ", append ? "Append" : "Prepend");
1280 FcValueListPrint (*head);
1286 last = FcValueListPtrCreateDynamic(new);
1287 while (FcValueListPtrU(FcValueListPtrU(last)->next))
1288 last = FcValueListPtrU(last)->next;
1290 FcValueListPtrU(last)->next = *prev;
1291 *prev = FcValueListPtrCreateDynamic(new);
1294 if (FcDebug () & FC_DBG_EDIT)
1296 printf ("%s list after ", append ? "Append" : "Prepend");
1297 FcValueListPrint (*head);
1305 FcConfigDel (FcValueListPtr *head,
1306 FcValueList *position)
1308 FcValueListPtr *prev;
1310 for (prev = head; FcValueListPtrU(*prev);
1311 prev = &(FcValueListPtrU(*prev)->next))
1313 if (FcValueListPtrU(*prev) == position)
1315 *prev = position->next;
1316 position->next = FcValueListPtrCreateDynamic(0);
1317 FcValueListDestroy (FcValueListPtrCreateDynamic(position));
1324 FcConfigPatternAdd (FcPattern *p,
1331 FcPatternElt *e = FcPatternInsertElt (p, object);
1335 FcConfigAdd (&e->values, 0, append, list);
1340 * Delete all values associated with a field
1343 FcConfigPatternDel (FcPattern *p,
1346 FcPatternElt *e = FcPatternFindElt (p, object);
1349 while (FcValueListPtrU(e->values))
1350 FcConfigDel (&e->values, FcValueListPtrU(e->values));
1354 FcConfigPatternCanon (FcPattern *p,
1357 FcPatternElt *e = FcPatternFindElt (p, object);
1360 if (!FcValueListPtrU(e->values))
1361 FcPatternDel (p, object);
1365 FcConfigSubstituteWithPat (FcConfig *config,
1380 config = FcConfigGetCurrent ();
1385 st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
1386 if (!st && config->maxObjects)
1388 FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1390 if (FcDebug () & FC_DBG_EDIT)
1392 printf ("FcConfigSubstitute ");
1395 if (kind == FcMatchPattern)
1396 s = config->substPattern;
1398 s = config->substFont;
1399 for (; s; s = s->next)
1402 * Check the tests to see if
1403 * they all match the pattern
1405 for (t = s->test, i = 0; t; t = t->next, i++)
1407 if (FcDebug () & FC_DBG_EDIT)
1409 printf ("FcConfigSubstitute test ");
1413 if (kind == FcMatchFont && t->kind == FcMatchPattern)
1418 st[i].elt = FcPatternFindElt (m, t->field);
1422 * If there's no such field in the font,
1423 * then FcQualAll matches while FcQualAny does not
1427 if (t->qual == FcQualAll)
1436 * Check to see if there is a match, mark the location
1437 * to apply match-relative edits
1439 st[i].value = FcConfigMatchValueList (m, t, FcValueListPtrU(st[i].elt->values));
1442 if (t->qual == FcQualFirst && st[i].value != FcValueListPtrU(st[i].elt->values))
1444 if (t->qual == FcQualNotFirst && st[i].value == FcValueListPtrU(st[i].elt->values))
1449 if (FcDebug () & FC_DBG_EDIT)
1450 printf ("No match\n");
1453 if (FcDebug () & FC_DBG_EDIT)
1455 printf ("Substitute ");
1458 for (e = s->edit; e; e = e->next)
1461 * Evaluate the list of expressions
1463 l = FcConfigValues (p, e->expr, e->binding);
1465 * Locate any test associated with this field, skipping
1466 * tests associated with the pattern when substituting in
1469 for (t = s->test, i = 0; t; t = t->next, i++)
1471 if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
1472 !FcStrCmpIgnoreCase ((FcChar8 *) t->field,
1473 (FcChar8 *) e->field))
1476 * KLUDGE - the pattern may have been reallocated or
1477 * things may have been inserted or deleted above
1478 * this element by other edits. Go back and find
1481 if (e != s->edit && st[i].elt)
1482 st[i].elt = FcPatternFindElt (p, t->field);
1491 * If there was a test, then replace the matched
1492 * value with the new list of values
1496 FcValueList *thisValue = st[i].value;
1497 FcValueList *nextValue = thisValue ? FcValueListPtrU(thisValue->next) : 0;
1500 * Append the new list of values after the current value
1502 FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
1504 * Delete the marked value
1506 FcConfigDel (&st[i].elt->values, thisValue);
1508 * Adjust any pointers into the value list to ensure
1509 * future edits occur at the same place
1511 for (t = s->test, i = 0; t; t = t->next, i++)
1513 if (st[i].value == thisValue)
1514 st[i].value = nextValue;
1518 /* fall through ... */
1519 case FcOpAssignReplace:
1521 * Delete all of the values and insert
1524 FcConfigPatternDel (p, e->field);
1525 FcConfigPatternAdd (p, e->field, l, FcTrue);
1527 * Adjust any pointers into the value list as they no
1528 * longer point to anything valid
1532 FcPatternElt *thisElt = st[i].elt;
1533 for (t = s->test, i = 0; t; t = t->next, i++)
1535 if (st[i].elt == thisElt)
1543 FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
1546 /* fall through ... */
1547 case FcOpPrependFirst:
1548 FcConfigPatternAdd (p, e->field, l, FcFalse);
1553 FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
1556 /* fall through ... */
1557 case FcOpAppendLast:
1558 FcConfigPatternAdd (p, e->field, l, FcTrue);
1565 * Now go through the pattern and eliminate
1566 * any properties without data
1568 for (e = s->edit; e; e = e->next)
1569 FcConfigPatternCanon (p, e->field);
1571 if (FcDebug () & FC_DBG_EDIT)
1573 printf ("FcConfigSubstitute edit");
1577 FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1579 if (FcDebug () & FC_DBG_EDIT)
1581 printf ("FcConfigSubstitute done");
1588 FcConfigSubstitute (FcConfig *config,
1592 return FcConfigSubstituteWithPat (config, p, 0, kind);
1595 #if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT))
1597 static FcChar8 fontconfig_path[1000] = "";
1600 DllMain (HINSTANCE hinstDLL,
1606 switch (fdwReason) {
1607 case DLL_PROCESS_ATTACH:
1608 if (!GetModuleFileName ((HMODULE) hinstDLL, fontconfig_path,
1609 sizeof (fontconfig_path)))
1612 /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
1613 * assume it's a Unix-style installation tree, and use
1614 * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
1615 * folder where the DLL is as FONTCONFIG_PATH.
1617 p = strrchr (fontconfig_path, '\\');
1621 p = strrchr (fontconfig_path, '\\');
1622 if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 ||
1623 FcStrCmpIgnoreCase (p + 1, "lib") == 0))
1625 strcat (fontconfig_path, "\\etc\\fonts");
1628 fontconfig_path[0] = '\0';
1636 #undef FONTCONFIG_PATH
1637 #define FONTCONFIG_PATH fontconfig_path
1639 #else /* !(_WIN32 && PIC) */
1641 #endif /* !(_WIN32 && PIC) */
1643 #ifndef FONTCONFIG_FILE
1644 #define FONTCONFIG_FILE "fonts.conf"
1648 FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
1653 dir = (FcChar8 *) "";
1654 path = malloc (strlen ((char *) dir) + 1 + strlen ((char *) file) + 1);
1658 strcpy ((char *) path, (const char *) dir);
1659 /* make sure there's a single separator */
1661 if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
1662 path[strlen((char *) path)-1] != '\\')) &&
1665 (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
1666 strcat ((char *) path, "\\");
1668 if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
1669 strcat ((char *) path, "/");
1671 strcat ((char *) path, (char *) file);
1673 FcMemAlloc (FC_MEM_STRING, strlen ((char *) path) + 1);
1674 if (access ((char *) path, R_OK) == 0)
1682 FcConfigGetPath (void)
1685 FcChar8 *env, *e, *colon;
1690 npath = 2; /* default dir + null */
1691 env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
1697 if (*e++ == FC_SEARCH_PATH_SEPARATOR)
1700 path = calloc (npath, sizeof (FcChar8 *));
1710 colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
1712 colon = e + strlen ((char *) e);
1713 path[i] = malloc (colon - e + 1);
1716 strncpy ((char *) path[i], (const char *) e, colon - e);
1717 path[i][colon - e] = '\0';
1726 dir = (FcChar8 *) FONTCONFIG_PATH;
1727 path[i] = malloc (strlen ((char *) dir) + 1);
1730 strcpy ((char *) path[i], (const char *) dir);
1734 for (i = 0; path[i]; i++)
1742 FcConfigFreePath (FcChar8 **path)
1746 for (p = path; *p; p++)
1751 static FcBool _FcConfigHomeEnabled = FcTrue;
1756 if (_FcConfigHomeEnabled)
1758 char *home = getenv ("HOME");
1762 home = getenv ("USERPROFILE");
1765 return (FcChar8 *) home;
1771 FcConfigEnableHome (FcBool enable)
1773 FcBool prev = _FcConfigHomeEnabled;
1774 _FcConfigHomeEnabled = enable;
1779 FcConfigFilename (const FcChar8 *url)
1781 FcChar8 *file, *dir, **path, **p;
1785 url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
1787 url = (FcChar8 *) FONTCONFIG_FILE;
1792 if (isalpha (*url) &&
1794 (url[2] == '/' || url[2] == '\\'))
1800 dir = FcConfigHome ();
1802 file = FcConfigFileExists (dir, url + 1);
1811 file = FcConfigFileExists (0, url);
1814 path = FcConfigGetPath ();
1817 for (p = path; *p; p++)
1819 file = FcConfigFileExists (*p, url);
1823 FcConfigFreePath (path);
1830 * Manage the application-specific fonts
1834 FcConfigAppFontAddFile (FcConfig *config,
1835 const FcChar8 *file)
1844 config = FcConfigGetCurrent ();
1849 subdirs = FcStrSetCreate ();
1853 set = FcConfigGetFonts (config, FcSetApplication);
1856 set = FcFontSetCreate ();
1859 FcStrSetDestroy (subdirs);
1862 FcConfigSetFonts (config, set, FcSetApplication);
1865 if (!FcFileScanConfig (set, subdirs, 0, config->blanks, file, FcFalse, config))
1867 FcStrSetDestroy (subdirs);
1870 if ((sublist = FcStrListCreate (subdirs)))
1872 while ((subdir = FcStrListNext (sublist)))
1874 FcConfigAppFontAddDir (config, subdir);
1876 FcStrListDone (sublist);
1878 FcStrSetDestroy (subdirs);
1883 FcConfigAppFontAddDir (FcConfig *config,
1893 config = FcConfigGetCurrent ();
1897 subdirs = FcStrSetCreate ();
1901 set = FcConfigGetFonts (config, FcSetApplication);
1904 set = FcFontSetCreate ();
1907 FcStrSetDestroy (subdirs);
1910 FcConfigSetFonts (config, set, FcSetApplication);
1913 if (!FcDirScanConfig (set, subdirs, 0, config->blanks, dir, FcFalse, config))
1915 FcStrSetDestroy (subdirs);
1918 if ((sublist = FcStrListCreate (subdirs)))
1920 while ((subdir = FcStrListNext (sublist)))
1922 FcConfigAppFontAddDir (config, subdir);
1924 FcStrListDone (sublist);
1926 FcStrSetDestroy (subdirs);
1931 FcConfigAppFontClear (FcConfig *config)
1935 config = FcConfigGetCurrent ();
1940 FcConfigSetFonts (config, 0, FcSetApplication);
1944 * Manage filename-based font source selectors
1948 FcConfigGlobAdd (FcConfig *config,
1949 const FcChar8 *glob,
1952 FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs;
1954 return FcStrSetAdd (set, glob);
1958 FcConfigGlobMatch (const FcChar8 *glob,
1959 const FcChar8 *string)
1963 while ((c = *glob++))
1967 /* short circuit common case */
1970 /* short circuit another common case */
1971 if (strchr ((char *) glob, '*') == 0)
1972 string += strlen ((char *) string) - strlen ((char *) glob);
1975 if (FcConfigGlobMatch (glob, string))
1981 if (*string++ == '\0')
1990 return *string == '\0';
1994 FcConfigGlobsMatch (const FcStrSet *globs,
1995 const FcChar8 *string)
1999 for (i = 0; i < globs->num; i++)
2000 if (FcConfigGlobMatch (globs->strs[i], string))
2006 FcConfigAcceptFilename (FcConfig *config,
2007 const FcChar8 *filename)
2009 if (FcConfigGlobsMatch (config->acceptGlobs, filename))
2011 if (FcConfigGlobsMatch (config->rejectGlobs, filename))
2017 * Manage font-pattern based font source selectors
2021 FcConfigPatternsAdd (FcConfig *config,
2025 FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns;
2027 return FcFontSetAdd (set, pattern);
2031 FcConfigPatternsMatch (const FcFontSet *patterns,
2032 const FcPattern *font)
2036 for (i = 0; i < patterns->nfont; i++)
2037 if (FcListPatternMatchAny (patterns->fonts[i], font))
2043 FcConfigAcceptFont (FcConfig *config,
2044 const FcPattern *font)
2046 if (FcConfigPatternsMatch (config->acceptPatterns, font))
2048 if (FcConfigPatternsMatch (config->rejectPatterns, font))