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