fccfg.c 33.1 KB
Newer Older
Keith Packard's avatar
Keith Packard committed
1
/*
2
 * $RCSId: xc/lib/fontconfig/src/fccfg.c,v 1.23 2002/08/31 22:17:32 keithp Exp $
Keith Packard's avatar
Keith Packard committed
3
 *
4
 * Copyright  2000 Keith Packard
Keith Packard's avatar
Keith Packard committed
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Keith Packard not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Keith Packard makes no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#include "fcint.h"

Tor Lillqvist's avatar
Tor Lillqvist committed
27
28
29
30
31
32
#if defined (_WIN32) && defined (PIC)
#define STRICT
#include <windows.h>
#undef STRICT
#endif

33
FcConfig    *_fcConfig;
Keith Packard's avatar
Keith Packard committed
34
35
36
37
38
39
40
41
42
43

FcConfig *
FcConfigCreate (void)
{
    FcSetName	set;
    FcConfig	*config;

    config = malloc (sizeof (FcConfig));
    if (!config)
	goto bail0;
44
    FcMemAlloc (FC_MEM_CONFIG, sizeof (FcConfig));
Keith Packard's avatar
Keith Packard committed
45
    
46
47
    config->configDirs = FcStrSetCreate ();
    if (!config->configDirs)
Keith Packard's avatar
Keith Packard committed
48
49
	goto bail1;
    
50
    config->configFiles = FcStrSetCreate ();
Keith Packard's avatar
Keith Packard committed
51
52
    if (!config->configFiles)
	goto bail2;
53
54
55
56
    
    config->fontDirs = FcStrSetCreate ();
    if (!config->fontDirs)
	goto bail3;
Keith Packard's avatar
Keith Packard committed
57
58
    
    config->cache = 0;
59
60
61
    if (FcConfigHome())
	if (!FcConfigSetCache (config, (FcChar8 *) ("~/" FC_USER_CACHE_FILE)))
	    goto bail4;
Keith Packard's avatar
Keith Packard committed
62
63
64
65
66
67
68
69

    config->blanks = 0;

    config->substPattern = 0;
    config->substFont = 0;
    config->maxObjects = 0;
    for (set = FcSetSystem; set <= FcSetApplication; set++)
	config->fonts[set] = 0;
70
71
72

    config->rescanTime = time(0);
    config->rescanInterval = 30;    
Keith Packard's avatar
Keith Packard committed
73
74
75
    
    return config;

76
77
bail4:
    FcStrSetDestroy (config->fontDirs);
Keith Packard's avatar
Keith Packard committed
78
bail3:
79
    FcStrSetDestroy (config->configFiles);
Keith Packard's avatar
Keith Packard committed
80
bail2:
81
    FcStrSetDestroy (config->configDirs);
Keith Packard's avatar
Keith Packard committed
82
83
bail1:
    free (config);
84
    FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
Keith Packard's avatar
Keith Packard committed
85
86
87
88
bail0:
    return 0;
}

89
90
91
92
93
94
typedef struct _FcFileTime {
    time_t  time;
    FcBool  set;
} FcFileTime;

static FcFileTime
95
96
97
FcConfigNewestFile (FcStrSet *files)
{
    FcStrList	    *list = FcStrListCreate (files);
98
    FcFileTime	    newest = { 0, FcFalse };
99
100
101
102
103
104
105
    FcChar8	    *file;
    struct  stat    statb;

    if (list)
    {
	while ((file = FcStrListNext (list)))
	    if (stat ((char *) file, &statb) == 0)
106
107
		if (!newest.set || statb.st_mtime - newest.time > 0)
		    newest.time = statb.st_mtime;
108
109
110
111
112
113
114
115
	FcStrListDone (list);
    }
    return newest;
}

FcBool
FcConfigUptoDate (FcConfig *config)
{
116
117
    FcFileTime	config_time, font_time;
    time_t	now = time(0);
118
119
120
121
122
123
124
125
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return FcFalse;
    }
    config_time = FcConfigNewestFile (config->configFiles);
    font_time = FcConfigNewestFile (config->configDirs);
126
127
    if ((config_time.set && config_time.time - config->rescanTime > 0) ||
	(font_time.set && font_time.time - config->rescanTime) > 0)
128
129
130
131
132
133
134
    {
	return FcFalse;
    }
    config->rescanTime = now;
    return FcTrue;
}

Keith Packard's avatar
Keith Packard committed
135
136
137
138
139
140
141
142
static void
FcSubstDestroy (FcSubst *s)
{
    FcSubst *n;
    
    while (s)
    {
	n = s->next;
143
144
145
146
	if (s->test)
	    FcTestDestroy (s->test);
	if (s->edit)
	    FcEditDestroy (s->edit);
Keith Packard's avatar
Keith Packard committed
147
148
149
150
151
152
153
154
155
	s = n;
    }
}

void
FcConfigDestroy (FcConfig *config)
{
    FcSetName	set;

156
157
158
159
160
161
162
163
    if (config == _fcConfig)
	_fcConfig = 0;

    FcStrSetDestroy (config->configDirs);
    FcStrSetDestroy (config->fontDirs);
    FcStrSetDestroy (config->configFiles);

    FcStrFree (config->cache);
Keith Packard's avatar
Keith Packard committed
164
165
166
167
168
169

    FcSubstDestroy (config->substPattern);
    FcSubstDestroy (config->substFont);
    for (set = FcSetSystem; set <= FcSetApplication; set++)
	if (config->fonts[set])
	    FcFontSetDestroy (config->fonts[set]);
170
171
    free (config);
    FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
Keith Packard's avatar
Keith Packard committed
172
173
174
175
176
177
178
179
180
181
182
}

/*
 * Scan the current list of directories in the configuration
 * and build the set of available fonts. Update the
 * per-user cache file to reflect the new configuration
 */

