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