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