FcBool
FcConfigBuildFonts (FcConfig *config)
{
183
184
185
186
    FcFontSet	    *fonts;
    FcGlobalCache   *cache;
    FcStrList	    *list;
    FcChar8	    *dir;
Keith Packard's avatar
Keith Packard committed
187
188
189
190
191

    fonts = FcFontSetCreate ();
    if (!fonts)
	goto bail0;
    
192
    cache = FcGlobalCacheCreate ();
Keith Packard's avatar
Keith Packard committed
193
194
195
    if (!cache)
	goto bail1;

196
    FcGlobalCacheLoad (cache, config->cache);
Keith Packard's avatar
Keith Packard committed
197

198
199
200
201
202
    list = FcConfigGetFontDirs (config);
    if (!list)
	goto bail1;

    while ((dir = FcStrListNext (list)))
Keith Packard's avatar
Keith Packard committed
203
204
    {
	if (FcDebug () & FC_DBG_FONTSET)
205
206
	    printf ("scan dir %s\n", dir);
	FcDirScan (fonts, config->fontDirs, cache, config->blanks, dir, FcFalse);
Keith Packard's avatar
Keith Packard committed
207
208
    }
    
209
210
    FcStrListDone (list);
    
Keith Packard's avatar
Keith Packard committed
211
212
213
    if (FcDebug () & FC_DBG_FONTSET)
	FcFontSetPrint (fonts);

214
215
    FcGlobalCacheSave (cache, config->cache);
    FcGlobalCacheDestroy (cache);
Keith Packard's avatar
Keith Packard committed
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232

    FcConfigSetFonts (config, fonts, FcSetSystem);
    
    return FcTrue;
bail1:
    FcFontSetDestroy (fonts);
bail0:
    return FcFalse;
}

FcBool
FcConfigSetCurrent (FcConfig *config)
{
    if (!config->fonts)
	if (!FcConfigBuildFonts (config))
	    return FcFalse;

233
234
235
    if (_fcConfig)
	FcConfigDestroy (_fcConfig);
    _fcConfig = config;
Keith Packard's avatar
Keith Packard committed
236
237
238
239
240
241
    return FcTrue;
}

FcConfig *
FcConfigGetCurrent (void)
{
242
243
244
245
    if (!_fcConfig)
	if (!FcInit ())
	    return 0;
    return _fcConfig;
Keith Packard's avatar
Keith Packard committed
246
247
248
}

FcBool
249
250
FcConfigAddConfigDir (FcConfig	    *config,
		      const FcChar8 *d)
Keith Packard's avatar
Keith Packard committed
251
{
252
253
    return FcStrSetAddFilename (config->configDirs, d);
}
Keith Packard's avatar
Keith Packard committed
254

255
256
257
258
FcStrList *
FcConfigGetConfigDirs (FcConfig   *config)
{
    if (!config)
Keith Packard's avatar
Keith Packard committed
259
    {
260
261
262
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
Keith Packard's avatar
Keith Packard committed
263
    }
264
265
266
267
268
269
270
271
    return FcStrListCreate (config->configDirs);
}

FcBool
FcConfigAddFontDir (FcConfig	    *config,
		    const FcChar8   *d)
{
    return FcStrSetAddFilename (config->fontDirs, d);
Keith Packard's avatar
Keith Packard committed
272
273
}

274
275
276
277
278
279
280
281
282
283
FcBool
FcConfigAddDir (FcConfig	    *config,
		const FcChar8	    *d)
{
    return (FcConfigAddConfigDir (config, d) && 
	    FcConfigAddFontDir (config, d));
}

FcStrList *
FcConfigGetFontDirs (FcConfig	*config)
Keith Packard's avatar
Keith Packard committed
284
285
286
287
288
289
290
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
    }
291
    return FcStrListCreate (config->fontDirs);
Keith Packard's avatar
Keith Packard committed
292
293
294
295
}

FcBool
FcConfigAddConfigFile (FcConfig	    *config,
296
		       const FcChar8   *f)
Keith Packard's avatar
Keith Packard committed
297
{
298
299
300
    FcBool	ret;
    FcChar8	*file = FcConfigFilename (f);
    
Keith Packard's avatar
Keith Packard committed
301
302
    if (!file)
	return FcFalse;
303
304
305
306
    
    ret = FcStrSetAdd (config->configFiles, file);
    FcStrFree (file);
    return ret;
Keith Packard's avatar
Keith Packard committed
307
308
}

309
FcStrList *
Keith Packard's avatar
Keith Packard committed
310
311
312
313
314
315
316
317
FcConfigGetConfigFiles (FcConfig    *config)
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
    }
318
    return FcStrListCreate (config->configFiles);
Keith Packard's avatar
Keith Packard committed
319
320
321
322
}

FcBool
FcConfigSetCache (FcConfig	*config,
323
		  const FcChar8	*c)
Keith Packard's avatar
Keith Packard committed
324
{
325
326
327
328
    FcChar8    *new = FcStrCopyFilename (c);
    
    if (!new)
	return FcFalse;
Keith Packard's avatar
Keith Packard committed
329
    if (config->cache)
330
	FcStrFree (config->cache);
Keith Packard's avatar
Keith Packard committed
331
332
333
334
    config->cache = new;
    return FcTrue;
}

335
FcChar8 *
Keith Packard's avatar
Keith Packard committed
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
FcConfigGetCache (FcConfig  *config)
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
    }
    return config->cache;
}

FcFontSet *
FcConfigGetFonts (FcConfig	*config,
		  FcSetName	set)
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
    }
    return config->fonts[set];
}

void
FcConfigSetFonts (FcConfig	*config,
		  FcFontSet	*fonts,
		  FcSetName	set)
{
    if (config->fonts[set])
	FcFontSetDestroy (config->fonts[set]);
    config->fonts[set] = fonts;
}

370
371


Keith Packard's avatar
Keith Packard committed
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
FcBlanks *
FcConfigGetBlanks (FcConfig	*config)
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
    }
    return config->blanks;
}

FcBool
FcConfigAddBlank (FcConfig	*config,
		  FcChar32    	blank)
{
    FcBlanks	*b;
    
    b = config->blanks;
    if (!b)
    {
	b = FcBlanksCreate ();
	if (!b)
	    return FcFalse;
    }
    if (!FcBlanksAdd (b, blank))
	return FcFalse;
    config->blanks = b;
    return FcTrue;
}

403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
int
FcConfigGetRescanInverval (FcConfig *config)
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
    }
    return config->rescanInterval;
}

FcBool
FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return FcFalse;
    }
    config->rescanInterval = rescanInterval;
    return FcTrue;
}

