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