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