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