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