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