Keith Packard's avatar
Keith Packard committed
428
429
430
431
432
433
434
435
436
437
438
439
440
FcBool
FcConfigAddEdit (FcConfig	*config,
		 FcTest		*test,
		 FcEdit		*edit,
		 FcMatchKind	kind)
{
    FcSubst	*subst, **prev;
    FcTest	*t;
    int		num;

    subst = (FcSubst *) malloc (sizeof (FcSubst));
    if (!subst)
	return FcFalse;
441
    FcMemAlloc (FC_MEM_SUBST, sizeof (FcSubst));
Keith Packard's avatar
Keith Packard committed
442
443
444
445
446
447
448
449
450
451
452
    if (kind == FcMatchPattern)
	prev = &config->substPattern;
    else
	prev = &config->substFont;
    for (; *prev; prev = &(*prev)->next);
    *prev = subst;
    subst->next = 0;
    subst->test = test;
    subst->edit = edit;
    num = 0;
    for (t = test; t; t = t->next)
453
454
455
    {
	if (t->kind == FcMatchDefault)
	    t->kind = kind;
Keith Packard's avatar
Keith Packard committed
456
	num++;
457
    }
Keith Packard's avatar
Keith Packard committed
458
459
    if (config->maxObjects < num)
	config->maxObjects = num;
460
461
462
463
464
    if (FcDebug () & FC_DBG_EDIT)
    {
	printf ("Add Subst ");
	FcSubstPrint (subst);
    }
Keith Packard's avatar
Keith Packard committed
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
    return FcTrue;
}

typedef struct _FcSubState {
    FcPatternElt   *elt;
    FcValueList    *value;
} FcSubState;

static FcValue
FcConfigPromote (FcValue v, FcValue u)
{
    if (v.type == FcTypeInteger)
    {
	v.type = FcTypeDouble;
	v.u.d = (double) v.u.i;
    }
    else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
    {
483
484
	v.u.m = &FcIdentityMatrix;
	v.type = FcTypeMatrix;
Keith Packard's avatar
Keith Packard committed
485
    }
486
487
488
489
490
    else if (v.type == FcTypeString && u.type == FcTypeLangSet)
    {
	v.u.l = FcLangSetPromote (v.u.s);
	v.type = FcTypeLangSet;
    }
Keith Packard's avatar
Keith Packard committed
491
492
493
494
    return v;
}

FcBool
495
496
497
FcConfigCompareValue (const FcValue	m_o,
		      FcOp		op,
		      const FcValue	v_o)
Keith Packard's avatar
Keith Packard committed
498
{
499
500
501
    FcValue	m = m_o;
    FcValue	v = v_o;
    FcBool	ret = FcFalse;
Keith Packard's avatar
Keith Packard committed
502
503
504
505
506
507
508
509
510
511
512
513
514
515
    
    m = FcConfigPromote (m, v);
    v = FcConfigPromote (v, m);
    if (m.type == v.type) 
    {
	switch (m.type) {
	case FcTypeInteger:
	    break;	/* FcConfigPromote prevents this from happening */
	case FcTypeDouble:
	    switch (op) {
	    case FcOpEqual:
	    case FcOpContains:
		ret = m.u.d == v.u.d;
		break;
516
517
	    case FcOpNotEqual:
	    case FcOpNotContains:
Keith Packard's avatar
Keith Packard committed
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
		ret = m.u.d != v.u.d;
		break;
	    case FcOpLess:    
		ret = m.u.d < v.u.d;
		break;
	    case FcOpLessEqual:    
		ret = m.u.d <= v.u.d;
		break;
	    case FcOpMore:    
		ret = m.u.d > v.u.d;
		break;
	    case FcOpMoreEqual:    
		ret = m.u.d >= v.u.d;
		break;
	    default:
		break;
	    }
	    break;
	case FcTypeBool:
	    switch (op) {
	    case FcOpEqual:    
	    case FcOpContains:
		ret = m.u.b == v.u.b;
		break;
542
543
	    case FcOpNotEqual:
	    case FcOpNotContains:
Keith Packard's avatar
Keith Packard committed
544
545
546
547
548
549
550
551
552
553
554
555
		ret = m.u.b != v.u.b;
		break;
	    default:
		break;
	    }
	    break;
	case FcTypeString:
	    switch (op) {
	    case FcOpEqual:    
	    case FcOpContains:
		ret = FcStrCmpIgnoreCase (m.u.s, v.u.s) == 0;
		break;
556
557
	    case FcOpNotEqual:
	    case FcOpNotContains:
Keith Packard's avatar
Keith Packard committed
558
559
560
561
562
563
564
565
566
567
568
569
570
		ret = FcStrCmpIgnoreCase (m.u.s, v.u.s) != 0;
		break;
	    default:
		break;
	    }
	    break;
	case FcTypeMatrix:
	    switch (op) {
	    case FcOpEqual:
	    case FcOpContains:
		ret = FcMatrixEqual (m.u.m, v.u.m);
		break;
	    case FcOpNotEqual:
571
	    case FcOpNotContains:
Keith Packard's avatar
Keith Packard committed
572
573
574
575
576
577
578
579
580
		ret = !FcMatrixEqual (m.u.m, v.u.m);
		break;
	    default:
		break;
	    }
	    break;
	case FcTypeCharSet:
	    switch (op) {
	    case FcOpContains:
581
582
		/* m contains v if v is a subset of m */
		ret = FcCharSetIsSubset (v.u.c, m.u.c);
Keith Packard's avatar
Keith Packard committed
583
		break;
584
585
586
587
	    case FcOpNotContains:
		/* m contains v if v is a subset of m */
		ret = !FcCharSetIsSubset (v.u.c, m.u.c);
		break;
Keith Packard's avatar
Keith Packard committed
588
589
590
591
592
593
594
595
596
597
	    case FcOpEqual:
		ret = FcCharSetEqual (m.u.c, v.u.c);
		break;
	    case FcOpNotEqual:
		ret = !FcCharSetEqual (m.u.c, v.u.c);
		break;
	    default:
		break;
	    }
	    break;
598
599
600
	case FcTypeLangSet:
	    switch (op) {
	    case FcOpContains:
601
		ret = FcLangSetContains (v.u.l, m.u.l);
602
		break;
603
	    case FcOpNotContains:
604
		ret = FcLangSetContains (v.u.l, m.u.l);
605
		break;
606
607
608
609
610
611
612
613
614
615
	    case FcOpEqual:
		ret = FcLangSetEqual (v.u.l, m.u.l);
		break;
	    case FcOpNotEqual:
		ret = !FcLangSetEqual (v.u.l, m.u.l);
		break;
	    default:
		break;
	    }
	    break;
Keith Packard's avatar
Keith Packard committed
616
617
618
619
620
621
622
623
624
625
	case FcTypeVoid:
	    switch (op) {
	    case FcOpEqual:
	    case FcOpContains:
		ret = FcTrue;
		break;
	    default:
		break;
	    }
	    break;
626
627
628
	case FcTypeFTFace:
	    switch (op) {
	    case FcOpEqual:
629
	    case FcOpContains:
630
631
632
		ret = m.u.f == v.u.f;
		break;
	    case FcOpNotEqual:
633
	    case FcOpNotContains:
634
635
636
637
638
		ret = m.u.f != v.u.f;
		break;
	    default:
		break;
	    }
639
	    break;
Keith Packard's avatar
Keith Packard committed
640
641
642
643
	}
    }
    else
    {
644
	if (op == FcOpNotEqual || op == FcOpNotContains)
Keith Packard's avatar
Keith Packard committed
645
646
647
648
649
650
	    ret = FcTrue;
    }
    return ret;
}


