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