fccfg.c 55.6 KB
Newer Older
Keith Packard's avatar
Keith Packard committed
1
/*
2
 * fontconfig/src/fccfg.c
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
 *
 * 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
10
 * documentation, and that the name of the author(s) not be used in
Keith Packard's avatar
Keith Packard committed
11
 * advertising or publicity pertaining to distribution of the software without
12
 * specific, written prior permission.  The authors make no
Keith Packard's avatar
Keith Packard committed
13 14 15
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
16
 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
Keith Packard's avatar
Keith Packard committed
17
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18
 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
Keith Packard's avatar
Keith Packard committed
19 20 21 22 23 24
 * 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.
 */

25 26
/* Objects MT-safe for readonly access. */

27
#include "fcint.h"
28 29
#include <dirent.h>
#include <sys/types.h>
Keith Packard's avatar
Keith Packard committed
30

31 32 33 34
#if defined (_WIN32) && !defined (R_OK)
#define R_OK 4
#endif

35
static FcConfig    *_fcConfig; /* MT-safe */
36

37 38
static FcConfig *
FcConfigEnsure (void)
39 40
{
    FcConfig	*config;
41
retry:
42
    config = fc_atomic_ptr_get (&_fcConfig);
43
    if (!config)
44 45 46 47 48
    {
	config = FcInitLoadConfigAndFonts ();

	if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) {
	    FcConfigDestroy (config);
49
	    goto retry;
50 51 52 53 54 55 56 57 58
	}
    }
    return config;
}

FcBool
FcConfigInit (void)
{
  return FcConfigEnsure () ? FcTrue : FcFalse;
59 60 61 62 63
}

void
FcConfigFini (void)
{
64 65 66
    FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig);
    if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL))
	FcConfigDestroy (cfg);
67 68
}

Keith Packard's avatar
Keith Packard committed
69 70 71 72 73 74

FcConfig *
FcConfigCreate (void)
{
    FcSetName	set;
    FcConfig	*config;
75 76
    FcMatchKind	k;
    FcBool	err = FcFalse;
Keith Packard's avatar
Keith Packard committed
77 78 79 80

    config = malloc (sizeof (FcConfig));
    if (!config)
	goto bail0;
81

82 83
    config->configDirs = FcStrSetCreate ();
    if (!config->configDirs)
Keith Packard's avatar
Keith Packard committed
84
	goto bail1;
85

86
    config->configFiles = FcStrSetCreate ();
Keith Packard's avatar
Keith Packard committed
87 88
    if (!config->configFiles)
	goto bail2;
89

90 91 92
    config->fontDirs = FcStrSetCreate ();
    if (!config->fontDirs)
	goto bail3;
93

94 95 96 97 98 99 100 101
    config->acceptGlobs = FcStrSetCreate ();
    if (!config->acceptGlobs)
	goto bail4;

    config->rejectGlobs = FcStrSetCreate ();
    if (!config->rejectGlobs)
	goto bail5;

102 103 104
    config->acceptPatterns = FcFontSetCreate ();
    if (!config->acceptPatterns)
	goto bail6;
105

106 107 108 109
    config->rejectPatterns = FcFontSetCreate ();
    if (!config->rejectPatterns)
	goto bail7;

110 111
    config->cacheDirs = FcStrSetCreate ();
    if (!config->cacheDirs)
112
	goto bail8;
113

114 115 116 117 118 119 120 121 122
    for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
    {
	config->subst[k] = FcPtrListCreate ((FcDestroyFunc) FcRuleSetDestroy);
	if (!config->subst[k])
	    err = FcTrue;
    }
    if (err)
	goto bail9;

Keith Packard's avatar
Keith Packard committed
123 124 125
    config->maxObjects = 0;
    for (set = FcSetSystem; set <= FcSetApplication; set++)
	config->fonts[set] = 0;
126 127

    config->rescanTime = time(0);
128
    config->rescanInterval = 30;
129

130 131
    config->expr_pool = NULL;

132 133
    config->sysRoot = NULL;

134 135 136 137 138 139 140
    config->rulesetList = FcPtrListCreate ((FcDestroyFunc) FcRuleSetDestroy);
    if (!config->rulesetList)
	goto bail9;
    config->availConfigFiles = FcStrSetCreate ();
    if (!config->availConfigFiles)
	goto bail10;

141 142 143 144 145 146 147 148 149 150 151 152 153
    config->uuid_table = FcHashTableCreate ((FcHashFunc) FcStrHashIgnoreCase,
					    (FcCompareFunc) FcStrCmp,
					    FcHashStrCopy,
					    FcHashUuidCopy,
					    (FcDestroyFunc) FcStrFree,
					    FcHashUuidFree);
    config->alias_table = FcHashTableCreate ((FcHashFunc) FcStrHashIgnoreCase,
					     (FcCompareFunc) FcStrCmp,
					     FcHashStrCopy,
					     FcHashStrCopy,
					     (FcDestroyFunc) FcStrFree,
					     (FcDestroyFunc) FcStrFree);

154
    FcRefInit (&config->ref, 1);
155

Keith Packard's avatar
Keith Packard committed
156 157
    return config;

158 159 160 161 162 163 164
bail10:
    FcPtrListDestroy (config->rulesetList);
bail9:
    for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
	if (config->subst[k])
	    FcPtrListDestroy (config->subst[k]);
    FcStrSetDestroy (config->cacheDirs);
165 166 167 168
bail8:
    FcFontSetDestroy (config->rejectPatterns);
bail7:
    FcFontSetDestroy (config->acceptPatterns);
169 170 171 172
bail6:
    FcStrSetDestroy (config->rejectGlobs);
bail5:
    FcStrSetDestroy (config->acceptGlobs);
173 174
bail4:
    FcStrSetDestroy (config->fontDirs);
Keith Packard's avatar
Keith Packard committed
175
bail3:
176
    FcStrSetDestroy (config->configFiles);
Keith Packard's avatar
Keith Packard committed
177
bail2:
178
    FcStrSetDestroy (config->configDirs);
Keith Packard's avatar
Keith Packard committed
179 180 181 182 183 184
bail1:
    free (config);
bail0:
    return 0;
}