651
652
653
654
655
656
657
#define _FcDoubleFloor(d)	((int) (d))
#define _FcDoubleCeil(d)	((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
#define FcDoubleFloor(d)	((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
#define FcDoubleCeil(d)		((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
#define FcDoubleRound(d)	FcDoubleFloor ((d) + 0.5)
#define FcDoubleTrunc(d)	((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))

Keith Packard's avatar
Keith Packard committed
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
static FcValue
FcConfigEvaluate (FcPattern *p, FcExpr *e)
{
    FcValue	v, vl, vr;
    FcResult	r;
    FcMatrix	*m;
    
    switch (e->op) {
    case FcOpInteger:
	v.type = FcTypeInteger;
	v.u.i = e->u.ival;
	break;
    case FcOpDouble:
	v.type = FcTypeDouble;
	v.u.d = e->u.dval;
	break;
    case FcOpString:
	v.type = FcTypeString;
	v.u.s = e->u.sval;
	v = FcValueSave (v);
	break;
    case FcOpMatrix:
	v.type = FcTypeMatrix;
	v.u.m = e->u.mval;
	v = FcValueSave (v);
	break;
    case FcOpCharSet:
	v.type = FcTypeCharSet;
	v.u.c = e->u.cval;
	v = FcValueSave (v);
	break;
    case FcOpBool:
	v.type = FcTypeBool;
	v.u.b = e->u.bval;
	break;
    case FcOpField:
	r = FcPatternGet (p, e->u.field, 0, &v);
	if (r != FcResultMatch)
	    v.type = FcTypeVoid;
	break;
    case FcOpConst:
	if (FcNameConstant (e->u.constant, &v.u.i))
	    v.type = FcTypeInteger;
	else
	    v.type = FcTypeVoid;
	break;
    case FcOpQuest:
	vl = FcConfigEvaluate (p, e->u.tree.left);
	if (vl.type == FcTypeBool)
	{
	    if (vl.u.b)
		v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
	    else
		v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
	}
	else
	    v.type = FcTypeVoid;
	FcValueDestroy (vl);
	break;
717
    case FcOpEqual:
Keith Packard's avatar
Keith Packard committed
718
719
720
721
722
    case FcOpNotEqual:
    case FcOpLess:
    case FcOpLessEqual:
    case FcOpMore:
    case FcOpMoreEqual:
723
724
    case FcOpContains:
    case FcOpNotContains:
725
726
727
728
729
730
731
732
733
	vl = FcConfigEvaluate (p, e->u.tree.left);
	vr = FcConfigEvaluate (p, e->u.tree.right);
	v.type = FcTypeBool;
	v.u.b = FcConfigCompareValue (vl, e->op, vr);
	FcValueDestroy (vl);
	FcValueDestroy (vr);
	break;	
    case FcOpOr:
    case FcOpAnd:
Keith Packard's avatar
Keith Packard committed
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
    case FcOpPlus:
    case FcOpMinus:
    case FcOpTimes:
    case FcOpDivide:
	vl = FcConfigEvaluate (p, e->u.tree.left);
	vr = FcConfigEvaluate (p, e->u.tree.right);
	vl = FcConfigPromote (vl, vr);
	vr = FcConfigPromote (vr, vl);
	if (vl.type == vr.type)
	{
	    switch (vl.type) {
	    case FcTypeDouble:
		switch (e->op) {
		case FcOpPlus:	   
		    v.type = FcTypeDouble;
		    v.u.d = vl.u.d + vr.u.d; 
		    break;
		case FcOpMinus:
		    v.type = FcTypeDouble;
		    v.u.d = vl.u.d - vr.u.d; 
		    break;
		case FcOpTimes:
		    v.type = FcTypeDouble;
		    v.u.d = vl.u.d * vr.u.d; 
		    break;
		case FcOpDivide:
		    v.type = FcTypeDouble;
		    v.u.d = vl.u.d / vr.u.d; 
		    break;
		default:
		    v.type = FcTypeVoid; 
		    break;
		}
		if (v.type == FcTypeDouble &&
		    v.u.d == (double) (int) v.u.d)
		{
		    v.type = FcTypeInteger;
		    v.u.i = (int) v.u.d;
		}
		break;
	    case FcTypeBool:
		switch (e->op) {
		case FcOpOr:
		    v.type = FcTypeBool;
		    v.u.b = vl.u.b || vr.u.b;
		    break;
		case FcOpAnd:
		    v.type = FcTypeBool;
		    v.u.b = vl.u.b && vr.u.b;
		    break;
		default:
		    v.type = FcTypeVoid; 
		    break;
		}
		break;
	    case FcTypeString:
		switch (e->op) {
		case FcOpPlus:
		    v.type = FcTypeString;
		    v.u.s = FcStrPlus (vl.u.s, vr.u.s);
		    if (!v.u.s)
			v.type = FcTypeVoid;
		    break;
		default:
		    v.type = FcTypeVoid;
		    break;
		}
801
		break;
Keith Packard's avatar
Keith Packard committed
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
	    case FcTypeMatrix:
		switch (e->op) {
		case FcOpTimes:
		    v.type = FcTypeMatrix;
		    m = malloc (sizeof (FcMatrix));
		    if (m)
		    {
			FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
			FcMatrixMultiply (m, vl.u.m, vr.u.m);
			v.u.m = m;
		    }
		    else
		    {
			v.type = FcTypeVoid;
		    }
		    break;
		default:
		    v.type = FcTypeVoid;
		    break;
		}
		break;
	    default:
		v.type = FcTypeVoid;
		break;
	    }
	}
	else
	    v.type = FcTypeVoid;
	FcValueDestroy (vl);
	FcValueDestroy (vr);
	break;
    case FcOpNot:
	vl = FcConfigEvaluate (p, e->u.tree.left);
	switch (vl.type) {
	case FcTypeBool:
	    v.type = FcTypeBool;
	    v.u.b = !vl.u.b;
	    break;
	default:
	    v.type = FcTypeVoid;
	    break;
	}
	FcValueDestroy (vl);
	break;
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
    case FcOpFloor:
	vl = FcConfigEvaluate (p, e->u.tree.left);
	switch (vl.type) {
	case FcTypeInteger:
	    v = vl;
	    break;
	case FcTypeDouble:
	    v.type = FcTypeInteger;
	    v.u.i = FcDoubleFloor (vl.u.d);
	    break;
	default:
	    v.type = FcTypeVoid;
	    break;
	}
	FcValueDestroy (vl);
	break;
    case FcOpCeil:
	vl = FcConfigEvaluate (p, e->u.tree.left);
	switch (vl.type) {
	case FcTypeInteger:
	    v = vl;
	    break;
	case FcTypeDouble:
	    v.type = FcTypeInteger;
	    v.u.i = FcDoubleCeil (vl.u.d);
	    break;
	default:
	    v.type = FcTypeVoid;
	    break;
	}
	FcValueDestroy (vl);
	break;
    case FcOpRound:
	vl = FcConfigEvaluate (p, e->u.tree.left);
	switch (vl.type) {
	case FcTypeInteger:
	    v = vl;
	    break;
	case FcTypeDouble:
	    v.type = FcTypeInteger;
	    v.u.i = FcDoubleRound (vl.u.d);
	    break;
	default:
	    v.type = FcTypeVoid;
	    break;
	}
	FcValueDestroy (vl);
	break;
    case FcOpTrunc:
	vl = FcConfigEvaluate (p, e->u.tree.left);
	switch (vl.type) {
	case FcTypeInteger:
	    v = vl;
	    break;
	case FcTypeDouble:
	    v.type = FcTypeInteger;
	    v.u.i = FcDoubleTrunc (vl.u.d);
	    break;
	default:
	    v.type = FcTypeVoid;
	    break;
	}
	FcValueDestroy (vl);
	break;
Keith Packard's avatar
Keith Packard committed
910
911
912
913
914
915
916
917
918
919
    default:
	v.type = FcTypeVoid;
	break;
    }
    return v;
}

