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