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