185
static FcFileTime
186 187 188
FcConfigNewestFile (FcStrSet *files)
{
    FcStrList	    *list = FcStrListCreate (files);
189
    FcFileTime	    newest = { 0, FcFalse };
190 191 192 193 194 195
    FcChar8	    *file;
    struct  stat    statb;

    if (list)
    {
	while ((file = FcStrListNext (list)))
196
	    if (FcStat (file, &statb) == 0)
197
		if (!newest.set || statb.st_mtime - newest.time > 0)
198 199
		{
		    newest.set = FcTrue;
200
		    newest.time = statb.st_mtime;
201
		}
202 203 204 205 206 207 208 209
	FcStrListDone (list);
    }
    return newest;
}

FcBool
FcConfigUptoDate (FcConfig *config)
{
210
    FcFileTime	config_time, config_dir_time, font_time;
211
    time_t	now = time(0);
212 213 214 215 216 217 218
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return FcFalse;
    }
    config_time = FcConfigNewestFile (config->configFiles);
219
    config_dir_time = FcConfigNewestFile (config->configDirs);
220
    font_time = FcConfigNewestFile (config->fontDirs);
221
    if ((config_time.set && config_time.time - config->rescanTime > 0) ||
222
	(config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) ||
223
	(font_time.set && (font_time.time - config->rescanTime) > 0))
224
    {
225 226 227 228 229 230
	/* We need to check for potential clock problems here (OLPC ticket #6046) */
	if ((config_time.set && (config_time.time - now) > 0) ||
    	(config_dir_time.set && (config_dir_time.time - now) > 0) ||
        (font_time.set && (font_time.time - now) > 0))
	{
	    fprintf (stderr,
231
                    "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected.\n");
232 233 234 235 236
	    config->rescanTime = now;
	    return FcTrue;
	}
	else
	    return FcFalse;
237 238 239 240 241
    }
    config->rescanTime = now;
    return FcTrue;
}

242 243 244
FcExpr *
FcConfigAllocExpr (FcConfig *config)
{
245 246 247 248 249 250 251 252 253 254 255 256
    if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end)
    {
	FcExprPage *new_page;

	new_page = malloc (sizeof (FcExprPage));
	if (!new_page)
	    return 0;

	new_page->next_page = config->expr_pool;
	new_page->next = new_page->exprs;
	config->expr_pool = new_page;
    }
257

258
    return config->expr_pool->next++;
259 260
}

261 262 263 264 265 266 267 268 269 270
FcConfig *
FcConfigReference (FcConfig *config)
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
    }

271
    FcRefInc (&config->ref);
272 273 274 275

    return config;
}

Keith Packard's avatar
Keith Packard committed
276 277 278 279
void
FcConfigDestroy (FcConfig *config)
{
    FcSetName	set;
280
    FcExprPage	*page;
281
    FcMatchKind	k;
Keith Packard's avatar
Keith Packard committed
282

283
    if (FcRefDec (&config->ref) != 1)
284 285
	return;

286
    (void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL);
287 288 289

    FcStrSetDestroy (config->configDirs);
    FcStrSetDestroy (config->fontDirs);
290
    FcStrSetDestroy (config->cacheDirs);
291
    FcStrSetDestroy (config->configFiles);
292 293
    FcStrSetDestroy (config->acceptGlobs);
    FcStrSetDestroy (config->rejectGlobs);
294 295
    FcFontSetDestroy (config->acceptPatterns);
    FcFontSetDestroy (config->rejectPatterns);
296

297 298 299 300
    for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
	FcPtrListDestroy (config->subst[k]);
    FcPtrListDestroy (config->rulesetList);
    FcStrSetDestroy (config->availConfigFiles);
Keith Packard's avatar
Keith Packard committed
301 302 303
    for (set = FcSetSystem; set <= FcSetApplication; set++)
	if (config->fonts[set])
	    FcFontSetDestroy (config->fonts[set]);
304

305 306 307 308 309 310 311
    page = config->expr_pool;
    while (page)
    {
      FcExprPage *next = page->next_page;
      free (page);
      page = next;
    }
312 313
    if (config->sysRoot)
	FcStrFree (config->sysRoot);
314

315 316 317
    FcHashTableDestroy (config->uuid_table);
    FcHashTableDestroy (config->alias_table);

318
    free (config);
Keith Packard's avatar
Keith Packard committed
319 320 321
}

/*
322
 * Add cache to configuration, adding fonts and directories
Keith Packard's avatar
Keith Packard committed
323 324 325
 */

FcBool
326
FcConfigAddCache (FcConfig *config, FcCache *cache,
327
		  FcSetName set, FcStrSet *dirSet)
