]> git.wh0rd.org - fontconfig.git/blame - src/fccfg.c
fc-cache: add a --root option
[fontconfig.git] / src / fccfg.c
CommitLineData
24330d27 1/*
317b8492 2 * fontconfig/src/fccfg.c
24330d27 3 *
46b51147 4 * Copyright © 2000 Keith Packard
24330d27
KP
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
5aaf466d 10 * documentation, and that the name of the author(s) not be used in
24330d27 11 * advertising or publicity pertaining to distribution of the software without
5aaf466d 12 * specific, written prior permission. The authors make no
24330d27
KP
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
15 *
3074a73b 16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
24330d27 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
3074a73b 18 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
24330d27
KP
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
f045376c 25#include "fcint.h"
f468f568
PL
26#include <dirent.h>
27#include <sys/types.h>
24330d27 28
92af858f 29#if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT))
daeed6e0
TL
30#define STRICT
31#include <windows.h>
32#undef STRICT
33#endif
34
e5206dbc
TL
35#if defined (_WIN32) && !defined (R_OK)
36#define R_OK 4
37#endif
38
6e9fc5de 39FcConfig *_fcConfig;
24330d27
KP
40
41FcConfig *
42FcConfigCreate (void)
43{
44 FcSetName set;
45 FcConfig *config;
46
47 config = malloc (sizeof (FcConfig));
48 if (!config)
49 goto bail0;
179c3995 50 FcMemAlloc (FC_MEM_CONFIG, sizeof (FcConfig));
594dcef0 51
179c3995
KP
52 config->configDirs = FcStrSetCreate ();
53 if (!config->configDirs)
24330d27 54 goto bail1;
594dcef0 55
179c3995 56 config->configFiles = FcStrSetCreate ();
24330d27
KP
57 if (!config->configFiles)
58 goto bail2;
594dcef0 59
179c3995
KP
60 config->fontDirs = FcStrSetCreate ();
61 if (!config->fontDirs)
62 goto bail3;
594dcef0 63
d47c9d6e
KP
64 config->acceptGlobs = FcStrSetCreate ();
65 if (!config->acceptGlobs)
66 goto bail4;
67
68 config->rejectGlobs = FcStrSetCreate ();
69 if (!config->rejectGlobs)
70 goto bail5;
71
4f27c1c0
KP
72 config->acceptPatterns = FcFontSetCreate ();
73 if (!config->acceptPatterns)
74 goto bail6;
594dcef0 75
4f27c1c0
KP
76 config->rejectPatterns = FcFontSetCreate ();
77 if (!config->rejectPatterns)
78 goto bail7;
79
7410e40b
PL
80 config->cacheDirs = FcStrSetCreate ();
81 if (!config->cacheDirs)
2d3387fd 82 goto bail8;
594dcef0 83
d0471dd2
MF
84 config->rootDir = FcStrCopy ((const FcChar8 *) "");
85
24330d27
KP
86 config->blanks = 0;
87
88 config->substPattern = 0;
89 config->substFont = 0;
fb6e30ab 90 config->substScan = 0;
24330d27
KP
91 config->maxObjects = 0;
92 for (set = FcSetSystem; set <= FcSetApplication; set++)
93 config->fonts[set] = 0;
179c3995
KP
94
95 config->rescanTime = time(0);
594dcef0 96 config->rescanInterval = 30;
241fbde1 97
390c05e6
BE
98 config->expr_pool = NULL;
99
241fbde1 100 config->ref = 1;
594dcef0 101
24330d27
KP
102 return config;
103
4f27c1c0
KP
104bail8:
105 FcFontSetDestroy (config->rejectPatterns);
106bail7:
107 FcFontSetDestroy (config->acceptPatterns);
d47c9d6e
KP
108bail6:
109 FcStrSetDestroy (config->rejectGlobs);
110bail5:
111 FcStrSetDestroy (config->acceptGlobs);
179c3995
KP
112bail4:
113 FcStrSetDestroy (config->fontDirs);
24330d27 114bail3:
179c3995 115 FcStrSetDestroy (config->configFiles);
24330d27 116bail2:
179c3995 117 FcStrSetDestroy (config->configDirs);
24330d27
KP
118bail1:
119 free (config);
179c3995 120 FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
24330d27
KP
121bail0:
122 return 0;
123}
124
4645eedf 125static FcFileTime
d0471dd2 126FcConfigNewestFile (FcConfig *config, FcStrSet *files)
179c3995
KP
127{
128 FcStrList *list = FcStrListCreate (files);
4645eedf 129 FcFileTime newest = { 0, FcFalse };
179c3995
KP
130 FcChar8 *file;
131 struct stat statb;
132
133 if (list)
134 {
135 while ((file = FcStrListNext (list)))
d0471dd2 136 if (FcStat (config, file, &statb) == 0)
4645eedf 137 if (!newest.set || statb.st_mtime - newest.time > 0)
b68b9646
KP
138 {
139 newest.set = FcTrue;
4645eedf 140 newest.time = statb.st_mtime;
b68b9646 141 }
179c3995
KP
142 FcStrListDone (list);
143 }
144 return newest;
145}
146
147FcBool
148FcConfigUptoDate (FcConfig *config)
149{
ad27687f 150 FcFileTime config_time, config_dir_time, font_time;
4645eedf 151 time_t now = time(0);
179c3995
KP
152 if (!config)
153 {
154 config = FcConfigGetCurrent ();
155 if (!config)
156 return FcFalse;
157 }
d0471dd2
MF
158 config_time = FcConfigNewestFile (config, config->configFiles);
159 config_dir_time = FcConfigNewestFile (config, config->configDirs);
160 font_time = FcConfigNewestFile (config, config->fontDirs);
4645eedf 161 if ((config_time.set && config_time.time - config->rescanTime > 0) ||
ad27687f 162 (config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) ||
28f93bc4 163 (font_time.set && (font_time.time - config->rescanTime) > 0))
179c3995 164 {
ad3fc667
SD
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;
179c3995
KP
177 }
178 config->rescanTime = now;
179 return FcTrue;
180}
181
24330d27
KP
182static void
183FcSubstDestroy (FcSubst *s)
184{
185 FcSubst *n;
594dcef0 186
24330d27
KP
187 while (s)
188 {
189 n = s->next;
f4007a67
KP
190 if (s->test)
191 FcTestDestroy (s->test);
192 if (s->edit)
193 FcEditDestroy (s->edit);
34cd0514
CW
194 free (s);
195 FcMemFree (FC_MEM_SUBST, sizeof (FcSubst));
24330d27
KP
196 s = n;
197 }
198}
199
390c05e6
BE
200FcExpr *
201FcConfigAllocExpr (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
241fbde1
BE
220FcConfig *
221FcConfigReference (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
24330d27
KP
235void
236FcConfigDestroy (FcConfig *config)
237{
238 FcSetName set;
390c05e6 239 FcExprPage *page;
24330d27 240
241fbde1
BE
241 if (--config->ref > 0)
242 return;
243
179c3995
KP
244 if (config == _fcConfig)
245 _fcConfig = 0;
246
247 FcStrSetDestroy (config->configDirs);
248 FcStrSetDestroy (config->fontDirs);
7410e40b 249 FcStrSetDestroy (config->cacheDirs);
179c3995 250 FcStrSetDestroy (config->configFiles);
d47c9d6e
KP
251 FcStrSetDestroy (config->acceptGlobs);
252 FcStrSetDestroy (config->rejectGlobs);
4f27c1c0
KP
253 FcFontSetDestroy (config->acceptPatterns);
254 FcFontSetDestroy (config->rejectPatterns);
179c3995 255
34cd0514
CW
256 if (config->blanks)
257 FcBlanksDestroy (config->blanks);
258
24330d27
KP
259 FcSubstDestroy (config->substPattern);
260 FcSubstDestroy (config->substFont);
fb6e30ab 261 FcSubstDestroy (config->substScan);
24330d27
KP
262 for (set = FcSetSystem; set <= FcSetApplication; set++)
263 if (config->fonts[set])
264 FcFontSetDestroy (config->fonts[set]);
34cd0514 265
390c05e6
BE
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
179c3995
KP
275 free (config);
276 FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
24330d27
KP
277}
278
279/*
bc5e487f 280 * Add cache to configuration, adding fonts and directories
24330d27
KP
281 */
282
283FcBool
594dcef0 284FcConfigAddCache (FcConfig *config, FcCache *cache,
97c3d5b6 285 FcSetName set, FcStrSet *dirSet)
24330d27 286{
bc5e487f
KP
287 FcFontSet *fs;
288 intptr_t *dirs;
289 int i;
24330d27 290
bc5e487f
KP
291 /*
292 * Add fonts
293 */
294 fs = FcCacheSet (cache);
295 if (fs)
4262e0b3 296 {
17389539
KP
297 int nref = 0;
298
bc5e487f 299 for (i = 0; i < fs->nfont; i++)
4262e0b3 300 {
bc5e487f
KP
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
17389539 320 nref++;
97c3d5b6 321 FcFontSetAdd (config->fonts[set], font);
4262e0b3 322 }
17389539 323 FcDirCacheReference (cache, nref);
4262e0b3 324 }
bc5e487f
KP
325
326 /*
327 * Add directories
328 */
329 dirs = FcCacheDirs (cache);
330 if (dirs)
24330d27 331 {
bc5e487f
KP
332 for (i = 0; i < cache->dirs_count; i++)
333 {
334 FcChar8 *dir = FcOffsetToPtr (dirs, dirs[i], FcChar8);
335 if (FcConfigAcceptFilename (config, dir))
97c3d5b6 336 FcStrSetAddFilename (dirSet, dir);
03a212e5 337 }
bc5e487f
KP
338 }
339 return FcTrue;
340}
03a212e5 341
97c3d5b6
KP
342static FcBool
343FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
344{
345 FcStrList *dirlist;
346 FcChar8 *dir;
347 FcCache *cache;
594dcef0 348
97c3d5b6
KP
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
bc5e487f
KP
367/*
368 * Scan the current list of directories in the configuration
369 * and build the set of available fonts.
370 */
e0421d02 371
bc5e487f
KP
372FcBool
373FcConfigBuildFonts (FcConfig *config)
374{
375 FcFontSet *fonts;
1b7be377 376
bc5e487f
KP
377 if (!config)
378 {
379 config = FcConfigGetCurrent ();
380 if (!config)
381 return FcFalse;
24330d27 382 }
bc5e487f
KP
383
384 fonts = FcFontSetCreate ();
385 if (!fonts)
97c3d5b6 386 return FcFalse;
594dcef0 387
bc5e487f 388 FcConfigSetFonts (config, fonts, FcSetSystem);
594dcef0 389
97c3d5b6
KP
390 if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs))
391 return FcFalse;
24330d27
KP
392 if (FcDebug () & FC_DBG_FONTSET)
393 FcFontSetPrint (fonts);
24330d27 394 return FcTrue;
24330d27
KP
395}
396
397FcBool
398FcConfigSetCurrent (FcConfig *config)
399{
fc141b49
KP
400 if (config == _fcConfig)
401 return FcTrue;
402
24330d27
KP
403 if (!config->fonts)
404 if (!FcConfigBuildFonts (config))
405 return FcFalse;
406
6e9fc5de
KP
407 if (_fcConfig)
408 FcConfigDestroy (_fcConfig);
409 _fcConfig = config;
24330d27
KP
410 return FcTrue;
411}
412
413FcConfig *
414FcConfigGetCurrent (void)
415{
6e9fc5de
KP
416 if (!_fcConfig)
417 if (!FcInit ())
418 return 0;
419 return _fcConfig;
24330d27
KP
420}
421
422FcBool
179c3995
KP
423FcConfigAddConfigDir (FcConfig *config,
424 const FcChar8 *d)
24330d27 425{
179c3995
KP
426 return FcStrSetAddFilename (config->configDirs, d);
427}
24330d27 428
179c3995
KP
429FcStrList *
430FcConfigGetConfigDirs (FcConfig *config)
431{
432 if (!config)
24330d27 433 {
179c3995
KP
434 config = FcConfigGetCurrent ();
435 if (!config)
436 return 0;
24330d27 437 }
179c3995
KP
438 return FcStrListCreate (config->configDirs);
439}
440
441FcBool
442FcConfigAddFontDir (FcConfig *config,
443 const FcChar8 *d)
444{
445 return FcStrSetAddFilename (config->fontDirs, d);
24330d27
KP
446}
447
179c3995
KP
448FcBool
449FcConfigAddDir (FcConfig *config,
450 const FcChar8 *d)
451{
594dcef0 452 return (FcConfigAddConfigDir (config, d) &&
179c3995
KP
453 FcConfigAddFontDir (config, d));
454}
455
456FcStrList *
457FcConfigGetFontDirs (FcConfig *config)
24330d27
KP
458{
459 if (!config)
460 {
461 config = FcConfigGetCurrent ();
462 if (!config)
463 return 0;
464 }
179c3995 465 return FcStrListCreate (config->fontDirs);
24330d27
KP
466}
467
7410e40b
PL
468FcBool
469FcConfigAddCacheDir (FcConfig *config,
470 const FcChar8 *d)
471{
472 return FcStrSetAddFilename (config->cacheDirs, d);
473}
474
475FcStrList *
476FcConfigGetCacheDirs (FcConfig *config)
477{
478 if (!config)
479 {
480 config = FcConfigGetCurrent ();
481 if (!config)
482 return 0;
483 }
484 return FcStrListCreate (config->cacheDirs);
485}
594dcef0 486
24330d27
KP
487FcBool
488FcConfigAddConfigFile (FcConfig *config,
ccb3e93b 489 const FcChar8 *f)
24330d27 490{
179c3995 491 FcBool ret;
d0471dd2 492 FcChar8 *file = FcConfigFilename2 (config, f);
594dcef0 493
24330d27
KP
494 if (!file)
495 return FcFalse;
594dcef0 496
179c3995
KP
497 ret = FcStrSetAdd (config->configFiles, file);
498 FcStrFree (file);
499 return ret;
24330d27
KP
500}
501
179c3995 502FcStrList *
24330d27
KP
503FcConfigGetConfigFiles (FcConfig *config)
504{
505 if (!config)
506 {
507 config = FcConfigGetCurrent ();
508 if (!config)
509 return 0;
510 }
179c3995 511 return FcStrListCreate (config->configFiles);
24330d27
KP
512}
513
ccb3e93b 514FcChar8 *
24330d27
KP
515FcConfigGetCache (FcConfig *config)
516{
2d3387fd 517 return NULL;
24330d27
KP
518}
519
520FcFontSet *
521FcConfigGetFonts (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
533void
534FcConfigSetFonts (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
543FcBlanks *
544FcConfigGetBlanks (FcConfig *config)
545{
546 if (!config)
547 {
548 config = FcConfigGetCurrent ();
549 if (!config)
550 return 0;
551 }
552 return config->blanks;
553}
554
555FcBool
556FcConfigAddBlank (FcConfig *config,
557 FcChar32 blank)
558{
2de24638 559 FcBlanks *b, *freeme = 0;
594dcef0 560
24330d27
KP
561 b = config->blanks;
562 if (!b)
563 {
2de24638 564 freeme = b = FcBlanksCreate ();
24330d27
KP
565 if (!b)
566 return FcFalse;
567 }
568 if (!FcBlanksAdd (b, blank))
2de24638
PL
569 {
570 if (freeme)
571 FcBlanksDestroy (freeme);
24330d27 572 return FcFalse;
2de24638 573 }
24330d27
KP
574 config->blanks = b;
575 return FcTrue;
576}
577
179c3995 578int
1d93c175 579FcConfigGetRescanInterval (FcConfig *config)
179c3995
KP
580{
581 if (!config)
582 {
583 config = FcConfigGetCurrent ();
584 if (!config)
585 return 0;
586 }
587 return config->rescanInterval;
588}
589
590FcBool
1d93c175 591FcConfigSetRescanInterval (FcConfig *config, int rescanInterval)
179c3995
KP
592{
593 if (!config)
594 {
595 config = FcConfigGetCurrent ();
596 if (!config)
597 return FcFalse;
598 }
599 config->rescanInterval = rescanInterval;
600 return FcTrue;
601}
602
de1faa42
KP
603/*
604 * A couple of typos escaped into the library
605 */
606int
607FcConfigGetRescanInverval (FcConfig *config)
608{
609 return FcConfigGetRescanInterval (config);
610}
611
612FcBool
613FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
614{
615 return FcConfigSetRescanInterval (config, rescanInterval);
616}
617
594dcef0 618
24330d27
KP
619FcBool
620FcConfigAddEdit (FcConfig *config,
621 FcTest *test,
622 FcEdit *edit,
623 FcMatchKind kind)
624{
625 FcSubst *subst, **prev;
626 FcTest *t;
627 int num;
628
c2c6976d
KP
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 }
24330d27
KP
642 subst = (FcSubst *) malloc (sizeof (FcSubst));
643 if (!subst)
644 return FcFalse;
9dac3c59 645 FcMemAlloc (FC_MEM_SUBST, sizeof (FcSubst));
24330d27
KP
646 for (; *prev; prev = &(*prev)->next);
647 *prev = subst;
648 subst->next = 0;
649 subst->test = test;
650 subst->edit = edit;
24330d27
KP
651 num = 0;
652 for (t = test; t; t = t->next)
938bc633
KP
653 {
654 if (t->kind == FcMatchDefault)
655 t->kind = kind;
24330d27 656 num++;
938bc633 657 }
24330d27
KP
658 if (config->maxObjects < num)
659 config->maxObjects = num;
938bc633
KP
660 if (FcDebug () & FC_DBG_EDIT)
661 {
662 printf ("Add Subst ");
663 FcSubstPrint (subst);
664 }
24330d27
KP
665 return FcTrue;
666}
667
668typedef struct _FcSubState {
669 FcPatternElt *elt;
670 FcValueList *value;
671} FcSubState;
672
24330d27
KP
673static FcValue
674FcConfigPromote (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 {
4262e0b3 683 v.u.m = &FcIdentityMatrix;
327a7fd4 684 v.type = FcTypeMatrix;
24330d27 685 }
d8d73958
KP
686 else if (v.type == FcTypeString && u.type == FcTypeLangSet)
687 {
4262e0b3 688 v.u.l = FcLangSetPromote (v.u.s);
d8d73958
KP
689 v.type = FcTypeLangSet;
690 }
24330d27
KP
691 return v;
692}
693
694FcBool
4262e0b3 695FcConfigCompareValue (const FcValue *left_o,
ca4339b8 696 FcOp op,
4262e0b3 697 const FcValue *right_o)
24330d27 698{
4262e0b3
PL
699 FcValue left = FcValueCanonicalize(left_o);
700 FcValue right = FcValueCanonicalize(right_o);
ca4339b8 701 FcBool ret = FcFalse;
594dcef0 702
74a623e0
KP
703 left = FcConfigPromote (left, right);
704 right = FcConfigPromote (right, left);
594dcef0 705 if (left.type == right.type)
24330d27 706 {
74a623e0 707 switch (left.type) {
24330d27
KP
708 case FcTypeInteger:
709 break; /* FcConfigPromote prevents this from happening */
710 case FcTypeDouble:
711 switch (op) {
712 case FcOpEqual:
713 case FcOpContains:
74a623e0
KP
714 case FcOpListing:
715 ret = left.u.d == right.u.d;
24330d27 716 break;
47d4f950
KP
717 case FcOpNotEqual:
718 case FcOpNotContains:
74a623e0 719 ret = left.u.d != right.u.d;
24330d27 720 break;
594dcef0 721 case FcOpLess:
74a623e0 722 ret = left.u.d < right.u.d;
24330d27 723 break;
594dcef0 724 case FcOpLessEqual:
74a623e0 725 ret = left.u.d <= right.u.d;
24330d27 726 break;
594dcef0 727 case FcOpMore:
74a623e0 728 ret = left.u.d > right.u.d;
24330d27 729 break;
594dcef0 730 case FcOpMoreEqual:
74a623e0 731 ret = left.u.d >= right.u.d;
24330d27
KP
732 break;
733 default:
734 break;
735 }
736 break;
737 case FcTypeBool:
738 switch (op) {
594dcef0 739 case FcOpEqual:
24330d27 740 case FcOpContains:
74a623e0
KP
741 case FcOpListing:
742 ret = left.u.b == right.u.b;
24330d27 743 break;
47d4f950
KP
744 case FcOpNotEqual:
745 case FcOpNotContains:
74a623e0 746 ret = left.u.b != right.u.b;
24330d27
KP
747 break;
748 default:
749 break;
750 }
751 break;
752 case FcTypeString:
753 switch (op) {
594dcef0 754 case FcOpEqual:
74a623e0 755 case FcOpListing:
4262e0b3 756 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
24330d27 757 break;
d4d1e8bc 758 case FcOpContains:
4262e0b3 759 ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
d4d1e8bc 760 break;
47d4f950 761 case FcOpNotEqual:
4262e0b3 762 ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
d4d1e8bc 763 break;
f1a42f6b 764 case FcOpNotContains:
0f787088 765 ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
f1a42f6b 766 break;
24330d27
KP
767 default:
768 break;
769 }
770 break;
771 case FcTypeMatrix:
772 switch (op) {
773 case FcOpEqual:
774 case FcOpContains:
74a623e0 775 case FcOpListing:
4262e0b3 776 ret = FcMatrixEqual (left.u.m, right.u.m);
24330d27
KP
777 break;
778 case FcOpNotEqual:
47d4f950 779 case FcOpNotContains:
4262e0b3 780 ret = !FcMatrixEqual (left.u.m, right.u.m);
24330d27
KP
781 break;
782 default:
783 break;
784 }
785 break;
786 case FcTypeCharSet:
787 switch (op) {
788 case FcOpContains:
74a623e0
KP
789 case FcOpListing:
790 /* left contains right if right is a subset of left */
4262e0b3 791 ret = FcCharSetIsSubset (right.u.c, left.u.c);
24330d27 792 break;
47d4f950 793 case FcOpNotContains:
74a623e0 794 /* left contains right if right is a subset of left */
4262e0b3 795 ret = !FcCharSetIsSubset (right.u.c, left.u.c);
47d4f950 796 break;
24330d27 797 case FcOpEqual:
4262e0b3 798 ret = FcCharSetEqual (left.u.c, right.u.c);
24330d27
KP
799 break;
800 case FcOpNotEqual:
4262e0b3 801 ret = !FcCharSetEqual (left.u.c, right.u.c);
24330d27
KP
802 break;
803 default:
804 break;
805 }
806 break;
d8d73958
KP
807 case FcTypeLangSet:
808 switch (op) {
809 case FcOpContains:
74a623e0 810 case FcOpListing:
4262e0b3 811 ret = FcLangSetContains (left.u.l, right.u.l);
d8d73958 812 break;
47d4f950 813 case FcOpNotContains:
4262e0b3 814 ret = !FcLangSetContains (left.u.l, right.u.l);
47d4f950 815 break;
d8d73958 816 case FcOpEqual:
4262e0b3 817 ret = FcLangSetEqual (left.u.l, right.u.l);
d8d73958
KP
818 break;
819 case FcOpNotEqual:
4262e0b3 820 ret = !FcLangSetEqual (left.u.l, right.u.l);
d8d73958
KP
821 break;
822 default:
823 break;
824 }
825 break;
24330d27
KP
826 case FcTypeVoid:
827 switch (op) {
828 case FcOpEqual:
829 case FcOpContains:
74a623e0 830 case FcOpListing:
24330d27
KP
831 ret = FcTrue;
832 break;
833 default:
834 break;
835 }
836 break;
8ec077f2
KP
837 case FcTypeFTFace:
838 switch (op) {
839 case FcOpEqual:
47d4f950 840 case FcOpContains:
74a623e0
KP
841 case FcOpListing:
842 ret = left.u.f == right.u.f;
8ec077f2
KP
843 break;
844 case FcOpNotEqual:
47d4f950 845 case FcOpNotContains:
74a623e0 846 ret = left.u.f != right.u.f;
8ec077f2
KP
847 break;
848 default:
849 break;
850 }
938bc633 851 break;
24330d27
KP
852 }
853 }
854 else
855 {
47d4f950 856 if (op == FcOpNotEqual || op == FcOpNotContains)
24330d27
KP
857 ret = FcTrue;
858 }
859 return ret;
860}
861
862
3f7653c2
KP
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
24330d27
KP
870static FcValue
871FcConfigEvaluate (FcPattern *p, FcExpr *e)
872{
873 FcValue v, vl, vr;
874 FcResult r;
875 FcMatrix *m;
3ea92166 876 FcChar8 *str;
594dcef0 877
24330d27
KP
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;
efe5eae2
BE
889 v.u.s = e->u.sval;
890 v = FcValueSave (v);
24330d27
KP
891 break;
892 case FcOpMatrix:
893 v.type = FcTypeMatrix;
4262e0b3 894 v.u.m = e->u.mval;
24330d27
KP
895 v = FcValueSave (v);
896 break;
897 case FcOpCharSet:
898 v.type = FcTypeCharSet;
4262e0b3 899 v.u.c = e->u.cval;
24330d27
KP
900 v = FcValueSave (v);
901 break;
3c862aad
AT
902 case FcOpLangSet:
903 v.type = FcTypeLangSet;
904 v.u.l = e->u.lval;
905 v = FcValueSave (v);
906 break;
24330d27
KP
907 case FcOpBool:
908 v.type = FcTypeBool;
909 v.u.b = e->u.bval;
910 break;
911 case FcOpField:
7ce19673 912 r = FcPatternObjectGet (p, e->u.object, 0, &v);
24330d27
KP
913 if (r != FcResultMatch)
914 v.type = FcTypeVoid;
575a37b7 915 v = FcValueSave (v);
24330d27
KP
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;
47d4f950 936 case FcOpEqual:
24330d27
KP
937 case FcOpNotEqual:
938 case FcOpLess:
939 case FcOpLessEqual:
940 case FcOpMore:
941 case FcOpMoreEqual:
47d4f950
KP
942 case FcOpContains:
943 case FcOpNotContains:
74a623e0 944 case FcOpListing:
938bc633
KP
945 vl = FcConfigEvaluate (p, e->u.tree.left);
946 vr = FcConfigEvaluate (p, e->u.tree.right);
947 v.type = FcTypeBool;
4262e0b3 948 v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
938bc633
KP
949 FcValueDestroy (vl);
950 FcValueDestroy (vr);
951 break;
952 case FcOpOr:
953 case FcOpAnd:
24330d27
KP
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) {
594dcef0 967 case FcOpPlus:
24330d27 968 v.type = FcTypeDouble;
594dcef0 969 v.u.d = vl.u.d + vr.u.d;
24330d27
KP
970 break;
971 case FcOpMinus:
972 v.type = FcTypeDouble;
594dcef0 973 v.u.d = vl.u.d - vr.u.d;
24330d27
KP
974 break;
975 case FcOpTimes:
976 v.type = FcTypeDouble;
594dcef0 977 v.u.d = vl.u.d * vr.u.d;
24330d27
KP
978 break;
979 case FcOpDivide:
980 v.type = FcTypeDouble;
594dcef0 981 v.u.d = vl.u.d / vr.u.d;
24330d27 982 break;
24330d27 983 default:
594dcef0 984 v.type = FcTypeVoid;
24330d27
KP
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;
24330d27 1004 default:
594dcef0 1005 v.type = FcTypeVoid;
24330d27
KP
1006 break;
1007 }
1008 break;
1009 case FcTypeString:
1010 switch (e->op) {
24330d27
KP
1011 case FcOpPlus:
1012 v.type = FcTypeString;
3ea92166
PL
1013 str = FcStrPlus (vl.u.s, vr.u.s);
1014 v.u.s = FcStrStaticName (str);
1015 FcStrFree (str);
594dcef0 1016
4262e0b3 1017 if (!v.u.s)
24330d27
KP
1018 v.type = FcTypeVoid;
1019 break;
1020 default:
1021 v.type = FcTypeVoid;
1022 break;
1023 }
8c96d1fc 1024 break;
24330d27
KP
1025 case FcTypeMatrix:
1026 switch (e->op) {
24330d27
KP
1027 case FcOpTimes:
1028 v.type = FcTypeMatrix;
1029 m = malloc (sizeof (FcMatrix));
1030 if (m)
1031 {
1032 FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
4262e0b3
PL
1033 FcMatrixMultiply (m, vl.u.m, vr.u.m);
1034 v.u.m = m;
24330d27
KP
1035 }
1036 else
1037 {
1038 v.type = FcTypeVoid;
1039 }
1040 break;
1041 default:
1042 v.type = FcTypeVoid;
1043 break;
1044 }
1045 break;
857b7efe
AT
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;
3c862aad
AT
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;
24330d27
KP
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;
3f7653c2
KP
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;
24330d27
KP
1171 default:
1172 v.type = FcTypeVoid;
1173 break;
1174 }
1175 return v;
1176}
1177
1178static FcValueList *
1179FcConfigMatchValueList (FcPattern *p,
1180 FcTest *t,
f534109f 1181 FcValueList *values)
24330d27 1182{
179c3995
KP
1183 FcValueList *ret = 0;
1184 FcExpr *e = t->expr;
1185 FcValue value;
f534109f 1186 FcValueList *v;
594dcef0 1187
179c3995 1188 while (e)
24330d27 1189 {
74a623e0 1190 /* Compute the value of the match expression */
179c3995 1191 if (e->op == FcOpComma)
24330d27 1192 {
179c3995
KP
1193 value = FcConfigEvaluate (p, e->u.tree.left);
1194 e = e->u.tree.right;
24330d27
KP
1195 }
1196 else
1197 {
179c3995
KP
1198 value = FcConfigEvaluate (p, e);
1199 e = 0;
1200 }
1201
7ce19673 1202 for (v = values; v; v = FcValueListNext(v))
179c3995 1203 {
74a623e0 1204 /* Compare the pattern value to the match expression value */
4262e0b3 1205 if (FcConfigCompareValue (&v->value, t->op, &value))
24330d27 1206 {
179c3995
KP
1207 if (!ret)
1208 ret = v;
1209 }
1210 else
1211 {
1212 if (t->qual == FcQualAll)
1213 {
1214 ret = 0;
1215 break;
1216 }
24330d27
KP
1217 }
1218 }
d0f07b8d 1219 FcValueDestroy (value);
24330d27 1220 }
24330d27
KP
1221 return ret;
1222}
1223
1224static FcValueList *
6fff2cda 1225FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding)
24330d27
KP
1226{
1227 FcValueList *l;
594dcef0 1228
24330d27
KP
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);
7ce19673 1238 l->next = FcConfigValues (p, e->u.tree.right, binding);
24330d27
KP
1239 }
1240 else
1241 {
1242 l->value = FcConfigEvaluate (p, e);
7ce19673 1243 l->next = NULL;
24330d27 1244 }
6fff2cda 1245 l->binding = binding;
82912b06 1246 if (l->value.type == FcTypeVoid)
24330d27 1247 {
7ce19673 1248 FcValueList *next = FcValueListNext(l);
cd2ec1a9 1249
82912b06
PL
1250 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
1251 free (l);
1252 l = next;
24330d27 1253 }
82912b06 1254
24330d27
KP
1255 return l;
1256}
1257
1258static FcBool
cd2ec1a9 1259FcConfigAdd (FcValueListPtr *head,
24330d27
KP
1260 FcValueList *position,
1261 FcBool append,
1262 FcValueList *new)
1263{
cd2ec1a9 1264 FcValueListPtr *prev, last, v;
dda7794f 1265 FcValueBinding sameBinding;
594dcef0 1266
dda7794f
KP
1267 if (position)
1268 sameBinding = position->binding;
1269 else
1270 sameBinding = FcValueBindingWeak;
7ce19673
KP
1271 for (v = new; v != NULL; v = FcValueListNext(v))
1272 if (v->binding == FcValueBindingSame)
1273 v->binding = sameBinding;
24330d27
KP
1274 if (append)
1275 {
1276 if (position)
1277 prev = &position->next;
1278 else
594dcef0 1279 for (prev = head; *prev != NULL;
7ce19673 1280 prev = &(*prev)->next)
24330d27
KP
1281 ;
1282 }
1283 else
1284 {
1285 if (position)
1286 {
594dcef0 1287 for (prev = head; *prev != NULL;
7ce19673 1288 prev = &(*prev)->next)
24330d27 1289 {
7ce19673 1290 if (*prev == position)
24330d27
KP
1291 break;
1292 }
1293 }
1294 else
1295 prev = head;
1296
1297 if (FcDebug () & FC_DBG_EDIT)
1298 {
7ce19673 1299 if (*prev == NULL)
24330d27
KP
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 }
594dcef0 1310
24330d27
KP
1311 if (new)
1312 {
7ce19673
KP
1313 last = new;
1314 while (last->next != NULL)
1315 last = last->next;
594dcef0 1316
7ce19673
KP
1317 last->next = *prev;
1318 *prev = new;
24330d27 1319 }
594dcef0 1320
24330d27
KP
1321 if (FcDebug () & FC_DBG_EDIT)
1322 {
1323 printf ("%s list after ", append ? "Append" : "Prepend");
1324 FcValueListPrint (*head);
1325 printf ("\n");
1326 }
594dcef0 1327
24330d27
KP
1328 return FcTrue;
1329}
1330
1331static void
cd2ec1a9 1332FcConfigDel (FcValueListPtr *head,
24330d27
KP
1333 FcValueList *position)
1334{
cd2ec1a9 1335 FcValueListPtr *prev;
24330d27 1336
7ce19673 1337 for (prev = head; *prev != NULL; prev = &(*prev)->next)
24330d27 1338 {
7ce19673 1339 if (*prev == position)
24330d27
KP
1340 {
1341 *prev = position->next;
7ce19673
KP
1342 position->next = NULL;
1343 FcValueListDestroy (position);
24330d27
KP
1344 break;
1345 }
1346 }
1347}
1348
1349static void
1350FcConfigPatternAdd (FcPattern *p,
7ce19673 1351 FcObject object,
24330d27
KP
1352 FcValueList *list,
1353 FcBool append)
1354{
1355 if (list)
1356 {
7ce19673 1357 FcPatternElt *e = FcPatternObjectInsertElt (p, object);
594dcef0 1358
24330d27
KP
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 */
1368static void
1369FcConfigPatternDel (FcPattern *p,
7ce19673 1370 FcObject object)
24330d27 1371{
7ce19673 1372 FcPatternElt *e = FcPatternObjectFindElt (p, object);
24330d27
KP
1373 if (!e)
1374 return;
7ce19673
KP
1375 while (e->values != NULL)
1376 FcConfigDel (&e->values, e->values);
24330d27
KP
1377}
1378
1379static void
1380FcConfigPatternCanon (FcPattern *p,
7ce19673 1381 FcObject object)
24330d27 1382{
7ce19673 1383 FcPatternElt *e = FcPatternObjectFindElt (p, object);
24330d27
KP
1384 if (!e)
1385 return;
7ce19673
KP
1386 if (e->values == NULL)
1387 FcPatternObjectDel (p, object);
24330d27
KP
1388}
1389
1390FcBool
fa244f3d
KP
1391FcConfigSubstituteWithPat (FcConfig *config,
1392 FcPattern *p,
1393 FcPattern *p_pat,
1394 FcMatchKind kind)
24330d27
KP
1395{
1396 FcSubst *s;
1397 FcSubState *st;
1398 int i;
1399 FcTest *t;
1400 FcEdit *e;
1401 FcValueList *l;
938bc633 1402 FcPattern *m;
24330d27
KP
1403
1404 if (!config)
1405 {
1406 config = FcConfigGetCurrent ();
1407 if (!config)
1408 return FcFalse;
1409 }
1410
c2c6976d
KP
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
24330d27
KP
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 }
24330d27
KP
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 }
938bc633
KP
1448 st[i].elt = 0;
1449 if (kind == FcMatchFont && t->kind == FcMatchPattern)
1450 m = p_pat;
1451 else
1452 m = p;
1453 if (m)
7ce19673 1454 st[i].elt = FcPatternObjectFindElt (m, t->object);
938bc633
KP
1455 else
1456 st[i].elt = 0;
24330d27
KP
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 */
7ce19673 1475 st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values);
24330d27
KP
1476 if (!st[i].value)
1477 break;
7ce19673 1478 if (t->qual == FcQualFirst && st[i].value != st[i].elt->values)
6f6563ed 1479 break;
7ce19673 1480 if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values)
6f6563ed 1481 break;
24330d27
KP
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 */
6fff2cda 1499 l = FcConfigValues (p, e->expr, e->binding);
24330d27 1500 /*
938bc633
KP
1501 * Locate any test associated with this field, skipping
1502 * tests associated with the pattern when substituting in
1503 * the font
24330d27
KP
1504 */
1505 for (t = s->test, i = 0; t; t = t->next, i++)
938bc633
KP
1506 {
1507 if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
7ce19673 1508 t->object == e->object)
432913ea 1509 {
594dcef0 1510 /*
5f84b65a
KP
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)
7ce19673 1517 st[i].elt = FcPatternObjectFindElt (p, t->object);
432913ea
DD
1518 if (!st[i].elt)
1519 t = 0;
24330d27 1520 break;
432913ea 1521 }
938bc633 1522 }
24330d27
KP
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 */
e9be9cd1 1529 if (t)
24330d27
KP
1530 {
1531 FcValueList *thisValue = st[i].value;
7ce19673 1532 FcValueList *nextValue = thisValue;
594dcef0 1533
24330d27
KP
1534 /*
1535 * Append the new list of values after the current value
1536 */
1537 FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
ccb3e93b
KP
1538 /*
1539 * Delete the marked value
1540 */
2f02e383
PL
1541 if (thisValue)
1542 FcConfigDel (&st[i].elt->values, thisValue);
24330d27
KP
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 }
24330d27
KP
1552 break;
1553 }
1554 /* fall through ... */
1555 case FcOpAssignReplace:
1556 /*
1557 * Delete all of the values and insert
1558 * the new set
1559 */
7ce19673
KP
1560 FcConfigPatternDel (p, e->object);
1561 FcConfigPatternAdd (p, e->object, l, FcTrue);
24330d27
KP
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:
7ce19673 1584 FcConfigPatternAdd (p, e->object, l, FcFalse);
24330d27
KP
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:
7ce19673 1594 FcConfigPatternAdd (p, e->object, l, FcTrue);
24330d27
KP
1595 break;
1596 default:
7ce19673 1597 FcValueListDestroy (l);
24330d27
KP
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)
7ce19673 1606 FcConfigPatternCanon (p, e->object);
24330d27
KP
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
fa244f3d
KP
1624FcBool
1625FcConfigSubstitute (FcConfig *config,
1626 FcPattern *p,
1627 FcMatchKind kind)
1628{
1629 return FcConfigSubstituteWithPat (config, p, 0, kind);
1630}
1631
6d65081e
DS
1632#if defined (_WIN32)
1633
1634# define WIN32_LEAN_AND_MEAN
1635# define WIN32_EXTRA_LEAN
1636# include <windows.h>
daeed6e0
TL
1637
1638static FcChar8 fontconfig_path[1000] = "";
1639
6d65081e
DS
1640# if (defined (PIC) || defined (DLL_EXPORT))
1641
daeed6e0
TL
1642BOOL WINAPI
1643DllMain (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';
594dcef0 1672
daeed6e0
TL
1673 break;
1674 }
1675
1676 return TRUE;
1677}
1678
6d65081e
DS
1679# endif /* !PIC */
1680
daeed6e0
TL
1681#undef FONTCONFIG_PATH
1682#define FONTCONFIG_PATH fontconfig_path
1683
6d65081e 1684#endif /* !_WIN32 */
daeed6e0 1685
24330d27
KP
1686#ifndef FONTCONFIG_FILE
1687#define FONTCONFIG_FILE "fonts.conf"
1688#endif
1689
ccb3e93b 1690static FcChar8 *
d0471dd2 1691FcConfigFileExists (FcConfig *config, const FcChar8 *dir, const FcChar8 *file)
24330d27 1692{
ccb3e93b 1693 FcChar8 *path;
24330d27
KP
1694
1695 if (!dir)
bb8057ea 1696 dir = (const FcChar8 *) "";
1c475d5c 1697
d0471dd2 1698 path = FcStrPathPlus (FcConfigGetRoot (config), dir, file, NULL);
ccb3e93b 1699 if (access ((char *) path, R_OK) == 0)
d0471dd2
MF
1700 {
1701 FcStrFree (path);
1702 return FcStrPathPlus (dir, file, NULL);
1703 }
594dcef0 1704
9dac3c59 1705 FcStrFree (path);
24330d27
KP
1706 return 0;
1707}
1708
ccb3e93b 1709static FcChar8 **
24330d27
KP
1710FcConfigGetPath (void)
1711{
ccb3e93b
KP
1712 FcChar8 **path;
1713 FcChar8 *env, *e, *colon;
1714 FcChar8 *dir;
24330d27
KP
1715 int npath;
1716 int i;
1717
1718 npath = 2; /* default dir + null */
ccb3e93b 1719 env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
24330d27
KP
1720 if (env)
1721 {
1722 e = env;
1723 npath++;
1724 while (*e)
daeed6e0 1725 if (*e++ == FC_SEARCH_PATH_SEPARATOR)
24330d27
KP
1726 npath++;
1727 }
ccb3e93b 1728 path = calloc (npath, sizeof (FcChar8 *));
24330d27
KP
1729 if (!path)
1730 goto bail0;
1731 i = 0;
1732
1733 if (env)
1734 {
1735 e = env;
594dcef0 1736 while (*e)
24330d27 1737 {
daeed6e0 1738 colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
24330d27 1739 if (!colon)
ccb3e93b 1740 colon = e + strlen ((char *) e);
24330d27
KP
1741 path[i] = malloc (colon - e + 1);
1742 if (!path[i])
1743 goto bail1;
9c8e07f1 1744 strncpy ((char *) path[i], (const char *) e, colon - e);
24330d27
KP
1745 path[i][colon - e] = '\0';
1746 if (*colon)
1747 e = colon + 1;
1748 else
1749 e = colon;
1750 i++;
1751 }
1752 }
594dcef0 1753
6d65081e
DS
1754#ifdef _WIN32
1755 if (fontconfig_path[0] == '\0')
1756 {
e04afe83 1757 char *p;
6d65081e
DS
1758 if(!GetModuleFileName(NULL, fontconfig_path, sizeof(fontconfig_path)))
1759 goto bail1;
e04afe83 1760 p = strrchr (fontconfig_path, '\\');
6d65081e
DS
1761 if (p) *p = '\0';
1762 strcat (fontconfig_path, "\\fonts");
1763 }
1764#endif
ccb3e93b
KP
1765 dir = (FcChar8 *) FONTCONFIG_PATH;
1766 path[i] = malloc (strlen ((char *) dir) + 1);
24330d27
KP
1767 if (!path[i])
1768 goto bail1;
9c8e07f1 1769 strcpy ((char *) path[i], (const char *) dir);
24330d27
KP
1770 return path;
1771
1772bail1:
1773 for (i = 0; path[i]; i++)
1774 free (path[i]);
1775 free (path);
1776bail0:
1777 return 0;
1778}
1779
1780static void
ccb3e93b 1781FcConfigFreePath (FcChar8 **path)
24330d27 1782{
ccb3e93b 1783 FcChar8 **p;
24330d27
KP
1784
1785 for (p = path; *p; p++)
1786 free (*p);
1787 free (path);
1788}
1789
ff3f1f98
KP
1790static FcBool _FcConfigHomeEnabled = FcTrue;
1791
1792FcChar8 *
1793FcConfigHome (void)
1794{
1795 if (_FcConfigHomeEnabled)
daeed6e0
TL
1796 {
1797 char *home = getenv ("HOME");
1798
1799#ifdef _WIN32
1800 if (home == NULL)
1801 home = getenv ("USERPROFILE");
1802#endif
1803
8245771d 1804 return (FcChar8 *) home;
daeed6e0 1805 }
ff3f1f98
KP
1806 return 0;
1807}
1808
1809FcBool
1810FcConfigEnableHome (FcBool enable)
1811{
1812 FcBool prev = _FcConfigHomeEnabled;
1813 _FcConfigHomeEnabled = enable;
1814 return prev;
1815}
1816
ccb3e93b
KP
1817FcChar8 *
1818FcConfigFilename (const FcChar8 *url)
d0471dd2
MF
1819{
1820 return FcConfigFilename2 (FcConfigGetCurrent (), url);
1821}
1822
1823FcChar8 *
1824FcConfigFilename2 (FcConfig *config, const FcChar8 *url)
24330d27 1825{
ccb3e93b 1826 FcChar8 *file, *dir, **path, **p;
6d65081e 1827
24330d27
KP
1828 if (!url || !*url)
1829 {
ccb3e93b 1830 url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
24330d27 1831 if (!url)
ccb3e93b 1832 url = (FcChar8 *) FONTCONFIG_FILE;
24330d27 1833 }
ccb3e93b 1834 file = 0;
daeed6e0
TL
1835
1836#ifdef _WIN32
1837 if (isalpha (*url) &&
1838 url[1] == ':' &&
1839 (url[2] == '/' || url[2] == '\\'))
1840 goto absolute_path;
1841#endif
1842
24330d27
KP
1843 switch (*url) {
1844 case '~':
ff3f1f98 1845 dir = FcConfigHome ();
24330d27 1846 if (dir)
d0471dd2 1847 file = FcConfigFileExists (config, dir, url + 1);
24330d27
KP
1848 else
1849 file = 0;
1850 break;
daeed6e0
TL
1851#ifdef _WIN32
1852 case '\\':
1853 absolute_path:
1854#endif
24330d27 1855 case '/':
d0471dd2 1856 file = FcConfigFileExists (config, 0, url);
24330d27
KP
1857 break;
1858 default:
1859 path = FcConfigGetPath ();
1860 if (!path)
1861 return 0;
1862 for (p = path; *p; p++)
1863 {
d0471dd2 1864 file = FcConfigFileExists (config, *p, url);
24330d27
KP
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
1878FcBool
1879FcConfigAppFontAddFile (FcConfig *config,
ccb3e93b 1880 const FcChar8 *file)
24330d27
KP
1881{
1882 FcFontSet *set;
179c3995
KP
1883 FcStrSet *subdirs;
1884 FcStrList *sublist;
1885 FcChar8 *subdir;
24330d27
KP
1886
1887 if (!config)
1888 {
1889 config = FcConfigGetCurrent ();
1890 if (!config)
1891 return FcFalse;
1892 }
1893
179c3995
KP
1894 subdirs = FcStrSetCreate ();
1895 if (!subdirs)
1896 return FcFalse;
594dcef0 1897
24330d27
KP
1898 set = FcConfigGetFonts (config, FcSetApplication);
1899 if (!set)
1900 {
1901 set = FcFontSetCreate ();
1902 if (!set)
179c3995
KP
1903 {
1904 FcStrSetDestroy (subdirs);
24330d27 1905 return FcFalse;
179c3995 1906 }
24330d27
KP
1907 FcConfigSetFonts (config, set, FcSetApplication);
1908 }
179c3995 1909
bc5e487f 1910 if (!FcFileScanConfig (set, subdirs, config->blanks, file, config))
179c3995
KP
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 }
c4c47a76 1923 FcStrSetDestroy (subdirs);
179c3995 1924 return FcTrue;
24330d27
KP
1925}
1926
1927FcBool
1928FcConfigAppFontAddDir (FcConfig *config,
ccb3e93b 1929 const FcChar8 *dir)
24330d27
KP
1930{
1931 FcFontSet *set;
97c3d5b6 1932 FcStrSet *dirs;
594dcef0 1933
24330d27
KP
1934 if (!config)
1935 {
1936 config = FcConfigGetCurrent ();
1937 if (!config)
1938 return FcFalse;
1939 }
97c3d5b6
KP
1940
1941 dirs = FcStrSetCreate ();
1942 if (!dirs)
179c3995 1943 return FcFalse;
594dcef0 1944
24330d27
KP
1945 set = FcConfigGetFonts (config, FcSetApplication);
1946 if (!set)
1947 {
1948 set = FcFontSetCreate ();
1949 if (!set)
179c3995 1950 {
97c3d5b6 1951 FcStrSetDestroy (dirs);
24330d27 1952 return FcFalse;
179c3995 1953 }
24330d27
KP
1954 FcConfigSetFonts (config, set, FcSetApplication);
1955 }
594dcef0 1956
97c3d5b6 1957 FcStrSetAddFilename (dirs, dir);
594dcef0 1958
97c3d5b6 1959 if (!FcConfigAddDirList (config, FcSetApplication, dirs))
179c3995 1960 {
97c3d5b6 1961 FcStrSetDestroy (dirs);
179c3995
KP
1962 return FcFalse;
1963 }
97c3d5b6 1964 FcStrSetDestroy (dirs);
179c3995 1965 return FcTrue;
24330d27
KP
1966}
1967
1968void
1969FcConfigAppFontClear (FcConfig *config)
1970{
3ef32bcd
MS
1971 if (!config)
1972 {
1973 config = FcConfigGetCurrent ();
1974 if (!config)
1975 return;
1976 }
1977
24330d27
KP
1978 FcConfigSetFonts (config, 0, FcSetApplication);
1979}
d47c9d6e
KP
1980
1981/*
1982 * Manage filename-based font source selectors
1983 */
1984
1985FcBool
1986FcConfigGlobAdd (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
1995static FcBool
1996FcConfigGlobMatch (const FcChar8 *glob,
1997 const FcChar8 *string)
1998{
1999 FcChar8 c;
2000
594dcef0 2001 while ((c = *glob++))
d47c9d6e
KP
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
2031static FcBool
2032FcConfigGlobsMatch (const FcStrSet *globs,
2033 const FcChar8 *string)
2034{
2035 int i;
2036
2037 for (i = 0; i < globs->num; i++)
4262e0b3 2038 if (FcConfigGlobMatch (globs->strs[i], string))
d47c9d6e
KP
2039 return FcTrue;
2040 return FcFalse;
2041}
2042
2043FcBool
2044FcConfigAcceptFilename (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}
4f27c1c0
KP
2053
2054/*
2055 * Manage font-pattern based font source selectors
2056 */
2057
2058FcBool
2059FcConfigPatternsAdd (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
2068static FcBool
2069FcConfigPatternsMatch (const FcFontSet *patterns,
2070 const FcPattern *font)
2071{
2072 int i;
594dcef0 2073
4f27c1c0
KP
2074 for (i = 0; i < patterns->nfont; i++)
2075 if (FcListPatternMatchAny (patterns->fonts[i], font))
2076 return FcTrue;
2077 return FcFalse;
2078}
2079
2080FcBool
2081FcConfigAcceptFont (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}
d0471dd2
MF
2090
2091void
2092FcConfigSetRoot (FcConfig *config,
2093 const FcChar8 *path)
2094{
2095 FcStrFree (config->rootDir);
2096 config->rootDir = FcStrCopy (path);
2097}
2098
2099const FcChar8 *
2100FcConfigGetRoot (FcConfig *config)
2101{
2102 return config->rootDir;
2103}
2104
2105FcChar8 *
2106FcConfigGetRootPlus (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
23816bf9
KP
2118#define __fccfg__
2119#include "fcaliastail.h"
2120#undef __fccfg__