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