Keith Packard's avatar
Keith Packard committed
328
{
329 330 331
    FcFontSet	*fs;
    intptr_t	*dirs;
    int		i;
Keith Packard's avatar
Keith Packard committed
332

333 334 335 336 337
    /*
     * Add fonts
     */
    fs = FcCacheSet (cache);
    if (fs)
338
    {
339 340
	int	nref = 0;
	
341
	for (i = 0; i < fs->nfont; i++)
342
	{
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
	    FcPattern	*font = FcFontSetFont (fs, i);
	    FcChar8	*font_file;

	    /*
	     * Check to see if font is banned by filename
	     */
	    if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
					  0, &font_file) == FcResultMatch &&
		!FcConfigAcceptFilename (config, font_file))
	    {
		continue;
	    }
		
	    /*
	     * Check to see if font is banned by pattern
	     */
	    if (!FcConfigAcceptFont (config, font))
		continue;
		
362 363
	    if (FcFontSetAdd (config->fonts[set], font))
		nref++;
364
	}
365
	FcDirCacheReference (cache, nref);
366
    }
367 368 369 370 371 372

    /*
     * Add directories
     */
    dirs = FcCacheDirs (cache);
    if (dirs)
Keith Packard's avatar
Keith Packard committed
373
    {
374 375
	for (i = 0; i < cache->dirs_count; i++)
	{
376
	    const FcChar8 *dir = FcCacheSubdir (cache, i);
377
	    FcChar8 *alias;
378
	    FcChar8 *d = FcStrDirname (dir);
379 380
	    FcChar8 *s = NULL;

381
	    if (FcHashTableFind (config->alias_table, d, (void **)&alias))
382
	    {
383 384
		FcChar8 *base = FcStrBasename (dir);
		dir = s = FcStrBuildFilename (alias, base, NULL);
385
		FcStrFree (alias);
386
		FcStrFree (base);
387
	    }
388
	    FcStrFree (d);
389
	    if (FcConfigAcceptFilename (config, dir))
390
		FcStrSetAddFilename (dirSet, dir);
391 392
	    if (s)
		FcStrFree (s);
393
	}
394 395 396
    }
    return FcTrue;
}
397

398 399 400 401 402 403
static FcBool
FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
{
    FcStrList	    *dirlist;
    FcChar8	    *dir;
    FcCache	    *cache;
404

405 406 407 408 409 410 411
    dirlist = FcStrListCreate (dirSet);
    if (!dirlist)
        return FcFalse;
	
    while ((dir = FcStrListNext (dirlist)))
    {
	if (FcDebug () & FC_DBG_FONTSET)
412
	    printf ("adding fonts from %s\n", dir);
413 414 415 416 417 418 419
	cache = FcDirCacheRead (dir, FcFalse, config);
	if (!cache)
	    continue;
	FcConfigAddCache (config, cache, set, dirSet);
	FcDirCacheUnload (cache);
    }
    FcStrListDone (dirlist);
420
    return FcTrue;
421 422
}

423 424 425 426
/*
 * Scan the current list of directories in the configuration
 * and build the set of available fonts.
 */
Patrick Lam's avatar
Patrick Lam committed
427

428 429 430 431
FcBool
FcConfigBuildFonts (FcConfig *config)
{
    FcFontSet	    *fonts;
432

433 434 435 436 437
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return FcFalse;
Keith Packard's avatar
Keith Packard committed
438
    }
439 440 441
	
    fonts = FcFontSetCreate ();
    if (!fonts)
442
	return FcFalse;
443

444
    FcConfigSetFonts (config, fonts, FcSetSystem);
445

446 447
    if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs))
	return FcFalse;
Keith Packard's avatar
Keith Packard committed
448 449 450 451 452 453 454 455
    if (FcDebug () & FC_DBG_FONTSET)
	FcFontSetPrint (fonts);
    return FcTrue;
}

FcBool
FcConfigSetCurrent (FcConfig *config)
{
456 457 458 459 460 461
    FcConfig *cfg;

retry:
    cfg = fc_atomic_ptr_get (&_fcConfig);

    if (config == cfg)
462 463
	return FcTrue;

464
    if (config && !config->fonts[FcSetSystem])
Keith Packard's avatar
Keith Packard committed
465 466 467
	if (!FcConfigBuildFonts (config))
	    return FcFalse;

468 469 470
    if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config))
	goto retry;

471
    FcConfigReference (config);
472 473 474
    if (cfg)
	FcConfigDestroy (cfg);

Keith Packard's avatar
Keith Packard committed
475 476 477 478 479 480
    return FcTrue;
}

FcConfig *
FcConfigGetCurrent (void)
{
481
    return FcConfigEnsure ();
Keith Packard's avatar
Keith Packard committed
482 483 484
}

FcBool
485 486
FcConfigAddConfigDir (FcConfig	    *config,
		      const FcChar8 *d)
Keith Packard's avatar
Keith Packard committed
487
{
488 489
    return FcStrSetAddFilename (config->configDirs, d);
}
Keith Packard's avatar
Keith Packard committed
490

491 492 493 494
FcStrList *
FcConfigGetConfigDirs (FcConfig   *config)
{
    if (!config)
Keith Packard's avatar
Keith Packard committed
495
    {
496 497 498
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
Keith Packard's avatar
Keith Packard committed
499
    }
500 501 502 503 504 505 506 507
    return FcStrListCreate (config->configDirs);
}

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

510 511
FcStrList *
FcConfigGetFontDirs (FcConfig	*config)
Keith Packard's avatar
Keith Packard committed
512 513 514 515 516 517 518
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
    }
