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