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