519
    return FcStrListCreate (config->fontDirs);
Keith Packard's avatar
Keith Packard committed
520 521
}

522 523 524 525 526 527 528 529
FcBool
FcConfigAddCacheDir (FcConfig	    *config,
		     const FcChar8  *d)
{
    return FcStrSetAddFilename (config->cacheDirs, d);
}

FcStrList *
530
FcConfigGetCacheDirs (const FcConfig *config)
531 532 533 534 535 536 537 538 539
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
    }
    return FcStrListCreate (config->cacheDirs);
}
540

Keith Packard's avatar
Keith Packard committed
541 542
FcBool
FcConfigAddConfigFile (FcConfig	    *config,
543
		       const FcChar8   *f)
Keith Packard's avatar
Keith Packard committed
544
{
545 546
    FcBool	ret;
    FcChar8	*file = FcConfigFilename (f);
547

Keith Packard's avatar
Keith Packard committed
548 549
    if (!file)
	return FcFalse;
550

551 552 553
    ret = FcStrSetAdd (config->configFiles, file);
    FcStrFree (file);
    return ret;
Keith Packard's avatar
Keith Packard committed
554 555
}

556
FcStrList *
Keith Packard's avatar
Keith Packard committed
557 558 559 560 561 562 563 564
FcConfigGetConfigFiles (FcConfig    *config)
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
    }
565
    return FcStrListCreate (config->configFiles);
Keith Packard's avatar
Keith Packard committed
566 567
}

568
FcChar8 *
569
FcConfigGetCache (FcConfig  *config FC_UNUSED)
Keith Packard's avatar
Keith Packard committed
570
{
571
    return NULL;
Keith Packard's avatar
Keith Packard committed
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
}

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;
}

597 598 599 600 601 602 603 604 605

FcBlanks *
FcBlanksCreate (void)
{
    /* Deprecated. */
    return NULL;
}

void
606
FcBlanksDestroy (FcBlanks *b FC_UNUSED)
607 608 609 610 611
{
    /* Deprecated. */
}

FcBool
612
FcBlanksAdd (FcBlanks *b FC_UNUSED, FcChar32 ucs4 FC_UNUSED)
613 614 615 616 617 618
{
    /* Deprecated. */
    return FcFalse;
}

FcBool
619
FcBlanksIsMember (FcBlanks *b FC_UNUSED, FcChar32 ucs4 FC_UNUSED)
620 621 622 623 624
{
    /* Deprecated. */
    return FcFalse;
}

Keith Packard's avatar
Keith Packard committed
625
FcBlanks *
626
FcConfigGetBlanks (FcConfig	*config FC_UNUSED)
Keith Packard's avatar
Keith Packard committed
627
{
628 629
    /* Deprecated. */
    return NULL;
Keith Packard's avatar
Keith Packard committed
630 631 632
}

FcBool
633 634
FcConfigAddBlank (FcConfig	*config FC_UNUSED,
		  FcChar32    	blank FC_UNUSED)
Keith Packard's avatar
Keith Packard committed
635
{
636 637
    /* Deprecated. */
    return FcFalse;
Keith Packard's avatar
Keith Packard committed
638 639
}

640

641
int
642
FcConfigGetRescanInterval (FcConfig *config)
643 644 645 646 647 648 649 650 651 652 653
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
    }
    return config->rescanInterval;
}

FcBool
654
FcConfigSetRescanInterval (FcConfig *config, int rescanInterval)
655 656 657 658 659 660 661 662 663 664 665
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return FcFalse;
    }
    config->rescanInterval = rescanInterval;
    return FcTrue;
}

666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
/*
 * A couple of typos escaped into the library
 */
int
FcConfigGetRescanInverval (FcConfig *config)
{
    return FcConfigGetRescanInterval (config);
}

FcBool
FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
{
    return FcConfigSetRescanInterval (config, rescanInterval);
}

Keith Packard's avatar
Keith Packard committed
681
FcBool
682 683
FcConfigAddRule (FcConfig	*config,
		 FcRule		*rule,
Keith Packard's avatar
Keith Packard committed
684 685
		 FcMatchKind	kind)
{
686 687
    /* deprecated */
    return FcFalse;
Keith Packard's avatar
Keith Packard committed
688 689 690
}

static FcValue
691
FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
Keith Packard's avatar
Keith Packard committed
692 693 694 695 696 697 698 699
{
    if (v.type == FcTypeInteger)
    {
	v.type = FcTypeDouble;
	v.u.d = (double) v.u.i;
    }
    else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
    {
700
	v.u.m = &FcIdentityMatrix;
701
	v.type = FcTypeMatrix;
Keith Packard's avatar
Keith Packard committed
702
    }
703
    else if (buf && v.type == FcTypeString && u.type == FcTypeLangSet)
704
    {
705
	v.u.l = FcLangSetPromote (v.u.s, buf);
706 707
	v.type = FcTypeLangSet;
    }
708 709 710 711 712 713 714 715 716 717
    else if (v.type == FcTypeVoid && u.type == FcTypeLangSet)
    {
	v.u.l = FcLangSetPromote (NULL, buf);
	v.type = FcTypeLangSet;
    }
    else if (v.type == FcTypeVoid && u.type == FcTypeCharSet)
    {
	v.u.c = FcCharSetPromote (buf);
	v.type = FcTypeCharSet;
    }
718 719 720 721 722
    if (buf && v.type == FcTypeDouble && u.type == FcTypeRange)
    {
	v.u.r = FcRangePromote (v.u.d, buf);
	v.type = FcTypeRange;
    }
Keith Packard's avatar
Keith Packard committed
723 724 725 726
    return v;
}

