fcdir.c revision 6fc018e4
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 the author(s) not be used in 11 * advertising or publicity pertaining to distribution of the software without 12 * specific, written prior permission. The authors make 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 (file, &statb) != 0) 34 return FcFalse; 35 return S_ISDIR(statb.st_mode); 36} 37 38FcBool 39FcFileIsLink (const FcChar8 *file) 40{ 41#if HAVE_LSTAT 42 struct stat statb; 43 44 if (lstat ((const char *)file, &statb) != 0) 45 return FcFalse; 46 return S_ISLNK (statb.st_mode); 47#else 48 return FcFalse; 49#endif 50} 51 52FcBool 53FcFileIsFile (const FcChar8 *file) 54{ 55 struct stat statb; 56 57 if (FcStat (file, &statb) != 0) 58 return FcFalse; 59 return S_ISREG (statb.st_mode); 60} 61 62static FcBool 63FcFileScanFontConfig (FcFontSet *set, 64 FcBlanks *blanks, 65 const FcChar8 *file, 66 FcConfig *config) 67{ 68 FcPattern *font; 69 FcBool ret = FcTrue; 70 int id; 71 int count = 0; 72 73 id = 0; 74 do 75 { 76 font = 0; 77 /* 78 * Nothing in the cache, scan the file 79 */ 80 if (FcDebug () & FC_DBG_SCAN) 81 { 82 printf ("\tScanning file %s...", file); 83 fflush (stdout); 84 } 85 font = FcFreeTypeQuery (file, id, blanks, &count); 86 if (FcDebug () & FC_DBG_SCAN) 87 printf ("done\n"); 88 89 /* 90 * Edit pattern with user-defined rules 91 */ 92 if (font && config && !FcConfigSubstitute (config, font, FcMatchScan)) 93 { 94 FcPatternDestroy (font); 95 font = NULL; 96 ret = FcFalse; 97 } 98 99 /* 100 * Add the font 101 */ 102 if (font) 103 { 104 if (FcDebug() & FC_DBG_SCANV) 105 { 106 printf ("Final font pattern:\n"); 107 FcPatternPrint (font); 108 } 109 if (!FcFontSetAdd (set, font)) 110 { 111 FcPatternDestroy (font); 112 font = NULL; 113 ret = FcFalse; 114 } 115 } 116 else if (font) 117 FcPatternDestroy (font); 118 id++; 119 } while (font && ret && id < count); 120 return ret; 121} 122 123FcBool 124FcFileScanConfig (FcFontSet *set, 125 FcStrSet *dirs, 126 FcBlanks *blanks, 127 const FcChar8 *file, 128 FcConfig *config) 129{ 130 if (FcFileIsDir (file)) 131 return FcStrSetAdd (dirs, file); 132 else 133 return FcFileScanFontConfig (set, blanks, file, config); 134} 135 136FcBool 137FcFileScan (FcFontSet *set, 138 FcStrSet *dirs, 139 FcFileCache *cache FC_UNUSED, 140 FcBlanks *blanks, 141 const FcChar8 *file, 142 FcBool force FC_UNUSED) 143{ 144 return FcFileScanConfig (set, dirs, blanks, file, FcConfigGetCurrent ()); 145} 146 147/* 148 * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage 149 */ 150static int 151cmpstringp(const void *p1, const void *p2) 152{ 153 return strcmp(* (char **) p1, * (char **) p2); 154} 155 156FcBool 157FcDirScanConfig (FcFontSet *set, 158 FcStrSet *dirs, 159 FcBlanks *blanks, 160 const FcChar8 *dir, 161 FcBool force, /* XXX unused */ 162 FcConfig *config) 163{ 164 DIR *d; 165 struct dirent *e; 166 FcStrSet *files; 167 FcChar8 *file; 168 FcChar8 *base; 169 FcBool ret = FcTrue; 170 int i; 171 172 if (!force) 173 return FcFalse; 174 175 if (!set && !dirs) 176 return FcTrue; 177 178 if (!blanks) 179 blanks = FcConfigGetBlanks (config); 180 181 /* freed below */ 182 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1); 183 if (!file) { 184 ret = FcFalse; 185 goto bail; 186 } 187 188 strcpy ((char *) file, (char *) dir); 189 strcat ((char *) file, "/"); 190 base = file + strlen ((char *) file); 191 192 if (FcDebug () & FC_DBG_SCAN) 193 printf ("\tScanning dir %s\n", dir); 194 195 d = opendir ((char *) dir); 196 if (!d) 197 { 198 /* Don't complain about missing directories */ 199 if (errno != ENOENT) 200 ret = FcFalse; 201 goto bail; 202 } 203 204 files = FcStrSetCreate (); 205 if (!files) 206 { 207 ret = FcFalse; 208 goto bail1; 209 } 210 while ((e = readdir (d))) 211 { 212 if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN) 213 { 214 strcpy ((char *) base, (char *) e->d_name); 215 if (!FcStrSetAdd (files, file)) { 216 ret = FcFalse; 217 goto bail2; 218 } 219 } 220 } 221 222 /* 223 * Sort files to make things prettier 224 */ 225 qsort(files->strs, files->num, sizeof(FcChar8 *), cmpstringp); 226 227 /* 228 * Scan file files to build font patterns 229 */ 230 for (i = 0; i < files->num; i++) 231 FcFileScanConfig (set, dirs, blanks, files->strs[i], config); 232 233bail2: 234 FcStrSetDestroy (files); 235bail1: 236 closedir (d); 237bail: 238 if (file) 239 free (file); 240 241 return ret; 242} 243 244FcBool 245FcDirScan (FcFontSet *set, 246 FcStrSet *dirs, 247 FcFileCache *cache, /* XXX unused */ 248 FcBlanks *blanks, 249 const FcChar8 *dir, 250 FcBool force /* XXX unused */) 251{ 252 if (cache || !force) 253 return FcFalse; 254 255 return FcDirScanConfig (set, dirs, blanks, dir, force, FcConfigGetCurrent ()); 256} 257 258/* 259 * Scan the specified directory and construct a cache of its contents 260 */ 261FcCache * 262FcDirCacheScan (const FcChar8 *dir, FcConfig *config) 263{ 264 FcStrSet *dirs; 265 FcFontSet *set; 266 FcCache *cache = NULL; 267 struct stat dir_stat; 268 269 if (FcDebug () & FC_DBG_FONTSET) 270 printf ("cache scan dir %s\n", dir); 271 272 if (FcStatChecksum (dir, &dir_stat) < 0) 273 goto bail; 274 275 set = FcFontSetCreate(); 276 if (!set) 277 goto bail; 278 279 dirs = FcStrSetCreate (); 280 if (!dirs) 281 goto bail1; 282 283 /* 284 * Scan the dir 285 */ 286 if (!FcDirScanConfig (set, dirs, NULL, dir, FcTrue, config)) 287 goto bail2; 288 289 /* 290 * Build the cache object 291 */ 292 cache = FcDirCacheBuild (set, dir, &dir_stat, dirs); 293 if (!cache) 294 goto bail2; 295 296 /* 297 * Write out the cache file, ignoring any troubles 298 */ 299 FcDirCacheWrite (cache, config); 300 301 bail2: 302 FcStrSetDestroy (dirs); 303 bail1: 304 FcFontSetDestroy (set); 305 bail: 306 return cache; 307} 308 309/* 310 * Read (or construct) the cache for a directory 311 */ 312FcCache * 313FcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config) 314{ 315 FcCache *cache = NULL; 316 317 /* Try to use existing cache file */ 318 if (!force) 319 cache = FcDirCacheLoad (dir, config, NULL); 320 321 /* Not using existing cache file, construct new cache */ 322 if (!cache) 323 cache = FcDirCacheScan (dir, config); 324 325 return cache; 326} 327 328FcBool 329FcDirSave (FcFontSet *set FC_UNUSED, FcStrSet * dirs FC_UNUSED, const FcChar8 *dir FC_UNUSED) 330{ 331 return FcFalse; /* XXX deprecated */ 332} 333#define __fcdir__ 334#include "fcaliastail.h" 335#undef __fcdir__ 336