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