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