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