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