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