1 /* 2 * fontconfig/fc-cat/fc-cat.c 3 * 4 * Copyright 2002 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 #ifdef HAVE_CONFIG_H 26 #include <config.h> 27 #else 28 #ifdef linux 29 #define HAVE_GETOPT_LONG 1 30 #endif 31 #define HAVE_GETOPT 1 32 #endif 33 34 #include <fontconfig/fontconfig.h> 35 #include "../src/fcarch.h" 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #ifdef HAVE_UNISTD_H 40 #include <unistd.h> 41 #endif 42 #include <sys/types.h> 43 #include <sys/stat.h> 44 #include <errno.h> 45 #include <locale.h> 46 47 #ifdef ENABLE_NLS 48 #include <libintl.h> 49 #define _(x) (dgettext(GETTEXT_PACKAGE, x)) 50 #else 51 #define dgettext(d, s) (s) 52 #define _(x) (x) 53 #endif 54 55 #ifndef HAVE_GETOPT 56 #define HAVE_GETOPT 0 57 #endif 58 #ifndef HAVE_GETOPT_LONG 59 #define HAVE_GETOPT_LONG 0 60 #endif 61 62 #if HAVE_GETOPT_LONG 63 #undef _GNU_SOURCE 64 #define _GNU_SOURCE 65 #include <getopt.h> 66 const struct option longopts[] = { 67 {"version", 0, 0, 'V'}, 68 {"verbose", 0, 0, 'v'}, 69 {"recurse", 0, 0, 'r'}, 70 {"help", 0, 0, 'h'}, 71 {NULL,0,0,0}, 72 }; 73 #else 74 #if HAVE_GETOPT 75 extern char *optarg; 76 extern int optind, opterr, optopt; 77 #endif 78 #endif 79 80 /* 81 * POSIX has broken stdio so that putc must do thread-safe locking, 82 * this is a serious performance problem for applications doing large 83 * amounts of IO with putc (as is done here). If available, use 84 * the putc_unlocked variant instead. 85 */ 86 87 #if defined(putc_unlocked) || defined(_IO_putc_unlocked) 88 #define PUTC(c,f) putc_unlocked(c,f) 89 #else 90 #define PUTC(c,f) putc(c,f) 91 #endif 92 93 static FcBool 94 write_chars (FILE *f, const FcChar8 *chars) 95 { 96 FcChar8 c; 97 while ((c = *chars++)) 98 { 99 switch (c) { 100 case '"': 101 case '\\': 102 if (PUTC ('\\', f) == EOF) 103 return FcFalse; 104 /* fall through */ 105 default: 106 if (PUTC (c, f) == EOF) 107 return FcFalse; 108 } 109 } 110 return FcTrue; 111 } 112 113 static FcBool 114 write_ulong (FILE *f, unsigned long t) 115 { 116 int pow; 117 unsigned long temp, digit; 118 119 temp = t; 120 pow = 1; 121 while (temp >= 10) 122 { 123 temp /= 10; 124 pow *= 10; 125 } 126 temp = t; 127 while (pow) 128 { 129 digit = temp / pow; 130 if (PUTC ((char) digit + '0', f) == EOF) 131 return FcFalse; 132 temp = temp - pow * digit; 133 pow = pow / 10; 134 } 135 return FcTrue; 136 } 137 138 static FcBool 139 write_int (FILE *f, int i) 140 { 141 return write_ulong (f, (unsigned long) i); 142 } 143 144 static FcBool 145 write_string (FILE *f, const FcChar8 *string) 146 { 147 148 if (PUTC ('"', f) == EOF) 149 return FcFalse; 150 if (!write_chars (f, string)) 151 return FcFalse; 152 if (PUTC ('"', f) == EOF) 153 return FcFalse; 154 return FcTrue; 155 } 156 157 static void 158 usage (char *program, int error) 159 { 160 FILE *file = error ? stderr : stdout; 161 #if HAVE_GETOPT_LONG 162 fprintf (file, _("usage: %s [-rv] [--recurse] [--verbose] [*-%s" FC_CACHE_SUFFIX "|directory]...\n"), 163 program, FC_ARCHITECTURE); 164 fprintf (file, " %s [-Vh] [--version] [--help]\n", program); 165 #else 166 fprintf (file, _("usage: %s [-rvVh] [*-%s" FC_CACHE_SUFFIX "|directory]...\n"), 167 program, FC_ARCHITECTURE); 168 #endif 169 fprintf (file, _("Reads font information cache from:\n")); 170 fprintf (file, _(" 1) specified fontconfig cache file\n")); 171 fprintf (file, _(" 2) related to a particular font directory\n")); 172 fprintf (file, "\n"); 173 #if HAVE_GETOPT_LONG 174 fprintf (file, _(" -r, --recurse recurse into subdirectories\n")); 175 fprintf (file, _(" -v, --verbose be verbose\n")); 176 fprintf (file, _(" -V, --version display font config version and exit\n")); 177 fprintf (file, _(" -h, --help display this help and exit\n")); 178 #else 179 fprintf (file, _(" -r (recurse) recurse into subdirectories\n")); 180 fprintf (file, _(" -v (verbose) be verbose\n")); 181 fprintf (file, _(" -V (version) display font config version and exit\n")); 182 fprintf (file, _(" -h (help) display this help and exit\n")); 183 #endif 184 exit (error); 185 } 186 187 /* 188 * return the path from the directory containing 'cache' to 'file' 189 */ 190 191 static const FcChar8 * 192 file_base_name (const FcChar8 *cache, const FcChar8 *file) 193 { 194 int cache_len = strlen ((char *) cache); 195 196 if (!strncmp ((char *) cache, (char *) file, cache_len) && file[cache_len] == '/') 197 return file + cache_len + 1; 198 return file; 199 } 200 201 #define FC_FONT_FILE_DIR ((FcChar8 *) ".dir") 202 203 static FcBool 204 cache_print_set (FcFontSet *set, FcStrSet *dirs, const FcChar8 *base_name, FcBool verbose) 205 { 206 FcChar8 *dir; 207 const FcChar8 *base; 208 int n; 209 int ndir = 0; 210 FcStrList *list; 211 212 list = FcStrListCreate (dirs); 213 if (!list) 214 goto bail2; 215 216 while ((dir = FcStrListNext (list))) 217 { 218 base = file_base_name (base_name, dir); 219 if (!write_string (stdout, base)) 220 goto bail3; 221 if (PUTC (' ', stdout) == EOF) 222 goto bail3; 223 if (!write_int (stdout, 0)) 224 goto bail3; 225 if (PUTC (' ', stdout) == EOF) 226 goto bail3; 227 if (!write_string (stdout, FC_FONT_FILE_DIR)) 228 goto bail3; 229 if (PUTC ('\n', stdout) == EOF) 230 goto bail3; 231 ndir++; 232 } 233 234 for (n = 0; n < set->nfont; n++) 235 { 236 FcPattern *font = set->fonts[n]; 237 FcChar8 *s; 238 239 s = FcPatternFormat (font, (const FcChar8 *) "%{=fccat}\n"); 240 if (s) 241 { 242 printf ("%s", s); 243 FcStrFree (s); 244 } 245 } 246 if (verbose && !set->nfont && !ndir) 247 printf ("<empty>\n"); 248 249 FcStrListDone (list); 250 251 return FcTrue; 252 253 bail3: 254 FcStrListDone (list); 255 bail2: 256 return FcFalse; 257 } 258 259 int 260 main (int argc, char **argv) 261 { 262 int i; 263 int ret = 0; 264 FcFontSet *fs; 265 FcStrSet *dirs; 266 FcStrSet *args = NULL; 267 FcStrList *arglist; 268 FcCache *cache; 269 FcConfig *config; 270 FcChar8 *arg; 271 int verbose = 0; 272 int recurse = 0; 273 FcBool first = FcTrue; 274 #if HAVE_GETOPT_LONG || HAVE_GETOPT 275 int c; 276 277 setlocale (LC_ALL, ""); 278 #if HAVE_GETOPT_LONG 279 while ((c = getopt_long (argc, argv, "Vvrh", longopts, NULL)) != -1) 280 #else 281 while ((c = getopt (argc, argv, "Vvrh")) != -1) 282 #endif 283 { 284 switch (c) { 285 case 'V': 286 fprintf (stderr, "fontconfig version %d.%d.%d\n", 287 FC_MAJOR, FC_MINOR, FC_REVISION); 288 exit (0); 289 case 'v': 290 verbose++; 291 break; 292 case 'r': 293 recurse++; 294 break; 295 case 'h': 296 usage (argv[0], 0); 297 default: 298 usage (argv[0], 1); 299 } 300 } 301 i = optind; 302 #else 303 i = 1; 304 #endif 305 306 config = FcInitLoadConfig (); 307 if (!config) 308 { 309 fprintf (stderr, _("%s: Can't initialize font config library\n"), argv[0]); 310 return 1; 311 } 312 FcConfigSetCurrent (config); 313 FcConfigDestroy (config); 314 315 args = FcStrSetCreate (); 316 if (!args) 317 { 318 fprintf (stderr, _("%s: malloc failure\n"), argv[0]); 319 return 1; 320 } 321 if (i < argc) 322 { 323 for (; i < argc; i++) 324 { 325 if (!FcStrSetAddFilename (args, (const FcChar8 *) argv[i])) 326 { 327 fprintf (stderr, _("%s: malloc failure\n"), argv[0]); 328 return 1; 329 } 330 } 331 } 332 else 333 { 334 recurse++; 335 arglist = FcConfigGetFontDirs (config); 336 while ((arg = FcStrListNext (arglist))) 337 if (!FcStrSetAdd (args, arg)) 338 { 339 fprintf (stderr, _("%s: malloc failure\n"), argv[0]); 340 return 1; 341 } 342 FcStrListDone (arglist); 343 } 344 arglist = FcStrListCreate (args); 345 if (!arglist) 346 { 347 fprintf (stderr, _("%s: malloc failure\n"), argv[0]); 348 return 1; 349 } 350 FcStrSetDestroy (args); 351 352 while ((arg = FcStrListNext (arglist))) 353 { 354 int j; 355 FcChar8 *cache_file = NULL; 356 struct stat file_stat; 357 358 /* reset errno */ 359 errno = 0; 360 if (FcFileIsDir (arg)) 361 cache = FcDirCacheLoad (arg, config, &cache_file); 362 else 363 cache = FcDirCacheLoadFile (arg, &file_stat); 364 if (!cache) 365 { 366 if (errno != 0) 367 perror ((char *) arg); 368 else 369 fprintf (stderr, "%s: Unable to load the cache: %s\n", argv[0], arg); 370 ret++; 371 continue; 372 } 373 374 dirs = FcStrSetCreate (); 375 fs = FcCacheCopySet (cache); 376 for (j = 0; j < FcCacheNumSubdir (cache); j++) 377 { 378 FcStrSetAdd (dirs, FcCacheSubdir (cache, j)); 379 if (recurse) 380 FcStrSetAdd (args, FcCacheSubdir (cache, j)); 381 } 382 383 if (verbose) 384 { 385 if (!first) 386 printf ("\n"); 387 printf (_("Directory: %s\nCache: %s\n--------\n"), 388 FcCacheDir(cache), cache_file ? cache_file : arg); 389 first = FcFalse; 390 } 391 cache_print_set (fs, dirs, FcCacheDir (cache), verbose); 392 393 FcStrSetDestroy (dirs); 394 395 FcFontSetDestroy (fs); 396 FcDirCacheUnload (cache); 397 if (cache_file) 398 FcStrFree (cache_file); 399 } 400 FcStrListDone (arglist); 401 402 FcFini (); 403 return 0; 404 } 405