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