static FcValueList *
FcConfigMatchValueList (FcPattern	*p,
			FcTest		*t,
920
			FcValueList	*values)
Keith Packard's avatar
Keith Packard committed
921
{
922
923
924
    FcValueList	    *ret = 0;
    FcExpr	    *e = t->expr;
    FcValue	    value;
925
    FcValueList	    *v;
Keith Packard's avatar
Keith Packard committed
926
    
927
    while (e)
Keith Packard's avatar
Keith Packard committed
928
    {
929
	if (e->op == FcOpComma)
Keith Packard's avatar
Keith Packard committed
930
	{
931
932
	    value = FcConfigEvaluate (p, e->u.tree.left);
	    e = e->u.tree.right;
Keith Packard's avatar
Keith Packard committed
933
934
935
	}
	else
	{
936
937
938
939
	    value = FcConfigEvaluate (p, e);
	    e = 0;
	}

940
	for (v = values; v; v = v->next)
941
942
	{
	    if (FcConfigCompareValue (v->value, t->op, value))
Keith Packard's avatar
Keith Packard committed
943
	    {
944
945
946
947
948
949
950
951
952
953
		if (!ret)
		    ret = v;
	    }
	    else
	    {
		if (t->qual == FcQualAll)
		{
		    ret = 0;
		    break;
		}
Keith Packard's avatar
Keith Packard committed
954
955
	    }
	}
956
	FcValueDestroy (value);
Keith Packard's avatar
Keith Packard committed
957
958
959
960
961
    }
    return ret;
}

static FcValueList *
962
FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding)
Keith Packard's avatar
Keith Packard committed
963
964
965
966
967
968
969
970
971
972
973
974
{
    FcValueList	*l;
    
    if (!e)
	return 0;
    l = (FcValueList *) malloc (sizeof (FcValueList));
    if (!l)
	return 0;
    FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
    if (e->op == FcOpComma)
    {
	l->value = FcConfigEvaluate (p, e->u.tree.left);
975
	l->next  = FcConfigValues (p, e->u.tree.right, binding);
Keith Packard's avatar
Keith Packard committed
976
977
978
979
980
981
    }
    else
    {
	l->value = FcConfigEvaluate (p, e);
	l->next  = 0;
    }
982
    l->binding = binding;
983
    while (l && l->value.type == FcTypeVoid)
Keith Packard's avatar
Keith Packard committed
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
    {
	FcValueList	*next = l->next;
	
	FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
	free (l);
	l = next;
    }
    return l;
}

static FcBool
FcConfigAdd (FcValueList    **head,
	     FcValueList    *position,
	     FcBool	    append,
	     FcValueList    *new)
{
1000
1001
    FcValueList	    **prev, *last, *v;
    FcValueBinding  sameBinding;
Keith Packard's avatar
Keith Packard committed
1002
    
1003
1004
1005
1006
1007
1008
1009
    if (position)
	sameBinding = position->binding;
    else
	sameBinding = FcValueBindingWeak;
    for (v = new; v; v = v->next)
	if (v->binding == FcValueBindingSame)
	    v->binding = sameBinding;
Keith Packard's avatar
Keith Packard committed
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
    if (append)
    {
	if (position)
	    prev = &position->next;
	else
	    for (prev = head; *prev; prev = &(*prev)->next)
		;
    }
    else
    {
	if (position)
	{
	    for (prev = head; *prev; prev = &(*prev)->next)
	    {
		if (*prev == position)
		    break;
	    }
	}
	else
	    prev = head;

	if (FcDebug () & FC_DBG_EDIT)
	{
	    if (!*prev)
		printf ("position not on list\n");
	}
    }

    if (FcDebug () & FC_DBG_EDIT)
    {
	printf ("%s list before ", append ? "Append" : "Prepend");
	FcValueListPrint (*head);
	printf ("\n");
    }
    
    if (new)
    {
	last = new;
	while (last->next)
	    last = last->next;
    
	last->next = *prev;
	*prev = new;
    }
    
    if (FcDebug () & FC_DBG_EDIT)
    {
	printf ("%s list after ", append ? "Append" : "Prepend");
	FcValueListPrint (*head);
	printf ("\n");
    }
    
    return FcTrue;
}

static void
FcConfigDel (FcValueList    **head,
	     FcValueList    *position)
{
    FcValueList    **prev;

    for (prev = head; *prev; prev = &(*prev)->next)
    {
	if (*prev == position)
	{
	    *prev = position->next;
	    position->next = 0;
	    FcValueListDestroy (position);
	    break;
	}
    }
}

