diff options
Diffstat (limited to 'fontconfig/src/fccfg.c')
-rw-r--r-- | fontconfig/src/fccfg.c | 4155 |
1 files changed, 2099 insertions, 2056 deletions
diff --git a/fontconfig/src/fccfg.c b/fontconfig/src/fccfg.c index 0f89b57a4..d6300515e 100644 --- a/fontconfig/src/fccfg.c +++ b/fontconfig/src/fccfg.c @@ -1,2056 +1,2099 @@ -/* - * fontconfig/src/fccfg.c - * - * Copyright © 2000 Keith Packard - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#include "fcint.h" -#include <dirent.h> -#include <sys/types.h> - -#if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT)) -#define STRICT -#include <windows.h> -#undef STRICT -#endif - -#if defined (_WIN32) && !defined (R_OK) -#define R_OK 4 -#endif - -FcConfig *_fcConfig; - -FcConfig * -FcConfigCreate (void) -{ - FcSetName set; - FcConfig *config; - - config = malloc (sizeof (FcConfig)); - if (!config) - goto bail0; - FcMemAlloc (FC_MEM_CONFIG, sizeof (FcConfig)); - - config->configDirs = FcStrSetCreate (); - if (!config->configDirs) - goto bail1; - - config->configFiles = FcStrSetCreate (); - if (!config->configFiles) - goto bail2; - - config->fontDirs = FcStrSetCreate (); - if (!config->fontDirs) - goto bail3; - - config->acceptGlobs = FcStrSetCreate (); - if (!config->acceptGlobs) - goto bail4; - - config->rejectGlobs = FcStrSetCreate (); - if (!config->rejectGlobs) - goto bail5; - - config->acceptPatterns = FcFontSetCreate (); - if (!config->acceptPatterns) - goto bail6; - - config->rejectPatterns = FcFontSetCreate (); - if (!config->rejectPatterns) - goto bail7; - - config->cacheDirs = FcStrSetCreate (); - if (!config->cacheDirs) - goto bail8; - - config->blanks = 0; - - config->substPattern = 0; - config->substFont = 0; - config->substScan = 0; - config->maxObjects = 0; - for (set = FcSetSystem; set <= FcSetApplication; set++) - config->fonts[set] = 0; - - config->rescanTime = time(0); - config->rescanInterval = 30; - - config->expr_pool = NULL; - - config->ref = 1; - - return config; - -bail8: - FcFontSetDestroy (config->rejectPatterns); -bail7: - FcFontSetDestroy (config->acceptPatterns); -bail6: - FcStrSetDestroy (config->rejectGlobs); -bail5: - FcStrSetDestroy (config->acceptGlobs); -bail4: - FcStrSetDestroy (config->fontDirs); -bail3: - FcStrSetDestroy (config->configFiles); -bail2: - FcStrSetDestroy (config->configDirs); -bail1: - free (config); - FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig)); -bail0: - return 0; -} - -static FcFileTime -FcConfigNewestFile (FcStrSet *files) -{ - FcStrList *list = FcStrListCreate (files); - FcFileTime newest = { 0, FcFalse }; - FcChar8 *file; - struct stat statb; - - if (list) - { - while ((file = FcStrListNext (list))) - if (FcStat ((char *) file, &statb) == 0) - if (!newest.set || statb.st_mtime - newest.time > 0) - { - newest.set = FcTrue; - newest.time = statb.st_mtime; - } - FcStrListDone (list); - } - return newest; -} - -FcBool -FcConfigUptoDate (FcConfig *config) -{ - FcFileTime config_time, config_dir_time, font_time; - time_t now = time(0); - if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return FcFalse; - } - config_time = FcConfigNewestFile (config->configFiles); - config_dir_time = FcConfigNewestFile (config->configDirs); - font_time = FcConfigNewestFile (config->fontDirs); - if ((config_time.set && config_time.time - config->rescanTime > 0) || - (config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) || - (font_time.set && (font_time.time - config->rescanTime) > 0)) - { - /* We need to check for potential clock problems here (OLPC ticket #6046) */ - if ((config_time.set && (config_time.time - now) > 0) || - (config_dir_time.set && (config_dir_time.time - now) > 0) || - (font_time.set && (font_time.time - now) > 0)) - { - fprintf (stderr, - "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected\n"); - config->rescanTime = now; - return FcTrue; - } - else - return FcFalse; - } - config->rescanTime = now; - return FcTrue; -} - -static void -FcSubstDestroy (FcSubst *s) -{ - FcSubst *n; - - while (s) - { - n = s->next; - if (s->test) - FcTestDestroy (s->test); - if (s->edit) - FcEditDestroy (s->edit); - free (s); - FcMemFree (FC_MEM_SUBST, sizeof (FcSubst)); - s = n; - } -} - -FcExpr * -FcConfigAllocExpr (FcConfig *config) -{ - if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end) - { - FcExprPage *new_page; - - new_page = malloc (sizeof (FcExprPage)); - if (!new_page) - return 0; - FcMemAlloc (FC_MEM_EXPR, sizeof (FcExprPage)); - - new_page->next_page = config->expr_pool; - new_page->next = new_page->exprs; - config->expr_pool = new_page; - } - - return config->expr_pool->next++; -} - -FcConfig * -FcConfigReference (FcConfig *config) -{ - if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return 0; - } - - config->ref++; - - return config; -} - -void -FcConfigDestroy (FcConfig *config) -{ - FcSetName set; - FcExprPage *page; - - if (--config->ref > 0) - return; - - if (config == _fcConfig) - _fcConfig = 0; - - FcStrSetDestroy (config->configDirs); - FcStrSetDestroy (config->fontDirs); - FcStrSetDestroy (config->cacheDirs); - FcStrSetDestroy (config->configFiles); - FcStrSetDestroy (config->acceptGlobs); - FcStrSetDestroy (config->rejectGlobs); - FcFontSetDestroy (config->acceptPatterns); - FcFontSetDestroy (config->rejectPatterns); - - if (config->blanks) - FcBlanksDestroy (config->blanks); - - FcSubstDestroy (config->substPattern); - FcSubstDestroy (config->substFont); - FcSubstDestroy (config->substScan); - for (set = FcSetSystem; set <= FcSetApplication; set++) - if (config->fonts[set]) - FcFontSetDestroy (config->fonts[set]); - - page = config->expr_pool; - while (page) - { - FcExprPage *next = page->next_page; - FcMemFree (FC_MEM_EXPR, sizeof (FcExprPage)); - free (page); - page = next; - } - - free (config); - FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig)); -} - -/* - * Add cache to configuration, adding fonts and directories - */ - -FcBool -FcConfigAddCache (FcConfig *config, FcCache *cache, - FcSetName set, FcStrSet *dirSet) -{ - FcFontSet *fs; - intptr_t *dirs; - int i; - - /* - * Add fonts - */ - fs = FcCacheSet (cache); - if (fs) - { - int nref = 0; - - for (i = 0; i < fs->nfont; i++) - { - FcPattern *font = FcFontSetFont (fs, i); - FcChar8 *font_file; - - /* - * Check to see if font is banned by filename - */ - if (FcPatternObjectGetString (font, FC_FILE_OBJECT, - 0, &font_file) == FcResultMatch && - !FcConfigAcceptFilename (config, font_file)) - { - continue; - } - - /* - * Check to see if font is banned by pattern - */ - if (!FcConfigAcceptFont (config, font)) - continue; - - nref++; - FcFontSetAdd (config->fonts[set], font); - } - FcDirCacheReference (cache, nref); - } - - /* - * Add directories - */ - dirs = FcCacheDirs (cache); - if (dirs) - { - for (i = 0; i < cache->dirs_count; i++) - { - FcChar8 *dir = FcOffsetToPtr (dirs, dirs[i], FcChar8); - if (FcConfigAcceptFilename (config, dir)) - FcStrSetAddFilename (dirSet, dir); - } - } - return FcTrue; -} - -static FcBool -FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet) -{ - FcStrList *dirlist; - FcChar8 *dir; - FcCache *cache; - - dirlist = FcStrListCreate (dirSet); - if (!dirlist) - return FcFalse; - - while ((dir = FcStrListNext (dirlist))) - { - if (FcDebug () & FC_DBG_FONTSET) - printf ("adding fonts from%s\n", dir); - cache = FcDirCacheRead (dir, FcFalse, config); - if (!cache) - continue; - FcConfigAddCache (config, cache, set, dirSet); - FcDirCacheUnload (cache); - } - FcStrListDone (dirlist); - return FcTrue; -} - -/* - * Scan the current list of directories in the configuration - * and build the set of available fonts. - */ - -FcBool -FcConfigBuildFonts (FcConfig *config) -{ - FcFontSet *fonts; - - if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return FcFalse; - } - - fonts = FcFontSetCreate (); - if (!fonts) - return FcFalse; - - FcConfigSetFonts (config, fonts, FcSetSystem); - - if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs)) - return FcFalse; - if (FcDebug () & FC_DBG_FONTSET) - FcFontSetPrint (fonts); - return FcTrue; -} - -FcBool -FcConfigSetCurrent (FcConfig *config) -{ - if (config == _fcConfig) - return FcTrue; - - if (!config->fonts) - if (!FcConfigBuildFonts (config)) - return FcFalse; - - if (_fcConfig) - FcConfigDestroy (_fcConfig); - _fcConfig = config; - return FcTrue; -} - -FcConfig * -FcConfigGetCurrent (void) -{ - if (!_fcConfig) - if (!FcInit ()) - return 0; - return _fcConfig; -} - -FcBool -FcConfigAddConfigDir (FcConfig *config, - const FcChar8 *d) -{ - return FcStrSetAddFilename (config->configDirs, d); -} - -FcStrList * -FcConfigGetConfigDirs (FcConfig *config) -{ - if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return 0; - } - return FcStrListCreate (config->configDirs); -} - -FcBool -FcConfigAddFontDir (FcConfig *config, - const FcChar8 *d) -{ - return FcStrSetAddFilename (config->fontDirs, d); -} - -FcBool -FcConfigAddDir (FcConfig *config, - const FcChar8 *d) -{ - return (FcConfigAddConfigDir (config, d) && - FcConfigAddFontDir (config, d)); -} - -FcStrList * -FcConfigGetFontDirs (FcConfig *config) -{ - if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return 0; - } - return FcStrListCreate (config->fontDirs); -} - -FcBool -FcConfigAddCacheDir (FcConfig *config, - const FcChar8 *d) -{ - return FcStrSetAddFilename (config->cacheDirs, d); -} - -FcStrList * -FcConfigGetCacheDirs (FcConfig *config) -{ - if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return 0; - } - return FcStrListCreate (config->cacheDirs); -} - -FcBool -FcConfigAddConfigFile (FcConfig *config, - const FcChar8 *f) -{ - FcBool ret; - FcChar8 *file = FcConfigFilename (f); - - if (!file) - return FcFalse; - - ret = FcStrSetAdd (config->configFiles, file); - FcStrFree (file); - return ret; -} - -FcStrList * -FcConfigGetConfigFiles (FcConfig *config) -{ - if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return 0; - } - return FcStrListCreate (config->configFiles); -} - -FcChar8 * -FcConfigGetCache (FcConfig *config) -{ - return NULL; -} - -FcFontSet * -FcConfigGetFonts (FcConfig *config, - FcSetName set) -{ - if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return 0; - } - return config->fonts[set]; -} - -void -FcConfigSetFonts (FcConfig *config, - FcFontSet *fonts, - FcSetName set) -{ - if (config->fonts[set]) - FcFontSetDestroy (config->fonts[set]); - config->fonts[set] = fonts; -} - -FcBlanks * -FcConfigGetBlanks (FcConfig *config) -{ - if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return 0; - } - return config->blanks; -} - -FcBool -FcConfigAddBlank (FcConfig *config, - FcChar32 blank) -{ - FcBlanks *b, *freeme = 0; - - b = config->blanks; - if (!b) - { - freeme = b = FcBlanksCreate (); - if (!b) - return FcFalse; - } - if (!FcBlanksAdd (b, blank)) - { - if (freeme) - FcBlanksDestroy (freeme); - return FcFalse; - } - config->blanks = b; - return FcTrue; -} - -int -FcConfigGetRescanInterval (FcConfig *config) -{ - if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return 0; - } - return config->rescanInterval; -} - -FcBool -FcConfigSetRescanInterval (FcConfig *config, int rescanInterval) -{ - if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return FcFalse; - } - config->rescanInterval = rescanInterval; - return FcTrue; -} - -/* - * A couple of typos escaped into the library - */ -int -FcConfigGetRescanInverval (FcConfig *config) -{ - return FcConfigGetRescanInterval (config); -} - -FcBool -FcConfigSetRescanInverval (FcConfig *config, int rescanInterval) -{ - return FcConfigSetRescanInterval (config, rescanInterval); -} - - -FcBool -FcConfigAddEdit (FcConfig *config, - FcTest *test, - FcEdit *edit, - FcMatchKind kind) -{ - FcSubst *subst, **prev; - FcTest *t; - int num; - - switch (kind) { - case FcMatchPattern: - prev = &config->substPattern; - break; - case FcMatchFont: - prev = &config->substFont; - break; - case FcMatchScan: - prev = &config->substScan; - break; - default: - return FcFalse; - } - subst = (FcSubst *) malloc (sizeof (FcSubst)); - if (!subst) - return FcFalse; - FcMemAlloc (FC_MEM_SUBST, sizeof (FcSubst)); - for (; *prev; prev = &(*prev)->next); - *prev = subst; - subst->next = 0; - subst->test = test; - subst->edit = edit; - num = 0; - for (t = test; t; t = t->next) - { - if (t->kind == FcMatchDefault) - t->kind = kind; - num++; - } - if (config->maxObjects < num) - config->maxObjects = num; - if (FcDebug () & FC_DBG_EDIT) - { - printf ("Add Subst "); - FcSubstPrint (subst); - } - return FcTrue; -} - -typedef struct _FcSubState { - FcPatternElt *elt; - FcValueList *value; -} FcSubState; - -static FcValue -FcConfigPromote (FcValue v, FcValue u) -{ - if (v.type == FcTypeInteger) - { - v.type = FcTypeDouble; - v.u.d = (double) v.u.i; - } - else if (v.type == FcTypeVoid && u.type == FcTypeMatrix) - { - v.u.m = &FcIdentityMatrix; - v.type = FcTypeMatrix; - } - else if (v.type == FcTypeString && u.type == FcTypeLangSet) - { - v.u.l = FcLangSetPromote (v.u.s); - v.type = FcTypeLangSet; - } - return v; -} - -FcBool -FcConfigCompareValue (const FcValue *left_o, - FcOp op, - const FcValue *right_o) -{ - FcValue left = FcValueCanonicalize(left_o); - FcValue right = FcValueCanonicalize(right_o); - FcBool ret = FcFalse; - - left = FcConfigPromote (left, right); - right = FcConfigPromote (right, left); - if (left.type == right.type) - { - switch (left.type) { - case FcTypeInteger: - break; /* FcConfigPromote prevents this from happening */ - case FcTypeDouble: - switch (op) { - case FcOpEqual: - case FcOpContains: - case FcOpListing: - ret = left.u.d == right.u.d; - break; - case FcOpNotEqual: - case FcOpNotContains: - ret = left.u.d != right.u.d; - break; - case FcOpLess: - ret = left.u.d < right.u.d; - break; - case FcOpLessEqual: - ret = left.u.d <= right.u.d; - break; - case FcOpMore: - ret = left.u.d > right.u.d; - break; - case FcOpMoreEqual: - ret = left.u.d >= right.u.d; - break; - default: - break; - } - break; - case FcTypeBool: - switch (op) { - case FcOpEqual: - case FcOpContains: - case FcOpListing: - ret = left.u.b == right.u.b; - break; - case FcOpNotEqual: - case FcOpNotContains: - ret = left.u.b != right.u.b; - break; - default: - break; - } - break; - case FcTypeString: - switch (op) { - case FcOpEqual: - case FcOpListing: - ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0; - break; - case FcOpContains: - ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0; - break; - case FcOpNotEqual: - ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0; - break; - case FcOpNotContains: - ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0; - break; - default: - break; - } - break; - case FcTypeMatrix: - switch (op) { - case FcOpEqual: - case FcOpContains: - case FcOpListing: - ret = FcMatrixEqual (left.u.m, right.u.m); - break; - case FcOpNotEqual: - case FcOpNotContains: - ret = !FcMatrixEqual (left.u.m, right.u.m); - break; - default: - break; - } - break; - case FcTypeCharSet: - switch (op) { - case FcOpContains: - case FcOpListing: - /* left contains right if right is a subset of left */ - ret = FcCharSetIsSubset (right.u.c, left.u.c); - break; - case FcOpNotContains: - /* left contains right if right is a subset of left */ - ret = !FcCharSetIsSubset (right.u.c, left.u.c); - break; - case FcOpEqual: - ret = FcCharSetEqual (left.u.c, right.u.c); - break; - case FcOpNotEqual: - ret = !FcCharSetEqual (left.u.c, right.u.c); - break; - default: - break; - } - break; - case FcTypeLangSet: - switch (op) { - case FcOpContains: - case FcOpListing: - ret = FcLangSetContains (left.u.l, right.u.l); - break; - case FcOpNotContains: - ret = !FcLangSetContains (left.u.l, right.u.l); - break; - case FcOpEqual: - ret = FcLangSetEqual (left.u.l, right.u.l); - break; - case FcOpNotEqual: - ret = !FcLangSetEqual (left.u.l, right.u.l); - break; - default: - break; - } - break; - case FcTypeVoid: - switch (op) { - case FcOpEqual: - case FcOpContains: - case FcOpListing: - ret = FcTrue; - break; - default: - break; - } - break; - case FcTypeFTFace: - switch (op) { - case FcOpEqual: - case FcOpContains: - case FcOpListing: - ret = left.u.f == right.u.f; - break; - case FcOpNotEqual: - case FcOpNotContains: - ret = left.u.f != right.u.f; - break; - default: - break; - } - break; - } - } - else - { - if (op == FcOpNotEqual || op == FcOpNotContains) - ret = FcTrue; - } - return ret; -} - - -#define _FcDoubleFloor(d) ((int) (d)) -#define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1)) -#define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d))) -#define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d))) -#define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5) -#define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d))) - -static FcValue -FcConfigEvaluate (FcPattern *p, FcExpr *e) -{ - FcValue v, vl, vr; - FcResult r; - FcMatrix *m; - FcChar8 *str; - - switch (e->op) { - case FcOpInteger: - v.type = FcTypeInteger; - v.u.i = e->u.ival; - break; - case FcOpDouble: - v.type = FcTypeDouble; - v.u.d = e->u.dval; - break; - case FcOpString: - v.type = FcTypeString; - v.u.s = e->u.sval; - v = FcValueSave (v); - break; - case FcOpMatrix: - v.type = FcTypeMatrix; - v.u.m = e->u.mval; - v = FcValueSave (v); - break; - case FcOpCharSet: - v.type = FcTypeCharSet; - v.u.c = e->u.cval; - v = FcValueSave (v); - break; - case FcOpBool: - v.type = FcTypeBool; - v.u.b = e->u.bval; - break; - case FcOpField: - r = FcPatternObjectGet (p, e->u.object, 0, &v); - if (r != FcResultMatch) - v.type = FcTypeVoid; - v = FcValueSave (v); - break; - case FcOpConst: - if (FcNameConstant (e->u.constant, &v.u.i)) - v.type = FcTypeInteger; - else - v.type = FcTypeVoid; - break; - case FcOpQuest: - vl = FcConfigEvaluate (p, e->u.tree.left); - if (vl.type == FcTypeBool) - { - if (vl.u.b) - v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left); - else - v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right); - } - else - v.type = FcTypeVoid; - FcValueDestroy (vl); - break; - case FcOpEqual: - case FcOpNotEqual: - case FcOpLess: - case FcOpLessEqual: - case FcOpMore: - case FcOpMoreEqual: - case FcOpContains: - case FcOpNotContains: - case FcOpListing: - vl = FcConfigEvaluate (p, e->u.tree.left); - vr = FcConfigEvaluate (p, e->u.tree.right); - v.type = FcTypeBool; - v.u.b = FcConfigCompareValue (&vl, e->op, &vr); - FcValueDestroy (vl); - FcValueDestroy (vr); - break; - case FcOpOr: - case FcOpAnd: - case FcOpPlus: - case FcOpMinus: - case FcOpTimes: - case FcOpDivide: - vl = FcConfigEvaluate (p, e->u.tree.left); - vr = FcConfigEvaluate (p, e->u.tree.right); - vl = FcConfigPromote (vl, vr); - vr = FcConfigPromote (vr, vl); - if (vl.type == vr.type) - { - switch (vl.type) { - case FcTypeDouble: - switch (e->op) { - case FcOpPlus: - v.type = FcTypeDouble; - v.u.d = vl.u.d + vr.u.d; - break; - case FcOpMinus: - v.type = FcTypeDouble; - v.u.d = vl.u.d - vr.u.d; - break; - case FcOpTimes: - v.type = FcTypeDouble; - v.u.d = vl.u.d * vr.u.d; - break; - case FcOpDivide: - v.type = FcTypeDouble; - v.u.d = vl.u.d / vr.u.d; - break; - default: - v.type = FcTypeVoid; - break; - } - if (v.type == FcTypeDouble && - v.u.d == (double) (int) v.u.d) - { - v.type = FcTypeInteger; - v.u.i = (int) v.u.d; - } - break; - case FcTypeBool: - switch (e->op) { - case FcOpOr: - v.type = FcTypeBool; - v.u.b = vl.u.b || vr.u.b; - break; - case FcOpAnd: - v.type = FcTypeBool; - v.u.b = vl.u.b && vr.u.b; - break; - default: - v.type = FcTypeVoid; - break; - } - break; - case FcTypeString: - switch (e->op) { - case FcOpPlus: - v.type = FcTypeString; - str = FcStrPlus (vl.u.s, vr.u.s); - v.u.s = FcStrStaticName (str); - FcStrFree (str); - - if (!v.u.s) - v.type = FcTypeVoid; - break; - default: - v.type = FcTypeVoid; - break; - } - break; - case FcTypeMatrix: - switch (e->op) { - case FcOpTimes: - v.type = FcTypeMatrix; - m = malloc (sizeof (FcMatrix)); - if (m) - { - FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix)); - FcMatrixMultiply (m, vl.u.m, vr.u.m); - v.u.m = m; - } - else - { - v.type = FcTypeVoid; - } - break; - default: - v.type = FcTypeVoid; - break; - } - break; - default: - v.type = FcTypeVoid; - break; - } - } - else - v.type = FcTypeVoid; - FcValueDestroy (vl); - FcValueDestroy (vr); - break; - case FcOpNot: - vl = FcConfigEvaluate (p, e->u.tree.left); - switch (vl.type) { - case FcTypeBool: - v.type = FcTypeBool; - v.u.b = !vl.u.b; - break; - default: - v.type = FcTypeVoid; - break; - } - FcValueDestroy (vl); - break; - case FcOpFloor: - vl = FcConfigEvaluate (p, e->u.tree.left); - switch (vl.type) { - case FcTypeInteger: - v = vl; - break; - case FcTypeDouble: - v.type = FcTypeInteger; - v.u.i = FcDoubleFloor (vl.u.d); - break; - default: - v.type = FcTypeVoid; - break; - } - FcValueDestroy (vl); - break; - case FcOpCeil: - vl = FcConfigEvaluate (p, e->u.tree.left); - switch (vl.type) { - case FcTypeInteger: - v = vl; - break; - case FcTypeDouble: - v.type = FcTypeInteger; - v.u.i = FcDoubleCeil (vl.u.d); - break; - default: - v.type = FcTypeVoid; - break; - } - FcValueDestroy (vl); - break; - case FcOpRound: - vl = FcConfigEvaluate (p, e->u.tree.left); - switch (vl.type) { - case FcTypeInteger: - v = vl; - break; - case FcTypeDouble: - v.type = FcTypeInteger; - v.u.i = FcDoubleRound (vl.u.d); - break; - default: - v.type = FcTypeVoid; - break; - } - FcValueDestroy (vl); - break; - case FcOpTrunc: - vl = FcConfigEvaluate (p, e->u.tree.left); - switch (vl.type) { - case FcTypeInteger: - v = vl; - break; - case FcTypeDouble: - v.type = FcTypeInteger; - v.u.i = FcDoubleTrunc (vl.u.d); - break; - default: - v.type = FcTypeVoid; - break; - } - FcValueDestroy (vl); - break; - default: - v.type = FcTypeVoid; - break; - } - return v; -} - -static FcValueList * -FcConfigMatchValueList (FcPattern *p, - FcTest *t, - FcValueList *values) -{ - FcValueList *ret = 0; - FcExpr *e = t->expr; - FcValue value; - FcValueList *v; - - while (e) - { - /* Compute the value of the match expression */ - if (e->op == FcOpComma) - { - value = FcConfigEvaluate (p, e->u.tree.left); - e = e->u.tree.right; - } - else - { - value = FcConfigEvaluate (p, e); - e = 0; - } - - for (v = values; v; v = FcValueListNext(v)) - { - /* Compare the pattern value to the match expression value */ - if (FcConfigCompareValue (&v->value, t->op, &value)) - { - if (!ret) - ret = v; - } - else - { - if (t->qual == FcQualAll) - { - ret = 0; - break; - } - } - } - FcValueDestroy (value); - } - return ret; -} - -static FcValueList * -FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding) -{ - FcValueList *l; - - if (!e) - return 0; - l = (FcValueList *) malloc (sizeof (FcValueList)); - if (!l) - return 0; - FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList)); - if (e->op == FcOpComma) - { - l->value = FcConfigEvaluate (p, e->u.tree.left); - l->next = FcConfigValues (p, e->u.tree.right, binding); - } - else - { - l->value = FcConfigEvaluate (p, e); - l->next = NULL; - } - l->binding = binding; - if (l->value.type == FcTypeVoid) - { - FcValueList *next = FcValueListNext(l); - - FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList)); - free (l); - l = next; - } - - return l; -} - -static FcBool -FcConfigAdd (FcValueListPtr *head, - FcValueList *position, - FcBool append, - FcValueList *new) -{ - FcValueListPtr *prev, last, v; - FcValueBinding sameBinding; - - if (position) - sameBinding = position->binding; - else - sameBinding = FcValueBindingWeak; - for (v = new; v != NULL; v = FcValueListNext(v)) - if (v->binding == FcValueBindingSame) - v->binding = sameBinding; - if (append) - { - if (position) - prev = &position->next; - else - for (prev = head; *prev != NULL; - prev = &(*prev)->next) - ; - } - else - { - if (position) - { - for (prev = head; *prev != NULL; - prev = &(*prev)->next) - { - if (*prev == position) - break; - } - } - else - prev = head; - - if (FcDebug () & FC_DBG_EDIT) - { - if (*prev == NULL) - printf ("position not on list\n"); - } - } - - if (FcDebug () & FC_DBG_EDIT) - { - printf ("%s list before ", append ? "Append" : "Prepend"); - FcValueListPrint (*head); - printf ("\n"); - } - - if (new) - { - last = new; - while (last->next != NULL) - last = last->next; - - last->next = *prev; - *prev = new; - } - - if (FcDebug () & FC_DBG_EDIT) - { - printf ("%s list after ", append ? "Append" : "Prepend"); - FcValueListPrint (*head); - printf ("\n"); - } - - return FcTrue; -} - -static void -FcConfigDel (FcValueListPtr *head, - FcValueList *position) -{ - FcValueListPtr *prev; - - for (prev = head; *prev != NULL; prev = &(*prev)->next) - { - if (*prev == position) - { - *prev = position->next; - position->next = NULL; - FcValueListDestroy (position); - break; - } - } -} - -static void -FcConfigPatternAdd (FcPattern *p, - FcObject object, - FcValueList *list, - FcBool append) -{ - if (list) - { - FcPatternElt *e = FcPatternObjectInsertElt (p, object); - - if (!e) - return; - FcConfigAdd (&e->values, 0, append, list); - } -} - -/* - * Delete all values associated with a field - */ -static void -FcConfigPatternDel (FcPattern *p, - FcObject object) -{ - FcPatternElt *e = FcPatternObjectFindElt (p, object); - if (!e) - return; - while (e->values != NULL) - FcConfigDel (&e->values, e->values); -} - -static void -FcConfigPatternCanon (FcPattern *p, - FcObject object) -{ - FcPatternElt *e = FcPatternObjectFindElt (p, object); - if (!e) - return; - if (e->values == NULL) - FcPatternObjectDel (p, object); -} - -FcBool -FcConfigSubstituteWithPat (FcConfig *config, - FcPattern *p, - FcPattern *p_pat, - FcMatchKind kind) -{ - FcSubst *s; - FcSubState *st; - int i; - FcTest *t; - FcEdit *e; - FcValueList *l; - FcPattern *m; - - if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return FcFalse; - } - - switch (kind) { - case FcMatchPattern: - s = config->substPattern; - break; - case FcMatchFont: - s = config->substFont; - break; - case FcMatchScan: - s = config->substScan; - break; - default: - return FcFalse; - } - - st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState)); - if (!st && config->maxObjects) - return FcFalse; - FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState)); - - if (FcDebug () & FC_DBG_EDIT) - { - printf ("FcConfigSubstitute "); - FcPatternPrint (p); - } - for (; s; s = s->next) - { - /* - * Check the tests to see if - * they all match the pattern - */ - for (t = s->test, i = 0; t; t = t->next, i++) - { - if (FcDebug () & FC_DBG_EDIT) - { - printf ("FcConfigSubstitute test "); - FcTestPrint (t); - } - st[i].elt = 0; - if (kind == FcMatchFont && t->kind == FcMatchPattern) - m = p_pat; - else - m = p; - if (m) - st[i].elt = FcPatternObjectFindElt (m, t->object); - else - st[i].elt = 0; - /* - * If there's no such field in the font, - * then FcQualAll matches while FcQualAny does not - */ - if (!st[i].elt) - { - if (t->qual == FcQualAll) - { - st[i].value = 0; - continue; - } - else - break; - } - /* - * Check to see if there is a match, mark the location - * to apply match-relative edits - */ - st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values); - if (!st[i].value) - break; - if (t->qual == FcQualFirst && st[i].value != st[i].elt->values) - break; - if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values) - break; - } - if (t) - { - if (FcDebug () & FC_DBG_EDIT) - printf ("No match\n"); - continue; - } - if (FcDebug () & FC_DBG_EDIT) - { - printf ("Substitute "); - FcSubstPrint (s); - } - for (e = s->edit; e; e = e->next) - { - /* - * Evaluate the list of expressions - */ - l = FcConfigValues (p, e->expr, e->binding); - /* - * Locate any test associated with this field, skipping - * tests associated with the pattern when substituting in - * the font - */ - for (t = s->test, i = 0; t; t = t->next, i++) - { - if ((t->kind == FcMatchFont || kind == FcMatchPattern) && - t->object == e->object) - { - /* - * KLUDGE - the pattern may have been reallocated or - * things may have been inserted or deleted above - * this element by other edits. Go back and find - * the element again - */ - if (e != s->edit && st[i].elt) - st[i].elt = FcPatternObjectFindElt (p, t->object); - if (!st[i].elt) - t = 0; - break; - } - } - switch (e->op) { - case FcOpAssign: - /* - * If there was a test, then replace the matched - * value with the new list of values - */ - if (t) - { - FcValueList *thisValue = st[i].value; - FcValueList *nextValue = thisValue; - - /* - * Append the new list of values after the current value - */ - FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l); - /* - * Delete the marked value - */ - if (thisValue) - FcConfigDel (&st[i].elt->values, thisValue); - /* - * Adjust any pointers into the value list to ensure - * future edits occur at the same place - */ - for (t = s->test, i = 0; t; t = t->next, i++) - { - if (st[i].value == thisValue) - st[i].value = nextValue; - } - break; - } - /* fall through ... */ - case FcOpAssignReplace: - /* - * Delete all of the values and insert - * the new set - */ - FcConfigPatternDel (p, e->object); - FcConfigPatternAdd (p, e->object, l, FcTrue); - /* - * Adjust any pointers into the value list as they no - * longer point to anything valid - */ - if (t) - { - FcPatternElt *thisElt = st[i].elt; - for (t = s->test, i = 0; t; t = t->next, i++) - { - if (st[i].elt == thisElt) - st[i].value = 0; - } - } - break; - case FcOpPrepend: - if (t) - { - FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l); - break; - } - /* fall through ... */ - case FcOpPrependFirst: - FcConfigPatternAdd (p, e->object, l, FcFalse); - break; - case FcOpAppend: - if (t) - { - FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l); - break; - } - /* fall through ... */ - case FcOpAppendLast: - FcConfigPatternAdd (p, e->object, l, FcTrue); - break; - default: - FcValueListDestroy (l); - break; - } - } - /* - * Now go through the pattern and eliminate - * any properties without data - */ - for (e = s->edit; e; e = e->next) - FcConfigPatternCanon (p, e->object); - - if (FcDebug () & FC_DBG_EDIT) - { - printf ("FcConfigSubstitute edit"); - FcPatternPrint (p); - } - } - FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState)); - free (st); - if (FcDebug () & FC_DBG_EDIT) - { - printf ("FcConfigSubstitute done"); - FcPatternPrint (p); - } - return FcTrue; -} - -FcBool -FcConfigSubstitute (FcConfig *config, - FcPattern *p, - FcMatchKind kind) -{ - return FcConfigSubstituteWithPat (config, p, 0, kind); -} - -#if defined (_WIN32) - -# define WIN32_LEAN_AND_MEAN -# define WIN32_EXTRA_LEAN -# include <windows.h> - -static FcChar8 fontconfig_path[1000] = ""; - -# if (defined (PIC) || defined (DLL_EXPORT)) - -BOOL WINAPI -DllMain (HINSTANCE hinstDLL, - DWORD fdwReason, - LPVOID lpvReserved) -{ - FcChar8 *p; - - switch (fdwReason) { - case DLL_PROCESS_ATTACH: - if (!GetModuleFileName ((HMODULE) hinstDLL, fontconfig_path, - sizeof (fontconfig_path))) - break; - - /* If the fontconfig DLL is in a "bin" or "lib" subfolder, - * assume it's a Unix-style installation tree, and use - * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the - * folder where the DLL is as FONTCONFIG_PATH. - */ - p = strrchr (fontconfig_path, '\\'); - if (p) - { - *p = '\0'; - p = strrchr (fontconfig_path, '\\'); - if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 || - FcStrCmpIgnoreCase (p + 1, "lib") == 0)) - *p = '\0'; - strcat (fontconfig_path, "\\etc\\fonts"); - } - else - fontconfig_path[0] = '\0'; - - break; - } - - return TRUE; -} - -# endif /* !PIC */ - -#undef FONTCONFIG_PATH -#define FONTCONFIG_PATH fontconfig_path - -#endif /* !_WIN32 */ - -#ifndef FONTCONFIG_FILE -#define FONTCONFIG_FILE "fonts.conf" -#endif - -static FcChar8 * -FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file) -{ - FcChar8 *path; - - if (!dir) - dir = (FcChar8 *) ""; - path = malloc (strlen ((char *) dir) + 1 + strlen ((char *) file) + 1); - if (!path) - return 0; - - strcpy ((char *) path, (const char *) dir); - /* make sure there's a single separator */ -#ifdef _WIN32 - if ((!path[0] || (path[strlen((char *) path)-1] != '/' && - path[strlen((char *) path)-1] != '\\')) && - !(file[0] == '/' || - file[0] == '\\' || - (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\')))) - strcat ((char *) path, "\\"); -#else - if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/') - strcat ((char *) path, "/"); -#endif - strcat ((char *) path, (char *) file); - - FcMemAlloc (FC_MEM_STRING, strlen ((char *) path) + 1); - if (access ((char *) path, R_OK) == 0) - return path; - - FcStrFree (path); - return 0; -} - -static FcChar8 ** -FcConfigGetPath (void) -{ - FcChar8 **path; - FcChar8 *env, *e, *colon; - FcChar8 *dir; - int npath; - int i; - - npath = 2; /* default dir + null */ - env = (FcChar8 *) getenv ("FONTCONFIG_PATH"); - if (env) - { - e = env; - npath++; - while (*e) - if (*e++ == FC_SEARCH_PATH_SEPARATOR) - npath++; - } - path = calloc (npath, sizeof (FcChar8 *)); - if (!path) - goto bail0; - i = 0; - - if (env) - { - e = env; - while (*e) - { - colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR); - if (!colon) - colon = e + strlen ((char *) e); - path[i] = malloc (colon - e + 1); - if (!path[i]) - goto bail1; - strncpy ((char *) path[i], (const char *) e, colon - e); - path[i][colon - e] = '\0'; - if (*colon) - e = colon + 1; - else - e = colon; - i++; - } - } - -#ifdef _WIN32 - if (fontconfig_path[0] == '\0') - { - char *p; - if(!GetModuleFileName(NULL, fontconfig_path, sizeof(fontconfig_path))) - goto bail1; - p = strrchr (fontconfig_path, '\\'); - if (p) *p = '\0'; - strcat (fontconfig_path, "\\fonts"); - } -#endif - dir = (FcChar8 *) FONTCONFIG_PATH; - path[i] = malloc (strlen ((char *) dir) + 1); - if (!path[i]) - goto bail1; - strcpy ((char *) path[i], (const char *) dir); - return path; - -bail1: - for (i = 0; path[i]; i++) - free (path[i]); - free (path); -bail0: - return 0; -} - -static void -FcConfigFreePath (FcChar8 **path) -{ - FcChar8 **p; - - for (p = path; *p; p++) - free (*p); - free (path); -} - -static FcBool _FcConfigHomeEnabled = FcTrue; - -FcChar8 * -FcConfigHome (void) -{ - if (_FcConfigHomeEnabled) - { - char *home = getenv ("HOME"); - -#ifdef _WIN32 - if (home == NULL) - home = getenv ("USERPROFILE"); -#endif - - return (FcChar8 *) home; - } - return 0; -} - -FcBool -FcConfigEnableHome (FcBool enable) -{ - FcBool prev = _FcConfigHomeEnabled; - _FcConfigHomeEnabled = enable; - return prev; -} - -FcChar8 * -FcConfigFilename (const FcChar8 *url) -{ - FcChar8 *file, *dir, **path, **p; - - if (!url || !*url) - { - url = (FcChar8 *) getenv ("FONTCONFIG_FILE"); - if (!url) - url = (FcChar8 *) FONTCONFIG_FILE; - } - file = 0; - -#ifdef _WIN32 - if (isalpha (*url) && - url[1] == ':' && - (url[2] == '/' || url[2] == '\\')) - goto absolute_path; -#endif - - switch (*url) { - case '~': - dir = FcConfigHome (); - if (dir) - file = FcConfigFileExists (dir, url + 1); - else - file = 0; - break; -#ifdef _WIN32 - case '\\': - absolute_path: -#endif - case '/': - file = FcConfigFileExists (0, url); - break; - default: - path = FcConfigGetPath (); - if (!path) - return 0; - for (p = path; *p; p++) - { - file = FcConfigFileExists (*p, url); - if (file) - break; - } - FcConfigFreePath (path); - break; - } - return file; -} - -/* - * Manage the application-specific fonts - */ - -FcBool -FcConfigAppFontAddFile (FcConfig *config, - const FcChar8 *file) -{ - FcFontSet *set; - FcStrSet *subdirs; - FcStrList *sublist; - FcChar8 *subdir; - - if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return FcFalse; - } - - subdirs = FcStrSetCreate (); - if (!subdirs) - return FcFalse; - - set = FcConfigGetFonts (config, FcSetApplication); - if (!set) - { - set = FcFontSetCreate (); - if (!set) - { - FcStrSetDestroy (subdirs); - return FcFalse; - } - FcConfigSetFonts (config, set, FcSetApplication); - } - - if (!FcFileScanConfig (set, subdirs, config->blanks, file, config)) - { - FcStrSetDestroy (subdirs); - return FcFalse; - } - if ((sublist = FcStrListCreate (subdirs))) - { - while ((subdir = FcStrListNext (sublist))) - { - FcConfigAppFontAddDir (config, subdir); - } - FcStrListDone (sublist); - } - FcStrSetDestroy (subdirs); - return FcTrue; -} - -FcBool -FcConfigAppFontAddDir (FcConfig *config, - const FcChar8 *dir) -{ - FcFontSet *set; - FcStrSet *dirs; - - if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return FcFalse; - } - - dirs = FcStrSetCreate (); - if (!dirs) - return FcFalse; - - set = FcConfigGetFonts (config, FcSetApplication); - if (!set) - { - set = FcFontSetCreate (); - if (!set) - { - FcStrSetDestroy (dirs); - return FcFalse; - } - FcConfigSetFonts (config, set, FcSetApplication); - } - - FcStrSetAddFilename (dirs, dir); - - if (!FcConfigAddDirList (config, FcSetApplication, dirs)) - { - FcStrSetDestroy (dirs); - return FcFalse; - } - FcStrSetDestroy (dirs); - return FcTrue; -} - -void -FcConfigAppFontClear (FcConfig *config) -{ - if (!config) - { - config = FcConfigGetCurrent (); - if (!config) - return; - } - - FcConfigSetFonts (config, 0, FcSetApplication); -} - -/* - * Manage filename-based font source selectors - */ - -FcBool -FcConfigGlobAdd (FcConfig *config, - const FcChar8 *glob, - FcBool accept) -{ - FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs; - - return FcStrSetAdd (set, glob); -} - -static FcBool -FcConfigGlobMatch (const FcChar8 *glob, - const FcChar8 *string) -{ - FcChar8 c; - - while ((c = *glob++)) - { - switch (c) { - case '*': - /* short circuit common case */ - if (!*glob) - return FcTrue; - /* short circuit another common case */ - if (strchr ((char *) glob, '*') == 0) - string += strlen ((char *) string) - strlen ((char *) glob); - while (*string) - { - if (FcConfigGlobMatch (glob, string)) - return FcTrue; - string++; - } - return FcFalse; - case '?': - if (*string++ == '\0') - return FcFalse; - break; - default: - if (*string++ != c) - return FcFalse; - break; - } - } - return *string == '\0'; -} - -static FcBool -FcConfigGlobsMatch (const FcStrSet *globs, - const FcChar8 *string) -{ - int i; - - for (i = 0; i < globs->num; i++) - if (FcConfigGlobMatch (globs->strs[i], string)) - return FcTrue; - return FcFalse; -} - -FcBool -FcConfigAcceptFilename (FcConfig *config, - const FcChar8 *filename) -{ - if (FcConfigGlobsMatch (config->acceptGlobs, filename)) - return FcTrue; - if (FcConfigGlobsMatch (config->rejectGlobs, filename)) - return FcFalse; - return FcTrue; -} - -/* - * Manage font-pattern based font source selectors - */ - -FcBool -FcConfigPatternsAdd (FcConfig *config, - FcPattern *pattern, - FcBool accept) -{ - FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns; - - return FcFontSetAdd (set, pattern); -} - -static FcBool -FcConfigPatternsMatch (const FcFontSet *patterns, - const FcPattern *font) -{ - int i; - - for (i = 0; i < patterns->nfont; i++) - if (FcListPatternMatchAny (patterns->fonts[i], font)) - return FcTrue; - return FcFalse; -} - -FcBool -FcConfigAcceptFont (FcConfig *config, - const FcPattern *font) -{ - if (FcConfigPatternsMatch (config->acceptPatterns, font)) - return FcTrue; - if (FcConfigPatternsMatch (config->rejectPatterns, font)) - return FcFalse; - return FcTrue; -} -#define __fccfg__ -#include "fcaliastail.h" -#undef __fccfg__ +/*
+ * fontconfig/src/fccfg.c
+ *
+ * Copyright © 2000 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the author(s) not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. The authors make no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fcint.h"
+#include <dirent.h>
+#include <sys/types.h>
+
+#if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT))
+#define STRICT
+#include <windows.h>
+#undef STRICT
+#endif
+
+#if defined (_WIN32) && !defined (R_OK)
+#define R_OK 4
+#endif
+
+FcConfig *_fcConfig;
+
+FcConfig *
+FcConfigCreate (void)
+{
+ FcSetName set;
+ FcConfig *config;
+
+ config = malloc (sizeof (FcConfig));
+ if (!config)
+ goto bail0;
+ FcMemAlloc (FC_MEM_CONFIG, sizeof (FcConfig));
+
+ config->configDirs = FcStrSetCreate ();
+ if (!config->configDirs)
+ goto bail1;
+
+ config->configFiles = FcStrSetCreate ();
+ if (!config->configFiles)
+ goto bail2;
+
+ config->fontDirs = FcStrSetCreate ();
+ if (!config->fontDirs)
+ goto bail3;
+
+ config->acceptGlobs = FcStrSetCreate ();
+ if (!config->acceptGlobs)
+ goto bail4;
+
+ config->rejectGlobs = FcStrSetCreate ();
+ if (!config->rejectGlobs)
+ goto bail5;
+
+ config->acceptPatterns = FcFontSetCreate ();
+ if (!config->acceptPatterns)
+ goto bail6;
+
+ config->rejectPatterns = FcFontSetCreate ();
+ if (!config->rejectPatterns)
+ goto bail7;
+
+ config->cacheDirs = FcStrSetCreate ();
+ if (!config->cacheDirs)
+ goto bail8;
+
+ config->blanks = 0;
+
+ config->substPattern = 0;
+ config->substFont = 0;
+ config->substScan = 0;
+ config->maxObjects = 0;
+ for (set = FcSetSystem; set <= FcSetApplication; set++)
+ config->fonts[set] = 0;
+
+ config->rescanTime = time(0);
+ config->rescanInterval = 30;
+
+ config->expr_pool = NULL;
+
+ config->ref = 1;
+
+ return config;
+
+bail8:
+ FcFontSetDestroy (config->rejectPatterns);
+bail7:
+ FcFontSetDestroy (config->acceptPatterns);
+bail6:
+ FcStrSetDestroy (config->rejectGlobs);
+bail5:
+ FcStrSetDestroy (config->acceptGlobs);
+bail4:
+ FcStrSetDestroy (config->fontDirs);
+bail3:
+ FcStrSetDestroy (config->configFiles);
+bail2:
+ FcStrSetDestroy (config->configDirs);
+bail1:
+ free (config);
+ FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
+bail0:
+ return 0;
+}
+
+static FcFileTime
+FcConfigNewestFile (FcStrSet *files)
+{
+ FcStrList *list = FcStrListCreate (files);
+ FcFileTime newest = { 0, FcFalse };
+ FcChar8 *file;
+ struct stat statb;
+
+ if (list)
+ {
+ while ((file = FcStrListNext (list)))
+ if (FcStat (file, &statb) == 0)
+ if (!newest.set || statb.st_mtime - newest.time > 0)
+ {
+ newest.set = FcTrue;
+ newest.time = statb.st_mtime;
+ }
+ FcStrListDone (list);
+ }
+ return newest;
+}
+
+FcBool
+FcConfigUptoDate (FcConfig *config)
+{
+ FcFileTime config_time, config_dir_time, font_time;
+ time_t now = time(0);
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return FcFalse;
+ }
+ config_time = FcConfigNewestFile (config->configFiles);
+ config_dir_time = FcConfigNewestFile (config->configDirs);
+ font_time = FcConfigNewestFile (config->fontDirs);
+ if ((config_time.set && config_time.time - config->rescanTime > 0) ||
+ (config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) ||
+ (font_time.set && (font_time.time - config->rescanTime) > 0))
+ {
+ /* We need to check for potential clock problems here (OLPC ticket #6046) */
+ if ((config_time.set && (config_time.time - now) > 0) ||
+ (config_dir_time.set && (config_dir_time.time - now) > 0) ||
+ (font_time.set && (font_time.time - now) > 0))
+ {
+ fprintf (stderr,
+ "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected\n");
+ config->rescanTime = now;
+ return FcTrue;
+ }
+ else
+ return FcFalse;
+ }
+ config->rescanTime = now;
+ return FcTrue;
+}
+
+static void
+FcSubstDestroy (FcSubst *s)
+{
+ FcSubst *n;
+
+ while (s)
+ {
+ n = s->next;
+ if (s->test)
+ FcTestDestroy (s->test);
+ if (s->edit)
+ FcEditDestroy (s->edit);
+ free (s);
+ FcMemFree (FC_MEM_SUBST, sizeof (FcSubst));
+ s = n;
+ }
+}
+
+FcExpr *
+FcConfigAllocExpr (FcConfig *config)
+{
+ if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end)
+ {
+ FcExprPage *new_page;
+
+ new_page = malloc (sizeof (FcExprPage));
+ if (!new_page)
+ return 0;
+ FcMemAlloc (FC_MEM_EXPR, sizeof (FcExprPage));
+
+ new_page->next_page = config->expr_pool;
+ new_page->next = new_page->exprs;
+ config->expr_pool = new_page;
+ }
+
+ return config->expr_pool->next++;
+}
+
+FcConfig *
+FcConfigReference (FcConfig *config)
+{
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return 0;
+ }
+
+ config->ref++;
+
+ return config;
+}
+
+void
+FcConfigDestroy (FcConfig *config)
+{
+ FcSetName set;
+ FcExprPage *page;
+
+ if (--config->ref > 0)
+ return;
+
+ if (config == _fcConfig)
+ _fcConfig = 0;
+
+ FcStrSetDestroy (config->configDirs);
+ FcStrSetDestroy (config->fontDirs);
+ FcStrSetDestroy (config->cacheDirs);
+ FcStrSetDestroy (config->configFiles);
+ FcStrSetDestroy (config->acceptGlobs);
+ FcStrSetDestroy (config->rejectGlobs);
+ FcFontSetDestroy (config->acceptPatterns);
+ FcFontSetDestroy (config->rejectPatterns);
+
+ if (config->blanks)
+ FcBlanksDestroy (config->blanks);
+
+ FcSubstDestroy (config->substPattern);
+ FcSubstDestroy (config->substFont);
+ FcSubstDestroy (config->substScan);
+ for (set = FcSetSystem; set <= FcSetApplication; set++)
+ if (config->fonts[set])
+ FcFontSetDestroy (config->fonts[set]);
+
+ page = config->expr_pool;
+ while (page)
+ {
+ FcExprPage *next = page->next_page;
+ FcMemFree (FC_MEM_EXPR, sizeof (FcExprPage));
+ free (page);
+ page = next;
+ }
+
+ free (config);
+ FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
+}
+
+/*
+ * Add cache to configuration, adding fonts and directories
+ */
+
+FcBool
+FcConfigAddCache (FcConfig *config, FcCache *cache,
+ FcSetName set, FcStrSet *dirSet)
+{
+ FcFontSet *fs;
+ intptr_t *dirs;
+ int i;
+
+ /*
+ * Add fonts
+ */
+ fs = FcCacheSet (cache);
+ if (fs)
+ {
+ int nref = 0;
+
+ for (i = 0; i < fs->nfont; i++)
+ {
+ FcPattern *font = FcFontSetFont (fs, i);
+ FcChar8 *font_file;
+
+ /*
+ * Check to see if font is banned by filename
+ */
+ if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
+ 0, &font_file) == FcResultMatch &&
+ !FcConfigAcceptFilename (config, font_file))
+ {
+ continue;
+ }
+
+ /*
+ * Check to see if font is banned by pattern
+ */
+ if (!FcConfigAcceptFont (config, font))
+ continue;
+
+ nref++;
+ FcFontSetAdd (config->fonts[set], font);
+ }
+ FcDirCacheReference (cache, nref);
+ }
+
+ /*
+ * Add directories
+ */
+ dirs = FcCacheDirs (cache);
+ if (dirs)
+ {
+ for (i = 0; i < cache->dirs_count; i++)
+ {
+ FcChar8 *dir = FcOffsetToPtr (dirs, dirs[i], FcChar8);
+ if (FcConfigAcceptFilename (config, dir))
+ FcStrSetAddFilename (dirSet, dir);
+ }
+ }
+ return FcTrue;
+}
+
+static FcBool
+FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
+{
+ FcStrList *dirlist;
+ FcChar8 *dir;
+ FcCache *cache;
+
+ dirlist = FcStrListCreate (dirSet);
+ if (!dirlist)
+ return FcFalse;
+
+ while ((dir = FcStrListNext (dirlist)))
+ {
+ if (FcDebug () & FC_DBG_FONTSET)
+ printf ("adding fonts from%s\n", dir);
+ cache = FcDirCacheRead (dir, FcFalse, config);
+ if (!cache)
+ continue;
+ FcConfigAddCache (config, cache, set, dirSet);
+ FcDirCacheUnload (cache);
+ }
+ FcStrListDone (dirlist);
+ return FcTrue;
+}
+
+/*
+ * Scan the current list of directories in the configuration
+ * and build the set of available fonts.
+ */
+
+FcBool
+FcConfigBuildFonts (FcConfig *config)
+{
+ FcFontSet *fonts;
+
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return FcFalse;
+ }
+
+ fonts = FcFontSetCreate ();
+ if (!fonts)
+ return FcFalse;
+
+ FcConfigSetFonts (config, fonts, FcSetSystem);
+
+ if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs))
+ return FcFalse;
+ if (FcDebug () & FC_DBG_FONTSET)
+ FcFontSetPrint (fonts);
+ return FcTrue;
+}
+
+FcBool
+FcConfigSetCurrent (FcConfig *config)
+{
+ if (config == _fcConfig)
+ return FcTrue;
+
+ if (!config->fonts)
+ if (!FcConfigBuildFonts (config))
+ return FcFalse;
+
+ if (_fcConfig)
+ FcConfigDestroy (_fcConfig);
+ _fcConfig = config;
+ return FcTrue;
+}
+
+FcConfig *
+FcConfigGetCurrent (void)
+{
+ if (!_fcConfig)
+ if (!FcInit ())
+ return 0;
+ return _fcConfig;
+}
+
+FcBool
+FcConfigAddConfigDir (FcConfig *config,
+ const FcChar8 *d)
+{
+ return FcStrSetAddFilename (config->configDirs, d);
+}
+
+FcStrList *
+FcConfigGetConfigDirs (FcConfig *config)
+{
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return 0;
+ }
+ return FcStrListCreate (config->configDirs);
+}
+
+FcBool
+FcConfigAddFontDir (FcConfig *config,
+ const FcChar8 *d)
+{
+ return FcStrSetAddFilename (config->fontDirs, d);
+}
+
+FcBool
+FcConfigAddDir (FcConfig *config,
+ const FcChar8 *d)
+{
+ return (FcConfigAddConfigDir (config, d) &&
+ FcConfigAddFontDir (config, d));
+}
+
+FcStrList *
+FcConfigGetFontDirs (FcConfig *config)
+{
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return 0;
+ }
+ return FcStrListCreate (config->fontDirs);
+}
+
+FcBool
+FcConfigAddCacheDir (FcConfig *config,
+ const FcChar8 *d)
+{
+ return FcStrSetAddFilename (config->cacheDirs, d);
+}
+
+FcStrList *
+FcConfigGetCacheDirs (FcConfig *config)
+{
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return 0;
+ }
+ return FcStrListCreate (config->cacheDirs);
+}
+
+FcBool
+FcConfigAddConfigFile (FcConfig *config,
+ const FcChar8 *f)
+{
+ FcBool ret;
+ FcChar8 *file = FcConfigFilename (f);
+
+ if (!file)
+ return FcFalse;
+
+ ret = FcStrSetAdd (config->configFiles, file);
+ FcStrFree (file);
+ return ret;
+}
+
+FcStrList *
+FcConfigGetConfigFiles (FcConfig *config)
+{
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return 0;
+ }
+ return FcStrListCreate (config->configFiles);
+}
+
+FcChar8 *
+FcConfigGetCache (FcConfig *config)
+{
+ return NULL;
+}
+
+FcFontSet *
+FcConfigGetFonts (FcConfig *config,
+ FcSetName set)
+{
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return 0;
+ }
+ return config->fonts[set];
+}
+
+void
+FcConfigSetFonts (FcConfig *config,
+ FcFontSet *fonts,
+ FcSetName set)
+{
+ if (config->fonts[set])
+ FcFontSetDestroy (config->fonts[set]);
+ config->fonts[set] = fonts;
+}
+
+FcBlanks *
+FcConfigGetBlanks (FcConfig *config)
+{
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return 0;
+ }
+ return config->blanks;
+}
+
+FcBool
+FcConfigAddBlank (FcConfig *config,
+ FcChar32 blank)
+{
+ FcBlanks *b, *freeme = 0;
+
+ b = config->blanks;
+ if (!b)
+ {
+ freeme = b = FcBlanksCreate ();
+ if (!b)
+ return FcFalse;
+ }
+ if (!FcBlanksAdd (b, blank))
+ {
+ if (freeme)
+ FcBlanksDestroy (freeme);
+ return FcFalse;
+ }
+ config->blanks = b;
+ return FcTrue;
+}
+
+int
+FcConfigGetRescanInterval (FcConfig *config)
+{
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return 0;
+ }
+ return config->rescanInterval;
+}
+
+FcBool
+FcConfigSetRescanInterval (FcConfig *config, int rescanInterval)
+{
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return FcFalse;
+ }
+ config->rescanInterval = rescanInterval;
+ return FcTrue;
+}
+
+/*
+ * A couple of typos escaped into the library
+ */
+int
+FcConfigGetRescanInverval (FcConfig *config)
+{
+ return FcConfigGetRescanInterval (config);
+}
+
+FcBool
+FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
+{
+ return FcConfigSetRescanInterval (config, rescanInterval);
+}
+
+
+FcBool
+FcConfigAddEdit (FcConfig *config,
+ FcTest *test,
+ FcEdit *edit,
+ FcMatchKind kind)
+{
+ FcSubst *subst, **prev;
+ FcTest *t;
+ int num;
+
+ switch (kind) {
+ case FcMatchPattern:
+ prev = &config->substPattern;
+ break;
+ case FcMatchFont:
+ prev = &config->substFont;
+ break;
+ case FcMatchScan:
+ prev = &config->substScan;
+ break;
+ default:
+ return FcFalse;
+ }
+ subst = (FcSubst *) malloc (sizeof (FcSubst));
+ if (!subst)
+ return FcFalse;
+ FcMemAlloc (FC_MEM_SUBST, sizeof (FcSubst));
+ for (; *prev; prev = &(*prev)->next);
+ *prev = subst;
+ subst->next = 0;
+ subst->test = test;
+ subst->edit = edit;
+ num = 0;
+ for (t = test; t; t = t->next)
+ {
+ if (t->kind == FcMatchDefault)
+ t->kind = kind;
+ num++;
+ }
+ if (config->maxObjects < num)
+ config->maxObjects = num;
+ if (FcDebug () & FC_DBG_EDIT)
+ {
+ printf ("Add Subst ");
+ FcSubstPrint (subst);
+ }
+ return FcTrue;
+}
+
+typedef struct _FcSubState {
+ FcPatternElt *elt;
+ FcValueList *value;
+} FcSubState;
+
+static FcValue
+FcConfigPromote (FcValue v, FcValue u)
+{
+ if (v.type == FcTypeInteger)
+ {
+ v.type = FcTypeDouble;
+ v.u.d = (double) v.u.i;
+ }
+ else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
+ {
+ v.u.m = &FcIdentityMatrix;
+ v.type = FcTypeMatrix;
+ }
+ else if (v.type == FcTypeString && u.type == FcTypeLangSet)
+ {
+ v.u.l = FcLangSetPromote (v.u.s);
+ v.type = FcTypeLangSet;
+ }
+ return v;
+}
+
+FcBool
+FcConfigCompareValue (const FcValue *left_o,
+ FcOp op,
+ const FcValue *right_o)
+{
+ FcValue left = FcValueCanonicalize(left_o);
+ FcValue right = FcValueCanonicalize(right_o);
+ FcBool ret = FcFalse;
+
+ left = FcConfigPromote (left, right);
+ right = FcConfigPromote (right, left);
+ if (left.type == right.type)
+ {
+ switch (left.type) {
+ case FcTypeInteger:
+ break; /* FcConfigPromote prevents this from happening */
+ case FcTypeDouble:
+ switch (op) {
+ case FcOpEqual:
+ case FcOpContains:
+ case FcOpListing:
+ ret = left.u.d == right.u.d;
+ break;
+ case FcOpNotEqual:
+ case FcOpNotContains:
+ ret = left.u.d != right.u.d;
+ break;
+ case FcOpLess:
+ ret = left.u.d < right.u.d;
+ break;
+ case FcOpLessEqual:
+ ret = left.u.d <= right.u.d;
+ break;
+ case FcOpMore:
+ ret = left.u.d > right.u.d;
+ break;
+ case FcOpMoreEqual:
+ ret = left.u.d >= right.u.d;
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeBool:
+ switch (op) {
+ case FcOpEqual:
+ case FcOpContains:
+ case FcOpListing:
+ ret = left.u.b == right.u.b;
+ break;
+ case FcOpNotEqual:
+ case FcOpNotContains:
+ ret = left.u.b != right.u.b;
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeString:
+ switch (op) {
+ case FcOpEqual:
+ case FcOpListing:
+ ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
+ break;
+ case FcOpContains:
+ ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
+ break;
+ case FcOpNotEqual:
+ ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
+ break;
+ case FcOpNotContains:
+ ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeMatrix:
+ switch (op) {
+ case FcOpEqual:
+ case FcOpContains:
+ case FcOpListing:
+ ret = FcMatrixEqual (left.u.m, right.u.m);
+ break;
+ case FcOpNotEqual:
+ case FcOpNotContains:
+ ret = !FcMatrixEqual (left.u.m, right.u.m);
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeCharSet:
+ switch (op) {
+ case FcOpContains:
+ case FcOpListing:
+ /* left contains right if right is a subset of left */
+ ret = FcCharSetIsSubset (right.u.c, left.u.c);
+ break;
+ case FcOpNotContains:
+ /* left contains right if right is a subset of left */
+ ret = !FcCharSetIsSubset (right.u.c, left.u.c);
+ break;
+ case FcOpEqual:
+ ret = FcCharSetEqual (left.u.c, right.u.c);
+ break;
+ case FcOpNotEqual:
+ ret = !FcCharSetEqual (left.u.c, right.u.c);
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeLangSet:
+ switch (op) {
+ case FcOpContains:
+ case FcOpListing:
+ ret = FcLangSetContains (left.u.l, right.u.l);
+ break;
+ case FcOpNotContains:
+ ret = !FcLangSetContains (left.u.l, right.u.l);
+ break;
+ case FcOpEqual:
+ ret = FcLangSetEqual (left.u.l, right.u.l);
+ break;
+ case FcOpNotEqual:
+ ret = !FcLangSetEqual (left.u.l, right.u.l);
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeVoid:
+ switch (op) {
+ case FcOpEqual:
+ case FcOpContains:
+ case FcOpListing:
+ ret = FcTrue;
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeFTFace:
+ switch (op) {
+ case FcOpEqual:
+ case FcOpContains:
+ case FcOpListing:
+ ret = left.u.f == right.u.f;
+ break;
+ case FcOpNotEqual:
+ case FcOpNotContains:
+ ret = left.u.f != right.u.f;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+ else
+ {
+ if (op == FcOpNotEqual || op == FcOpNotContains)
+ ret = FcTrue;
+ }
+ return ret;
+}
+
+
+#define _FcDoubleFloor(d) ((int) (d))
+#define _FcDoubleCeil(d) ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
+#define FcDoubleFloor(d) ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
+#define FcDoubleCeil(d) ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
+#define FcDoubleRound(d) FcDoubleFloor ((d) + 0.5)
+#define FcDoubleTrunc(d) ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
+
+static FcValue
+FcConfigEvaluate (FcPattern *p, FcExpr *e)
+{
+ FcValue v, vl, vr;
+ FcResult r;
+ FcMatrix *m;
+ FcChar8 *str;
+
+ switch (e->op) {
+ case FcOpInteger:
+ v.type = FcTypeInteger;
+ v.u.i = e->u.ival;
+ break;
+ case FcOpDouble:
+ v.type = FcTypeDouble;
+ v.u.d = e->u.dval;
+ break;
+ case FcOpString:
+ v.type = FcTypeString;
+ v.u.s = e->u.sval;
+ v = FcValueSave (v);
+ break;
+ case FcOpMatrix:
+ v.type = FcTypeMatrix;
+ v.u.m = e->u.mval;
+ v = FcValueSave (v);
+ break;
+ case FcOpCharSet:
+ v.type = FcTypeCharSet;
+ v.u.c = e->u.cval;
+ v = FcValueSave (v);
+ break;
+ case FcOpLangSet:
+ v.type = FcTypeLangSet;
+ v.u.l = e->u.lval;
+ v = FcValueSave (v);
+ break;
+ case FcOpBool:
+ v.type = FcTypeBool;
+ v.u.b = e->u.bval;
+ break;
+ case FcOpField:
+ r = FcPatternObjectGet (p, e->u.object, 0, &v);
+ if (r != FcResultMatch)
+ v.type = FcTypeVoid;
+ v = FcValueSave (v);
+ break;
+ case FcOpConst:
+ if (FcNameConstant (e->u.constant, &v.u.i))
+ v.type = FcTypeInteger;
+ else
+ v.type = FcTypeVoid;
+ break;
+ case FcOpQuest:
+ vl = FcConfigEvaluate (p, e->u.tree.left);
+ if (vl.type == FcTypeBool)
+ {
+ if (vl.u.b)
+ v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
+ else
+ v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
+ }
+ else
+ v.type = FcTypeVoid;
+ FcValueDestroy (vl);
+ break;
+ case FcOpEqual:
+ case FcOpNotEqual:
+ case FcOpLess:
+ case FcOpLessEqual:
+ case FcOpMore:
+ case FcOpMoreEqual:
+ case FcOpContains:
+ case FcOpNotContains:
+ case FcOpListing:
+ vl = FcConfigEvaluate (p, e->u.tree.left);
+ vr = FcConfigEvaluate (p, e->u.tree.right);
+ v.type = FcTypeBool;
+ v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
+ FcValueDestroy (vl);
+ FcValueDestroy (vr);
+ break;
+ case FcOpOr:
+ case FcOpAnd:
+ case FcOpPlus:
+ case FcOpMinus:
+ case FcOpTimes:
+ case FcOpDivide:
+ vl = FcConfigEvaluate (p, e->u.tree.left);
+ vr = FcConfigEvaluate (p, e->u.tree.right);
+ vl = FcConfigPromote (vl, vr);
+ vr = FcConfigPromote (vr, vl);
+ if (vl.type == vr.type)
+ {
+ switch (vl.type) {
+ case FcTypeDouble:
+ switch (e->op) {
+ case FcOpPlus:
+ v.type = FcTypeDouble;
+ v.u.d = vl.u.d + vr.u.d;
+ break;
+ case FcOpMinus:
+ v.type = FcTypeDouble;
+ v.u.d = vl.u.d - vr.u.d;
+ break;
+ case FcOpTimes:
+ v.type = FcTypeDouble;
+ v.u.d = vl.u.d * vr.u.d;
+ break;
+ case FcOpDivide:
+ v.type = FcTypeDouble;
+ v.u.d = vl.u.d / vr.u.d;
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ if (v.type == FcTypeDouble &&
+ v.u.d == (double) (int) v.u.d)
+ {
+ v.type = FcTypeInteger;
+ v.u.i = (int) v.u.d;
+ }
+ break;
+ case FcTypeBool:
+ switch (e->op) {
+ case FcOpOr:
+ v.type = FcTypeBool;
+ v.u.b = vl.u.b || vr.u.b;
+ break;
+ case FcOpAnd:
+ v.type = FcTypeBool;
+ v.u.b = vl.u.b && vr.u.b;
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ break;
+ case FcTypeString:
+ switch (e->op) {
+ case FcOpPlus:
+ v.type = FcTypeString;
+ str = FcStrPlus (vl.u.s, vr.u.s);
+ v.u.s = FcStrStaticName (str);
+ FcStrFree (str);
+
+ if (!v.u.s)
+ v.type = FcTypeVoid;
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ break;
+ case FcTypeMatrix:
+ switch (e->op) {
+ case FcOpTimes:
+ v.type = FcTypeMatrix;
+ m = malloc (sizeof (FcMatrix));
+ if (m)
+ {
+ FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
+ FcMatrixMultiply (m, vl.u.m, vr.u.m);
+ v.u.m = m;
+ }
+ else
+ {
+ v.type = FcTypeVoid;
+ }
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ break;
+ case FcTypeCharSet:
+ switch (e->op) {
+ case FcOpPlus:
+ v.type = FcTypeCharSet;
+ v.u.c = FcCharSetUnion (vl.u.c, vr.u.c);
+ if (!v.u.c)
+ v.type = FcTypeVoid;
+ break;
+ case FcOpMinus:
+ v.type = FcTypeCharSet;
+ v.u.c = FcCharSetSubtract (vl.u.c, vr.u.c);
+ if (!v.u.c)
+ v.type = FcTypeVoid;
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ break;
+ case FcTypeLangSet:
+ switch (e->op) {
+ case FcOpPlus:
+ v.type = FcTypeLangSet;
+ v.u.l = FcLangSetUnion (vl.u.l, vr.u.l);
+ if (!v.u.l)
+ v.type = FcTypeVoid;
+ break;
+ case FcOpMinus:
+ v.type = FcTypeLangSet;
+ v.u.l = FcLangSetSubtract (vl.u.l, vr.u.l);
+ if (!v.u.l)
+ v.type = FcTypeVoid;
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ }
+ else
+ v.type = FcTypeVoid;
+ FcValueDestroy (vl);
+ FcValueDestroy (vr);
+ break;
+ case FcOpNot:
+ vl = FcConfigEvaluate (p, e->u.tree.left);
+ switch (vl.type) {
+ case FcTypeBool:
+ v.type = FcTypeBool;
+ v.u.b = !vl.u.b;
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ FcValueDestroy (vl);
+ break;
+ case FcOpFloor:
+ vl = FcConfigEvaluate (p, e->u.tree.left);
+ switch (vl.type) {
+ case FcTypeInteger:
+ v = vl;
+ break;
+ case FcTypeDouble:
+ v.type = FcTypeInteger;
+ v.u.i = FcDoubleFloor (vl.u.d);
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ FcValueDestroy (vl);
+ break;
+ case FcOpCeil:
+ vl = FcConfigEvaluate (p, e->u.tree.left);
+ switch (vl.type) {
+ case FcTypeInteger:
+ v = vl;
+ break;
+ case FcTypeDouble:
+ v.type = FcTypeInteger;
+ v.u.i = FcDoubleCeil (vl.u.d);
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ FcValueDestroy (vl);
+ break;
+ case FcOpRound:
+ vl = FcConfigEvaluate (p, e->u.tree.left);
+ switch (vl.type) {
+ case FcTypeInteger:
+ v = vl;
+ break;
+ case FcTypeDouble:
+ v.type = FcTypeInteger;
+ v.u.i = FcDoubleRound (vl.u.d);
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ FcValueDestroy (vl);
+ break;
+ case FcOpTrunc:
+ vl = FcConfigEvaluate (p, e->u.tree.left);
+ switch (vl.type) {
+ case FcTypeInteger:
+ v = vl;
+ break;
+ case FcTypeDouble:
+ v.type = FcTypeInteger;
+ v.u.i = FcDoubleTrunc (vl.u.d);
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ FcValueDestroy (vl);
+ break;
+ default:
+ v.type = FcTypeVoid;
+ break;
+ }
+ return v;
+}
+
+static FcValueList *
+FcConfigMatchValueList (FcPattern *p,
+ FcTest *t,
+ FcValueList *values)
+{
+ FcValueList *ret = 0;
+ FcExpr *e = t->expr;
+ FcValue value;
+ FcValueList *v;
+
+ while (e)
+ {
+ /* Compute the value of the match expression */
+ if (e->op == FcOpComma)
+ {
+ value = FcConfigEvaluate (p, e->u.tree.left);
+ e = e->u.tree.right;
+ }
+ else
+ {
+ value = FcConfigEvaluate (p, e);
+ e = 0;
+ }
+
+ for (v = values; v; v = FcValueListNext(v))
+ {
+ /* Compare the pattern value to the match expression value */
+ if (FcConfigCompareValue (&v->value, t->op, &value))
+ {
+ if (!ret)
+ ret = v;
+ }
+ else
+ {
+ if (t->qual == FcQualAll)
+ {
+ ret = 0;
+ break;
+ }
+ }
+ }
+ FcValueDestroy (value);
+ }
+ return ret;
+}
+
+static FcValueList *
+FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding)
+{
+ FcValueList *l;
+
+ if (!e)
+ return 0;
+ l = (FcValueList *) malloc (sizeof (FcValueList));
+ if (!l)
+ return 0;
+ FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
+ if (e->op == FcOpComma)
+ {
+ l->value = FcConfigEvaluate (p, e->u.tree.left);
+ l->next = FcConfigValues (p, e->u.tree.right, binding);
+ }
+ else
+ {
+ l->value = FcConfigEvaluate (p, e);
+ l->next = NULL;
+ }
+ l->binding = binding;
+ if (l->value.type == FcTypeVoid)
+ {
+ FcValueList *next = FcValueListNext(l);
+
+ FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
+ free (l);
+ l = next;
+ }
+
+ return l;
+}
+
+static FcBool
+FcConfigAdd (FcValueListPtr *head,
+ FcValueList *position,
+ FcBool append,
+ FcValueList *new)
+{
+ FcValueListPtr *prev, last, v;
+ FcValueBinding sameBinding;
+
+ if (position)
+ sameBinding = position->binding;
+ else
+ sameBinding = FcValueBindingWeak;
+ for (v = new; v != NULL; v = FcValueListNext(v))
+ if (v->binding == FcValueBindingSame)
+ v->binding = sameBinding;
+ if (append)
+ {
+ if (position)
+ prev = &position->next;
+ else
+ for (prev = head; *prev != NULL;
+ prev = &(*prev)->next)
+ ;
+ }
+ else
+ {
+ if (position)
+ {
+ for (prev = head; *prev != NULL;
+ prev = &(*prev)->next)
+ {
+ if (*prev == position)
+ break;
+ }
+ }
+ else
+ prev = head;
+
+ if (FcDebug () & FC_DBG_EDIT)
+ {
+ if (*prev == NULL)
+ printf ("position not on list\n");
+ }
+ }
+
+ if (FcDebug () & FC_DBG_EDIT)
+ {
+ printf ("%s list before ", append ? "Append" : "Prepend");
+ FcValueListPrint (*head);
+ printf ("\n");
+ }
+
+ if (new)
+ {
+ last = new;
+ while (last->next != NULL)
+ last = last->next;
+
+ last->next = *prev;
+ *prev = new;
+ }
+
+ if (FcDebug () & FC_DBG_EDIT)
+ {
+ printf ("%s list after ", append ? "Append" : "Prepend");
+ FcValueListPrint (*head);
+ printf ("\n");
+ }
+
+ return FcTrue;
+}
+
+static void
+FcConfigDel (FcValueListPtr *head,
+ FcValueList *position)
+{
+ FcValueListPtr *prev;
+
+ for (prev = head; *prev != NULL; prev = &(*prev)->next)
+ {
+ if (*prev == position)
+ {
+ *prev = position->next;
+ position->next = NULL;
+ FcValueListDestroy (position);
+ break;
+ }
+ }
+}
+
+static void
+FcConfigPatternAdd (FcPattern *p,
+ FcObject object,
+ FcValueList *list,
+ FcBool append)
+{
+ if (list)
+ {
+ FcPatternElt *e = FcPatternObjectInsertElt (p, object);
+
+ if (!e)
+ return;
+ FcConfigAdd (&e->values, 0, append, list);
+ }
+}
+
+/*
+ * Delete all values associated with a field
+ */
+static void
+FcConfigPatternDel (FcPattern *p,
+ FcObject object)
+{
+ FcPatternElt *e = FcPatternObjectFindElt (p, object);
+ if (!e)
+ return;
+ while (e->values != NULL)
+ FcConfigDel (&e->values, e->values);
+}
+
+static void
+FcConfigPatternCanon (FcPattern *p,
+ FcObject object)
+{
+ FcPatternElt *e = FcPatternObjectFindElt (p, object);
+ if (!e)
+ return;
+ if (e->values == NULL)
+ FcPatternObjectDel (p, object);
+}
+
+FcBool
+FcConfigSubstituteWithPat (FcConfig *config,
+ FcPattern *p,
+ FcPattern *p_pat,
+ FcMatchKind kind)
+{
+ FcSubst *s;
+ FcSubState *st;
+ int i;
+ FcTest *t;
+ FcEdit *e;
+ FcValueList *l;
+ FcPattern *m;
+
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return FcFalse;
+ }
+
+ switch (kind) {
+ case FcMatchPattern:
+ s = config->substPattern;
+ break;
+ case FcMatchFont:
+ s = config->substFont;
+ break;
+ case FcMatchScan:
+ s = config->substScan;
+ break;
+ default:
+ return FcFalse;
+ }
+
+ st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
+ if (!st && config->maxObjects)
+ return FcFalse;
+ FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
+
+ if (FcDebug () & FC_DBG_EDIT)
+ {
+ printf ("FcConfigSubstitute ");
+ FcPatternPrint (p);
+ }
+ for (; s; s = s->next)
+ {
+ /*
+ * Check the tests to see if
+ * they all match the pattern
+ */
+ for (t = s->test, i = 0; t; t = t->next, i++)
+ {
+ if (FcDebug () & FC_DBG_EDIT)
+ {
+ printf ("FcConfigSubstitute test ");
+ FcTestPrint (t);
+ }
+ st[i].elt = 0;
+ if (kind == FcMatchFont && t->kind == FcMatchPattern)
+ m = p_pat;
+ else
+ m = p;
+ if (m)
+ st[i].elt = FcPatternObjectFindElt (m, t->object);
+ else
+ st[i].elt = 0;
+ /*
+ * If there's no such field in the font,
+ * then FcQualAll matches while FcQualAny does not
+ */
+ if (!st[i].elt)
+ {
+ if (t->qual == FcQualAll)
+ {
+ st[i].value = 0;
+ continue;
+ }
+ else
+ break;
+ }
+ /*
+ * Check to see if there is a match, mark the location
+ * to apply match-relative edits
+ */
+ st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values);
+ if (!st[i].value)
+ break;
+ if (t->qual == FcQualFirst && st[i].value != st[i].elt->values)
+ break;
+ if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values)
+ break;
+ }
+ if (t)
+ {
+ if (FcDebug () & FC_DBG_EDIT)
+ printf ("No match\n");
+ continue;
+ }
+ if (FcDebug () & FC_DBG_EDIT)
+ {
+ printf ("Substitute ");
+ FcSubstPrint (s);
+ }
+ for (e = s->edit; e; e = e->next)
+ {
+ /*
+ * Evaluate the list of expressions
+ */
+ l = FcConfigValues (p, e->expr, e->binding);
+ /*
+ * Locate any test associated with this field, skipping
+ * tests associated with the pattern when substituting in
+ * the font
+ */
+ for (t = s->test, i = 0; t; t = t->next, i++)
+ {
+ if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
+ t->object == e->object)
+ {
+ /*
+ * KLUDGE - the pattern may have been reallocated or
+ * things may have been inserted or deleted above
+ * this element by other edits. Go back and find
+ * the element again
+ */
+ if (e != s->edit && st[i].elt)
+ st[i].elt = FcPatternObjectFindElt (p, t->object);
+ if (!st[i].elt)
+ t = 0;
+ break;
+ }
+ }
+ switch (e->op) {
+ case FcOpAssign:
+ /*
+ * If there was a test, then replace the matched
+ * value with the new list of values
+ */
+ if (t)
+ {
+ FcValueList *thisValue = st[i].value;
+ FcValueList *nextValue = thisValue;
+
+ /*
+ * Append the new list of values after the current value
+ */
+ FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
+ /*
+ * Delete the marked value
+ */
+ if (thisValue)
+ FcConfigDel (&st[i].elt->values, thisValue);
+ /*
+ * Adjust any pointers into the value list to ensure
+ * future edits occur at the same place
+ */
+ for (t = s->test, i = 0; t; t = t->next, i++)
+ {
+ if (st[i].value == thisValue)
+ st[i].value = nextValue;
+ }
+ break;
+ }
+ /* fall through ... */
+ case FcOpAssignReplace:
+ /*
+ * Delete all of the values and insert
+ * the new set
+ */
+ FcConfigPatternDel (p, e->object);
+ FcConfigPatternAdd (p, e->object, l, FcTrue);
+ /*
+ * Adjust any pointers into the value list as they no
+ * longer point to anything valid
+ */
+ if (t)
+ {
+ FcPatternElt *thisElt = st[i].elt;
+ for (t = s->test, i = 0; t; t = t->next, i++)
+ {
+ if (st[i].elt == thisElt)
+ st[i].value = 0;
+ }
+ }
+ break;
+ case FcOpPrepend:
+ if (t)
+ {
+ FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
+ break;
+ }
+ /* fall through ... */
+ case FcOpPrependFirst:
+ FcConfigPatternAdd (p, e->object, l, FcFalse);
+ break;
+ case FcOpAppend:
+ if (t)
+ {
+ FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
+ break;
+ }
+ /* fall through ... */
+ case FcOpAppendLast:
+ FcConfigPatternAdd (p, e->object, l, FcTrue);
+ break;
+ default:
+ FcValueListDestroy (l);
+ break;
+ }
+ }
+ /*
+ * Now go through the pattern and eliminate
+ * any properties without data
+ */
+ for (e = s->edit; e; e = e->next)
+ FcConfigPatternCanon (p, e->object);
+
+ if (FcDebug () & FC_DBG_EDIT)
+ {
+ printf ("FcConfigSubstitute edit");
+ FcPatternPrint (p);
+ }
+ }
+ FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
+ free (st);
+ if (FcDebug () & FC_DBG_EDIT)
+ {
+ printf ("FcConfigSubstitute done");
+ FcPatternPrint (p);
+ }
+ return FcTrue;
+}
+
+FcBool
+FcConfigSubstitute (FcConfig *config,
+ FcPattern *p,
+ FcMatchKind kind)
+{
+ return FcConfigSubstituteWithPat (config, p, 0, kind);
+}
+
+#if defined (_WIN32)
+
+# define WIN32_LEAN_AND_MEAN
+# define WIN32_EXTRA_LEAN
+# include <windows.h>
+
+static FcChar8 fontconfig_path[1000] = "";
+
+# if (defined (PIC) || defined (DLL_EXPORT))
+
+BOOL WINAPI
+DllMain (HINSTANCE hinstDLL,
+ DWORD fdwReason,
+ LPVOID lpvReserved)
+{
+ FcChar8 *p;
+
+ switch (fdwReason) {
+ case DLL_PROCESS_ATTACH:
+ if (!GetModuleFileName ((HMODULE) hinstDLL, fontconfig_path,
+ sizeof (fontconfig_path)))
+ break;
+
+ /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
+ * assume it's a Unix-style installation tree, and use
+ * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
+ * folder where the DLL is as FONTCONFIG_PATH.
+ */
+ p = strrchr (fontconfig_path, '\\');
+ if (p)
+ {
+ *p = '\0';
+ p = strrchr (fontconfig_path, '\\');
+ if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 ||
+ FcStrCmpIgnoreCase (p + 1, "lib") == 0))
+ *p = '\0';
+ strcat (fontconfig_path, "\\etc\\fonts");
+ }
+ else
+ fontconfig_path[0] = '\0';
+
+ break;
+ }
+
+ return TRUE;
+}
+
+# endif /* !PIC */
+
+#undef FONTCONFIG_PATH
+#define FONTCONFIG_PATH fontconfig_path
+
+#endif /* !_WIN32 */
+
+#ifndef FONTCONFIG_FILE
+#define FONTCONFIG_FILE "fonts.conf"
+#endif
+
+static FcChar8 *
+FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
+{
+ FcChar8 *path;
+
+ if (!dir)
+ dir = (FcChar8 *) "";
+ path = malloc (strlen ((char *) dir) + 1 + strlen ((char *) file) + 1);
+ if (!path)
+ return 0;
+
+ strcpy ((char *) path, (const char *) dir);
+ /* make sure there's a single separator */
+#ifdef _WIN32
+ if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
+ path[strlen((char *) path)-1] != '\\')) &&
+ !(file[0] == '/' ||
+ file[0] == '\\' ||
+ (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
+ strcat ((char *) path, "\\");
+#else
+ if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
+ strcat ((char *) path, "/");
+#endif
+ strcat ((char *) path, (char *) file);
+
+ FcMemAlloc (FC_MEM_STRING, strlen ((char *) path) + 1);
+ if (access ((char *) path, R_OK) == 0)
+ return path;
+
+ FcStrFree (path);
+ return 0;
+}
+
+static FcChar8 **
+FcConfigGetPath (void)
+{
+ FcChar8 **path;
+ FcChar8 *env, *e, *colon;
+ FcChar8 *dir;
+ int npath;
+ int i;
+
+ npath = 2; /* default dir + null */
+ env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
+ if (env)
+ {
+ e = env;
+ npath++;
+ while (*e)
+ if (*e++ == FC_SEARCH_PATH_SEPARATOR)
+ npath++;
+ }
+ path = calloc (npath, sizeof (FcChar8 *));
+ if (!path)
+ goto bail0;
+ i = 0;
+
+ if (env)
+ {
+ e = env;
+ while (*e)
+ {
+ colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
+ if (!colon)
+ colon = e + strlen ((char *) e);
+ path[i] = malloc (colon - e + 1);
+ if (!path[i])
+ goto bail1;
+ strncpy ((char *) path[i], (const char *) e, colon - e);
+ path[i][colon - e] = '\0';
+ if (*colon)
+ e = colon + 1;
+ else
+ e = colon;
+ i++;
+ }
+ }
+
+#ifdef _WIN32
+ if (fontconfig_path[0] == '\0')
+ {
+ char *p;
+ if(!GetModuleFileName(NULL, fontconfig_path, sizeof(fontconfig_path)))
+ goto bail1;
+ p = strrchr (fontconfig_path, '\\');
+ if (p) *p = '\0';
+ strcat (fontconfig_path, "\\fonts");
+ }
+#endif
+ dir = (FcChar8 *) FONTCONFIG_PATH;
+ path[i] = malloc (strlen ((char *) dir) + 1);
+ if (!path[i])
+ goto bail1;
+ strcpy ((char *) path[i], (const char *) dir);
+ return path;
+
+bail1:
+ for (i = 0; path[i]; i++)
+ free (path[i]);
+ free (path);
+bail0:
+ return 0;
+}
+
+static void
+FcConfigFreePath (FcChar8 **path)
+{
+ FcChar8 **p;
+
+ for (p = path; *p; p++)
+ free (*p);
+ free (path);
+}
+
+static FcBool _FcConfigHomeEnabled = FcTrue;
+
+FcChar8 *
+FcConfigHome (void)
+{
+ if (_FcConfigHomeEnabled)
+ {
+ char *home = getenv ("HOME");
+
+#ifdef _WIN32
+ if (home == NULL)
+ home = getenv ("USERPROFILE");
+#endif
+
+ return (FcChar8 *) home;
+ }
+ return 0;
+}
+
+FcBool
+FcConfigEnableHome (FcBool enable)
+{
+ FcBool prev = _FcConfigHomeEnabled;
+ _FcConfigHomeEnabled = enable;
+ return prev;
+}
+
+FcChar8 *
+FcConfigFilename (const FcChar8 *url)
+{
+ FcChar8 *file, *dir, **path, **p;
+
+ if (!url || !*url)
+ {
+ url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
+ if (!url)
+ url = (FcChar8 *) FONTCONFIG_FILE;
+ }
+ file = 0;
+
+#ifdef _WIN32
+ if (isalpha (*url) &&
+ url[1] == ':' &&
+ (url[2] == '/' || url[2] == '\\'))
+ goto absolute_path;
+#endif
+
+ switch (*url) {
+ case '~':
+ dir = FcConfigHome ();
+ if (dir)
+ file = FcConfigFileExists (dir, url + 1);
+ else
+ file = 0;
+ break;
+#ifdef _WIN32
+ case '\\':
+ absolute_path:
+#endif
+ case '/':
+ file = FcConfigFileExists (0, url);
+ break;
+ default:
+ path = FcConfigGetPath ();
+ if (!path)
+ return 0;
+ for (p = path; *p; p++)
+ {
+ file = FcConfigFileExists (*p, url);
+ if (file)
+ break;
+ }
+ FcConfigFreePath (path);
+ break;
+ }
+ return file;
+}
+
+/*
+ * Manage the application-specific fonts
+ */
+
+FcBool
+FcConfigAppFontAddFile (FcConfig *config,
+ const FcChar8 *file)
+{
+ FcFontSet *set;
+ FcStrSet *subdirs;
+ FcStrList *sublist;
+ FcChar8 *subdir;
+
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return FcFalse;
+ }
+
+ subdirs = FcStrSetCreate ();
+ if (!subdirs)
+ return FcFalse;
+
+ set = FcConfigGetFonts (config, FcSetApplication);
+ if (!set)
+ {
+ set = FcFontSetCreate ();
+ if (!set)
+ {
+ FcStrSetDestroy (subdirs);
+ return FcFalse;
+ }
+ FcConfigSetFonts (config, set, FcSetApplication);
+ }
+
+ if (!FcFileScanConfig (set, subdirs, config->blanks, file, config))
+ {
+ FcStrSetDestroy (subdirs);
+ return FcFalse;
+ }
+ if ((sublist = FcStrListCreate (subdirs)))
+ {
+ while ((subdir = FcStrListNext (sublist)))
+ {
+ FcConfigAppFontAddDir (config, subdir);
+ }
+ FcStrListDone (sublist);
+ }
+ FcStrSetDestroy (subdirs);
+ return FcTrue;
+}
+
+FcBool
+FcConfigAppFontAddDir (FcConfig *config,
+ const FcChar8 *dir)
+{
+ FcFontSet *set;
+ FcStrSet *dirs;
+
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return FcFalse;
+ }
+
+ dirs = FcStrSetCreate ();
+ if (!dirs)
+ return FcFalse;
+
+ set = FcConfigGetFonts (config, FcSetApplication);
+ if (!set)
+ {
+ set = FcFontSetCreate ();
+ if (!set)
+ {
+ FcStrSetDestroy (dirs);
+ return FcFalse;
+ }
+ FcConfigSetFonts (config, set, FcSetApplication);
+ }
+
+ FcStrSetAddFilename (dirs, dir);
+
+ if (!FcConfigAddDirList (config, FcSetApplication, dirs))
+ {
+ FcStrSetDestroy (dirs);
+ return FcFalse;
+ }
+ FcStrSetDestroy (dirs);
+ return FcTrue;
+}
+
+void
+FcConfigAppFontClear (FcConfig *config)
+{
+ if (!config)
+ {
+ config = FcConfigGetCurrent ();
+ if (!config)
+ return;
+ }
+
+ FcConfigSetFonts (config, 0, FcSetApplication);
+}
+
+/*
+ * Manage filename-based font source selectors
+ */
+
+FcBool
+FcConfigGlobAdd (FcConfig *config,
+ const FcChar8 *glob,
+ FcBool accept)
+{
+ FcStrSet *set = accept ? config->acceptGlobs : config->rejectGlobs;
+
+ return FcStrSetAdd (set, glob);
+}
+
+static FcBool
+FcConfigGlobMatch (const FcChar8 *glob,
+ const FcChar8 *string)
+{
+ FcChar8 c;
+
+ while ((c = *glob++))
+ {
+ switch (c) {
+ case '*':
+ /* short circuit common case */
+ if (!*glob)
+ return FcTrue;
+ /* short circuit another common case */
+ if (strchr ((char *) glob, '*') == 0)
+ string += strlen ((char *) string) - strlen ((char *) glob);
+ while (*string)
+ {
+ if (FcConfigGlobMatch (glob, string))
+ return FcTrue;
+ string++;
+ }
+ return FcFalse;
+ case '?':
+ if (*string++ == '\0')
+ return FcFalse;
+ break;
+ default:
+ if (*string++ != c)
+ return FcFalse;
+ break;
+ }
+ }
+ return *string == '\0';
+}
+
+static FcBool
+FcConfigGlobsMatch (const FcStrSet *globs,
+ const FcChar8 *string)
+{
+ int i;
+
+ for (i = 0; i < globs->num; i++)
+ if (FcConfigGlobMatch (globs->strs[i], string))
+ return FcTrue;
+ return FcFalse;
+}
+
+FcBool
+FcConfigAcceptFilename (FcConfig *config,
+ const FcChar8 *filename)
+{
+ if (FcConfigGlobsMatch (config->acceptGlobs, filename))
+ return FcTrue;
+ if (FcConfigGlobsMatch (config->rejectGlobs, filename))
+ return FcFalse;
+ return FcTrue;
+}
+
+/*
+ * Manage font-pattern based font source selectors
+ */
+
+FcBool
+FcConfigPatternsAdd (FcConfig *config,
+ FcPattern *pattern,
+ FcBool accept)
+{
+ FcFontSet *set = accept ? config->acceptPatterns : config->rejectPatterns;
+
+ return FcFontSetAdd (set, pattern);
+}
+
+static FcBool
+FcConfigPatternsMatch (const FcFontSet *patterns,
+ const FcPattern *font)
+{
+ int i;
+
+ for (i = 0; i < patterns->nfont; i++)
+ if (FcListPatternMatchAny (patterns->fonts[i], font))
+ return FcTrue;
+ return FcFalse;
+}
+
+FcBool
+FcConfigAcceptFont (FcConfig *config,
+ const FcPattern *font)
+{
+ if (FcConfigPatternsMatch (config->acceptPatterns, font))
+ return FcTrue;
+ if (FcConfigPatternsMatch (config->rejectPatterns, font))
+ return FcFalse;
+ return FcTrue;
+}
+#define __fccfg__
+#include "fcaliastail.h"
+#undef __fccfg__
|