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