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