]> git.wh0rd.org Git - fontconfig.git/blob - src/fccfg.c
Fix "contains" op for strings and langsets.
[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                 ret = FcStrCmpIgnoreCase (m.u.s, v.u.s) == 0;
569                 break;
570             case FcOpContains:
571                 ret = FcStrStrIgnoreCase (m.u.s, v.u.s) != 0;
572                 break;
573             case FcOpNotEqual:
574                 ret = FcStrCmpIgnoreCase (m.u.s, v.u.s) != 0;
575                 break;
576             case FcOpNotContains:
577                 ret = FcStrStrIgnoreCase (m.u.s, v.u.s) == 0;
578                 break;
579             default:
580                 break;
581             }
582             break;
583         case FcTypeMatrix:
584             switch (op) {
585             case FcOpEqual:
586             case FcOpContains:
587                 ret = FcMatrixEqual (m.u.m, v.u.m);
588                 break;
589             case FcOpNotEqual:
590             case FcOpNotContains:
591                 ret = !FcMatrixEqual (m.u.m, v.u.m);
592                 break;
593             default:
594                 break;
595             }
596             break;
597         case FcTypeCharSet:
598             switch (op) {
599             case FcOpContains:
600                 /* v contains m if m is a subset of v */
601                 ret = FcCharSetIsSubset (m.u.c, v.u.c);
602                 break;
603             case FcOpNotContains:
604                 /* v contains m if m is a subset of v */
605                 ret = !FcCharSetIsSubset (m.u.c, v.u.c);
606                 break;
607             case FcOpEqual:
608                 ret = FcCharSetEqual (m.u.c, v.u.c);
609                 break;
610             case FcOpNotEqual:
611                 ret = !FcCharSetEqual (m.u.c, v.u.c);
612                 break;
613             default:
614                 break;
615             }
616             break;
617         case FcTypeLangSet:
618             switch (op) {
619             case FcOpContains:
620                 ret = FcLangSetContains (m.u.l, v.u.l);
621                 break;
622             case FcOpNotContains:
623                 ret = FcLangSetContains (m.u.l, v.u.l);
624                 break;
625             case FcOpEqual:
626                 ret = FcLangSetEqual (m.u.l, v.u.l);
627                 break;
628             case FcOpNotEqual:
629                 ret = !FcLangSetEqual (m.u.l, v.u.l);
630                 break;
631             default:
632                 break;
633             }
634             break;
635         case FcTypeVoid:
636             switch (op) {
637             case FcOpEqual:
638             case FcOpContains:
639                 ret = FcTrue;
640                 break;
641             default:
642                 break;
643             }
644             break;
645         case FcTypeFTFace:
646             switch (op) {
647             case FcOpEqual:
648             case FcOpContains:
649                 ret = m.u.f == v.u.f;
650                 break;
651             case FcOpNotEqual:
652             case FcOpNotContains:
653                 ret = m.u.f != v.u.f;
654                 break;
655             default:
656                 break;
657             }
658             break;
659         }
660     }
661     else
662     {
663         if (op == FcOpNotEqual || op == FcOpNotContains)
664             ret = FcTrue;
665     }
666     return ret;
667 }
668
669
670 #define _FcDoubleFloor(d)       ((int) (d))
671 #define _FcDoubleCeil(d)        ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
672 #define FcDoubleFloor(d)        ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
673 #define FcDoubleCeil(d)         ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
674 #define FcDoubleRound(d)        FcDoubleFloor ((d) + 0.5)
675 #define FcDoubleTrunc(d)        ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
676
677 static FcValue
678 FcConfigEvaluate (FcPattern *p, FcExpr *e)
679 {
680     FcValue     v, vl, vr;
681     FcResult    r;
682     FcMatrix    *m;
683     
684     switch (e->op) {
685     case FcOpInteger:
686         v.type = FcTypeInteger;
687         v.u.i = e->u.ival;
688         break;
689     case FcOpDouble:
690         v.type = FcTypeDouble;
691         v.u.d = e->u.dval;
692         break;
693     case FcOpString:
694         v.type = FcTypeString;
695         v.u.s = e->u.sval;
696         v = FcValueSave (v);
697         break;
698     case FcOpMatrix:
699         v.type = FcTypeMatrix;
700         v.u.m = e->u.mval;
701         v = FcValueSave (v);
702         break;
703     case FcOpCharSet:
704         v.type = FcTypeCharSet;
705         v.u.c = e->u.cval;
706         v = FcValueSave (v);
707         break;
708     case FcOpBool:
709         v.type = FcTypeBool;
710         v.u.b = e->u.bval;
711         break;
712     case FcOpField:
713         r = FcPatternGet (p, e->u.field, 0, &v);
714         if (r != FcResultMatch)
715             v.type = FcTypeVoid;
716         break;
717     case FcOpConst:
718         if (FcNameConstant (e->u.constant, &v.u.i))
719             v.type = FcTypeInteger;
720         else
721             v.type = FcTypeVoid;
722         break;
723     case FcOpQuest:
724         vl = FcConfigEvaluate (p, e->u.tree.left);
725         if (vl.type == FcTypeBool)
726         {
727             if (vl.u.b)
728                 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
729             else
730                 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
731         }
732         else
733             v.type = FcTypeVoid;
734         FcValueDestroy (vl);
735         break;
736     case FcOpEqual:
737     case FcOpNotEqual:
738     case FcOpLess:
739     case FcOpLessEqual:
740     case FcOpMore:
741     case FcOpMoreEqual:
742     case FcOpContains:
743     case FcOpNotContains:
744         vl = FcConfigEvaluate (p, e->u.tree.left);
745         vr = FcConfigEvaluate (p, e->u.tree.right);
746         v.type = FcTypeBool;
747         v.u.b = FcConfigCompareValue (vl, e->op, vr);
748         FcValueDestroy (vl);
749         FcValueDestroy (vr);
750         break;  
751     case FcOpOr:
752     case FcOpAnd:
753     case FcOpPlus:
754     case FcOpMinus:
755     case FcOpTimes:
756     case FcOpDivide:
757         vl = FcConfigEvaluate (p, e->u.tree.left);
758         vr = FcConfigEvaluate (p, e->u.tree.right);
759         vl = FcConfigPromote (vl, vr);
760         vr = FcConfigPromote (vr, vl);
761         if (vl.type == vr.type)
762         {
763             switch (vl.type) {
764             case FcTypeDouble:
765                 switch (e->op) {
766                 case FcOpPlus:     
767                     v.type = FcTypeDouble;
768                     v.u.d = vl.u.d + vr.u.d; 
769                     break;
770                 case FcOpMinus:
771                     v.type = FcTypeDouble;
772                     v.u.d = vl.u.d - vr.u.d; 
773                     break;
774                 case FcOpTimes:
775                     v.type = FcTypeDouble;
776                     v.u.d = vl.u.d * vr.u.d; 
777                     break;
778                 case FcOpDivide:
779                     v.type = FcTypeDouble;
780                     v.u.d = vl.u.d / vr.u.d; 
781                     break;
782                 default:
783                     v.type = FcTypeVoid; 
784                     break;
785                 }
786                 if (v.type == FcTypeDouble &&
787                     v.u.d == (double) (int) v.u.d)
788                 {
789                     v.type = FcTypeInteger;
790                     v.u.i = (int) v.u.d;
791                 }
792                 break;
793             case FcTypeBool:
794                 switch (e->op) {
795                 case FcOpOr:
796                     v.type = FcTypeBool;
797                     v.u.b = vl.u.b || vr.u.b;
798                     break;
799                 case FcOpAnd:
800                     v.type = FcTypeBool;
801                     v.u.b = vl.u.b && vr.u.b;
802                     break;
803                 default:
804                     v.type = FcTypeVoid; 
805                     break;
806                 }
807                 break;
808             case FcTypeString:
809                 switch (e->op) {
810                 case FcOpPlus:
811                     v.type = FcTypeString;
812                     v.u.s = FcStrPlus (vl.u.s, vr.u.s);
813                     if (!v.u.s)
814                         v.type = FcTypeVoid;
815                     break;
816                 default:
817                     v.type = FcTypeVoid;
818                     break;
819                 }
820                 break;
821             case FcTypeMatrix:
822                 switch (e->op) {
823                 case FcOpTimes:
824                     v.type = FcTypeMatrix;
825                     m = malloc (sizeof (FcMatrix));
826                     if (m)
827                     {
828                         FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
829                         FcMatrixMultiply (m, vl.u.m, vr.u.m);
830                         v.u.m = m;
831                     }
832                     else
833                     {
834                         v.type = FcTypeVoid;
835                     }
836                     break;
837                 default:
838                     v.type = FcTypeVoid;
839                     break;
840                 }
841                 break;
842             default:
843                 v.type = FcTypeVoid;
844                 break;
845             }
846         }
847         else
848             v.type = FcTypeVoid;
849         FcValueDestroy (vl);
850         FcValueDestroy (vr);
851         break;
852     case FcOpNot:
853         vl = FcConfigEvaluate (p, e->u.tree.left);
854         switch (vl.type) {
855         case FcTypeBool:
856             v.type = FcTypeBool;
857             v.u.b = !vl.u.b;
858             break;
859         default:
860             v.type = FcTypeVoid;
861             break;
862         }
863         FcValueDestroy (vl);
864         break;
865     case FcOpFloor:
866         vl = FcConfigEvaluate (p, e->u.tree.left);
867         switch (vl.type) {
868         case FcTypeInteger:
869             v = vl;
870             break;
871         case FcTypeDouble:
872             v.type = FcTypeInteger;
873             v.u.i = FcDoubleFloor (vl.u.d);
874             break;
875         default:
876             v.type = FcTypeVoid;
877             break;
878         }
879         FcValueDestroy (vl);
880         break;
881     case FcOpCeil:
882         vl = FcConfigEvaluate (p, e->u.tree.left);
883         switch (vl.type) {
884         case FcTypeInteger:
885             v = vl;
886             break;
887         case FcTypeDouble:
888             v.type = FcTypeInteger;
889             v.u.i = FcDoubleCeil (vl.u.d);
890             break;
891         default:
892             v.type = FcTypeVoid;
893             break;
894         }
895         FcValueDestroy (vl);
896         break;
897     case FcOpRound:
898         vl = FcConfigEvaluate (p, e->u.tree.left);
899         switch (vl.type) {
900         case FcTypeInteger:
901             v = vl;
902             break;
903         case FcTypeDouble:
904             v.type = FcTypeInteger;
905             v.u.i = FcDoubleRound (vl.u.d);
906             break;
907         default:
908             v.type = FcTypeVoid;
909             break;
910         }
911         FcValueDestroy (vl);
912         break;
913     case FcOpTrunc:
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 = FcDoubleTrunc (vl.u.d);
922             break;
923         default:
924             v.type = FcTypeVoid;
925             break;
926         }
927         FcValueDestroy (vl);
928         break;
929     default:
930         v.type = FcTypeVoid;
931         break;
932     }
933     return v;
934 }
935
936 static FcValueList *
937 FcConfigMatchValueList (FcPattern       *p,
938                         FcTest          *t,
939                         FcValueList     *values)
940 {
941     FcValueList     *ret = 0;
942     FcExpr          *e = t->expr;
943     FcValue         value;
944     FcValueList     *v;
945     
946     while (e)
947     {
948         if (e->op == FcOpComma)
949         {
950             value = FcConfigEvaluate (p, e->u.tree.left);
951             e = e->u.tree.right;
952         }
953         else
954         {
955             value = FcConfigEvaluate (p, e);
956             e = 0;
957         }
958
959         for (v = values; v; v = v->next)
960         {
961             if (FcConfigCompareValue (v->value, t->op, value))
962             {
963                 if (!ret)
964                     ret = v;
965             }
966             else
967             {
968                 if (t->qual == FcQualAll)
969                 {
970                     ret = 0;
971                     break;
972                 }
973             }
974         }
975         FcValueDestroy (value);
976     }
977     return ret;
978 }
979
980 static FcValueList *
981 FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding)
982 {
983     FcValueList *l;
984     
985     if (!e)
986         return 0;
987     l = (FcValueList *) malloc (sizeof (FcValueList));
988     if (!l)
989         return 0;
990     FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
991     if (e->op == FcOpComma)
992     {
993         l->value = FcConfigEvaluate (p, e->u.tree.left);
994         l->next  = FcConfigValues (p, e->u.tree.right, binding);
995     }
996     else
997     {
998         l->value = FcConfigEvaluate (p, e);
999         l->next  = 0;
1000     }
1001     l->binding = binding;
1002     while (l && l->value.type == FcTypeVoid)
1003     {
1004         FcValueList     *next = l->next;
1005         
1006         FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
1007         free (l);
1008         l = next;
1009     }
1010     return l;
1011 }
1012
1013 static FcBool
1014 FcConfigAdd (FcValueList    **head,
1015              FcValueList    *position,
1016              FcBool         append,
1017              FcValueList    *new)
1018 {
1019     FcValueList     **prev, *last, *v;
1020     FcValueBinding  sameBinding;
1021     
1022     if (position)
1023         sameBinding = position->binding;
1024     else
1025         sameBinding = FcValueBindingWeak;
1026     for (v = new; v; v = v->next)
1027         if (v->binding == FcValueBindingSame)
1028             v->binding = sameBinding;
1029     if (append)
1030     {
1031         if (position)
1032             prev = &position->next;
1033         else
1034             for (prev = head; *prev; prev = &(*prev)->next)
1035                 ;
1036     }
1037     else
1038     {
1039         if (position)
1040         {
1041             for (prev = head; *prev; prev = &(*prev)->next)
1042             {
1043                 if (*prev == position)
1044                     break;
1045             }
1046         }
1047         else
1048             prev = head;
1049
1050         if (FcDebug () & FC_DBG_EDIT)
1051         {
1052             if (!*prev)
1053                 printf ("position not on list\n");
1054         }
1055     }
1056
1057     if (FcDebug () & FC_DBG_EDIT)
1058     {
1059         printf ("%s list before ", append ? "Append" : "Prepend");
1060         FcValueListPrint (*head);
1061         printf ("\n");
1062     }
1063     
1064     if (new)
1065     {
1066         last = new;
1067         while (last->next)
1068             last = last->next;
1069     
1070         last->next = *prev;
1071         *prev = new;
1072     }
1073     
1074     if (FcDebug () & FC_DBG_EDIT)
1075     {
1076         printf ("%s list after ", append ? "Append" : "Prepend");
1077         FcValueListPrint (*head);
1078         printf ("\n");
1079     }
1080     
1081     return FcTrue;
1082 }
1083
1084 static void
1085 FcConfigDel (FcValueList    **head,
1086              FcValueList    *position)
1087 {
1088     FcValueList    **prev;
1089
1090     for (prev = head; *prev; prev = &(*prev)->next)
1091     {
1092         if (*prev == position)
1093         {
1094             *prev = position->next;
1095             position->next = 0;
1096             FcValueListDestroy (position);
1097             break;
1098         }
1099     }
1100 }
1101
1102 static void
1103 FcConfigPatternAdd (FcPattern   *p,
1104                     const char  *object,
1105                     FcValueList *list,
1106                     FcBool      append)
1107 {
1108     if (list)
1109     {
1110         FcPatternElt    *e = FcPatternInsertElt (p, object);
1111     
1112         if (!e)
1113             return;
1114         FcConfigAdd (&e->values, 0, append, list);
1115     }
1116 }
1117
1118 /*
1119  * Delete all values associated with a field
1120  */
1121 static void
1122 FcConfigPatternDel (FcPattern   *p,
1123                     const char  *object)
1124 {
1125     FcPatternElt    *e = FcPatternFindElt (p, object);
1126     if (!e)
1127         return;
1128     while (e->values)
1129         FcConfigDel (&e->values, e->values);
1130 }
1131
1132 static void
1133 FcConfigPatternCanon (FcPattern     *p,
1134                       const char    *object)
1135 {
1136     FcPatternElt    *e = FcPatternFindElt (p, object);
1137     if (!e)
1138         return;
1139     if (!e->values)
1140         FcPatternDel (p, object);
1141 }
1142
1143 FcBool
1144 FcConfigSubstituteWithPat (FcConfig    *config,
1145                            FcPattern   *p,
1146                            FcPattern   *p_pat,
1147                            FcMatchKind kind)
1148 {
1149     FcSubst         *s;
1150     FcSubState      *st;
1151     int             i;
1152     FcTest          *t;
1153     FcEdit          *e;
1154     FcValueList     *l;
1155     FcPattern       *m;
1156
1157     if (!config)
1158     {
1159         config = FcConfigGetCurrent ();
1160         if (!config)
1161             return FcFalse;
1162     }
1163
1164     st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
1165     if (!st && config->maxObjects)
1166         return FcFalse;
1167     FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1168
1169     if (FcDebug () & FC_DBG_EDIT)
1170     {
1171         printf ("FcConfigSubstitute ");
1172         FcPatternPrint (p);
1173     }
1174     if (kind == FcMatchPattern)
1175         s = config->substPattern;
1176     else
1177         s = config->substFont;
1178     for (; s; s = s->next)
1179     {
1180         /*
1181          * Check the tests to see if
1182          * they all match the pattern
1183          */
1184         for (t = s->test, i = 0; t; t = t->next, i++)
1185         {
1186             if (FcDebug () & FC_DBG_EDIT)
1187             {
1188                 printf ("FcConfigSubstitute test ");
1189                 FcTestPrint (t);
1190             }
1191             st[i].elt = 0;
1192             if (kind == FcMatchFont && t->kind == FcMatchPattern)
1193                 m = p_pat;
1194             else
1195                 m = p;
1196             if (m)
1197                 st[i].elt = FcPatternFindElt (m, t->field);
1198             else
1199                 st[i].elt = 0;
1200             /*
1201              * If there's no such field in the font,
1202              * then FcQualAll matches while FcQualAny does not
1203              */
1204             if (!st[i].elt)
1205             {
1206                 if (t->qual == FcQualAll)
1207                 {
1208                     st[i].value = 0;
1209                     continue;
1210                 }
1211                 else
1212                     break;
1213             }
1214             /*
1215              * Check to see if there is a match, mark the location
1216              * to apply match-relative edits
1217              */
1218             st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values);
1219             if (!st[i].value)
1220                 break;
1221             if (t->qual == FcQualFirst && st[i].value != st[i].elt->values)
1222                 break;
1223             if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values)
1224                 break;
1225         }
1226         if (t)
1227         {
1228             if (FcDebug () & FC_DBG_EDIT)
1229                 printf ("No match\n");
1230             continue;
1231         }
1232         if (FcDebug () & FC_DBG_EDIT)
1233         {
1234             printf ("Substitute ");
1235             FcSubstPrint (s);
1236         }
1237         for (e = s->edit; e; e = e->next)
1238         {
1239             /*
1240              * Evaluate the list of expressions
1241              */
1242             l = FcConfigValues (p, e->expr, e->binding);
1243             /*
1244              * Locate any test associated with this field, skipping
1245              * tests associated with the pattern when substituting in
1246              * the font
1247              */
1248             for (t = s->test, i = 0; t; t = t->next, i++)
1249             {
1250                 if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
1251                     !FcStrCmpIgnoreCase ((FcChar8 *) t->field, 
1252                                          (FcChar8 *) e->field))
1253                 {
1254                     /* 
1255                      * KLUDGE - the pattern may have been reallocated or
1256                      * things may have been inserted or deleted above
1257                      * this element by other edits.  Go back and find
1258                      * the element again
1259                      */
1260                     if (e != s->edit && st[i].elt)
1261                         st[i].elt = FcPatternFindElt (p, t->field);
1262                     if (!st[i].elt)
1263                         t = 0;
1264                     break;
1265                 }
1266             }
1267             switch (e->op) {
1268             case FcOpAssign:
1269                 /*
1270                  * If there was a test, then replace the matched
1271                  * value with the new list of values
1272                  */
1273                 if (t)
1274                 {
1275                     FcValueList *thisValue = st[i].value;
1276                     FcValueList *nextValue = thisValue ? thisValue->next : 0;
1277                     
1278                     /*
1279                      * Append the new list of values after the current value
1280                      */
1281                     FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
1282                     /*
1283                      * Delete the marked value
1284                      */
1285                     FcConfigDel (&st[i].elt->values, thisValue);
1286                     /*
1287                      * Adjust any pointers into the value list to ensure
1288                      * future edits occur at the same place
1289                      */
1290                     for (t = s->test, i = 0; t; t = t->next, i++)
1291                     {
1292                         if (st[i].value == thisValue)
1293                             st[i].value = nextValue;
1294                     }
1295                     break;
1296                 }
1297                 /* fall through ... */
1298             case FcOpAssignReplace:
1299                 /*
1300                  * Delete all of the values and insert
1301                  * the new set
1302                  */
1303                 FcConfigPatternDel (p, e->field);
1304                 FcConfigPatternAdd (p, e->field, l, FcTrue);
1305                 /*
1306                  * Adjust any pointers into the value list as they no
1307                  * longer point to anything valid
1308                  */
1309                 if (t)
1310                 {
1311                     FcPatternElt    *thisElt = st[i].elt;
1312                     for (t = s->test, i = 0; t; t = t->next, i++)
1313                     {
1314                         if (st[i].elt == thisElt)
1315                             st[i].value = 0;
1316                     }
1317                 }
1318                 break;
1319             case FcOpPrepend:
1320                 if (t)
1321                 {
1322                     FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
1323                     break;
1324                 }
1325                 /* fall through ... */
1326             case FcOpPrependFirst:
1327                 FcConfigPatternAdd (p, e->field, l, FcFalse);
1328                 break;
1329             case FcOpAppend:
1330                 if (t)
1331                 {
1332                     FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
1333                     break;
1334                 }
1335                 /* fall through ... */
1336             case FcOpAppendLast:
1337                 FcConfigPatternAdd (p, e->field, l, FcTrue);
1338                 break;
1339             default:
1340                 break;
1341             }
1342         }
1343         /*
1344          * Now go through the pattern and eliminate
1345          * any properties without data
1346          */
1347         for (e = s->edit; e; e = e->next)
1348             FcConfigPatternCanon (p, e->field);
1349
1350         if (FcDebug () & FC_DBG_EDIT)
1351         {
1352             printf ("FcConfigSubstitute edit");
1353             FcPatternPrint (p);
1354         }
1355     }
1356     FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1357     free (st);
1358     if (FcDebug () & FC_DBG_EDIT)
1359     {
1360         printf ("FcConfigSubstitute done");
1361         FcPatternPrint (p);
1362     }
1363     return FcTrue;
1364 }
1365
1366 FcBool
1367 FcConfigSubstitute (FcConfig    *config,
1368                     FcPattern   *p,
1369                     FcMatchKind kind)
1370 {
1371     return FcConfigSubstituteWithPat (config, p, 0, kind);
1372 }
1373
1374 #if defined (_WIN32) && defined (PIC)
1375
1376 static FcChar8 fontconfig_path[1000] = "";
1377
1378 BOOL WINAPI
1379 DllMain (HINSTANCE hinstDLL,
1380          DWORD     fdwReason,
1381          LPVOID    lpvReserved)
1382 {
1383   FcChar8 *p;
1384
1385   switch (fdwReason) {
1386   case DLL_PROCESS_ATTACH:
1387       if (!GetModuleFileName ((HMODULE) hinstDLL, fontconfig_path,
1388                               sizeof (fontconfig_path)))
1389           break;
1390
1391       /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
1392        * assume it's a Unix-style installation tree, and use
1393        * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
1394        * folder where the DLL is as FONTCONFIG_PATH.
1395        */
1396       p = strrchr (fontconfig_path, '\\');
1397       if (p)
1398       {
1399           *p = '\0';
1400           p = strrchr (fontconfig_path, '\\');
1401           if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 ||
1402                     FcStrCmpIgnoreCase (p + 1, "lib") == 0))
1403               *p = '\0';
1404           strcat (fontconfig_path, "\\etc\\fonts");
1405       }
1406       else
1407           fontconfig_path[0] = '\0';
1408       
1409       break;
1410   }
1411
1412   return TRUE;
1413 }
1414
1415 #undef FONTCONFIG_PATH
1416 #define FONTCONFIG_PATH fontconfig_path
1417
1418 #else /* !(_WIN32 && PIC) */
1419
1420 #endif /* !(_WIN32 && PIC) */
1421
1422 #ifndef FONTCONFIG_FILE
1423 #define FONTCONFIG_FILE "fonts.conf"
1424 #endif
1425
1426 static FcChar8 *
1427 FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
1428 {
1429     FcChar8    *path;
1430
1431     if (!dir)
1432         dir = (FcChar8 *) "";
1433     path = malloc (strlen ((char *) dir) + 1 + strlen ((char *) file) + 1);
1434     if (!path)
1435         return 0;
1436
1437     strcpy ((char *) path, (const char *) dir);
1438     /* make sure there's a single separator */
1439 #ifdef _WIN32
1440     if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
1441                       path[strlen((char *) path)-1] != '\\')) &&
1442          (file[0] != '/' && file[0] != '\\'))
1443         strcat ((char *) path, "\\");
1444 #else
1445     if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
1446         strcat ((char *) path, "/");
1447 #endif
1448     strcat ((char *) path, (char *) file);
1449
1450     FcMemAlloc (FC_MEM_STRING, strlen ((char *) path) + 1);
1451     if (access ((char *) path, R_OK) == 0)
1452         return path;
1453     
1454     FcStrFree (path);
1455     return 0;
1456 }
1457
1458 static FcChar8 **
1459 FcConfigGetPath (void)
1460 {
1461     FcChar8    **path;
1462     FcChar8    *env, *e, *colon;
1463     FcChar8    *dir;
1464     int     npath;
1465     int     i;
1466
1467     npath = 2;  /* default dir + null */
1468     env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
1469     if (env)
1470     {
1471         e = env;
1472         npath++;
1473         while (*e)
1474             if (*e++ == FC_SEARCH_PATH_SEPARATOR)
1475                 npath++;
1476     }
1477     path = calloc (npath, sizeof (FcChar8 *));
1478     if (!path)
1479         goto bail0;
1480     i = 0;
1481
1482     if (env)
1483     {
1484         e = env;
1485         while (*e) 
1486         {
1487             colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
1488             if (!colon)
1489                 colon = e + strlen ((char *) e);
1490             path[i] = malloc (colon - e + 1);
1491             if (!path[i])
1492                 goto bail1;
1493             strncpy ((char *) path[i], (const char *) e, colon - e);
1494             path[i][colon - e] = '\0';
1495             if (*colon)
1496                 e = colon + 1;
1497             else
1498                 e = colon;
1499             i++;
1500         }
1501     }
1502     
1503     dir = (FcChar8 *) FONTCONFIG_PATH;
1504     path[i] = malloc (strlen ((char *) dir) + 1);
1505     if (!path[i])
1506         goto bail1;
1507     strcpy ((char *) path[i], (const char *) dir);
1508     return path;
1509
1510 bail1:
1511     for (i = 0; path[i]; i++)
1512         free (path[i]);
1513     free (path);
1514 bail0:
1515     return 0;
1516 }
1517
1518 static void
1519 FcConfigFreePath (FcChar8 **path)
1520 {
1521     FcChar8    **p;
1522
1523     for (p = path; *p; p++)
1524         free (*p);
1525     free (path);
1526 }
1527
1528 static FcBool   _FcConfigHomeEnabled = FcTrue;
1529
1530 FcChar8 *
1531 FcConfigHome (void)
1532 {
1533     if (_FcConfigHomeEnabled)
1534     {
1535         char *home = getenv ("HOME");
1536
1537 #ifdef _WIN32
1538         if (home == NULL)
1539             home = getenv ("USERPROFILE");
1540 #endif
1541
1542         return home;
1543     }
1544     return 0;
1545 }
1546
1547 FcBool
1548 FcConfigEnableHome (FcBool enable)
1549 {
1550     FcBool  prev = _FcConfigHomeEnabled;
1551     _FcConfigHomeEnabled = enable;
1552     return prev;
1553 }
1554
1555 FcChar8 *
1556 FcConfigFilename (const FcChar8 *url)
1557 {
1558     FcChar8    *file, *dir, **path, **p;
1559     
1560     if (!url || !*url)
1561     {
1562         url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
1563         if (!url)
1564             url = (FcChar8 *) FONTCONFIG_FILE;
1565     }
1566     file = 0;
1567
1568 #ifdef _WIN32
1569     if (isalpha (*url) &&
1570         url[1] == ':' &&
1571         (url[2] == '/' || url[2] == '\\'))
1572         goto absolute_path;
1573 #endif
1574
1575     switch (*url) {
1576     case '~':
1577         dir = FcConfigHome ();
1578         if (dir)
1579             file = FcConfigFileExists (dir, url + 1);
1580         else
1581             file = 0;
1582         break;
1583 #ifdef _WIN32
1584     case '\\':
1585     absolute_path:
1586 #endif
1587     case '/':
1588         file = FcConfigFileExists (0, url);
1589         break;
1590     default:
1591         path = FcConfigGetPath ();
1592         if (!path)
1593             return 0;
1594         for (p = path; *p; p++)
1595         {
1596             file = FcConfigFileExists (*p, url);
1597             if (file)
1598                 break;
1599         }
1600         FcConfigFreePath (path);
1601         break;
1602     }
1603     return file;
1604 }
1605
1606 /*
1607  * Manage the application-specific fonts
1608  */
1609
1610 FcBool
1611 FcConfigAppFontAddFile (FcConfig    *config,
1612                         const FcChar8  *file)
1613 {
1614     FcFontSet   *set;
1615     FcStrSet    *subdirs;
1616     FcStrList   *sublist;
1617     FcChar8     *subdir;
1618
1619     if (!config)
1620     {
1621         config = FcConfigGetCurrent ();
1622         if (!config)
1623             return FcFalse;
1624     }
1625
1626     subdirs = FcStrSetCreate ();
1627     if (!subdirs)
1628         return FcFalse;
1629     
1630     set = FcConfigGetFonts (config, FcSetApplication);
1631     if (!set)
1632     {
1633         set = FcFontSetCreate ();
1634         if (!set)
1635         {
1636             FcStrSetDestroy (subdirs);
1637             return FcFalse;
1638         }
1639         FcConfigSetFonts (config, set, FcSetApplication);
1640     }
1641         
1642     if (!FcFileScanConfig (set, subdirs, 0, config->blanks, file, FcFalse, config))
1643     {
1644         FcStrSetDestroy (subdirs);
1645         return FcFalse;
1646     }
1647     if ((sublist = FcStrListCreate (subdirs)))
1648     {
1649         while ((subdir = FcStrListNext (sublist)))
1650         {
1651             FcConfigAppFontAddDir (config, subdir);
1652         }
1653         FcStrListDone (sublist);
1654     }
1655     return FcTrue;
1656 }
1657
1658 FcBool
1659 FcConfigAppFontAddDir (FcConfig     *config,
1660                        const FcChar8   *dir)
1661 {
1662     FcFontSet   *set;
1663     FcStrSet    *subdirs;
1664     FcStrList   *sublist;
1665     FcChar8     *subdir;
1666     
1667     if (!config)
1668     {
1669         config = FcConfigGetCurrent ();
1670         if (!config)
1671             return FcFalse;
1672     }
1673     subdirs = FcStrSetCreate ();
1674     if (!subdirs)
1675         return FcFalse;
1676     
1677     set = FcConfigGetFonts (config, FcSetApplication);
1678     if (!set)
1679     {
1680         set = FcFontSetCreate ();
1681         if (!set)
1682         {
1683             FcStrSetDestroy (subdirs);
1684             return FcFalse;
1685         }
1686         FcConfigSetFonts (config, set, FcSetApplication);
1687     }
1688     
1689     if (!FcDirScanConfig (set, subdirs, 0, config->blanks, dir, FcFalse, config))
1690     {
1691         FcStrSetDestroy (subdirs);
1692         return FcFalse;
1693     }
1694     if ((sublist = FcStrListCreate (subdirs)))
1695     {
1696         while ((subdir = FcStrListNext (sublist)))
1697         {
1698             FcConfigAppFontAddDir (config, subdir);
1699         }
1700         FcStrListDone (sublist);
1701     }
1702     return FcTrue;
1703 }
1704
1705 void
1706 FcConfigAppFontClear (FcConfig      *config)
1707 {
1708     FcConfigSetFonts (config, 0, FcSetApplication);
1709 }
1710
1711 /*
1712  * Manage filename-based font source selectors
1713  */
1714
1715 FcBool
1716 FcConfigGlobAdd (FcConfig       *config,
1717                  const FcChar8  *glob,
1718                  FcBool         accept)
1719 {
1720     FcStrSet    *set = accept ? config->acceptGlobs : config->rejectGlobs;
1721
1722     return FcStrSetAdd (set, glob);
1723 }
1724
1725 static FcBool
1726 FcConfigGlobMatch (const FcChar8    *glob,
1727                    const FcChar8    *string)
1728 {
1729     FcChar8     c;
1730
1731     while ((c = *glob++)) 
1732     {
1733         switch (c) {
1734         case '*':
1735             /* short circuit common case */
1736             if (!*glob)
1737                 return FcTrue;
1738             /* short circuit another common case */
1739             if (strchr ((char *) glob, '*') == 0)
1740                 string += strlen ((char *) string) - strlen ((char *) glob);
1741             while (*string)
1742             {
1743                 if (FcConfigGlobMatch (glob, string))
1744                     return FcTrue;
1745                 string++;
1746             }
1747             return FcFalse;
1748         case '?':
1749             if (*string++ == '\0')
1750                 return FcFalse;
1751             break;
1752         default:
1753             if (*string++ != c)
1754                 return FcFalse;
1755             break;
1756         }
1757     }
1758     return *string == '\0';
1759 }
1760
1761 static FcBool
1762 FcConfigGlobsMatch (const FcStrSet      *globs,
1763                     const FcChar8       *string)
1764 {
1765     int i;
1766
1767     for (i = 0; i < globs->num; i++)
1768         if (FcConfigGlobMatch (globs->strs[i], string))
1769             return FcTrue;
1770     return FcFalse;
1771 }
1772
1773 FcBool
1774 FcConfigAcceptFilename (FcConfig        *config,
1775                         const FcChar8   *filename)
1776 {
1777     if (FcConfigGlobsMatch (config->acceptGlobs, filename))
1778         return FcTrue;
1779     if (FcConfigGlobsMatch (config->rejectGlobs, filename))
1780         return FcFalse;
1781     return FcTrue;
1782 }