]> git.wh0rd.org Git - fontconfig.git/blob - src/fccfg.c
[lang] Fix serializing LangSet from older versions
[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 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  * 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 ((char *) 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 FcOpBool:
901         v.type = FcTypeBool;
902         v.u.b = e->u.bval;
903         break;
904     case FcOpField:
905         r = FcPatternObjectGet (p, e->u.object, 0, &v);
906         if (r != FcResultMatch)
907             v.type = FcTypeVoid;
908         v = FcValueSave (v);
909         break;
910     case FcOpConst:
911         if (FcNameConstant (e->u.constant, &v.u.i))
912             v.type = FcTypeInteger;
913         else
914             v.type = FcTypeVoid;
915         break;
916     case FcOpQuest:
917         vl = FcConfigEvaluate (p, e->u.tree.left);
918         if (vl.type == FcTypeBool)
919         {
920             if (vl.u.b)
921                 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
922             else
923                 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
924         }
925         else
926             v.type = FcTypeVoid;
927         FcValueDestroy (vl);
928         break;
929     case FcOpEqual:
930     case FcOpNotEqual:
931     case FcOpLess:
932     case FcOpLessEqual:
933     case FcOpMore:
934     case FcOpMoreEqual:
935     case FcOpContains:
936     case FcOpNotContains:
937     case FcOpListing:
938         vl = FcConfigEvaluate (p, e->u.tree.left);
939         vr = FcConfigEvaluate (p, e->u.tree.right);
940         v.type = FcTypeBool;
941         v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
942         FcValueDestroy (vl);
943         FcValueDestroy (vr);
944         break;  
945     case FcOpOr:
946     case FcOpAnd:
947     case FcOpPlus:
948     case FcOpMinus:
949     case FcOpTimes:
950     case FcOpDivide:
951         vl = FcConfigEvaluate (p, e->u.tree.left);
952         vr = FcConfigEvaluate (p, e->u.tree.right);
953         vl = FcConfigPromote (vl, vr);
954         vr = FcConfigPromote (vr, vl);
955         if (vl.type == vr.type)
956         {
957             switch (vl.type) {
958             case FcTypeDouble:
959                 switch (e->op) {
960                 case FcOpPlus:     
961                     v.type = FcTypeDouble;
962                     v.u.d = vl.u.d + vr.u.d; 
963                     break;
964                 case FcOpMinus:
965                     v.type = FcTypeDouble;
966                     v.u.d = vl.u.d - vr.u.d; 
967                     break;
968                 case FcOpTimes:
969                     v.type = FcTypeDouble;
970                     v.u.d = vl.u.d * vr.u.d; 
971                     break;
972                 case FcOpDivide:
973                     v.type = FcTypeDouble;
974                     v.u.d = vl.u.d / vr.u.d; 
975                     break;
976                 default:
977                     v.type = FcTypeVoid; 
978                     break;
979                 }
980                 if (v.type == FcTypeDouble &&
981                     v.u.d == (double) (int) v.u.d)
982                 {
983                     v.type = FcTypeInteger;
984                     v.u.i = (int) v.u.d;
985                 }
986                 break;
987             case FcTypeBool:
988                 switch (e->op) {
989                 case FcOpOr:
990                     v.type = FcTypeBool;
991                     v.u.b = vl.u.b || vr.u.b;
992                     break;
993                 case FcOpAnd:
994                     v.type = FcTypeBool;
995                     v.u.b = vl.u.b && vr.u.b;
996                     break;
997                 default:
998                     v.type = FcTypeVoid; 
999                     break;
1000                 }
1001                 break;
1002             case FcTypeString:
1003                 switch (e->op) {
1004                 case FcOpPlus:
1005                     v.type = FcTypeString;
1006                     str = FcStrPlus (vl.u.s, vr.u.s);
1007                     v.u.s = FcStrStaticName (str);
1008                     FcStrFree (str);
1009                          
1010                     if (!v.u.s)
1011                         v.type = FcTypeVoid;
1012                     break;
1013                 default:
1014                     v.type = FcTypeVoid;
1015                     break;
1016                 }
1017                 break;
1018             case FcTypeMatrix:
1019                 switch (e->op) {
1020                 case FcOpTimes:
1021                     v.type = FcTypeMatrix;
1022                     m = malloc (sizeof (FcMatrix));
1023                     if (m)
1024                     {
1025                         FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
1026                         FcMatrixMultiply (m, vl.u.m, vr.u.m);
1027                         v.u.m = m;
1028                     }
1029                     else
1030                     {
1031                         v.type = FcTypeVoid;
1032                     }
1033                     break;
1034                 default:
1035                     v.type = FcTypeVoid;
1036                     break;
1037                 }
1038                 break;
1039             default:
1040                 v.type = FcTypeVoid;
1041                 break;
1042             }
1043         }
1044         else
1045             v.type = FcTypeVoid;
1046         FcValueDestroy (vl);
1047         FcValueDestroy (vr);
1048         break;
1049     case FcOpNot:
1050         vl = FcConfigEvaluate (p, e->u.tree.left);
1051         switch (vl.type) {
1052         case FcTypeBool:
1053             v.type = FcTypeBool;
1054             v.u.b = !vl.u.b;
1055             break;
1056         default:
1057             v.type = FcTypeVoid;
1058             break;
1059         }
1060         FcValueDestroy (vl);
1061         break;
1062     case FcOpFloor:
1063         vl = FcConfigEvaluate (p, e->u.tree.left);
1064         switch (vl.type) {
1065         case FcTypeInteger:
1066             v = vl;
1067             break;
1068         case FcTypeDouble:
1069             v.type = FcTypeInteger;
1070             v.u.i = FcDoubleFloor (vl.u.d);
1071             break;
1072         default:
1073             v.type = FcTypeVoid;
1074             break;
1075         }
1076         FcValueDestroy (vl);
1077         break;
1078     case FcOpCeil:
1079         vl = FcConfigEvaluate (p, e->u.tree.left);
1080         switch (vl.type) {
1081         case FcTypeInteger:
1082             v = vl;
1083             break;
1084         case FcTypeDouble:
1085             v.type = FcTypeInteger;
1086             v.u.i = FcDoubleCeil (vl.u.d);
1087             break;
1088         default:
1089             v.type = FcTypeVoid;
1090             break;
1091         }
1092         FcValueDestroy (vl);
1093         break;
1094     case FcOpRound:
1095         vl = FcConfigEvaluate (p, e->u.tree.left);
1096         switch (vl.type) {
1097         case FcTypeInteger:
1098             v = vl;
1099             break;
1100         case FcTypeDouble:
1101             v.type = FcTypeInteger;
1102             v.u.i = FcDoubleRound (vl.u.d);
1103             break;
1104         default:
1105             v.type = FcTypeVoid;
1106             break;
1107         }
1108         FcValueDestroy (vl);
1109         break;
1110     case FcOpTrunc:
1111         vl = FcConfigEvaluate (p, e->u.tree.left);
1112         switch (vl.type) {
1113         case FcTypeInteger:
1114             v = vl;
1115             break;
1116         case FcTypeDouble:
1117             v.type = FcTypeInteger;
1118             v.u.i = FcDoubleTrunc (vl.u.d);
1119             break;
1120         default:
1121             v.type = FcTypeVoid;
1122             break;
1123         }
1124         FcValueDestroy (vl);
1125         break;
1126     default:
1127         v.type = FcTypeVoid;
1128         break;
1129     }
1130     return v;
1131 }
1132
1133 static FcValueList *
1134 FcConfigMatchValueList (FcPattern       *p,
1135                         FcTest          *t,
1136                         FcValueList     *values)
1137 {
1138     FcValueList     *ret = 0;
1139     FcExpr          *e = t->expr;
1140     FcValue         value;
1141     FcValueList     *v;
1142     
1143     while (e)
1144     {
1145         /* Compute the value of the match expression */
1146         if (e->op == FcOpComma)
1147         {
1148             value = FcConfigEvaluate (p, e->u.tree.left);
1149             e = e->u.tree.right;
1150         }
1151         else
1152         {
1153             value = FcConfigEvaluate (p, e);
1154             e = 0;
1155         }
1156
1157         for (v = values; v; v = FcValueListNext(v))
1158         {
1159             /* Compare the pattern value to the match expression value */
1160             if (FcConfigCompareValue (&v->value, t->op, &value))
1161             {
1162                 if (!ret)
1163                     ret = v;
1164             }
1165             else
1166             {
1167                 if (t->qual == FcQualAll)
1168                 {
1169                     ret = 0;
1170                     break;
1171                 }
1172             }
1173         }
1174         FcValueDestroy (value);
1175     }
1176     return ret;
1177 }
1178
1179 static FcValueList *
1180 FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding)
1181 {
1182     FcValueList *l;
1183     
1184     if (!e)
1185         return 0;
1186     l = (FcValueList *) malloc (sizeof (FcValueList));
1187     if (!l)
1188         return 0;
1189     FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
1190     if (e->op == FcOpComma)
1191     {
1192         l->value = FcConfigEvaluate (p, e->u.tree.left);
1193         l->next = FcConfigValues (p, e->u.tree.right, binding);
1194     }
1195     else
1196     {
1197         l->value = FcConfigEvaluate (p, e);
1198         l->next = NULL;
1199     }
1200     l->binding = binding;
1201     if (l->value.type == FcTypeVoid)
1202     {
1203         FcValueList  *next = FcValueListNext(l);
1204
1205         FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
1206         free (l);
1207         l = next;
1208     }
1209
1210     return l;
1211 }
1212
1213 static FcBool
1214 FcConfigAdd (FcValueListPtr *head,
1215              FcValueList    *position,
1216              FcBool         append,
1217              FcValueList    *new)
1218 {
1219     FcValueListPtr  *prev, last, v;
1220     FcValueBinding  sameBinding;
1221     
1222     if (position)
1223         sameBinding = position->binding;
1224     else
1225         sameBinding = FcValueBindingWeak;
1226     for (v = new; v != NULL; v = FcValueListNext(v))
1227         if (v->binding == FcValueBindingSame)
1228             v->binding = sameBinding;
1229     if (append)
1230     {
1231         if (position)
1232             prev = &position->next;
1233         else
1234             for (prev = head; *prev != NULL; 
1235                  prev = &(*prev)->next)
1236                 ;
1237     }
1238     else
1239     {
1240         if (position)
1241         {
1242             for (prev = head; *prev != NULL; 
1243                  prev = &(*prev)->next)
1244             {
1245                 if (*prev == position)
1246                     break;
1247             }
1248         }
1249         else
1250             prev = head;
1251
1252         if (FcDebug () & FC_DBG_EDIT)
1253         {
1254             if (*prev == NULL)
1255                 printf ("position not on list\n");
1256         }
1257     }
1258
1259     if (FcDebug () & FC_DBG_EDIT)
1260     {
1261         printf ("%s list before ", append ? "Append" : "Prepend");
1262         FcValueListPrint (*head);
1263         printf ("\n");
1264     }
1265     
1266     if (new)
1267     {
1268         last = new;
1269         while (last->next != NULL)
1270             last = last->next;
1271     
1272         last->next = *prev;
1273         *prev = new;
1274     }
1275     
1276     if (FcDebug () & FC_DBG_EDIT)
1277     {
1278         printf ("%s list after ", append ? "Append" : "Prepend");
1279         FcValueListPrint (*head);
1280         printf ("\n");
1281     }
1282     
1283     return FcTrue;
1284 }
1285
1286 static void
1287 FcConfigDel (FcValueListPtr *head,
1288              FcValueList    *position)
1289 {
1290     FcValueListPtr *prev;
1291
1292     for (prev = head; *prev != NULL; prev = &(*prev)->next)
1293     {
1294         if (*prev == position)
1295         {
1296             *prev = position->next;
1297             position->next = NULL;
1298             FcValueListDestroy (position);
1299             break;
1300         }
1301     }
1302 }
1303
1304 static void
1305 FcConfigPatternAdd (FcPattern   *p,
1306                     FcObject    object,
1307                     FcValueList *list,
1308                     FcBool      append)
1309 {
1310     if (list)
1311     {
1312         FcPatternElt    *e = FcPatternObjectInsertElt (p, object);
1313     
1314         if (!e)
1315             return;
1316         FcConfigAdd (&e->values, 0, append, list);
1317     }
1318 }
1319
1320 /*
1321  * Delete all values associated with a field
1322  */
1323 static void
1324 FcConfigPatternDel (FcPattern   *p,
1325                     FcObject    object)
1326 {
1327     FcPatternElt    *e = FcPatternObjectFindElt (p, object);
1328     if (!e)
1329         return;
1330     while (e->values != NULL)
1331         FcConfigDel (&e->values, e->values);
1332 }
1333
1334 static void
1335 FcConfigPatternCanon (FcPattern     *p,
1336                       FcObject      object)
1337 {
1338     FcPatternElt    *e = FcPatternObjectFindElt (p, object);
1339     if (!e)
1340         return;
1341     if (e->values == NULL)
1342         FcPatternObjectDel (p, object);
1343 }
1344
1345 FcBool
1346 FcConfigSubstituteWithPat (FcConfig    *config,
1347                            FcPattern   *p,
1348                            FcPattern   *p_pat,
1349                            FcMatchKind kind)
1350 {
1351     FcSubst         *s;
1352     FcSubState      *st;
1353     int             i;
1354     FcTest          *t;
1355     FcEdit          *e;
1356     FcValueList     *l;
1357     FcPattern       *m;
1358
1359     if (!config)
1360     {
1361         config = FcConfigGetCurrent ();
1362         if (!config)
1363             return FcFalse;
1364     }
1365
1366     switch (kind) {
1367     case FcMatchPattern:
1368         s = config->substPattern;
1369         break;
1370     case FcMatchFont:
1371         s = config->substFont;
1372         break;
1373     case FcMatchScan:
1374         s = config->substScan;
1375         break;
1376     default:
1377         return FcFalse;
1378     }
1379
1380     st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
1381     if (!st && config->maxObjects)
1382         return FcFalse;
1383     FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1384
1385     if (FcDebug () & FC_DBG_EDIT)
1386     {
1387         printf ("FcConfigSubstitute ");
1388         FcPatternPrint (p);
1389     }
1390     for (; s; s = s->next)
1391     {
1392         /*
1393          * Check the tests to see if
1394          * they all match the pattern
1395          */
1396         for (t = s->test, i = 0; t; t = t->next, i++)
1397         {
1398             if (FcDebug () & FC_DBG_EDIT)
1399             {
1400                 printf ("FcConfigSubstitute test ");
1401                 FcTestPrint (t);
1402             }
1403             st[i].elt = 0;
1404             if (kind == FcMatchFont && t->kind == FcMatchPattern)
1405                 m = p_pat;
1406             else
1407                 m = p;
1408             if (m)
1409                 st[i].elt = FcPatternObjectFindElt (m, t->object);
1410             else
1411                 st[i].elt = 0;
1412             /*
1413              * If there's no such field in the font,
1414              * then FcQualAll matches while FcQualAny does not
1415              */
1416             if (!st[i].elt)
1417             {
1418                 if (t->qual == FcQualAll)
1419                 {
1420                     st[i].value = 0;
1421                     continue;
1422                 }
1423                 else
1424                     break;
1425             }
1426             /*
1427              * Check to see if there is a match, mark the location
1428              * to apply match-relative edits
1429              */
1430             st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values);
1431             if (!st[i].value)
1432                 break;
1433             if (t->qual == FcQualFirst && st[i].value != st[i].elt->values)
1434                 break;
1435             if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values)
1436                 break;
1437         }
1438         if (t)
1439         {
1440             if (FcDebug () & FC_DBG_EDIT)
1441                 printf ("No match\n");
1442             continue;
1443         }
1444         if (FcDebug () & FC_DBG_EDIT)
1445         {
1446             printf ("Substitute ");
1447             FcSubstPrint (s);
1448         }
1449         for (e = s->edit; e; e = e->next)
1450         {
1451             /*
1452              * Evaluate the list of expressions
1453              */
1454             l = FcConfigValues (p, e->expr, e->binding);
1455             /*
1456              * Locate any test associated with this field, skipping
1457              * tests associated with the pattern when substituting in
1458              * the font
1459              */
1460             for (t = s->test, i = 0; t; t = t->next, i++)
1461             {
1462                 if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
1463                     t->object == e->object)
1464                 {
1465                     /* 
1466                      * KLUDGE - the pattern may have been reallocated or
1467                      * things may have been inserted or deleted above
1468                      * this element by other edits.  Go back and find
1469                      * the element again
1470                      */
1471                     if (e != s->edit && st[i].elt)
1472                         st[i].elt = FcPatternObjectFindElt (p, t->object);
1473                     if (!st[i].elt)
1474                         t = 0;
1475                     break;
1476                 }
1477             }
1478             switch (e->op) {
1479             case FcOpAssign:
1480                 /*
1481                  * If there was a test, then replace the matched
1482                  * value with the new list of values
1483                  */
1484                 if (t)
1485                 {
1486                     FcValueList *thisValue = st[i].value;
1487                     FcValueList *nextValue = thisValue;
1488                     
1489                     /*
1490                      * Append the new list of values after the current value
1491                      */
1492                     FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
1493                     /*
1494                      * Delete the marked value
1495                      */
1496                     if (thisValue)
1497                         FcConfigDel (&st[i].elt->values, thisValue);
1498                     /*
1499                      * Adjust any pointers into the value list to ensure
1500                      * future edits occur at the same place
1501                      */
1502                     for (t = s->test, i = 0; t; t = t->next, i++)
1503                     {
1504                         if (st[i].value == thisValue)
1505                             st[i].value = nextValue;
1506                     }
1507                     break;
1508                 }
1509                 /* fall through ... */
1510             case FcOpAssignReplace:
1511                 /*
1512                  * Delete all of the values and insert
1513                  * the new set
1514                  */
1515                 FcConfigPatternDel (p, e->object);
1516                 FcConfigPatternAdd (p, e->object, l, FcTrue);
1517                 /*
1518                  * Adjust any pointers into the value list as they no
1519                  * longer point to anything valid
1520                  */
1521                 if (t)
1522                 {
1523                     FcPatternElt    *thisElt = st[i].elt;
1524                     for (t = s->test, i = 0; t; t = t->next, i++)
1525                     {
1526                         if (st[i].elt == thisElt)
1527                             st[i].value = 0;
1528                     }
1529                 }
1530                 break;
1531             case FcOpPrepend:
1532                 if (t)
1533                 {
1534                     FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
1535                     break;
1536                 }
1537                 /* fall through ... */
1538             case FcOpPrependFirst:
1539                 FcConfigPatternAdd (p, e->object, l, FcFalse);
1540                 break;
1541             case FcOpAppend:
1542                 if (t)
1543                 {
1544                     FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
1545                     break;
1546                 }
1547                 /* fall through ... */
1548             case FcOpAppendLast:
1549                 FcConfigPatternAdd (p, e->object, l, FcTrue);
1550                 break;
1551             default:
1552                 FcValueListDestroy (l);
1553                 break;
1554             }
1555         }
1556         /*
1557          * Now go through the pattern and eliminate
1558          * any properties without data
1559          */
1560         for (e = s->edit; e; e = e->next)
1561             FcConfigPatternCanon (p, e->object);
1562
1563         if (FcDebug () & FC_DBG_EDIT)
1564         {
1565             printf ("FcConfigSubstitute edit");
1566             FcPatternPrint (p);
1567         }
1568     }
1569     FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1570     free (st);
1571     if (FcDebug () & FC_DBG_EDIT)
1572     {
1573         printf ("FcConfigSubstitute done");
1574         FcPatternPrint (p);
1575     }
1576     return FcTrue;
1577 }
1578
1579 FcBool
1580 FcConfigSubstitute (FcConfig    *config,
1581                     FcPattern   *p,
1582                     FcMatchKind kind)
1583 {
1584     return FcConfigSubstituteWithPat (config, p, 0, kind);
1585 }
1586
1587 #if defined (_WIN32)
1588
1589 #  define WIN32_LEAN_AND_MEAN
1590 #  define WIN32_EXTRA_LEAN
1591 #  include <windows.h>
1592
1593 static FcChar8 fontconfig_path[1000] = "";
1594
1595 #  if (defined (PIC) || defined (DLL_EXPORT))
1596
1597 BOOL WINAPI
1598 DllMain (HINSTANCE hinstDLL,
1599          DWORD     fdwReason,
1600          LPVOID    lpvReserved)
1601 {
1602   FcChar8 *p;
1603
1604   switch (fdwReason) {
1605   case DLL_PROCESS_ATTACH:
1606       if (!GetModuleFileName ((HMODULE) hinstDLL, fontconfig_path,
1607                               sizeof (fontconfig_path)))
1608           break;
1609
1610       /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
1611        * assume it's a Unix-style installation tree, and use
1612        * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
1613        * folder where the DLL is as FONTCONFIG_PATH.
1614        */
1615       p = strrchr (fontconfig_path, '\\');
1616       if (p)
1617       {
1618           *p = '\0';
1619           p = strrchr (fontconfig_path, '\\');
1620           if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 ||
1621                     FcStrCmpIgnoreCase (p + 1, "lib") == 0))
1622               *p = '\0';
1623           strcat (fontconfig_path, "\\etc\\fonts");
1624       }
1625       else
1626           fontconfig_path[0] = '\0';
1627       
1628       break;
1629   }
1630
1631   return TRUE;
1632 }
1633
1634 #  endif /* !PIC */
1635
1636 #undef FONTCONFIG_PATH
1637 #define FONTCONFIG_PATH fontconfig_path
1638
1639 #endif /* !_WIN32 */
1640
1641 #ifndef FONTCONFIG_FILE
1642 #define FONTCONFIG_FILE "fonts.conf"
1643 #endif
1644
1645 static FcChar8 *
1646 FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
1647 {
1648     FcChar8    *path;
1649
1650     if (!dir)
1651         dir = (FcChar8 *) "";
1652     path = malloc (strlen ((char *) dir) + 1 + strlen ((char *) file) + 1);
1653     if (!path)
1654         return 0;
1655
1656     strcpy ((char *) path, (const char *) dir);
1657     /* make sure there's a single separator */
1658 #ifdef _WIN32
1659     if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
1660                       path[strlen((char *) path)-1] != '\\')) &&
1661         !(file[0] == '/' ||
1662           file[0] == '\\' ||
1663           (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
1664         strcat ((char *) path, "\\");
1665 #else
1666     if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
1667         strcat ((char *) path, "/");
1668 #endif
1669     strcat ((char *) path, (char *) file);
1670
1671     FcMemAlloc (FC_MEM_STRING, strlen ((char *) path) + 1);
1672     if (access ((char *) path, R_OK) == 0)
1673         return path;
1674     
1675     FcStrFree (path);
1676     return 0;
1677 }
1678
1679 static FcChar8 **
1680 FcConfigGetPath (void)
1681 {
1682     FcChar8    **path;
1683     FcChar8    *env, *e, *colon;
1684     FcChar8    *dir;
1685     int     npath;
1686     int     i;
1687
1688     npath = 2;  /* default dir + null */
1689     env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
1690     if (env)
1691     {
1692         e = env;
1693         npath++;
1694         while (*e)
1695             if (*e++ == FC_SEARCH_PATH_SEPARATOR)
1696                 npath++;
1697     }
1698     path = calloc (npath, sizeof (FcChar8 *));
1699     if (!path)
1700         goto bail0;
1701     i = 0;
1702
1703     if (env)
1704     {
1705         e = env;
1706         while (*e) 
1707         {
1708             colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
1709             if (!colon)
1710                 colon = e + strlen ((char *) e);
1711             path[i] = malloc (colon - e + 1);
1712             if (!path[i])
1713                 goto bail1;
1714             strncpy ((char *) path[i], (const char *) e, colon - e);
1715             path[i][colon - e] = '\0';
1716             if (*colon)
1717                 e = colon + 1;
1718             else
1719                 e = colon;
1720             i++;
1721         }
1722     }
1723     
1724 #ifdef _WIN32
1725         if (fontconfig_path[0] == '\0')
1726         {
1727                 char *p;
1728                 if(!GetModuleFileName(NULL, fontconfig_path, sizeof(fontconfig_path)))
1729                         goto bail1;
1730                 p = strrchr (fontconfig_path, '\\');
1731                 if (p) *p = '\0';
1732                 strcat (fontconfig_path, "\\fonts");
1733         }
1734 #endif
1735     dir = (FcChar8 *) FONTCONFIG_PATH;
1736     path[i] = malloc (strlen ((char *) dir) + 1);
1737     if (!path[i])
1738         goto bail1;
1739     strcpy ((char *) path[i], (const char *) dir);
1740     return path;
1741
1742 bail1:
1743     for (i = 0; path[i]; i++)
1744         free (path[i]);
1745     free (path);
1746 bail0:
1747     return 0;
1748 }
1749
1750 static void
1751 FcConfigFreePath (FcChar8 **path)
1752 {
1753     FcChar8    **p;
1754
1755     for (p = path; *p; p++)
1756         free (*p);
1757     free (path);
1758 }
1759
1760 static FcBool   _FcConfigHomeEnabled = FcTrue;
1761
1762 FcChar8 *
1763 FcConfigHome (void)
1764 {
1765     if (_FcConfigHomeEnabled)
1766     {
1767         char *home = getenv ("HOME");
1768
1769 #ifdef _WIN32
1770         if (home == NULL)
1771             home = getenv ("USERPROFILE");
1772 #endif
1773
1774         return (FcChar8 *) home;
1775     }
1776     return 0;
1777 }
1778
1779 FcBool
1780 FcConfigEnableHome (FcBool enable)
1781 {
1782     FcBool  prev = _FcConfigHomeEnabled;
1783     _FcConfigHomeEnabled = enable;
1784     return prev;
1785 }
1786
1787 FcChar8 *
1788 FcConfigFilename (const FcChar8 *url)
1789 {
1790     FcChar8    *file, *dir, **path, **p;
1791
1792     if (!url || !*url)
1793     {
1794         url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
1795         if (!url)
1796             url = (FcChar8 *) FONTCONFIG_FILE;
1797     }
1798     file = 0;
1799
1800 #ifdef _WIN32
1801     if (isalpha (*url) &&
1802         url[1] == ':' &&
1803         (url[2] == '/' || url[2] == '\\'))
1804         goto absolute_path;
1805 #endif
1806
1807     switch (*url) {
1808     case '~':
1809         dir = FcConfigHome ();
1810         if (dir)
1811             file = FcConfigFileExists (dir, url + 1);
1812         else
1813             file = 0;
1814         break;
1815 #ifdef _WIN32
1816     case '\\':
1817     absolute_path:
1818 #endif
1819     case '/':
1820         file = FcConfigFileExists (0, url);
1821         break;
1822     default:
1823         path = FcConfigGetPath ();
1824         if (!path)
1825             return 0;
1826         for (p = path; *p; p++)
1827         {
1828             file = FcConfigFileExists (*p, url);
1829             if (file)
1830                 break;
1831         }
1832         FcConfigFreePath (path);
1833         break;
1834     }
1835     return file;
1836 }
1837
1838 /*
1839  * Manage the application-specific fonts
1840  */
1841
1842 FcBool
1843 FcConfigAppFontAddFile (FcConfig    *config,
1844                         const FcChar8  *file)
1845 {
1846     FcFontSet   *set;
1847     FcStrSet    *subdirs;
1848     FcStrList   *sublist;
1849     FcChar8     *subdir;
1850
1851     if (!config)
1852     {
1853         config = FcConfigGetCurrent ();
1854         if (!config)
1855             return FcFalse;
1856     }
1857
1858     subdirs = FcStrSetCreate ();
1859     if (!subdirs)
1860         return FcFalse;
1861     
1862     set = FcConfigGetFonts (config, FcSetApplication);
1863     if (!set)
1864     {
1865         set = FcFontSetCreate ();
1866         if (!set)
1867         {
1868             FcStrSetDestroy (subdirs);
1869             return FcFalse;
1870         }
1871         FcConfigSetFonts (config, set, FcSetApplication);
1872     }
1873         
1874     if (!FcFileScanConfig (set, subdirs, config->blanks, file, config))
1875     {
1876         FcStrSetDestroy (subdirs);
1877         return FcFalse;
1878     }
1879     if ((sublist = FcStrListCreate (subdirs)))
1880     {
1881         while ((subdir = FcStrListNext (sublist)))
1882         {
1883             FcConfigAppFontAddDir (config, subdir);
1884         }
1885         FcStrListDone (sublist);
1886     }
1887     FcStrSetDestroy (subdirs);
1888     return FcTrue;
1889 }
1890
1891 FcBool
1892 FcConfigAppFontAddDir (FcConfig     *config,
1893                        const FcChar8   *dir)
1894 {
1895     FcFontSet   *set;
1896     FcStrSet    *dirs;
1897     
1898     if (!config)
1899     {
1900         config = FcConfigGetCurrent ();
1901         if (!config)
1902             return FcFalse;
1903     }
1904
1905     dirs = FcStrSetCreate ();
1906     if (!dirs)
1907         return FcFalse;
1908     
1909     set = FcConfigGetFonts (config, FcSetApplication);
1910     if (!set)
1911     {
1912         set = FcFontSetCreate ();
1913         if (!set)
1914         {
1915             FcStrSetDestroy (dirs);
1916             return FcFalse;
1917         }
1918         FcConfigSetFonts (config, set, FcSetApplication);
1919     }
1920     
1921     FcStrSetAddFilename (dirs, dir);
1922     
1923     if (!FcConfigAddDirList (config, FcSetApplication, dirs))
1924     {
1925         FcStrSetDestroy (dirs);
1926         return FcFalse;
1927     }
1928     FcStrSetDestroy (dirs);
1929     return FcTrue;
1930 }
1931
1932 void
1933 FcConfigAppFontClear (FcConfig      *config)
1934 {
1935     if (!config)
1936     {
1937         config = FcConfigGetCurrent ();
1938         if (!config)
1939             return;
1940     }
1941
1942     FcConfigSetFonts (config, 0, FcSetApplication);
1943 }
1944
1945 /*
1946  * Manage filename-based font source selectors
1947  */
1948
1949 FcBool
1950 FcConfigGlobAdd (FcConfig       *config,
1951                  const FcChar8  *glob,
1952                  FcBool         accept)
1953 {
1954     FcStrSet    *set = accept ? config->acceptGlobs : config->rejectGlobs;
1955
1956     return FcStrSetAdd (set, glob);
1957 }
1958
1959 static FcBool
1960 FcConfigGlobMatch (const FcChar8    *glob,
1961                    const FcChar8    *string)
1962 {
1963     FcChar8     c;
1964
1965     while ((c = *glob++)) 
1966     {
1967         switch (c) {
1968         case '*':
1969             /* short circuit common case */
1970             if (!*glob)
1971                 return FcTrue;
1972             /* short circuit another common case */
1973             if (strchr ((char *) glob, '*') == 0)
1974                 string += strlen ((char *) string) - strlen ((char *) glob);
1975             while (*string)
1976             {
1977                 if (FcConfigGlobMatch (glob, string))
1978                     return FcTrue;
1979                 string++;
1980             }
1981             return FcFalse;
1982         case '?':
1983             if (*string++ == '\0')
1984                 return FcFalse;
1985             break;
1986         default:
1987             if (*string++ != c)
1988                 return FcFalse;
1989             break;
1990         }
1991     }
1992     return *string == '\0';
1993 }
1994
1995 static FcBool
1996 FcConfigGlobsMatch (const FcStrSet      *globs,
1997                     const FcChar8       *string)
1998 {
1999     int i;
2000
2001     for (i = 0; i < globs->num; i++)
2002         if (FcConfigGlobMatch (globs->strs[i], string))
2003             return FcTrue;
2004     return FcFalse;
2005 }
2006
2007 FcBool
2008 FcConfigAcceptFilename (FcConfig        *config,
2009                         const FcChar8   *filename)
2010 {
2011     if (FcConfigGlobsMatch (config->acceptGlobs, filename))
2012         return FcTrue;
2013     if (FcConfigGlobsMatch (config->rejectGlobs, filename))
2014         return FcFalse;
2015     return FcTrue;
2016 }
2017
2018 /*
2019  * Manage font-pattern based font source selectors
2020  */
2021
2022 FcBool
2023 FcConfigPatternsAdd (FcConfig   *config,
2024                      FcPattern  *pattern,
2025                      FcBool     accept)
2026 {
2027     FcFontSet   *set = accept ? config->acceptPatterns : config->rejectPatterns;
2028
2029     return FcFontSetAdd (set, pattern);
2030 }
2031
2032 static FcBool
2033 FcConfigPatternsMatch (const FcFontSet  *patterns,
2034                        const FcPattern  *font)
2035 {
2036     int i;
2037     
2038     for (i = 0; i < patterns->nfont; i++)
2039         if (FcListPatternMatchAny (patterns->fonts[i], font))
2040             return FcTrue;
2041     return FcFalse;
2042 }
2043
2044 FcBool
2045 FcConfigAcceptFont (FcConfig        *config,
2046                     const FcPattern *font)
2047 {
2048     if (FcConfigPatternsMatch (config->acceptPatterns, font))
2049         return FcTrue;
2050     if (FcConfigPatternsMatch (config->rejectPatterns, font))
2051         return FcFalse;
2052     return FcTrue;
2053 }
2054 #define __fccfg__
2055 #include "fcaliastail.h"
2056 #undef __fccfg__