static void
FcConfigPatternAdd (FcPattern	*p,
		    const char	*object,
		    FcValueList	*list,
		    FcBool	append)
{
    if (list)
    {
1091
	FcPatternElt    *e = FcPatternInsertElt (p, object);
Keith Packard's avatar
Keith Packard committed
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
    
	if (!e)
	    return;
	FcConfigAdd (&e->values, 0, append, list);
    }
}

/*
 * Delete all values associated with a field
 */
static void
FcConfigPatternDel (FcPattern	*p,
		    const char	*object)
{
1106
    FcPatternElt    *e = FcPatternFindElt (p, object);
Keith Packard's avatar
Keith Packard committed
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
    if (!e)
	return;
    while (e->values)
	FcConfigDel (&e->values, e->values);
}

static void
FcConfigPatternCanon (FcPattern	    *p,
		      const char    *object)
{
1117
    FcPatternElt    *e = FcPatternFindElt (p, object);
Keith Packard's avatar
Keith Packard committed
1118
1119
1120
1121
1122
1123
1124
    if (!e)
	return;
    if (!e->values)
	FcPatternDel (p, object);
}

FcBool
1125
1126
1127
1128
FcConfigSubstituteWithPat (FcConfig    *config,
			   FcPattern   *p,
			   FcPattern   *p_pat,
			   FcMatchKind kind)
Keith Packard's avatar
Keith Packard committed
1129
1130
1131
1132
1133
1134
1135
{
    FcSubst	    *s;
    FcSubState	    *st;
    int		    i;
    FcTest	    *t;
    FcEdit	    *e;
    FcValueList	    *l;
1136
    FcPattern	    *m;
Keith Packard's avatar
Keith Packard committed
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171

    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return FcFalse;
    }

    st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
    if (!st && config->maxObjects)
	return FcFalse;
    FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));

    if (FcDebug () & FC_DBG_EDIT)
    {
	printf ("FcConfigSubstitute ");
	FcPatternPrint (p);
    }
    if (kind == FcMatchPattern)
	s = config->substPattern;
    else
	s = config->substFont;
    for (; s; s = s->next)
    {
	/*
	 * Check the tests to see if
	 * they all match the pattern
	 */
	for (t = s->test, i = 0; t; t = t->next, i++)
	{
	    if (FcDebug () & FC_DBG_EDIT)
	    {
		printf ("FcConfigSubstitute test ");
		FcTestPrint (t);
	    }
1172
1173
1174
1175
1176
1177
1178
1179
1180
	    st[i].elt = 0;
	    if (kind == FcMatchFont && t->kind == FcMatchPattern)
		m = p_pat;
	    else
		m = p;
	    if (m)
		st[i].elt = FcPatternFindElt (m, t->field);
	    else
		st[i].elt = 0;
Keith Packard's avatar
Keith Packard committed
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
	    /*
	     * If there's no such field in the font,
	     * then FcQualAll matches while FcQualAny does not
	     */
	    if (!st[i].elt)
	    {
		if (t->qual == FcQualAll)
		{
		    st[i].value = 0;
		    continue;
		}
		else
		    break;
	    }
	    /*
	     * Check to see if there is a match, mark the location
	     * to apply match-relative edits
	     */
1199
	    st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values);
Keith Packard's avatar
Keith Packard committed
1200
1201
	    if (!st[i].value)
		break;
1202
1203
1204
1205
	    if (t->qual == FcQualFirst && st[i].value != st[i].elt->values)
		break;
	    if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values)
		break;
Keith Packard's avatar
Keith Packard committed
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
	}
	if (t)
	{
	    if (FcDebug () & FC_DBG_EDIT)
		printf ("No match\n");
	    continue;
	}
	if (FcDebug () & FC_DBG_EDIT)
	{
	    printf ("Substitute ");
	    FcSubstPrint (s);
	}
	for (e = s->edit; e; e = e->next)
	{
	    /*
	     * Evaluate the list of expressions
	     */
1223
	    l = FcConfigValues (p, e->expr, e->binding);
Keith Packard's avatar
Keith Packard committed
1224
	    /*
1225
1226
1227
	     * Locate any test associated with this field, skipping
	     * tests associated with the pattern when substituting in
	     * the font
Keith Packard's avatar
Keith Packard committed
1228
1229
	     */
	    for (t = s->test, i = 0; t; t = t->next, i++)
1230
1231
1232
1233
	    {
		if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
		    !FcStrCmpIgnoreCase ((FcChar8 *) t->field, 
					 (FcChar8 *) e->field))
1234
1235
1236
		{
		    if (!st[i].elt)
			t = 0;
Keith Packard's avatar
Keith Packard committed
1237
		    break;
1238
		}
1239
	    }
Keith Packard's avatar
Keith Packard committed
1240
1241
1242
1243
1244
1245
	    switch (e->op) {
	    case FcOpAssign:
		/*
		 * If there was a test, then replace the matched
		 * value with the new list of values
		 */
1246
		if (t)
Keith Packard's avatar
Keith Packard committed
1247
1248
1249
1250
1251
1252
1253
1254
		{
		    FcValueList	*thisValue = st[i].value;
		    FcValueList	*nextValue = thisValue ? thisValue->next : 0;
		    
		    /*
		     * Append the new list of values after the current value
		     */
		    FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
1255
1256
1257
1258
		    /*
		     * Delete the marked value
		     */
		    FcConfigDel (&st[i].elt->values, thisValue);
Keith Packard's avatar
Keith Packard committed
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
		    /*
		     * Adjust any pointers into the value list to ensure
		     * future edits occur at the same place
		     */
		    for (t = s->test, i = 0; t; t = t->next, i++)
		    {
			if (st[i].value == thisValue)
			    st[i].value = nextValue;
		    }
		    break;
		}
		/* fall through ... */
	    case FcOpAssignReplace:
		/*
		 * Delete all of the values and insert
		 * the new set
		 */
		FcConfigPatternDel (p, e->field);
		FcConfigPatternAdd (p, e->field, l, FcTrue);
		/*
		 * Adjust any pointers into the value list as they no
		 * longer point to anything valid
		 */
		if (t)
		{
		    FcPatternElt    *thisElt = st[i].elt;
		    for (t = s->test, i = 0; t; t = t->next, i++)
		    {
			if (st[i].elt == thisElt)
			    st[i].value = 0;
		    }
		}
		break;
	    case FcOpPrepend:
		if (t)
		{
		    FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
		    break;
		}
		/* fall through ... */
	    case FcOpPrependFirst:
		FcConfigPatternAdd (p, e->field, l, FcFalse);
		break;
	    case FcOpAppend:
		if (t)
		{
		    FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
		    break;
		}
		/* fall through ... */
	    case FcOpAppendLast:
		FcConfigPatternAdd (p, e->field, l, FcTrue);
		break;
	    default:
		break;
	    }
	}
	/*
	 * Now go through the pattern and eliminate
	 * any properties without data
	 */
	for (e = s->edit; e; e = e->next)
	    FcConfigPatternCanon (p, e->field);

	if (FcDebug () & FC_DBG_EDIT)
	{
	    printf ("FcConfigSubstitute edit");
	    FcPatternPrint (p);
	}
    }
    FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
    free (st);
    if (FcDebug () & FC_DBG_EDIT)
    {
	printf ("FcConfigSubstitute done");
	FcPatternPrint (p);
    }
    return FcTrue;
}

