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