4 * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
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.
30 static FcConfig *fcConfig;
38 config = malloc (sizeof (FcConfig));
42 config->dirs = malloc (sizeof (char *));
47 config->configFiles = malloc (sizeof (char *));
48 if (!config->configFiles)
50 config->configFiles[0] = 0;
53 if (!FcConfigSetCache (config, (FcChar8 *) ("~/" FC_USER_CACHE_FILE)))
58 config->substPattern = 0;
59 config->substFont = 0;
60 config->maxObjects = 0;
61 for (set = FcSetSystem; set <= FcSetApplication; set++)
62 config->fonts[set] = 0;
67 free (config->configFiles);
77 FcSubstDestroy (FcSubst *s)
84 FcTestDestroy (s->test);
85 FcEditDestroy (s->edit);
91 FcConfigDestroyStrings (FcChar8 **strings)
95 for (s = strings; s && *s; s++)
102 FcConfigAddString (FcChar8 ***strings, FcChar8 *string)
108 for (s = *strings; s && *s; s++)
110 s = malloc ((n + 2) * sizeof (FcChar8 *));
115 memcpy (s, *strings, n * sizeof (FcChar8 *));
122 FcConfigDestroy (FcConfig *config)
125 FcConfigDestroyStrings (config->dirs);
126 FcConfigDestroyStrings (config->configFiles);
128 free (config->cache);
130 FcSubstDestroy (config->substPattern);
131 FcSubstDestroy (config->substFont);
132 for (set = FcSetSystem; set <= FcSetApplication; set++)
133 if (config->fonts[set])
134 FcFontSetDestroy (config->fonts[set]);
138 * Scan the current list of directories in the configuration
139 * and build the set of available fonts. Update the
140 * per-user cache file to reflect the new configuration
144 FcConfigBuildFonts (FcConfig *config)
150 fonts = FcFontSetCreate ();
154 cache = FcFileCacheCreate ();
158 FcFileCacheLoad (cache, config->cache);
160 for (d = config->dirs; d && *d; d++)
162 if (FcDebug () & FC_DBG_FONTSET)
163 printf ("scan dir %s\n", *d);
164 FcDirScan (fonts, cache, config->blanks, *d, FcFalse);
167 if (FcDebug () & FC_DBG_FONTSET)
168 FcFontSetPrint (fonts);
170 FcFileCacheSave (cache, config->cache);
171 FcFileCacheDestroy (cache);
173 FcConfigSetFonts (config, fonts, FcSetSystem);
177 FcFontSetDestroy (fonts);
183 FcConfigSetCurrent (FcConfig *config)
186 if (!FcConfigBuildFonts (config))
190 FcConfigDestroy (fcConfig);
196 FcConfigGetCurrent (void)
202 FcConfigAddDir (FcConfig *config,
210 h = (FcChar8 *) getenv ("HOME");
213 dir = (FcChar8 *) malloc (strlen ((char *) h) + strlen ((char *) d));
216 strcpy ((char *) dir, (char *) h);
217 strcat ((char *) dir, (char *) d+1);
221 dir = (FcChar8 *) malloc (strlen ((char *) d) + 1);
226 if (!FcConfigAddString (&config->dirs, dir))
235 FcConfigGetDirs (FcConfig *config)
239 config = FcConfigGetCurrent ();
247 FcConfigAddConfigFile (FcConfig *config,
251 file = FcConfigFilename (f);
254 if (!FcConfigAddString (&config->configFiles, file))
263 FcConfigGetConfigFiles (FcConfig *config)
267 config = FcConfigGetCurrent ();
271 return config->configFiles;
275 FcConfigSetCache (FcConfig *config,
283 h = (FcChar8 *) getenv ("HOME");
286 new = (FcChar8 *) malloc (strlen ((char *) h) + strlen ((char *) c));
289 strcpy ((char *) new, (char *) h);
290 strcat ((char *) new, (char *) c+1);
297 free (config->cache);
303 FcConfigGetCache (FcConfig *config)
307 config = FcConfigGetCurrent ();
311 return config->cache;
315 FcConfigGetFonts (FcConfig *config,
320 config = FcConfigGetCurrent ();
324 return config->fonts[set];
328 FcConfigSetFonts (FcConfig *config,
332 if (config->fonts[set])
333 FcFontSetDestroy (config->fonts[set]);
334 config->fonts[set] = fonts;
338 FcConfigGetBlanks (FcConfig *config)
342 config = FcConfigGetCurrent ();
346 return config->blanks;
350 FcConfigAddBlank (FcConfig *config,
358 b = FcBlanksCreate ();
362 if (!FcBlanksAdd (b, blank))
369 FcConfigAddEdit (FcConfig *config,
374 FcSubst *subst, **prev;
378 subst = (FcSubst *) malloc (sizeof (FcSubst));
381 if (kind == FcMatchPattern)
382 prev = &config->substPattern;
384 prev = &config->substFont;
385 for (; *prev; prev = &(*prev)->next);
390 if (FcDebug () & FC_DBG_EDIT)
392 printf ("Add Subst ");
393 FcSubstPrint (subst);
396 for (t = test; t; t = t->next)
398 if (config->maxObjects < num)
399 config->maxObjects = num;
403 typedef struct _FcSubState {
408 static const FcMatrix FcIdentityMatrix = { 1, 0, 0, 1 };
411 FcConfigPromote (FcValue v, FcValue u)
413 if (v.type == FcTypeInteger)
415 v.type = FcTypeDouble;
416 v.u.d = (double) v.u.i;
418 else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
420 v.u.m = (FcMatrix *) &FcIdentityMatrix;
421 v.type = FcTypeMatrix;
427 FcConfigCompareValue (FcValue m,
431 FcBool ret = FcFalse;
433 m = FcConfigPromote (m, v);
434 v = FcConfigPromote (v, m);
435 if (m.type == v.type)
440 break; /* FcConfigPromote prevents this from happening */
445 ret = m.u.d == v.u.d;
448 ret = m.u.d != v.u.d;
454 ret = m.u.d <= v.u.d;
460 ret = m.u.d >= v.u.d;
470 ret = m.u.b == v.u.b;
473 ret = m.u.b != v.u.b;
483 ret = FcStrCmpIgnoreCase (m.u.s, v.u.s) == 0;
486 ret = FcStrCmpIgnoreCase (m.u.s, v.u.s) != 0;
496 ret = FcMatrixEqual (m.u.m, v.u.m);
499 ret = !FcMatrixEqual (m.u.m, v.u.m);
508 /* m contains v if v - m is empty */
509 ret = FcCharSetSubtractCount (v.u.c, m.u.c) == 0;
512 ret = FcCharSetEqual (m.u.c, v.u.c);
515 ret = !FcCharSetEqual (m.u.c, v.u.c);
535 if (op == FcOpNotEqual)
543 FcConfigEvaluate (FcPattern *p, FcExpr *e)
551 v.type = FcTypeInteger;
555 v.type = FcTypeDouble;
559 v.type = FcTypeString;
564 v.type = FcTypeMatrix;
569 v.type = FcTypeCharSet;
578 r = FcPatternGet (p, e->u.field, 0, &v);
579 if (r != FcResultMatch)
583 if (FcNameConstant (e->u.constant, &v.u.i))
584 v.type = FcTypeInteger;
589 vl = FcConfigEvaluate (p, e->u.tree.left);
590 if (vl.type == FcTypeBool)
593 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
595 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
614 vl = FcConfigEvaluate (p, e->u.tree.left);
615 vr = FcConfigEvaluate (p, e->u.tree.right);
616 vl = FcConfigPromote (vl, vr);
617 vr = FcConfigPromote (vr, vl);
618 if (vl.type == vr.type)
624 v.type = FcTypeDouble;
625 v.u.d = vl.u.d + vr.u.d;
628 v.type = FcTypeDouble;
629 v.u.d = vl.u.d - vr.u.d;
632 v.type = FcTypeDouble;
633 v.u.d = vl.u.d * vr.u.d;
636 v.type = FcTypeDouble;
637 v.u.d = vl.u.d / vr.u.d;
642 v.u.b = vl.u.d == vr.u.d;
646 v.u.b = vl.u.d != vr.u.d;
650 v.u.b = vl.u.d < vr.u.d;
654 v.u.b = vl.u.d <= vr.u.d;
658 v.u.b = vl.u.d > vr.u.d;
662 v.u.b = vl.u.d >= vr.u.d;
668 if (v.type == FcTypeDouble &&
669 v.u.d == (double) (int) v.u.d)
671 v.type = FcTypeInteger;
679 v.u.b = vl.u.b || vr.u.b;
683 v.u.b = vl.u.b && vr.u.b;
688 v.u.b = vl.u.b == vr.u.b;
692 v.u.b = vl.u.b != vr.u.b;
704 v.u.b = FcStrCmpIgnoreCase (vl.u.s, vr.u.s) == 0;
708 v.u.b = FcStrCmpIgnoreCase (vl.u.s, vr.u.s) != 0;
711 v.type = FcTypeString;
712 v.u.s = FcStrPlus (vl.u.s, vr.u.s);
725 v.u.b = FcMatrixEqual (vl.u.m, vr.u.m);
729 v.u.b = FcMatrixEqual (vl.u.m, vr.u.m);
732 v.type = FcTypeMatrix;
733 m = malloc (sizeof (FcMatrix));
736 FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
737 FcMatrixMultiply (m, vl.u.m, vr.u.m);
753 /* vl contains vr if vr - vl is empty */
755 v.u.b = FcCharSetSubtractCount (vr.u.c, vl.u.c) == 0;
759 v.u.b = FcCharSetEqual (vl.u.c, vr.u.c);
763 v.u.b = !FcCharSetEqual (vl.u.c, vr.u.c);
781 vl = FcConfigEvaluate (p, e->u.tree.left);
801 FcConfigMatchValueList (FcPattern *p,
805 FcValueList *ret = 0;
806 FcValue value = FcConfigEvaluate (p, t->expr);
808 for (; v; v = v->next)
810 if (FcConfigCompareValue (v->value, t->op, value))
817 if (t->qual == FcQualAll)
824 FcValueDestroy (value);
829 FcConfigValues (FcPattern *p, FcExpr *e)
835 l = (FcValueList *) malloc (sizeof (FcValueList));
838 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
839 if (e->op == FcOpComma)
841 l->value = FcConfigEvaluate (p, e->u.tree.left);
842 l->next = FcConfigValues (p, e->u.tree.right);
846 l->value = FcConfigEvaluate (p, e);
849 while (l->value.type == FcTypeVoid)
851 FcValueList *next = l->next;
853 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
861 FcConfigAdd (FcValueList **head,
862 FcValueList *position,
866 FcValueList **prev, *last;
871 prev = &position->next;
873 for (prev = head; *prev; prev = &(*prev)->next)
880 for (prev = head; *prev; prev = &(*prev)->next)
882 if (*prev == position)
889 if (FcDebug () & FC_DBG_EDIT)
892 printf ("position not on list\n");
896 if (FcDebug () & FC_DBG_EDIT)
898 printf ("%s list before ", append ? "Append" : "Prepend");
899 FcValueListPrint (*head);
913 if (FcDebug () & FC_DBG_EDIT)
915 printf ("%s list after ", append ? "Append" : "Prepend");
916 FcValueListPrint (*head);
924 FcConfigDel (FcValueList **head,
925 FcValueList *position)
929 for (prev = head; *prev; prev = &(*prev)->next)
931 if (*prev == position)
933 *prev = position->next;
935 FcValueListDestroy (position);
942 FcConfigPatternAdd (FcPattern *p,
949 FcPatternElt *e = FcPatternFind (p, object, FcTrue);
953 FcConfigAdd (&e->values, 0, append, list);
958 * Delete all values associated with a field
961 FcConfigPatternDel (FcPattern *p,
964 FcPatternElt *e = FcPatternFind (p, object, FcFalse);
968 FcConfigDel (&e->values, e->values);
972 FcConfigPatternCanon (FcPattern *p,
975 FcPatternElt *e = FcPatternFind (p, object, FcFalse);
979 FcPatternDel (p, object);
983 FcConfigSubstitute (FcConfig *config,
996 config = FcConfigGetCurrent ();
1001 st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
1002 if (!st && config->maxObjects)
1004 FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1006 if (FcDebug () & FC_DBG_EDIT)
1008 printf ("FcConfigSubstitute ");
1011 if (kind == FcMatchPattern)
1012 s = config->substPattern;
1014 s = config->substFont;
1015 for (; s; s = s->next)
1018 * Check the tests to see if
1019 * they all match the pattern
1021 for (t = s->test, i = 0; t; t = t->next, i++)
1023 if (FcDebug () & FC_DBG_EDIT)
1025 printf ("FcConfigSubstitute test ");
1028 st[i].elt = FcPatternFind (p, t->field, FcFalse);
1030 * If there's no such field in the font,
1031 * then FcQualAll matches while FcQualAny does not
1035 if (t->qual == FcQualAll)
1044 * Check to see if there is a match, mark the location
1045 * to apply match-relative edits
1047 st[i].value = FcConfigMatchValueList (p, t, st[i].elt->values);
1053 if (FcDebug () & FC_DBG_EDIT)
1054 printf ("No match\n");
1057 if (FcDebug () & FC_DBG_EDIT)
1059 printf ("Substitute ");
1062 for (e = s->edit; e; e = e->next)
1065 * Evaluate the list of expressions
1067 l = FcConfigValues (p, e->expr);
1069 * Locate any test associated with this field
1071 for (t = s->test, i = 0; t; t = t->next, i++)
1072 if (!FcStrCmpIgnoreCase ((FcChar8 *) t->field, (FcChar8 *) e->field))
1077 * If there was a test, then replace the matched
1078 * value with the new list of values
1082 FcValueList *thisValue = st[i].value;
1083 FcValueList *nextValue = thisValue ? thisValue->next : 0;
1086 * Append the new list of values after the current value
1088 FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
1090 * Delete the marked value
1092 FcConfigDel (&st[i].elt->values, thisValue);
1094 * Adjust any pointers into the value list to ensure
1095 * future edits occur at the same place
1097 for (t = s->test, i = 0; t; t = t->next, i++)
1099 if (st[i].value == thisValue)
1100 st[i].value = nextValue;
1104 /* fall through ... */
1105 case FcOpAssignReplace:
1107 * Delete all of the values and insert
1110 FcConfigPatternDel (p, e->field);
1111 FcConfigPatternAdd (p, e->field, l, FcTrue);
1113 * Adjust any pointers into the value list as they no
1114 * longer point to anything valid
1118 FcPatternElt *thisElt = st[i].elt;
1119 for (t = s->test, i = 0; t; t = t->next, i++)
1121 if (st[i].elt == thisElt)
1129 FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
1132 /* fall through ... */
1133 case FcOpPrependFirst:
1134 FcConfigPatternAdd (p, e->field, l, FcFalse);
1139 FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
1142 /* fall through ... */
1143 case FcOpAppendLast:
1144 FcConfigPatternAdd (p, e->field, l, FcTrue);
1151 * Now go through the pattern and eliminate
1152 * any properties without data
1154 for (e = s->edit; e; e = e->next)
1155 FcConfigPatternCanon (p, e->field);
1157 if (FcDebug () & FC_DBG_EDIT)
1159 printf ("FcConfigSubstitute edit");
1163 FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1165 if (FcDebug () & FC_DBG_EDIT)
1167 printf ("FcConfigSubstitute done");
1173 #ifndef FONTCONFIG_PATH
1174 #define FONTCONFIG_PATH "/etc/fonts"
1177 #ifndef FONTCONFIG_FILE
1178 #define FONTCONFIG_FILE "fonts.conf"
1182 FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
1187 dir = (FcChar8 *) "";
1188 path = malloc (strlen ((char *) dir) + 1 + strlen ((char *) file) + 1);
1193 /* make sure there's a single separating / */
1194 if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
1195 strcat ((char *) path, "/");
1196 strcat ((char *) path, (char *) file);
1198 if (access ((char *) path, R_OK) == 0)
1206 FcConfigGetPath (void)
1209 FcChar8 *env, *e, *colon;
1214 npath = 2; /* default dir + null */
1215 env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
1224 path = calloc (npath, sizeof (FcChar8 *));
1234 colon = (FcChar8 *) strchr ((char *) e, ':');
1236 colon = e + strlen ((char *) e);
1237 path[i] = malloc (colon - e + 1);
1240 strncpy (path[i], e, colon - e);
1241 path[i][colon - e] = '\0';
1250 dir = (FcChar8 *) FONTCONFIG_PATH;
1251 path[i] = malloc (strlen ((char *) dir) + 1);
1254 strcpy (path[i], dir);
1258 for (i = 0; path[i]; i++)
1266 FcConfigFreePath (FcChar8 **path)
1270 for (p = path; *p; p++)
1276 FcConfigFilename (const FcChar8 *url)
1278 FcChar8 *file, *dir, **path, **p;
1282 url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
1284 url = (FcChar8 *) FONTCONFIG_FILE;
1289 dir = (FcChar8 *) getenv ("HOME");
1291 file = FcConfigFileExists (dir, url + 1);
1296 file = FcConfigFileExists (0, url);
1299 path = FcConfigGetPath ();
1302 for (p = path; *p; p++)
1304 file = FcConfigFileExists (*p, url);
1308 FcConfigFreePath (path);
1315 * Manage the application-specific fonts
1319 FcConfigAppFontAddFile (FcConfig *config,
1320 const FcChar8 *file)
1326 config = FcConfigGetCurrent ();
1331 set = FcConfigGetFonts (config, FcSetApplication);
1334 set = FcFontSetCreate ();
1337 FcConfigSetFonts (config, set, FcSetApplication);
1339 return FcFileScan (set, 0, config->blanks, file, FcFalse);
1343 FcConfigAppFontAddDir (FcConfig *config,
1350 config = FcConfigGetCurrent ();
1354 set = FcConfigGetFonts (config, FcSetApplication);
1357 set = FcFontSetCreate ();
1360 FcConfigSetFonts (config, set, FcSetApplication);
1362 return FcDirScan (set, 0, config->blanks, dir, FcFalse);
1366 FcConfigAppFontClear (FcConfig *config)
1368 FcConfigSetFonts (config, 0, FcSetApplication);