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