]> git.wh0rd.org - fontconfig.git/blob - src/fccfg.c
Convert ObjectPtr from a fat structure to a simple index into an id table;
[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 (FcObjectPtrU(left.u.si),
636 FcObjectPtrU(right.u.si)) != 0;
637 break;
638 case FcOpNotContains:
639 ret = FcStrCmpIgnoreCase (FcObjectPtrU(left.u.si),
640 FcObjectPtrU(right.u.si)) == 0;
641 break;
642 default:
643 break;
644 }
645 break;
646 case FcTypeMatrix:
647 switch (op) {
648 case FcOpEqual:
649 case FcOpContains:
650 case FcOpListing:
651 ret = FcMatrixEqual (FcMatrixPtrU(left.u.mi), FcMatrixPtrU(right.u.mi));
652 break;
653 case FcOpNotEqual:
654 case FcOpNotContains:
655 ret = !FcMatrixEqual (FcMatrixPtrU(left.u.mi), FcMatrixPtrU(right.u.mi));
656 break;
657 default:
658 break;
659 }
660 break;
661 case FcTypeCharSet:
662 switch (op) {
663 case FcOpContains:
664 case FcOpListing:
665 /* left contains right if right is a subset of left */
666 ret = FcCharSetIsSubset (FcCharSetPtrU(right.u.ci), FcCharSetPtrU(left.u.ci));
667 break;
668 case FcOpNotContains:
669 /* left contains right if right is a subset of left */
670 ret = !FcCharSetIsSubset (FcCharSetPtrU(right.u.ci), FcCharSetPtrU(left.u.ci));
671 break;
672 case FcOpEqual:
673 ret = FcCharSetEqual (FcCharSetPtrU(left.u.ci), FcCharSetPtrU(right.u.ci));
674 break;
675 case FcOpNotEqual:
676 ret = !FcCharSetEqual (FcCharSetPtrU(left.u.ci), FcCharSetPtrU(right.u.ci));
677 break;
678 default:
679 break;
680 }
681 break;
682 case FcTypeLangSet:
683 switch (op) {
684 case FcOpContains:
685 case FcOpListing:
686 ret = FcLangSetContains (FcLangSetPtrU(left.u.li), FcLangSetPtrU(right.u.li));
687 break;
688 case FcOpNotContains:
689 ret = !FcLangSetContains (FcLangSetPtrU(left.u.li), FcLangSetPtrU(right.u.li));
690 break;
691 case FcOpEqual:
692 ret = FcLangSetEqual (FcLangSetPtrU(left.u.li), FcLangSetPtrU(right.u.li));
693 break;
694 case FcOpNotEqual:
695 ret = !FcLangSetEqual (FcLangSetPtrU(left.u.li), FcLangSetPtrU(right.u.li));
696 break;
697 default:
698 break;
699 }
700 break;
701 case FcTypeVoid:
702 switch (op) {
703 case FcOpEqual:
704 case FcOpContains:
705 case FcOpListing:
706 ret = FcTrue;
707 break;
708 default:
709 break;
710 }
711 break;
712 case FcTypeFTFace:
713 switch (op) {
714 case FcOpEqual:
715 case FcOpContains:
716 case FcOpListing:
717 ret = left.u.f == right.u.f;
718 break;
719 case FcOpNotEqual:
720 case FcOpNotContains:
721 ret = left.u.f != right.u.f;
722 break;
723 default:
724 break;
725 }
726 break;
727 }
728 }
729 else
730 {
731 if (op == FcOpNotEqual || op == FcOpNotContains)
732 ret = FcTrue;
733 }
734 return ret;
735 }
736
737
738 #define _FcDoubleFloor(d) ((int) (d))
739 #define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
740 #define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
741 #define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
742 #define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5)
743 #define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
744
745 static FcValue
746 FcConfigEvaluate (FcPattern *p, FcExpr *e)
747 {
748 FcValue v, vl, vr;
749 FcResult r;
750 FcMatrix *m;
751
752 switch (e->op) {
753 case FcOpInteger:
754 v.type = FcTypeInteger;
755 v.u.i = e->u.ival;
756 break;
757 case FcOpDouble:
758 v.type = FcTypeDouble;
759 v.u.d = e->u.dval;
760 break;
761 case FcOpString:
762 v.type = FcTypeString;
763 v.u.si = FcObjectStaticName(e->u.sval);
764 v = FcValueSave (v);
765 break;
766 case FcOpMatrix:
767 v.type = FcTypeMatrix;
768 v.u.mi = FcMatrixPtrCreateDynamic(e->u.mval);
769 v = FcValueSave (v);
770 break;
771 case FcOpCharSet:
772 v.type = FcTypeCharSet;
773 v.u.ci = FcCharSetPtrCreateDynamic(e->u.cval);
774 v = FcValueSave (v);
775 break;
776 case FcOpBool:
777 v.type = FcTypeBool;
778 v.u.b = e->u.bval;
779 break;
780 case FcOpField:
781 r = FcPatternGet (p, e->u.field, 0, &v);
782 if (r != FcResultMatch)
783 v.type = FcTypeVoid;
784 break;
785 case FcOpConst:
786 if (FcNameConstant (e->u.constant, &v.u.i))
787 v.type = FcTypeInteger;
788 else
789 v.type = FcTypeVoid;
790 break;
791 case FcOpQuest:
792 vl = FcConfigEvaluate (p, e->u.tree.left);
793 if (vl.type == FcTypeBool)
794 {
795 if (vl.u.b)
796 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
797 else
798 v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
799 }
800 else
801 v.type = FcTypeVoid;
802 FcValueDestroy (vl);
803 break;
804 case FcOpEqual:
805 case FcOpNotEqual:
806 case FcOpLess:
807 case FcOpLessEqual:
808 case FcOpMore:
809 case FcOpMoreEqual:
810 case FcOpContains:
811 case FcOpNotContains:
812 case FcOpListing:
813 vl = FcConfigEvaluate (p, e->u.tree.left);
814 vr = FcConfigEvaluate (p, e->u.tree.right);
815 v.type = FcTypeBool;
816 v.u.b = FcConfigCompareValue (vl, e->op, vr);
817 FcValueDestroy (vl);
818 FcValueDestroy (vr);
819 break;
820 case FcOpOr:
821 case FcOpAnd:
822 case FcOpPlus:
823 case FcOpMinus:
824 case FcOpTimes:
825 case FcOpDivide:
826 vl = FcConfigEvaluate (p, e->u.tree.left);
827 vr = FcConfigEvaluate (p, e->u.tree.right);
828 vl = FcConfigPromote (vl, vr);
829 vr = FcConfigPromote (vr, vl);
830 if (vl.type == vr.type)
831 {
832 switch (vl.type) {
833 case FcTypeDouble:
834 switch (e->op) {
835 case FcOpPlus:
836 v.type = FcTypeDouble;
837 v.u.d = vl.u.d + vr.u.d;
838 break;
839 case FcOpMinus:
840 v.type = FcTypeDouble;
841 v.u.d = vl.u.d - vr.u.d;
842 break;
843 case FcOpTimes:
844 v.type = FcTypeDouble;
845 v.u.d = vl.u.d * vr.u.d;
846 break;
847 case FcOpDivide:
848 v.type = FcTypeDouble;
849 v.u.d = vl.u.d / vr.u.d;
850 break;
851 default:
852 v.type = FcTypeVoid;
853 break;
854 }
855 if (v.type == FcTypeDouble &&
856 v.u.d == (double) (int) v.u.d)
857 {
858 v.type = FcTypeInteger;
859 v.u.i = (int) v.u.d;
860 }
861 break;
862 case FcTypeBool:
863 switch (e->op) {
864 case FcOpOr:
865 v.type = FcTypeBool;
866 v.u.b = vl.u.b || vr.u.b;
867 break;
868 case FcOpAnd:
869 v.type = FcTypeBool;
870 v.u.b = vl.u.b && vr.u.b;
871 break;
872 default:
873 v.type = FcTypeVoid;
874 break;
875 }
876 break;
877 case FcTypeString:
878 switch (e->op) {
879 case FcOpPlus:
880 v.type = FcTypeString;
881 v.u.si = FcObjectStaticName
882 (FcStrPlus (FcObjectPtrU(vl.u.si),
883 FcObjectPtrU(vr.u.si)));
884
885 if (!FcObjectPtrU(v.u.si))
886 v.type = FcTypeVoid;
887 break;
888 default:
889 v.type = FcTypeVoid;
890 break;
891 }
892 break;
893 case FcTypeMatrix:
894 switch (e->op) {
895 case FcOpTimes:
896 v.type = FcTypeMatrix;
897 m = malloc (sizeof (FcMatrix));
898 if (m)
899 {
900 FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
901 FcMatrixMultiply (m, FcMatrixPtrU(vl.u.mi),
902 FcMatrixPtrU(vr.u.mi));
903 v.u.mi = FcMatrixPtrCreateDynamic(m);
904 }
905 else
906 {
907 v.type = FcTypeVoid;
908 }
909 break;
910 default:
911 v.type = FcTypeVoid;
912 break;
913 }
914 break;
915 default:
916 v.type = FcTypeVoid;
917 break;
918 }
919 }
920 else
921 v.type = FcTypeVoid;
922 FcValueDestroy (vl);
923 FcValueDestroy (vr);
924 break;
925 case FcOpNot:
926 vl = FcConfigEvaluate (p, e->u.tree.left);
927 switch (vl.type) {
928 case FcTypeBool:
929 v.type = FcTypeBool;
930 v.u.b = !vl.u.b;
931 break;
932 default:
933 v.type = FcTypeVoid;
934 break;
935 }
936 FcValueDestroy (vl);
937 break;
938 case FcOpFloor:
939 vl = FcConfigEvaluate (p, e->u.tree.left);
940 switch (vl.type) {
941 case FcTypeInteger:
942 v = vl;
943 break;
944 case FcTypeDouble:
945 v.type = FcTypeInteger;
946 v.u.i = FcDoubleFloor (vl.u.d);
947 break;
948 default:
949 v.type = FcTypeVoid;
950 break;
951 }
952 FcValueDestroy (vl);
953 break;
954 case FcOpCeil:
955 vl = FcConfigEvaluate (p, e->u.tree.left);
956 switch (vl.type) {
957 case FcTypeInteger:
958 v = vl;
959 break;
960 case FcTypeDouble:
961 v.type = FcTypeInteger;
962 v.u.i = FcDoubleCeil (vl.u.d);
963 break;
964 default:
965 v.type = FcTypeVoid;
966 break;
967 }
968 FcValueDestroy (vl);
969 break;
970 case FcOpRound:
971 vl = FcConfigEvaluate (p, e->u.tree.left);
972 switch (vl.type) {
973 case FcTypeInteger:
974 v = vl;
975 break;
976 case FcTypeDouble:
977 v.type = FcTypeInteger;
978 v.u.i = FcDoubleRound (vl.u.d);
979 break;
980 default:
981 v.type = FcTypeVoid;
982 break;
983 }
984 FcValueDestroy (vl);
985 break;
986 case FcOpTrunc:
987 vl = FcConfigEvaluate (p, e->u.tree.left);
988 switch (vl.type) {
989 case FcTypeInteger:
990 v = vl;
991 break;
992 case FcTypeDouble:
993 v.type = FcTypeInteger;
994 v.u.i = FcDoubleTrunc (vl.u.d);
995 break;
996 default:
997 v.type = FcTypeVoid;
998 break;
999 }
1000 FcValueDestroy (vl);
1001 break;
1002 default:
1003 v.type = FcTypeVoid;
1004 break;
1005 }
1006 return v;
1007 }
1008
1009 static FcValueList *
1010 FcConfigMatchValueList (FcPattern *p,
1011 FcTest *t,
1012 FcValueList *values)
1013 {
1014 FcValueList *ret = 0;
1015 FcExpr *e = t->expr;
1016 FcValue value;
1017 FcValueList *v;
1018
1019 while (e)
1020 {
1021 /* Compute the value of the match expression */
1022 if (e->op == FcOpComma)
1023 {
1024 value = FcConfigEvaluate (p, e->u.tree.left);
1025 e = e->u.tree.right;
1026 }
1027 else
1028 {
1029 value = FcConfigEvaluate (p, e);
1030 e = 0;
1031 }
1032
1033 for (v = values; v; v = FcValueListPtrU(v->next))
1034 {
1035 /* Compare the pattern value to the match expression value */
1036 if (FcConfigCompareValue (v->value, t->op, value))
1037 {
1038 if (!ret)
1039 ret = v;
1040 }
1041 else
1042 {
1043 if (t->qual == FcQualAll)
1044 {
1045 ret = 0;
1046 break;
1047 }
1048 }
1049 }
1050 FcValueDestroy (value);
1051 }
1052 return ret;
1053 }
1054
1055 static FcValueList *
1056 FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding)
1057 {
1058 FcValueList *l;
1059 FcValueListPtr lp;
1060
1061 if (!e)
1062 return 0;
1063 l = (FcValueList *) malloc (sizeof (FcValueList));
1064 if (!l)
1065 return 0;
1066 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
1067 if (e->op == FcOpComma)
1068 {
1069 l->value = FcConfigEvaluate (p, e->u.tree.left);
1070 l->next = FcValueListPtrCreateDynamic(FcConfigValues (p, e->u.tree.right, binding));
1071 }
1072 else
1073 {
1074 l->value = FcConfigEvaluate (p, e);
1075 l->next = FcValueListPtrCreateDynamic(0);
1076 }
1077 l->binding = binding;
1078 lp = FcValueListPtrCreateDynamic(l);
1079 while (FcValueListPtrU(lp) && FcValueListPtrU(lp)->value.type == FcTypeVoid)
1080 {
1081 FcValueListPtr next = FcValueListPtrU(lp)->next;
1082
1083 if (lp.storage == FcStorageDynamic)
1084 {
1085 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
1086 free (l);
1087 }
1088 lp = next;
1089 }
1090 return l;
1091 }
1092
1093 static FcBool
1094 FcConfigAdd (FcValueListPtr *head,
1095 FcValueList *position,
1096 FcBool append,
1097 FcValueList *new)
1098 {
1099 FcValueListPtr *prev, last, v;
1100 FcValueBinding sameBinding;
1101
1102 if (position)
1103 sameBinding = position->binding;
1104 else
1105 sameBinding = FcValueBindingWeak;
1106 for (v = FcValueListPtrCreateDynamic(new); FcValueListPtrU(v);
1107 v = FcValueListPtrU(v)->next)
1108 if (FcValueListPtrU(v)->binding == FcValueBindingSame)
1109 FcValueListPtrU(v)->binding = sameBinding;
1110 if (append)
1111 {
1112 if (position)
1113 prev = &position->next;
1114 else
1115 for (prev = head; FcValueListPtrU(*prev);
1116 prev = &(FcValueListPtrU(*prev)->next))
1117 ;
1118 }
1119 else
1120 {
1121 if (position)
1122 {
1123 for (prev = head; FcValueListPtrU(*prev);
1124 prev = &(FcValueListPtrU(*prev)->next))
1125 {
1126 if (FcValueListPtrU(*prev) == position)
1127 break;
1128 }
1129 }
1130 else
1131 prev = head;
1132
1133 if (FcDebug () & FC_DBG_EDIT)
1134 {
1135 if (!FcValueListPtrU(*prev))
1136 printf ("position not on list\n");
1137 }
1138 }
1139
1140 if (FcDebug () & FC_DBG_EDIT)
1141 {
1142 printf ("%s list before ", append ? "Append" : "Prepend");
1143 FcValueListPrint (*head);
1144 printf ("\n");
1145 }
1146
1147 if (new)
1148 {
1149 last = FcValueListPtrCreateDynamic(new);
1150 while (FcValueListPtrU(FcValueListPtrU(last)->next))
1151 last = FcValueListPtrU(last)->next;
1152
1153 FcValueListPtrU(last)->next = *prev;
1154 *prev = FcValueListPtrCreateDynamic(new);
1155 }
1156
1157 if (FcDebug () & FC_DBG_EDIT)
1158 {
1159 printf ("%s list after ", append ? "Append" : "Prepend");
1160 FcValueListPrint (*head);
1161 printf ("\n");
1162 }
1163
1164 return FcTrue;
1165 }
1166
1167 static void
1168 FcConfigDel (FcValueListPtr *head,
1169 FcValueList *position)
1170 {
1171 FcValueListPtr *prev;
1172
1173 for (prev = head; FcValueListPtrU(*prev);
1174 prev = &(FcValueListPtrU(*prev)->next))
1175 {
1176 if (FcValueListPtrU(*prev) == position)
1177 {
1178 *prev = position->next;
1179 position->next = FcValueListPtrCreateDynamic(0);
1180 FcValueListDestroy (FcValueListPtrCreateDynamic(position));
1181 break;
1182 }
1183 }
1184 }
1185
1186 static void
1187 FcConfigPatternAdd (FcPattern *p,
1188 const char *object,
1189 FcValueList *list,
1190 FcBool append)
1191 {
1192 if (list)
1193 {
1194 FcPatternElt *e = FcPatternInsertElt (p, object);
1195
1196 if (!e)
1197 return;
1198 FcConfigAdd (&e->values, 0, append, list);
1199 }
1200 }
1201
1202 /*
1203 * Delete all values associated with a field
1204 */
1205 static void
1206 FcConfigPatternDel (FcPattern *p,
1207 const char *object)
1208 {
1209 FcPatternElt *e = FcPatternFindElt (p, object);
1210 if (!e)
1211 return;
1212 while (FcValueListPtrU(e->values))
1213 FcConfigDel (&e->values, FcValueListPtrU(e->values));
1214 }
1215
1216 static void
1217 FcConfigPatternCanon (FcPattern *p,
1218 const char *object)
1219 {
1220 FcPatternElt *e = FcPatternFindElt (p, object);
1221 if (!e)
1222 return;
1223 if (!FcValueListPtrU(e->values))
1224 FcPatternDel (p, object);
1225 }
1226
1227 FcBool
1228 FcConfigSubstituteWithPat (FcConfig *config,
1229 FcPattern *p,
1230 FcPattern *p_pat,
1231 FcMatchKind kind)
1232 {
1233 FcSubst *s;
1234 FcSubState *st;
1235 int i;
1236 FcTest *t;
1237 FcEdit *e;
1238 FcValueList *l;
1239 FcPattern *m;
1240
1241 if (!config)
1242 {
1243 config = FcConfigGetCurrent ();
1244 if (!config)
1245 return FcFalse;
1246 }
1247
1248 st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
1249 if (!st && config->maxObjects)
1250 return FcFalse;
1251 FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1252
1253 if (FcDebug () & FC_DBG_EDIT)
1254 {
1255 printf ("FcConfigSubstitute ");
1256 FcPatternPrint (p);
1257 }
1258 if (kind == FcMatchPattern)
1259 s = config->substPattern;
1260 else
1261 s = config->substFont;
1262 for (; s; s = s->next)
1263 {
1264 /*
1265 * Check the tests to see if
1266 * they all match the pattern
1267 */
1268 for (t = s->test, i = 0; t; t = t->next, i++)
1269 {
1270 if (FcDebug () & FC_DBG_EDIT)
1271 {
1272 printf ("FcConfigSubstitute test ");
1273 FcTestPrint (t);
1274 }
1275 st[i].elt = 0;
1276 if (kind == FcMatchFont && t->kind == FcMatchPattern)
1277 m = p_pat;
1278 else
1279 m = p;
1280 if (m)
1281 st[i].elt = FcPatternFindElt (m, t->field);
1282 else
1283 st[i].elt = 0;
1284 /*
1285 * If there's no such field in the font,
1286 * then FcQualAll matches while FcQualAny does not
1287 */
1288 if (!st[i].elt)
1289 {
1290 if (t->qual == FcQualAll)
1291 {
1292 st[i].value = 0;
1293 continue;
1294 }
1295 else
1296 break;
1297 }
1298 /*
1299 * Check to see if there is a match, mark the location
1300 * to apply match-relative edits
1301 */
1302 st[i].value = FcConfigMatchValueList (m, t, FcValueListPtrU(st[i].elt->values));
1303 if (!st[i].value)
1304 break;
1305 if (t->qual == FcQualFirst && st[i].value != FcValueListPtrU(st[i].elt->values))
1306 break;
1307 if (t->qual == FcQualNotFirst && st[i].value == FcValueListPtrU(st[i].elt->values))
1308 break;
1309 }
1310 if (t)
1311 {
1312 if (FcDebug () & FC_DBG_EDIT)
1313 printf ("No match\n");
1314 continue;
1315 }
1316 if (FcDebug () & FC_DBG_EDIT)
1317 {
1318 printf ("Substitute ");
1319 FcSubstPrint (s);
1320 }
1321 for (e = s->edit; e; e = e->next)
1322 {
1323 /*
1324 * Evaluate the list of expressions
1325 */
1326 l = FcConfigValues (p, e->expr, e->binding);
1327 /*
1328 * Locate any test associated with this field, skipping
1329 * tests associated with the pattern when substituting in
1330 * the font
1331 */
1332 for (t = s->test, i = 0; t; t = t->next, i++)
1333 {
1334 if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
1335 !FcStrCmpIgnoreCase ((FcChar8 *) t->field,
1336 (FcChar8 *) e->field))
1337 {
1338 /*
1339 * KLUDGE - the pattern may have been reallocated or
1340 * things may have been inserted or deleted above
1341 * this element by other edits. Go back and find
1342 * the element again
1343 */
1344 if (e != s->edit && st[i].elt)
1345 st[i].elt = FcPatternFindElt (p, t->field);
1346 if (!st[i].elt)
1347 t = 0;
1348 break;
1349 }
1350 }
1351 switch (e->op) {
1352 case FcOpAssign:
1353 /*
1354 * If there was a test, then replace the matched
1355 * value with the new list of values
1356 */
1357 if (t)
1358 {
1359 FcValueList *thisValue = st[i].value;
1360 FcValueList *nextValue = thisValue ? FcValueListPtrU(thisValue->next) : 0;
1361
1362 /*
1363 * Append the new list of values after the current value
1364 */
1365 FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
1366 /*
1367 * Delete the marked value
1368 */
1369 FcConfigDel (&st[i].elt->values, thisValue);
1370 /*
1371 * Adjust any pointers into the value list to ensure
1372 * future edits occur at the same place
1373 */
1374 for (t = s->test, i = 0; t; t = t->next, i++)
1375 {
1376 if (st[i].value == thisValue)
1377 st[i].value = nextValue;
1378 }
1379 break;
1380 }
1381 /* fall through ... */
1382 case FcOpAssignReplace:
1383 /*
1384 * Delete all of the values and insert
1385 * the new set
1386 */
1387 FcConfigPatternDel (p, e->field);
1388 FcConfigPatternAdd (p, e->field, l, FcTrue);
1389 /*
1390 * Adjust any pointers into the value list as they no
1391 * longer point to anything valid
1392 */
1393 if (t)
1394 {
1395 FcPatternElt *thisElt = st[i].elt;
1396 for (t = s->test, i = 0; t; t = t->next, i++)
1397 {
1398 if (st[i].elt == thisElt)
1399 st[i].value = 0;
1400 }
1401 }
1402 break;
1403 case FcOpPrepend:
1404 if (t)
1405 {
1406 FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
1407 break;
1408 }
1409 /* fall through ... */
1410 case FcOpPrependFirst:
1411 FcConfigPatternAdd (p, e->field, l, FcFalse);
1412 break;
1413 case FcOpAppend:
1414 if (t)
1415 {
1416 FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
1417 break;
1418 }
1419 /* fall through ... */
1420 case FcOpAppendLast:
1421 FcConfigPatternAdd (p, e->field, l, FcTrue);
1422 break;
1423 default:
1424 break;
1425 }
1426 }
1427 /*
1428 * Now go through the pattern and eliminate
1429 * any properties without data
1430 */
1431 for (e = s->edit; e; e = e->next)
1432 FcConfigPatternCanon (p, e->field);
1433
1434 if (FcDebug () & FC_DBG_EDIT)
1435 {
1436 printf ("FcConfigSubstitute edit");
1437 FcPatternPrint (p);
1438 }
1439 }
1440 FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1441 free (st);
1442 if (FcDebug () & FC_DBG_EDIT)
1443 {
1444 printf ("FcConfigSubstitute done");
1445 FcPatternPrint (p);
1446 }
1447 return FcTrue;
1448 }
1449
1450 FcBool
1451 FcConfigSubstitute (FcConfig *config,
1452 FcPattern *p,
1453 FcMatchKind kind)
1454 {
1455 return FcConfigSubstituteWithPat (config, p, 0, kind);
1456 }
1457
1458 #if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT))
1459
1460 static FcChar8 fontconfig_path[1000] = "";
1461
1462 BOOL WINAPI
1463 DllMain (HINSTANCE hinstDLL,
1464 DWORD fdwReason,
1465 LPVOID lpvReserved)
1466 {
1467 FcChar8 *p;
1468
1469 switch (fdwReason) {
1470 case DLL_PROCESS_ATTACH:
1471 if (!GetModuleFileName ((HMODULE) hinstDLL, fontconfig_path,
1472 sizeof (fontconfig_path)))
1473 break;
1474
1475 /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
1476 * assume it's a Unix-style installation tree, and use
1477 * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
1478 * folder where the DLL is as FONTCONFIG_PATH.
1479 */
1480 p = strrchr (fontconfig_path, '\\');
1481 if (p)
1482 {
1483 *p = '\0';
1484 p = strrchr (fontconfig_path, '\\');
1485 if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 ||
1486 FcStrCmpIgnoreCase (p + 1, "lib") == 0))
1487 *p = '\0';
1488 strcat (fontconfig_path, "\\etc\\fonts");
1489 }
1490 else
1491 fontconfig_path[0] = '\0';
1492
1493 break;
1494 }
1495
1496 return TRUE;
1497 }
1498
1499 #undef FONTCONFIG_PATH
1500 #define FONTCONFIG_PATH fontconfig_path
1501
1502 #else /* !(_WIN32 && PIC) */
1503
1504 #endif /* !(_WIN32 && PIC) */
1505
1506 #ifndef FONTCONFIG_FILE
1507 #define FONTCONFIG_FILE "fonts.conf"
1508 #endif
1509
1510 static FcChar8 *
1511 FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
1512 {
1513 FcChar8 *path;
1514
1515 if (!dir)
1516 dir = (FcChar8 *) "";
1517 path = malloc (strlen ((char *) dir) + 1 + strlen ((char *) file) + 1);
1518 if (!path)
1519 return 0;
1520
1521 strcpy ((char *) path, (const char *) dir);
1522 /* make sure there's a single separator */
1523 #ifdef _WIN32
1524 if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
1525 path[strlen((char *) path)-1] != '\\')) &&
1526 !(file[0] == '/' ||
1527 file[0] == '\\' ||
1528 (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
1529 strcat ((char *) path, "\\");
1530 #else
1531 if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
1532 strcat ((char *) path, "/");
1533 #endif
1534 strcat ((char *) path, (char *) file);
1535
1536 FcMemAlloc (FC_MEM_STRING, strlen ((char *) path) + 1);
1537 if (access ((char *) path, R_OK) == 0)
1538 return path;
1539
1540 FcStrFree (path);
1541 return 0;
1542 }
1543
1544 static FcChar8 **
1545 FcConfigGetPath (void)
1546 {
1547 FcChar8 **path;
1548 FcChar8 *env, *e, *colon;
1549 FcChar8 *dir;
1550 int npath;
1551 int i;
1552
1553 npath = 2; /* default dir + null */
1554 env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
1555 if (env)
1556 {
1557 e = env;
1558 npath++;
1559 while (*e)
1560 if (*e++ == FC_SEARCH_PATH_SEPARATOR)
1561 npath++;
1562 }
1563 path = calloc (npath, sizeof (FcChar8 *));
1564 if (!path)
1565 goto bail0;
1566 i = 0;
1567
1568 if (env)
1569 {
1570 e = env;
1571 while (*e)
1572 {
1573 colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
1574 if (!colon)
1575 colon = e + strlen ((char *) e);
1576 path[i] = malloc (colon - e + 1);
1577 if (!path[i])
1578 goto bail1;
1579 strncpy ((char *) path[i], (const char *) e, colon - e);
1580 path[i][colon - e] = '\0';
1581 if (*colon)
1582 e = colon + 1;
1583 else
1584 e = colon;
1585 i++;
1586 }
1587 }
1588
1589 dir = (FcChar8 *) FONTCONFIG_PATH;
1590 path[i] = malloc (strlen ((char *) dir) + 1);
1591 if (!path[i])
1592 goto bail1;
1593 strcpy ((char *) path[i], (const char *) dir);
1594 return path;
1595
1596 bail1:
1597 for (i = 0; path[i]; i++)
1598 free (path[i]);
1599 free (path);
1600 bail0:
1601 return 0;
1602 }
1603
1604 static void
1605 FcConfigFreePath (FcChar8 **path)
1606 {
1607 FcChar8 **p;
1608
1609 for (p = path; *p; p++)
1610 free (*p);
1611 free (path);
1612 }
1613
1614 static FcBool _FcConfigHomeEnabled = FcTrue;
1615
1616 FcChar8 *
1617 FcConfigHome (void)
1618 {
1619 if (_FcConfigHomeEnabled)
1620 {
1621 char *home = getenv ("HOME");
1622
1623 #ifdef _WIN32
1624 if (home == NULL)
1625 home = getenv ("USERPROFILE");
1626 #endif
1627
1628 return home;
1629 }
1630 return 0;
1631 }
1632
1633 FcBool
1634 FcConfigEnableHome (FcBool enable)
1635 {
1636 FcBool prev = _FcConfigHomeEnabled;
1637 _FcConfigHomeEnabled = enable;
1638 return prev;
1639 }
1640
1641 FcChar8 *
1642 FcConfigFilename (const FcChar8 *url)
1643 {
1644 FcChar8 *file, *dir, **path, **p;
1645
1646 if (!url || !*url)
1647 {
1648 url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
1649 if (!url)
1650 url = (FcChar8 *) FONTCONFIG_FILE;
1651 }
1652 file = 0;
1653
1654 #ifdef _WIN32
1655 if (isalpha (*url) &&
1656 url[1] == ':' &&
1657 (url[2] == '/' || url[2] == '\\'))
1658 goto absolute_path;
1659 #endif
1660
1661 switch (*url) {
1662 case '~':
1663 dir = FcConfigHome ();
1664 if (dir)
1665 file = FcConfigFileExists (dir, url + 1);
1666 else
1667 file = 0;
1668 break;
1669 #ifdef _WIN32
1670 case '\\':
1671 absolute_path:
1672 #endif
1673 case '/':
1674 file = FcConfigFileExists (0, url);
1675 break;
1676 default:
1677 path = FcConfigGetPath ();
1678 if (!path)
1679 return 0;
1680 for (p = path; *p; p++)
1681 {
1682 file = FcConfigFileExists (*p, url);
1683 if (file)
1684 break;
1685 }
1686 FcConfigFreePath (path);
1687 break;
1688 }
1689 return file;
1690 }
1691
1692 /*
1693 * Manage the application-specific fonts
1694 */
1695
1696 FcBool
1697 FcConfigAppFontAddFile (FcConfig *config,
1698 const FcChar8 *file)
1699 {
1700 FcFontSet *set;
1701 FcStrSet *subdirs;
1702 FcStrList *sublist;
1703 FcChar8 *subdir;
1704
1705 if (!config)
1706 {
1707 config = FcConfigGetCurrent ();
1708 if (!config)
1709 return FcFalse;
1710 }
1711
1712 subdirs = FcStrSetCreate ();
1713 if (!subdirs)
1714 return FcFalse;
1715
1716 set = FcConfigGetFonts (config, FcSetApplication);
1717 if (!set)
1718 {
1719 set = FcFontSetCreate ();
1720 if (!set)
1721 {
1722 FcStrSetDestroy (subdirs);
1723 return FcFalse;
1724 }
1725 FcConfigSetFonts (config, set, FcSetApplication);
1726 }
1727
1728 if (!FcFileScanConfig (set, subdirs, 0, config->blanks, file, FcFalse, config))
1729 {
1730 FcStrSetDestroy (subdirs);
1731 return FcFalse;
1732 }
1733 if ((sublist = FcStrListCreate (subdirs)))
1734 {
1735 while ((subdir = FcStrListNext (sublist)))
1736 {
1737 FcConfigAppFontAddDir (config, subdir);
1738 }
1739 FcStrListDone (sublist);
1740 }
1741 return FcTrue;
1742 }
1743
1744 FcBool
1745 FcConfigAppFontAddDir (FcConfig *config,
1746 const FcChar8 *dir)
1747 {
1748 FcFontSet *set;
1749 FcStrSet *subdirs;
1750 FcStrList *sublist;
1751 FcChar8 *subdir;
1752
1753 if (!config)
1754 {
1755 config = FcConfigGetCurrent ();
1756 if (!config)
1757 return FcFalse;
1758 }
1759 subdirs = FcStrSetCreate ();
1760 if (!subdirs)
1761 return FcFalse;
1762
1763 set = FcConfigGetFonts (config, FcSetApplication);
1764 if (!set)
1765 {
1766 set = FcFontSetCreate ();
1767 if (!set)
1768 {
1769 FcStrSetDestroy (subdirs);
1770 return FcFalse;
1771 }
1772 FcConfigSetFonts (config, set, FcSetApplication);
1773 }
1774
1775 if (!FcDirScanConfig (set, subdirs, 0, config->blanks, dir, FcFalse, config))
1776 {
1777 FcStrSetDestroy (subdirs);
1778 return FcFalse;
1779 }
1780 if ((sublist = FcStrListCreate (subdirs)))
1781 {
1782 while ((subdir = FcStrListNext (sublist)))
1783 {
1784 FcConfigAppFontAddDir (config, subdir);
1785 }
1786 FcStrListDone (sublist);
1787 }
1788 return FcTrue;
1789 }
1790
1791 void
1792 FcConfigAppFontClear (FcConfig *config)
1793 {
1794 if (!config)
1795 {
1796 config = FcConfigGetCurrent ();
1797 if (!config)
1798 return;
1799 }
1800
1801 FcConfigSetFonts (config, 0, FcSetApplication);
1802 }
1803
1804 /*
1805 * Manage filename-based font source selectors
1806 */
1807
1808 FcBool
1809 FcConfigGlobAdd (FcConfig *config,
1810 const FcChar8 *glob,
1811 FcBool accept)
1812 {
1813 FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs;
1814
1815 return FcStrSetAdd (set, glob);
1816 }
1817
1818 static FcBool
1819 FcConfigGlobMatch (const FcChar8 *glob,
1820 const FcChar8 *string)
1821 {
1822 FcChar8 c;
1823
1824 while ((c = *glob++))
1825 {
1826 switch (c) {
1827 case '*':
1828 /* short circuit common case */
1829 if (!*glob)
1830 return FcTrue;
1831 /* short circuit another common case */
1832 if (strchr ((char *) glob, '*') == 0)
1833 string += strlen ((char *) string) - strlen ((char *) glob);
1834 while (*string)
1835 {
1836 if (FcConfigGlobMatch (glob, string))
1837 return FcTrue;
1838 string++;
1839 }
1840 return FcFalse;
1841 case '?':
1842 if (*string++ == '\0')
1843 return FcFalse;
1844 break;
1845 default:
1846 if (*string++ != c)
1847 return FcFalse;
1848 break;
1849 }
1850 }
1851 return *string == '\0';
1852 }
1853
1854 static FcBool
1855 FcConfigGlobsMatch (const FcStrSet *globs,
1856 const FcChar8 *string)
1857 {
1858 int i;
1859
1860 for (i = 0; i < globs->num; i++)
1861 if (FcConfigGlobMatch (FcStrSetGet(globs, i), string))
1862 return FcTrue;
1863 return FcFalse;
1864 }
1865
1866 FcBool
1867 FcConfigAcceptFilename (FcConfig *config,
1868 const FcChar8 *filename)
1869 {
1870 if (FcConfigGlobsMatch (config->acceptGlobs, filename))
1871 return FcTrue;
1872 if (FcConfigGlobsMatch (config->rejectGlobs, filename))
1873 return FcFalse;
1874 return FcTrue;
1875 }
1876
1877 /*
1878 * Manage font-pattern based font source selectors
1879 */
1880
1881 FcBool
1882 FcConfigPatternsAdd (FcConfig *config,
1883 FcPattern *pattern,
1884 FcBool accept)
1885 {
1886 FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns;
1887
1888 return FcFontSetAdd (set, pattern);
1889 }
1890
1891 static FcBool
1892 FcConfigPatternsMatch (const FcFontSet *patterns,
1893 const FcPattern *font)
1894 {
1895 int i;
1896
1897 for (i = 0; i < patterns->nfont; i++)
1898 if (FcListPatternMatchAny (patterns->fonts[i], font))
1899 return FcTrue;
1900 return FcFalse;
1901 }
1902
1903 FcBool
1904 FcConfigAcceptFont (FcConfig *config,
1905 const FcPattern *font)
1906 {
1907 if (FcConfigPatternsMatch (config->acceptPatterns, font))
1908 return FcTrue;
1909 if (FcConfigPatternsMatch (config->rejectPatterns, font))
1910 return FcFalse;
1911 return FcTrue;
1912 }