fc-cat.c revision 953daeba
12c393a42Smrg/* 2a6844aabSmrg * fontconfig/fc-cat/fc-cat.c 32c393a42Smrg * 42c393a42Smrg * Copyright © 2002 Keith Packard 52c393a42Smrg * 62c393a42Smrg * Permission to use, copy, modify, distribute, and sell this software and its 72c393a42Smrg * documentation for any purpose is hereby granted without fee, provided that 82c393a42Smrg * the above copyright notice appear in all copies and that both that 92c393a42Smrg * copyright notice and this permission notice appear in supporting 10ca08ab68Smrg * documentation, and that the name of the author(s) not be used in 112c393a42Smrg * advertising or publicity pertaining to distribution of the software without 12ca08ab68Smrg * specific, written prior permission. The authors make no 132c393a42Smrg * representations about the suitability of this software for any purpose. It 142c393a42Smrg * is provided "as is" without express or implied warranty. 152c393a42Smrg * 16a6844aabSmrg * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 172c393a42Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18a6844aabSmrg * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR 192c393a42Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 202c393a42Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 212c393a42Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 222c393a42Smrg * PERFORMANCE OF THIS SOFTWARE. 232c393a42Smrg */ 242c393a42Smrg 252c393a42Smrg#ifdef HAVE_CONFIG_H 262c393a42Smrg#include <config.h> 272c393a42Smrg#else 282c393a42Smrg#ifdef linux 292c393a42Smrg#define HAVE_GETOPT_LONG 1 302c393a42Smrg#endif 312c393a42Smrg#define HAVE_GETOPT 1 322c393a42Smrg#endif 332c393a42Smrg 342c393a42Smrg#include <fontconfig/fontconfig.h> 35ca08ab68Smrg#include "../src/fcarch.h" 362c393a42Smrg#include <stdio.h> 372c393a42Smrg#include <stdlib.h> 382c393a42Smrg#include <string.h> 392c393a42Smrg#include <unistd.h> 402c393a42Smrg#include <sys/types.h> 412c393a42Smrg#include <sys/stat.h> 422c393a42Smrg#include <errno.h> 432c393a42Smrg 442c393a42Smrg#ifndef HAVE_GETOPT 452c393a42Smrg#define HAVE_GETOPT 0 462c393a42Smrg#endif 472c393a42Smrg#ifndef HAVE_GETOPT_LONG 482c393a42Smrg#define HAVE_GETOPT_LONG 0 492c393a42Smrg#endif 502c393a42Smrg 512c393a42Smrg#if HAVE_GETOPT_LONG 522c393a42Smrg#undef _GNU_SOURCE 532c393a42Smrg#define _GNU_SOURCE 542c393a42Smrg#include <getopt.h> 552c393a42Smrgconst struct option longopts[] = { 562c393a42Smrg {"version", 0, 0, 'V'}, 572c393a42Smrg {"verbose", 0, 0, 'v'}, 582c393a42Smrg {"recurse", 0, 0, 'r'}, 59a6844aabSmrg {"help", 0, 0, 'h'}, 602c393a42Smrg {NULL,0,0,0}, 612c393a42Smrg}; 622c393a42Smrg#else 632c393a42Smrg#if HAVE_GETOPT 642c393a42Smrgextern char *optarg; 652c393a42Smrgextern int optind, opterr, optopt; 662c393a42Smrg#endif 672c393a42Smrg#endif 682c393a42Smrg 692c393a42Smrg/* 70c9710b42Smrg * POSIX has broken stdio so that putc must do thread-safe locking, 712c393a42Smrg * this is a serious performance problem for applications doing large 72c9710b42Smrg * amounts of IO with putc (as is done here). If available, use 73c9710b42Smrg * the putc_unlocked varient instead. 742c393a42Smrg */ 752c393a42Smrg 76c9710b42Smrg#if defined(putc_unlocked) || defined(_IO_putc_unlocked) 772c393a42Smrg#define PUTC(c,f) putc_unlocked(c,f) 782c393a42Smrg#else 792c393a42Smrg#define PUTC(c,f) putc(c,f) 802c393a42Smrg#endif 812c393a42Smrg 822c393a42Smrgstatic FcBool 832c393a42Smrgwrite_chars (FILE *f, const FcChar8 *chars) 842c393a42Smrg{ 852c393a42Smrg FcChar8 c; 862c393a42Smrg while ((c = *chars++)) 872c393a42Smrg { 882c393a42Smrg switch (c) { 892c393a42Smrg case '"': 902c393a42Smrg case '\\': 912c393a42Smrg if (PUTC ('\\', f) == EOF) 922c393a42Smrg return FcFalse; 932c393a42Smrg /* fall through */ 942c393a42Smrg default: 952c393a42Smrg if (PUTC (c, f) == EOF) 962c393a42Smrg return FcFalse; 972c393a42Smrg } 982c393a42Smrg } 992c393a42Smrg return FcTrue; 1002c393a42Smrg} 1012c393a42Smrg 1022c393a42Smrgstatic FcBool 1032c393a42Smrgwrite_ulong (FILE *f, unsigned long t) 1042c393a42Smrg{ 1052c393a42Smrg int pow; 1062c393a42Smrg unsigned long temp, digit; 1072c393a42Smrg 1082c393a42Smrg temp = t; 1092c393a42Smrg pow = 1; 1102c393a42Smrg while (temp >= 10) 1112c393a42Smrg { 1122c393a42Smrg temp /= 10; 1132c393a42Smrg pow *= 10; 1142c393a42Smrg } 1152c393a42Smrg temp = t; 1162c393a42Smrg while (pow) 1172c393a42Smrg { 1182c393a42Smrg digit = temp / pow; 1192c393a42Smrg if (PUTC ((char) digit + '0', f) == EOF) 1202c393a42Smrg return FcFalse; 1212c393a42Smrg temp = temp - pow * digit; 1222c393a42Smrg pow = pow / 10; 1232c393a42Smrg } 1242c393a42Smrg return FcTrue; 1252c393a42Smrg} 1262c393a42Smrg 1272c393a42Smrgstatic FcBool 1282c393a42Smrgwrite_int (FILE *f, int i) 1292c393a42Smrg{ 1302c393a42Smrg return write_ulong (f, (unsigned long) i); 1312c393a42Smrg} 1322c393a42Smrg 1332c393a42Smrgstatic FcBool 1342c393a42Smrgwrite_string (FILE *f, const FcChar8 *string) 1352c393a42Smrg{ 1362c393a42Smrg 1372c393a42Smrg if (PUTC ('"', f) == EOF) 1382c393a42Smrg return FcFalse; 1392c393a42Smrg if (!write_chars (f, string)) 1402c393a42Smrg return FcFalse; 1412c393a42Smrg if (PUTC ('"', f) == EOF) 1422c393a42Smrg return FcFalse; 1432c393a42Smrg return FcTrue; 1442c393a42Smrg} 1452c393a42Smrg 1462c393a42Smrgstatic void 147a6844aabSmrgusage (char *program, int error) 1482c393a42Smrg{ 149a6844aabSmrg FILE *file = error ? stderr : stdout; 1502c393a42Smrg#if HAVE_GETOPT_LONG 151ca08ab68Smrg fprintf (file, "usage: %s [-rv] [--recurse] [--verbose] [*-%s" FC_CACHE_SUFFIX "|directory]...\n", 1522c393a42Smrg program, FC_ARCHITECTURE); 153a6844aabSmrg fprintf (file, " %s [-Vh] [--version] [--help]\n", program); 1542c393a42Smrg#else 155ca08ab68Smrg fprintf (file, "usage: %s [-rvVh] [*-%s" FC_CACHE_SUFFIX "|directory]...\n", 1562c393a42Smrg program, FC_ARCHITECTURE); 1572c393a42Smrg#endif 158a6844aabSmrg fprintf (file, "Reads font information cache from:\n"); 159a6844aabSmrg fprintf (file, " 1) specified fontconfig cache file\n"); 160a6844aabSmrg fprintf (file, " 2) related to a particular font directory\n"); 161a6844aabSmrg fprintf (file, "\n"); 1622c393a42Smrg#if HAVE_GETOPT_LONG 163a6844aabSmrg fprintf (file, " -r, --recurse recurse into subdirectories\n"); 164a6844aabSmrg fprintf (file, " -v, --verbose be verbose\n"); 165a6844aabSmrg fprintf (file, " -V, --version display font config version and exit\n"); 166a6844aabSmrg fprintf (file, " -h, --help display this help and exit\n"); 1672c393a42Smrg#else 168a6844aabSmrg fprintf (file, " -r (recurse) recurse into subdirectories\n"); 169a6844aabSmrg fprintf (file, " -v (verbose) be verbose\n"); 170a6844aabSmrg fprintf (file, " -V (version) display font config version and exit\n"); 171a6844aabSmrg fprintf (file, " -h (help) display this help and exit\n"); 1722c393a42Smrg#endif 173a6844aabSmrg exit (error); 1742c393a42Smrg} 1752c393a42Smrg 1762c393a42Smrg/* 1772c393a42Smrg * return the path from the directory containing 'cache' to 'file' 1782c393a42Smrg */ 1792c393a42Smrg 1802c393a42Smrgstatic const FcChar8 * 1812c393a42Smrgfile_base_name (const FcChar8 *cache, const FcChar8 *file) 1822c393a42Smrg{ 1832c393a42Smrg int cache_len = strlen ((char *) cache); 1842c393a42Smrg 1852c393a42Smrg if (!strncmp ((char *) cache, (char *) file, cache_len) && file[cache_len] == '/') 1862c393a42Smrg return file + cache_len + 1; 1872c393a42Smrg return file; 1882c393a42Smrg} 1892c393a42Smrg 1902c393a42Smrg#define FC_FONT_FILE_DIR ((FcChar8 *) ".dir") 1912c393a42Smrg 1922c393a42Smrgstatic FcBool 1932c393a42Smrgcache_print_set (FcFontSet *set, FcStrSet *dirs, const FcChar8 *base_name, FcBool verbose) 1942c393a42Smrg{ 195ca08ab68Smrg FcChar8 *dir; 196ca08ab68Smrg const FcChar8 *base; 1972c393a42Smrg int n; 1982c393a42Smrg int ndir = 0; 1992c393a42Smrg FcStrList *list; 2002c393a42Smrg 2012c393a42Smrg list = FcStrListCreate (dirs); 2022c393a42Smrg if (!list) 2032c393a42Smrg goto bail2; 2042c393a42Smrg 2052c393a42Smrg while ((dir = FcStrListNext (list))) 2062c393a42Smrg { 2072c393a42Smrg base = file_base_name (base_name, dir); 2082c393a42Smrg if (!write_string (stdout, base)) 2092c393a42Smrg goto bail3; 2102c393a42Smrg if (PUTC (' ', stdout) == EOF) 2112c393a42Smrg goto bail3; 2122c393a42Smrg if (!write_int (stdout, 0)) 2132c393a42Smrg goto bail3; 2142c393a42Smrg if (PUTC (' ', stdout) == EOF) 2152c393a42Smrg goto bail3; 2162c393a42Smrg if (!write_string (stdout, FC_FONT_FILE_DIR)) 2172c393a42Smrg goto bail3; 2182c393a42Smrg if (PUTC ('\n', stdout) == EOF) 2192c393a42Smrg goto bail3; 2202c393a42Smrg ndir++; 2212c393a42Smrg } 2222c393a42Smrg 2232c393a42Smrg for (n = 0; n < set->nfont; n++) 2242c393a42Smrg { 2252c393a42Smrg FcPattern *font = set->fonts[n]; 226ca08ab68Smrg FcChar8 *s; 2272c393a42Smrg 228ca08ab68Smrg s = FcPatternFormat (font, (const FcChar8 *) "%{=fccat}\n"); 229ca08ab68Smrg if (s) 230ca08ab68Smrg { 231ca08ab68Smrg printf ("%s", s); 232ca08ab68Smrg FcStrFree (s); 233ca08ab68Smrg } 2342c393a42Smrg } 2352c393a42Smrg if (verbose && !set->nfont && !ndir) 2362c393a42Smrg printf ("<empty>\n"); 237ca08ab68Smrg 2382c393a42Smrg FcStrListDone (list); 2392c393a42Smrg 2402c393a42Smrg return FcTrue; 241ca08ab68Smrg 2422c393a42Smrgbail3: 2432c393a42Smrg FcStrListDone (list); 2442c393a42Smrgbail2: 2452c393a42Smrg return FcFalse; 2462c393a42Smrg} 2472c393a42Smrg 2482c393a42Smrgint 2492c393a42Smrgmain (int argc, char **argv) 2502c393a42Smrg{ 2512c393a42Smrg int i; 2522c393a42Smrg int ret = 0; 2532c393a42Smrg FcFontSet *fs; 2542c393a42Smrg FcStrSet *dirs; 2552c393a42Smrg FcStrSet *args = NULL; 2562c393a42Smrg FcStrList *arglist; 2572c393a42Smrg FcCache *cache; 2582c393a42Smrg FcConfig *config; 2592c393a42Smrg FcChar8 *arg; 2602c393a42Smrg int verbose = 0; 2612c393a42Smrg int recurse = 0; 2622c393a42Smrg FcBool first = FcTrue; 2632c393a42Smrg#if HAVE_GETOPT_LONG || HAVE_GETOPT 2642c393a42Smrg int c; 2652c393a42Smrg 2662c393a42Smrg#if HAVE_GETOPT_LONG 267a6844aabSmrg while ((c = getopt_long (argc, argv, "Vvrh", longopts, NULL)) != -1) 2682c393a42Smrg#else 269a6844aabSmrg while ((c = getopt (argc, argv, "Vvrh")) != -1) 2702c393a42Smrg#endif 2712c393a42Smrg { 2722c393a42Smrg switch (c) { 2732c393a42Smrg case 'V': 2742c393a42Smrg fprintf (stderr, "fontconfig version %d.%d.%d\n", 2752c393a42Smrg FC_MAJOR, FC_MINOR, FC_REVISION); 2762c393a42Smrg exit (0); 2772c393a42Smrg case 'v': 2782c393a42Smrg verbose++; 2792c393a42Smrg break; 2802c393a42Smrg case 'r': 2812c393a42Smrg recurse++; 2822c393a42Smrg break; 283a6844aabSmrg case 'h': 284a6844aabSmrg usage (argv[0], 0); 2852c393a42Smrg default: 286a6844aabSmrg usage (argv[0], 1); 2872c393a42Smrg } 2882c393a42Smrg } 2892c393a42Smrg i = optind; 2902c393a42Smrg#else 2912c393a42Smrg i = 1; 2922c393a42Smrg#endif 2932c393a42Smrg 2942c393a42Smrg config = FcInitLoadConfig (); 2952c393a42Smrg if (!config) 2962c393a42Smrg { 2972c393a42Smrg fprintf (stderr, "%s: Can't init font config library\n", argv[0]); 2982c393a42Smrg return 1; 2992c393a42Smrg } 3002c393a42Smrg FcConfigSetCurrent (config); 301953daebaSmrg FcConfigDestroy (config); 3022c393a42Smrg 3032c393a42Smrg args = FcStrSetCreate (); 3042c393a42Smrg if (!args) 3052c393a42Smrg { 3062c393a42Smrg fprintf (stderr, "%s: malloc failure\n", argv[0]); 3072c393a42Smrg return 1; 3082c393a42Smrg } 3092c393a42Smrg if (i < argc) 3102c393a42Smrg { 3112c393a42Smrg for (; i < argc; i++) 3122c393a42Smrg { 3132c393a42Smrg if (!FcStrSetAddFilename (args, (const FcChar8 *) argv[i])) 3142c393a42Smrg { 3152c393a42Smrg fprintf (stderr, "%s: malloc failure\n", argv[0]); 3162c393a42Smrg return 1; 3172c393a42Smrg } 3182c393a42Smrg } 3192c393a42Smrg } 3202c393a42Smrg else 3212c393a42Smrg { 3222c393a42Smrg recurse++; 3232c393a42Smrg arglist = FcConfigGetFontDirs (config); 3242c393a42Smrg while ((arg = FcStrListNext (arglist))) 3252c393a42Smrg if (!FcStrSetAdd (args, arg)) 3262c393a42Smrg { 3272c393a42Smrg fprintf (stderr, "%s: malloc failure\n", argv[0]); 3282c393a42Smrg return 1; 3292c393a42Smrg } 3302c393a42Smrg FcStrListDone (arglist); 3312c393a42Smrg } 3322c393a42Smrg arglist = FcStrListCreate (args); 3332c393a42Smrg if (!arglist) 3342c393a42Smrg { 3352c393a42Smrg fprintf (stderr, "%s: malloc failure\n", argv[0]); 3362c393a42Smrg return 1; 3372c393a42Smrg } 338953daebaSmrg FcStrSetDestroy (args); 3392c393a42Smrg 3402c393a42Smrg while ((arg = FcStrListNext (arglist))) 3412c393a42Smrg { 3422c393a42Smrg int j; 3432c393a42Smrg FcChar8 *cache_file = NULL; 3442c393a42Smrg struct stat file_stat; 345953daebaSmrg 346953daebaSmrg /* reset errno */ 347953daebaSmrg errno = 0; 3482c393a42Smrg if (FcFileIsDir (arg)) 3492c393a42Smrg cache = FcDirCacheLoad (arg, config, &cache_file); 3502c393a42Smrg else 3512c393a42Smrg cache = FcDirCacheLoadFile (arg, &file_stat); 3522c393a42Smrg if (!cache) 3532c393a42Smrg { 354953daebaSmrg if (errno != 0) 355953daebaSmrg perror ((char *) arg); 356953daebaSmrg else 357953daebaSmrg fprintf (stderr, "%s: Unable to load the cache: %s\n", argv[0], arg); 3582c393a42Smrg ret++; 3592c393a42Smrg continue; 3602c393a42Smrg } 3612c393a42Smrg 3622c393a42Smrg dirs = FcStrSetCreate (); 3632c393a42Smrg fs = FcCacheCopySet (cache); 3642c393a42Smrg for (j = 0; j < FcCacheNumSubdir (cache); j++) 3652c393a42Smrg { 3662c393a42Smrg FcStrSetAdd (dirs, FcCacheSubdir (cache, j)); 3672c393a42Smrg if (recurse) 3682c393a42Smrg FcStrSetAdd (args, FcCacheSubdir (cache, j)); 3692c393a42Smrg } 3702c393a42Smrg 3712c393a42Smrg if (verbose) 3722c393a42Smrg { 3732c393a42Smrg if (!first) 3742c393a42Smrg printf ("\n"); 3752c393a42Smrg printf ("Directory: %s\nCache: %s\n--------\n", 3762c393a42Smrg FcCacheDir(cache), cache_file ? cache_file : arg); 3772c393a42Smrg first = FcFalse; 3782c393a42Smrg } 3792c393a42Smrg cache_print_set (fs, dirs, FcCacheDir (cache), verbose); 3802c393a42Smrg 3812c393a42Smrg FcStrSetDestroy (dirs); 3822c393a42Smrg 3832c393a42Smrg FcFontSetDestroy (fs); 3842c393a42Smrg FcDirCacheUnload (cache); 3852c393a42Smrg if (cache_file) 3862c393a42Smrg FcStrFree (cache_file); 3872c393a42Smrg } 388953daebaSmrg FcStrListDone (arglist); 3892c393a42Smrg 390ca08ab68Smrg FcFini (); 3912c393a42Smrg return 0; 3922c393a42Smrg} 393