FcBool
727
FcConfigCompareValue (const FcValue	*left_o,
728
		      unsigned int      op_,
729
		      const FcValue	*right_o)
Keith Packard's avatar
Keith Packard committed
730
{
731 732
    FcValue	left = FcValueCanonicalize(left_o);
    FcValue	right = FcValueCanonicalize(right_o);
733
    FcBool	ret = FcFalse;
734 735
    FcOp	op = FC_OP_GET_OP (op_);
    int		flags = FC_OP_GET_FLAGS (op_);
736
    FcValuePromotionBuffer buf1, buf2;
737

738 739
    left = FcConfigPromote (left, right, &buf1);
    right = FcConfigPromote (right, left, &buf2);
740
    if (left.type == right.type)
Keith Packard's avatar
Keith Packard committed
741
    {
742
	switch (left.type) {
743 744
	case FcTypeUnknown:
	    break;	/* No way to guess how to compare for this object */
Keith Packard's avatar
Keith Packard committed
745 746 747
	case FcTypeInteger:
	    break;	/* FcConfigPromote prevents this from happening */
	case FcTypeDouble:
Behdad Esfahbod's avatar
Behdad Esfahbod committed
748
	    switch ((int) op) {
Keith Packard's avatar
Keith Packard committed
749 750
	    case FcOpEqual:
	    case FcOpContains:
751 752
	    case FcOpListing:
		ret = left.u.d == right.u.d;
Keith Packard's avatar
Keith Packard committed
753
		break;
754 755
	    case FcOpNotEqual:
	    case FcOpNotContains:
756
		ret = left.u.d != right.u.d;
Keith Packard's avatar
Keith Packard committed
757
		break;
758
	    case FcOpLess:
759
		ret = left.u.d < right.u.d;
Keith Packard's avatar
Keith Packard committed
760
		break;
761
	    case FcOpLessEqual:
762
		ret = left.u.d <= right.u.d;
Keith Packard's avatar
Keith Packard committed
763
		break;
764
	    case FcOpMore:
765
		ret = left.u.d > right.u.d;
Keith Packard's avatar
Keith Packard committed
766
		break;
767
	    case FcOpMoreEqual:
768
		ret = left.u.d >= right.u.d;
Keith Packard's avatar
Keith Packard committed
769 770 771 772 773 774
		break;
	    default:
		break;
	    }
	    break;
	case FcTypeBool:
Behdad Esfahbod's avatar
Behdad Esfahbod committed
775
	    switch ((int) op) {
776
	    case FcOpEqual:
777 778
		ret = left.u.b == right.u.b;
		break;
Keith Packard's avatar
Keith Packard committed
779
	    case FcOpContains:
780
	    case FcOpListing:
781
		ret = left.u.b == right.u.b || left.u.b == FcDontCare;
Keith Packard's avatar
Keith Packard committed
782
		break;
783
	    case FcOpNotEqual:
784
		ret = left.u.b != right.u.b;
Keith Packard's avatar
Keith Packard committed
785
		break;
786 787 788
	    case FcOpNotContains:
		ret = !(left.u.b == right.u.b || left.u.b == FcDontCare);
		break;
789 790 791 792 793 794 795 796 797 798 799 800
	    case FcOpLess:
		ret = left.u.b != right.u.b && right.u.b == FcDontCare;
		break;
	    case FcOpLessEqual:
		ret = left.u.b == right.u.b || right.u.b == FcDontCare;
		break;
	    case FcOpMore:
		ret = left.u.b != right.u.b && left.u.b == FcDontCare;
		break;
	    case FcOpMoreEqual:
		ret = left.u.b == right.u.b || left.u.b == FcDontCare;
		break;
Keith Packard's avatar
Keith Packard committed
801 802 803 804 805
	    default:
		break;
	    }
	    break;
	case FcTypeString:
Behdad Esfahbod's avatar
Behdad Esfahbod committed
806
	    switch ((int) op) {
807
	    case FcOpEqual:
808
	    case FcOpListing:
809 810 811 812
		if (flags & FcOpFlagIgnoreBlanks)
		    ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0;
		else
		    ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
Keith Packard's avatar
Keith Packard committed
813
		break;
814
	    case FcOpContains:
815
		ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
816
		break;
817
	    case FcOpNotEqual:
818 819 820 821
		if (flags & FcOpFlagIgnoreBlanks)
		    ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0;
		else
		    ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
822
		break;
823
	    case FcOpNotContains:
824
		ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
825
		break;
Keith Packard's avatar
Keith Packard committed
826 827 828 829 830
	    default:
		break;
	    }
	    break;
	case FcTypeMatrix:
Behdad Esfahbod's avatar
Behdad Esfahbod committed
831
	    switch ((int) op) {
Keith Packard's avatar
Keith Packard committed
832 833
	    case FcOpEqual:
	    case FcOpContains:
834
	    case FcOpListing:
835
		ret = FcMatrixEqual (left.u.m, right.u.m);
Keith Packard's avatar
Keith Packard committed
836 837
		break;
	    case FcOpNotEqual:
838
	    case FcOpNotContains:
839
		ret = !FcMatrixEqual (left.u.m, right.u.m);
Keith Packard's avatar
Keith Packard committed
840 841 842 843 844 845
		break;
	    default:
		break;
	    }
	    break;
	case FcTypeCharSet:
Behdad Esfahbod's avatar
Behdad Esfahbod committed
846
	    switch ((int) op) {
Keith Packard's avatar
Keith Packard committed
847
	    case FcOpContains:
848 849
	    case FcOpListing:
		/* left contains right if right is a subset of left */
850
		ret = FcCharSetIsSubset (right.u.c, left.u.c);
Keith Packard's avatar
Keith Packard committed
851
		break;
852
	    case FcOpNotContains:
853
		/* left contains right if right is a subset of left */
854
		ret = !FcCharSetIsSubset (right.u.c, left.u.c);
855
		break;
Keith Packard's avatar
Keith Packard committed
856
	    case FcOpEqual:
857
		ret = FcCharSetEqual (left.u.c, right.u.c);
Keith Packard's avatar
Keith Packard committed
858 859
		break;
	    case FcOpNotEqual:
860
		ret = !FcCharSetEqual (left.u.c, right.u.c);
Keith Packard's avatar
Keith Packard committed
861 862 863 864 865
		break;
	    default:
		break;
	    }
	    break;
866
	case FcTypeLangSet:
Behdad Esfahbod's avatar
Behdad Esfahbod committed
867
	    switch ((int) op) {
868
	    case FcOpContains:
869
	    case FcOpListing:
870
		ret = FcLangSetContains (left.u.l, right.u.l);
871
		break;
872
	    case FcOpNotContains:
873
		ret = !FcLangSetContains (left.u.l, right.u.l);
874
		break;
875
	    case FcOpEqual:
876
		ret = FcLangSetEqual (left.u.l, right.u.l);
877 878
		break;
	    case FcOpNotEqual:
879
		ret = !FcLangSetEqual (left.u.l, right.u.l);
880 881 882 883 884
		break;
	    default:
		break;
	    }
	    break;
Keith Packard's avatar
Keith Packard committed
885
	case FcTypeVoid:
Behdad Esfahbod's avatar
Behdad Esfahbod committed
886
	    switch ((int) op) {
Keith Packard's avatar
Keith Packard committed
887 888
	    case FcOpEqual:
	    case FcOpContains:
889
	    case FcOpListing:
Keith Packard's avatar
Keith Packard committed
890 891 892 893 894 895
		ret = FcTrue;
		break;
	    default:
		break;
	    }
	    break;
896
	case FcTypeFTFace:
Behdad Esfahbod's avatar
Behdad Esfahbod committed
897
	    switch ((int) op) {
898
	    case FcOpEqual:
899
	    case FcOpContains:
900 901
	    case FcOpListing:
		ret = left.u.f == right.u.f;
902 903
		break;
	    case FcOpNotEqual:
904
	    case FcOpNotContains:
905
		ret = left.u.f != right.u.f;
906 907 908 909
		break;
	    default:
		break;
	    }
910
	    break;
911 912 913
	case FcTypeRange:
	    ret = FcRangeCompare (op, left.u.r, right.u.r);
	    break;
Keith Packard's avatar
Keith Packard committed
914 915 916 917
	}
    }
    else
    {
918
	if (op == FcOpNotEqual || op == FcOpNotContains)
Keith Packard's avatar
Keith Packard committed
919 920 921 922 923 924
	    ret = FcTrue;
    }
    return ret;
}


