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