fccfg.c revision 2c393a42
12c393a42Smrg/*
22c393a42Smrg * $RCSId: xc/lib/fontconfig/src/fccfg.c,v 1.23 2002/08/31 22:17:32 keithp Exp $
32c393a42Smrg *
42c393a42Smrg * Copyright © 2000 Keith Packard
52c393a42Smrg *
62c393a42Smrg * Permission to use, copy, modify, distribute, and sell this software and its
72c393a42Smrg * documentation for any purpose is hereby granted without fee, provided that
82c393a42Smrg * the above copyright notice appear in all copies and that both that
92c393a42Smrg * copyright notice and this permission notice appear in supporting
102c393a42Smrg * documentation, and that the name of Keith Packard not be used in
112c393a42Smrg * advertising or publicity pertaining to distribution of the software without
122c393a42Smrg * specific, written prior permission.  Keith Packard makes no
132c393a42Smrg * representations about the suitability of this software for any purpose.  It
142c393a42Smrg * is provided "as is" without express or implied warranty.
152c393a42Smrg *
162c393a42Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
172c393a42Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
182c393a42Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
192c393a42Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
202c393a42Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
212c393a42Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
222c393a42Smrg * PERFORMANCE OF THIS SOFTWARE.
232c393a42Smrg */
242c393a42Smrg
252c393a42Smrg#include "fcint.h"
262c393a42Smrg#include <dirent.h>
272c393a42Smrg#include <sys/types.h>
282c393a42Smrg
292c393a42Smrg#if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT))
302c393a42Smrg#define STRICT
312c393a42Smrg#include <windows.h>
322c393a42Smrg#undef STRICT
332c393a42Smrg#endif
342c393a42Smrg
352c393a42Smrg#if defined (_WIN32) && !defined (R_OK)
362c393a42Smrg#define R_OK 4
372c393a42Smrg#endif
382c393a42Smrg
392c393a42SmrgFcConfig    *_fcConfig;
402c393a42Smrg
412c393a42SmrgFcConfig *
422c393a42SmrgFcConfigCreate (void)
432c393a42Smrg{
442c393a42Smrg    FcSetName	set;
452c393a42Smrg    FcConfig	*config;
462c393a42Smrg
472c393a42Smrg    config = malloc (sizeof (FcConfig));
482c393a42Smrg    if (!config)
492c393a42Smrg	goto bail0;
502c393a42Smrg    FcMemAlloc (FC_MEM_CONFIG, sizeof (FcConfig));
512c393a42Smrg
522c393a42Smrg    config->configDirs = FcStrSetCreate ();
532c393a42Smrg    if (!config->configDirs)
542c393a42Smrg	goto bail1;
552c393a42Smrg
562c393a42Smrg    config->configFiles = FcStrSetCreate ();
572c393a42Smrg    if (!config->configFiles)
582c393a42Smrg	goto bail2;
592c393a42Smrg
602c393a42Smrg    config->fontDirs = FcStrSetCreate ();
612c393a42Smrg    if (!config->fontDirs)
622c393a42Smrg	goto bail3;
632c393a42Smrg
642c393a42Smrg    config->acceptGlobs = FcStrSetCreate ();
652c393a42Smrg    if (!config->acceptGlobs)
662c393a42Smrg	goto bail4;
672c393a42Smrg
682c393a42Smrg    config->rejectGlobs = FcStrSetCreate ();
692c393a42Smrg    if (!config->rejectGlobs)
702c393a42Smrg	goto bail5;
712c393a42Smrg
722c393a42Smrg    config->acceptPatterns = FcFontSetCreate ();
732c393a42Smrg    if (!config->acceptPatterns)
742c393a42Smrg	goto bail6;
752c393a42Smrg
762c393a42Smrg    config->rejectPatterns = FcFontSetCreate ();
772c393a42Smrg    if (!config->rejectPatterns)
782c393a42Smrg	goto bail7;
792c393a42Smrg
802c393a42Smrg    config->cacheDirs = FcStrSetCreate ();
812c393a42Smrg    if (!config->cacheDirs)
822c393a42Smrg	goto bail8;
832c393a42Smrg
842c393a42Smrg    config->blanks = 0;
852c393a42Smrg
862c393a42Smrg    config->substPattern = 0;
872c393a42Smrg    config->substFont = 0;
882c393a42Smrg    config->substScan = 0;
892c393a42Smrg    config->maxObjects = 0;
902c393a42Smrg    for (set = FcSetSystem; set <= FcSetApplication; set++)
912c393a42Smrg	config->fonts[set] = 0;
922c393a42Smrg
932c393a42Smrg    config->rescanTime = time(0);
942c393a42Smrg    config->rescanInterval = 30;
952c393a42Smrg
962c393a42Smrg    return config;
972c393a42Smrg
982c393a42Smrgbail8:
992c393a42Smrg    FcFontSetDestroy (config->rejectPatterns);
1002c393a42Smrgbail7:
1012c393a42Smrg    FcFontSetDestroy (config->acceptPatterns);
1022c393a42Smrgbail6:
1032c393a42Smrg    FcStrSetDestroy (config->rejectGlobs);
1042c393a42Smrgbail5:
1052c393a42Smrg    FcStrSetDestroy (config->acceptGlobs);
1062c393a42Smrgbail4:
1072c393a42Smrg    FcStrSetDestroy (config->fontDirs);
1082c393a42Smrgbail3:
1092c393a42Smrg    FcStrSetDestroy (config->configFiles);
1102c393a42Smrgbail2:
1112c393a42Smrg    FcStrSetDestroy (config->configDirs);
1122c393a42Smrgbail1:
1132c393a42Smrg    free (config);
1142c393a42Smrg    FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
1152c393a42Smrgbail0:
1162c393a42Smrg    return 0;
1172c393a42Smrg}
1182c393a42Smrg
1192c393a42Smrgstatic FcFileTime
1202c393a42SmrgFcConfigNewestFile (FcStrSet *files)
1212c393a42Smrg{
1222c393a42Smrg    FcStrList	    *list = FcStrListCreate (files);
1232c393a42Smrg    FcFileTime	    newest = { 0, FcFalse };
1242c393a42Smrg    FcChar8	    *file;
1252c393a42Smrg    struct  stat    statb;
1262c393a42Smrg
1272c393a42Smrg    if (list)
1282c393a42Smrg    {
1292c393a42Smrg	while ((file = FcStrListNext (list)))
1302c393a42Smrg	    if (stat ((char *) file, &statb) == 0)
1312c393a42Smrg		if (!newest.set || statb.st_mtime - newest.time > 0)
1322c393a42Smrg		{
1332c393a42Smrg		    newest.set = FcTrue;
1342c393a42Smrg		    newest.time = statb.st_mtime;
1352c393a42Smrg		}
1362c393a42Smrg	FcStrListDone (list);
1372c393a42Smrg    }
1382c393a42Smrg    return newest;
1392c393a42Smrg}
1402c393a42Smrg
1412c393a42SmrgFcBool
1422c393a42SmrgFcConfigUptoDate (FcConfig *config)
1432c393a42Smrg{
1442c393a42Smrg    FcFileTime	config_time, config_dir_time, font_time;
1452c393a42Smrg    time_t	now = time(0);
1462c393a42Smrg    if (!config)
1472c393a42Smrg    {
1482c393a42Smrg	config = FcConfigGetCurrent ();
1492c393a42Smrg	if (!config)
1502c393a42Smrg	    return FcFalse;
1512c393a42Smrg    }
1522c393a42Smrg    config_time = FcConfigNewestFile (config->configFiles);
1532c393a42Smrg    config_dir_time = FcConfigNewestFile (config->configDirs);
1542c393a42Smrg    font_time = FcConfigNewestFile (config->fontDirs);
1552c393a42Smrg    if ((config_time.set && config_time.time - config->rescanTime > 0) ||
1562c393a42Smrg	(config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) ||
1572c393a42Smrg	(font_time.set && (font_time.time - config->rescanTime) > 0))
1582c393a42Smrg    {
1592c393a42Smrg	/* We need to check for potential clock problems here (OLPC ticket #6046) */
1602c393a42Smrg	if ((config_time.set && (config_time.time - now) > 0) ||
1612c393a42Smrg    	(config_dir_time.set && (config_dir_time.time - now) > 0) ||
1622c393a42Smrg        (font_time.set && (font_time.time - now) > 0))
1632c393a42Smrg	{
1642c393a42Smrg	    fprintf (stderr,
1652c393a42Smrg                    "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected\n");
1662c393a42Smrg	    config->rescanTime = now;
1672c393a42Smrg	    return FcTrue;
1682c393a42Smrg	}
1692c393a42Smrg	else
1702c393a42Smrg	    return FcFalse;
1712c393a42Smrg    }
1722c393a42Smrg    config->rescanTime = now;
1732c393a42Smrg    return FcTrue;
1742c393a42Smrg}
1752c393a42Smrg
1762c393a42Smrgstatic void
1772c393a42SmrgFcSubstDestroy (FcSubst *s)
1782c393a42Smrg{
1792c393a42Smrg    FcSubst *n;
1802c393a42Smrg
1812c393a42Smrg    while (s)
1822c393a42Smrg    {
1832c393a42Smrg	n = s->next;
1842c393a42Smrg	if (s->test)
1852c393a42Smrg	    FcTestDestroy (s->test);
1862c393a42Smrg	if (s->edit)
1872c393a42Smrg	    FcEditDestroy (s->edit);
1882c393a42Smrg	free (s);
1892c393a42Smrg	FcMemFree (FC_MEM_SUBST, sizeof (FcSubst));
1902c393a42Smrg	s = n;
1912c393a42Smrg    }
1922c393a42Smrg}
1932c393a42Smrg
1942c393a42Smrgvoid
1952c393a42SmrgFcConfigDestroy (FcConfig *config)
1962c393a42Smrg{
1972c393a42Smrg    FcSetName	set;
1982c393a42Smrg
1992c393a42Smrg    if (config == _fcConfig)
2002c393a42Smrg	_fcConfig = 0;
2012c393a42Smrg
2022c393a42Smrg    FcStrSetDestroy (config->configDirs);
2032c393a42Smrg    FcStrSetDestroy (config->fontDirs);
2042c393a42Smrg    FcStrSetDestroy (config->cacheDirs);
2052c393a42Smrg    FcStrSetDestroy (config->configFiles);
2062c393a42Smrg    FcStrSetDestroy (config->acceptGlobs);
2072c393a42Smrg    FcStrSetDestroy (config->rejectGlobs);
2082c393a42Smrg    FcFontSetDestroy (config->acceptPatterns);
2092c393a42Smrg    FcFontSetDestroy (config->rejectPatterns);
2102c393a42Smrg
2112c393a42Smrg    if (config->blanks)
2122c393a42Smrg	FcBlanksDestroy (config->blanks);
2132c393a42Smrg
2142c393a42Smrg    FcSubstDestroy (config->substPattern);
2152c393a42Smrg    FcSubstDestroy (config->substFont);
2162c393a42Smrg    FcSubstDestroy (config->substScan);
2172c393a42Smrg    for (set = FcSetSystem; set <= FcSetApplication; set++)
2182c393a42Smrg	if (config->fonts[set])
2192c393a42Smrg	    FcFontSetDestroy (config->fonts[set]);
2202c393a42Smrg
2212c393a42Smrg    free (config);
2222c393a42Smrg    FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
2232c393a42Smrg}
2242c393a42Smrg
2252c393a42Smrg/*
2262c393a42Smrg * Add cache to configuration, adding fonts and directories
2272c393a42Smrg */
2282c393a42Smrg
2292c393a42SmrgFcBool
2302c393a42SmrgFcConfigAddCache (FcConfig *config, FcCache *cache,
2312c393a42Smrg		  FcSetName set, FcStrSet *dirSet)
2322c393a42Smrg{
2332c393a42Smrg    FcFontSet	*fs;
2342c393a42Smrg    intptr_t	*dirs;
2352c393a42Smrg    int		i;
2362c393a42Smrg
2372c393a42Smrg    /*
2382c393a42Smrg     * Add fonts
2392c393a42Smrg     */
2402c393a42Smrg    fs = FcCacheSet (cache);
2412c393a42Smrg    if (fs)
2422c393a42Smrg    {
2432c393a42Smrg	int	nref = 0;
2442c393a42Smrg
2452c393a42Smrg	for (i = 0; i < fs->nfont; i++)
2462c393a42Smrg	{
2472c393a42Smrg	    FcPattern	*font = FcFontSetFont (fs, i);
2482c393a42Smrg	    FcChar8	*font_file;
2492c393a42Smrg
2502c393a42Smrg	    /*
2512c393a42Smrg	     * Check to see if font is banned by filename
2522c393a42Smrg	     */
2532c393a42Smrg	    if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
2542c393a42Smrg					  0, &font_file) == FcResultMatch &&
2552c393a42Smrg		!FcConfigAcceptFilename (config, font_file))
2562c393a42Smrg	    {
2572c393a42Smrg		continue;
2582c393a42Smrg	    }
2592c393a42Smrg
2602c393a42Smrg	    /*
2612c393a42Smrg	     * Check to see if font is banned by pattern
2622c393a42Smrg	     */
2632c393a42Smrg	    if (!FcConfigAcceptFont (config, font))
2642c393a42Smrg		continue;
2652c393a42Smrg
2662c393a42Smrg	    nref++;
2672c393a42Smrg	    FcFontSetAdd (config->fonts[set], font);
2682c393a42Smrg	}
2692c393a42Smrg	FcDirCacheReference (cache, nref);
2702c393a42Smrg    }
2712c393a42Smrg
2722c393a42Smrg    /*
2732c393a42Smrg     * Add directories
2742c393a42Smrg     */
2752c393a42Smrg    dirs = FcCacheDirs (cache);
2762c393a42Smrg    if (dirs)
2772c393a42Smrg    {
2782c393a42Smrg	for (i = 0; i < cache->dirs_count; i++)
2792c393a42Smrg	{
2802c393a42Smrg	    FcChar8	*dir = FcOffsetToPtr (dirs, dirs[i], FcChar8);
2812c393a42Smrg	    if (FcConfigAcceptFilename (config, dir))
2822c393a42Smrg		FcStrSetAddFilename (dirSet, dir);
2832c393a42Smrg	}
2842c393a42Smrg    }
2852c393a42Smrg    return FcTrue;
2862c393a42Smrg}
2872c393a42Smrg
2882c393a42Smrgstatic FcBool
2892c393a42SmrgFcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
2902c393a42Smrg{
2912c393a42Smrg    FcStrList	    *dirlist;
2922c393a42Smrg    FcChar8	    *dir;
2932c393a42Smrg    FcCache	    *cache;
2942c393a42Smrg
2952c393a42Smrg    dirlist = FcStrListCreate (dirSet);
2962c393a42Smrg    if (!dirlist)
2972c393a42Smrg        return FcFalse;
2982c393a42Smrg
2992c393a42Smrg    while ((dir = FcStrListNext (dirlist)))
3002c393a42Smrg    {
3012c393a42Smrg	if (FcDebug () & FC_DBG_FONTSET)
3022c393a42Smrg	    printf ("adding fonts from%s\n", dir);
3032c393a42Smrg	cache = FcDirCacheRead (dir, FcFalse, config);
3042c393a42Smrg	if (!cache)
3052c393a42Smrg	    continue;
3062c393a42Smrg	FcConfigAddCache (config, cache, set, dirSet);
3072c393a42Smrg	FcDirCacheUnload (cache);
3082c393a42Smrg    }
3092c393a42Smrg    FcStrListDone (dirlist);
3102c393a42Smrg    return FcTrue;
3112c393a42Smrg}
3122c393a42Smrg
3132c393a42Smrg/*
3142c393a42Smrg * Scan the current list of directories in the configuration
3152c393a42Smrg * and build the set of available fonts.
3162c393a42Smrg */
3172c393a42Smrg
3182c393a42SmrgFcBool
3192c393a42SmrgFcConfigBuildFonts (FcConfig *config)
3202c393a42Smrg{
3212c393a42Smrg    FcFontSet	    *fonts;
3222c393a42Smrg
3232c393a42Smrg    if (!config)
3242c393a42Smrg    {
3252c393a42Smrg	config = FcConfigGetCurrent ();
3262c393a42Smrg	if (!config)
3272c393a42Smrg	    return FcFalse;
3282c393a42Smrg    }
3292c393a42Smrg
3302c393a42Smrg    fonts = FcFontSetCreate ();
3312c393a42Smrg    if (!fonts)
3322c393a42Smrg	return FcFalse;
3332c393a42Smrg
3342c393a42Smrg    FcConfigSetFonts (config, fonts, FcSetSystem);
3352c393a42Smrg
3362c393a42Smrg    if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs))
3372c393a42Smrg	return FcFalse;
3382c393a42Smrg    if (FcDebug () & FC_DBG_FONTSET)
3392c393a42Smrg	FcFontSetPrint (fonts);
3402c393a42Smrg    return FcTrue;
3412c393a42Smrg}
3422c393a42Smrg
3432c393a42SmrgFcBool
3442c393a42SmrgFcConfigSetCurrent (FcConfig *config)
3452c393a42Smrg{
3462c393a42Smrg    if (config == _fcConfig)
3472c393a42Smrg	return FcTrue;
3482c393a42Smrg
3492c393a42Smrg    if (!config->fonts)
3502c393a42Smrg	if (!FcConfigBuildFonts (config))
3512c393a42Smrg	    return FcFalse;
3522c393a42Smrg
3532c393a42Smrg    if (_fcConfig)
3542c393a42Smrg	FcConfigDestroy (_fcConfig);
3552c393a42Smrg    _fcConfig = config;
3562c393a42Smrg    return FcTrue;
3572c393a42Smrg}
3582c393a42Smrg
3592c393a42SmrgFcConfig *
3602c393a42SmrgFcConfigGetCurrent (void)
3612c393a42Smrg{
3622c393a42Smrg    if (!_fcConfig)
3632c393a42Smrg	if (!FcInit ())
3642c393a42Smrg	    return 0;
3652c393a42Smrg    return _fcConfig;
3662c393a42Smrg}
3672c393a42Smrg
3682c393a42SmrgFcBool
3692c393a42SmrgFcConfigAddConfigDir (FcConfig	    *config,
3702c393a42Smrg		      const FcChar8 *d)
3712c393a42Smrg{
3722c393a42Smrg    return FcStrSetAddFilename (config->configDirs, d);
3732c393a42Smrg}
3742c393a42Smrg
3752c393a42SmrgFcStrList *
3762c393a42SmrgFcConfigGetConfigDirs (FcConfig   *config)
3772c393a42Smrg{
3782c393a42Smrg    if (!config)
3792c393a42Smrg    {
3802c393a42Smrg	config = FcConfigGetCurrent ();
3812c393a42Smrg	if (!config)
3822c393a42Smrg	    return 0;
3832c393a42Smrg    }
3842c393a42Smrg    return FcStrListCreate (config->configDirs);
3852c393a42Smrg}
3862c393a42Smrg
3872c393a42SmrgFcBool
3882c393a42SmrgFcConfigAddFontDir (FcConfig	    *config,
3892c393a42Smrg		    const FcChar8   *d)
3902c393a42Smrg{
3912c393a42Smrg    return FcStrSetAddFilename (config->fontDirs, d);
3922c393a42Smrg}
3932c393a42Smrg
3942c393a42SmrgFcBool
3952c393a42SmrgFcConfigAddDir (FcConfig	    *config,
3962c393a42Smrg		const FcChar8	    *d)
3972c393a42Smrg{
3982c393a42Smrg    return (FcConfigAddConfigDir (config, d) &&
3992c393a42Smrg	    FcConfigAddFontDir (config, d));
4002c393a42Smrg}
4012c393a42Smrg
4022c393a42SmrgFcStrList *
4032c393a42SmrgFcConfigGetFontDirs (FcConfig	*config)
4042c393a42Smrg{
4052c393a42Smrg    if (!config)
4062c393a42Smrg    {
4072c393a42Smrg	config = FcConfigGetCurrent ();
4082c393a42Smrg	if (!config)
4092c393a42Smrg	    return 0;
4102c393a42Smrg    }
4112c393a42Smrg    return FcStrListCreate (config->fontDirs);
4122c393a42Smrg}
4132c393a42Smrg
4142c393a42SmrgFcBool
4152c393a42SmrgFcConfigAddCacheDir (FcConfig	    *config,
4162c393a42Smrg		     const FcChar8  *d)
4172c393a42Smrg{
4182c393a42Smrg    return FcStrSetAddFilename (config->cacheDirs, d);
4192c393a42Smrg}
4202c393a42Smrg
4212c393a42SmrgFcStrList *
4222c393a42SmrgFcConfigGetCacheDirs (FcConfig	*config)
4232c393a42Smrg{
4242c393a42Smrg    if (!config)
4252c393a42Smrg    {
4262c393a42Smrg	config = FcConfigGetCurrent ();
4272c393a42Smrg	if (!config)
4282c393a42Smrg	    return 0;
4292c393a42Smrg    }
4302c393a42Smrg    return FcStrListCreate (config->cacheDirs);
4312c393a42Smrg}
4322c393a42Smrg
4332c393a42SmrgFcBool
4342c393a42SmrgFcConfigAddConfigFile (FcConfig	    *config,
4352c393a42Smrg		       const FcChar8   *f)
4362c393a42Smrg{
4372c393a42Smrg    FcBool	ret;
4382c393a42Smrg    FcChar8	*file = FcConfigFilename (f);
4392c393a42Smrg
4402c393a42Smrg    if (!file)
4412c393a42Smrg	return FcFalse;
4422c393a42Smrg
4432c393a42Smrg    ret = FcStrSetAdd (config->configFiles, file);
4442c393a42Smrg    FcStrFree (file);
4452c393a42Smrg    return ret;
4462c393a42Smrg}
4472c393a42Smrg
4482c393a42SmrgFcStrList *
4492c393a42SmrgFcConfigGetConfigFiles (FcConfig    *config)
4502c393a42Smrg{
4512c393a42Smrg    if (!config)
4522c393a42Smrg    {
4532c393a42Smrg	config = FcConfigGetCurrent ();
4542c393a42Smrg	if (!config)
4552c393a42Smrg	    return 0;
4562c393a42Smrg    }
4572c393a42Smrg    return FcStrListCreate (config->configFiles);
4582c393a42Smrg}
4592c393a42Smrg
4602c393a42SmrgFcChar8 *
4612c393a42SmrgFcConfigGetCache (FcConfig  *config)
4622c393a42Smrg{
4632c393a42Smrg    return NULL;
4642c393a42Smrg}
4652c393a42Smrg
4662c393a42SmrgFcFontSet *
4672c393a42SmrgFcConfigGetFonts (FcConfig	*config,
4682c393a42Smrg		  FcSetName	set)
4692c393a42Smrg{
4702c393a42Smrg    if (!config)
4712c393a42Smrg    {
4722c393a42Smrg	config = FcConfigGetCurrent ();
4732c393a42Smrg	if (!config)
4742c393a42Smrg	    return 0;
4752c393a42Smrg    }
4762c393a42Smrg    return config->fonts[set];
4772c393a42Smrg}
4782c393a42Smrg
4792c393a42Smrgvoid
4802c393a42SmrgFcConfigSetFonts (FcConfig	*config,
4812c393a42Smrg		  FcFontSet	*fonts,
4822c393a42Smrg		  FcSetName	set)
4832c393a42Smrg{
4842c393a42Smrg    if (config->fonts[set])
4852c393a42Smrg	FcFontSetDestroy (config->fonts[set]);
4862c393a42Smrg    config->fonts[set] = fonts;
4872c393a42Smrg}
4882c393a42Smrg
4892c393a42SmrgFcBlanks *
4902c393a42SmrgFcConfigGetBlanks (FcConfig	*config)
4912c393a42Smrg{
4922c393a42Smrg    if (!config)
4932c393a42Smrg    {
4942c393a42Smrg	config = FcConfigGetCurrent ();
4952c393a42Smrg	if (!config)
4962c393a42Smrg	    return 0;
4972c393a42Smrg    }
4982c393a42Smrg    return config->blanks;
4992c393a42Smrg}
5002c393a42Smrg
5012c393a42SmrgFcBool
5022c393a42SmrgFcConfigAddBlank (FcConfig	*config,
5032c393a42Smrg		  FcChar32    	blank)
5042c393a42Smrg{
5052c393a42Smrg    FcBlanks	*b, *freeme = 0;
5062c393a42Smrg
5072c393a42Smrg    b = config->blanks;
5082c393a42Smrg    if (!b)
5092c393a42Smrg    {
5102c393a42Smrg	freeme = b = FcBlanksCreate ();
5112c393a42Smrg	if (!b)
5122c393a42Smrg	    return FcFalse;
5132c393a42Smrg    }
5142c393a42Smrg    if (!FcBlanksAdd (b, blank))
5152c393a42Smrg    {
5162c393a42Smrg        if (freeme)
5172c393a42Smrg            FcBlanksDestroy (freeme);
5182c393a42Smrg	return FcFalse;
5192c393a42Smrg    }
5202c393a42Smrg    config->blanks = b;
5212c393a42Smrg    return FcTrue;
5222c393a42Smrg}
5232c393a42Smrg
5242c393a42Smrgint
5252c393a42SmrgFcConfigGetRescanInterval (FcConfig *config)
5262c393a42Smrg{
5272c393a42Smrg    if (!config)
5282c393a42Smrg    {
5292c393a42Smrg	config = FcConfigGetCurrent ();
5302c393a42Smrg	if (!config)
5312c393a42Smrg	    return 0;
5322c393a42Smrg    }
5332c393a42Smrg    return config->rescanInterval;
5342c393a42Smrg}
5352c393a42Smrg
5362c393a42SmrgFcBool
5372c393a42SmrgFcConfigSetRescanInterval (FcConfig *config, int rescanInterval)
5382c393a42Smrg{
5392c393a42Smrg    if (!config)
5402c393a42Smrg    {
5412c393a42Smrg	config = FcConfigGetCurrent ();
5422c393a42Smrg	if (!config)
5432c393a42Smrg	    return FcFalse;
5442c393a42Smrg    }
5452c393a42Smrg    config->rescanInterval = rescanInterval;
5462c393a42Smrg    return FcTrue;
5472c393a42Smrg}
5482c393a42Smrg
5492c393a42Smrg/*
5502c393a42Smrg * A couple of typos escaped into the library
5512c393a42Smrg */
5522c393a42Smrgint
5532c393a42SmrgFcConfigGetRescanInverval (FcConfig *config)
5542c393a42Smrg{
5552c393a42Smrg    return FcConfigGetRescanInterval (config);
5562c393a42Smrg}
5572c393a42Smrg
5582c393a42SmrgFcBool
5592c393a42SmrgFcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
5602c393a42Smrg{
5612c393a42Smrg    return FcConfigSetRescanInterval (config, rescanInterval);
5622c393a42Smrg}
5632c393a42Smrg
5642c393a42Smrg
5652c393a42SmrgFcBool
5662c393a42SmrgFcConfigAddEdit (FcConfig	*config,
5672c393a42Smrg		 FcTest		*test,
5682c393a42Smrg		 FcEdit		*edit,
5692c393a42Smrg		 FcMatchKind	kind)
5702c393a42Smrg{
5712c393a42Smrg    FcSubst	*subst, **prev;
5722c393a42Smrg    FcTest	*t;
5732c393a42Smrg    int		num;
5742c393a42Smrg
5752c393a42Smrg    switch (kind) {
5762c393a42Smrg    case FcMatchPattern:
5772c393a42Smrg	prev = &config->substPattern;
5782c393a42Smrg	break;
5792c393a42Smrg    case FcMatchFont:
5802c393a42Smrg	prev = &config->substFont;
5812c393a42Smrg	break;
5822c393a42Smrg    case FcMatchScan:
5832c393a42Smrg	prev = &config->substScan;
5842c393a42Smrg	break;
5852c393a42Smrg    default:
5862c393a42Smrg	return FcFalse;
5872c393a42Smrg    }
5882c393a42Smrg    subst = (FcSubst *) malloc (sizeof (FcSubst));
5892c393a42Smrg    if (!subst)
5902c393a42Smrg	return FcFalse;
5912c393a42Smrg    FcMemAlloc (FC_MEM_SUBST, sizeof (FcSubst));
5922c393a42Smrg    for (; *prev; prev = &(*prev)->next);
5932c393a42Smrg    *prev = subst;
5942c393a42Smrg    subst->next = 0;
5952c393a42Smrg    subst->test = test;
5962c393a42Smrg    subst->edit = edit;
5972c393a42Smrg    num = 0;
5982c393a42Smrg    for (t = test; t; t = t->next)
5992c393a42Smrg    {
6002c393a42Smrg	if (t->kind == FcMatchDefault)
6012c393a42Smrg	    t->kind = kind;
6022c393a42Smrg	num++;
6032c393a42Smrg    }
6042c393a42Smrg    if (config->maxObjects < num)
6052c393a42Smrg	config->maxObjects = num;
6062c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
6072c393a42Smrg    {
6082c393a42Smrg	printf ("Add Subst ");
6092c393a42Smrg	FcSubstPrint (subst);
6102c393a42Smrg    }
6112c393a42Smrg    return FcTrue;
6122c393a42Smrg}
6132c393a42Smrg
6142c393a42Smrgtypedef struct _FcSubState {
6152c393a42Smrg    FcPatternElt   *elt;
6162c393a42Smrg    FcValueList    *value;
6172c393a42Smrg} FcSubState;
6182c393a42Smrg
6192c393a42Smrgstatic FcValue
6202c393a42SmrgFcConfigPromote (FcValue v, FcValue u)
6212c393a42Smrg{
6222c393a42Smrg    if (v.type == FcTypeInteger)
6232c393a42Smrg    {
6242c393a42Smrg	v.type = FcTypeDouble;
6252c393a42Smrg	v.u.d = (double) v.u.i;
6262c393a42Smrg    }
6272c393a42Smrg    else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
6282c393a42Smrg    {
6292c393a42Smrg	v.u.m = &FcIdentityMatrix;
6302c393a42Smrg	v.type = FcTypeMatrix;
6312c393a42Smrg    }
6322c393a42Smrg    else if (v.type == FcTypeString && u.type == FcTypeLangSet)
6332c393a42Smrg    {
6342c393a42Smrg	v.u.l = FcLangSetPromote (v.u.s);
6352c393a42Smrg	v.type = FcTypeLangSet;
6362c393a42Smrg    }
6372c393a42Smrg    return v;
6382c393a42Smrg}
6392c393a42Smrg
6402c393a42SmrgFcBool
6412c393a42SmrgFcConfigCompareValue (const FcValue	*left_o,
6422c393a42Smrg		      FcOp		op,
6432c393a42Smrg		      const FcValue	*right_o)
6442c393a42Smrg{
6452c393a42Smrg    FcValue	left = FcValueCanonicalize(left_o);
6462c393a42Smrg    FcValue	right = FcValueCanonicalize(right_o);
6472c393a42Smrg    FcBool	ret = FcFalse;
6482c393a42Smrg
6492c393a42Smrg    left = FcConfigPromote (left, right);
6502c393a42Smrg    right = FcConfigPromote (right, left);
6512c393a42Smrg    if (left.type == right.type)
6522c393a42Smrg    {
6532c393a42Smrg	switch (left.type) {
6542c393a42Smrg	case FcTypeInteger:
6552c393a42Smrg	    break;	/* FcConfigPromote prevents this from happening */
6562c393a42Smrg	case FcTypeDouble:
6572c393a42Smrg	    switch (op) {
6582c393a42Smrg	    case FcOpEqual:
6592c393a42Smrg	    case FcOpContains:
6602c393a42Smrg	    case FcOpListing:
6612c393a42Smrg		ret = left.u.d == right.u.d;
6622c393a42Smrg		break;
6632c393a42Smrg	    case FcOpNotEqual:
6642c393a42Smrg	    case FcOpNotContains:
6652c393a42Smrg		ret = left.u.d != right.u.d;
6662c393a42Smrg		break;
6672c393a42Smrg	    case FcOpLess:
6682c393a42Smrg		ret = left.u.d < right.u.d;
6692c393a42Smrg		break;
6702c393a42Smrg	    case FcOpLessEqual:
6712c393a42Smrg		ret = left.u.d <= right.u.d;
6722c393a42Smrg		break;
6732c393a42Smrg	    case FcOpMore:
6742c393a42Smrg		ret = left.u.d > right.u.d;
6752c393a42Smrg		break;
6762c393a42Smrg	    case FcOpMoreEqual:
6772c393a42Smrg		ret = left.u.d >= right.u.d;
6782c393a42Smrg		break;
6792c393a42Smrg	    default:
6802c393a42Smrg		break;
6812c393a42Smrg	    }
6822c393a42Smrg	    break;
6832c393a42Smrg	case FcTypeBool:
6842c393a42Smrg	    switch (op) {
6852c393a42Smrg	    case FcOpEqual:
6862c393a42Smrg	    case FcOpContains:
6872c393a42Smrg	    case FcOpListing:
6882c393a42Smrg		ret = left.u.b == right.u.b;
6892c393a42Smrg		break;
6902c393a42Smrg	    case FcOpNotEqual:
6912c393a42Smrg	    case FcOpNotContains:
6922c393a42Smrg		ret = left.u.b != right.u.b;
6932c393a42Smrg		break;
6942c393a42Smrg	    default:
6952c393a42Smrg		break;
6962c393a42Smrg	    }
6972c393a42Smrg	    break;
6982c393a42Smrg	case FcTypeString:
6992c393a42Smrg	    switch (op) {
7002c393a42Smrg	    case FcOpEqual:
7012c393a42Smrg	    case FcOpListing:
7022c393a42Smrg		ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
7032c393a42Smrg		break;
7042c393a42Smrg	    case FcOpContains:
7052c393a42Smrg		ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
7062c393a42Smrg		break;
7072c393a42Smrg	    case FcOpNotEqual:
7082c393a42Smrg		ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
7092c393a42Smrg		break;
7102c393a42Smrg	    case FcOpNotContains:
7112c393a42Smrg		ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
7122c393a42Smrg		break;
7132c393a42Smrg	    default:
7142c393a42Smrg		break;
7152c393a42Smrg	    }
7162c393a42Smrg	    break;
7172c393a42Smrg	case FcTypeMatrix:
7182c393a42Smrg	    switch (op) {
7192c393a42Smrg	    case FcOpEqual:
7202c393a42Smrg	    case FcOpContains:
7212c393a42Smrg	    case FcOpListing:
7222c393a42Smrg		ret = FcMatrixEqual (left.u.m, right.u.m);
7232c393a42Smrg		break;
7242c393a42Smrg	    case FcOpNotEqual:
7252c393a42Smrg	    case FcOpNotContains:
7262c393a42Smrg		ret = !FcMatrixEqual (left.u.m, right.u.m);
7272c393a42Smrg		break;
7282c393a42Smrg	    default:
7292c393a42Smrg		break;
7302c393a42Smrg	    }
7312c393a42Smrg	    break;
7322c393a42Smrg	case FcTypeCharSet:
7332c393a42Smrg	    switch (op) {
7342c393a42Smrg	    case FcOpContains:
7352c393a42Smrg	    case FcOpListing:
7362c393a42Smrg		/* left contains right if right is a subset of left */
7372c393a42Smrg		ret = FcCharSetIsSubset (right.u.c, left.u.c);
7382c393a42Smrg		break;
7392c393a42Smrg	    case FcOpNotContains:
7402c393a42Smrg		/* left contains right if right is a subset of left */
7412c393a42Smrg		ret = !FcCharSetIsSubset (right.u.c, left.u.c);
7422c393a42Smrg		break;
7432c393a42Smrg	    case FcOpEqual:
7442c393a42Smrg		ret = FcCharSetEqual (left.u.c, right.u.c);
7452c393a42Smrg		break;
7462c393a42Smrg	    case FcOpNotEqual:
7472c393a42Smrg		ret = !FcCharSetEqual (left.u.c, right.u.c);
7482c393a42Smrg		break;
7492c393a42Smrg	    default:
7502c393a42Smrg		break;
7512c393a42Smrg	    }
7522c393a42Smrg	    break;
7532c393a42Smrg	case FcTypeLangSet:
7542c393a42Smrg	    switch (op) {
7552c393a42Smrg	    case FcOpContains:
7562c393a42Smrg	    case FcOpListing:
7572c393a42Smrg		ret = FcLangSetContains (left.u.l, right.u.l);
7582c393a42Smrg		break;
7592c393a42Smrg	    case FcOpNotContains:
7602c393a42Smrg		ret = !FcLangSetContains (left.u.l, right.u.l);
7612c393a42Smrg		break;
7622c393a42Smrg	    case FcOpEqual:
7632c393a42Smrg		ret = FcLangSetEqual (left.u.l, right.u.l);
7642c393a42Smrg		break;
7652c393a42Smrg	    case FcOpNotEqual:
7662c393a42Smrg		ret = !FcLangSetEqual (left.u.l, right.u.l);
7672c393a42Smrg		break;
7682c393a42Smrg	    default:
7692c393a42Smrg		break;
7702c393a42Smrg	    }
7712c393a42Smrg	    break;
7722c393a42Smrg	case FcTypeVoid:
7732c393a42Smrg	    switch (op) {
7742c393a42Smrg	    case FcOpEqual:
7752c393a42Smrg	    case FcOpContains:
7762c393a42Smrg	    case FcOpListing:
7772c393a42Smrg		ret = FcTrue;
7782c393a42Smrg		break;
7792c393a42Smrg	    default:
7802c393a42Smrg		break;
7812c393a42Smrg	    }
7822c393a42Smrg	    break;
7832c393a42Smrg	case FcTypeFTFace:
7842c393a42Smrg	    switch (op) {
7852c393a42Smrg	    case FcOpEqual:
7862c393a42Smrg	    case FcOpContains:
7872c393a42Smrg	    case FcOpListing:
7882c393a42Smrg		ret = left.u.f == right.u.f;
7892c393a42Smrg		break;
7902c393a42Smrg	    case FcOpNotEqual:
7912c393a42Smrg	    case FcOpNotContains:
7922c393a42Smrg		ret = left.u.f != right.u.f;
7932c393a42Smrg		break;
7942c393a42Smrg	    default:
7952c393a42Smrg		break;
7962c393a42Smrg	    }
7972c393a42Smrg	    break;
7982c393a42Smrg	}
7992c393a42Smrg    }
8002c393a42Smrg    else
8012c393a42Smrg    {
8022c393a42Smrg	if (op == FcOpNotEqual || op == FcOpNotContains)
8032c393a42Smrg	    ret = FcTrue;
8042c393a42Smrg    }
8052c393a42Smrg    return ret;
8062c393a42Smrg}
8072c393a42Smrg
8082c393a42Smrg
8092c393a42Smrg#define _FcDoubleFloor(d)	((int) (d))
8102c393a42Smrg#define _FcDoubleCeil(d)	((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
8112c393a42Smrg#define FcDoubleFloor(d)	((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
8122c393a42Smrg#define FcDoubleCeil(d)		((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
8132c393a42Smrg#define FcDoubleRound(d)	FcDoubleFloor ((d) + 0.5)
8142c393a42Smrg#define FcDoubleTrunc(d)	((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
8152c393a42Smrg
8162c393a42Smrgstatic FcValue
8172c393a42SmrgFcConfigEvaluate (FcPattern *p, FcExpr *e)
8182c393a42Smrg{
8192c393a42Smrg    FcValue	v, vl, vr;
8202c393a42Smrg    FcResult	r;
8212c393a42Smrg    FcMatrix	*m;
8222c393a42Smrg    FcChar8     *str;
8232c393a42Smrg
8242c393a42Smrg    switch (e->op) {
8252c393a42Smrg    case FcOpInteger:
8262c393a42Smrg	v.type = FcTypeInteger;
8272c393a42Smrg	v.u.i = e->u.ival;
8282c393a42Smrg	break;
8292c393a42Smrg    case FcOpDouble:
8302c393a42Smrg	v.type = FcTypeDouble;
8312c393a42Smrg	v.u.d = e->u.dval;
8322c393a42Smrg	break;
8332c393a42Smrg    case FcOpString:
8342c393a42Smrg	v.type = FcTypeString;
8352c393a42Smrg	v.u.s = FcStrStaticName(e->u.sval);
8362c393a42Smrg	break;
8372c393a42Smrg    case FcOpMatrix:
8382c393a42Smrg	v.type = FcTypeMatrix;
8392c393a42Smrg	v.u.m = e->u.mval;
8402c393a42Smrg	v = FcValueSave (v);
8412c393a42Smrg	break;
8422c393a42Smrg    case FcOpCharSet:
8432c393a42Smrg	v.type = FcTypeCharSet;
8442c393a42Smrg	v.u.c = e->u.cval;
8452c393a42Smrg	v = FcValueSave (v);
8462c393a42Smrg	break;
8472c393a42Smrg    case FcOpBool:
8482c393a42Smrg	v.type = FcTypeBool;
8492c393a42Smrg	v.u.b = e->u.bval;
8502c393a42Smrg	break;
8512c393a42Smrg    case FcOpField:
8522c393a42Smrg	r = FcPatternObjectGet (p, e->u.object, 0, &v);
8532c393a42Smrg	if (r != FcResultMatch)
8542c393a42Smrg	    v.type = FcTypeVoid;
8552c393a42Smrg	v = FcValueSave (v);
8562c393a42Smrg	break;
8572c393a42Smrg    case FcOpConst:
8582c393a42Smrg	if (FcNameConstant (e->u.constant, &v.u.i))
8592c393a42Smrg	    v.type = FcTypeInteger;
8602c393a42Smrg	else
8612c393a42Smrg	    v.type = FcTypeVoid;
8622c393a42Smrg	break;
8632c393a42Smrg    case FcOpQuest:
8642c393a42Smrg	vl = FcConfigEvaluate (p, e->u.tree.left);
8652c393a42Smrg	if (vl.type == FcTypeBool)
8662c393a42Smrg	{
8672c393a42Smrg	    if (vl.u.b)
8682c393a42Smrg		v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
8692c393a42Smrg	    else
8702c393a42Smrg		v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
8712c393a42Smrg	}
8722c393a42Smrg	else
8732c393a42Smrg	    v.type = FcTypeVoid;
8742c393a42Smrg	FcValueDestroy (vl);
8752c393a42Smrg	break;
8762c393a42Smrg    case FcOpEqual:
8772c393a42Smrg    case FcOpNotEqual:
8782c393a42Smrg    case FcOpLess:
8792c393a42Smrg    case FcOpLessEqual:
8802c393a42Smrg    case FcOpMore:
8812c393a42Smrg    case FcOpMoreEqual:
8822c393a42Smrg    case FcOpContains:
8832c393a42Smrg    case FcOpNotContains:
8842c393a42Smrg    case FcOpListing:
8852c393a42Smrg	vl = FcConfigEvaluate (p, e->u.tree.left);
8862c393a42Smrg	vr = FcConfigEvaluate (p, e->u.tree.right);
8872c393a42Smrg	v.type = FcTypeBool;
8882c393a42Smrg	v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
8892c393a42Smrg	FcValueDestroy (vl);
8902c393a42Smrg	FcValueDestroy (vr);
8912c393a42Smrg	break;
8922c393a42Smrg    case FcOpOr:
8932c393a42Smrg    case FcOpAnd:
8942c393a42Smrg    case FcOpPlus:
8952c393a42Smrg    case FcOpMinus:
8962c393a42Smrg    case FcOpTimes:
8972c393a42Smrg    case FcOpDivide:
8982c393a42Smrg	vl = FcConfigEvaluate (p, e->u.tree.left);
8992c393a42Smrg	vr = FcConfigEvaluate (p, e->u.tree.right);
9002c393a42Smrg	vl = FcConfigPromote (vl, vr);
9012c393a42Smrg	vr = FcConfigPromote (vr, vl);
9022c393a42Smrg	if (vl.type == vr.type)
9032c393a42Smrg	{
9042c393a42Smrg	    switch (vl.type) {
9052c393a42Smrg	    case FcTypeDouble:
9062c393a42Smrg		switch (e->op) {
9072c393a42Smrg		case FcOpPlus:
9082c393a42Smrg		    v.type = FcTypeDouble;
9092c393a42Smrg		    v.u.d = vl.u.d + vr.u.d;
9102c393a42Smrg		    break;
9112c393a42Smrg		case FcOpMinus:
9122c393a42Smrg		    v.type = FcTypeDouble;
9132c393a42Smrg		    v.u.d = vl.u.d - vr.u.d;
9142c393a42Smrg		    break;
9152c393a42Smrg		case FcOpTimes:
9162c393a42Smrg		    v.type = FcTypeDouble;
9172c393a42Smrg		    v.u.d = vl.u.d * vr.u.d;
9182c393a42Smrg		    break;
9192c393a42Smrg		case FcOpDivide:
9202c393a42Smrg		    v.type = FcTypeDouble;
9212c393a42Smrg		    v.u.d = vl.u.d / vr.u.d;
9222c393a42Smrg		    break;
9232c393a42Smrg		default:
9242c393a42Smrg		    v.type = FcTypeVoid;
9252c393a42Smrg		    break;
9262c393a42Smrg		}
9272c393a42Smrg		if (v.type == FcTypeDouble &&
9282c393a42Smrg		    v.u.d == (double) (int) v.u.d)
9292c393a42Smrg		{
9302c393a42Smrg		    v.type = FcTypeInteger;
9312c393a42Smrg		    v.u.i = (int) v.u.d;
9322c393a42Smrg		}
9332c393a42Smrg		break;
9342c393a42Smrg	    case FcTypeBool:
9352c393a42Smrg		switch (e->op) {
9362c393a42Smrg		case FcOpOr:
9372c393a42Smrg		    v.type = FcTypeBool;
9382c393a42Smrg		    v.u.b = vl.u.b || vr.u.b;
9392c393a42Smrg		    break;
9402c393a42Smrg		case FcOpAnd:
9412c393a42Smrg		    v.type = FcTypeBool;
9422c393a42Smrg		    v.u.b = vl.u.b && vr.u.b;
9432c393a42Smrg		    break;
9442c393a42Smrg		default:
9452c393a42Smrg		    v.type = FcTypeVoid;
9462c393a42Smrg		    break;
9472c393a42Smrg		}
9482c393a42Smrg		break;
9492c393a42Smrg	    case FcTypeString:
9502c393a42Smrg		switch (e->op) {
9512c393a42Smrg		case FcOpPlus:
9522c393a42Smrg		    v.type = FcTypeString;
9532c393a42Smrg		    str = FcStrPlus (vl.u.s, vr.u.s);
9542c393a42Smrg		    v.u.s = FcStrStaticName (str);
9552c393a42Smrg		    FcStrFree (str);
9562c393a42Smrg
9572c393a42Smrg		    if (!v.u.s)
9582c393a42Smrg			v.type = FcTypeVoid;
9592c393a42Smrg		    break;
9602c393a42Smrg		default:
9612c393a42Smrg		    v.type = FcTypeVoid;
9622c393a42Smrg		    break;
9632c393a42Smrg		}
9642c393a42Smrg		break;
9652c393a42Smrg	    case FcTypeMatrix:
9662c393a42Smrg		switch (e->op) {
9672c393a42Smrg		case FcOpTimes:
9682c393a42Smrg		    v.type = FcTypeMatrix;
9692c393a42Smrg		    m = malloc (sizeof (FcMatrix));
9702c393a42Smrg		    if (m)
9712c393a42Smrg		    {
9722c393a42Smrg			FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
9732c393a42Smrg			FcMatrixMultiply (m, vl.u.m, vr.u.m);
9742c393a42Smrg			v.u.m = m;
9752c393a42Smrg		    }
9762c393a42Smrg		    else
9772c393a42Smrg		    {
9782c393a42Smrg			v.type = FcTypeVoid;
9792c393a42Smrg		    }
9802c393a42Smrg		    break;
9812c393a42Smrg		default:
9822c393a42Smrg		    v.type = FcTypeVoid;
9832c393a42Smrg		    break;
9842c393a42Smrg		}
9852c393a42Smrg		break;
9862c393a42Smrg	    default:
9872c393a42Smrg		v.type = FcTypeVoid;
9882c393a42Smrg		break;
9892c393a42Smrg	    }
9902c393a42Smrg	}
9912c393a42Smrg	else
9922c393a42Smrg	    v.type = FcTypeVoid;
9932c393a42Smrg	FcValueDestroy (vl);
9942c393a42Smrg	FcValueDestroy (vr);
9952c393a42Smrg	break;
9962c393a42Smrg    case FcOpNot:
9972c393a42Smrg	vl = FcConfigEvaluate (p, e->u.tree.left);
9982c393a42Smrg	switch (vl.type) {
9992c393a42Smrg	case FcTypeBool:
10002c393a42Smrg	    v.type = FcTypeBool;
10012c393a42Smrg	    v.u.b = !vl.u.b;
10022c393a42Smrg	    break;
10032c393a42Smrg	default:
10042c393a42Smrg	    v.type = FcTypeVoid;
10052c393a42Smrg	    break;
10062c393a42Smrg	}
10072c393a42Smrg	FcValueDestroy (vl);
10082c393a42Smrg	break;
10092c393a42Smrg    case FcOpFloor:
10102c393a42Smrg	vl = FcConfigEvaluate (p, e->u.tree.left);
10112c393a42Smrg	switch (vl.type) {
10122c393a42Smrg	case FcTypeInteger:
10132c393a42Smrg	    v = vl;
10142c393a42Smrg	    break;
10152c393a42Smrg	case FcTypeDouble:
10162c393a42Smrg	    v.type = FcTypeInteger;
10172c393a42Smrg	    v.u.i = FcDoubleFloor (vl.u.d);
10182c393a42Smrg	    break;
10192c393a42Smrg	default:
10202c393a42Smrg	    v.type = FcTypeVoid;
10212c393a42Smrg	    break;
10222c393a42Smrg	}
10232c393a42Smrg	FcValueDestroy (vl);
10242c393a42Smrg	break;
10252c393a42Smrg    case FcOpCeil:
10262c393a42Smrg	vl = FcConfigEvaluate (p, e->u.tree.left);
10272c393a42Smrg	switch (vl.type) {
10282c393a42Smrg	case FcTypeInteger:
10292c393a42Smrg	    v = vl;
10302c393a42Smrg	    break;
10312c393a42Smrg	case FcTypeDouble:
10322c393a42Smrg	    v.type = FcTypeInteger;
10332c393a42Smrg	    v.u.i = FcDoubleCeil (vl.u.d);
10342c393a42Smrg	    break;
10352c393a42Smrg	default:
10362c393a42Smrg	    v.type = FcTypeVoid;
10372c393a42Smrg	    break;
10382c393a42Smrg	}
10392c393a42Smrg	FcValueDestroy (vl);
10402c393a42Smrg	break;
10412c393a42Smrg    case FcOpRound:
10422c393a42Smrg	vl = FcConfigEvaluate (p, e->u.tree.left);
10432c393a42Smrg	switch (vl.type) {
10442c393a42Smrg	case FcTypeInteger:
10452c393a42Smrg	    v = vl;
10462c393a42Smrg	    break;
10472c393a42Smrg	case FcTypeDouble:
10482c393a42Smrg	    v.type = FcTypeInteger;
10492c393a42Smrg	    v.u.i = FcDoubleRound (vl.u.d);
10502c393a42Smrg	    break;
10512c393a42Smrg	default:
10522c393a42Smrg	    v.type = FcTypeVoid;
10532c393a42Smrg	    break;
10542c393a42Smrg	}
10552c393a42Smrg	FcValueDestroy (vl);
10562c393a42Smrg	break;
10572c393a42Smrg    case FcOpTrunc:
10582c393a42Smrg	vl = FcConfigEvaluate (p, e->u.tree.left);
10592c393a42Smrg	switch (vl.type) {
10602c393a42Smrg	case FcTypeInteger:
10612c393a42Smrg	    v = vl;
10622c393a42Smrg	    break;
10632c393a42Smrg	case FcTypeDouble:
10642c393a42Smrg	    v.type = FcTypeInteger;
10652c393a42Smrg	    v.u.i = FcDoubleTrunc (vl.u.d);
10662c393a42Smrg	    break;
10672c393a42Smrg	default:
10682c393a42Smrg	    v.type = FcTypeVoid;
10692c393a42Smrg	    break;
10702c393a42Smrg	}
10712c393a42Smrg	FcValueDestroy (vl);
10722c393a42Smrg	break;
10732c393a42Smrg    default:
10742c393a42Smrg	v.type = FcTypeVoid;
10752c393a42Smrg	break;
10762c393a42Smrg    }
10772c393a42Smrg    return v;
10782c393a42Smrg}
10792c393a42Smrg
10802c393a42Smrgstatic FcValueList *
10812c393a42SmrgFcConfigMatchValueList (FcPattern	*p,
10822c393a42Smrg			FcTest		*t,
10832c393a42Smrg			FcValueList	*values)
10842c393a42Smrg{
10852c393a42Smrg    FcValueList	    *ret = 0;
10862c393a42Smrg    FcExpr	    *e = t->expr;
10872c393a42Smrg    FcValue	    value;
10882c393a42Smrg    FcValueList	    *v;
10892c393a42Smrg
10902c393a42Smrg    while (e)
10912c393a42Smrg    {
10922c393a42Smrg	/* Compute the value of the match expression */
10932c393a42Smrg	if (e->op == FcOpComma)
10942c393a42Smrg	{
10952c393a42Smrg	    value = FcConfigEvaluate (p, e->u.tree.left);
10962c393a42Smrg	    e = e->u.tree.right;
10972c393a42Smrg	}
10982c393a42Smrg	else
10992c393a42Smrg	{
11002c393a42Smrg	    value = FcConfigEvaluate (p, e);
11012c393a42Smrg	    e = 0;
11022c393a42Smrg	}
11032c393a42Smrg
11042c393a42Smrg	for (v = values; v; v = FcValueListNext(v))
11052c393a42Smrg	{
11062c393a42Smrg	    /* Compare the pattern value to the match expression value */
11072c393a42Smrg	    if (FcConfigCompareValue (&v->value, t->op, &value))
11082c393a42Smrg	    {
11092c393a42Smrg		if (!ret)
11102c393a42Smrg		    ret = v;
11112c393a42Smrg	    }
11122c393a42Smrg	    else
11132c393a42Smrg	    {
11142c393a42Smrg		if (t->qual == FcQualAll)
11152c393a42Smrg		{
11162c393a42Smrg		    ret = 0;
11172c393a42Smrg		    break;
11182c393a42Smrg		}
11192c393a42Smrg	    }
11202c393a42Smrg	}
11212c393a42Smrg	FcValueDestroy (value);
11222c393a42Smrg    }
11232c393a42Smrg    return ret;
11242c393a42Smrg}
11252c393a42Smrg
11262c393a42Smrgstatic FcValueList *
11272c393a42SmrgFcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding)
11282c393a42Smrg{
11292c393a42Smrg    FcValueList	*l;
11302c393a42Smrg
11312c393a42Smrg    if (!e)
11322c393a42Smrg	return 0;
11332c393a42Smrg    l = (FcValueList *) malloc (sizeof (FcValueList));
11342c393a42Smrg    if (!l)
11352c393a42Smrg	return 0;
11362c393a42Smrg    FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
11372c393a42Smrg    if (e->op == FcOpComma)
11382c393a42Smrg    {
11392c393a42Smrg	l->value = FcConfigEvaluate (p, e->u.tree.left);
11402c393a42Smrg	l->next = FcConfigValues (p, e->u.tree.right, binding);
11412c393a42Smrg    }
11422c393a42Smrg    else
11432c393a42Smrg    {
11442c393a42Smrg	l->value = FcConfigEvaluate (p, e);
11452c393a42Smrg	l->next = NULL;
11462c393a42Smrg    }
11472c393a42Smrg    l->binding = binding;
11482c393a42Smrg    if (l->value.type == FcTypeVoid)
11492c393a42Smrg    {
11502c393a42Smrg	FcValueList  *next = FcValueListNext(l);
11512c393a42Smrg
11522c393a42Smrg	FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
11532c393a42Smrg	free (l);
11542c393a42Smrg	l = next;
11552c393a42Smrg    }
11562c393a42Smrg
11572c393a42Smrg    return l;
11582c393a42Smrg}
11592c393a42Smrg
11602c393a42Smrgstatic FcBool
11612c393a42SmrgFcConfigAdd (FcValueListPtr *head,
11622c393a42Smrg	     FcValueList    *position,
11632c393a42Smrg	     FcBool	    append,
11642c393a42Smrg	     FcValueList    *new)
11652c393a42Smrg{
11662c393a42Smrg    FcValueListPtr  *prev, last, v;
11672c393a42Smrg    FcValueBinding  sameBinding;
11682c393a42Smrg
11692c393a42Smrg    if (position)
11702c393a42Smrg	sameBinding = position->binding;
11712c393a42Smrg    else
11722c393a42Smrg	sameBinding = FcValueBindingWeak;
11732c393a42Smrg    for (v = new; v != NULL; v = FcValueListNext(v))
11742c393a42Smrg	if (v->binding == FcValueBindingSame)
11752c393a42Smrg	    v->binding = sameBinding;
11762c393a42Smrg    if (append)
11772c393a42Smrg    {
11782c393a42Smrg	if (position)
11792c393a42Smrg	    prev = &position->next;
11802c393a42Smrg	else
11812c393a42Smrg	    for (prev = head; *prev != NULL;
11822c393a42Smrg		 prev = &(*prev)->next)
11832c393a42Smrg		;
11842c393a42Smrg    }
11852c393a42Smrg    else
11862c393a42Smrg    {
11872c393a42Smrg	if (position)
11882c393a42Smrg	{
11892c393a42Smrg	    for (prev = head; *prev != NULL;
11902c393a42Smrg		 prev = &(*prev)->next)
11912c393a42Smrg	    {
11922c393a42Smrg		if (*prev == position)
11932c393a42Smrg		    break;
11942c393a42Smrg	    }
11952c393a42Smrg	}
11962c393a42Smrg	else
11972c393a42Smrg	    prev = head;
11982c393a42Smrg
11992c393a42Smrg	if (FcDebug () & FC_DBG_EDIT)
12002c393a42Smrg	{
12012c393a42Smrg	    if (*prev == NULL)
12022c393a42Smrg		printf ("position not on list\n");
12032c393a42Smrg	}
12042c393a42Smrg    }
12052c393a42Smrg
12062c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
12072c393a42Smrg    {
12082c393a42Smrg	printf ("%s list before ", append ? "Append" : "Prepend");
12092c393a42Smrg	FcValueListPrint (*head);
12102c393a42Smrg	printf ("\n");
12112c393a42Smrg    }
12122c393a42Smrg
12132c393a42Smrg    if (new)
12142c393a42Smrg    {
12152c393a42Smrg	last = new;
12162c393a42Smrg	while (last->next != NULL)
12172c393a42Smrg	    last = last->next;
12182c393a42Smrg
12192c393a42Smrg	last->next = *prev;
12202c393a42Smrg	*prev = new;
12212c393a42Smrg    }
12222c393a42Smrg
12232c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
12242c393a42Smrg    {
12252c393a42Smrg	printf ("%s list after ", append ? "Append" : "Prepend");
12262c393a42Smrg	FcValueListPrint (*head);
12272c393a42Smrg	printf ("\n");
12282c393a42Smrg    }
12292c393a42Smrg
12302c393a42Smrg    return FcTrue;
12312c393a42Smrg}
12322c393a42Smrg
12332c393a42Smrgstatic void
12342c393a42SmrgFcConfigDel (FcValueListPtr *head,
12352c393a42Smrg	     FcValueList    *position)
12362c393a42Smrg{
12372c393a42Smrg    FcValueListPtr *prev;
12382c393a42Smrg
12392c393a42Smrg    for (prev = head; *prev != NULL; prev = &(*prev)->next)
12402c393a42Smrg    {
12412c393a42Smrg	if (*prev == position)
12422c393a42Smrg	{
12432c393a42Smrg	    *prev = position->next;
12442c393a42Smrg	    position->next = NULL;
12452c393a42Smrg	    FcValueListDestroy (position);
12462c393a42Smrg	    break;
12472c393a42Smrg	}
12482c393a42Smrg    }
12492c393a42Smrg}
12502c393a42Smrg
12512c393a42Smrgstatic void
12522c393a42SmrgFcConfigPatternAdd (FcPattern	*p,
12532c393a42Smrg		    FcObject	object,
12542c393a42Smrg		    FcValueList	*list,
12552c393a42Smrg		    FcBool	append)
12562c393a42Smrg{
12572c393a42Smrg    if (list)
12582c393a42Smrg    {
12592c393a42Smrg	FcPatternElt    *e = FcPatternObjectInsertElt (p, object);
12602c393a42Smrg
12612c393a42Smrg	if (!e)
12622c393a42Smrg	    return;
12632c393a42Smrg	FcConfigAdd (&e->values, 0, append, list);
12642c393a42Smrg    }
12652c393a42Smrg}
12662c393a42Smrg
12672c393a42Smrg/*
12682c393a42Smrg * Delete all values associated with a field
12692c393a42Smrg */
12702c393a42Smrgstatic void
12712c393a42SmrgFcConfigPatternDel (FcPattern	*p,
12722c393a42Smrg		    FcObject	object)
12732c393a42Smrg{
12742c393a42Smrg    FcPatternElt    *e = FcPatternObjectFindElt (p, object);
12752c393a42Smrg    if (!e)
12762c393a42Smrg	return;
12772c393a42Smrg    while (e->values != NULL)
12782c393a42Smrg	FcConfigDel (&e->values, e->values);
12792c393a42Smrg}
12802c393a42Smrg
12812c393a42Smrgstatic void
12822c393a42SmrgFcConfigPatternCanon (FcPattern	    *p,
12832c393a42Smrg		      FcObject	    object)
12842c393a42Smrg{
12852c393a42Smrg    FcPatternElt    *e = FcPatternObjectFindElt (p, object);
12862c393a42Smrg    if (!e)
12872c393a42Smrg	return;
12882c393a42Smrg    if (e->values == NULL)
12892c393a42Smrg	FcPatternObjectDel (p, object);
12902c393a42Smrg}
12912c393a42Smrg
12922c393a42SmrgFcBool
12932c393a42SmrgFcConfigSubstituteWithPat (FcConfig    *config,
12942c393a42Smrg			   FcPattern   *p,
12952c393a42Smrg			   FcPattern   *p_pat,
12962c393a42Smrg			   FcMatchKind kind)
12972c393a42Smrg{
12982c393a42Smrg    FcSubst	    *s;
12992c393a42Smrg    FcSubState	    *st;
13002c393a42Smrg    int		    i;
13012c393a42Smrg    FcTest	    *t;
13022c393a42Smrg    FcEdit	    *e;
13032c393a42Smrg    FcValueList	    *l;
13042c393a42Smrg    FcPattern	    *m;
13052c393a42Smrg
13062c393a42Smrg    if (!config)
13072c393a42Smrg    {
13082c393a42Smrg	config = FcConfigGetCurrent ();
13092c393a42Smrg	if (!config)
13102c393a42Smrg	    return FcFalse;
13112c393a42Smrg    }
13122c393a42Smrg
13132c393a42Smrg    switch (kind) {
13142c393a42Smrg    case FcMatchPattern:
13152c393a42Smrg	s = config->substPattern;
13162c393a42Smrg	break;
13172c393a42Smrg    case FcMatchFont:
13182c393a42Smrg	s = config->substFont;
13192c393a42Smrg	break;
13202c393a42Smrg    case FcMatchScan:
13212c393a42Smrg	s = config->substScan;
13222c393a42Smrg	break;
13232c393a42Smrg    default:
13242c393a42Smrg	return FcFalse;
13252c393a42Smrg    }
13262c393a42Smrg
13272c393a42Smrg    st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
13282c393a42Smrg    if (!st && config->maxObjects)
13292c393a42Smrg	return FcFalse;
13302c393a42Smrg    FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
13312c393a42Smrg
13322c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
13332c393a42Smrg    {
13342c393a42Smrg	printf ("FcConfigSubstitute ");
13352c393a42Smrg	FcPatternPrint (p);
13362c393a42Smrg    }
13372c393a42Smrg    for (; s; s = s->next)
13382c393a42Smrg    {
13392c393a42Smrg	/*
13402c393a42Smrg	 * Check the tests to see if
13412c393a42Smrg	 * they all match the pattern
13422c393a42Smrg	 */
13432c393a42Smrg	for (t = s->test, i = 0; t; t = t->next, i++)
13442c393a42Smrg	{
13452c393a42Smrg	    if (FcDebug () & FC_DBG_EDIT)
13462c393a42Smrg	    {
13472c393a42Smrg		printf ("FcConfigSubstitute test ");
13482c393a42Smrg		FcTestPrint (t);
13492c393a42Smrg	    }
13502c393a42Smrg	    st[i].elt = 0;
13512c393a42Smrg	    if (kind == FcMatchFont && t->kind == FcMatchPattern)
13522c393a42Smrg		m = p_pat;
13532c393a42Smrg	    else
13542c393a42Smrg		m = p;
13552c393a42Smrg	    if (m)
13562c393a42Smrg		st[i].elt = FcPatternObjectFindElt (m, t->object);
13572c393a42Smrg	    else
13582c393a42Smrg		st[i].elt = 0;
13592c393a42Smrg	    /*
13602c393a42Smrg	     * If there's no such field in the font,
13612c393a42Smrg	     * then FcQualAll matches while FcQualAny does not
13622c393a42Smrg	     */
13632c393a42Smrg	    if (!st[i].elt)
13642c393a42Smrg	    {
13652c393a42Smrg		if (t->qual == FcQualAll)
13662c393a42Smrg		{
13672c393a42Smrg		    st[i].value = 0;
13682c393a42Smrg		    continue;
13692c393a42Smrg		}
13702c393a42Smrg		else
13712c393a42Smrg		    break;
13722c393a42Smrg	    }
13732c393a42Smrg	    /*
13742c393a42Smrg	     * Check to see if there is a match, mark the location
13752c393a42Smrg	     * to apply match-relative edits
13762c393a42Smrg	     */
13772c393a42Smrg	    st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values);
13782c393a42Smrg	    if (!st[i].value)
13792c393a42Smrg		break;
13802c393a42Smrg	    if (t->qual == FcQualFirst && st[i].value != st[i].elt->values)
13812c393a42Smrg		break;
13822c393a42Smrg	    if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values)
13832c393a42Smrg		break;
13842c393a42Smrg	}
13852c393a42Smrg	if (t)
13862c393a42Smrg	{
13872c393a42Smrg	    if (FcDebug () & FC_DBG_EDIT)
13882c393a42Smrg		printf ("No match\n");
13892c393a42Smrg	    continue;
13902c393a42Smrg	}
13912c393a42Smrg	if (FcDebug () & FC_DBG_EDIT)
13922c393a42Smrg	{
13932c393a42Smrg	    printf ("Substitute ");
13942c393a42Smrg	    FcSubstPrint (s);
13952c393a42Smrg	}
13962c393a42Smrg	for (e = s->edit; e; e = e->next)
13972c393a42Smrg	{
13982c393a42Smrg	    /*
13992c393a42Smrg	     * Evaluate the list of expressions
14002c393a42Smrg	     */
14012c393a42Smrg	    l = FcConfigValues (p, e->expr, e->binding);
14022c393a42Smrg	    /*
14032c393a42Smrg	     * Locate any test associated with this field, skipping
14042c393a42Smrg	     * tests associated with the pattern when substituting in
14052c393a42Smrg	     * the font
14062c393a42Smrg	     */
14072c393a42Smrg	    for (t = s->test, i = 0; t; t = t->next, i++)
14082c393a42Smrg	    {
14092c393a42Smrg		if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
14102c393a42Smrg		    t->object == e->object)
14112c393a42Smrg		{
14122c393a42Smrg		    /*
14132c393a42Smrg		     * KLUDGE - the pattern may have been reallocated or
14142c393a42Smrg		     * things may have been inserted or deleted above
14152c393a42Smrg		     * this element by other edits.  Go back and find
14162c393a42Smrg		     * the element again
14172c393a42Smrg		     */
14182c393a42Smrg		    if (e != s->edit && st[i].elt)
14192c393a42Smrg			st[i].elt = FcPatternObjectFindElt (p, t->object);
14202c393a42Smrg		    if (!st[i].elt)
14212c393a42Smrg			t = 0;
14222c393a42Smrg		    break;
14232c393a42Smrg		}
14242c393a42Smrg	    }
14252c393a42Smrg	    switch (e->op) {
14262c393a42Smrg	    case FcOpAssign:
14272c393a42Smrg		/*
14282c393a42Smrg		 * If there was a test, then replace the matched
14292c393a42Smrg		 * value with the new list of values
14302c393a42Smrg		 */
14312c393a42Smrg		if (t)
14322c393a42Smrg		{
14332c393a42Smrg		    FcValueList	*thisValue = st[i].value;
14342c393a42Smrg		    FcValueList	*nextValue = thisValue;
14352c393a42Smrg
14362c393a42Smrg		    /*
14372c393a42Smrg		     * Append the new list of values after the current value
14382c393a42Smrg		     */
14392c393a42Smrg		    FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
14402c393a42Smrg		    /*
14412c393a42Smrg		     * Delete the marked value
14422c393a42Smrg		     */
14432c393a42Smrg                    if (thisValue)
14442c393a42Smrg			FcConfigDel (&st[i].elt->values, thisValue);
14452c393a42Smrg		    /*
14462c393a42Smrg		     * Adjust any pointers into the value list to ensure
14472c393a42Smrg		     * future edits occur at the same place
14482c393a42Smrg		     */
14492c393a42Smrg		    for (t = s->test, i = 0; t; t = t->next, i++)
14502c393a42Smrg		    {
14512c393a42Smrg			if (st[i].value == thisValue)
14522c393a42Smrg			    st[i].value = nextValue;
14532c393a42Smrg		    }
14542c393a42Smrg		    break;
14552c393a42Smrg		}
14562c393a42Smrg		/* fall through ... */
14572c393a42Smrg	    case FcOpAssignReplace:
14582c393a42Smrg		/*
14592c393a42Smrg		 * Delete all of the values and insert
14602c393a42Smrg		 * the new set
14612c393a42Smrg		 */
14622c393a42Smrg		FcConfigPatternDel (p, e->object);
14632c393a42Smrg		FcConfigPatternAdd (p, e->object, l, FcTrue);
14642c393a42Smrg		/*
14652c393a42Smrg		 * Adjust any pointers into the value list as they no
14662c393a42Smrg		 * longer point to anything valid
14672c393a42Smrg		 */
14682c393a42Smrg		if (t)
14692c393a42Smrg		{
14702c393a42Smrg		    FcPatternElt    *thisElt = st[i].elt;
14712c393a42Smrg		    for (t = s->test, i = 0; t; t = t->next, i++)
14722c393a42Smrg		    {
14732c393a42Smrg			if (st[i].elt == thisElt)
14742c393a42Smrg			    st[i].value = 0;
14752c393a42Smrg		    }
14762c393a42Smrg		}
14772c393a42Smrg		break;
14782c393a42Smrg	    case FcOpPrepend:
14792c393a42Smrg		if (t)
14802c393a42Smrg		{
14812c393a42Smrg		    FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
14822c393a42Smrg		    break;
14832c393a42Smrg		}
14842c393a42Smrg		/* fall through ... */
14852c393a42Smrg	    case FcOpPrependFirst:
14862c393a42Smrg		FcConfigPatternAdd (p, e->object, l, FcFalse);
14872c393a42Smrg		break;
14882c393a42Smrg	    case FcOpAppend:
14892c393a42Smrg		if (t)
14902c393a42Smrg		{
14912c393a42Smrg		    FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
14922c393a42Smrg		    break;
14932c393a42Smrg		}
14942c393a42Smrg		/* fall through ... */
14952c393a42Smrg	    case FcOpAppendLast:
14962c393a42Smrg		FcConfigPatternAdd (p, e->object, l, FcTrue);
14972c393a42Smrg		break;
14982c393a42Smrg	    default:
14992c393a42Smrg                FcValueListDestroy (l);
15002c393a42Smrg		break;
15012c393a42Smrg	    }
15022c393a42Smrg	}
15032c393a42Smrg	/*
15042c393a42Smrg	 * Now go through the pattern and eliminate
15052c393a42Smrg	 * any properties without data
15062c393a42Smrg	 */
15072c393a42Smrg	for (e = s->edit; e; e = e->next)
15082c393a42Smrg	    FcConfigPatternCanon (p, e->object);
15092c393a42Smrg
15102c393a42Smrg	if (FcDebug () & FC_DBG_EDIT)
15112c393a42Smrg	{
15122c393a42Smrg	    printf ("FcConfigSubstitute edit");
15132c393a42Smrg	    FcPatternPrint (p);
15142c393a42Smrg	}
15152c393a42Smrg    }
15162c393a42Smrg    FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
15172c393a42Smrg    free (st);
15182c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
15192c393a42Smrg    {
15202c393a42Smrg	printf ("FcConfigSubstitute done");
15212c393a42Smrg	FcPatternPrint (p);
15222c393a42Smrg    }
15232c393a42Smrg    return FcTrue;
15242c393a42Smrg}
15252c393a42Smrg
15262c393a42SmrgFcBool
15272c393a42SmrgFcConfigSubstitute (FcConfig	*config,
15282c393a42Smrg		    FcPattern	*p,
15292c393a42Smrg		    FcMatchKind	kind)
15302c393a42Smrg{
15312c393a42Smrg    return FcConfigSubstituteWithPat (config, p, 0, kind);
15322c393a42Smrg}
15332c393a42Smrg
15342c393a42Smrg#if defined (_WIN32)
15352c393a42Smrg
15362c393a42Smrg#  define WIN32_LEAN_AND_MEAN
15372c393a42Smrg#  define WIN32_EXTRA_LEAN
15382c393a42Smrg#  include <windows.h>
15392c393a42Smrg
15402c393a42Smrgstatic FcChar8 fontconfig_path[1000] = "";
15412c393a42Smrg
15422c393a42Smrg#  if (defined (PIC) || defined (DLL_EXPORT))
15432c393a42Smrg
15442c393a42SmrgBOOL WINAPI
15452c393a42SmrgDllMain (HINSTANCE hinstDLL,
15462c393a42Smrg	 DWORD     fdwReason,
15472c393a42Smrg	 LPVOID    lpvReserved)
15482c393a42Smrg{
15492c393a42Smrg  FcChar8 *p;
15502c393a42Smrg
15512c393a42Smrg  switch (fdwReason) {
15522c393a42Smrg  case DLL_PROCESS_ATTACH:
15532c393a42Smrg      if (!GetModuleFileName ((HMODULE) hinstDLL, fontconfig_path,
15542c393a42Smrg			      sizeof (fontconfig_path)))
15552c393a42Smrg	  break;
15562c393a42Smrg
15572c393a42Smrg      /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
15582c393a42Smrg       * assume it's a Unix-style installation tree, and use
15592c393a42Smrg       * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
15602c393a42Smrg       * folder where the DLL is as FONTCONFIG_PATH.
15612c393a42Smrg       */
15622c393a42Smrg      p = strrchr (fontconfig_path, '\\');
15632c393a42Smrg      if (p)
15642c393a42Smrg      {
15652c393a42Smrg	  *p = '\0';
15662c393a42Smrg	  p = strrchr (fontconfig_path, '\\');
15672c393a42Smrg	  if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 ||
15682c393a42Smrg		    FcStrCmpIgnoreCase (p + 1, "lib") == 0))
15692c393a42Smrg	      *p = '\0';
15702c393a42Smrg	  strcat (fontconfig_path, "\\etc\\fonts");
15712c393a42Smrg      }
15722c393a42Smrg      else
15732c393a42Smrg          fontconfig_path[0] = '\0';
15742c393a42Smrg
15752c393a42Smrg      break;
15762c393a42Smrg  }
15772c393a42Smrg
15782c393a42Smrg  return TRUE;
15792c393a42Smrg}
15802c393a42Smrg
15812c393a42Smrg#  endif /* !PIC */
15822c393a42Smrg
15832c393a42Smrg#undef FONTCONFIG_PATH
15842c393a42Smrg#define FONTCONFIG_PATH fontconfig_path
15852c393a42Smrg
15862c393a42Smrg#endif /* !_WIN32 */
15872c393a42Smrg
15882c393a42Smrg#ifndef FONTCONFIG_FILE
15892c393a42Smrg#define FONTCONFIG_FILE	"fonts.conf"
15902c393a42Smrg#endif
15912c393a42Smrg
15922c393a42Smrgstatic FcChar8 *
15932c393a42SmrgFcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
15942c393a42Smrg{
15952c393a42Smrg    FcChar8    *path;
15962c393a42Smrg
15972c393a42Smrg    if (!dir)
15982c393a42Smrg	dir = (FcChar8 *) "";
15992c393a42Smrg    path = malloc (strlen ((char *) dir) + 1 + strlen ((char *) file) + 1);
16002c393a42Smrg    if (!path)
16012c393a42Smrg	return 0;
16022c393a42Smrg
16032c393a42Smrg    strcpy ((char *) path, (const char *) dir);
16042c393a42Smrg    /* make sure there's a single separator */
16052c393a42Smrg#ifdef _WIN32
16062c393a42Smrg    if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
16072c393a42Smrg		      path[strlen((char *) path)-1] != '\\')) &&
16082c393a42Smrg	!(file[0] == '/' ||
16092c393a42Smrg	  file[0] == '\\' ||
16102c393a42Smrg	  (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
16112c393a42Smrg	strcat ((char *) path, "\\");
16122c393a42Smrg#else
16132c393a42Smrg    if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
16142c393a42Smrg	strcat ((char *) path, "/");
16152c393a42Smrg#endif
16162c393a42Smrg    strcat ((char *) path, (char *) file);
16172c393a42Smrg
16182c393a42Smrg    FcMemAlloc (FC_MEM_STRING, strlen ((char *) path) + 1);
16192c393a42Smrg    if (access ((char *) path, R_OK) == 0)
16202c393a42Smrg	return path;
16212c393a42Smrg
16222c393a42Smrg    FcStrFree (path);
16232c393a42Smrg    return 0;
16242c393a42Smrg}
16252c393a42Smrg
16262c393a42Smrgstatic FcChar8 **
16272c393a42SmrgFcConfigGetPath (void)
16282c393a42Smrg{
16292c393a42Smrg    FcChar8    **path;
16302c393a42Smrg    FcChar8    *env, *e, *colon;
16312c393a42Smrg    FcChar8    *dir;
16322c393a42Smrg    int	    npath;
16332c393a42Smrg    int	    i;
16342c393a42Smrg
16352c393a42Smrg    npath = 2;	/* default dir + null */
16362c393a42Smrg    env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
16372c393a42Smrg    if (env)
16382c393a42Smrg    {
16392c393a42Smrg	e = env;
16402c393a42Smrg	npath++;
16412c393a42Smrg	while (*e)
16422c393a42Smrg	    if (*e++ == FC_SEARCH_PATH_SEPARATOR)
16432c393a42Smrg		npath++;
16442c393a42Smrg    }
16452c393a42Smrg    path = calloc (npath, sizeof (FcChar8 *));
16462c393a42Smrg    if (!path)
16472c393a42Smrg	goto bail0;
16482c393a42Smrg    i = 0;
16492c393a42Smrg
16502c393a42Smrg    if (env)
16512c393a42Smrg    {
16522c393a42Smrg	e = env;
16532c393a42Smrg	while (*e)
16542c393a42Smrg	{
16552c393a42Smrg	    colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
16562c393a42Smrg	    if (!colon)
16572c393a42Smrg		colon = e + strlen ((char *) e);
16582c393a42Smrg	    path[i] = malloc (colon - e + 1);
16592c393a42Smrg	    if (!path[i])
16602c393a42Smrg		goto bail1;
16612c393a42Smrg	    strncpy ((char *) path[i], (const char *) e, colon - e);
16622c393a42Smrg	    path[i][colon - e] = '\0';
16632c393a42Smrg	    if (*colon)
16642c393a42Smrg		e = colon + 1;
16652c393a42Smrg	    else
16662c393a42Smrg		e = colon;
16672c393a42Smrg	    i++;
16682c393a42Smrg	}
16692c393a42Smrg    }
16702c393a42Smrg
16712c393a42Smrg#ifdef _WIN32
16722c393a42Smrg	if (fontconfig_path[0] == '\0')
16732c393a42Smrg	{
16742c393a42Smrg		if(!GetModuleFileName(NULL, fontconfig_path, sizeof(fontconfig_path)))
16752c393a42Smrg			goto bail1;
16762c393a42Smrg		char *p = strrchr (fontconfig_path, '\\');
16772c393a42Smrg		if (p) *p = '\0';
16782c393a42Smrg		strcat (fontconfig_path, "\\fonts");
16792c393a42Smrg	}
16802c393a42Smrg#endif
16812c393a42Smrg    dir = (FcChar8 *) FONTCONFIG_PATH;
16822c393a42Smrg    path[i] = malloc (strlen ((char *) dir) + 1);
16832c393a42Smrg    if (!path[i])
16842c393a42Smrg	goto bail1;
16852c393a42Smrg    strcpy ((char *) path[i], (const char *) dir);
16862c393a42Smrg    return path;
16872c393a42Smrg
16882c393a42Smrgbail1:
16892c393a42Smrg    for (i = 0; path[i]; i++)
16902c393a42Smrg	free (path[i]);
16912c393a42Smrg    free (path);
16922c393a42Smrgbail0:
16932c393a42Smrg    return 0;
16942c393a42Smrg}
16952c393a42Smrg
16962c393a42Smrgstatic void
16972c393a42SmrgFcConfigFreePath (FcChar8 **path)
16982c393a42Smrg{
16992c393a42Smrg    FcChar8    **p;
17002c393a42Smrg
17012c393a42Smrg    for (p = path; *p; p++)
17022c393a42Smrg	free (*p);
17032c393a42Smrg    free (path);
17042c393a42Smrg}
17052c393a42Smrg
17062c393a42Smrgstatic FcBool	_FcConfigHomeEnabled = FcTrue;
17072c393a42Smrg
17082c393a42SmrgFcChar8 *
17092c393a42SmrgFcConfigHome (void)
17102c393a42Smrg{
17112c393a42Smrg    if (_FcConfigHomeEnabled)
17122c393a42Smrg    {
17132c393a42Smrg        char *home = getenv ("HOME");
17142c393a42Smrg
17152c393a42Smrg#ifdef _WIN32
17162c393a42Smrg	if (home == NULL)
17172c393a42Smrg	    home = getenv ("USERPROFILE");
17182c393a42Smrg#endif
17192c393a42Smrg
17202c393a42Smrg	return (FcChar8 *) home;
17212c393a42Smrg    }
17222c393a42Smrg    return 0;
17232c393a42Smrg}
17242c393a42Smrg
17252c393a42SmrgFcBool
17262c393a42SmrgFcConfigEnableHome (FcBool enable)
17272c393a42Smrg{
17282c393a42Smrg    FcBool  prev = _FcConfigHomeEnabled;
17292c393a42Smrg    _FcConfigHomeEnabled = enable;
17302c393a42Smrg    return prev;
17312c393a42Smrg}
17322c393a42Smrg
17332c393a42SmrgFcChar8 *
17342c393a42SmrgFcConfigFilename (const FcChar8 *url)
17352c393a42Smrg{
17362c393a42Smrg    FcChar8    *file, *dir, **path, **p;
17372c393a42Smrg
17382c393a42Smrg    if (!url || !*url)
17392c393a42Smrg    {
17402c393a42Smrg	url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
17412c393a42Smrg	if (!url)
17422c393a42Smrg	    url = (FcChar8 *) FONTCONFIG_FILE;
17432c393a42Smrg    }
17442c393a42Smrg    file = 0;
17452c393a42Smrg
17462c393a42Smrg#ifdef _WIN32
17472c393a42Smrg    if (isalpha (*url) &&
17482c393a42Smrg	url[1] == ':' &&
17492c393a42Smrg	(url[2] == '/' || url[2] == '\\'))
17502c393a42Smrg	goto absolute_path;
17512c393a42Smrg#endif
17522c393a42Smrg
17532c393a42Smrg    switch (*url) {
17542c393a42Smrg    case '~':
17552c393a42Smrg	dir = FcConfigHome ();
17562c393a42Smrg	if (dir)
17572c393a42Smrg	    file = FcConfigFileExists (dir, url + 1);
17582c393a42Smrg	else
17592c393a42Smrg	    file = 0;
17602c393a42Smrg	break;
17612c393a42Smrg#ifdef _WIN32
17622c393a42Smrg    case '\\':
17632c393a42Smrg    absolute_path:
17642c393a42Smrg#endif
17652c393a42Smrg    case '/':
17662c393a42Smrg	file = FcConfigFileExists (0, url);
17672c393a42Smrg	break;
17682c393a42Smrg    default:
17692c393a42Smrg	path = FcConfigGetPath ();
17702c393a42Smrg	if (!path)
17712c393a42Smrg	    return 0;
17722c393a42Smrg	for (p = path; *p; p++)
17732c393a42Smrg	{
17742c393a42Smrg	    file = FcConfigFileExists (*p, url);
17752c393a42Smrg	    if (file)
17762c393a42Smrg		break;
17772c393a42Smrg	}
17782c393a42Smrg	FcConfigFreePath (path);
17792c393a42Smrg	break;
17802c393a42Smrg    }
17812c393a42Smrg    return file;
17822c393a42Smrg}
17832c393a42Smrg
17842c393a42Smrg/*
17852c393a42Smrg * Manage the application-specific fonts
17862c393a42Smrg */
17872c393a42Smrg
17882c393a42SmrgFcBool
17892c393a42SmrgFcConfigAppFontAddFile (FcConfig    *config,
17902c393a42Smrg			const FcChar8  *file)
17912c393a42Smrg{
17922c393a42Smrg    FcFontSet	*set;
17932c393a42Smrg    FcStrSet	*subdirs;
17942c393a42Smrg    FcStrList	*sublist;
17952c393a42Smrg    FcChar8	*subdir;
17962c393a42Smrg
17972c393a42Smrg    if (!config)
17982c393a42Smrg    {
17992c393a42Smrg	config = FcConfigGetCurrent ();
18002c393a42Smrg	if (!config)
18012c393a42Smrg	    return FcFalse;
18022c393a42Smrg    }
18032c393a42Smrg
18042c393a42Smrg    subdirs = FcStrSetCreate ();
18052c393a42Smrg    if (!subdirs)
18062c393a42Smrg	return FcFalse;
18072c393a42Smrg
18082c393a42Smrg    set = FcConfigGetFonts (config, FcSetApplication);
18092c393a42Smrg    if (!set)
18102c393a42Smrg    {
18112c393a42Smrg	set = FcFontSetCreate ();
18122c393a42Smrg	if (!set)
18132c393a42Smrg	{
18142c393a42Smrg	    FcStrSetDestroy (subdirs);
18152c393a42Smrg	    return FcFalse;
18162c393a42Smrg	}
18172c393a42Smrg	FcConfigSetFonts (config, set, FcSetApplication);
18182c393a42Smrg    }
18192c393a42Smrg
18202c393a42Smrg    if (!FcFileScanConfig (set, subdirs, config->blanks, file, config))
18212c393a42Smrg    {
18222c393a42Smrg	FcStrSetDestroy (subdirs);
18232c393a42Smrg	return FcFalse;
18242c393a42Smrg    }
18252c393a42Smrg    if ((sublist = FcStrListCreate (subdirs)))
18262c393a42Smrg    {
18272c393a42Smrg	while ((subdir = FcStrListNext (sublist)))
18282c393a42Smrg	{
18292c393a42Smrg	    FcConfigAppFontAddDir (config, subdir);
18302c393a42Smrg	}
18312c393a42Smrg	FcStrListDone (sublist);
18322c393a42Smrg    }
18332c393a42Smrg    FcStrSetDestroy (subdirs);
18342c393a42Smrg    return FcTrue;
18352c393a42Smrg}
18362c393a42Smrg
18372c393a42SmrgFcBool
18382c393a42SmrgFcConfigAppFontAddDir (FcConfig	    *config,
18392c393a42Smrg		       const FcChar8   *dir)
18402c393a42Smrg{
18412c393a42Smrg    FcFontSet	*set;
18422c393a42Smrg    FcStrSet	*dirs;
18432c393a42Smrg
18442c393a42Smrg    if (!config)
18452c393a42Smrg    {
18462c393a42Smrg	config = FcConfigGetCurrent ();
18472c393a42Smrg	if (!config)
18482c393a42Smrg	    return FcFalse;
18492c393a42Smrg    }
18502c393a42Smrg
18512c393a42Smrg    dirs = FcStrSetCreate ();
18522c393a42Smrg    if (!dirs)
18532c393a42Smrg	return FcFalse;
18542c393a42Smrg
18552c393a42Smrg    set = FcConfigGetFonts (config, FcSetApplication);
18562c393a42Smrg    if (!set)
18572c393a42Smrg    {
18582c393a42Smrg	set = FcFontSetCreate ();
18592c393a42Smrg	if (!set)
18602c393a42Smrg	{
18612c393a42Smrg	    FcStrSetDestroy (dirs);
18622c393a42Smrg	    return FcFalse;
18632c393a42Smrg	}
18642c393a42Smrg	FcConfigSetFonts (config, set, FcSetApplication);
18652c393a42Smrg    }
18662c393a42Smrg
18672c393a42Smrg    FcStrSetAddFilename (dirs, dir);
18682c393a42Smrg
18692c393a42Smrg    if (!FcConfigAddDirList (config, FcSetApplication, dirs))
18702c393a42Smrg    {
18712c393a42Smrg	FcStrSetDestroy (dirs);
18722c393a42Smrg	return FcFalse;
18732c393a42Smrg    }
18742c393a42Smrg    FcStrSetDestroy (dirs);
18752c393a42Smrg    return FcTrue;
18762c393a42Smrg}
18772c393a42Smrg
18782c393a42Smrgvoid
18792c393a42SmrgFcConfigAppFontClear (FcConfig	    *config)
18802c393a42Smrg{
18812c393a42Smrg    if (!config)
18822c393a42Smrg    {
18832c393a42Smrg	config = FcConfigGetCurrent ();
18842c393a42Smrg	if (!config)
18852c393a42Smrg	    return;
18862c393a42Smrg    }
18872c393a42Smrg
18882c393a42Smrg    FcConfigSetFonts (config, 0, FcSetApplication);
18892c393a42Smrg}
18902c393a42Smrg
18912c393a42Smrg/*
18922c393a42Smrg * Manage filename-based font source selectors
18932c393a42Smrg */
18942c393a42Smrg
18952c393a42SmrgFcBool
18962c393a42SmrgFcConfigGlobAdd (FcConfig	*config,
18972c393a42Smrg		 const FcChar8  *glob,
18982c393a42Smrg		 FcBool		accept)
18992c393a42Smrg{
19002c393a42Smrg    FcStrSet	*set = accept ? config->acceptGlobs : config->rejectGlobs;
19012c393a42Smrg
19022c393a42Smrg    return FcStrSetAdd (set, glob);
19032c393a42Smrg}
19042c393a42Smrg
19052c393a42Smrgstatic FcBool
19062c393a42SmrgFcConfigGlobMatch (const FcChar8    *glob,
19072c393a42Smrg		   const FcChar8    *string)
19082c393a42Smrg{
19092c393a42Smrg    FcChar8	c;
19102c393a42Smrg
19112c393a42Smrg    while ((c = *glob++))
19122c393a42Smrg    {
19132c393a42Smrg	switch (c) {
19142c393a42Smrg	case '*':
19152c393a42Smrg	    /* short circuit common case */
19162c393a42Smrg	    if (!*glob)
19172c393a42Smrg		return FcTrue;
19182c393a42Smrg	    /* short circuit another common case */
19192c393a42Smrg	    if (strchr ((char *) glob, '*') == 0)
19202c393a42Smrg		string += strlen ((char *) string) - strlen ((char *) glob);
19212c393a42Smrg	    while (*string)
19222c393a42Smrg	    {
19232c393a42Smrg		if (FcConfigGlobMatch (glob, string))
19242c393a42Smrg		    return FcTrue;
19252c393a42Smrg		string++;
19262c393a42Smrg	    }
19272c393a42Smrg	    return FcFalse;
19282c393a42Smrg	case '?':
19292c393a42Smrg	    if (*string++ == '\0')
19302c393a42Smrg		return FcFalse;
19312c393a42Smrg	    break;
19322c393a42Smrg	default:
19332c393a42Smrg	    if (*string++ != c)
19342c393a42Smrg		return FcFalse;
19352c393a42Smrg	    break;
19362c393a42Smrg	}
19372c393a42Smrg    }
19382c393a42Smrg    return *string == '\0';
19392c393a42Smrg}
19402c393a42Smrg
19412c393a42Smrgstatic FcBool
19422c393a42SmrgFcConfigGlobsMatch (const FcStrSet	*globs,
19432c393a42Smrg		    const FcChar8	*string)
19442c393a42Smrg{
19452c393a42Smrg    int	i;
19462c393a42Smrg
19472c393a42Smrg    for (i = 0; i < globs->num; i++)
19482c393a42Smrg	if (FcConfigGlobMatch (globs->strs[i], string))
19492c393a42Smrg	    return FcTrue;
19502c393a42Smrg    return FcFalse;
19512c393a42Smrg}
19522c393a42Smrg
19532c393a42SmrgFcBool
19542c393a42SmrgFcConfigAcceptFilename (FcConfig	*config,
19552c393a42Smrg			const FcChar8	*filename)
19562c393a42Smrg{
19572c393a42Smrg    if (FcConfigGlobsMatch (config->acceptGlobs, filename))
19582c393a42Smrg	return FcTrue;
19592c393a42Smrg    if (FcConfigGlobsMatch (config->rejectGlobs, filename))
19602c393a42Smrg	return FcFalse;
19612c393a42Smrg    return FcTrue;
19622c393a42Smrg}
19632c393a42Smrg
19642c393a42Smrg/*
19652c393a42Smrg * Manage font-pattern based font source selectors
19662c393a42Smrg */
19672c393a42Smrg
19682c393a42SmrgFcBool
19692c393a42SmrgFcConfigPatternsAdd (FcConfig	*config,
19702c393a42Smrg		     FcPattern	*pattern,
19712c393a42Smrg		     FcBool	accept)
19722c393a42Smrg{
19732c393a42Smrg    FcFontSet	*set = accept ? config->acceptPatterns : config->rejectPatterns;
19742c393a42Smrg
19752c393a42Smrg    return FcFontSetAdd (set, pattern);
19762c393a42Smrg}
19772c393a42Smrg
19782c393a42Smrgstatic FcBool
19792c393a42SmrgFcConfigPatternsMatch (const FcFontSet	*patterns,
19802c393a42Smrg		       const FcPattern	*font)
19812c393a42Smrg{
19822c393a42Smrg    int i;
19832c393a42Smrg
19842c393a42Smrg    for (i = 0; i < patterns->nfont; i++)
19852c393a42Smrg	if (FcListPatternMatchAny (patterns->fonts[i], font))
19862c393a42Smrg	    return FcTrue;
19872c393a42Smrg    return FcFalse;
19882c393a42Smrg}
19892c393a42Smrg
19902c393a42SmrgFcBool
19912c393a42SmrgFcConfigAcceptFont (FcConfig	    *config,
19922c393a42Smrg		    const FcPattern *font)
19932c393a42Smrg{
19942c393a42Smrg    if (FcConfigPatternsMatch (config->acceptPatterns, font))
19952c393a42Smrg	return FcTrue;
19962c393a42Smrg    if (FcConfigPatternsMatch (config->rejectPatterns, font))
19972c393a42Smrg	return FcFalse;
19982c393a42Smrg    return FcTrue;
19992c393a42Smrg}
20002c393a42Smrg#define __fccfg__
20012c393a42Smrg#include "fcaliastail.h"
20022c393a42Smrg#undef __fccfg__
2003