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