fccfg.c revision ca08ab68
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
10ca08ab68Smrg * documentation, and that the name of the author(s) not be used in
112c393a42Smrg * advertising or publicity pertaining to distribution of the software without
12ca08ab68Smrg * specific, written prior permission.  The authors make 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));
51ca08ab68Smrg
522c393a42Smrg    config->configDirs = FcStrSetCreate ();
532c393a42Smrg    if (!config->configDirs)
542c393a42Smrg	goto bail1;
55ca08ab68Smrg
562c393a42Smrg    config->configFiles = FcStrSetCreate ();
572c393a42Smrg    if (!config->configFiles)
582c393a42Smrg	goto bail2;
59ca08ab68Smrg
602c393a42Smrg    config->fontDirs = FcStrSetCreate ();
612c393a42Smrg    if (!config->fontDirs)
622c393a42Smrg	goto bail3;
63ca08ab68Smrg
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;
75ca08ab68Smrg
762c393a42Smrg    config->rejectPatterns = FcFontSetCreate ();
772c393a42Smrg    if (!config->rejectPatterns)
782c393a42Smrg	goto bail7;
792c393a42Smrg
802c393a42Smrg    config->cacheDirs = FcStrSetCreate ();
812c393a42Smrg    if (!config->cacheDirs)
822c393a42Smrg	goto bail8;
83ca08ab68Smrg
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);
94ca08ab68Smrg    config->rescanInterval = 30;
95a6844aabSmrg
96a6844aabSmrg    config->expr_pool = NULL;
97a6844aabSmrg
98a6844aabSmrg    config->ref = 1;
99ca08ab68Smrg
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)))
134ca08ab68Smrg	    if (FcStat (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;
184ca08ab68Smrg
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
282ca08ab68SmrgFcConfigAddCache (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;
346ca08ab68Smrg
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;
385ca08ab68Smrg
3862c393a42Smrg    FcConfigSetFonts (config, fonts, FcSetSystem);
387ca08ab68Smrg
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{
450ca08ab68Smrg    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 *
474ca08ab68SmrgFcConfigGetCacheDirs (const FcConfig *config)
4752c393a42Smrg{
4762c393a42Smrg    if (!config)
4772c393a42Smrg    {
4782c393a42Smrg	config = FcConfigGetCurrent ();
4792c393a42Smrg	if (!config)
4802c393a42Smrg	    return 0;
4812c393a42Smrg    }
4822c393a42Smrg    return FcStrListCreate (config->cacheDirs);
4832c393a42Smrg}
484ca08ab68Smrg
4852c393a42SmrgFcBool
4862c393a42SmrgFcConfigAddConfigFile (FcConfig	    *config,
4872c393a42Smrg		       const FcChar8   *f)
4882c393a42Smrg{
4892c393a42Smrg    FcBool	ret;
4902c393a42Smrg    FcChar8	*file = FcConfigFilename (f);
491ca08ab68Smrg
4922c393a42Smrg    if (!file)
4932c393a42Smrg	return FcFalse;
494ca08ab68Smrg
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;
558ca08ab68Smrg
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
616ca08ab68Smrg
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,
694ca08ab68Smrg		      FcOp		op_,
6952c393a42Smrg		      const FcValue	*right_o)
6962c393a42Smrg{
6972c393a42Smrg    FcValue	left = FcValueCanonicalize(left_o);
6982c393a42Smrg    FcValue	right = FcValueCanonicalize(right_o);
6992c393a42Smrg    FcBool	ret = FcFalse;
700ca08ab68Smrg    FcOp	op = FC_OP_GET_OP (op_);
701ca08ab68Smrg    int		flags = FC_OP_GET_FLAGS (op_);
702ca08ab68Smrg
7032c393a42Smrg    left = FcConfigPromote (left, right);
7042c393a42Smrg    right = FcConfigPromote (right, left);
705ca08ab68Smrg    if (left.type == right.type)
7062c393a42Smrg    {
7072c393a42Smrg	switch (left.type) {
7082c393a42Smrg	case FcTypeInteger:
7092c393a42Smrg	    break;	/* FcConfigPromote prevents this from happening */
7102c393a42Smrg	case FcTypeDouble:
7112c393a42Smrg	    switch (op) {
7122c393a42Smrg	    case FcOpEqual:
7132c393a42Smrg	    case FcOpContains:
7142c393a42Smrg	    case FcOpListing:
7152c393a42Smrg		ret = left.u.d == right.u.d;
7162c393a42Smrg		break;
7172c393a42Smrg	    case FcOpNotEqual:
7182c393a42Smrg	    case FcOpNotContains:
7192c393a42Smrg		ret = left.u.d != right.u.d;
7202c393a42Smrg		break;
721ca08ab68Smrg	    case FcOpLess:
7222c393a42Smrg		ret = left.u.d < right.u.d;
7232c393a42Smrg		break;
724ca08ab68Smrg	    case FcOpLessEqual:
7252c393a42Smrg		ret = left.u.d <= right.u.d;
7262c393a42Smrg		break;
727ca08ab68Smrg	    case FcOpMore:
7282c393a42Smrg		ret = left.u.d > right.u.d;
7292c393a42Smrg		break;
730ca08ab68Smrg	    case FcOpMoreEqual:
7312c393a42Smrg		ret = left.u.d >= right.u.d;
7322c393a42Smrg		break;
7332c393a42Smrg	    default:
7342c393a42Smrg		break;
7352c393a42Smrg	    }
7362c393a42Smrg	    break;
7372c393a42Smrg	case FcTypeBool:
7382c393a42Smrg	    switch (op) {
739ca08ab68Smrg	    case FcOpEqual:
7402c393a42Smrg	    case FcOpContains:
7412c393a42Smrg	    case FcOpListing:
7422c393a42Smrg		ret = left.u.b == right.u.b;
7432c393a42Smrg		break;
7442c393a42Smrg	    case FcOpNotEqual:
7452c393a42Smrg	    case FcOpNotContains:
7462c393a42Smrg		ret = left.u.b != right.u.b;
7472c393a42Smrg		break;
7482c393a42Smrg	    default:
7492c393a42Smrg		break;
7502c393a42Smrg	    }
7512c393a42Smrg	    break;
7522c393a42Smrg	case FcTypeString:
7532c393a42Smrg	    switch (op) {
754ca08ab68Smrg	    case FcOpEqual:
7552c393a42Smrg	    case FcOpListing:
756ca08ab68Smrg		if (flags & FcOpFlagIgnoreBlanks)
757ca08ab68Smrg		    ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0;
758ca08ab68Smrg		else
759ca08ab68Smrg		    ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
7602c393a42Smrg		break;
7612c393a42Smrg	    case FcOpContains:
7622c393a42Smrg		ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
7632c393a42Smrg		break;
7642c393a42Smrg	    case FcOpNotEqual:
765ca08ab68Smrg		if (flags & FcOpFlagIgnoreBlanks)
766ca08ab68Smrg		    ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0;
767ca08ab68Smrg		else
768ca08ab68Smrg		    ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
7692c393a42Smrg		break;
7702c393a42Smrg	    case FcOpNotContains:
7712c393a42Smrg		ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
7722c393a42Smrg		break;
7732c393a42Smrg	    default:
7742c393a42Smrg		break;
7752c393a42Smrg	    }
7762c393a42Smrg	    break;
7772c393a42Smrg	case FcTypeMatrix:
7782c393a42Smrg	    switch (op) {
7792c393a42Smrg	    case FcOpEqual:
7802c393a42Smrg	    case FcOpContains:
7812c393a42Smrg	    case FcOpListing:
7822c393a42Smrg		ret = FcMatrixEqual (left.u.m, right.u.m);
7832c393a42Smrg		break;
7842c393a42Smrg	    case FcOpNotEqual:
7852c393a42Smrg	    case FcOpNotContains:
7862c393a42Smrg		ret = !FcMatrixEqual (left.u.m, right.u.m);
7872c393a42Smrg		break;
7882c393a42Smrg	    default:
7892c393a42Smrg		break;
7902c393a42Smrg	    }
7912c393a42Smrg	    break;
7922c393a42Smrg	case FcTypeCharSet:
7932c393a42Smrg	    switch (op) {
7942c393a42Smrg	    case FcOpContains:
7952c393a42Smrg	    case FcOpListing:
7962c393a42Smrg		/* left contains right if right is a subset of left */
7972c393a42Smrg		ret = FcCharSetIsSubset (right.u.c, left.u.c);
7982c393a42Smrg		break;
7992c393a42Smrg	    case FcOpNotContains:
8002c393a42Smrg		/* left contains right if right is a subset of left */
8012c393a42Smrg		ret = !FcCharSetIsSubset (right.u.c, left.u.c);
8022c393a42Smrg		break;
8032c393a42Smrg	    case FcOpEqual:
8042c393a42Smrg		ret = FcCharSetEqual (left.u.c, right.u.c);
8052c393a42Smrg		break;
8062c393a42Smrg	    case FcOpNotEqual:
8072c393a42Smrg		ret = !FcCharSetEqual (left.u.c, right.u.c);
8082c393a42Smrg		break;
8092c393a42Smrg	    default:
8102c393a42Smrg		break;
8112c393a42Smrg	    }
8122c393a42Smrg	    break;
8132c393a42Smrg	case FcTypeLangSet:
8142c393a42Smrg	    switch (op) {
8152c393a42Smrg	    case FcOpContains:
8162c393a42Smrg	    case FcOpListing:
8172c393a42Smrg		ret = FcLangSetContains (left.u.l, right.u.l);
8182c393a42Smrg		break;
8192c393a42Smrg	    case FcOpNotContains:
8202c393a42Smrg		ret = !FcLangSetContains (left.u.l, right.u.l);
8212c393a42Smrg		break;
8222c393a42Smrg	    case FcOpEqual:
8232c393a42Smrg		ret = FcLangSetEqual (left.u.l, right.u.l);
8242c393a42Smrg		break;
8252c393a42Smrg	    case FcOpNotEqual:
8262c393a42Smrg		ret = !FcLangSetEqual (left.u.l, right.u.l);
8272c393a42Smrg		break;
8282c393a42Smrg	    default:
8292c393a42Smrg		break;
8302c393a42Smrg	    }
8312c393a42Smrg	    break;
8322c393a42Smrg	case FcTypeVoid:
8332c393a42Smrg	    switch (op) {
8342c393a42Smrg	    case FcOpEqual:
8352c393a42Smrg	    case FcOpContains:
8362c393a42Smrg	    case FcOpListing:
8372c393a42Smrg		ret = FcTrue;
8382c393a42Smrg		break;
8392c393a42Smrg	    default:
8402c393a42Smrg		break;
8412c393a42Smrg	    }
8422c393a42Smrg	    break;
8432c393a42Smrg	case FcTypeFTFace:
8442c393a42Smrg	    switch (op) {
8452c393a42Smrg	    case FcOpEqual:
8462c393a42Smrg	    case FcOpContains:
8472c393a42Smrg	    case FcOpListing:
8482c393a42Smrg		ret = left.u.f == right.u.f;
8492c393a42Smrg		break;
8502c393a42Smrg	    case FcOpNotEqual:
8512c393a42Smrg	    case FcOpNotContains:
8522c393a42Smrg		ret = left.u.f != right.u.f;
8532c393a42Smrg		break;
8542c393a42Smrg	    default:
8552c393a42Smrg		break;
8562c393a42Smrg	    }
8572c393a42Smrg	    break;
8582c393a42Smrg	}
8592c393a42Smrg    }
8602c393a42Smrg    else
8612c393a42Smrg    {
8622c393a42Smrg	if (op == FcOpNotEqual || op == FcOpNotContains)
8632c393a42Smrg	    ret = FcTrue;
8642c393a42Smrg    }
8652c393a42Smrg    return ret;
8662c393a42Smrg}
8672c393a42Smrg
8682c393a42Smrg
8692c393a42Smrg#define _FcDoubleFloor(d)	((int) (d))
8702c393a42Smrg#define _FcDoubleCeil(d)	((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
8712c393a42Smrg#define FcDoubleFloor(d)	((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
8722c393a42Smrg#define FcDoubleCeil(d)		((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
8732c393a42Smrg#define FcDoubleRound(d)	FcDoubleFloor ((d) + 0.5)
8742c393a42Smrg#define FcDoubleTrunc(d)	((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
8752c393a42Smrg
8762c393a42Smrgstatic FcValue
8772c393a42SmrgFcConfigEvaluate (FcPattern *p, FcExpr *e)
8782c393a42Smrg{
8792c393a42Smrg    FcValue	v, vl, vr;
8802c393a42Smrg    FcResult	r;
8812c393a42Smrg    FcMatrix	*m;
8822c393a42Smrg    FcChar8     *str;
883ca08ab68Smrg    FcOp	op = FC_OP_GET_OP (e->op);
884ca08ab68Smrg
885ca08ab68Smrg    switch (op) {
8862c393a42Smrg    case FcOpInteger:
8872c393a42Smrg	v.type = FcTypeInteger;
8882c393a42Smrg	v.u.i = e->u.ival;
8892c393a42Smrg	break;
8902c393a42Smrg    case FcOpDouble:
8912c393a42Smrg	v.type = FcTypeDouble;
8922c393a42Smrg	v.u.d = e->u.dval;
8932c393a42Smrg	break;
8942c393a42Smrg    case FcOpString:
8952c393a42Smrg	v.type = FcTypeString;
896a6844aabSmrg	v.u.s = e->u.sval;
897a6844aabSmrg	v = FcValueSave (v);
8982c393a42Smrg	break;
8992c393a42Smrg    case FcOpMatrix:
9002c393a42Smrg	v.type = FcTypeMatrix;
9012c393a42Smrg	v.u.m = e->u.mval;
9022c393a42Smrg	v = FcValueSave (v);
9032c393a42Smrg	break;
9042c393a42Smrg    case FcOpCharSet:
9052c393a42Smrg	v.type = FcTypeCharSet;
9062c393a42Smrg	v.u.c = e->u.cval;
9072c393a42Smrg	v = FcValueSave (v);
9082c393a42Smrg	break;
909ca08ab68Smrg    case FcOpLangSet:
910ca08ab68Smrg	v.type = FcTypeLangSet;
911ca08ab68Smrg	v.u.l = e->u.lval;
912ca08ab68Smrg	v = FcValueSave (v);
913ca08ab68Smrg	break;
9142c393a42Smrg    case FcOpBool:
9152c393a42Smrg	v.type = FcTypeBool;
9162c393a42Smrg	v.u.b = e->u.bval;
9172c393a42Smrg	break;
9182c393a42Smrg    case FcOpField:
9192c393a42Smrg	r = FcPatternObjectGet (p, e->u.object, 0, &v);
9202c393a42Smrg	if (r != FcResultMatch)
9212c393a42Smrg	    v.type = FcTypeVoid;
9222c393a42Smrg	v = FcValueSave (v);
9232c393a42Smrg	break;
9242c393a42Smrg    case FcOpConst:
9252c393a42Smrg	if (FcNameConstant (e->u.constant, &v.u.i))
9262c393a42Smrg	    v.type = FcTypeInteger;
9272c393a42Smrg	else
9282c393a42Smrg	    v.type = FcTypeVoid;
9292c393a42Smrg	break;
9302c393a42Smrg    case FcOpQuest:
9312c393a42Smrg	vl = FcConfigEvaluate (p, e->u.tree.left);
9322c393a42Smrg	if (vl.type == FcTypeBool)
9332c393a42Smrg	{
9342c393a42Smrg	    if (vl.u.b)
9352c393a42Smrg		v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
9362c393a42Smrg	    else
9372c393a42Smrg		v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
9382c393a42Smrg	}
9392c393a42Smrg	else
9402c393a42Smrg	    v.type = FcTypeVoid;
9412c393a42Smrg	FcValueDestroy (vl);
9422c393a42Smrg	break;
9432c393a42Smrg    case FcOpEqual:
9442c393a42Smrg    case FcOpNotEqual:
9452c393a42Smrg    case FcOpLess:
9462c393a42Smrg    case FcOpLessEqual:
9472c393a42Smrg    case FcOpMore:
9482c393a42Smrg    case FcOpMoreEqual:
9492c393a42Smrg    case FcOpContains:
9502c393a42Smrg    case FcOpNotContains:
9512c393a42Smrg    case FcOpListing:
9522c393a42Smrg	vl = FcConfigEvaluate (p, e->u.tree.left);
9532c393a42Smrg	vr = FcConfigEvaluate (p, e->u.tree.right);
9542c393a42Smrg	v.type = FcTypeBool;
9552c393a42Smrg	v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
9562c393a42Smrg	FcValueDestroy (vl);
9572c393a42Smrg	FcValueDestroy (vr);
9582c393a42Smrg	break;
9592c393a42Smrg    case FcOpOr:
9602c393a42Smrg    case FcOpAnd:
9612c393a42Smrg    case FcOpPlus:
9622c393a42Smrg    case FcOpMinus:
9632c393a42Smrg    case FcOpTimes:
9642c393a42Smrg    case FcOpDivide:
9652c393a42Smrg	vl = FcConfigEvaluate (p, e->u.tree.left);
9662c393a42Smrg	vr = FcConfigEvaluate (p, e->u.tree.right);
9672c393a42Smrg	vl = FcConfigPromote (vl, vr);
9682c393a42Smrg	vr = FcConfigPromote (vr, vl);
9692c393a42Smrg	if (vl.type == vr.type)
9702c393a42Smrg	{
9712c393a42Smrg	    switch (vl.type) {
9722c393a42Smrg	    case FcTypeDouble:
973ca08ab68Smrg		switch (op) {
974ca08ab68Smrg		case FcOpPlus:
9752c393a42Smrg		    v.type = FcTypeDouble;
976ca08ab68Smrg		    v.u.d = vl.u.d + vr.u.d;
9772c393a42Smrg		    break;
9782c393a42Smrg		case FcOpMinus:
9792c393a42Smrg		    v.type = FcTypeDouble;
980ca08ab68Smrg		    v.u.d = vl.u.d - vr.u.d;
9812c393a42Smrg		    break;
9822c393a42Smrg		case FcOpTimes:
9832c393a42Smrg		    v.type = FcTypeDouble;
984ca08ab68Smrg		    v.u.d = vl.u.d * vr.u.d;
9852c393a42Smrg		    break;
9862c393a42Smrg		case FcOpDivide:
9872c393a42Smrg		    v.type = FcTypeDouble;
988ca08ab68Smrg		    v.u.d = vl.u.d / vr.u.d;
9892c393a42Smrg		    break;
9902c393a42Smrg		default:
991ca08ab68Smrg		    v.type = FcTypeVoid;
9922c393a42Smrg		    break;
9932c393a42Smrg		}
9942c393a42Smrg		if (v.type == FcTypeDouble &&
9952c393a42Smrg		    v.u.d == (double) (int) v.u.d)
9962c393a42Smrg		{
9972c393a42Smrg		    v.type = FcTypeInteger;
9982c393a42Smrg		    v.u.i = (int) v.u.d;
9992c393a42Smrg		}
10002c393a42Smrg		break;
10012c393a42Smrg	    case FcTypeBool:
1002ca08ab68Smrg		switch (op) {
10032c393a42Smrg		case FcOpOr:
10042c393a42Smrg		    v.type = FcTypeBool;
10052c393a42Smrg		    v.u.b = vl.u.b || vr.u.b;
10062c393a42Smrg		    break;
10072c393a42Smrg		case FcOpAnd:
10082c393a42Smrg		    v.type = FcTypeBool;
10092c393a42Smrg		    v.u.b = vl.u.b && vr.u.b;
10102c393a42Smrg		    break;
10112c393a42Smrg		default:
1012ca08ab68Smrg		    v.type = FcTypeVoid;
10132c393a42Smrg		    break;
10142c393a42Smrg		}
10152c393a42Smrg		break;
10162c393a42Smrg	    case FcTypeString:
1017ca08ab68Smrg		switch (op) {
10182c393a42Smrg		case FcOpPlus:
10192c393a42Smrg		    v.type = FcTypeString;
10202c393a42Smrg		    str = FcStrPlus (vl.u.s, vr.u.s);
1021ca08ab68Smrg		    v.u.s = FcSharedStr (str);
10222c393a42Smrg		    FcStrFree (str);
1023ca08ab68Smrg
10242c393a42Smrg		    if (!v.u.s)
10252c393a42Smrg			v.type = FcTypeVoid;
10262c393a42Smrg		    break;
10272c393a42Smrg		default:
10282c393a42Smrg		    v.type = FcTypeVoid;
10292c393a42Smrg		    break;
10302c393a42Smrg		}
10312c393a42Smrg		break;
10322c393a42Smrg	    case FcTypeMatrix:
1033ca08ab68Smrg		switch (op) {
10342c393a42Smrg		case FcOpTimes:
10352c393a42Smrg		    v.type = FcTypeMatrix;
10362c393a42Smrg		    m = malloc (sizeof (FcMatrix));
10372c393a42Smrg		    if (m)
10382c393a42Smrg		    {
10392c393a42Smrg			FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
10402c393a42Smrg			FcMatrixMultiply (m, vl.u.m, vr.u.m);
10412c393a42Smrg			v.u.m = m;
10422c393a42Smrg		    }
10432c393a42Smrg		    else
10442c393a42Smrg		    {
10452c393a42Smrg			v.type = FcTypeVoid;
10462c393a42Smrg		    }
10472c393a42Smrg		    break;
10482c393a42Smrg		default:
10492c393a42Smrg		    v.type = FcTypeVoid;
10502c393a42Smrg		    break;
10512c393a42Smrg		}
10522c393a42Smrg		break;
1053ca08ab68Smrg	    case FcTypeCharSet:
1054ca08ab68Smrg		switch (op) {
1055ca08ab68Smrg		case FcOpPlus:
1056ca08ab68Smrg		    v.type = FcTypeCharSet;
1057ca08ab68Smrg		    v.u.c = FcCharSetUnion (vl.u.c, vr.u.c);
1058ca08ab68Smrg		    if (!v.u.c)
1059ca08ab68Smrg			v.type = FcTypeVoid;
1060ca08ab68Smrg		    break;
1061ca08ab68Smrg		case FcOpMinus:
1062ca08ab68Smrg		    v.type = FcTypeCharSet;
1063ca08ab68Smrg		    v.u.c = FcCharSetSubtract (vl.u.c, vr.u.c);
1064ca08ab68Smrg		    if (!v.u.c)
1065ca08ab68Smrg			v.type = FcTypeVoid;
1066ca08ab68Smrg		    break;
1067ca08ab68Smrg		default:
1068ca08ab68Smrg		    v.type = FcTypeVoid;
1069ca08ab68Smrg		    break;
1070ca08ab68Smrg		}
1071ca08ab68Smrg		break;
1072ca08ab68Smrg	    case FcTypeLangSet:
1073ca08ab68Smrg		switch (op) {
1074ca08ab68Smrg		case FcOpPlus:
1075ca08ab68Smrg		    v.type = FcTypeLangSet;
1076ca08ab68Smrg		    v.u.l = FcLangSetUnion (vl.u.l, vr.u.l);
1077ca08ab68Smrg		    if (!v.u.l)
1078ca08ab68Smrg			v.type = FcTypeVoid;
1079ca08ab68Smrg		    break;
1080ca08ab68Smrg		case FcOpMinus:
1081ca08ab68Smrg		    v.type = FcTypeLangSet;
1082ca08ab68Smrg		    v.u.l = FcLangSetSubtract (vl.u.l, vr.u.l);
1083ca08ab68Smrg		    if (!v.u.l)
1084ca08ab68Smrg			v.type = FcTypeVoid;
1085ca08ab68Smrg		    break;
1086ca08ab68Smrg		default:
1087ca08ab68Smrg		    v.type = FcTypeVoid;
1088ca08ab68Smrg		    break;
1089ca08ab68Smrg		}
1090ca08ab68Smrg		break;
10912c393a42Smrg	    default:
10922c393a42Smrg		v.type = FcTypeVoid;
10932c393a42Smrg		break;
10942c393a42Smrg	    }
10952c393a42Smrg	}
10962c393a42Smrg	else
10972c393a42Smrg	    v.type = FcTypeVoid;
10982c393a42Smrg	FcValueDestroy (vl);
10992c393a42Smrg	FcValueDestroy (vr);
11002c393a42Smrg	break;
11012c393a42Smrg    case FcOpNot:
11022c393a42Smrg	vl = FcConfigEvaluate (p, e->u.tree.left);
11032c393a42Smrg	switch (vl.type) {
11042c393a42Smrg	case FcTypeBool:
11052c393a42Smrg	    v.type = FcTypeBool;
11062c393a42Smrg	    v.u.b = !vl.u.b;
11072c393a42Smrg	    break;
11082c393a42Smrg	default:
11092c393a42Smrg	    v.type = FcTypeVoid;
11102c393a42Smrg	    break;
11112c393a42Smrg	}
11122c393a42Smrg	FcValueDestroy (vl);
11132c393a42Smrg	break;
11142c393a42Smrg    case FcOpFloor:
11152c393a42Smrg	vl = FcConfigEvaluate (p, e->u.tree.left);
11162c393a42Smrg	switch (vl.type) {
11172c393a42Smrg	case FcTypeInteger:
11182c393a42Smrg	    v = vl;
11192c393a42Smrg	    break;
11202c393a42Smrg	case FcTypeDouble:
11212c393a42Smrg	    v.type = FcTypeInteger;
11222c393a42Smrg	    v.u.i = FcDoubleFloor (vl.u.d);
11232c393a42Smrg	    break;
11242c393a42Smrg	default:
11252c393a42Smrg	    v.type = FcTypeVoid;
11262c393a42Smrg	    break;
11272c393a42Smrg	}
11282c393a42Smrg	FcValueDestroy (vl);
11292c393a42Smrg	break;
11302c393a42Smrg    case FcOpCeil:
11312c393a42Smrg	vl = FcConfigEvaluate (p, e->u.tree.left);
11322c393a42Smrg	switch (vl.type) {
11332c393a42Smrg	case FcTypeInteger:
11342c393a42Smrg	    v = vl;
11352c393a42Smrg	    break;
11362c393a42Smrg	case FcTypeDouble:
11372c393a42Smrg	    v.type = FcTypeInteger;
11382c393a42Smrg	    v.u.i = FcDoubleCeil (vl.u.d);
11392c393a42Smrg	    break;
11402c393a42Smrg	default:
11412c393a42Smrg	    v.type = FcTypeVoid;
11422c393a42Smrg	    break;
11432c393a42Smrg	}
11442c393a42Smrg	FcValueDestroy (vl);
11452c393a42Smrg	break;
11462c393a42Smrg    case FcOpRound:
11472c393a42Smrg	vl = FcConfigEvaluate (p, e->u.tree.left);
11482c393a42Smrg	switch (vl.type) {
11492c393a42Smrg	case FcTypeInteger:
11502c393a42Smrg	    v = vl;
11512c393a42Smrg	    break;
11522c393a42Smrg	case FcTypeDouble:
11532c393a42Smrg	    v.type = FcTypeInteger;
11542c393a42Smrg	    v.u.i = FcDoubleRound (vl.u.d);
11552c393a42Smrg	    break;
11562c393a42Smrg	default:
11572c393a42Smrg	    v.type = FcTypeVoid;
11582c393a42Smrg	    break;
11592c393a42Smrg	}
11602c393a42Smrg	FcValueDestroy (vl);
11612c393a42Smrg	break;
11622c393a42Smrg    case FcOpTrunc:
11632c393a42Smrg	vl = FcConfigEvaluate (p, e->u.tree.left);
11642c393a42Smrg	switch (vl.type) {
11652c393a42Smrg	case FcTypeInteger:
11662c393a42Smrg	    v = vl;
11672c393a42Smrg	    break;
11682c393a42Smrg	case FcTypeDouble:
11692c393a42Smrg	    v.type = FcTypeInteger;
11702c393a42Smrg	    v.u.i = FcDoubleTrunc (vl.u.d);
11712c393a42Smrg	    break;
11722c393a42Smrg	default:
11732c393a42Smrg	    v.type = FcTypeVoid;
11742c393a42Smrg	    break;
11752c393a42Smrg	}
11762c393a42Smrg	FcValueDestroy (vl);
11772c393a42Smrg	break;
11782c393a42Smrg    default:
11792c393a42Smrg	v.type = FcTypeVoid;
11802c393a42Smrg	break;
11812c393a42Smrg    }
11822c393a42Smrg    return v;
11832c393a42Smrg}
11842c393a42Smrg
11852c393a42Smrgstatic FcValueList *
11862c393a42SmrgFcConfigMatchValueList (FcPattern	*p,
11872c393a42Smrg			FcTest		*t,
11882c393a42Smrg			FcValueList	*values)
11892c393a42Smrg{
11902c393a42Smrg    FcValueList	    *ret = 0;
11912c393a42Smrg    FcExpr	    *e = t->expr;
11922c393a42Smrg    FcValue	    value;
11932c393a42Smrg    FcValueList	    *v;
1194ca08ab68Smrg
11952c393a42Smrg    while (e)
11962c393a42Smrg    {
11972c393a42Smrg	/* Compute the value of the match expression */
1198ca08ab68Smrg	if (FC_OP_GET_OP (e->op) == FcOpComma)
11992c393a42Smrg	{
12002c393a42Smrg	    value = FcConfigEvaluate (p, e->u.tree.left);
12012c393a42Smrg	    e = e->u.tree.right;
12022c393a42Smrg	}
12032c393a42Smrg	else
12042c393a42Smrg	{
12052c393a42Smrg	    value = FcConfigEvaluate (p, e);
12062c393a42Smrg	    e = 0;
12072c393a42Smrg	}
12082c393a42Smrg
12092c393a42Smrg	for (v = values; v; v = FcValueListNext(v))
12102c393a42Smrg	{
12112c393a42Smrg	    /* Compare the pattern value to the match expression value */
12122c393a42Smrg	    if (FcConfigCompareValue (&v->value, t->op, &value))
12132c393a42Smrg	    {
12142c393a42Smrg		if (!ret)
12152c393a42Smrg		    ret = v;
12162c393a42Smrg	    }
12172c393a42Smrg	    else
12182c393a42Smrg	    {
12192c393a42Smrg		if (t->qual == FcQualAll)
12202c393a42Smrg		{
12212c393a42Smrg		    ret = 0;
12222c393a42Smrg		    break;
12232c393a42Smrg		}
12242c393a42Smrg	    }
12252c393a42Smrg	}
12262c393a42Smrg	FcValueDestroy (value);
12272c393a42Smrg    }
12282c393a42Smrg    return ret;
12292c393a42Smrg}
12302c393a42Smrg
12312c393a42Smrgstatic FcValueList *
12322c393a42SmrgFcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding)
12332c393a42Smrg{
12342c393a42Smrg    FcValueList	*l;
1235ca08ab68Smrg
12362c393a42Smrg    if (!e)
12372c393a42Smrg	return 0;
12382c393a42Smrg    l = (FcValueList *) malloc (sizeof (FcValueList));
12392c393a42Smrg    if (!l)
12402c393a42Smrg	return 0;
12412c393a42Smrg    FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
1242ca08ab68Smrg    if (FC_OP_GET_OP (e->op) == FcOpComma)
12432c393a42Smrg    {
12442c393a42Smrg	l->value = FcConfigEvaluate (p, e->u.tree.left);
12452c393a42Smrg	l->next = FcConfigValues (p, e->u.tree.right, binding);
12462c393a42Smrg    }
12472c393a42Smrg    else
12482c393a42Smrg    {
12492c393a42Smrg	l->value = FcConfigEvaluate (p, e);
12502c393a42Smrg	l->next = NULL;
12512c393a42Smrg    }
12522c393a42Smrg    l->binding = binding;
12532c393a42Smrg    if (l->value.type == FcTypeVoid)
12542c393a42Smrg    {
12552c393a42Smrg	FcValueList  *next = FcValueListNext(l);
12562c393a42Smrg
12572c393a42Smrg	FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
12582c393a42Smrg	free (l);
12592c393a42Smrg	l = next;
12602c393a42Smrg    }
12612c393a42Smrg
12622c393a42Smrg    return l;
12632c393a42Smrg}
12642c393a42Smrg
12652c393a42Smrgstatic FcBool
12662c393a42SmrgFcConfigAdd (FcValueListPtr *head,
12672c393a42Smrg	     FcValueList    *position,
12682c393a42Smrg	     FcBool	    append,
12692c393a42Smrg	     FcValueList    *new)
12702c393a42Smrg{
12712c393a42Smrg    FcValueListPtr  *prev, last, v;
12722c393a42Smrg    FcValueBinding  sameBinding;
1273ca08ab68Smrg
12742c393a42Smrg    if (position)
12752c393a42Smrg	sameBinding = position->binding;
12762c393a42Smrg    else
12772c393a42Smrg	sameBinding = FcValueBindingWeak;
12782c393a42Smrg    for (v = new; v != NULL; v = FcValueListNext(v))
12792c393a42Smrg	if (v->binding == FcValueBindingSame)
12802c393a42Smrg	    v->binding = sameBinding;
12812c393a42Smrg    if (append)
12822c393a42Smrg    {
12832c393a42Smrg	if (position)
12842c393a42Smrg	    prev = &position->next;
12852c393a42Smrg	else
1286ca08ab68Smrg	    for (prev = head; *prev != NULL;
12872c393a42Smrg		 prev = &(*prev)->next)
12882c393a42Smrg		;
12892c393a42Smrg    }
12902c393a42Smrg    else
12912c393a42Smrg    {
12922c393a42Smrg	if (position)
12932c393a42Smrg	{
1294ca08ab68Smrg	    for (prev = head; *prev != NULL;
12952c393a42Smrg		 prev = &(*prev)->next)
12962c393a42Smrg	    {
12972c393a42Smrg		if (*prev == position)
12982c393a42Smrg		    break;
12992c393a42Smrg	    }
13002c393a42Smrg	}
13012c393a42Smrg	else
13022c393a42Smrg	    prev = head;
13032c393a42Smrg
13042c393a42Smrg	if (FcDebug () & FC_DBG_EDIT)
13052c393a42Smrg	{
13062c393a42Smrg	    if (*prev == NULL)
13072c393a42Smrg		printf ("position not on list\n");
13082c393a42Smrg	}
13092c393a42Smrg    }
13102c393a42Smrg
13112c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
13122c393a42Smrg    {
13132c393a42Smrg	printf ("%s list before ", append ? "Append" : "Prepend");
1314ca08ab68Smrg	FcValueListPrintWithPosition (*head, *prev);
13152c393a42Smrg	printf ("\n");
13162c393a42Smrg    }
1317ca08ab68Smrg
13182c393a42Smrg    if (new)
13192c393a42Smrg    {
13202c393a42Smrg	last = new;
13212c393a42Smrg	while (last->next != NULL)
13222c393a42Smrg	    last = last->next;
1323ca08ab68Smrg
13242c393a42Smrg	last->next = *prev;
13252c393a42Smrg	*prev = new;
13262c393a42Smrg    }
1327ca08ab68Smrg
13282c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
13292c393a42Smrg    {
13302c393a42Smrg	printf ("%s list after ", append ? "Append" : "Prepend");
13312c393a42Smrg	FcValueListPrint (*head);
13322c393a42Smrg	printf ("\n");
13332c393a42Smrg    }
1334ca08ab68Smrg
13352c393a42Smrg    return FcTrue;
13362c393a42Smrg}
13372c393a42Smrg
13382c393a42Smrgstatic void
13392c393a42SmrgFcConfigDel (FcValueListPtr *head,
13402c393a42Smrg	     FcValueList    *position)
13412c393a42Smrg{
13422c393a42Smrg    FcValueListPtr *prev;
13432c393a42Smrg
13442c393a42Smrg    for (prev = head; *prev != NULL; prev = &(*prev)->next)
13452c393a42Smrg    {
13462c393a42Smrg	if (*prev == position)
13472c393a42Smrg	{
13482c393a42Smrg	    *prev = position->next;
13492c393a42Smrg	    position->next = NULL;
13502c393a42Smrg	    FcValueListDestroy (position);
13512c393a42Smrg	    break;
13522c393a42Smrg	}
13532c393a42Smrg    }
13542c393a42Smrg}
13552c393a42Smrg
13562c393a42Smrgstatic void
13572c393a42SmrgFcConfigPatternAdd (FcPattern	*p,
13582c393a42Smrg		    FcObject	object,
13592c393a42Smrg		    FcValueList	*list,
13602c393a42Smrg		    FcBool	append)
13612c393a42Smrg{
13622c393a42Smrg    if (list)
13632c393a42Smrg    {
13642c393a42Smrg	FcPatternElt    *e = FcPatternObjectInsertElt (p, object);
1365ca08ab68Smrg
13662c393a42Smrg	if (!e)
13672c393a42Smrg	    return;
13682c393a42Smrg	FcConfigAdd (&e->values, 0, append, list);
13692c393a42Smrg    }
13702c393a42Smrg}
13712c393a42Smrg
13722c393a42Smrg/*
13732c393a42Smrg * Delete all values associated with a field
13742c393a42Smrg */
13752c393a42Smrgstatic void
13762c393a42SmrgFcConfigPatternDel (FcPattern	*p,
13772c393a42Smrg		    FcObject	object)
13782c393a42Smrg{
13792c393a42Smrg    FcPatternElt    *e = FcPatternObjectFindElt (p, object);
13802c393a42Smrg    if (!e)
13812c393a42Smrg	return;
13822c393a42Smrg    while (e->values != NULL)
13832c393a42Smrg	FcConfigDel (&e->values, e->values);
13842c393a42Smrg}
13852c393a42Smrg
13862c393a42Smrgstatic void
13872c393a42SmrgFcConfigPatternCanon (FcPattern	    *p,
13882c393a42Smrg		      FcObject	    object)
13892c393a42Smrg{
13902c393a42Smrg    FcPatternElt    *e = FcPatternObjectFindElt (p, object);
13912c393a42Smrg    if (!e)
13922c393a42Smrg	return;
13932c393a42Smrg    if (e->values == NULL)
13942c393a42Smrg	FcPatternObjectDel (p, object);
13952c393a42Smrg}
13962c393a42Smrg
13972c393a42SmrgFcBool
13982c393a42SmrgFcConfigSubstituteWithPat (FcConfig    *config,
13992c393a42Smrg			   FcPattern   *p,
14002c393a42Smrg			   FcPattern   *p_pat,
14012c393a42Smrg			   FcMatchKind kind)
14022c393a42Smrg{
14032c393a42Smrg    FcSubst	    *s;
14042c393a42Smrg    FcSubState	    *st;
14052c393a42Smrg    int		    i;
14062c393a42Smrg    FcTest	    *t;
14072c393a42Smrg    FcEdit	    *e;
14082c393a42Smrg    FcValueList	    *l;
14092c393a42Smrg    FcPattern	    *m;
1410ca08ab68Smrg    FcStrSet	    *strs;
14112c393a42Smrg
14122c393a42Smrg    if (!config)
14132c393a42Smrg    {
14142c393a42Smrg	config = FcConfigGetCurrent ();
14152c393a42Smrg	if (!config)
14162c393a42Smrg	    return FcFalse;
14172c393a42Smrg    }
14182c393a42Smrg
14192c393a42Smrg    switch (kind) {
14202c393a42Smrg    case FcMatchPattern:
14212c393a42Smrg	s = config->substPattern;
1422ca08ab68Smrg	strs = FcGetDefaultLangs ();
1423ca08ab68Smrg	if (strs)
1424ca08ab68Smrg	{
1425ca08ab68Smrg	    FcStrList *l = FcStrListCreate (strs);
1426ca08ab68Smrg	    FcChar8 *lang;
1427ca08ab68Smrg	    FcValue v;
1428ca08ab68Smrg
1429ca08ab68Smrg	    FcStrSetDestroy (strs);
1430ca08ab68Smrg	    while (l && (lang = FcStrListNext (l)))
1431ca08ab68Smrg	    {
1432ca08ab68Smrg		v.type = FcTypeString;
1433ca08ab68Smrg		v.u.s = lang;
1434ca08ab68Smrg		FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue);
1435ca08ab68Smrg	    }
1436ca08ab68Smrg	    FcStrListDone (l);
1437ca08ab68Smrg	}
14382c393a42Smrg	break;
14392c393a42Smrg    case FcMatchFont:
14402c393a42Smrg	s = config->substFont;
14412c393a42Smrg	break;
14422c393a42Smrg    case FcMatchScan:
14432c393a42Smrg	s = config->substScan;
14442c393a42Smrg	break;
14452c393a42Smrg    default:
14462c393a42Smrg	return FcFalse;
14472c393a42Smrg    }
14482c393a42Smrg
14492c393a42Smrg    st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
14502c393a42Smrg    if (!st && config->maxObjects)
14512c393a42Smrg	return FcFalse;
14522c393a42Smrg    FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
14532c393a42Smrg
14542c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
14552c393a42Smrg    {
14562c393a42Smrg	printf ("FcConfigSubstitute ");
14572c393a42Smrg	FcPatternPrint (p);
14582c393a42Smrg    }
14592c393a42Smrg    for (; s; s = s->next)
14602c393a42Smrg    {
14612c393a42Smrg	/*
14622c393a42Smrg	 * Check the tests to see if
14632c393a42Smrg	 * they all match the pattern
14642c393a42Smrg	 */
14652c393a42Smrg	for (t = s->test, i = 0; t; t = t->next, i++)
14662c393a42Smrg	{
14672c393a42Smrg	    if (FcDebug () & FC_DBG_EDIT)
14682c393a42Smrg	    {
14692c393a42Smrg		printf ("FcConfigSubstitute test ");
14702c393a42Smrg		FcTestPrint (t);
14712c393a42Smrg	    }
14722c393a42Smrg	    st[i].elt = 0;
14732c393a42Smrg	    if (kind == FcMatchFont && t->kind == FcMatchPattern)
14742c393a42Smrg		m = p_pat;
14752c393a42Smrg	    else
14762c393a42Smrg		m = p;
14772c393a42Smrg	    if (m)
14782c393a42Smrg		st[i].elt = FcPatternObjectFindElt (m, t->object);
14792c393a42Smrg	    else
14802c393a42Smrg		st[i].elt = 0;
14812c393a42Smrg	    /*
14822c393a42Smrg	     * If there's no such field in the font,
14832c393a42Smrg	     * then FcQualAll matches while FcQualAny does not
14842c393a42Smrg	     */
14852c393a42Smrg	    if (!st[i].elt)
14862c393a42Smrg	    {
14872c393a42Smrg		if (t->qual == FcQualAll)
14882c393a42Smrg		{
14892c393a42Smrg		    st[i].value = 0;
14902c393a42Smrg		    continue;
14912c393a42Smrg		}
14922c393a42Smrg		else
14932c393a42Smrg		    break;
14942c393a42Smrg	    }
14952c393a42Smrg	    /*
14962c393a42Smrg	     * Check to see if there is a match, mark the location
14972c393a42Smrg	     * to apply match-relative edits
14982c393a42Smrg	     */
14992c393a42Smrg	    st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values);
15002c393a42Smrg	    if (!st[i].value)
15012c393a42Smrg		break;
15022c393a42Smrg	    if (t->qual == FcQualFirst && st[i].value != st[i].elt->values)
15032c393a42Smrg		break;
15042c393a42Smrg	    if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values)
15052c393a42Smrg		break;
15062c393a42Smrg	}
15072c393a42Smrg	if (t)
15082c393a42Smrg	{
15092c393a42Smrg	    if (FcDebug () & FC_DBG_EDIT)
15102c393a42Smrg		printf ("No match\n");
15112c393a42Smrg	    continue;
15122c393a42Smrg	}
15132c393a42Smrg	if (FcDebug () & FC_DBG_EDIT)
15142c393a42Smrg	{
15152c393a42Smrg	    printf ("Substitute ");
15162c393a42Smrg	    FcSubstPrint (s);
15172c393a42Smrg	}
15182c393a42Smrg	for (e = s->edit; e; e = e->next)
15192c393a42Smrg	{
15202c393a42Smrg	    /*
15212c393a42Smrg	     * Evaluate the list of expressions
15222c393a42Smrg	     */
15232c393a42Smrg	    l = FcConfigValues (p, e->expr, e->binding);
15242c393a42Smrg	    /*
15252c393a42Smrg	     * Locate any test associated with this field, skipping
15262c393a42Smrg	     * tests associated with the pattern when substituting in
15272c393a42Smrg	     * the font
15282c393a42Smrg	     */
15292c393a42Smrg	    for (t = s->test, i = 0; t; t = t->next, i++)
15302c393a42Smrg	    {
15312c393a42Smrg		if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
15322c393a42Smrg		    t->object == e->object)
15332c393a42Smrg		{
1534ca08ab68Smrg		    /*
15352c393a42Smrg		     * KLUDGE - the pattern may have been reallocated or
15362c393a42Smrg		     * things may have been inserted or deleted above
15372c393a42Smrg		     * this element by other edits.  Go back and find
15382c393a42Smrg		     * the element again
15392c393a42Smrg		     */
15402c393a42Smrg		    if (e != s->edit && st[i].elt)
15412c393a42Smrg			st[i].elt = FcPatternObjectFindElt (p, t->object);
15422c393a42Smrg		    if (!st[i].elt)
15432c393a42Smrg			t = 0;
15442c393a42Smrg		    break;
15452c393a42Smrg		}
15462c393a42Smrg	    }
1547ca08ab68Smrg	    switch (FC_OP_GET_OP (e->op)) {
15482c393a42Smrg	    case FcOpAssign:
15492c393a42Smrg		/*
15502c393a42Smrg		 * If there was a test, then replace the matched
15512c393a42Smrg		 * value with the new list of values
15522c393a42Smrg		 */
15532c393a42Smrg		if (t)
15542c393a42Smrg		{
15552c393a42Smrg		    FcValueList	*thisValue = st[i].value;
15562c393a42Smrg		    FcValueList	*nextValue = thisValue;
1557ca08ab68Smrg
15582c393a42Smrg		    /*
15592c393a42Smrg		     * Append the new list of values after the current value
15602c393a42Smrg		     */
15612c393a42Smrg		    FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
15622c393a42Smrg		    /*
15632c393a42Smrg		     * Delete the marked value
15642c393a42Smrg		     */
15652c393a42Smrg                    if (thisValue)
15662c393a42Smrg			FcConfigDel (&st[i].elt->values, thisValue);
15672c393a42Smrg		    /*
15682c393a42Smrg		     * Adjust any pointers into the value list to ensure
15692c393a42Smrg		     * future edits occur at the same place
15702c393a42Smrg		     */
15712c393a42Smrg		    for (t = s->test, i = 0; t; t = t->next, i++)
15722c393a42Smrg		    {
15732c393a42Smrg			if (st[i].value == thisValue)
15742c393a42Smrg			    st[i].value = nextValue;
15752c393a42Smrg		    }
15762c393a42Smrg		    break;
15772c393a42Smrg		}
15782c393a42Smrg		/* fall through ... */
15792c393a42Smrg	    case FcOpAssignReplace:
15802c393a42Smrg		/*
15812c393a42Smrg		 * Delete all of the values and insert
15822c393a42Smrg		 * the new set
15832c393a42Smrg		 */
15842c393a42Smrg		FcConfigPatternDel (p, e->object);
15852c393a42Smrg		FcConfigPatternAdd (p, e->object, l, FcTrue);
15862c393a42Smrg		/*
15872c393a42Smrg		 * Adjust any pointers into the value list as they no
15882c393a42Smrg		 * longer point to anything valid
15892c393a42Smrg		 */
15902c393a42Smrg		if (t)
15912c393a42Smrg		{
15922c393a42Smrg		    FcPatternElt    *thisElt = st[i].elt;
15932c393a42Smrg		    for (t = s->test, i = 0; t; t = t->next, i++)
15942c393a42Smrg		    {
15952c393a42Smrg			if (st[i].elt == thisElt)
15962c393a42Smrg			    st[i].value = 0;
15972c393a42Smrg		    }
15982c393a42Smrg		}
15992c393a42Smrg		break;
16002c393a42Smrg	    case FcOpPrepend:
16012c393a42Smrg		if (t)
16022c393a42Smrg		{
16032c393a42Smrg		    FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
16042c393a42Smrg		    break;
16052c393a42Smrg		}
16062c393a42Smrg		/* fall through ... */
16072c393a42Smrg	    case FcOpPrependFirst:
16082c393a42Smrg		FcConfigPatternAdd (p, e->object, l, FcFalse);
16092c393a42Smrg		break;
16102c393a42Smrg	    case FcOpAppend:
16112c393a42Smrg		if (t)
16122c393a42Smrg		{
16132c393a42Smrg		    FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
16142c393a42Smrg		    break;
16152c393a42Smrg		}
16162c393a42Smrg		/* fall through ... */
16172c393a42Smrg	    case FcOpAppendLast:
16182c393a42Smrg		FcConfigPatternAdd (p, e->object, l, FcTrue);
16192c393a42Smrg		break;
16202c393a42Smrg	    default:
16212c393a42Smrg                FcValueListDestroy (l);
16222c393a42Smrg		break;
16232c393a42Smrg	    }
16242c393a42Smrg	}
16252c393a42Smrg	/*
16262c393a42Smrg	 * Now go through the pattern and eliminate
16272c393a42Smrg	 * any properties without data
16282c393a42Smrg	 */
16292c393a42Smrg	for (e = s->edit; e; e = e->next)
16302c393a42Smrg	    FcConfigPatternCanon (p, e->object);
16312c393a42Smrg
16322c393a42Smrg	if (FcDebug () & FC_DBG_EDIT)
16332c393a42Smrg	{
16342c393a42Smrg	    printf ("FcConfigSubstitute edit");
16352c393a42Smrg	    FcPatternPrint (p);
16362c393a42Smrg	}
16372c393a42Smrg    }
16382c393a42Smrg    FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
16392c393a42Smrg    free (st);
16402c393a42Smrg    if (FcDebug () & FC_DBG_EDIT)
16412c393a42Smrg    {
16422c393a42Smrg	printf ("FcConfigSubstitute done");
16432c393a42Smrg	FcPatternPrint (p);
16442c393a42Smrg    }
16452c393a42Smrg    return FcTrue;
16462c393a42Smrg}
16472c393a42Smrg
16482c393a42SmrgFcBool
16492c393a42SmrgFcConfigSubstitute (FcConfig	*config,
16502c393a42Smrg		    FcPattern	*p,
16512c393a42Smrg		    FcMatchKind	kind)
16522c393a42Smrg{
16532c393a42Smrg    return FcConfigSubstituteWithPat (config, p, 0, kind);
16542c393a42Smrg}
16552c393a42Smrg
16562c393a42Smrg#if defined (_WIN32)
16572c393a42Smrg
16582c393a42Smrg#  define WIN32_LEAN_AND_MEAN
16592c393a42Smrg#  define WIN32_EXTRA_LEAN
16602c393a42Smrg#  include <windows.h>
16612c393a42Smrg
16622c393a42Smrgstatic FcChar8 fontconfig_path[1000] = "";
16632c393a42Smrg
16642c393a42Smrg#  if (defined (PIC) || defined (DLL_EXPORT))
16652c393a42Smrg
16662c393a42SmrgBOOL WINAPI
16672c393a42SmrgDllMain (HINSTANCE hinstDLL,
16682c393a42Smrg	 DWORD     fdwReason,
16692c393a42Smrg	 LPVOID    lpvReserved)
16702c393a42Smrg{
16712c393a42Smrg  FcChar8 *p;
16722c393a42Smrg
16732c393a42Smrg  switch (fdwReason) {
16742c393a42Smrg  case DLL_PROCESS_ATTACH:
1675ca08ab68Smrg      if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path,
16762c393a42Smrg			      sizeof (fontconfig_path)))
16772c393a42Smrg	  break;
16782c393a42Smrg
16792c393a42Smrg      /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
16802c393a42Smrg       * assume it's a Unix-style installation tree, and use
16812c393a42Smrg       * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
16822c393a42Smrg       * folder where the DLL is as FONTCONFIG_PATH.
16832c393a42Smrg       */
1684ca08ab68Smrg      p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
16852c393a42Smrg      if (p)
16862c393a42Smrg      {
16872c393a42Smrg	  *p = '\0';
1688ca08ab68Smrg	  p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
1689ca08ab68Smrg	  if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 ||
1690ca08ab68Smrg		    FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0))
16912c393a42Smrg	      *p = '\0';
1692ca08ab68Smrg	  strcat ((char *) fontconfig_path, "\\etc\\fonts");
16932c393a42Smrg      }
16942c393a42Smrg      else
16952c393a42Smrg          fontconfig_path[0] = '\0';
1696ca08ab68Smrg
16972c393a42Smrg      break;
16982c393a42Smrg  }
16992c393a42Smrg
17002c393a42Smrg  return TRUE;
17012c393a42Smrg}
17022c393a42Smrg
17032c393a42Smrg#  endif /* !PIC */
17042c393a42Smrg
17052c393a42Smrg#undef FONTCONFIG_PATH
17062c393a42Smrg#define FONTCONFIG_PATH fontconfig_path
17072c393a42Smrg
17082c393a42Smrg#endif /* !_WIN32 */
17092c393a42Smrg
17102c393a42Smrg#ifndef FONTCONFIG_FILE
17112c393a42Smrg#define FONTCONFIG_FILE	"fonts.conf"
17122c393a42Smrg#endif
17132c393a42Smrg
17142c393a42Smrgstatic FcChar8 *
17152c393a42SmrgFcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
17162c393a42Smrg{
17172c393a42Smrg    FcChar8    *path;
1718ca08ab68Smrg    int         size, osize;
17192c393a42Smrg
17202c393a42Smrg    if (!dir)
17212c393a42Smrg	dir = (FcChar8 *) "";
1722ca08ab68Smrg
1723ca08ab68Smrg    osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1;
1724ca08ab68Smrg    /*
1725ca08ab68Smrg     * workaround valgrind warning because glibc takes advantage of how it knows memory is
1726ca08ab68Smrg     * allocated to implement strlen by reading in groups of 4
1727ca08ab68Smrg     */
1728ca08ab68Smrg    size = (osize + 3) & ~3;
1729ca08ab68Smrg
1730ca08ab68Smrg    path = malloc (size);
17312c393a42Smrg    if (!path)
17322c393a42Smrg	return 0;
17332c393a42Smrg
17342c393a42Smrg    strcpy ((char *) path, (const char *) dir);
17352c393a42Smrg    /* make sure there's a single separator */
17362c393a42Smrg#ifdef _WIN32
17372c393a42Smrg    if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
17382c393a42Smrg		      path[strlen((char *) path)-1] != '\\')) &&
17392c393a42Smrg	!(file[0] == '/' ||
17402c393a42Smrg	  file[0] == '\\' ||
17412c393a42Smrg	  (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
17422c393a42Smrg	strcat ((char *) path, "\\");
17432c393a42Smrg#else
17442c393a42Smrg    if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
17452c393a42Smrg	strcat ((char *) path, "/");
17462c393a42Smrg#endif
17472c393a42Smrg    strcat ((char *) path, (char *) file);
17482c393a42Smrg
1749ca08ab68Smrg    FcMemAlloc (FC_MEM_STRING, osize);
17502c393a42Smrg    if (access ((char *) path, R_OK) == 0)
17512c393a42Smrg	return path;
1752ca08ab68Smrg
17532c393a42Smrg    FcStrFree (path);
1754ca08ab68Smrg
17552c393a42Smrg    return 0;
17562c393a42Smrg}
17572c393a42Smrg
17582c393a42Smrgstatic FcChar8 **
17592c393a42SmrgFcConfigGetPath (void)
17602c393a42Smrg{
17612c393a42Smrg    FcChar8    **path;
17622c393a42Smrg    FcChar8    *env, *e, *colon;
17632c393a42Smrg    FcChar8    *dir;
17642c393a42Smrg    int	    npath;
17652c393a42Smrg    int	    i;
17662c393a42Smrg
17672c393a42Smrg    npath = 2;	/* default dir + null */
17682c393a42Smrg    env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
17692c393a42Smrg    if (env)
17702c393a42Smrg    {
17712c393a42Smrg	e = env;
17722c393a42Smrg	npath++;
17732c393a42Smrg	while (*e)
17742c393a42Smrg	    if (*e++ == FC_SEARCH_PATH_SEPARATOR)
17752c393a42Smrg		npath++;
17762c393a42Smrg    }
17772c393a42Smrg    path = calloc (npath, sizeof (FcChar8 *));
17782c393a42Smrg    if (!path)
17792c393a42Smrg	goto bail0;
17802c393a42Smrg    i = 0;
17812c393a42Smrg
17822c393a42Smrg    if (env)
17832c393a42Smrg    {
17842c393a42Smrg	e = env;
1785ca08ab68Smrg	while (*e)
17862c393a42Smrg	{
17872c393a42Smrg	    colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
17882c393a42Smrg	    if (!colon)
17892c393a42Smrg		colon = e + strlen ((char *) e);
17902c393a42Smrg	    path[i] = malloc (colon - e + 1);
17912c393a42Smrg	    if (!path[i])
17922c393a42Smrg		goto bail1;
17932c393a42Smrg	    strncpy ((char *) path[i], (const char *) e, colon - e);
17942c393a42Smrg	    path[i][colon - e] = '\0';
17952c393a42Smrg	    if (*colon)
17962c393a42Smrg		e = colon + 1;
17972c393a42Smrg	    else
17982c393a42Smrg		e = colon;
17992c393a42Smrg	    i++;
18002c393a42Smrg	}
18012c393a42Smrg    }
1802ca08ab68Smrg
18032c393a42Smrg#ifdef _WIN32
18042c393a42Smrg	if (fontconfig_path[0] == '\0')
18052c393a42Smrg	{
1806a6844aabSmrg		char *p;
1807ca08ab68Smrg		if(!GetModuleFileName(NULL, (LPCH) fontconfig_path, sizeof(fontconfig_path)))
18082c393a42Smrg			goto bail1;
1809ca08ab68Smrg		p = strrchr ((const char *) fontconfig_path, '\\');
18102c393a42Smrg		if (p) *p = '\0';
1811ca08ab68Smrg		strcat ((char *) fontconfig_path, "\\fonts");
18122c393a42Smrg	}
18132c393a42Smrg#endif
18142c393a42Smrg    dir = (FcChar8 *) FONTCONFIG_PATH;
18152c393a42Smrg    path[i] = malloc (strlen ((char *) dir) + 1);
18162c393a42Smrg    if (!path[i])
18172c393a42Smrg	goto bail1;
18182c393a42Smrg    strcpy ((char *) path[i], (const char *) dir);
18192c393a42Smrg    return path;
18202c393a42Smrg
18212c393a42Smrgbail1:
18222c393a42Smrg    for (i = 0; path[i]; i++)
18232c393a42Smrg	free (path[i]);
18242c393a42Smrg    free (path);
18252c393a42Smrgbail0:
18262c393a42Smrg    return 0;
18272c393a42Smrg}
18282c393a42Smrg
18292c393a42Smrgstatic void
18302c393a42SmrgFcConfigFreePath (FcChar8 **path)
18312c393a42Smrg{
18322c393a42Smrg    FcChar8    **p;
18332c393a42Smrg
18342c393a42Smrg    for (p = path; *p; p++)
18352c393a42Smrg	free (*p);
18362c393a42Smrg    free (path);
18372c393a42Smrg}
18382c393a42Smrg
18392c393a42Smrgstatic FcBool	_FcConfigHomeEnabled = FcTrue;
18402c393a42Smrg
18412c393a42SmrgFcChar8 *
18422c393a42SmrgFcConfigHome (void)
18432c393a42Smrg{
18442c393a42Smrg    if (_FcConfigHomeEnabled)
18452c393a42Smrg    {
18462c393a42Smrg        char *home = getenv ("HOME");
18472c393a42Smrg
18482c393a42Smrg#ifdef _WIN32
18492c393a42Smrg	if (home == NULL)
18502c393a42Smrg	    home = getenv ("USERPROFILE");
18512c393a42Smrg#endif
18522c393a42Smrg
18532c393a42Smrg	return (FcChar8 *) home;
18542c393a42Smrg    }
18552c393a42Smrg    return 0;
18562c393a42Smrg}
18572c393a42Smrg
1858ca08ab68SmrgFcChar8 *
1859ca08ab68SmrgFcConfigXdgCacheHome (void)
1860ca08ab68Smrg{
1861ca08ab68Smrg    const char *env = getenv ("XDG_CACHE_HOME");
1862ca08ab68Smrg    FcChar8 *ret = NULL;
1863ca08ab68Smrg
1864ca08ab68Smrg    if (env)
1865ca08ab68Smrg	ret = FcStrCopy ((const FcChar8 *)env);
1866ca08ab68Smrg    else
1867ca08ab68Smrg    {
1868ca08ab68Smrg	const FcChar8 *home = FcConfigHome ();
1869ca08ab68Smrg	size_t len = home ? strlen ((const char *)home) : 0;
1870ca08ab68Smrg
1871ca08ab68Smrg	ret = malloc (len + 7 + 1);
1872ca08ab68Smrg	if (ret)
1873ca08ab68Smrg	{
1874ca08ab68Smrg	    FcMemAlloc (FC_MEM_STRING, len + 7 + 1);
1875ca08ab68Smrg	    memcpy (ret, home, len);
1876ca08ab68Smrg	    memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7);
1877ca08ab68Smrg	    ret[len + 7] = 0;
1878ca08ab68Smrg	}
1879ca08ab68Smrg    }
1880ca08ab68Smrg
1881ca08ab68Smrg    return ret;
1882ca08ab68Smrg}
1883ca08ab68Smrg
1884ca08ab68SmrgFcChar8 *
1885ca08ab68SmrgFcConfigXdgConfigHome (void)
1886ca08ab68Smrg{
1887ca08ab68Smrg    const char *env = getenv ("XDG_CONFIG_HOME");
1888ca08ab68Smrg    FcChar8 *ret = NULL;
1889ca08ab68Smrg
1890ca08ab68Smrg    if (env)
1891ca08ab68Smrg	ret = FcStrCopy ((const FcChar8 *)env);
1892ca08ab68Smrg    else
1893ca08ab68Smrg    {
1894ca08ab68Smrg	const FcChar8 *home = FcConfigHome ();
1895ca08ab68Smrg	size_t len = home ? strlen ((const char *)home) : 0;
1896ca08ab68Smrg
1897ca08ab68Smrg	ret = malloc (len + 8 + 1);
1898ca08ab68Smrg	if (ret)
1899ca08ab68Smrg	{
1900ca08ab68Smrg	    FcMemAlloc (FC_MEM_STRING, len + 8 + 1);
1901ca08ab68Smrg	    memcpy (ret, home, len);
1902ca08ab68Smrg	    memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8);
1903ca08ab68Smrg	    ret[len + 8] = 0;
1904ca08ab68Smrg	}
1905ca08ab68Smrg    }
1906ca08ab68Smrg
1907ca08ab68Smrg    return ret;
1908ca08ab68Smrg}
1909ca08ab68Smrg
1910ca08ab68SmrgFcChar8 *
1911ca08ab68SmrgFcConfigXdgDataHome (void)
1912ca08ab68Smrg{
1913ca08ab68Smrg    const char *env = getenv ("XDG_DATA_HOME");
1914ca08ab68Smrg    FcChar8 *ret = NULL;
1915ca08ab68Smrg
1916ca08ab68Smrg    if (env)
1917ca08ab68Smrg	ret = FcStrCopy ((const FcChar8 *)env);
1918ca08ab68Smrg    else
1919ca08ab68Smrg    {
1920ca08ab68Smrg	const FcChar8 *home = FcConfigHome ();
1921ca08ab68Smrg	size_t len = home ? strlen ((const char *)home) : 0;
1922ca08ab68Smrg
1923ca08ab68Smrg	ret = malloc (len + 13 + 1);
1924ca08ab68Smrg	if (ret)
1925ca08ab68Smrg	{
1926ca08ab68Smrg	    FcMemAlloc (FC_MEM_STRING, len + 13 + 1);
1927ca08ab68Smrg	    memcpy (ret, home, len);
1928ca08ab68Smrg	    memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13);
1929ca08ab68Smrg	    ret[len + 13] = 0;
1930ca08ab68Smrg	}
1931ca08ab68Smrg    }
1932ca08ab68Smrg
1933ca08ab68Smrg    return ret;
1934ca08ab68Smrg}
1935ca08ab68Smrg
19362c393a42SmrgFcBool
19372c393a42SmrgFcConfigEnableHome (FcBool enable)
19382c393a42Smrg{
19392c393a42Smrg    FcBool  prev = _FcConfigHomeEnabled;
19402c393a42Smrg    _FcConfigHomeEnabled = enable;
19412c393a42Smrg    return prev;
19422c393a42Smrg}
19432c393a42Smrg
19442c393a42SmrgFcChar8 *
19452c393a42SmrgFcConfigFilename (const FcChar8 *url)
19462c393a42Smrg{
19472c393a42Smrg    FcChar8    *file, *dir, **path, **p;
19482c393a42Smrg
19492c393a42Smrg    if (!url || !*url)
19502c393a42Smrg    {
19512c393a42Smrg	url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
19522c393a42Smrg	if (!url)
19532c393a42Smrg	    url = (FcChar8 *) FONTCONFIG_FILE;
19542c393a42Smrg    }
19552c393a42Smrg    file = 0;
19562c393a42Smrg
19572c393a42Smrg#ifdef _WIN32
19582c393a42Smrg    if (isalpha (*url) &&
19592c393a42Smrg	url[1] == ':' &&
19602c393a42Smrg	(url[2] == '/' || url[2] == '\\'))
19612c393a42Smrg	goto absolute_path;
19622c393a42Smrg#endif
19632c393a42Smrg
19642c393a42Smrg    switch (*url) {
19652c393a42Smrg    case '~':
19662c393a42Smrg	dir = FcConfigHome ();
19672c393a42Smrg	if (dir)
19682c393a42Smrg	    file = FcConfigFileExists (dir, url + 1);
19692c393a42Smrg	else
19702c393a42Smrg	    file = 0;
19712c393a42Smrg	break;
19722c393a42Smrg#ifdef _WIN32
19732c393a42Smrg    case '\\':
19742c393a42Smrg    absolute_path:
19752c393a42Smrg#endif
19762c393a42Smrg    case '/':
19772c393a42Smrg	file = FcConfigFileExists (0, url);
19782c393a42Smrg	break;
19792c393a42Smrg    default:
19802c393a42Smrg	path = FcConfigGetPath ();
19812c393a42Smrg	if (!path)
1982ca08ab68Smrg	    return NULL;
19832c393a42Smrg	for (p = path; *p; p++)
19842c393a42Smrg	{
19852c393a42Smrg	    file = FcConfigFileExists (*p, url);
19862c393a42Smrg	    if (file)
19872c393a42Smrg		break;
19882c393a42Smrg	}
19892c393a42Smrg	FcConfigFreePath (path);
19902c393a42Smrg	break;
19912c393a42Smrg    }
1992ca08ab68Smrg
19932c393a42Smrg    return file;
19942c393a42Smrg}
19952c393a42Smrg
19962c393a42Smrg/*
19972c393a42Smrg * Manage the application-specific fonts
19982c393a42Smrg */
19992c393a42Smrg
20002c393a42SmrgFcBool
20012c393a42SmrgFcConfigAppFontAddFile (FcConfig    *config,
20022c393a42Smrg			const FcChar8  *file)
20032c393a42Smrg{
20042c393a42Smrg    FcFontSet	*set;
20052c393a42Smrg    FcStrSet	*subdirs;
20062c393a42Smrg    FcStrList	*sublist;
20072c393a42Smrg    FcChar8	*subdir;
20082c393a42Smrg
20092c393a42Smrg    if (!config)
20102c393a42Smrg    {
20112c393a42Smrg	config = FcConfigGetCurrent ();
20122c393a42Smrg	if (!config)
20132c393a42Smrg	    return FcFalse;
20142c393a42Smrg    }
20152c393a42Smrg
20162c393a42Smrg    subdirs = FcStrSetCreate ();
20172c393a42Smrg    if (!subdirs)
20182c393a42Smrg	return FcFalse;
2019ca08ab68Smrg
20202c393a42Smrg    set = FcConfigGetFonts (config, FcSetApplication);
20212c393a42Smrg    if (!set)
20222c393a42Smrg    {
20232c393a42Smrg	set = FcFontSetCreate ();
20242c393a42Smrg	if (!set)
20252c393a42Smrg	{
20262c393a42Smrg	    FcStrSetDestroy (subdirs);
20272c393a42Smrg	    return FcFalse;
20282c393a42Smrg	}
20292c393a42Smrg	FcConfigSetFonts (config, set, FcSetApplication);
20302c393a42Smrg    }
20312c393a42Smrg
20322c393a42Smrg    if (!FcFileScanConfig (set, subdirs, config->blanks, file, config))
20332c393a42Smrg    {
20342c393a42Smrg	FcStrSetDestroy (subdirs);
20352c393a42Smrg	return FcFalse;
20362c393a42Smrg    }
20372c393a42Smrg    if ((sublist = FcStrListCreate (subdirs)))
20382c393a42Smrg    {
20392c393a42Smrg	while ((subdir = FcStrListNext (sublist)))
20402c393a42Smrg	{
20412c393a42Smrg	    FcConfigAppFontAddDir (config, subdir);
20422c393a42Smrg	}
20432c393a42Smrg	FcStrListDone (sublist);
20442c393a42Smrg    }
20452c393a42Smrg    FcStrSetDestroy (subdirs);
20462c393a42Smrg    return FcTrue;
20472c393a42Smrg}
20482c393a42Smrg
20492c393a42SmrgFcBool
20502c393a42SmrgFcConfigAppFontAddDir (FcConfig	    *config,
20512c393a42Smrg		       const FcChar8   *dir)
20522c393a42Smrg{
20532c393a42Smrg    FcFontSet	*set;
20542c393a42Smrg    FcStrSet	*dirs;
2055ca08ab68Smrg
20562c393a42Smrg    if (!config)
20572c393a42Smrg    {
20582c393a42Smrg	config = FcConfigGetCurrent ();
20592c393a42Smrg	if (!config)
20602c393a42Smrg	    return FcFalse;
20612c393a42Smrg    }
20622c393a42Smrg
20632c393a42Smrg    dirs = FcStrSetCreate ();
20642c393a42Smrg    if (!dirs)
20652c393a42Smrg	return FcFalse;
2066ca08ab68Smrg
20672c393a42Smrg    set = FcConfigGetFonts (config, FcSetApplication);
20682c393a42Smrg    if (!set)
20692c393a42Smrg    {
20702c393a42Smrg	set = FcFontSetCreate ();
20712c393a42Smrg	if (!set)
20722c393a42Smrg	{
20732c393a42Smrg	    FcStrSetDestroy (dirs);
20742c393a42Smrg	    return FcFalse;
20752c393a42Smrg	}
20762c393a42Smrg	FcConfigSetFonts (config, set, FcSetApplication);
20772c393a42Smrg    }
2078ca08ab68Smrg
20792c393a42Smrg    FcStrSetAddFilename (dirs, dir);
2080ca08ab68Smrg
20812c393a42Smrg    if (!FcConfigAddDirList (config, FcSetApplication, dirs))
20822c393a42Smrg    {
20832c393a42Smrg	FcStrSetDestroy (dirs);
20842c393a42Smrg	return FcFalse;
20852c393a42Smrg    }
20862c393a42Smrg    FcStrSetDestroy (dirs);
20872c393a42Smrg    return FcTrue;
20882c393a42Smrg}
20892c393a42Smrg
20902c393a42Smrgvoid
20912c393a42SmrgFcConfigAppFontClear (FcConfig	    *config)
20922c393a42Smrg{
20932c393a42Smrg    if (!config)
20942c393a42Smrg    {
20952c393a42Smrg	config = FcConfigGetCurrent ();
20962c393a42Smrg	if (!config)
20972c393a42Smrg	    return;
20982c393a42Smrg    }
20992c393a42Smrg
21002c393a42Smrg    FcConfigSetFonts (config, 0, FcSetApplication);
21012c393a42Smrg}
21022c393a42Smrg
21032c393a42Smrg/*
21042c393a42Smrg * Manage filename-based font source selectors
21052c393a42Smrg */
21062c393a42Smrg
21072c393a42SmrgFcBool
21082c393a42SmrgFcConfigGlobAdd (FcConfig	*config,
21092c393a42Smrg		 const FcChar8  *glob,
21102c393a42Smrg		 FcBool		accept)
21112c393a42Smrg{
21122c393a42Smrg    FcStrSet	*set = accept ? config->acceptGlobs : config->rejectGlobs;
21132c393a42Smrg
21142c393a42Smrg    return FcStrSetAdd (set, glob);
21152c393a42Smrg}
21162c393a42Smrg
21172c393a42Smrgstatic FcBool
21182c393a42SmrgFcConfigGlobMatch (const FcChar8    *glob,
21192c393a42Smrg		   const FcChar8    *string)
21202c393a42Smrg{
21212c393a42Smrg    FcChar8	c;
21222c393a42Smrg
2123ca08ab68Smrg    while ((c = *glob++))
21242c393a42Smrg    {
21252c393a42Smrg	switch (c) {
21262c393a42Smrg	case '*':
21272c393a42Smrg	    /* short circuit common case */
21282c393a42Smrg	    if (!*glob)
21292c393a42Smrg		return FcTrue;
21302c393a42Smrg	    /* short circuit another common case */
21312c393a42Smrg	    if (strchr ((char *) glob, '*') == 0)
2132ca08ab68Smrg	    {
2133ca08ab68Smrg		size_t l1, l2;
2134ca08ab68Smrg
2135ca08ab68Smrg		l1 = strlen ((char *) string);
2136ca08ab68Smrg		l2 = strlen ((char *) glob);
2137ca08ab68Smrg		if (l1 < l2)
2138ca08ab68Smrg		    return FcFalse;
2139ca08ab68Smrg		string += (l1 - l2);
2140ca08ab68Smrg	    }
21412c393a42Smrg	    while (*string)
21422c393a42Smrg	    {
21432c393a42Smrg		if (FcConfigGlobMatch (glob, string))
21442c393a42Smrg		    return FcTrue;
21452c393a42Smrg		string++;
21462c393a42Smrg	    }
21472c393a42Smrg	    return FcFalse;
21482c393a42Smrg	case '?':
21492c393a42Smrg	    if (*string++ == '\0')
21502c393a42Smrg		return FcFalse;
21512c393a42Smrg	    break;
21522c393a42Smrg	default:
21532c393a42Smrg	    if (*string++ != c)
21542c393a42Smrg		return FcFalse;
21552c393a42Smrg	    break;
21562c393a42Smrg	}
21572c393a42Smrg    }
21582c393a42Smrg    return *string == '\0';
21592c393a42Smrg}
21602c393a42Smrg
21612c393a42Smrgstatic FcBool
21622c393a42SmrgFcConfigGlobsMatch (const FcStrSet	*globs,
21632c393a42Smrg		    const FcChar8	*string)
21642c393a42Smrg{
21652c393a42Smrg    int	i;
21662c393a42Smrg
21672c393a42Smrg    for (i = 0; i < globs->num; i++)
21682c393a42Smrg	if (FcConfigGlobMatch (globs->strs[i], string))
21692c393a42Smrg	    return FcTrue;
21702c393a42Smrg    return FcFalse;
21712c393a42Smrg}
21722c393a42Smrg
21732c393a42SmrgFcBool
21742c393a42SmrgFcConfigAcceptFilename (FcConfig	*config,
21752c393a42Smrg			const FcChar8	*filename)
21762c393a42Smrg{
21772c393a42Smrg    if (FcConfigGlobsMatch (config->acceptGlobs, filename))
21782c393a42Smrg	return FcTrue;
21792c393a42Smrg    if (FcConfigGlobsMatch (config->rejectGlobs, filename))
21802c393a42Smrg	return FcFalse;
21812c393a42Smrg    return FcTrue;
21822c393a42Smrg}
21832c393a42Smrg
21842c393a42Smrg/*
21852c393a42Smrg * Manage font-pattern based font source selectors
21862c393a42Smrg */
21872c393a42Smrg
21882c393a42SmrgFcBool
21892c393a42SmrgFcConfigPatternsAdd (FcConfig	*config,
21902c393a42Smrg		     FcPattern	*pattern,
21912c393a42Smrg		     FcBool	accept)
21922c393a42Smrg{
21932c393a42Smrg    FcFontSet	*set = accept ? config->acceptPatterns : config->rejectPatterns;
21942c393a42Smrg
21952c393a42Smrg    return FcFontSetAdd (set, pattern);
21962c393a42Smrg}
21972c393a42Smrg
21982c393a42Smrgstatic FcBool
21992c393a42SmrgFcConfigPatternsMatch (const FcFontSet	*patterns,
22002c393a42Smrg		       const FcPattern	*font)
22012c393a42Smrg{
22022c393a42Smrg    int i;
2203ca08ab68Smrg
22042c393a42Smrg    for (i = 0; i < patterns->nfont; i++)
22052c393a42Smrg	if (FcListPatternMatchAny (patterns->fonts[i], font))
22062c393a42Smrg	    return FcTrue;
22072c393a42Smrg    return FcFalse;
22082c393a42Smrg}
22092c393a42Smrg
22102c393a42SmrgFcBool
22112c393a42SmrgFcConfigAcceptFont (FcConfig	    *config,
22122c393a42Smrg		    const FcPattern *font)
22132c393a42Smrg{
22142c393a42Smrg    if (FcConfigPatternsMatch (config->acceptPatterns, font))
22152c393a42Smrg	return FcTrue;
22162c393a42Smrg    if (FcConfigPatternsMatch (config->rejectPatterns, font))
22172c393a42Smrg	return FcFalse;
22182c393a42Smrg    return FcTrue;
22192c393a42Smrg}
22202c393a42Smrg#define __fccfg__
22212c393a42Smrg#include "fcaliastail.h"
22222c393a42Smrg#undef __fccfg__
2223