1339
1340
1341
1342
1343
1344
1345
1346
FcBool
FcConfigSubstitute (FcConfig	*config,
		    FcPattern	*p,
		    FcMatchKind	kind)
{
    return FcConfigSubstituteWithPat (config, p, 0, kind);
}

Tor Lillqvist's avatar
Tor Lillqvist committed
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
#if defined (_WIN32) && defined (PIC)

static FcChar8 fontconfig_path[1000] = "";

BOOL WINAPI
DllMain (HINSTANCE hinstDLL,
	 DWORD     fdwReason,
	 LPVOID    lpvReserved)
{
  FcChar8 *p;

  switch (fdwReason) {
  case DLL_PROCESS_ATTACH:
      if (!GetModuleFileName ((HMODULE) hinstDLL, fontconfig_path,
			      sizeof (fontconfig_path)))
	  break;

      /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
       * assume it's a Unix-style installation tree, and use
       * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
       * folder where the DLL is as FONTCONFIG_PATH.
       */
      p = strrchr (fontconfig_path, '\\');
      if (p)
      {
	  *p = '\0';
	  p = strrchr (fontconfig_path, '\\');
	  if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 ||
		    FcStrCmpIgnoreCase (p + 1, "lib") == 0))
	      *p = '\0';
	  strcat (fontconfig_path, "\\etc\\fonts");
      }
      else
          fontconfig_path[0] = '\0';
      
      break;
  }

  return TRUE;
}

#undef FONTCONFIG_PATH
#define FONTCONFIG_PATH fontconfig_path

#else /* !(_WIN32 && PIC) */

#endif /* !(_WIN32 && PIC) */

Keith Packard's avatar
Keith Packard committed
1395
1396
1397
1398
#ifndef FONTCONFIG_FILE
#define FONTCONFIG_FILE	"fonts.conf"
#endif

1399
1400
static FcChar8 *
FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
Keith Packard's avatar
Keith Packard committed
1401
{
1402
    FcChar8    *path;
Keith Packard's avatar
Keith Packard committed
1403
1404

    if (!dir)
1405
1406
	dir = (FcChar8 *) "";
    path = malloc (strlen ((char *) dir) + 1 + strlen ((char *) file) + 1);
Keith Packard's avatar
Keith Packard committed
1407
1408
1409
    if (!path)
	return 0;

Keith Packard's avatar
Keith Packard committed
1410
    strcpy ((char *) path, (const char *) dir);
Tor Lillqvist's avatar
Tor Lillqvist committed
1411
1412
1413
1414
1415
1416
1417
    /* make sure there's a single separator */
#ifdef _WIN32
    if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
		      path[strlen((char *) path)-1] != '\\')) &&
	 (file[0] != '/' && file[0] != '\\'))
	strcat ((char *) path, "\\");
#else
1418
1419
    if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
	strcat ((char *) path, "/");
Tor Lillqvist's avatar
Tor Lillqvist committed
1420
#endif
1421
    strcat ((char *) path, (char *) file);
Keith Packard's avatar
Keith Packard committed
1422

1423
    FcMemAlloc (FC_MEM_STRING, strlen ((char *) path) + 1);
1424
    if (access ((char *) path, R_OK) == 0)
Keith Packard's avatar
Keith Packard committed
1425
1426
	return path;
    
1427
    FcStrFree (path);
Keith Packard's avatar
Keith Packard committed
1428
1429
1430
    return 0;
}

1431
static FcChar8 **
Keith Packard's avatar
Keith Packard committed
1432
1433
FcConfigGetPath (void)
{
1434
1435
1436
    FcChar8    **path;
    FcChar8    *env, *e, *colon;
    FcChar8    *dir;
Keith Packard's avatar
Keith Packard committed
1437
1438
1439
1440
    int	    npath;
    int	    i;

    npath = 2;	/* default dir + null */
1441
    env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
Keith Packard's avatar
Keith Packard committed
1442
1443
1444
1445
1446
    if (env)
    {
	e = env;
	npath++;
	while (*e)
Tor Lillqvist's avatar
Tor Lillqvist committed
1447
	    if (*e++ == FC_SEARCH_PATH_SEPARATOR)
Keith Packard's avatar
Keith Packard committed
1448
1449
		npath++;
    }
1450
    path = calloc (npath, sizeof (FcChar8 *));
Keith Packard's avatar
Keith Packard committed
1451
1452
1453
1454
1455
1456
1457
1458
1459
    if (!path)
	goto bail0;
    i = 0;

    if (env)
    {
	e = env;
	while (*e) 
	{
Tor Lillqvist's avatar
Tor Lillqvist committed
1460
	    colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
Keith Packard's avatar
Keith Packard committed
1461
	    if (!colon)
1462
		colon = e + strlen ((char *) e);
Keith Packard's avatar
Keith Packard committed
1463
1464
1465
	    path[i] = malloc (colon - e + 1);
	    if (!path[i])
		goto bail1;
Keith Packard's avatar
Keith Packard committed
1466
	    strncpy ((char *) path[i], (const char *) e, colon - e);
Keith Packard's avatar
Keith Packard committed
1467
1468
1469
1470
1471
1472
1473
1474
1475
	    path[i][colon - e] = '\0';
	    if (*colon)
		e = colon + 1;
	    else
		e = colon;
	    i++;
	}
    }
    
1476
1477
    dir = (FcChar8 *) FONTCONFIG_PATH;
    path[i] = malloc (strlen ((char *) dir) + 1);
Keith Packard's avatar
Keith Packard committed
1478
1479
    if (!path[i])
	goto bail1;
Keith Packard's avatar
Keith Packard committed
1480
    strcpy ((char *) path[i], (const char *) dir);
Keith Packard's avatar
Keith Packard committed
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
    return path;

bail1:
    for (i = 0; path[i]; i++)
	free (path[i]);
    free (path);
bail0:
    return 0;
}

