| /* |
| * fontconfig/src/fcdir.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> |
| |
| FcBool |
| FcFileIsDir (const FcChar8 *file) |
| { |
| struct stat statb; |
| |
| if (FcStat ((const char *) file, &statb) != 0) |
| return FcFalse; |
| return S_ISDIR(statb.st_mode); |
| } |
| |
| static FcBool |
| FcFileScanFontConfig (FcFontSet *set, |
| FcBlanks *blanks, |
| const FcChar8 *file, |
| FcConfig *config) |
| { |
| FcPattern *font; |
| FcBool ret = FcTrue; |
| int id; |
| int count = 0; |
| |
| id = 0; |
| do |
| { |
| font = 0; |
| /* |
| * Nothing in the cache, scan the file |
| */ |
| if (FcDebug () & FC_DBG_SCAN) |
| { |
| printf ("\tScanning file %s...", file); |
| fflush (stdout); |
| } |
| font = FcFreeTypeQuery (file, id, blanks, &count); |
| if (FcDebug () & FC_DBG_SCAN) |
| printf ("done\n"); |
| |
| /* |
| * Edit pattern with user-defined rules |
| */ |
| if (font && config && !FcConfigSubstituteWithPat (config, font, NULL, FcMatchScan)) |
| { |
| FcPatternDestroy (font); |
| font = NULL; |
| ret = FcFalse; |
| } |
| |
| /* |
| * Add the font |
| */ |
| if (font && (!config || FcConfigAcceptFont (config, font))) |
| { |
| if (FcDebug() & FC_DBG_SCANV) |
| { |
| printf ("Final font pattern:\n"); |
| FcPatternPrint (font); |
| } |
| if (!FcFontSetAdd (set, font)) |
| { |
| FcPatternDestroy (font); |
| font = NULL; |
| ret = FcFalse; |
| } |
| } |
| else if (font) |
| FcPatternDestroy (font); |
| id++; |
| } while (font && ret && id < count); |
| return ret; |
| } |
| |
| FcBool |
| FcFileScanConfig (FcFontSet *set, |
| FcStrSet *dirs, |
| FcBlanks *blanks, |
| const FcChar8 *file, |
| FcConfig *config) |
| { |
| if (FcFileIsDir (file)) |
| return FcStrSetAdd (dirs, file); |
| else |
| return FcFileScanFontConfig (set, blanks, file, config); |
| } |
| |
| FcBool |
| FcFileScan (FcFontSet *set, |
| FcStrSet *dirs, |
| FcFileCache *cache, /* XXX unused */ |
| FcBlanks *blanks, |
| const FcChar8 *file, |
| FcBool force) |
| { |
| return FcFileScanConfig (set, dirs, blanks, file, FcConfigGetCurrent ()); |
| } |
| |
| /* |
| * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage |
| */ |
| static int |
| cmpstringp(const void *p1, const void *p2) |
| { |
| return strcmp(* (char **) p1, * (char **) p2); |
| } |
| |
| FcBool |
| FcDirScanConfig (FcFontSet *set, |
| FcStrSet *dirs, |
| FcBlanks *blanks, |
| const FcChar8 *dir, |
| FcBool force, /* XXX unused */ |
| FcConfig *config) |
| { |
| DIR *d; |
| struct dirent *e; |
| FcStrSet *files; |
| FcChar8 *file; |
| FcChar8 *base; |
| FcBool ret = FcTrue; |
| int i; |
| |
| if (!force) |
| return FcFalse; |
| |
| if (!set && !dirs) |
| return FcTrue; |
| |
| if (!blanks) |
| blanks = FcConfigGetBlanks (config); |
| |
| /* freed below */ |
| file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1); |
| if (!file) { |
| ret = FcFalse; |
| goto bail; |
| } |
| |
| strcpy ((char *) file, (char *) dir); |
| strcat ((char *) file, "/"); |
| base = file + strlen ((char *) file); |
| |
| if (FcDebug () & FC_DBG_SCAN) |
| printf ("\tScanning dir %s\n", dir); |
| |
| d = opendir ((char *) dir); |
| if (!d) |
| { |
| /* Don't complain about missing directories */ |
| if (errno != ENOENT) |
| ret = FcFalse; |
| goto bail; |
| } |
| |
| files = FcStrSetCreate (); |
| if (!files) |
| { |
| ret = FcFalse; |
| goto bail1; |
| } |
| while ((e = readdir (d))) |
| { |
| if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN) |
| { |
| strcpy ((char *) base, (char *) e->d_name); |
| if (!FcStrSetAdd (files, file)) { |
| ret = FcFalse; |
| goto bail2; |
| } |
| } |
| } |
| |
| /* |
| * Sort files to make things prettier |
| */ |
| qsort(files->strs, files->num, sizeof(FcChar8 *), cmpstringp); |
| |
| /* |
| * Scan file files to build font patterns |
| */ |
| for (i = 0; i < files->num; i++) |
| FcFileScanConfig (set, dirs, blanks, files->strs[i], config); |
| |
| bail2: |
| FcStrSetDestroy (files); |
| bail1: |
| closedir (d); |
| bail: |
| return ret; |
| } |
| |
| FcBool |
| FcDirScan (FcFontSet *set, |
| FcStrSet *dirs, |
| FcFileCache *cache, /* XXX unused */ |
| FcBlanks *blanks, |
| const FcChar8 *dir, |
| FcBool force /* XXX unused */) |
| { |
| if (cache || !force) |
| return FcFalse; |
| |
| return FcDirScanConfig (set, dirs, blanks, dir, force, FcConfigGetCurrent ()); |
| } |
| |
| /* |
| * Scan the specified directory and construct a cache of its contents |
| */ |
| FcCache * |
| FcDirCacheScan (const FcChar8 *dir, FcConfig *config) |
| { |
| FcStrSet *dirs; |
| FcBool ret = FcTrue; |
| FcFontSet *set; |
| FcCache *cache = NULL; |
| struct stat dir_stat; |
| |
| if (FcDebug () & FC_DBG_FONTSET) |
| printf ("cache scan dir %s\n", dir); |
| |
| if (FcStat ((char *) dir, &dir_stat) < 0) |
| { |
| if (errno != ENOENT) |
| ret = FcFalse; |
| goto bail; |
| } |
| |
| set = FcFontSetCreate(); |
| if (!set) |
| { |
| ret = FcFalse; |
| goto bail; |
| } |
| |
| dirs = FcStrSetCreate (); |
| if (!dirs) |
| { |
| ret = FcFalse; |
| goto bail1; |
| } |
| |
| /* |
| * Scan the dir |
| */ |
| if (!FcDirScanConfig (set, dirs, NULL, dir, FcTrue, config)) |
| { |
| ret = FcFalse; |
| goto bail2; |
| } |
| |
| /* |
| * Build the cache object |
| */ |
| cache = FcDirCacheBuild (set, dir, &dir_stat, dirs); |
| if (!cache) |
| { |
| ret = FcFalse; |
| goto bail2; |
| } |
| |
| /* |
| * Write out the cache file, ignoring any troubles |
| */ |
| FcDirCacheWrite (cache, config); |
| |
| bail2: |
| FcStrSetDestroy (dirs); |
| bail1: |
| FcFontSetDestroy (set); |
| bail: |
| return cache; |
| } |
| |
| /* |
| * Read (or construct) the cache for a directory |
| */ |
| FcCache * |
| FcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config) |
| { |
| FcCache *cache = NULL; |
| |
| if (config && !FcConfigAcceptFilename (config, dir)) |
| return NULL; |
| |
| /* Try to use existing cache file */ |
| if (!force) |
| cache = FcDirCacheLoad (dir, config, NULL); |
| |
| /* Not using existing cache file, construct new cache */ |
| if (!cache) |
| cache = FcDirCacheScan (dir, config); |
| |
| return cache; |
| } |
| |
| FcBool |
| FcDirSave (FcFontSet *set, FcStrSet * dirs, const FcChar8 *dir) |
| { |
| return FcFalse; /* XXX deprecated */ |
| } |
| #define __fcdir__ |
| #include "fcaliastail.h" |
| #undef __fcdir__ |