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