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