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