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