fc-cat.c revision a32e9e42
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> 43a32e9e42Smrg#include <locale.h> 44a32e9e42Smrg 45a32e9e42Smrg#ifdef ENABLE_NLS 46a32e9e42Smrg#include <libintl.h> 47a32e9e42Smrg#define _(x) (dgettext(GETTEXT_PACKAGE, x)) 48a32e9e42Smrg#else 49a32e9e42Smrg#define dgettext(d, s) (s) 50a32e9e42Smrg#define _(x) (x) 51a32e9e42Smrg#endif 522c393a42Smrg 532c393a42Smrg#ifndef HAVE_GETOPT 542c393a42Smrg#define HAVE_GETOPT 0 552c393a42Smrg#endif 562c393a42Smrg#ifndef HAVE_GETOPT_LONG 572c393a42Smrg#define HAVE_GETOPT_LONG 0 582c393a42Smrg#endif 592c393a42Smrg 602c393a42Smrg#if HAVE_GETOPT_LONG 612c393a42Smrg#undef _GNU_SOURCE 622c393a42Smrg#define _GNU_SOURCE 632c393a42Smrg#include <getopt.h> 642c393a42Smrgconst struct option longopts[] = { 652c393a42Smrg {"version", 0, 0, 'V'}, 662c393a42Smrg {"verbose", 0, 0, 'v'}, 672c393a42Smrg {"recurse", 0, 0, 'r'}, 68a6844aabSmrg {"help", 0, 0, 'h'}, 692c393a42Smrg {NULL,0,0,0}, 702c393a42Smrg}; 712c393a42Smrg#else 722c393a42Smrg#if HAVE_GETOPT 732c393a42Smrgextern char *optarg; 742c393a42Smrgextern int optind, opterr, optopt; 752c393a42Smrg#endif 762c393a42Smrg#endif 772c393a42Smrg 782c393a42Smrg/* 79c9710b42Smrg * POSIX has broken stdio so that putc must do thread-safe locking, 802c393a42Smrg * this is a serious performance problem for applications doing large 81c9710b42Smrg * amounts of IO with putc (as is done here). If available, use 82c9710b42Smrg * the putc_unlocked varient instead. 832c393a42Smrg */ 842c393a42Smrg 85c9710b42Smrg#if defined(putc_unlocked) || defined(_IO_putc_unlocked) 862c393a42Smrg#define PUTC(c,f) putc_unlocked(c,f) 872c393a42Smrg#else 882c393a42Smrg#define PUTC(c,f) putc(c,f) 892c393a42Smrg#endif 902c393a42Smrg 912c393a42Smrgstatic FcBool 922c393a42Smrgwrite_chars (FILE *f, const FcChar8 *chars) 932c393a42Smrg{ 942c393a42Smrg FcChar8 c; 952c393a42Smrg while ((c = *chars++)) 962c393a42Smrg { 972c393a42Smrg switch (c) { 982c393a42Smrg case '"': 992c393a42Smrg case '\\': 1002c393a42Smrg if (PUTC ('\\', f) == EOF) 1012c393a42Smrg return FcFalse; 1022c393a42Smrg /* fall through */ 1032c393a42Smrg default: 1042c393a42Smrg if (PUTC (c, f) == EOF) 1052c393a42Smrg return FcFalse; 1062c393a42Smrg } 1072c393a42Smrg } 1082c393a42Smrg return FcTrue; 1092c393a42Smrg} 1102c393a42Smrg 1112c393a42Smrgstatic FcBool 1122c393a42Smrgwrite_ulong (FILE *f, unsigned long t) 1132c393a42Smrg{ 1142c393a42Smrg int pow; 1152c393a42Smrg unsigned long temp, digit; 1162c393a42Smrg 1172c393a42Smrg temp = t; 1182c393a42Smrg pow = 1; 1192c393a42Smrg while (temp >= 10) 1202c393a42Smrg { 1212c393a42Smrg temp /= 10; 1222c393a42Smrg pow *= 10; 1232c393a42Smrg } 1242c393a42Smrg temp = t; 1252c393a42Smrg while (pow) 1262c393a42Smrg { 1272c393a42Smrg digit = temp / pow; 1282c393a42Smrg if (PUTC ((char) digit + '0', f) == EOF) 1292c393a42Smrg return FcFalse; 1302c393a42Smrg temp = temp - pow * digit; 1312c393a42Smrg pow = pow / 10; 1322c393a42Smrg } 1332c393a42Smrg return FcTrue; 1342c393a42Smrg} 1352c393a42Smrg 1362c393a42Smrgstatic FcBool 1372c393a42Smrgwrite_int (FILE *f, int i) 1382c393a42Smrg{ 1392c393a42Smrg return write_ulong (f, (unsigned long) i); 1402c393a42Smrg} 1412c393a42Smrg 1422c393a42Smrgstatic FcBool 1432c393a42Smrgwrite_string (FILE *f, const FcChar8 *string) 1442c393a42Smrg{ 1452c393a42Smrg 1462c393a42Smrg if (PUTC ('"', f) == EOF) 1472c393a42Smrg return FcFalse; 1482c393a42Smrg if (!write_chars (f, string)) 1492c393a42Smrg return FcFalse; 1502c393a42Smrg if (PUTC ('"', f) == EOF) 1512c393a42Smrg return FcFalse; 1522c393a42Smrg return FcTrue; 1532c393a42Smrg} 1542c393a42Smrg 1552c393a42Smrgstatic void 156a6844aabSmrgusage (char *program, int error) 1572c393a42Smrg{ 158a6844aabSmrg FILE *file = error ? stderr : stdout; 1592c393a42Smrg#if HAVE_GETOPT_LONG 160a32e9e42Smrg fprintf (file, _("usage: %s [-rv] [--recurse] [--verbose] [*-%s" FC_CACHE_SUFFIX "|directory]...\n"), 1612c393a42Smrg program, FC_ARCHITECTURE); 162a6844aabSmrg fprintf (file, " %s [-Vh] [--version] [--help]\n", program); 1632c393a42Smrg#else 164a32e9e42Smrg fprintf (file, _("usage: %s [-rvVh] [*-%s" FC_CACHE_SUFFIX "|directory]...\n"), 1652c393a42Smrg program, FC_ARCHITECTURE); 1662c393a42Smrg#endif 167a32e9e42Smrg fprintf (file, _("Reads font information cache from:\n")); 168a32e9e42Smrg fprintf (file, _(" 1) specified fontconfig cache file\n")); 169a32e9e42Smrg fprintf (file, _(" 2) related to a particular font directory\n")); 170a6844aabSmrg fprintf (file, "\n"); 1712c393a42Smrg#if HAVE_GETOPT_LONG 172a32e9e42Smrg fprintf (file, _(" -r, --recurse recurse into subdirectories\n")); 173a32e9e42Smrg fprintf (file, _(" -v, --verbose be verbose\n")); 174a32e9e42Smrg fprintf (file, _(" -V, --version display font config version and exit\n")); 175a32e9e42Smrg fprintf (file, _(" -h, --help display this help and exit\n")); 1762c393a42Smrg#else 177a32e9e42Smrg fprintf (file, _(" -r (recurse) recurse into subdirectories\n")); 178a32e9e42Smrg fprintf (file, _(" -v (verbose) be verbose\n")); 179a32e9e42Smrg fprintf (file, _(" -V (version) display font config version and exit\n")); 180a32e9e42Smrg fprintf (file, _(" -h (help) display this help and exit\n")); 1812c393a42Smrg#endif 182a6844aabSmrg exit (error); 1832c393a42Smrg} 1842c393a42Smrg 1852c393a42Smrg/* 1862c393a42Smrg * return the path from the directory containing 'cache' to 'file' 1872c393a42Smrg */ 1882c393a42Smrg 1892c393a42Smrgstatic const FcChar8 * 1902c393a42Smrgfile_base_name (const FcChar8 *cache, const FcChar8 *file) 1912c393a42Smrg{ 1922c393a42Smrg int cache_len = strlen ((char *) cache); 1932c393a42Smrg 1942c393a42Smrg if (!strncmp ((char *) cache, (char *) file, cache_len) && file[cache_len] == '/') 1952c393a42Smrg return file + cache_len + 1; 1962c393a42Smrg return file; 1972c393a42Smrg} 1982c393a42Smrg 1992c393a42Smrg#define FC_FONT_FILE_DIR ((FcChar8 *) ".dir") 2002c393a42Smrg 2012c393a42Smrgstatic FcBool 2022c393a42Smrgcache_print_set (FcFontSet *set, FcStrSet *dirs, const FcChar8 *base_name, FcBool verbose) 2032c393a42Smrg{ 204ca08ab68Smrg FcChar8 *dir; 205ca08ab68Smrg const FcChar8 *base; 2062c393a42Smrg int n; 2072c393a42Smrg int ndir = 0; 2082c393a42Smrg FcStrList *list; 2092c393a42Smrg 2102c393a42Smrg list = FcStrListCreate (dirs); 2112c393a42Smrg if (!list) 2122c393a42Smrg goto bail2; 2132c393a42Smrg 2142c393a42Smrg while ((dir = FcStrListNext (list))) 2152c393a42Smrg { 2162c393a42Smrg base = file_base_name (base_name, dir); 2172c393a42Smrg if (!write_string (stdout, base)) 2182c393a42Smrg goto bail3; 2192c393a42Smrg if (PUTC (' ', stdout) == EOF) 2202c393a42Smrg goto bail3; 2212c393a42Smrg if (!write_int (stdout, 0)) 2222c393a42Smrg goto bail3; 2232c393a42Smrg if (PUTC (' ', stdout) == EOF) 2242c393a42Smrg goto bail3; 2252c393a42Smrg if (!write_string (stdout, FC_FONT_FILE_DIR)) 2262c393a42Smrg goto bail3; 2272c393a42Smrg if (PUTC ('\n', stdout) == EOF) 2282c393a42Smrg goto bail3; 2292c393a42Smrg ndir++; 2302c393a42Smrg } 2312c393a42Smrg 2322c393a42Smrg for (n = 0; n < set->nfont; n++) 2332c393a42Smrg { 2342c393a42Smrg FcPattern *font = set->fonts[n]; 235ca08ab68Smrg FcChar8 *s; 2362c393a42Smrg 237ca08ab68Smrg s = FcPatternFormat (font, (const FcChar8 *) "%{=fccat}\n"); 238ca08ab68Smrg if (s) 239ca08ab68Smrg { 240ca08ab68Smrg printf ("%s", s); 241ca08ab68Smrg FcStrFree (s); 242ca08ab68Smrg } 2432c393a42Smrg } 2442c393a42Smrg if (verbose && !set->nfont && !ndir) 2452c393a42Smrg printf ("<empty>\n"); 246ca08ab68Smrg 2472c393a42Smrg FcStrListDone (list); 2482c393a42Smrg 2492c393a42Smrg return FcTrue; 250ca08ab68Smrg 2512c393a42Smrgbail3: 2522c393a42Smrg FcStrListDone (list); 2532c393a42Smrgbail2: 2542c393a42Smrg return FcFalse; 2552c393a42Smrg} 2562c393a42Smrg 2572c393a42Smrgint 2582c393a42Smrgmain (int argc, char **argv) 2592c393a42Smrg{ 2602c393a42Smrg int i; 2612c393a42Smrg int ret = 0; 2622c393a42Smrg FcFontSet *fs; 2632c393a42Smrg FcStrSet *dirs; 2642c393a42Smrg FcStrSet *args = NULL; 2652c393a42Smrg FcStrList *arglist; 2662c393a42Smrg FcCache *cache; 2672c393a42Smrg FcConfig *config; 2682c393a42Smrg FcChar8 *arg; 2692c393a42Smrg int verbose = 0; 2702c393a42Smrg int recurse = 0; 2712c393a42Smrg FcBool first = FcTrue; 2722c393a42Smrg#if HAVE_GETOPT_LONG || HAVE_GETOPT 2732c393a42Smrg int c; 2742c393a42Smrg 275a32e9e42Smrg setlocale (LC_ALL, ""); 2762c393a42Smrg#if HAVE_GETOPT_LONG 277a6844aabSmrg while ((c = getopt_long (argc, argv, "Vvrh", longopts, NULL)) != -1) 2782c393a42Smrg#else 279a6844aabSmrg while ((c = getopt (argc, argv, "Vvrh")) != -1) 2802c393a42Smrg#endif 2812c393a42Smrg { 2822c393a42Smrg switch (c) { 2832c393a42Smrg case 'V': 2842c393a42Smrg fprintf (stderr, "fontconfig version %d.%d.%d\n", 2852c393a42Smrg FC_MAJOR, FC_MINOR, FC_REVISION); 2862c393a42Smrg exit (0); 2872c393a42Smrg case 'v': 2882c393a42Smrg verbose++; 2892c393a42Smrg break; 2902c393a42Smrg case 'r': 2912c393a42Smrg recurse++; 2922c393a42Smrg break; 293a6844aabSmrg case 'h': 294a6844aabSmrg usage (argv[0], 0); 2952c393a42Smrg default: 296a6844aabSmrg usage (argv[0], 1); 2972c393a42Smrg } 2982c393a42Smrg } 2992c393a42Smrg i = optind; 3002c393a42Smrg#else 3012c393a42Smrg i = 1; 3022c393a42Smrg#endif 3032c393a42Smrg 3042c393a42Smrg config = FcInitLoadConfig (); 3052c393a42Smrg if (!config) 3062c393a42Smrg { 307a32e9e42Smrg fprintf (stderr, _("%s: Can't initialize font config library\n"), argv[0]); 3082c393a42Smrg return 1; 3092c393a42Smrg } 3102c393a42Smrg FcConfigSetCurrent (config); 311953daebaSmrg FcConfigDestroy (config); 3122c393a42Smrg 3132c393a42Smrg args = FcStrSetCreate (); 3142c393a42Smrg if (!args) 3152c393a42Smrg { 316a32e9e42Smrg fprintf (stderr, _("%s: malloc failure\n"), argv[0]); 3172c393a42Smrg return 1; 3182c393a42Smrg } 3192c393a42Smrg if (i < argc) 3202c393a42Smrg { 3212c393a42Smrg for (; i < argc; i++) 3222c393a42Smrg { 3232c393a42Smrg if (!FcStrSetAddFilename (args, (const FcChar8 *) argv[i])) 3242c393a42Smrg { 325a32e9e42Smrg fprintf (stderr, _("%s: malloc failure\n"), argv[0]); 3262c393a42Smrg return 1; 3272c393a42Smrg } 3282c393a42Smrg } 3292c393a42Smrg } 3302c393a42Smrg else 3312c393a42Smrg { 3322c393a42Smrg recurse++; 3332c393a42Smrg arglist = FcConfigGetFontDirs (config); 3342c393a42Smrg while ((arg = FcStrListNext (arglist))) 3352c393a42Smrg if (!FcStrSetAdd (args, arg)) 3362c393a42Smrg { 337a32e9e42Smrg fprintf (stderr, _("%s: malloc failure\n"), argv[0]); 3382c393a42Smrg return 1; 3392c393a42Smrg } 3402c393a42Smrg FcStrListDone (arglist); 3412c393a42Smrg } 3422c393a42Smrg arglist = FcStrListCreate (args); 3432c393a42Smrg if (!arglist) 3442c393a42Smrg { 345a32e9e42Smrg fprintf (stderr, _("%s: malloc failure\n"), argv[0]); 3462c393a42Smrg return 1; 3472c393a42Smrg } 348953daebaSmrg FcStrSetDestroy (args); 3492c393a42Smrg 3502c393a42Smrg while ((arg = FcStrListNext (arglist))) 3512c393a42Smrg { 3522c393a42Smrg int j; 3532c393a42Smrg FcChar8 *cache_file = NULL; 3542c393a42Smrg struct stat file_stat; 355953daebaSmrg 356953daebaSmrg /* reset errno */ 357953daebaSmrg errno = 0; 3582c393a42Smrg if (FcFileIsDir (arg)) 3592c393a42Smrg cache = FcDirCacheLoad (arg, config, &cache_file); 3602c393a42Smrg else 3612c393a42Smrg cache = FcDirCacheLoadFile (arg, &file_stat); 3622c393a42Smrg if (!cache) 3632c393a42Smrg { 364953daebaSmrg if (errno != 0) 365953daebaSmrg perror ((char *) arg); 366953daebaSmrg else 367953daebaSmrg fprintf (stderr, "%s: Unable to load the cache: %s\n", argv[0], arg); 3682c393a42Smrg ret++; 3692c393a42Smrg continue; 3702c393a42Smrg } 3712c393a42Smrg 3722c393a42Smrg dirs = FcStrSetCreate (); 3732c393a42Smrg fs = FcCacheCopySet (cache); 3742c393a42Smrg for (j = 0; j < FcCacheNumSubdir (cache); j++) 3752c393a42Smrg { 3762c393a42Smrg FcStrSetAdd (dirs, FcCacheSubdir (cache, j)); 3772c393a42Smrg if (recurse) 3782c393a42Smrg FcStrSetAdd (args, FcCacheSubdir (cache, j)); 3792c393a42Smrg } 3802c393a42Smrg 3812c393a42Smrg if (verbose) 3822c393a42Smrg { 3832c393a42Smrg if (!first) 3842c393a42Smrg printf ("\n"); 385a32e9e42Smrg printf (_("Directory: %s\nCache: %s\n--------\n"), 3862c393a42Smrg FcCacheDir(cache), cache_file ? cache_file : arg); 3872c393a42Smrg first = FcFalse; 3882c393a42Smrg } 3892c393a42Smrg cache_print_set (fs, dirs, FcCacheDir (cache), verbose); 3902c393a42Smrg 3912c393a42Smrg FcStrSetDestroy (dirs); 3922c393a42Smrg 3932c393a42Smrg FcFontSetDestroy (fs); 3942c393a42Smrg FcDirCacheUnload (cache); 3952c393a42Smrg if (cache_file) 3962c393a42Smrg FcStrFree (cache_file); 3972c393a42Smrg } 398953daebaSmrg FcStrListDone (arglist); 3992c393a42Smrg 400ca08ab68Smrg FcFini (); 4012c393a42Smrg return 0; 4022c393a42Smrg} 403