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