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