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