]> git.wh0rd.org Git - fontconfig.git/blob - src/fccfg.c
Simplify FcValueSave() semantics
[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  * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL THE AUTHOR(S) 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 = e->u.sval;
856         v = FcValueSave (v);
857         break;
858     case FcOpMatrix:
859         v.type = FcTypeMatrix;
860         v.u.m = e->u.mval;
861         v = FcValueSave (v);
862         break;
863     case FcOpCharSet:
864         v.type = FcTypeCharSet;
865         v.u.c = e->u.cval;
866         v = FcValueSave (v);
867         break;
868     case FcOpBool:
869         v.type = FcTypeBool;
870         v.u.b = e->u.bval;
871         break;
872     case FcOpField:
873         r = FcPatternObjectGet (p, e->u.object, 0, &v);
874         if (r != FcResultMatch)
875             v.type = FcTypeVoid;
876         v = FcValueSave (v);
877         break;
878     case FcOpConst:
879         if (FcNameConstant (e->u.constant, &v.u.i))
880             v.type = FcTypeInteger;
881         else
882             v.type = FcTypeVoid;
883         break;
884     case FcOpQuest:
885         vl = FcConfigEvaluate (p, e->u.tree.left);
886         if (vl.type == FcTypeBool)
887         {
888             if (vl.u.b)
889                 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
890             else
891                 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
892         }
893         else
894             v.type = FcTypeVoid;
895         FcValueDestroy (vl);
896         break;
897     case FcOpEqual:
898     case FcOpNotEqual:
899     case FcOpLess:
900     case FcOpLessEqual:
901     case FcOpMore:
902     case FcOpMoreEqual:
903     case FcOpContains:
904     case FcOpNotContains:
905     case FcOpListing:
906         vl = FcConfigEvaluate (p, e->u.tree.left);
907         vr = FcConfigEvaluate (p, e->u.tree.right);
908         v.type = FcTypeBool;
909         v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
910         FcValueDestroy (vl);
911         FcValueDestroy (vr);
912         break;  
913     case FcOpOr:
914     case FcOpAnd:
915     case FcOpPlus:
916     case FcOpMinus:
917     case FcOpTimes:
918     case FcOpDivide:
919         vl = FcConfigEvaluate (p, e->u.tree.left);
920         vr = FcConfigEvaluate (p, e->u.tree.right);
921         vl = FcConfigPromote (vl, vr);
922         vr = FcConfigPromote (vr, vl);
923         if (vl.type == vr.type)
924         {
925             switch (vl.type) {
926             case FcTypeDouble:
927                 switch (e->op) {
928                 case FcOpPlus:     
929                     v.type = FcTypeDouble;
930                     v.u.d = vl.u.d + vr.u.d; 
931                     break;
932                 case FcOpMinus:
933                     v.type = FcTypeDouble;
934                     v.u.d = vl.u.d - vr.u.d; 
935                     break;
936                 case FcOpTimes:
937                     v.type = FcTypeDouble;
938                     v.u.d = vl.u.d * vr.u.d; 
939                     break;
940                 case FcOpDivide:
941                     v.type = FcTypeDouble;
942                     v.u.d = vl.u.d / vr.u.d; 
943                     break;
944                 default:
945                     v.type = FcTypeVoid; 
946                     break;
947                 }
948                 if (v.type == FcTypeDouble &&
949                     v.u.d == (double) (int) v.u.d)
950                 {
951                     v.type = FcTypeInteger;
952                     v.u.i = (int) v.u.d;
953                 }
954                 break;
955             case FcTypeBool:
956                 switch (e->op) {
957                 case FcOpOr:
958                     v.type = FcTypeBool;
959                     v.u.b = vl.u.b || vr.u.b;
960                     break;
961                 case FcOpAnd:
962                     v.type = FcTypeBool;
963                     v.u.b = vl.u.b && vr.u.b;
964                     break;
965                 default:
966                     v.type = FcTypeVoid; 
967                     break;
968                 }
969                 break;
970             case FcTypeString:
971                 switch (e->op) {
972                 case FcOpPlus:
973                     v.type = FcTypeString;
974                     str = FcStrPlus (vl.u.s, vr.u.s);
975                     v.u.s = FcStrStaticName (str);
976                     FcStrFree (str);
977                          
978                     if (!v.u.s)
979                         v.type = FcTypeVoid;
980                     break;
981                 default:
982                     v.type = FcTypeVoid;
983                     break;
984                 }
985                 break;
986             case FcTypeMatrix:
987                 switch (e->op) {
988                 case FcOpTimes:
989                     v.type = FcTypeMatrix;
990                     m = malloc (sizeof (FcMatrix));
991                     if (m)
992                     {
993                         FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
994                         FcMatrixMultiply (m, vl.u.m, vr.u.m);
995                         v.u.m = m;
996                     }
997                     else
998                     {
999                         v.type = FcTypeVoid;
1000                     }
1001                     break;
1002                 default:
1003                     v.type = FcTypeVoid;
1004                     break;
1005                 }
1006                 break;
1007             default:
1008                 v.type = FcTypeVoid;
1009                 break;
1010             }
1011         }
1012         else
1013             v.type = FcTypeVoid;
1014         FcValueDestroy (vl);
1015         FcValueDestroy (vr);
1016         break;
1017     case FcOpNot:
1018         vl = FcConfigEvaluate (p, e->u.tree.left);
1019         switch (vl.type) {
1020         case FcTypeBool:
1021             v.type = FcTypeBool;
1022             v.u.b = !vl.u.b;
1023             break;
1024         default:
1025             v.type = FcTypeVoid;
1026             break;
1027         }
1028         FcValueDestroy (vl);
1029         break;
1030     case FcOpFloor:
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 = FcDoubleFloor (vl.u.d);
1039             break;
1040         default:
1041             v.type = FcTypeVoid;
1042             break;
1043         }
1044         FcValueDestroy (vl);
1045         break;
1046     case FcOpCeil:
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 = FcDoubleCeil (vl.u.d);
1055             break;
1056         default:
1057             v.type = FcTypeVoid;
1058             break;
1059         }
1060         FcValueDestroy (vl);
1061         break;
1062     case FcOpRound:
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 = FcDoubleRound (vl.u.d);
1071             break;
1072         default:
1073             v.type = FcTypeVoid;
1074             break;
1075         }
1076         FcValueDestroy (vl);
1077         break;
1078     case FcOpTrunc:
1079         vl = FcConfigEvaluate (p, e->u.tree.left);
1080         switch (vl.type) {
1081         case FcTypeInteger:
1082             v = vl;
1083             break;
1084         case FcTypeDouble:
1085             v.type = FcTypeInteger;
1086             v.u.i = FcDoubleTrunc (vl.u.d);
1087             break;
1088         default:
1089             v.type = FcTypeVoid;
1090             break;
1091         }
1092         FcValueDestroy (vl);
1093         break;
1094     default:
1095         v.type = FcTypeVoid;
1096         break;
1097     }
1098     return v;
1099 }
1100
1101 static FcValueList *
1102 FcConfigMatchValueList (FcPattern       *p,
1103                         FcTest          *t,
1104                         FcValueList     *values)
1105 {
1106     FcValueList     *ret = 0;
1107     FcExpr          *e = t->expr;
1108     FcValue         value;
1109     FcValueList     *v;
1110     
1111     while (e)
1112     {
1113         /* Compute the value of the match expression */
1114         if (e->op == FcOpComma)
1115         {
1116             value = FcConfigEvaluate (p, e->u.tree.left);
1117             e = e->u.tree.right;
1118         }
1119         else
1120         {
1121             value = FcConfigEvaluate (p, e);
1122             e = 0;
1123         }
1124
1125         for (v = values; v; v = FcValueListNext(v))
1126         {
1127             /* Compare the pattern value to the match expression value */
1128             if (FcConfigCompareValue (&v->value, t->op, &value))
1129             {
1130                 if (!ret)
1131                     ret = v;
1132             }
1133             else
1134             {
1135                 if (t->qual == FcQualAll)
1136                 {
1137                     ret = 0;
1138                     break;
1139                 }
1140             }
1141         }
1142         FcValueDestroy (value);
1143     }
1144     return ret;
1145 }
1146
1147 static FcValueList *
1148 FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding)
1149 {
1150     FcValueList *l;
1151     
1152     if (!e)
1153         return 0;
1154     l = (FcValueList *) malloc (sizeof (FcValueList));
1155     if (!l)
1156         return 0;
1157     FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
1158     if (e->op == FcOpComma)
1159     {
1160         l->value = FcConfigEvaluate (p, e->u.tree.left);
1161         l->next = FcConfigValues (p, e->u.tree.right, binding);
1162     }
1163     else
1164     {
1165         l->value = FcConfigEvaluate (p, e);
1166         l->next = NULL;
1167     }
1168     l->binding = binding;
1169     if (l->value.type == FcTypeVoid)
1170     {
1171         FcValueList  *next = FcValueListNext(l);
1172
1173         FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
1174         free (l);
1175         l = next;
1176     }
1177
1178     return l;
1179 }
1180
1181 static FcBool
1182 FcConfigAdd (FcValueListPtr *head,
1183              FcValueList    *position,
1184              FcBool         append,
1185              FcValueList    *new)
1186 {
1187     FcValueListPtr  *prev, last, v;
1188     FcValueBinding  sameBinding;
1189     
1190     if (position)
1191         sameBinding = position->binding;
1192     else
1193         sameBinding = FcValueBindingWeak;
1194     for (v = new; v != NULL; v = FcValueListNext(v))
1195         if (v->binding == FcValueBindingSame)
1196             v->binding = sameBinding;
1197     if (append)
1198     {
1199         if (position)
1200             prev = &position->next;
1201         else
1202             for (prev = head; *prev != NULL; 
1203                  prev = &(*prev)->next)
1204                 ;
1205     }
1206     else
1207     {
1208         if (position)
1209         {
1210             for (prev = head; *prev != NULL; 
1211                  prev = &(*prev)->next)
1212             {
1213                 if (*prev == position)
1214                     break;
1215             }
1216         }
1217         else
1218             prev = head;
1219
1220         if (FcDebug () & FC_DBG_EDIT)
1221         {
1222             if (*prev == NULL)
1223                 printf ("position not on list\n");
1224         }
1225     }
1226
1227     if (FcDebug () & FC_DBG_EDIT)
1228     {
1229         printf ("%s list before ", append ? "Append" : "Prepend");
1230         FcValueListPrint (*head);
1231         printf ("\n");
1232     }
1233     
1234     if (new)
1235     {
1236         last = new;
1237         while (last->next != NULL)
1238             last = last->next;
1239     
1240         last->next = *prev;
1241         *prev = new;
1242     }
1243     
1244     if (FcDebug () & FC_DBG_EDIT)
1245     {
1246         printf ("%s list after ", append ? "Append" : "Prepend");
1247         FcValueListPrint (*head);
1248         printf ("\n");
1249     }
1250     
1251     return FcTrue;
1252 }
1253
1254 static void
1255 FcConfigDel (FcValueListPtr *head,
1256              FcValueList    *position)
1257 {
1258     FcValueListPtr *prev;
1259
1260     for (prev = head; *prev != NULL; prev = &(*prev)->next)
1261     {
1262         if (*prev == position)
1263         {
1264             *prev = position->next;
1265             position->next = NULL;
1266             FcValueListDestroy (position);
1267             break;
1268         }
1269     }
1270 }
1271
1272 static void
1273 FcConfigPatternAdd (FcPattern   *p,
1274                     FcObject    object,
1275                     FcValueList *list,
1276                     FcBool      append)
1277 {
1278     if (list)
1279     {
1280         FcPatternElt    *e = FcPatternObjectInsertElt (p, object);
1281     
1282         if (!e)
1283             return;
1284         FcConfigAdd (&e->values, 0, append, list);
1285     }
1286 }
1287
1288 /*
1289  * Delete all values associated with a field
1290  */
1291 static void
1292 FcConfigPatternDel (FcPattern   *p,
1293                     FcObject    object)
1294 {
1295     FcPatternElt    *e = FcPatternObjectFindElt (p, object);
1296     if (!e)
1297         return;
1298     while (e->values != NULL)
1299         FcConfigDel (&e->values, e->values);
1300 }
1301
1302 static void
1303 FcConfigPatternCanon (FcPattern     *p,
1304                       FcObject      object)
1305 {
1306     FcPatternElt    *e = FcPatternObjectFindElt (p, object);
1307     if (!e)
1308         return;
1309     if (e->values == NULL)
1310         FcPatternObjectDel (p, object);
1311 }
1312
1313 FcBool
1314 FcConfigSubstituteWithPat (FcConfig    *config,
1315                            FcPattern   *p,
1316                            FcPattern   *p_pat,
1317                            FcMatchKind kind)
1318 {
1319     FcSubst         *s;
1320     FcSubState      *st;
1321     int             i;
1322     FcTest          *t;
1323     FcEdit          *e;
1324     FcValueList     *l;
1325     FcPattern       *m;
1326
1327     if (!config)
1328     {
1329         config = FcConfigGetCurrent ();
1330         if (!config)
1331             return FcFalse;
1332     }
1333
1334     switch (kind) {
1335     case FcMatchPattern:
1336         s = config->substPattern;
1337         break;
1338     case FcMatchFont:
1339         s = config->substFont;
1340         break;
1341     case FcMatchScan:
1342         s = config->substScan;
1343         break;
1344     default:
1345         return FcFalse;
1346     }
1347
1348     st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
1349     if (!st && config->maxObjects)
1350         return FcFalse;
1351     FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1352
1353     if (FcDebug () & FC_DBG_EDIT)
1354     {
1355         printf ("FcConfigSubstitute ");
1356         FcPatternPrint (p);
1357     }
1358     for (; s; s = s->next)
1359     {
1360         /*
1361          * Check the tests to see if
1362          * they all match the pattern
1363          */
1364         for (t = s->test, i = 0; t; t = t->next, i++)
1365         {
1366             if (FcDebug () & FC_DBG_EDIT)
1367             {
1368                 printf ("FcConfigSubstitute test ");
1369                 FcTestPrint (t);
1370             }
1371             st[i].elt = 0;
1372             if (kind == FcMatchFont && t->kind == FcMatchPattern)
1373                 m = p_pat;
1374             else
1375                 m = p;
1376             if (m)
1377                 st[i].elt = FcPatternObjectFindElt (m, t->object);
1378             else
1379                 st[i].elt = 0;
1380             /*
1381              * If there's no such field in the font,
1382              * then FcQualAll matches while FcQualAny does not
1383              */
1384             if (!st[i].elt)
1385             {
1386                 if (t->qual == FcQualAll)
1387                 {
1388                     st[i].value = 0;
1389                     continue;
1390                 }
1391                 else
1392                     break;
1393             }
1394             /*
1395              * Check to see if there is a match, mark the location
1396              * to apply match-relative edits
1397              */
1398             st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values);
1399             if (!st[i].value)
1400                 break;
1401             if (t->qual == FcQualFirst && st[i].value != st[i].elt->values)
1402                 break;
1403             if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values)
1404                 break;
1405         }
1406         if (t)
1407         {
1408             if (FcDebug () & FC_DBG_EDIT)
1409                 printf ("No match\n");
1410             continue;
1411         }
1412         if (FcDebug () & FC_DBG_EDIT)
1413         {
1414             printf ("Substitute ");
1415             FcSubstPrint (s);
1416         }
1417         for (e = s->edit; e; e = e->next)
1418         {
1419             /*
1420              * Evaluate the list of expressions
1421              */
1422             l = FcConfigValues (p, e->expr, e->binding);
1423             /*
1424              * Locate any test associated with this field, skipping
1425              * tests associated with the pattern when substituting in
1426              * the font
1427              */
1428             for (t = s->test, i = 0; t; t = t->next, i++)
1429             {
1430                 if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
1431                     t->object == e->object)
1432                 {
1433                     /* 
1434                      * KLUDGE - the pattern may have been reallocated or
1435                      * things may have been inserted or deleted above
1436                      * this element by other edits.  Go back and find
1437                      * the element again
1438                      */
1439                     if (e != s->edit && st[i].elt)
1440                         st[i].elt = FcPatternObjectFindElt (p, t->object);
1441                     if (!st[i].elt)
1442                         t = 0;
1443                     break;
1444                 }
1445             }
1446             switch (e->op) {
1447             case FcOpAssign:
1448                 /*
1449                  * If there was a test, then replace the matched
1450                  * value with the new list of values
1451                  */
1452                 if (t)
1453                 {
1454                     FcValueList *thisValue = st[i].value;
1455                     FcValueList *nextValue = thisValue;
1456                     
1457                     /*
1458                      * Append the new list of values after the current value
1459                      */
1460                     FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
1461                     /*
1462                      * Delete the marked value
1463                      */
1464                     if (thisValue)
1465                         FcConfigDel (&st[i].elt->values, thisValue);
1466                     /*
1467                      * Adjust any pointers into the value list to ensure
1468                      * future edits occur at the same place
1469                      */
1470                     for (t = s->test, i = 0; t; t = t->next, i++)
1471                     {
1472                         if (st[i].value == thisValue)
1473                             st[i].value = nextValue;
1474                     }
1475                     break;
1476                 }
1477                 /* fall through ... */
1478             case FcOpAssignReplace:
1479                 /*
1480                  * Delete all of the values and insert
1481                  * the new set
1482                  */
1483                 FcConfigPatternDel (p, e->object);
1484                 FcConfigPatternAdd (p, e->object, l, FcTrue);
1485                 /*
1486                  * Adjust any pointers into the value list as they no
1487                  * longer point to anything valid
1488                  */
1489                 if (t)
1490                 {
1491                     FcPatternElt    *thisElt = st[i].elt;
1492                     for (t = s->test, i = 0; t; t = t->next, i++)
1493                     {
1494                         if (st[i].elt == thisElt)
1495                             st[i].value = 0;
1496                     }
1497                 }
1498                 break;
1499             case FcOpPrepend:
1500                 if (t)
1501                 {
1502                     FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
1503                     break;
1504                 }
1505                 /* fall through ... */
1506             case FcOpPrependFirst:
1507                 FcConfigPatternAdd (p, e->object, l, FcFalse);
1508                 break;
1509             case FcOpAppend:
1510                 if (t)
1511                 {
1512                     FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
1513                     break;
1514                 }
1515                 /* fall through ... */
1516             case FcOpAppendLast:
1517                 FcConfigPatternAdd (p, e->object, l, FcTrue);
1518                 break;
1519             default:
1520                 FcValueListDestroy (l);
1521                 break;
1522             }
1523         }
1524         /*
1525          * Now go through the pattern and eliminate
1526          * any properties without data
1527          */
1528         for (e = s->edit; e; e = e->next)
1529             FcConfigPatternCanon (p, e->object);
1530
1531         if (FcDebug () & FC_DBG_EDIT)
1532         {
1533             printf ("FcConfigSubstitute edit");
1534             FcPatternPrint (p);
1535         }
1536     }
1537     FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1538     free (st);
1539     if (FcDebug () & FC_DBG_EDIT)
1540     {
1541         printf ("FcConfigSubstitute done");
1542         FcPatternPrint (p);
1543     }
1544     return FcTrue;
1545 }
1546
1547 FcBool
1548 FcConfigSubstitute (FcConfig    *config,
1549                     FcPattern   *p,
1550                     FcMatchKind kind)
1551 {
1552     return FcConfigSubstituteWithPat (config, p, 0, kind);
1553 }
1554
1555 #if defined (_WIN32)
1556
1557 #  define WIN32_LEAN_AND_MEAN
1558 #  define WIN32_EXTRA_LEAN
1559 #  include <windows.h>
1560
1561 static FcChar8 fontconfig_path[1000] = "";
1562
1563 #  if (defined (PIC) || defined (DLL_EXPORT))
1564
1565 BOOL WINAPI
1566 DllMain (HINSTANCE hinstDLL,
1567          DWORD     fdwReason,
1568          LPVOID    lpvReserved)
1569 {
1570   FcChar8 *p;
1571
1572   switch (fdwReason) {
1573   case DLL_PROCESS_ATTACH:
1574       if (!GetModuleFileName ((HMODULE) hinstDLL, fontconfig_path,
1575                               sizeof (fontconfig_path)))
1576           break;
1577
1578       /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
1579        * assume it's a Unix-style installation tree, and use
1580        * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
1581        * folder where the DLL is as FONTCONFIG_PATH.
1582        */
1583       p = strrchr (fontconfig_path, '\\');
1584       if (p)
1585       {
1586           *p = '\0';
1587           p = strrchr (fontconfig_path, '\\');
1588           if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 ||
1589                     FcStrCmpIgnoreCase (p + 1, "lib") == 0))
1590               *p = '\0';
1591           strcat (fontconfig_path, "\\etc\\fonts");
1592       }
1593       else
1594           fontconfig_path[0] = '\0';
1595       
1596       break;
1597   }
1598
1599   return TRUE;
1600 }
1601
1602 #  endif /* !PIC */
1603
1604 #undef FONTCONFIG_PATH
1605 #define FONTCONFIG_PATH fontconfig_path
1606
1607 #endif /* !_WIN32 */
1608
1609 #ifndef FONTCONFIG_FILE
1610 #define FONTCONFIG_FILE "fonts.conf"
1611 #endif
1612
1613 static FcChar8 *
1614 FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
1615 {
1616     FcChar8    *path;
1617
1618     if (!dir)
1619         dir = (FcChar8 *) "";
1620     path = malloc (strlen ((char *) dir) + 1 + strlen ((char *) file) + 1);
1621     if (!path)
1622         return 0;
1623
1624     strcpy ((char *) path, (const char *) dir);
1625     /* make sure there's a single separator */
1626 #ifdef _WIN32
1627     if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
1628                       path[strlen((char *) path)-1] != '\\')) &&
1629         !(file[0] == '/' ||
1630           file[0] == '\\' ||
1631           (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
1632         strcat ((char *) path, "\\");
1633 #else
1634     if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
1635         strcat ((char *) path, "/");
1636 #endif
1637     strcat ((char *) path, (char *) file);
1638
1639     FcMemAlloc (FC_MEM_STRING, strlen ((char *) path) + 1);
1640     if (access ((char *) path, R_OK) == 0)
1641         return path;
1642     
1643     FcStrFree (path);
1644     return 0;
1645 }
1646
1647 static FcChar8 **
1648 FcConfigGetPath (void)
1649 {
1650     FcChar8    **path;
1651     FcChar8    *env, *e, *colon;
1652     FcChar8    *dir;
1653     int     npath;
1654     int     i;
1655
1656     npath = 2;  /* default dir + null */
1657     env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
1658     if (env)
1659     {
1660         e = env;
1661         npath++;
1662         while (*e)
1663             if (*e++ == FC_SEARCH_PATH_SEPARATOR)
1664                 npath++;
1665     }
1666     path = calloc (npath, sizeof (FcChar8 *));
1667     if (!path)
1668         goto bail0;
1669     i = 0;
1670
1671     if (env)
1672     {
1673         e = env;
1674         while (*e) 
1675         {
1676             colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
1677             if (!colon)
1678                 colon = e + strlen ((char *) e);
1679             path[i] = malloc (colon - e + 1);
1680             if (!path[i])
1681                 goto bail1;
1682             strncpy ((char *) path[i], (const char *) e, colon - e);
1683             path[i][colon - e] = '\0';
1684             if (*colon)
1685                 e = colon + 1;
1686             else
1687                 e = colon;
1688             i++;
1689         }
1690     }
1691     
1692 #ifdef _WIN32
1693         if (fontconfig_path[0] == '\0')
1694         {
1695                 char *p;
1696                 if(!GetModuleFileName(NULL, fontconfig_path, sizeof(fontconfig_path)))
1697                         goto bail1;
1698                 p = strrchr (fontconfig_path, '\\');
1699                 if (p) *p = '\0';
1700                 strcat (fontconfig_path, "\\fonts");
1701         }
1702 #endif
1703     dir = (FcChar8 *) FONTCONFIG_PATH;
1704     path[i] = malloc (strlen ((char *) dir) + 1);
1705     if (!path[i])
1706         goto bail1;
1707     strcpy ((char *) path[i], (const char *) dir);
1708     return path;
1709
1710 bail1:
1711     for (i = 0; path[i]; i++)
1712         free (path[i]);
1713     free (path);
1714 bail0:
1715     return 0;
1716 }
1717
1718 static void
1719 FcConfigFreePath (FcChar8 **path)
1720 {
1721     FcChar8    **p;
1722
1723     for (p = path; *p; p++)
1724         free (*p);
1725     free (path);
1726 }
1727
1728 static FcBool   _FcConfigHomeEnabled = FcTrue;
1729
1730 FcChar8 *
1731 FcConfigHome (void)
1732 {
1733     if (_FcConfigHomeEnabled)
1734     {
1735         char *home = getenv ("HOME");
1736
1737 #ifdef _WIN32
1738         if (home == NULL)
1739             home = getenv ("USERPROFILE");
1740 #endif
1741
1742         return (FcChar8 *) home;
1743     }
1744     return 0;
1745 }
1746
1747 FcBool
1748 FcConfigEnableHome (FcBool enable)
1749 {
1750     FcBool  prev = _FcConfigHomeEnabled;
1751     _FcConfigHomeEnabled = enable;
1752     return prev;
1753 }
1754
1755 FcChar8 *
1756 FcConfigFilename (const FcChar8 *url)
1757 {
1758     FcChar8    *file, *dir, **path, **p;
1759
1760     if (!url || !*url)
1761     {
1762         url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
1763         if (!url)
1764             url = (FcChar8 *) FONTCONFIG_FILE;
1765     }
1766     file = 0;
1767
1768 #ifdef _WIN32
1769     if (isalpha (*url) &&
1770         url[1] == ':' &&
1771         (url[2] == '/' || url[2] == '\\'))
1772         goto absolute_path;
1773 #endif
1774
1775     switch (*url) {
1776     case '~':
1777         dir = FcConfigHome ();
1778         if (dir)
1779             file = FcConfigFileExists (dir, url + 1);
1780         else
1781             file = 0;
1782         break;
1783 #ifdef _WIN32
1784     case '\\':
1785     absolute_path:
1786 #endif
1787     case '/':
1788         file = FcConfigFileExists (0, url);
1789         break;
1790     default:
1791         path = FcConfigGetPath ();
1792         if (!path)
1793             return 0;
1794         for (p = path; *p; p++)
1795         {
1796             file = FcConfigFileExists (*p, url);
1797             if (file)
1798                 break;
1799         }
1800         FcConfigFreePath (path);
1801         break;
1802     }
1803     return file;
1804 }
1805
1806 /*
1807  * Manage the application-specific fonts
1808  */
1809
1810 FcBool
1811 FcConfigAppFontAddFile (FcConfig    *config,
1812                         const FcChar8  *file)
1813 {
1814     FcFontSet   *set;
1815     FcStrSet    *subdirs;
1816     FcStrList   *sublist;
1817     FcChar8     *subdir;
1818
1819     if (!config)
1820     {
1821         config = FcConfigGetCurrent ();
1822         if (!config)
1823             return FcFalse;
1824     }
1825
1826     subdirs = FcStrSetCreate ();
1827     if (!subdirs)
1828         return FcFalse;
1829     
1830     set = FcConfigGetFonts (config, FcSetApplication);
1831     if (!set)
1832     {
1833         set = FcFontSetCreate ();
1834         if (!set)
1835         {
1836             FcStrSetDestroy (subdirs);
1837             return FcFalse;
1838         }
1839         FcConfigSetFonts (config, set, FcSetApplication);
1840     }
1841         
1842     if (!FcFileScanConfig (set, subdirs, config->blanks, file, config))
1843     {
1844         FcStrSetDestroy (subdirs);
1845         return FcFalse;
1846     }
1847     if ((sublist = FcStrListCreate (subdirs)))
1848     {
1849         while ((subdir = FcStrListNext (sublist)))
1850         {
1851             FcConfigAppFontAddDir (config, subdir);
1852         }
1853         FcStrListDone (sublist);
1854     }
1855     FcStrSetDestroy (subdirs);
1856     return FcTrue;
1857 }
1858
1859 FcBool
1860 FcConfigAppFontAddDir (FcConfig     *config,
1861                        const FcChar8   *dir)
1862 {
1863     FcFontSet   *set;
1864     FcStrSet    *dirs;
1865     
1866     if (!config)
1867     {
1868         config = FcConfigGetCurrent ();
1869         if (!config)
1870             return FcFalse;
1871     }
1872
1873     dirs = FcStrSetCreate ();
1874     if (!dirs)
1875         return FcFalse;
1876     
1877     set = FcConfigGetFonts (config, FcSetApplication);
1878     if (!set)
1879     {
1880         set = FcFontSetCreate ();
1881         if (!set)
1882         {
1883             FcStrSetDestroy (dirs);
1884             return FcFalse;
1885         }
1886         FcConfigSetFonts (config, set, FcSetApplication);
1887     }
1888     
1889     FcStrSetAddFilename (dirs, dir);
1890     
1891     if (!FcConfigAddDirList (config, FcSetApplication, dirs))
1892     {
1893         FcStrSetDestroy (dirs);
1894         return FcFalse;
1895     }
1896     FcStrSetDestroy (dirs);
1897     return FcTrue;
1898 }
1899
1900 void
1901 FcConfigAppFontClear (FcConfig      *config)
1902 {
1903     if (!config)
1904     {
1905         config = FcConfigGetCurrent ();
1906         if (!config)
1907             return;
1908     }
1909
1910     FcConfigSetFonts (config, 0, FcSetApplication);
1911 }
1912
1913 /*
1914  * Manage filename-based font source selectors
1915  */
1916
1917 FcBool
1918 FcConfigGlobAdd (FcConfig       *config,
1919                  const FcChar8  *glob,
1920                  FcBool         accept)
1921 {
1922     FcStrSet    *set = accept ? config->acceptGlobs : config->rejectGlobs;
1923
1924     return FcStrSetAdd (set, glob);
1925 }
1926
1927 static FcBool
1928 FcConfigGlobMatch (const FcChar8    *glob,
1929                    const FcChar8    *string)
1930 {
1931     FcChar8     c;
1932
1933     while ((c = *glob++)) 
1934     {
1935         switch (c) {
1936         case '*':
1937             /* short circuit common case */
1938             if (!*glob)
1939                 return FcTrue;
1940             /* short circuit another common case */
1941             if (strchr ((char *) glob, '*') == 0)
1942                 string += strlen ((char *) string) - strlen ((char *) glob);
1943             while (*string)
1944             {
1945                 if (FcConfigGlobMatch (glob, string))
1946                     return FcTrue;
1947                 string++;
1948             }
1949             return FcFalse;
1950         case '?':
1951             if (*string++ == '\0')
1952                 return FcFalse;
1953             break;
1954         default:
1955             if (*string++ != c)
1956                 return FcFalse;
1957             break;
1958         }
1959     }
1960     return *string == '\0';
1961 }
1962
1963 static FcBool
1964 FcConfigGlobsMatch (const FcStrSet      *globs,
1965                     const FcChar8       *string)
1966 {
1967     int i;
1968
1969     for (i = 0; i < globs->num; i++)
1970         if (FcConfigGlobMatch (globs->strs[i], string))
1971             return FcTrue;
1972     return FcFalse;
1973 }
1974
1975 FcBool
1976 FcConfigAcceptFilename (FcConfig        *config,
1977                         const FcChar8   *filename)
1978 {
1979     if (FcConfigGlobsMatch (config->acceptGlobs, filename))
1980         return FcTrue;
1981     if (FcConfigGlobsMatch (config->rejectGlobs, filename))
1982         return FcFalse;
1983     return FcTrue;
1984 }
1985
1986 /*
1987  * Manage font-pattern based font source selectors
1988  */
1989
1990 FcBool
1991 FcConfigPatternsAdd (FcConfig   *config,
1992                      FcPattern  *pattern,
1993                      FcBool     accept)
1994 {
1995     FcFontSet   *set = accept ? config->acceptPatterns : config->rejectPatterns;
1996
1997     return FcFontSetAdd (set, pattern);
1998 }
1999
2000 static FcBool
2001 FcConfigPatternsMatch (const FcFontSet  *patterns,
2002                        const FcPattern  *font)
2003 {
2004     int i;
2005     
2006     for (i = 0; i < patterns->nfont; i++)
2007         if (FcListPatternMatchAny (patterns->fonts[i], font))
2008             return FcTrue;
2009     return FcFalse;
2010 }
2011
2012 FcBool
2013 FcConfigAcceptFont (FcConfig        *config,
2014                     const FcPattern *font)
2015 {
2016     if (FcConfigPatternsMatch (config->acceptPatterns, font))
2017         return FcTrue;
2018     if (FcConfigPatternsMatch (config->rejectPatterns, font))
2019         return FcFalse;
2020     return FcTrue;
2021 }
2022 #define __fccfg__
2023 #include "fcaliastail.h"
2024 #undef __fccfg__