2 * $XFree86: xc/lib/fontconfig/src/fccfg.c,v 1.3 2002/02/19 08:33:23 keithp Exp $
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.
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)
205 FcConfigAddDir (FcConfig
*config
,
213 h
= (FcChar8
*) getenv ("HOME");
216 dir
= (FcChar8
*) malloc (strlen ((char *) h
) + strlen ((char *) d
));
219 strcpy ((char *) dir
, (char *) h
);
220 strcat ((char *) dir
, (char *) d
+1);
224 dir
= (FcChar8
*) malloc (strlen ((char *) d
) + 1);
229 if (!FcConfigAddString (&config
->dirs
, dir
))
238 FcConfigGetDirs (FcConfig
*config
)
242 config
= FcConfigGetCurrent ();
250 FcConfigAddConfigFile (FcConfig
*config
,
254 file
= FcConfigFilename (f
);
257 if (!FcConfigAddString (&config
->configFiles
, file
))
266 FcConfigGetConfigFiles (FcConfig
*config
)
270 config
= FcConfigGetCurrent ();
274 return config
->configFiles
;
278 FcConfigSetCache (FcConfig
*config
,
286 h
= (FcChar8
*) getenv ("HOME");
289 new = (FcChar8
*) malloc (strlen ((char *) h
) + strlen ((char *) c
));
292 strcpy ((char *) new, (char *) h
);
293 strcat ((char *) new, (char *) c
+1);
300 free (config
->cache
);
306 FcConfigGetCache (FcConfig
*config
)
310 config
= FcConfigGetCurrent ();
314 return config
->cache
;
318 FcConfigGetFonts (FcConfig
*config
,
323 config
= FcConfigGetCurrent ();
327 return config
->fonts
[set
];
331 FcConfigSetFonts (FcConfig
*config
,
335 if (config
->fonts
[set
])
336 FcFontSetDestroy (config
->fonts
[set
]);
337 config
->fonts
[set
] = fonts
;
341 FcConfigGetBlanks (FcConfig
*config
)
345 config
= FcConfigGetCurrent ();
349 return config
->blanks
;
353 FcConfigAddBlank (FcConfig
*config
,
361 b
= FcBlanksCreate ();
365 if (!FcBlanksAdd (b
, blank
))
372 FcConfigAddEdit (FcConfig
*config
,
377 FcSubst
*subst
, **prev
;
381 subst
= (FcSubst
*) malloc (sizeof (FcSubst
));
384 if (kind
== FcMatchPattern
)
385 prev
= &config
->substPattern
;
387 prev
= &config
->substFont
;
388 for (; *prev
; prev
= &(*prev
)->next
);
393 if (FcDebug () & FC_DBG_EDIT
)
395 printf ("Add Subst ");
396 FcSubstPrint (subst
);
399 for (t
= test
; t
; t
= t
->next
)
401 if (config
->maxObjects
< num
)
402 config
->maxObjects
= num
;
406 typedef struct _FcSubState
{
411 static const FcMatrix FcIdentityMatrix
= { 1, 0, 0, 1 };
414 FcConfigPromote (FcValue v
, FcValue u
)
416 if (v
.type
== FcTypeInteger
)
418 v
.type
= FcTypeDouble
;
419 v
.u
.d
= (double) v
.u
.i
;
421 else if (v
.type
== FcTypeVoid
&& u
.type
== FcTypeMatrix
)
423 v
.u
.m
= (FcMatrix
*) &FcIdentityMatrix
;
424 v
.type
= FcTypeMatrix
;
430 FcConfigCompareValue (FcValue m
,
434 FcBool ret
= FcFalse
;
436 m
= FcConfigPromote (m
, v
);
437 v
= FcConfigPromote (v
, m
);
438 if (m
.type
== v
.type
)
443 break; /* FcConfigPromote prevents this from happening */
448 ret
= m
.u
.d
== v
.u
.d
;
451 ret
= m
.u
.d
!= v
.u
.d
;
457 ret
= m
.u
.d
<= v
.u
.d
;
463 ret
= m
.u
.d
>= v
.u
.d
;
473 ret
= m
.u
.b
== v
.u
.b
;
476 ret
= m
.u
.b
!= v
.u
.b
;
486 ret
= FcStrCmpIgnoreCase (m
.u
.s
, v
.u
.s
) == 0;
489 ret
= FcStrCmpIgnoreCase (m
.u
.s
, v
.u
.s
) != 0;
499 ret
= FcMatrixEqual (m
.u
.m
, v
.u
.m
);
502 ret
= !FcMatrixEqual (m
.u
.m
, v
.u
.m
);
511 /* m contains v if v - m is empty */
512 ret
= FcCharSetSubtractCount (v
.u
.c
, m
.u
.c
) == 0;
515 ret
= FcCharSetEqual (m
.u
.c
, v
.u
.c
);
518 ret
= !FcCharSetEqual (m
.u
.c
, v
.u
.c
);
538 if (op
== FcOpNotEqual
)
546 FcConfigEvaluate (FcPattern
*p
, FcExpr
*e
)
554 v
.type
= FcTypeInteger
;
558 v
.type
= FcTypeDouble
;
562 v
.type
= FcTypeString
;
567 v
.type
= FcTypeMatrix
;
572 v
.type
= FcTypeCharSet
;
581 r
= FcPatternGet (p
, e
->u
.field
, 0, &v
);
582 if (r
!= FcResultMatch
)
586 if (FcNameConstant (e
->u
.constant
, &v
.u
.i
))
587 v
.type
= FcTypeInteger
;
592 vl
= FcConfigEvaluate (p
, e
->u
.tree
.left
);
593 if (vl
.type
== FcTypeBool
)
596 v
= FcConfigEvaluate (p
, e
->u
.tree
.right
->u
.tree
.left
);
598 v
= FcConfigEvaluate (p
, e
->u
.tree
.right
->u
.tree
.right
);
617 vl
= FcConfigEvaluate (p
, e
->u
.tree
.left
);
618 vr
= FcConfigEvaluate (p
, e
->u
.tree
.right
);
619 vl
= FcConfigPromote (vl
, vr
);
620 vr
= FcConfigPromote (vr
, vl
);
621 if (vl
.type
== vr
.type
)
627 v
.type
= FcTypeDouble
;
628 v
.u
.d
= vl
.u
.d
+ vr
.u
.d
;
631 v
.type
= FcTypeDouble
;
632 v
.u
.d
= vl
.u
.d
- vr
.u
.d
;
635 v
.type
= FcTypeDouble
;
636 v
.u
.d
= vl
.u
.d
* vr
.u
.d
;
639 v
.type
= FcTypeDouble
;
640 v
.u
.d
= vl
.u
.d
/ vr
.u
.d
;
645 v
.u
.b
= vl
.u
.d
== vr
.u
.d
;
649 v
.u
.b
= vl
.u
.d
!= vr
.u
.d
;
653 v
.u
.b
= vl
.u
.d
< vr
.u
.d
;
657 v
.u
.b
= vl
.u
.d
<= vr
.u
.d
;
661 v
.u
.b
= vl
.u
.d
> vr
.u
.d
;
665 v
.u
.b
= vl
.u
.d
>= vr
.u
.d
;
671 if (v
.type
== FcTypeDouble
&&
672 v
.u
.d
== (double) (int) v
.u
.d
)
674 v
.type
= FcTypeInteger
;
682 v
.u
.b
= vl
.u
.b
|| vr
.u
.b
;
686 v
.u
.b
= vl
.u
.b
&& vr
.u
.b
;
691 v
.u
.b
= vl
.u
.b
== vr
.u
.b
;
695 v
.u
.b
= vl
.u
.b
!= vr
.u
.b
;
707 v
.u
.b
= FcStrCmpIgnoreCase (vl
.u
.s
, vr
.u
.s
) == 0;
711 v
.u
.b
= FcStrCmpIgnoreCase (vl
.u
.s
, vr
.u
.s
) != 0;
714 v
.type
= FcTypeString
;
715 v
.u
.s
= FcStrPlus (vl
.u
.s
, vr
.u
.s
);
728 v
.u
.b
= FcMatrixEqual (vl
.u
.m
, vr
.u
.m
);
732 v
.u
.b
= FcMatrixEqual (vl
.u
.m
, vr
.u
.m
);
735 v
.type
= FcTypeMatrix
;
736 m
= malloc (sizeof (FcMatrix
));
739 FcMemAlloc (FC_MEM_MATRIX
, sizeof (FcMatrix
));
740 FcMatrixMultiply (m
, vl
.u
.m
, vr
.u
.m
);
756 /* vl contains vr if vr - vl is empty */
758 v
.u
.b
= FcCharSetSubtractCount (vr
.u
.c
, vl
.u
.c
) == 0;
762 v
.u
.b
= FcCharSetEqual (vl
.u
.c
, vr
.u
.c
);
766 v
.u
.b
= !FcCharSetEqual (vl
.u
.c
, vr
.u
.c
);
784 vl
= FcConfigEvaluate (p
, e
->u
.tree
.left
);
804 FcConfigMatchValueList (FcPattern
*p
,
808 FcValueList
*ret
= 0;
809 FcValue value
= FcConfigEvaluate (p
, t
->expr
);
811 for (; v
; v
= v
->next
)
813 if (FcConfigCompareValue (v
->value
, t
->op
, value
))
820 if (t
->qual
== FcQualAll
)
827 FcValueDestroy (value
);
832 FcConfigValues (FcPattern
*p
, FcExpr
*e
)
838 l
= (FcValueList
*) malloc (sizeof (FcValueList
));
841 FcMemAlloc (FC_MEM_VALLIST
, sizeof (FcValueList
));
842 if (e
->op
== FcOpComma
)
844 l
->value
= FcConfigEvaluate (p
, e
->u
.tree
.left
);
845 l
->next
= FcConfigValues (p
, e
->u
.tree
.right
);
849 l
->value
= FcConfigEvaluate (p
, e
);
852 while (l
&& l
->value
.type
== FcTypeVoid
)
854 FcValueList
*next
= l
->next
;
856 FcMemFree (FC_MEM_VALLIST
, sizeof (FcValueList
));
864 FcConfigAdd (FcValueList
**head
,
865 FcValueList
*position
,
869 FcValueList
**prev
, *last
;
874 prev
= &position
->next
;
876 for (prev
= head
; *prev
; prev
= &(*prev
)->next
)
883 for (prev
= head
; *prev
; prev
= &(*prev
)->next
)
885 if (*prev
== position
)
892 if (FcDebug () & FC_DBG_EDIT
)
895 printf ("position not on list\n");
899 if (FcDebug () & FC_DBG_EDIT
)
901 printf ("%s list before ", append
? "Append" : "Prepend");
902 FcValueListPrint (*head
);
916 if (FcDebug () & FC_DBG_EDIT
)
918 printf ("%s list after ", append
? "Append" : "Prepend");
919 FcValueListPrint (*head
);
927 FcConfigDel (FcValueList
**head
,
928 FcValueList
*position
)
932 for (prev
= head
; *prev
; prev
= &(*prev
)->next
)
934 if (*prev
== position
)
936 *prev
= position
->next
;
938 FcValueListDestroy (position
);
945 FcConfigPatternAdd (FcPattern
*p
,
952 FcPatternElt
*e
= FcPatternFind (p
, object
, FcTrue
);
956 FcConfigAdd (&e
->values
, 0, append
, list
);
961 * Delete all values associated with a field
964 FcConfigPatternDel (FcPattern
*p
,
967 FcPatternElt
*e
= FcPatternFind (p
, object
, FcFalse
);
971 FcConfigDel (&e
->values
, e
->values
);
975 FcConfigPatternCanon (FcPattern
*p
,
978 FcPatternElt
*e
= FcPatternFind (p
, object
, FcFalse
);
982 FcPatternDel (p
, object
);
986 FcConfigSubstitute (FcConfig
*config
,
999 config
= FcConfigGetCurrent ();
1004 st
= (FcSubState
*) malloc (config
->maxObjects
* sizeof (FcSubState
));
1005 if (!st
&& config
->maxObjects
)
1007 FcMemAlloc (FC_MEM_SUBSTATE
, config
->maxObjects
* sizeof (FcSubState
));
1009 if (FcDebug () & FC_DBG_EDIT
)
1011 printf ("FcConfigSubstitute ");
1014 if (kind
== FcMatchPattern
)
1015 s
= config
->substPattern
;
1017 s
= config
->substFont
;
1018 for (; s
; s
= s
->next
)
1021 * Check the tests to see if
1022 * they all match the pattern
1024 for (t
= s
->test
, i
= 0; t
; t
= t
->next
, i
++)
1026 if (FcDebug () & FC_DBG_EDIT
)
1028 printf ("FcConfigSubstitute test ");
1031 st
[i
].elt
= FcPatternFind (p
, t
->field
, FcFalse
);
1033 * If there's no such field in the font,
1034 * then FcQualAll matches while FcQualAny does not
1038 if (t
->qual
== FcQualAll
)
1047 * Check to see if there is a match, mark the location
1048 * to apply match-relative edits
1050 st
[i
].value
= FcConfigMatchValueList (p
, t
, st
[i
].elt
->values
);
1056 if (FcDebug () & FC_DBG_EDIT
)
1057 printf ("No match\n");
1060 if (FcDebug () & FC_DBG_EDIT
)
1062 printf ("Substitute ");
1065 for (e
= s
->edit
; e
; e
= e
->next
)
1068 * Evaluate the list of expressions
1070 l
= FcConfigValues (p
, e
->expr
);
1072 * Locate any test associated with this field
1074 for (t
= s
->test
, i
= 0; t
; t
= t
->next
, i
++)
1075 if (!FcStrCmpIgnoreCase ((FcChar8
*) t
->field
, (FcChar8
*) e
->field
))
1080 * If there was a test, then replace the matched
1081 * value with the new list of values
1085 FcValueList
*thisValue
= st
[i
].value
;
1086 FcValueList
*nextValue
= thisValue
? thisValue
->next
: 0;
1089 * Append the new list of values after the current value
1091 FcConfigAdd (&st
[i
].elt
->values
, thisValue
, FcTrue
, l
);
1093 * Delete the marked value
1095 FcConfigDel (&st
[i
].elt
->values
, thisValue
);
1097 * Adjust any pointers into the value list to ensure
1098 * future edits occur at the same place
1100 for (t
= s
->test
, i
= 0; t
; t
= t
->next
, i
++)
1102 if (st
[i
].value
== thisValue
)
1103 st
[i
].value
= nextValue
;
1107 /* fall through ... */
1108 case FcOpAssignReplace
:
1110 * Delete all of the values and insert
1113 FcConfigPatternDel (p
, e
->field
);
1114 FcConfigPatternAdd (p
, e
->field
, l
, FcTrue
);
1116 * Adjust any pointers into the value list as they no
1117 * longer point to anything valid
1121 FcPatternElt
*thisElt
= st
[i
].elt
;
1122 for (t
= s
->test
, i
= 0; t
; t
= t
->next
, i
++)
1124 if (st
[i
].elt
== thisElt
)
1132 FcConfigAdd (&st
[i
].elt
->values
, st
[i
].value
, FcFalse
, l
);
1135 /* fall through ... */
1136 case FcOpPrependFirst
:
1137 FcConfigPatternAdd (p
, e
->field
, l
, FcFalse
);
1142 FcConfigAdd (&st
[i
].elt
->values
, st
[i
].value
, FcTrue
, l
);
1145 /* fall through ... */
1146 case FcOpAppendLast
:
1147 FcConfigPatternAdd (p
, e
->field
, l
, FcTrue
);
1154 * Now go through the pattern and eliminate
1155 * any properties without data
1157 for (e
= s
->edit
; e
; e
= e
->next
)
1158 FcConfigPatternCanon (p
, e
->field
);
1160 if (FcDebug () & FC_DBG_EDIT
)
1162 printf ("FcConfigSubstitute edit");
1166 FcMemFree (FC_MEM_SUBSTATE
, config
->maxObjects
* sizeof (FcSubState
));
1168 if (FcDebug () & FC_DBG_EDIT
)
1170 printf ("FcConfigSubstitute done");
1176 #ifndef FONTCONFIG_PATH
1177 #define FONTCONFIG_PATH "/etc/fonts"
1180 #ifndef FONTCONFIG_FILE
1181 #define FONTCONFIG_FILE "fonts.conf"
1185 FcConfigFileExists (const FcChar8
*dir
, const FcChar8
*file
)
1190 dir
= (FcChar8
*) "";
1191 path
= malloc (strlen ((char *) dir
) + 1 + strlen ((char *) file
) + 1);
1196 /* make sure there's a single separating / */
1197 if ((!path
[0] || path
[strlen((char *) path
)-1] != '/') && file
[0] != '/')
1198 strcat ((char *) path
, "/");
1199 strcat ((char *) path
, (char *) file
);
1201 if (access ((char *) path
, R_OK
) == 0)
1209 FcConfigGetPath (void)
1212 FcChar8
*env
, *e
, *colon
;
1217 npath
= 2; /* default dir + null */
1218 env
= (FcChar8
*) getenv ("FONTCONFIG_PATH");
1227 path
= calloc (npath
, sizeof (FcChar8
*));
1237 colon
= (FcChar8
*) strchr ((char *) e
, ':');
1239 colon
= e
+ strlen ((char *) e
);
1240 path
[i
] = malloc (colon
- e
+ 1);
1243 strncpy (path
[i
], e
, colon
- e
);
1244 path
[i
][colon
- e
] = '\0';
1253 dir
= (FcChar8
*) FONTCONFIG_PATH
;
1254 path
[i
] = malloc (strlen ((char *) dir
) + 1);
1257 strcpy (path
[i
], dir
);
1261 for (i
= 0; path
[i
]; i
++)
1269 FcConfigFreePath (FcChar8
**path
)
1273 for (p
= path
; *p
; p
++)
1279 FcConfigFilename (const FcChar8
*url
)
1281 FcChar8
*file
, *dir
, **path
, **p
;
1285 url
= (FcChar8
*) getenv ("FONTCONFIG_FILE");
1287 url
= (FcChar8
*) FONTCONFIG_FILE
;
1292 dir
= (FcChar8
*) getenv ("HOME");
1294 file
= FcConfigFileExists (dir
, url
+ 1);
1299 file
= FcConfigFileExists (0, url
);
1302 path
= FcConfigGetPath ();
1305 for (p
= path
; *p
; p
++)
1307 file
= FcConfigFileExists (*p
, url
);
1311 FcConfigFreePath (path
);
1318 * Manage the application-specific fonts
1322 FcConfigAppFontAddFile (FcConfig
*config
,
1323 const FcChar8
*file
)
1329 config
= FcConfigGetCurrent ();
1334 set
= FcConfigGetFonts (config
, FcSetApplication
);
1337 set
= FcFontSetCreate ();
1340 FcConfigSetFonts (config
, set
, FcSetApplication
);
1342 return FcFileScan (set
, 0, config
->blanks
, file
, FcFalse
);
1346 FcConfigAppFontAddDir (FcConfig
*config
,
1353 config
= FcConfigGetCurrent ();
1357 set
= FcConfigGetFonts (config
, FcSetApplication
);
1360 set
= FcFontSetCreate ();
1363 FcConfigSetFonts (config
, set
, FcSetApplication
);
1365 return FcDirScan (set
, 0, config
->blanks
, dir
, FcFalse
);
1369 FcConfigAppFontClear (FcConfig
*config
)
1371 FcConfigSetFonts (config
, 0, FcSetApplication
);