925 926 927 928 929 930 931
#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
932
static FcValue
933
FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
Keith Packard's avatar
Keith Packard committed
934
{
935
    FcValue	v, vl, vr, vle, vre;
Keith Packard's avatar
Keith Packard committed
936
    FcMatrix	*m;
937
    FcChar8     *str;
938
    FcOp	op = FC_OP_GET_OP (e->op);
939
    FcValuePromotionBuffer buf1, buf2;
940

Behdad Esfahbod's avatar
Behdad Esfahbod committed
941
    switch ((int) op) {
Keith Packard's avatar
Keith Packard committed
942 943 944 945 946 947 948 949 950 951
    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;
952 953
	v.u.s = e->u.sval;
	v = FcValueSave (v);
Keith Packard's avatar
Keith Packard committed
954 955
	break;
    case FcOpMatrix:
956 957 958
	{
	  FcMatrix m;
	  FcValue xx, xy, yx, yy;
Behdad Esfahbod's avatar
Behdad Esfahbod committed
959
	  v.type = FcTypeMatrix;
960 961 962 963
	  xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL);
	  xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL);
	  yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL);
	  yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL);
964 965 966 967 968 969 970 971 972 973 974 975 976
	  if (xx.type == FcTypeDouble && xy.type == FcTypeDouble &&
	      yx.type == FcTypeDouble && yy.type == FcTypeDouble)
	  {
	    m.xx = xx.u.d;
	    m.xy = xy.u.d;
	    m.yx = yx.u.d;
	    m.yy = yy.u.d;
	    v.u.m = &m;
	  }
	  else
	    v.type = FcTypeVoid;
	  v = FcValueSave (v);
	}
Keith Packard's avatar
Keith Packard committed
977 978 979
	break;
    case FcOpCharSet:
	v.type = FcTypeCharSet;
980
	v.u.c = e->u.cval;
Keith Packard's avatar
Keith Packard committed
981 982
	v = FcValueSave (v);
	break;
983 984 985 986 987
    case FcOpLangSet:
	v.type = FcTypeLangSet;
	v.u.l = e->u.lval;
	v = FcValueSave (v);
	break;
