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