fcdir.c revision a6844aab
1/* 2 * fontconfig/src/fcdir.c 3 * 4 * Copyright © 2000 Keith Packard 5 * 6 * Permission to use, copy, modify, distribute, and sell this software and its 7 * documentation for any purpose is hereby granted without fee, provided that 8 * the above copyright notice appear in all copies and that both that 9 * copyright notice and this permission notice appear in supporting 10 * documentation, and that the name of Keith Packard not be used in 11 * advertising or publicity pertaining to distribution of the software without 12 * specific, written prior permission. Keith Packard makes no 13 * representations about the suitability of this software for any purpose. It 14 * is provided "as is" without express or implied warranty. 15 * 16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22 * PERFORMANCE OF THIS SOFTWARE. 23 */ 24 25#include "fcint.h" 26#include <dirent.h> 27 28FcBool 29FcFileIsDir (const FcChar8 *file) 30{ 31 struct stat statb; 32 33 if (FcStat ((const char *) file, &statb) != 0) 34 return FcFalse; 35 return S_ISDIR(statb.st_mode); 36} 37 38static FcBool 39FcFileScanFontConfig (FcFontSet *set, 40 FcBlanks *blanks, 41 const FcChar8 *file, 42 FcConfig *config) 43{ 44 FcPattern *font; 45 FcBool ret = FcTrue; 46 int id; 47 int count = 0; 48 49 id = 0; 50 do 51 { 52 font = 0; 53 /* 54 * Nothing in the cache, scan the file 55 */ 56 if (FcDebug () & FC_DBG_SCAN) 57 { 58 printf ("\tScanning file %s...", file); 59 fflush (stdout); 60 } 61 font = FcFreeTypeQuery (file, id, blanks, &count); 62 if (FcDebug () & FC_DBG_SCAN) 63 printf ("done\n"); 64 65 /* 66 * Edit pattern with user-defined rules 67 */ 68 if (font && config && !FcConfigSubstituteWithPat (config, font, NULL, FcMatchScan)) 69 { 70 FcPatternDestroy (font); 71 font = NULL; 72 ret = FcFalse; 73 } 74 75 /* 76 * Add the font 77 */ 78 if (font && (!config || FcConfigAcceptFont (config, font))) 79 { 80 if (FcDebug() & FC_DBG_SCANV) 81 { 82 printf ("Final font pattern:\n"); 83 FcPatternPrint (font); 84 } 85 if (!FcFontSetAdd (set, font)) 86 { 87 FcPatternDestroy (font); 88 font = NULL; 89 ret = FcFalse; 90 } 91 } 92 else if (font) 93 FcPatternDestroy (font); 94 id++; 95 } while (font && ret && id < count); 96 return ret; 97} 98 99FcBool 100FcFileScanConfig (FcFontSet *set, 101 FcStrSet *dirs, 102 FcBlanks *blanks, 103 const FcChar8 *file, 104 FcConfig *config) 105{ 106 if (FcFileIsDir (file)) 107 return FcStrSetAdd (dirs, file); 108 else 109 return FcFileScanFontConfig (set, blanks, file, config); 110} 111 112FcBool 113FcFileScan (FcFontSet *set, 114 FcStrSet *dirs, 115 FcFileCache *cache, /* XXX unused */ 116 FcBlanks *blanks, 117 const FcChar8 *file, 118 FcBool force) 119{ 120 return FcFileScanConfig (set, dirs, blanks, file, FcConfigGetCurrent ()); 121} 122 123/* 124 * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage 125 */ 126static int 127cmpstringp(const void *p1, const void *p2) 128{ 129 return strcmp(* (char **) p1, * (char **) p2); 130} 131 132FcBool 133FcDirScanConfig (FcFontSet *set, 134 FcStrSet *dirs, 135 FcBlanks *blanks, 136 const FcChar8 *dir, 137 FcBool force, /* XXX unused */ 138 FcConfig *config) 139{ 140 DIR *d; 141 struct dirent *e; 142 FcStrSet *files; 143 FcChar8 *file; 144 FcChar8 *base; 145 FcBool ret = FcTrue; 146 int i; 147 148 if (!force) 149 return FcFalse; 150 151 if (!set && !dirs) 152 return FcTrue; 153 154 if (!blanks) 155 blanks = FcConfigGetBlanks (config); 156 157 /* freed below */ 158 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1); 159 if (!file) { 160 ret = FcFalse; 161 goto bail; 162 } 163 164 strcpy ((char *) file, (char *) dir); 165 strcat ((char *) file, "/"); 166 base = file + strlen ((char *) file); 167 168 if (FcDebug () & FC_DBG_SCAN) 169 printf ("\tScanning dir %s\n", dir); 170 171 d = opendir ((char *) dir); 172 if (!d) 173 { 174 /* Don't complain about missing directories */ 175 if (errno != ENOENT) 176 ret = FcFalse; 177 goto bail; 178 } 179 180 files = FcStrSetCreate (); 181 if (!files) 182 { 183 ret = FcFalse; 184 goto bail1; 185 } 186 while ((e = readdir (d))) 187 { 188 if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN) 189 { 190 strcpy ((char *) base, (char *) e->d_name); 191 if (!FcStrSetAdd (files, file)) { 192 ret = FcFalse; 193 goto bail2; 194 } 195 } 196 } 197 198 /* 199 * Sort files to make things prettier 200 */ 201 qsort(files->strs, files->num, sizeof(FcChar8 *), cmpstringp); 202 203 /* 204 * Scan file files to build font patterns 205 */ 206 for (i = 0; i < files->num; i++) 207 FcFileScanConfig (set, dirs, blanks, files->strs[i], config); 208 209bail2: 210 FcStrSetDestroy (files); 211bail1: 212 closedir (d); 213bail: 214 return ret; 215} 216 217FcBool 218FcDirScan (FcFontSet *set, 219 FcStrSet *dirs, 220 FcFileCache *cache, /* XXX unused */ 221 FcBlanks *blanks, 222 const FcChar8 *dir, 223 FcBool force /* XXX unused */) 224{ 225 if (cache || !force) 226 return FcFalse; 227 228 return FcDirScanConfig (set, dirs, blanks, dir, force, FcConfigGetCurrent ()); 229} 230 231/* 232 * Scan the specified directory and construct a cache of its contents 233 */ 234FcCache * 235FcDirCacheScan (const FcChar8 *dir, FcConfig *config) 236{ 237 FcStrSet *dirs; 238 FcBool ret = FcTrue; 239 FcFontSet *set; 240 FcCache *cache = NULL; 241 struct stat dir_stat; 242 243 if (FcDebug () & FC_DBG_FONTSET) 244 printf ("cache scan dir %s\n", dir); 245 246 if (FcStat ((char *) dir, &dir_stat) < 0) 247 { 248 if (errno != ENOENT) 249 ret = FcFalse; 250 goto bail; 251 } 252 253 set = FcFontSetCreate(); 254 if (!set) 255 { 256 ret = FcFalse; 257 goto bail; 258 } 259 260 dirs = FcStrSetCreate (); 261 if (!dirs) 262 { 263 ret = FcFalse; 264 goto bail1; 265 } 266 267 /* 268 * Scan the dir 269 */ 270 if (!FcDirScanConfig (set, dirs, NULL, dir, FcTrue, config)) 271 { 272 ret = FcFalse; 273 goto bail2; 274 } 275 276 /* 277 * Build the cache object 278 */ 279 cache = FcDirCacheBuild (set, dir, &dir_stat, dirs); 280 if (!cache) 281 { 282 ret = FcFalse; 283 goto bail2; 284 } 285 286 /* 287 * Write out the cache file, ignoring any troubles 288 */ 289 FcDirCacheWrite (cache, config); 290 291 bail2: 292 FcStrSetDestroy (dirs); 293 bail1: 294 FcFontSetDestroy (set); 295 bail: 296 return cache; 297} 298 299/* 300 * Read (or construct) the cache for a directory 301 */ 302FcCache * 303FcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config) 304{ 305 FcCache *cache = NULL; 306 307 if (config && !FcConfigAcceptFilename (config, dir)) 308 return NULL; 309 310 /* Try to use existing cache file */ 311 if (!force) 312 cache = FcDirCacheLoad (dir, config, NULL); 313 314 /* Not using existing cache file, construct new cache */ 315 if (!cache) 316 cache = FcDirCacheScan (dir, config); 317 318 return cache; 319} 320 321FcBool 322FcDirSave (FcFontSet *set, FcStrSet * dirs, const FcChar8 *dir) 323{ 324 return FcFalse; /* XXX deprecated */ 325} 326#define __fcdir__ 327#include "fcaliastail.h" 328#undef __fcdir__ 329