988 989 990 991 992
    case FcOpRange:
	v.type = FcTypeRange;
	v.u.r = e->u.rval;
	v = FcValueSave (v);
	break;
Keith Packard's avatar
Keith Packard committed
993 994 995 996 997
    case FcOpBool:
	v.type = FcTypeBool;
	v.u.b = e->u.bval;
	break;
    case FcOpField:
998
	if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern)
999 1000 1001 1002 1003 1004 1005 1006
	{
	    if (FcResultMatch != FcPatternObjectGet (p_pat, e->u.name.object, 0, &v))
		v.type = FcTypeVoid;
	}
	else if (kind == FcMatchPattern && e->u.name.kind == FcMatchFont)
	{
	    fprintf (stderr,
                    "Fontconfig warning: <name> tag has target=\"font\" in a <match target=\"pattern\">.\n");
Keith Packard's avatar
Keith Packard committed
1007
	    v.type = FcTypeVoid;
1008 1009 1010 1011 1012 1013
	}
	else
	{
	    if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v))
		v.type = FcTypeVoid;
	}
1014
	v = FcValueSave (v);
Keith Packard's avatar
Keith Packard committed
1015 1016 1017 1018 1019 1020 1021 1022
	break;
    case FcOpConst:
	if (FcNameConstant (e->u.constant, &v.u.i))
	    v.type = FcTypeInteger;
	else
	    v.type = FcTypeVoid;
	break;
    case FcOpQuest:
1023
	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
Keith Packard's avatar
Keith Packard committed
1024 1025 1026
	if (vl.type == FcTypeBool)
	{
	    if (vl.u.b)
1027
		v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left);
Keith Packard's avatar
Keith Packard committed
1028
	    else
1029
		v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.right);
Keith Packard's avatar
Keith Packard committed
1030 1031 1032 1033 1034
	}
	else
	    v.type = FcTypeVoid;
	FcValueDestroy (vl);
	break;
1035
    case FcOpEqual:
Keith Packard's avatar
Keith Packard committed
1036 1037 1038 1039 1040
    case FcOpNotEqual:
    case FcOpLess:
    case FcOpLessEqual:
    case FcOpMore:
    case FcOpMoreEqual:
1041 1042
    case FcOpContains:
    case FcOpNotContains:
1043
    case FcOpListing:
1044 1045
	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
	vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
1046
	v.type = FcTypeBool;
1047
	v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
1048 1049 1050 1051 1052
	FcValueDestroy (vl);
	FcValueDestroy (vr);
	break;	
    case FcOpOr:
    case FcOpAnd:
Keith Packard's avatar
Keith Packard committed
1053 1054 1055 1056
    case FcOpPlus:
    case FcOpMinus:
    case FcOpTimes:
    case FcOpDivide:
1057 1058
	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
	vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
1059 1060 1061
	vle = FcConfigPromote (vl, vr, &buf1);
	vre = FcConfigPromote (vr, vle, &buf2);
	if (vle.type == vre.type)