static void
1492
FcConfigFreePath (FcChar8 **path)
Keith Packard's avatar
Keith Packard committed
1493
{
1494
    FcChar8    **p;
Keith Packard's avatar
Keith Packard committed
1495
1496
1497
1498
1499
1500

    for (p = path; *p; p++)
	free (*p);
    free (path);
}

1501
1502
1503
1504
1505
1506
static FcBool	_FcConfigHomeEnabled = FcTrue;

FcChar8 *
FcConfigHome (void)
{
    if (_FcConfigHomeEnabled)
Tor Lillqvist's avatar
Tor Lillqvist committed
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
    {
        char *home = getenv ("HOME");

#ifdef _WIN32
	if (home == NULL)
	    home = getenv ("USERPROFILE");
#endif

	return home;
    }
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
    return 0;
}

FcBool
FcConfigEnableHome (FcBool enable)
{
    FcBool  prev = _FcConfigHomeEnabled;
    _FcConfigHomeEnabled = enable;
    return prev;
}

1528
1529
FcChar8 *
FcConfigFilename (const FcChar8 *url)
Keith Packard's avatar
Keith Packard committed
1530
{
1531
    FcChar8    *file, *dir, **path, **p;
Keith Packard's avatar
Keith Packard committed
1532
1533
1534
    
    if (!url || !*url)
    {
1535
	url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
Keith Packard's avatar
Keith Packard committed
1536
	if (!url)
1537
	    url = (FcChar8 *) FONTCONFIG_FILE;
Keith Packard's avatar
Keith Packard committed
1538
    }
1539
    file = 0;
Tor Lillqvist's avatar
Tor Lillqvist committed
1540
1541
1542
1543
1544
1545
1546
1547

#ifdef _WIN32
    if (isalpha (*url) &&
	url[1] == ':' &&
	(url[2] == '/' || url[2] == '\\'))
	goto absolute_path;
#endif

Keith Packard's avatar
Keith Packard committed
1548
1549
    switch (*url) {
    case '~':
1550
	dir = FcConfigHome ();
Keith Packard's avatar
Keith Packard committed
1551
1552
1553
1554
1555
	if (dir)
	    file = FcConfigFileExists (dir, url + 1);
	else
	    file = 0;
	break;
Tor Lillqvist's avatar
Tor Lillqvist committed
1556
1557
1558
1559
#ifdef _WIN32
    case '\\':
    absolute_path:
#endif
Keith Packard's avatar
Keith Packard committed
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
    case '/':
	file = FcConfigFileExists (0, url);
	break;
    default:
	path = FcConfigGetPath ();
	if (!path)
	    return 0;
	for (p = path; *p; p++)
	{
	    file = FcConfigFileExists (*p, url);
	    if (file)
		break;
	}
	FcConfigFreePath (path);
	break;
    }
    return file;
}

/*
 * Manage the application-specific fonts
 */

FcBool
FcConfigAppFontAddFile (FcConfig    *config,
1585
			const FcChar8  *file)
Keith Packard's avatar
Keith Packard committed
1586
1587
{
    FcFontSet	*set;
1588
1589
1590
    FcStrSet	*subdirs;
    FcStrList	*sublist;
    FcChar8	*subdir;
Keith Packard's avatar
Keith Packard committed
1591
1592
1593
1594
1595
1596
1597
1598

    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return FcFalse;
    }

1599
1600
1601
1602
    subdirs = FcStrSetCreate ();
    if (!subdirs)
	return FcFalse;
    
Keith Packard's avatar
Keith Packard committed
1603
1604
1605
1606
1607
    set = FcConfigGetFonts (config, FcSetApplication);
    if (!set)
    {
	set = FcFontSetCreate ();
	if (!set)
1608
1609
	{
	    FcStrSetDestroy (subdirs);
Keith Packard's avatar
Keith Packard committed
1610
	    return FcFalse;
1611
	}
Keith Packard's avatar
Keith Packard committed
1612
1613
	FcConfigSetFonts (config, set, FcSetApplication);
    }
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
	
    if (!FcFileScan (set, subdirs, 0, config->blanks, file, FcFalse))
    {
	FcStrSetDestroy (subdirs);
	return FcFalse;
    }
    if ((sublist = FcStrListCreate (subdirs)))
    {
	while ((subdir = FcStrListNext (sublist)))
	{
	    FcConfigAppFontAddDir (config, subdir);
	}
	FcStrListDone (sublist);
    }
    return FcTrue;
Keith Packard's avatar
Keith Packard committed
1629
1630
1631
1632
}

FcBool
FcConfigAppFontAddDir (FcConfig	    *config,
1633
		       const FcChar8   *dir)
Keith Packard's avatar
Keith Packard committed
1634
1635
{
    FcFontSet	*set;
1636
1637
1638
    FcStrSet	*subdirs;
    FcStrList	*sublist;
    FcChar8	*subdir;
Keith Packard's avatar
Keith Packard committed
1639
1640
1641
1642
1643
1644
1645
    
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return FcFalse;
    }
1646
1647
1648
1649
    subdirs = FcStrSetCreate ();
    if (!subdirs)
	return FcFalse;
    
Keith Packard's avatar
Keith Packard committed
1650
1651
1652
1653
1654
    set = FcConfigGetFonts (config, FcSetApplication);
    if (!set)
    {
	set = FcFontSetCreate ();
	if (!set)
1655
1656
	{
	    FcStrSetDestroy (subdirs);
Keith Packard's avatar
Keith Packard committed
1657
	    return FcFalse;
1658
	}
Keith Packard's avatar
Keith Packard committed
1659
1660
	FcConfigSetFonts (config, set, FcSetApplication);
    }
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
    
    if (!FcDirScan (set, subdirs, 0, config->blanks, dir, FcFalse))
    {
	FcStrSetDestroy (subdirs);
	return FcFalse;
    }
    if ((sublist = FcStrListCreate (subdirs)))
    {
	while ((subdir = FcStrListNext (sublist)))
	{
	    FcConfigAppFontAddDir (config, subdir);
	}
	FcStrListDone (sublist);
    }
    return FcTrue;
Keith Packard's avatar
Keith Packard committed
1676
1677
1678
1679
1680
1681
1682
}

void
FcConfigAppFontClear (FcConfig	    *config)
{
    FcConfigSetFonts (config, 0, FcSetApplication);
}