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