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