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