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