Keith Packard's avatar
Keith Packard committed
1062
	{
1063
	    switch ((int) vle.type) {
Keith Packard's avatar
Keith Packard committed
1064
	    case FcTypeDouble:
Behdad Esfahbod's avatar
Behdad Esfahbod committed
1065
		switch ((int) op) {
1066
		case FcOpPlus:	
Keith Packard's avatar
Keith Packard committed
1067
		    v.type = FcTypeDouble;
1068
		    v.u.d = vle.u.d + vre.u.d;
Keith Packard's avatar
Keith Packard committed
1069 1070 1071
		    break;
		case FcOpMinus:
		    v.type = FcTypeDouble;
1072
		    v.u.d = vle.u.d - vre.u.d;
Keith Packard's avatar
Keith Packard committed
1073 1074 1075
		    break;
		case FcOpTimes:
		    v.type = FcTypeDouble;
1076
		    v.u.d = vle.u.d * vre.u.d;
Keith Packard's avatar
Keith Packard committed
1077 1078 1079
		    break;
		case FcOpDivide:
		    v.type = FcTypeDouble;
1080
		    v.u.d = vle.u.d / vre.u.d;
Keith Packard's avatar
Keith Packard committed
1081 1082
		    break;
		default:
1083
		    v.type = FcTypeVoid;
Keith Packard's avatar
Keith Packard committed
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
		    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:
Behdad Esfahbod's avatar
Behdad Esfahbod committed
1094
		switch ((int) op) {
Keith Packard's avatar
Keith Packard committed
1095 1096
		case FcOpOr:
		    v.type = FcTypeBool;
1097
		    v.u.b = vle.u.b || vre.u.b;
Keith Packard's avatar
Keith Packard committed
1098 1099 1100
		    break;
		case FcOpAnd:
		    v.type = FcTypeBool;
1101
		    v.u.b = vle.u.b && vre.u.b;
Keith Packard's avatar
Keith Packard committed
1102 1103
		    break;
		default:
1104
		    v.type = FcTypeVoid;
Keith Packard's avatar
Keith Packard committed
1105 1106 1107 1108
		    break;
		}
		break;
	    case FcTypeString:
Behdad Esfahbod's avatar
Behdad Esfahbod committed
1109
		switch ((int) op) {
Keith Packard's avatar
Keith Packard committed
1110 1111
		case FcOpPlus:
		    v.type = FcTypeString;
1112
		    str = FcStrPlus (vle.u.s, vre.u.s);
Behdad Esfahbod's avatar
Behdad Esfahbod committed
1113
		    v.u.s = FcStrdup (str);
1114
		    FcStrFree (str);
1115
			
1116
		    if (!v.u.s)
Keith Packard's avatar
Keith Packard committed
1117 1118 1119 1120 1121 1122
			v.type = FcTypeVoid;
		    break;
		default:
		    v.type = FcTypeVoid;
		    break;
		}
1123
		break;
Keith Packard's avatar
Keith Packard committed
1124
	    case FcTypeMatrix:
Behdad Esfahbod's avatar
Behdad Esfahbod committed
1125
		switch ((int) op) {
Keith Packard's avatar
Keith Packard committed
1126 1127 1128 1129 1130
		case FcOpTimes:
		    v.type = FcTypeMatrix;
		    m = malloc (sizeof (FcMatrix));
		    if (m)
		    {
1131
			FcMatrixMultiply (m, vle.u.m, vre.u.m);
1132
			v.u.m = m;
Keith Packard's avatar
Keith Packard committed
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
		    }
		    else
		    {
			v.type = FcTypeVoid;
		    }
		    break;
		default:
		    v.type = FcTypeVoid;
		    break;
		}
		break;
1144
	    case FcTypeCharSet:
Behdad Esfahbod's avatar
Behdad Esfahbod committed
1145
		switch ((int) op) {
1146 1147
		case FcOpPlus:
		    v.type = FcTypeCharSet;
1148
		    v.u.c = FcCharSetUnion (vle.u.c, vre.u.c);
1149 1150 1151 1152 1153
		    if (!v.u.c)
			v.type = FcTypeVoid;
		    break;
		case FcOpMinus:
		    v.type = FcTypeCharSet;
1154
		    v.u.c = FcCharSetSubtract (vle.u.c, vre.u.c);
1155 1156 1157 1158 1159 1160 1161 1162
		    if (!v.u.c)
			v.type = FcTypeVoid;
		    break;
		default:
		    v.type = FcTypeVoid;
		    break;
		}
		break;
1163
	    case FcTypeLangSet:
Behdad Esfahbod's avatar
Behdad Esfahbod committed
1164
		switch ((int) op) {
1165 1166
		case FcOpPlus:
		    v.type = FcTypeLangSet;
1167
		    v.u.l = FcLangSetUnion (vle.u.l, vre.u.l);
1168 1169 1170 1171 1172
		    if (!v.u.l)
			v.type = FcTypeVoid;
		    break;
		case FcOpMinus:
		    v.type = FcTypeLangSet;
1173
		    v.u.l = FcLangSetSubtract (vle.u.l, vre.u.l);
1174 1175 1176 1177 1178 1179 1180 1181
		    if (!v.u.l)
			v.type = FcTypeVoid;
		    break;
		default:
		    v.type = FcTypeVoid;
		    break;
		}
		break;
Keith Packard's avatar
Keith Packard committed
1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
	    default:
		v.type = FcTypeVoid;
		break;
	    }
	}
	else
	    v.type = FcTypeVoid;
	FcValueDestroy (vl);
	FcValueDestroy (vr);
	break;
    case FcOpNot:
1193
	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
Behdad Esfahbod's avatar
Behdad Esfahbod committed
1194
	switch ((int) vl.type) {
Keith Packard's avatar
Keith Packard committed
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204
	case FcTypeBool:
	    v.type = FcTypeBool;
	    v.u.b = !vl.u.b;
	    break;
	default:
	    v.type = FcTypeVoid;
	    break;
	}
	FcValueDestroy (vl);
	break;
1205
    case FcOpFloor:
1206
	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
Behdad Esfahbod's avatar
Behdad Esfahbod committed
1207
	switch ((int) vl.type) {
1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221
	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:
1222
	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
Behdad Esfahbod's avatar
Behdad Esfahbod committed
1223
	switch ((int) vl.type) {
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237
	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:
1238
	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
Behdad Esfahbod's avatar
Behdad Esfahbod committed
1239
	switch ((int) vl.type) {
1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
	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:
1254
	vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
Behdad Esfahbod's avatar
Behdad Esfahbod committed
1255
	switch ((int) vl.type) {
1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
	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
1269 1270 1271 1272 1273 1274 1275 1276 1277
    default:
	v.type = FcTypeVoid;
	break;
    }
    return v;
}

static FcValueList *
FcConfigMatchValueList (FcPattern	*p,
1278 1279
			FcPattern	*p_pat,
			FcMatchKind      kind,
Keith Packard's avatar
Keith Packard committed
1280
			FcTest		*t,
1281
			FcValueList	*values)
Keith Packard's avatar
Keith Packard committed
1282
{
1283 1284 1285
    FcValueList	    *ret = 0;
    FcExpr	    *e = t->expr;
    FcValue	    value;
1286
    FcValueList	    *v;
1287

1288
    while (e)
Keith Packard's avatar
Keith Packard committed
1289
    {
1290
	/* Compute the value of the match expression */
1291
	if (FC_OP_GET_OP (e->op) == FcOpComma)
Keith Packard's avatar
Keith Packard committed
1292
	{
1293
	    value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
1294
	    e = e->u.tree.right;
Keith Packard's avatar
Keith Packard committed
1295 1296 1297
	}
	else
	{
1298
	    value = FcConfigEvaluate (p, p_pat, kind, e);
1299 1300 1301
	    e = 0;
	}

1302
	for (v = values; v; v = FcValueListNext(v))