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