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