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