fccfg.c revision 2c393a42
1/*
2 * $RCSId: xc/lib/fontconfig/src/fccfg.c,v 1.23 2002/08/31 22:17:32 keithp Exp $
3 *
4 * Copyright © 2000 Keith Packard
5 *
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.
15 *
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.
23 */
24
25#include "fcint.h"
26#include <dirent.h>
27#include <sys/types.h>
28
29#if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT))
30#define STRICT
31#include <windows.h>
32#undef STRICT
33#endif
34
35#if defined (_WIN32) && !defined (R_OK)
36#define R_OK 4
37#endif
38
39FcConfig    *_fcConfig;
40
41FcConfig *
42FcConfigCreate (void)
43{
44    FcSetName	set;
45    FcConfig	*config;
46
47    config = malloc (sizeof (FcConfig));
48    if (!config)
49	goto bail0;
50    FcMemAlloc (FC_MEM_CONFIG, sizeof (FcConfig));
51
52    config->configDirs = FcStrSetCreate ();
53    if (!config->configDirs)
54	goto bail1;
55
56    config->configFiles = FcStrSetCreate ();
57    if (!config->configFiles)
58	goto bail2;
59
60    config->fontDirs = FcStrSetCreate ();
61    if (!config->fontDirs)
62	goto bail3;
63
64    config->acceptGlobs = FcStrSetCreate ();
65    if (!config->acceptGlobs)
66	goto bail4;
67
68    config->rejectGlobs = FcStrSetCreate ();
69    if (!config->rejectGlobs)
70	goto bail5;
71
72    config->acceptPatterns = FcFontSetCreate ();
73    if (!config->acceptPatterns)
74	goto bail6;
75
76    config->rejectPatterns = FcFontSetCreate ();
77    if (!config->rejectPatterns)
78	goto bail7;
79
80    config->cacheDirs = FcStrSetCreate ();
81    if (!config->cacheDirs)
82	goto bail8;
83
84    config->blanks = 0;
85
86    config->substPattern = 0;
87    config->substFont = 0;
88    config->substScan = 0;
89    config->maxObjects = 0;
90    for (set = FcSetSystem; set <= FcSetApplication; set++)
91	config->fonts[set] = 0;
92
93    config->rescanTime = time(0);
94    config->rescanInterval = 30;
95
96    return config;
97
98bail8:
99    FcFontSetDestroy (config->rejectPatterns);
100bail7:
101    FcFontSetDestroy (config->acceptPatterns);
102bail6:
103    FcStrSetDestroy (config->rejectGlobs);
104bail5:
105    FcStrSetDestroy (config->acceptGlobs);
106bail4:
107    FcStrSetDestroy (config->fontDirs);
108bail3:
109    FcStrSetDestroy (config->configFiles);
110bail2:
111    FcStrSetDestroy (config->configDirs);
112bail1:
113    free (config);
114    FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
115bail0:
116    return 0;
117}
118
119static FcFileTime
120FcConfigNewestFile (FcStrSet *files)
121{
122    FcStrList	    *list = FcStrListCreate (files);
123    FcFileTime	    newest = { 0, FcFalse };
124    FcChar8	    *file;
125    struct  stat    statb;
126
127    if (list)
128    {
129	while ((file = FcStrListNext (list)))
130	    if (stat ((char *) file, &statb) == 0)
131		if (!newest.set || statb.st_mtime - newest.time > 0)
132		{
133		    newest.set = FcTrue;
134		    newest.time = statb.st_mtime;
135		}
136	FcStrListDone (list);
137    }
138    return newest;
139}
140
141FcBool
142FcConfigUptoDate (FcConfig *config)
143{
144    FcFileTime	config_time, config_dir_time, font_time;
145    time_t	now = time(0);
146    if (!config)
147    {
148	config = FcConfigGetCurrent ();
149	if (!config)
150	    return FcFalse;
151    }
152    config_time = FcConfigNewestFile (config->configFiles);
153    config_dir_time = FcConfigNewestFile (config->configDirs);
154    font_time = FcConfigNewestFile (config->fontDirs);
155    if ((config_time.set && config_time.time - config->rescanTime > 0) ||
156	(config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) ||
157	(font_time.set && (font_time.time - config->rescanTime) > 0))
158    {
159	/* We need to check for potential clock problems here (OLPC ticket #6046) */
160	if ((config_time.set && (config_time.time - now) > 0) ||
161    	(config_dir_time.set && (config_dir_time.time - now) > 0) ||
162        (font_time.set && (font_time.time - now) > 0))
163	{
164	    fprintf (stderr,
165                    "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected\n");
166	    config->rescanTime = now;
167	    return FcTrue;
168	}
169	else
170	    return FcFalse;
171    }
172    config->rescanTime = now;
173    return FcTrue;
174}
175
176static void
177FcSubstDestroy (FcSubst *s)
178{
179    FcSubst *n;
180
181    while (s)
182    {
183	n = s->next;
184	if (s->test)
185	    FcTestDestroy (s->test);
186	if (s->edit)
187	    FcEditDestroy (s->edit);
188	free (s);
189	FcMemFree (FC_MEM_SUBST, sizeof (FcSubst));
190	s = n;
191    }
192}
193
194void
195FcConfigDestroy (FcConfig *config)
196{
197    FcSetName	set;
198
199    if (config == _fcConfig)
200	_fcConfig = 0;
201
202    FcStrSetDestroy (config->configDirs);
203    FcStrSetDestroy (config->fontDirs);
204    FcStrSetDestroy (config->cacheDirs);
205    FcStrSetDestroy (config->configFiles);
206    FcStrSetDestroy (config->acceptGlobs);
207    FcStrSetDestroy (config->rejectGlobs);
208    FcFontSetDestroy (config->acceptPatterns);
209    FcFontSetDestroy (config->rejectPatterns);
210
211    if (config->blanks)
212	FcBlanksDestroy (config->blanks);
213
214    FcSubstDestroy (config->substPattern);
215    FcSubstDestroy (config->substFont);
216    FcSubstDestroy (config->substScan);
217    for (set = FcSetSystem; set <= FcSetApplication; set++)
218	if (config->fonts[set])
219	    FcFontSetDestroy (config->fonts[set]);
220
221    free (config);
222    FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
223}
224
225/*
226 * Add cache to configuration, adding fonts and directories
227 */
228
229FcBool
230FcConfigAddCache (FcConfig *config, FcCache *cache,
231		  FcSetName set, FcStrSet *dirSet)
232{
233    FcFontSet	*fs;
234    intptr_t	*dirs;
235    int		i;
236
237    /*
238     * Add fonts
239     */
240    fs = FcCacheSet (cache);
241    if (fs)
242    {
243	int	nref = 0;
244
245	for (i = 0; i < fs->nfont; i++)
246	{
247	    FcPattern	*font = FcFontSetFont (fs, i);
248	    FcChar8	*font_file;
249
250	    /*
251	     * Check to see if font is banned by filename
252	     */
253	    if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
254					  0, &font_file) == FcResultMatch &&
255		!FcConfigAcceptFilename (config, font_file))
256	    {
257		continue;
258	    }
259
260	    /*
261	     * Check to see if font is banned by pattern
262	     */
263	    if (!FcConfigAcceptFont (config, font))
264		continue;
265
266	    nref++;
267	    FcFontSetAdd (config->fonts[set], font);
268	}
269	FcDirCacheReference (cache, nref);
270    }
271
272    /*
273     * Add directories
274     */
275    dirs = FcCacheDirs (cache);
276    if (dirs)
277    {
278	for (i = 0; i < cache->dirs_count; i++)
279	{
280	    FcChar8	*dir = FcOffsetToPtr (dirs, dirs[i], FcChar8);
281	    if (FcConfigAcceptFilename (config, dir))
282		FcStrSetAddFilename (dirSet, dir);
283	}
284    }
285    return FcTrue;
286}
287
288static FcBool
289FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
290{
291    FcStrList	    *dirlist;
292    FcChar8	    *dir;
293    FcCache	    *cache;
294
295    dirlist = FcStrListCreate (dirSet);
296    if (!dirlist)
297        return FcFalse;
298
299    while ((dir = FcStrListNext (dirlist)))
300    {
301	if (FcDebug () & FC_DBG_FONTSET)
302	    printf ("adding fonts from%s\n", dir);
303	cache = FcDirCacheRead (dir, FcFalse, config);
304	if (!cache)
305	    continue;
306	FcConfigAddCache (config, cache, set, dirSet);
307	FcDirCacheUnload (cache);
308    }
309    FcStrListDone (dirlist);
310    return FcTrue;
311}
312
313/*
314 * Scan the current list of directories in the configuration
315 * and build the set of available fonts.
316 */
317
318FcBool
319FcConfigBuildFonts (FcConfig *config)
320{
321    FcFontSet	    *fonts;
322
323    if (!config)
324    {
325	config = FcConfigGetCurrent ();
326	if (!config)
327	    return FcFalse;
328    }
329
330    fonts = FcFontSetCreate ();
331    if (!fonts)
332	return FcFalse;
333
334    FcConfigSetFonts (config, fonts, FcSetSystem);
335
336    if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs))
337	return FcFalse;
338    if (FcDebug () & FC_DBG_FONTSET)
339	FcFontSetPrint (fonts);
340    return FcTrue;
341}
342
343FcBool
344FcConfigSetCurrent (FcConfig *config)
345{
346    if (config == _fcConfig)
347	return FcTrue;
348
349    if (!config->fonts)
350	if (!FcConfigBuildFonts (config))
351	    return FcFalse;
352
353    if (_fcConfig)
354	FcConfigDestroy (_fcConfig);
355    _fcConfig = config;
356    return FcTrue;
357}
358
359FcConfig *
360FcConfigGetCurrent (void)
361{
362    if (!_fcConfig)
363	if (!FcInit ())
364	    return 0;
365    return _fcConfig;
366}
367
368FcBool
369FcConfigAddConfigDir (FcConfig	    *config,
370		      const FcChar8 *d)
371{
372    return FcStrSetAddFilename (config->configDirs, d);
373}
374
375FcStrList *
376FcConfigGetConfigDirs (FcConfig   *config)
377{
378    if (!config)
379    {
380	config = FcConfigGetCurrent ();
381	if (!config)
382	    return 0;
383    }
384    return FcStrListCreate (config->configDirs);
385}
386
387FcBool
388FcConfigAddFontDir (FcConfig	    *config,
389		    const FcChar8   *d)
390{
391    return FcStrSetAddFilename (config->fontDirs, d);
392}
393
394FcBool
395FcConfigAddDir (FcConfig	    *config,
396		const FcChar8	    *d)
397{
398    return (FcConfigAddConfigDir (config, d) &&
399	    FcConfigAddFontDir (config, d));
400}
401
402FcStrList *
403FcConfigGetFontDirs (FcConfig	*config)
404{
405    if (!config)
406    {
407	config = FcConfigGetCurrent ();
408	if (!config)
409	    return 0;
410    }
411    return FcStrListCreate (config->fontDirs);
412}
413
414FcBool
415FcConfigAddCacheDir (FcConfig	    *config,
416		     const FcChar8  *d)
417{
418    return FcStrSetAddFilename (config->cacheDirs, d);
419}
420
421FcStrList *
422FcConfigGetCacheDirs (FcConfig	*config)
423{
424    if (!config)
425    {
426	config = FcConfigGetCurrent ();
427	if (!config)
428	    return 0;
429    }
430    return FcStrListCreate (config->cacheDirs);
431}
432
433FcBool
434FcConfigAddConfigFile (FcConfig	    *config,
435		       const FcChar8   *f)
436{
437    FcBool	ret;
438    FcChar8	*file = FcConfigFilename (f);
439
440    if (!file)
441	return FcFalse;
442
443    ret = FcStrSetAdd (config->configFiles, file);
444    FcStrFree (file);
445    return ret;
446}
447
448FcStrList *
449FcConfigGetConfigFiles (FcConfig    *config)
450{
451    if (!config)
452    {
453	config = FcConfigGetCurrent ();
454	if (!config)
455	    return 0;
456    }
457    return FcStrListCreate (config->configFiles);
458}
459
460FcChar8 *
461FcConfigGetCache (FcConfig  *config)
462{
463    return NULL;
464}
465
466FcFontSet *
467FcConfigGetFonts (FcConfig	*config,
468		  FcSetName	set)
469{
470    if (!config)
471    {
472	config = FcConfigGetCurrent ();
473	if (!config)
474	    return 0;
475    }
476    return config->fonts[set];
477}
478
479void
480FcConfigSetFonts (FcConfig	*config,
481		  FcFontSet	*fonts,
482		  FcSetName	set)
483{
484    if (config->fonts[set])
485	FcFontSetDestroy (config->fonts[set]);
486    config->fonts[set] = fonts;
487}
488
489FcBlanks *
490FcConfigGetBlanks (FcConfig	*config)
491{
492    if (!config)
493    {
494	config = FcConfigGetCurrent ();
495	if (!config)
496	    return 0;
497    }
498    return config->blanks;
499}
500
501FcBool
502FcConfigAddBlank (FcConfig	*config,
503		  FcChar32    	blank)
504{
505    FcBlanks	*b, *freeme = 0;
506
507    b = config->blanks;
508    if (!b)
509    {
510	freeme = b = FcBlanksCreate ();
511	if (!b)
512	    return FcFalse;
513    }
514    if (!FcBlanksAdd (b, blank))
515    {
516        if (freeme)
517            FcBlanksDestroy (freeme);
518	return FcFalse;
519    }
520    config->blanks = b;
521    return FcTrue;
522}
523
524int
525FcConfigGetRescanInterval (FcConfig *config)
526{
527    if (!config)
528    {
529	config = FcConfigGetCurrent ();
530	if (!config)
531	    return 0;
532    }
533    return config->rescanInterval;
534}
535
536FcBool
537FcConfigSetRescanInterval (FcConfig *config, int rescanInterval)
538{
539    if (!config)
540    {
541	config = FcConfigGetCurrent ();
542	if (!config)
543	    return FcFalse;
544    }
545    config->rescanInterval = rescanInterval;
546    return FcTrue;
547}
548
549/*
550 * A couple of typos escaped into the library
551 */
552int
553FcConfigGetRescanInverval (FcConfig *config)
554{
555    return FcConfigGetRescanInterval (config);
556}
557
558FcBool
559FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
560{
561    return FcConfigSetRescanInterval (config, rescanInterval);
562}
563
564
565FcBool
566FcConfigAddEdit (FcConfig	*config,
567		 FcTest		*test,
568		 FcEdit		*edit,
569		 FcMatchKind	kind)
570{
571    FcSubst	*subst, **prev;
572    FcTest	*t;
573    int		num;
574
575    switch (kind) {
576    case FcMatchPattern:
577	prev = &config->substPattern;
578	break;
579    case FcMatchFont:
580	prev = &config->substFont;
581	break;
582    case FcMatchScan:
583	prev = &config->substScan;
584	break;
585    default:
586	return FcFalse;
587    }
588    subst = (FcSubst *) malloc (sizeof (FcSubst));
589    if (!subst)
590	return FcFalse;
591    FcMemAlloc (FC_MEM_SUBST, sizeof (FcSubst));
592    for (; *prev; prev = &(*prev)->next);
593    *prev = subst;
594    subst->next = 0;
595    subst->test = test;
596    subst->edit = edit;
597    num = 0;
598    for (t = test; t; t = t->next)
599    {
600	if (t->kind == FcMatchDefault)
601	    t->kind = kind;
602	num++;
603    }
604    if (config->maxObjects < num)
605	config->maxObjects = num;
606    if (FcDebug () & FC_DBG_EDIT)
607    {
608	printf ("Add Subst ");
609	FcSubstPrint (subst);
610    }
611    return FcTrue;
612}
613
614typedef struct _FcSubState {
615    FcPatternElt   *elt;
616    FcValueList    *value;
617} FcSubState;
618
619static FcValue
620FcConfigPromote (FcValue v, FcValue u)
621{
622    if (v.type == FcTypeInteger)
623    {
624	v.type = FcTypeDouble;
625	v.u.d = (double) v.u.i;
626    }
627    else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
628    {
629	v.u.m = &FcIdentityMatrix;
630	v.type = FcTypeMatrix;
631    }
632    else if (v.type == FcTypeString && u.type == FcTypeLangSet)
633    {
634	v.u.l = FcLangSetPromote (v.u.s);
635	v.type = FcTypeLangSet;
636    }
637    return v;
638}
639
640FcBool
641FcConfigCompareValue (const FcValue	*left_o,
642		      FcOp		op,
643		      const FcValue	*right_o)
644{
645    FcValue	left = FcValueCanonicalize(left_o);
646    FcValue	right = FcValueCanonicalize(right_o);
647    FcBool	ret = FcFalse;
648
649    left = FcConfigPromote (left, right);
650    right = FcConfigPromote (right, left);
651    if (left.type == right.type)
652    {
653	switch (left.type) {
654	case FcTypeInteger:
655	    break;	/* FcConfigPromote prevents this from happening */
656	case FcTypeDouble:
657	    switch (op) {
658	    case FcOpEqual:
659	    case FcOpContains:
660	    case FcOpListing:
661		ret = left.u.d == right.u.d;
662		break;
663	    case FcOpNotEqual:
664	    case FcOpNotContains:
665		ret = left.u.d != right.u.d;
666		break;
667	    case FcOpLess:
668		ret = left.u.d < right.u.d;
669		break;
670	    case FcOpLessEqual:
671		ret = left.u.d <= right.u.d;
672		break;
673	    case FcOpMore:
674		ret = left.u.d > right.u.d;
675		break;
676	    case FcOpMoreEqual:
677		ret = left.u.d >= right.u.d;
678		break;
679	    default:
680		break;
681	    }
682	    break;
683	case FcTypeBool:
684	    switch (op) {
685	    case FcOpEqual:
686	    case FcOpContains:
687	    case FcOpListing:
688		ret = left.u.b == right.u.b;
689		break;
690	    case FcOpNotEqual:
691	    case FcOpNotContains:
692		ret = left.u.b != right.u.b;
693		break;
694	    default:
695		break;
696	    }
697	    break;
698	case FcTypeString:
699	    switch (op) {
700	    case FcOpEqual:
701	    case FcOpListing:
702		ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
703		break;
704	    case FcOpContains:
705		ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
706		break;
707	    case FcOpNotEqual:
708		ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
709		break;
710	    case FcOpNotContains:
711		ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
712		break;
713	    default:
714		break;
715	    }
716	    break;
717	case FcTypeMatrix:
718	    switch (op) {
719	    case FcOpEqual:
720	    case FcOpContains:
721	    case FcOpListing:
722		ret = FcMatrixEqual (left.u.m, right.u.m);
723		break;
724	    case FcOpNotEqual:
725	    case FcOpNotContains:
726		ret = !FcMatrixEqual (left.u.m, right.u.m);
727		break;
728	    default:
729		break;
730	    }
731	    break;
732	case FcTypeCharSet:
733	    switch (op) {
734	    case FcOpContains:
735	    case FcOpListing:
736		/* left contains right if right is a subset of left */
737		ret = FcCharSetIsSubset (right.u.c, left.u.c);
738		break;
739	    case FcOpNotContains:
740		/* left contains right if right is a subset of left */
741		ret = !FcCharSetIsSubset (right.u.c, left.u.c);
742		break;
743	    case FcOpEqual:
744		ret = FcCharSetEqual (left.u.c, right.u.c);
745		break;
746	    case FcOpNotEqual:
747		ret = !FcCharSetEqual (left.u.c, right.u.c);
748		break;
749	    default:
750		break;
751	    }
752	    break;
753	case FcTypeLangSet:
754	    switch (op) {
755	    case FcOpContains:
756	    case FcOpListing:
757		ret = FcLangSetContains (left.u.l, right.u.l);
758		break;
759	    case FcOpNotContains:
760		ret = !FcLangSetContains (left.u.l, right.u.l);
761		break;
762	    case FcOpEqual:
763		ret = FcLangSetEqual (left.u.l, right.u.l);
764		break;
765	    case FcOpNotEqual:
766		ret = !FcLangSetEqual (left.u.l, right.u.l);
767		break;
768	    default:
769		break;
770	    }
771	    break;
772	case FcTypeVoid:
773	    switch (op) {
774	    case FcOpEqual:
775	    case FcOpContains:
776	    case FcOpListing:
777		ret = FcTrue;
778		break;
779	    default:
780		break;
781	    }
782	    break;
783	case FcTypeFTFace:
784	    switch (op) {
785	    case FcOpEqual:
786	    case FcOpContains:
787	    case FcOpListing:
788		ret = left.u.f == right.u.f;
789		break;
790	    case FcOpNotEqual:
791	    case FcOpNotContains:
792		ret = left.u.f != right.u.f;
793		break;
794	    default:
795		break;
796	    }
797	    break;
798	}
799    }
800    else
801    {
802	if (op == FcOpNotEqual || op == FcOpNotContains)
803	    ret = FcTrue;
804    }
805    return ret;
806}
807
808
809#define _FcDoubleFloor(d)	((int) (d))
810#define _FcDoubleCeil(d)	((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
811#define FcDoubleFloor(d)	((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
812#define FcDoubleCeil(d)		((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
813#define FcDoubleRound(d)	FcDoubleFloor ((d) + 0.5)
814#define FcDoubleTrunc(d)	((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
815
816static FcValue
817FcConfigEvaluate (FcPattern *p, FcExpr *e)
818{
819    FcValue	v, vl, vr;
820    FcResult	r;
821    FcMatrix	*m;
822    FcChar8     *str;
823
824    switch (e->op) {
825    case FcOpInteger:
826	v.type = FcTypeInteger;
827	v.u.i = e->u.ival;
828	break;
829    case FcOpDouble:
830	v.type = FcTypeDouble;
831	v.u.d = e->u.dval;
832	break;
833    case FcOpString:
834	v.type = FcTypeString;
835	v.u.s = FcStrStaticName(e->u.sval);
836	break;
837    case FcOpMatrix:
838	v.type = FcTypeMatrix;
839	v.u.m = e->u.mval;
840	v = FcValueSave (v);
841	break;
842    case FcOpCharSet:
843	v.type = FcTypeCharSet;
844	v.u.c = e->u.cval;
845	v = FcValueSave (v);
846	break;
847    case FcOpBool:
848	v.type = FcTypeBool;
849	v.u.b = e->u.bval;
850	break;
851    case FcOpField:
852	r = FcPatternObjectGet (p, e->u.object, 0, &v);
853	if (r != FcResultMatch)
854	    v.type = FcTypeVoid;
855	v = FcValueSave (v);
856	break;
857    case FcOpConst:
858	if (FcNameConstant (e->u.constant, &v.u.i))
859	    v.type = FcTypeInteger;
860	else
861	    v.type = FcTypeVoid;
862	break;
863    case FcOpQuest:
864	vl = FcConfigEvaluate (p, e->u.tree.left);
865	if (vl.type == FcTypeBool)
866	{
867	    if (vl.u.b)
868		v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
869	    else
870		v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
871	}
872	else
873	    v.type = FcTypeVoid;
874	FcValueDestroy (vl);
875	break;
876    case FcOpEqual:
877    case FcOpNotEqual:
878    case FcOpLess:
879    case FcOpLessEqual:
880    case FcOpMore:
881    case FcOpMoreEqual:
882    case FcOpContains:
883    case FcOpNotContains:
884    case FcOpListing:
885	vl = FcConfigEvaluate (p, e->u.tree.left);
886	vr = FcConfigEvaluate (p, e->u.tree.right);
887	v.type = FcTypeBool;
888	v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
889	FcValueDestroy (vl);
890	FcValueDestroy (vr);
891	break;
892    case FcOpOr:
893    case FcOpAnd:
894    case FcOpPlus:
895    case FcOpMinus:
896    case FcOpTimes:
897    case FcOpDivide:
898	vl = FcConfigEvaluate (p, e->u.tree.left);
899	vr = FcConfigEvaluate (p, e->u.tree.right);
900	vl = FcConfigPromote (vl, vr);
901	vr = FcConfigPromote (vr, vl);
902	if (vl.type == vr.type)
903	{
904	    switch (vl.type) {
905	    case FcTypeDouble:
906		switch (e->op) {
907		case FcOpPlus:
908		    v.type = FcTypeDouble;
909		    v.u.d = vl.u.d + vr.u.d;
910		    break;
911		case FcOpMinus:
912		    v.type = FcTypeDouble;
913		    v.u.d = vl.u.d - vr.u.d;
914		    break;
915		case FcOpTimes:
916		    v.type = FcTypeDouble;
917		    v.u.d = vl.u.d * vr.u.d;
918		    break;
919		case FcOpDivide:
920		    v.type = FcTypeDouble;
921		    v.u.d = vl.u.d / vr.u.d;
922		    break;
923		default:
924		    v.type = FcTypeVoid;
925		    break;
926		}
927		if (v.type == FcTypeDouble &&
928		    v.u.d == (double) (int) v.u.d)
929		{
930		    v.type = FcTypeInteger;
931		    v.u.i = (int) v.u.d;
932		}
933		break;
934	    case FcTypeBool:
935		switch (e->op) {
936		case FcOpOr:
937		    v.type = FcTypeBool;
938		    v.u.b = vl.u.b || vr.u.b;
939		    break;
940		case FcOpAnd:
941		    v.type = FcTypeBool;
942		    v.u.b = vl.u.b && vr.u.b;
943		    break;
944		default:
945		    v.type = FcTypeVoid;
946		    break;
947		}
948		break;
949	    case FcTypeString:
950		switch (e->op) {
951		case FcOpPlus:
952		    v.type = FcTypeString;
953		    str = FcStrPlus (vl.u.s, vr.u.s);
954		    v.u.s = FcStrStaticName (str);
955		    FcStrFree (str);
956
957		    if (!v.u.s)
958			v.type = FcTypeVoid;
959		    break;
960		default:
961		    v.type = FcTypeVoid;
962		    break;
963		}
964		break;
965	    case FcTypeMatrix:
966		switch (e->op) {
967		case FcOpTimes:
968		    v.type = FcTypeMatrix;
969		    m = malloc (sizeof (FcMatrix));
970		    if (m)
971		    {
972			FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
973			FcMatrixMultiply (m, vl.u.m, vr.u.m);
974			v.u.m = m;
975		    }
976		    else
977		    {
978			v.type = FcTypeVoid;
979		    }
980		    break;
981		default:
982		    v.type = FcTypeVoid;
983		    break;
984		}
985		break;
986	    default:
987		v.type = FcTypeVoid;
988		break;
989	    }
990	}
991	else
992	    v.type = FcTypeVoid;
993	FcValueDestroy (vl);
994	FcValueDestroy (vr);
995	break;
996    case FcOpNot:
997	vl = FcConfigEvaluate (p, e->u.tree.left);
998	switch (vl.type) {
999	case FcTypeBool:
1000	    v.type = FcTypeBool;
1001	    v.u.b = !vl.u.b;
1002	    break;
1003	default:
1004	    v.type = FcTypeVoid;
1005	    break;
1006	}
1007	FcValueDestroy (vl);
1008	break;
1009    case FcOpFloor:
1010	vl = FcConfigEvaluate (p, e->u.tree.left);
1011	switch (vl.type) {
1012	case FcTypeInteger:
1013	    v = vl;
1014	    break;
1015	case FcTypeDouble:
1016	    v.type = FcTypeInteger;
1017	    v.u.i = FcDoubleFloor (vl.u.d);
1018	    break;
1019	default:
1020	    v.type = FcTypeVoid;
1021	    break;
1022	}
1023	FcValueDestroy (vl);
1024	break;
1025    case FcOpCeil:
1026	vl = FcConfigEvaluate (p, e->u.tree.left);
1027	switch (vl.type) {
1028	case FcTypeInteger:
1029	    v = vl;
1030	    break;
1031	case FcTypeDouble:
1032	    v.type = FcTypeInteger;
1033	    v.u.i = FcDoubleCeil (vl.u.d);
1034	    break;
1035	default:
1036	    v.type = FcTypeVoid;
1037	    break;
1038	}
1039	FcValueDestroy (vl);
1040	break;
1041    case FcOpRound:
1042	vl = FcConfigEvaluate (p, e->u.tree.left);
1043	switch (vl.type) {
1044	case FcTypeInteger:
1045	    v = vl;
1046	    break;
1047	case FcTypeDouble:
1048	    v.type = FcTypeInteger;
1049	    v.u.i = FcDoubleRound (vl.u.d);
1050	    break;
1051	default:
1052	    v.type = FcTypeVoid;
1053	    break;
1054	}
1055	FcValueDestroy (vl);
1056	break;
1057    case FcOpTrunc:
1058	vl = FcConfigEvaluate (p, e->u.tree.left);
1059	switch (vl.type) {
1060	case FcTypeInteger:
1061	    v = vl;
1062	    break;
1063	case FcTypeDouble:
1064	    v.type = FcTypeInteger;
1065	    v.u.i = FcDoubleTrunc (vl.u.d);
1066	    break;
1067	default:
1068	    v.type = FcTypeVoid;
1069	    break;
1070	}
1071	FcValueDestroy (vl);
1072	break;
1073    default:
1074	v.type = FcTypeVoid;
1075	break;
1076    }
1077    return v;
1078}
1079
1080static FcValueList *
1081FcConfigMatchValueList (FcPattern	*p,
1082			FcTest		*t,
1083			FcValueList	*values)
1084{
1085    FcValueList	    *ret = 0;
1086    FcExpr	    *e = t->expr;
1087    FcValue	    value;
1088    FcValueList	    *v;
1089
1090    while (e)
1091    {
1092	/* Compute the value of the match expression */
1093	if (e->op == FcOpComma)
1094	{
1095	    value = FcConfigEvaluate (p, e->u.tree.left);
1096	    e = e->u.tree.right;
1097	}
1098	else
1099	{
1100	    value = FcConfigEvaluate (p, e);
1101	    e = 0;
1102	}
1103
1104	for (v = values; v; v = FcValueListNext(v))
1105	{
1106	    /* Compare the pattern value to the match expression value */
1107	    if (FcConfigCompareValue (&v->value, t->op, &value))
1108	    {
1109		if (!ret)
1110		    ret = v;
1111	    }
1112	    else
1113	    {
1114		if (t->qual == FcQualAll)
1115		{
1116		    ret = 0;
1117		    break;
1118		}
1119	    }
1120	}
1121	FcValueDestroy (value);
1122    }
1123    return ret;
1124}
1125
1126static FcValueList *
1127FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding)
1128{
1129    FcValueList	*l;
1130
1131    if (!e)
1132	return 0;
1133    l = (FcValueList *) malloc (sizeof (FcValueList));
1134    if (!l)
1135	return 0;
1136    FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
1137    if (e->op == FcOpComma)
1138    {
1139	l->value = FcConfigEvaluate (p, e->u.tree.left);
1140	l->next = FcConfigValues (p, e->u.tree.right, binding);
1141    }
1142    else
1143    {
1144	l->value = FcConfigEvaluate (p, e);
1145	l->next = NULL;
1146    }
1147    l->binding = binding;
1148    if (l->value.type == FcTypeVoid)
1149    {
1150	FcValueList  *next = FcValueListNext(l);
1151
1152	FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
1153	free (l);
1154	l = next;
1155    }
1156
1157    return l;
1158}
1159
1160static FcBool
1161FcConfigAdd (FcValueListPtr *head,
1162	     FcValueList    *position,
1163	     FcBool	    append,
1164	     FcValueList    *new)
1165{
1166    FcValueListPtr  *prev, last, v;
1167    FcValueBinding  sameBinding;
1168
1169    if (position)
1170	sameBinding = position->binding;
1171    else
1172	sameBinding = FcValueBindingWeak;
1173    for (v = new; v != NULL; v = FcValueListNext(v))
1174	if (v->binding == FcValueBindingSame)
1175	    v->binding = sameBinding;
1176    if (append)
1177    {
1178	if (position)
1179	    prev = &position->next;
1180	else
1181	    for (prev = head; *prev != NULL;
1182		 prev = &(*prev)->next)
1183		;
1184    }
1185    else
1186    {
1187	if (position)
1188	{
1189	    for (prev = head; *prev != NULL;
1190		 prev = &(*prev)->next)
1191	    {
1192		if (*prev == position)
1193		    break;
1194	    }
1195	}
1196	else
1197	    prev = head;
1198
1199	if (FcDebug () & FC_DBG_EDIT)
1200	{
1201	    if (*prev == NULL)
1202		printf ("position not on list\n");
1203	}
1204    }
1205
1206    if (FcDebug () & FC_DBG_EDIT)
1207    {
1208	printf ("%s list before ", append ? "Append" : "Prepend");
1209	FcValueListPrint (*head);
1210	printf ("\n");
1211    }
1212
1213    if (new)
1214    {
1215	last = new;
1216	while (last->next != NULL)
1217	    last = last->next;
1218
1219	last->next = *prev;
1220	*prev = new;
1221    }
1222
1223    if (FcDebug () & FC_DBG_EDIT)
1224    {
1225	printf ("%s list after ", append ? "Append" : "Prepend");
1226	FcValueListPrint (*head);
1227	printf ("\n");
1228    }
1229
1230    return FcTrue;
1231}
1232
1233static void
1234FcConfigDel (FcValueListPtr *head,
1235	     FcValueList    *position)
1236{
1237    FcValueListPtr *prev;
1238
1239    for (prev = head; *prev != NULL; prev = &(*prev)->next)
1240    {
1241	if (*prev == position)
1242	{
1243	    *prev = position->next;
1244	    position->next = NULL;
1245	    FcValueListDestroy (position);
1246	    break;
1247	}
1248    }
1249}
1250
1251static void
1252FcConfigPatternAdd (FcPattern	*p,
1253		    FcObject	object,
1254		    FcValueList	*list,
1255		    FcBool	append)
1256{
1257    if (list)
1258    {
1259	FcPatternElt    *e = FcPatternObjectInsertElt (p, object);
1260
1261	if (!e)
1262	    return;
1263	FcConfigAdd (&e->values, 0, append, list);
1264    }
1265}
1266
1267/*
1268 * Delete all values associated with a field
1269 */
1270static void
1271FcConfigPatternDel (FcPattern	*p,
1272		    FcObject	object)
1273{
1274    FcPatternElt    *e = FcPatternObjectFindElt (p, object);
1275    if (!e)
1276	return;
1277    while (e->values != NULL)
1278	FcConfigDel (&e->values, e->values);
1279}
1280
1281static void
1282FcConfigPatternCanon (FcPattern	    *p,
1283		      FcObject	    object)
1284{
1285    FcPatternElt    *e = FcPatternObjectFindElt (p, object);
1286    if (!e)
1287	return;
1288    if (e->values == NULL)
1289	FcPatternObjectDel (p, object);
1290}
1291
1292FcBool
1293FcConfigSubstituteWithPat (FcConfig    *config,
1294			   FcPattern   *p,
1295			   FcPattern   *p_pat,
1296			   FcMatchKind kind)
1297{
1298    FcSubst	    *s;
1299    FcSubState	    *st;
1300    int		    i;
1301    FcTest	    *t;
1302    FcEdit	    *e;
1303    FcValueList	    *l;
1304    FcPattern	    *m;
1305
1306    if (!config)
1307    {
1308	config = FcConfigGetCurrent ();
1309	if (!config)
1310	    return FcFalse;
1311    }
1312
1313    switch (kind) {
1314    case FcMatchPattern:
1315	s = config->substPattern;
1316	break;
1317    case FcMatchFont:
1318	s = config->substFont;
1319	break;
1320    case FcMatchScan:
1321	s = config->substScan;
1322	break;
1323    default:
1324	return FcFalse;
1325    }
1326
1327    st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
1328    if (!st && config->maxObjects)
1329	return FcFalse;
1330    FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1331
1332    if (FcDebug () & FC_DBG_EDIT)
1333    {
1334	printf ("FcConfigSubstitute ");
1335	FcPatternPrint (p);
1336    }
1337    for (; s; s = s->next)
1338    {
1339	/*
1340	 * Check the tests to see if
1341	 * they all match the pattern
1342	 */
1343	for (t = s->test, i = 0; t; t = t->next, i++)
1344	{
1345	    if (FcDebug () & FC_DBG_EDIT)
1346	    {
1347		printf ("FcConfigSubstitute test ");
1348		FcTestPrint (t);
1349	    }
1350	    st[i].elt = 0;
1351	    if (kind == FcMatchFont && t->kind == FcMatchPattern)
1352		m = p_pat;
1353	    else
1354		m = p;
1355	    if (m)
1356		st[i].elt = FcPatternObjectFindElt (m, t->object);
1357	    else
1358		st[i].elt = 0;
1359	    /*
1360	     * If there's no such field in the font,
1361	     * then FcQualAll matches while FcQualAny does not
1362	     */
1363	    if (!st[i].elt)
1364	    {
1365		if (t->qual == FcQualAll)
1366		{
1367		    st[i].value = 0;
1368		    continue;
1369		}
1370		else
1371		    break;
1372	    }
1373	    /*
1374	     * Check to see if there is a match, mark the location
1375	     * to apply match-relative edits
1376	     */
1377	    st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values);
1378	    if (!st[i].value)
1379		break;
1380	    if (t->qual == FcQualFirst && st[i].value != st[i].elt->values)
1381		break;
1382	    if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values)
1383		break;
1384	}
1385	if (t)
1386	{
1387	    if (FcDebug () & FC_DBG_EDIT)
1388		printf ("No match\n");
1389	    continue;
1390	}
1391	if (FcDebug () & FC_DBG_EDIT)
1392	{
1393	    printf ("Substitute ");
1394	    FcSubstPrint (s);
1395	}
1396	for (e = s->edit; e; e = e->next)
1397	{
1398	    /*
1399	     * Evaluate the list of expressions
1400	     */
1401	    l = FcConfigValues (p, e->expr, e->binding);
1402	    /*
1403	     * Locate any test associated with this field, skipping
1404	     * tests associated with the pattern when substituting in
1405	     * the font
1406	     */
1407	    for (t = s->test, i = 0; t; t = t->next, i++)
1408	    {
1409		if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
1410		    t->object == e->object)
1411		{
1412		    /*
1413		     * KLUDGE - the pattern may have been reallocated or
1414		     * things may have been inserted or deleted above
1415		     * this element by other edits.  Go back and find
1416		     * the element again
1417		     */
1418		    if (e != s->edit && st[i].elt)
1419			st[i].elt = FcPatternObjectFindElt (p, t->object);
1420		    if (!st[i].elt)
1421			t = 0;
1422		    break;
1423		}
1424	    }
1425	    switch (e->op) {
1426	    case FcOpAssign:
1427		/*
1428		 * If there was a test, then replace the matched
1429		 * value with the new list of values
1430		 */
1431		if (t)
1432		{
1433		    FcValueList	*thisValue = st[i].value;
1434		    FcValueList	*nextValue = thisValue;
1435
1436		    /*
1437		     * Append the new list of values after the current value
1438		     */
1439		    FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
1440		    /*
1441		     * Delete the marked value
1442		     */
1443                    if (thisValue)
1444			FcConfigDel (&st[i].elt->values, thisValue);
1445		    /*
1446		     * Adjust any pointers into the value list to ensure
1447		     * future edits occur at the same place
1448		     */
1449		    for (t = s->test, i = 0; t; t = t->next, i++)
1450		    {
1451			if (st[i].value == thisValue)
1452			    st[i].value = nextValue;
1453		    }
1454		    break;
1455		}
1456		/* fall through ... */
1457	    case FcOpAssignReplace:
1458		/*
1459		 * Delete all of the values and insert
1460		 * the new set
1461		 */
1462		FcConfigPatternDel (p, e->object);
1463		FcConfigPatternAdd (p, e->object, l, FcTrue);
1464		/*
1465		 * Adjust any pointers into the value list as they no
1466		 * longer point to anything valid
1467		 */
1468		if (t)
1469		{
1470		    FcPatternElt    *thisElt = st[i].elt;
1471		    for (t = s->test, i = 0; t; t = t->next, i++)
1472		    {
1473			if (st[i].elt == thisElt)
1474			    st[i].value = 0;
1475		    }
1476		}
1477		break;
1478	    case FcOpPrepend:
1479		if (t)
1480		{
1481		    FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
1482		    break;
1483		}
1484		/* fall through ... */
1485	    case FcOpPrependFirst:
1486		FcConfigPatternAdd (p, e->object, l, FcFalse);
1487		break;
1488	    case FcOpAppend:
1489		if (t)
1490		{
1491		    FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
1492		    break;
1493		}
1494		/* fall through ... */
1495	    case FcOpAppendLast:
1496		FcConfigPatternAdd (p, e->object, l, FcTrue);
1497		break;
1498	    default:
1499                FcValueListDestroy (l);
1500		break;
1501	    }
1502	}
1503	/*
1504	 * Now go through the pattern and eliminate
1505	 * any properties without data
1506	 */
1507	for (e = s->edit; e; e = e->next)
1508	    FcConfigPatternCanon (p, e->object);
1509
1510	if (FcDebug () & FC_DBG_EDIT)
1511	{
1512	    printf ("FcConfigSubstitute edit");
1513	    FcPatternPrint (p);
1514	}
1515    }
1516    FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1517    free (st);
1518    if (FcDebug () & FC_DBG_EDIT)
1519    {
1520	printf ("FcConfigSubstitute done");
1521	FcPatternPrint (p);
1522    }
1523    return FcTrue;
1524}
1525
1526FcBool
1527FcConfigSubstitute (FcConfig	*config,
1528		    FcPattern	*p,
1529		    FcMatchKind	kind)
1530{
1531    return FcConfigSubstituteWithPat (config, p, 0, kind);
1532}
1533
1534#if defined (_WIN32)
1535
1536#  define WIN32_LEAN_AND_MEAN
1537#  define WIN32_EXTRA_LEAN
1538#  include <windows.h>
1539
1540static FcChar8 fontconfig_path[1000] = "";
1541
1542#  if (defined (PIC) || defined (DLL_EXPORT))
1543
1544BOOL WINAPI
1545DllMain (HINSTANCE hinstDLL,
1546	 DWORD     fdwReason,
1547	 LPVOID    lpvReserved)
1548{
1549  FcChar8 *p;
1550
1551  switch (fdwReason) {
1552  case DLL_PROCESS_ATTACH:
1553      if (!GetModuleFileName ((HMODULE) hinstDLL, fontconfig_path,
1554			      sizeof (fontconfig_path)))
1555	  break;
1556
1557      /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
1558       * assume it's a Unix-style installation tree, and use
1559       * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
1560       * folder where the DLL is as FONTCONFIG_PATH.
1561       */
1562      p = strrchr (fontconfig_path, '\\');
1563      if (p)
1564      {
1565	  *p = '\0';
1566	  p = strrchr (fontconfig_path, '\\');
1567	  if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 ||
1568		    FcStrCmpIgnoreCase (p + 1, "lib") == 0))
1569	      *p = '\0';
1570	  strcat (fontconfig_path, "\\etc\\fonts");
1571      }
1572      else
1573          fontconfig_path[0] = '\0';
1574
1575      break;
1576  }
1577
1578  return TRUE;
1579}
1580
1581#  endif /* !PIC */
1582
1583#undef FONTCONFIG_PATH
1584#define FONTCONFIG_PATH fontconfig_path
1585
1586#endif /* !_WIN32 */
1587
1588#ifndef FONTCONFIG_FILE
1589#define FONTCONFIG_FILE	"fonts.conf"
1590#endif
1591
1592static FcChar8 *
1593FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
1594{
1595    FcChar8    *path;
1596
1597    if (!dir)
1598	dir = (FcChar8 *) "";
1599    path = malloc (strlen ((char *) dir) + 1 + strlen ((char *) file) + 1);
1600    if (!path)
1601	return 0;
1602
1603    strcpy ((char *) path, (const char *) dir);
1604    /* make sure there's a single separator */
1605#ifdef _WIN32
1606    if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
1607		      path[strlen((char *) path)-1] != '\\')) &&
1608	!(file[0] == '/' ||
1609	  file[0] == '\\' ||
1610	  (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
1611	strcat ((char *) path, "\\");
1612#else
1613    if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
1614	strcat ((char *) path, "/");
1615#endif
1616    strcat ((char *) path, (char *) file);
1617
1618    FcMemAlloc (FC_MEM_STRING, strlen ((char *) path) + 1);
1619    if (access ((char *) path, R_OK) == 0)
1620	return path;
1621
1622    FcStrFree (path);
1623    return 0;
1624}
1625
1626static FcChar8 **
1627FcConfigGetPath (void)
1628{
1629    FcChar8    **path;
1630    FcChar8    *env, *e, *colon;
1631    FcChar8    *dir;
1632    int	    npath;
1633    int	    i;
1634
1635    npath = 2;	/* default dir + null */
1636    env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
1637    if (env)
1638    {
1639	e = env;
1640	npath++;
1641	while (*e)
1642	    if (*e++ == FC_SEARCH_PATH_SEPARATOR)
1643		npath++;
1644    }
1645    path = calloc (npath, sizeof (FcChar8 *));
1646    if (!path)
1647	goto bail0;
1648    i = 0;
1649
1650    if (env)
1651    {
1652	e = env;
1653	while (*e)
1654	{
1655	    colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
1656	    if (!colon)
1657		colon = e + strlen ((char *) e);
1658	    path[i] = malloc (colon - e + 1);
1659	    if (!path[i])
1660		goto bail1;
1661	    strncpy ((char *) path[i], (const char *) e, colon - e);
1662	    path[i][colon - e] = '\0';
1663	    if (*colon)
1664		e = colon + 1;
1665	    else
1666		e = colon;
1667	    i++;
1668	}
1669    }
1670
1671#ifdef _WIN32
1672	if (fontconfig_path[0] == '\0')
1673	{
1674		if(!GetModuleFileName(NULL, fontconfig_path, sizeof(fontconfig_path)))
1675			goto bail1;
1676		char *p = strrchr (fontconfig_path, '\\');
1677		if (p) *p = '\0';
1678		strcat (fontconfig_path, "\\fonts");
1679	}
1680#endif
1681    dir = (FcChar8 *) FONTCONFIG_PATH;
1682    path[i] = malloc (strlen ((char *) dir) + 1);
1683    if (!path[i])
1684	goto bail1;
1685    strcpy ((char *) path[i], (const char *) dir);
1686    return path;
1687
1688bail1:
1689    for (i = 0; path[i]; i++)
1690	free (path[i]);
1691    free (path);
1692bail0:
1693    return 0;
1694}
1695
1696static void
1697FcConfigFreePath (FcChar8 **path)
1698{
1699    FcChar8    **p;
1700
1701    for (p = path; *p; p++)
1702	free (*p);
1703    free (path);
1704}
1705
1706static FcBool	_FcConfigHomeEnabled = FcTrue;
1707
1708FcChar8 *
1709FcConfigHome (void)
1710{
1711    if (_FcConfigHomeEnabled)
1712    {
1713        char *home = getenv ("HOME");
1714
1715#ifdef _WIN32
1716	if (home == NULL)
1717	    home = getenv ("USERPROFILE");
1718#endif
1719
1720	return (FcChar8 *) home;
1721    }
1722    return 0;
1723}
1724
1725FcBool
1726FcConfigEnableHome (FcBool enable)
1727{
1728    FcBool  prev = _FcConfigHomeEnabled;
1729    _FcConfigHomeEnabled = enable;
1730    return prev;
1731}
1732
1733FcChar8 *
1734FcConfigFilename (const FcChar8 *url)
1735{
1736    FcChar8    *file, *dir, **path, **p;
1737
1738    if (!url || !*url)
1739    {
1740	url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
1741	if (!url)
1742	    url = (FcChar8 *) FONTCONFIG_FILE;
1743    }
1744    file = 0;
1745
1746#ifdef _WIN32
1747    if (isalpha (*url) &&
1748	url[1] == ':' &&
1749	(url[2] == '/' || url[2] == '\\'))
1750	goto absolute_path;
1751#endif
1752
1753    switch (*url) {
1754    case '~':
1755	dir = FcConfigHome ();
1756	if (dir)
1757	    file = FcConfigFileExists (dir, url + 1);
1758	else
1759	    file = 0;
1760	break;
1761#ifdef _WIN32
1762    case '\\':
1763    absolute_path:
1764#endif
1765    case '/':
1766	file = FcConfigFileExists (0, url);
1767	break;
1768    default:
1769	path = FcConfigGetPath ();
1770	if (!path)
1771	    return 0;
1772	for (p = path; *p; p++)
1773	{
1774	    file = FcConfigFileExists (*p, url);
1775	    if (file)
1776		break;
1777	}
1778	FcConfigFreePath (path);
1779	break;
1780    }
1781    return file;
1782}
1783
1784/*
1785 * Manage the application-specific fonts
1786 */
1787
1788FcBool
1789FcConfigAppFontAddFile (FcConfig    *config,
1790			const FcChar8  *file)
1791{
1792    FcFontSet	*set;
1793    FcStrSet	*subdirs;
1794    FcStrList	*sublist;
1795    FcChar8	*subdir;
1796
1797    if (!config)
1798    {
1799	config = FcConfigGetCurrent ();
1800	if (!config)
1801	    return FcFalse;
1802    }
1803
1804    subdirs = FcStrSetCreate ();
1805    if (!subdirs)
1806	return FcFalse;
1807
1808    set = FcConfigGetFonts (config, FcSetApplication);
1809    if (!set)
1810    {
1811	set = FcFontSetCreate ();
1812	if (!set)
1813	{
1814	    FcStrSetDestroy (subdirs);
1815	    return FcFalse;
1816	}
1817	FcConfigSetFonts (config, set, FcSetApplication);
1818    }
1819
1820    if (!FcFileScanConfig (set, subdirs, config->blanks, file, config))
1821    {
1822	FcStrSetDestroy (subdirs);
1823	return FcFalse;
1824    }
1825    if ((sublist = FcStrListCreate (subdirs)))
1826    {
1827	while ((subdir = FcStrListNext (sublist)))
1828	{
1829	    FcConfigAppFontAddDir (config, subdir);
1830	}
1831	FcStrListDone (sublist);
1832    }
1833    FcStrSetDestroy (subdirs);
1834    return FcTrue;
1835}
1836
1837FcBool
1838FcConfigAppFontAddDir (FcConfig	    *config,
1839		       const FcChar8   *dir)
1840{
1841    FcFontSet	*set;
1842    FcStrSet	*dirs;
1843
1844    if (!config)
1845    {
1846	config = FcConfigGetCurrent ();
1847	if (!config)
1848	    return FcFalse;
1849    }
1850
1851    dirs = FcStrSetCreate ();
1852    if (!dirs)
1853	return FcFalse;
1854
1855    set = FcConfigGetFonts (config, FcSetApplication);
1856    if (!set)
1857    {
1858	set = FcFontSetCreate ();
1859	if (!set)
1860	{
1861	    FcStrSetDestroy (dirs);
1862	    return FcFalse;
1863	}
1864	FcConfigSetFonts (config, set, FcSetApplication);
1865    }
1866
1867    FcStrSetAddFilename (dirs, dir);
1868
1869    if (!FcConfigAddDirList (config, FcSetApplication, dirs))
1870    {
1871	FcStrSetDestroy (dirs);
1872	return FcFalse;
1873    }
1874    FcStrSetDestroy (dirs);
1875    return FcTrue;
1876}
1877
1878void
1879FcConfigAppFontClear (FcConfig	    *config)
1880{
1881    if (!config)
1882    {
1883	config = FcConfigGetCurrent ();
1884	if (!config)
1885	    return;
1886    }
1887
1888    FcConfigSetFonts (config, 0, FcSetApplication);
1889}
1890
1891/*
1892 * Manage filename-based font source selectors
1893 */
1894
1895FcBool
1896FcConfigGlobAdd (FcConfig	*config,
1897		 const FcChar8  *glob,
1898		 FcBool		accept)
1899{
1900    FcStrSet	*set = accept ? config->acceptGlobs : config->rejectGlobs;
1901
1902    return FcStrSetAdd (set, glob);
1903}
1904
1905static FcBool
1906FcConfigGlobMatch (const FcChar8    *glob,
1907		   const FcChar8    *string)
1908{
1909    FcChar8	c;
1910
1911    while ((c = *glob++))
1912    {
1913	switch (c) {
1914	case '*':
1915	    /* short circuit common case */
1916	    if (!*glob)
1917		return FcTrue;
1918	    /* short circuit another common case */
1919	    if (strchr ((char *) glob, '*') == 0)
1920		string += strlen ((char *) string) - strlen ((char *) glob);
1921	    while (*string)
1922	    {
1923		if (FcConfigGlobMatch (glob, string))
1924		    return FcTrue;
1925		string++;
1926	    }
1927	    return FcFalse;
1928	case '?':
1929	    if (*string++ == '\0')
1930		return FcFalse;
1931	    break;
1932	default:
1933	    if (*string++ != c)
1934		return FcFalse;
1935	    break;
1936	}
1937    }
1938    return *string == '\0';
1939}
1940
1941static FcBool
1942FcConfigGlobsMatch (const FcStrSet	*globs,
1943		    const FcChar8	*string)
1944{
1945    int	i;
1946
1947    for (i = 0; i < globs->num; i++)
1948	if (FcConfigGlobMatch (globs->strs[i], string))
1949	    return FcTrue;
1950    return FcFalse;
1951}
1952
1953FcBool
1954FcConfigAcceptFilename (FcConfig	*config,
1955			const FcChar8	*filename)
1956{
1957    if (FcConfigGlobsMatch (config->acceptGlobs, filename))
1958	return FcTrue;
1959    if (FcConfigGlobsMatch (config->rejectGlobs, filename))
1960	return FcFalse;
1961    return FcTrue;
1962}
1963
1964/*
1965 * Manage font-pattern based font source selectors
1966 */
1967
1968FcBool
1969FcConfigPatternsAdd (FcConfig	*config,
1970		     FcPattern	*pattern,
1971		     FcBool	accept)
1972{
1973    FcFontSet	*set = accept ? config->acceptPatterns : config->rejectPatterns;
1974
1975    return FcFontSetAdd (set, pattern);
1976}
1977
1978static FcBool
1979FcConfigPatternsMatch (const FcFontSet	*patterns,
1980		       const FcPattern	*font)
1981{
1982    int i;
1983
1984    for (i = 0; i < patterns->nfont; i++)
1985	if (FcListPatternMatchAny (patterns->fonts[i], font))
1986	    return FcTrue;
1987    return FcFalse;
1988}
1989
1990FcBool
1991FcConfigAcceptFont (FcConfig	    *config,
1992		    const FcPattern *font)
1993{
1994    if (FcConfigPatternsMatch (config->acceptPatterns, font))
1995	return FcTrue;
1996    if (FcConfigPatternsMatch (config->rejectPatterns, font))
1997	return FcFalse;
1998    return FcTrue;
1999}
2000#define __fccfg__
2001#include "fcaliastail.h"
2002#undef __fccfg__
2003