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