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> 39a4e54154Smrg#ifdef HAVE_UNISTD_H 402c393a42Smrg#include <unistd.h> 41a4e54154Smrg#endif 422c393a42Smrg#include <sys/types.h> 432c393a42Smrg#include <sys/stat.h> 442c393a42Smrg#include <errno.h> 45a32e9e42Smrg#include <locale.h> 46a32e9e42Smrg 47a32e9e42Smrg#ifdef ENABLE_NLS 48a32e9e42Smrg#include <libintl.h> 49a32e9e42Smrg#define _(x) (dgettext(GETTEXT_PACKAGE, x)) 50a32e9e42Smrg#else 51a32e9e42Smrg#define dgettext(d, s) (s) 52a32e9e42Smrg#define _(x) (x) 53a32e9e42Smrg#endif 542c393a42Smrg 552c393a42Smrg#ifndef HAVE_GETOPT 562c393a42Smrg#define HAVE_GETOPT 0 572c393a42Smrg#endif 582c393a42Smrg#ifndef HAVE_GETOPT_LONG 592c393a42Smrg#define HAVE_GETOPT_LONG 0 602c393a42Smrg#endif 612c393a42Smrg 622c393a42Smrg#if HAVE_GETOPT_LONG 632c393a42Smrg#undef _GNU_SOURCE 642c393a42Smrg#define _GNU_SOURCE 652c393a42Smrg#include <getopt.h> 662c393a42Smrgconst struct option longopts[] = { 672c393a42Smrg {"version", 0, 0, 'V'}, 682c393a42Smrg {"verbose", 0, 0, 'v'}, 692c393a42Smrg {"recurse", 0, 0, 'r'}, 70a6844aabSmrg {"help", 0, 0, 'h'}, 712c393a42Smrg {NULL,0,0,0}, 722c393a42Smrg}; 732c393a42Smrg#else 742c393a42Smrg#if HAVE_GETOPT 752c393a42Smrgextern char *optarg; 762c393a42Smrgextern int optind, opterr, optopt; 772c393a42Smrg#endif 782c393a42Smrg#endif 792c393a42Smrg 802c393a42Smrg/* 81c9710b42Smrg * POSIX has broken stdio so that putc must do thread-safe locking, 822c393a42Smrg * this is a serious performance problem for applications doing large 83c9710b42Smrg * amounts of IO with putc (as is done here). If available, use 84a4e54154Smrg * the putc_unlocked variant instead. 852c393a42Smrg */ 862c393a42Smrg 87c9710b42Smrg#if defined(putc_unlocked) || defined(_IO_putc_unlocked) 882c393a42Smrg#define PUTC(c,f) putc_unlocked(c,f) 892c393a42Smrg#else 902c393a42Smrg#define PUTC(c,f) putc(c,f) 912c393a42Smrg#endif 922c393a42Smrg 932c393a42Smrgstatic FcBool 942c393a42Smrgwrite_chars (FILE *f, const FcChar8 *chars) 952c393a42Smrg{ 962c393a42Smrg FcChar8 c; 972c393a42Smrg while ((c = *chars++)) 982c393a42Smrg { 992c393a42Smrg switch (c) { 1002c393a42Smrg case '"': 1012c393a42Smrg case '\\': 1022c393a42Smrg if (PUTC ('\\', f) == EOF) 1032c393a42Smrg return FcFalse; 1042c393a42Smrg /* fall through */ 1052c393a42Smrg default: 1062c393a42Smrg if (PUTC (c, f) == EOF) 1072c393a42Smrg return FcFalse; 1082c393a42Smrg } 1092c393a42Smrg } 1102c393a42Smrg return FcTrue; 1112c393a42Smrg} 1122c393a42Smrg 1132c393a42Smrgstatic FcBool 1142c393a42Smrgwrite_ulong (FILE *f, unsigned long t) 1152c393a42Smrg{ 1162c393a42Smrg int pow; 1172c393a42Smrg unsigned long temp, digit; 1182c393a42Smrg 1192c393a42Smrg temp = t; 1202c393a42Smrg pow = 1; 1212c393a42Smrg while (temp >= 10) 1222c393a42Smrg { 1232c393a42Smrg temp /= 10; 1242c393a42Smrg pow *= 10; 1252c393a42Smrg } 1262c393a42Smrg temp = t; 1272c393a42Smrg while (pow) 1282c393a42Smrg { 1292c393a42Smrg digit = temp / pow; 1302c393a42Smrg if (PUTC ((char) digit + '0', f) == EOF) 1312c393a42Smrg return FcFalse; 1322c393a42Smrg temp = temp - pow * digit; 1332c393a42Smrg pow = pow / 10; 1342c393a42Smrg } 1352c393a42Smrg return FcTrue; 1362c393a42Smrg} 1372c393a42Smrg 1382c393a42Smrgstatic FcBool 1392c393a42Smrgwrite_int (FILE *f, int i) 1402c393a42Smrg{ 1412c393a42Smrg return write_ulong (f, (unsigned long) i); 1422c393a42Smrg} 1432c393a42Smrg 1442c393a42Smrgstatic FcBool 1452c393a42Smrgwrite_string (FILE *f, const FcChar8 *string) 1462c393a42Smrg{ 1472c393a42Smrg 1482c393a42Smrg if (PUTC ('"', f) == EOF) 1492c393a42Smrg return FcFalse; 1502c393a42Smrg if (!write_chars (f, string)) 1512c393a42Smrg return FcFalse; 1522c393a42Smrg if (PUTC ('"', f) == EOF) 1532c393a42Smrg return FcFalse; 1542c393a42Smrg return FcTrue; 1552c393a42Smrg} 1562c393a42Smrg 1572c393a42Smrgstatic void 158a6844aabSmrgusage (char *program, int error) 1592c393a42Smrg{ 160a6844aabSmrg FILE *file = error ? stderr : stdout; 1612c393a42Smrg#if HAVE_GETOPT_LONG 162a32e9e42Smrg fprintf (file, _("usage: %s [-rv] [--recurse] [--verbose] [*-%s" FC_CACHE_SUFFIX "|directory]...\n"), 1632c393a42Smrg program, FC_ARCHITECTURE); 164a6844aabSmrg fprintf (file, " %s [-Vh] [--version] [--help]\n", program); 1652c393a42Smrg#else 166a32e9e42Smrg fprintf (file, _("usage: %s [-rvVh] [*-%s" FC_CACHE_SUFFIX "|directory]...\n"), 1672c393a42Smrg program, FC_ARCHITECTURE); 1682c393a42Smrg#endif 169a32e9e42Smrg fprintf (file, _("Reads font information cache from:\n")); 170a32e9e42Smrg fprintf (file, _(" 1) specified fontconfig cache file\n")); 171a32e9e42Smrg fprintf (file, _(" 2) related to a particular font directory\n")); 172a6844aabSmrg fprintf (file, "\n"); 1732c393a42Smrg#if HAVE_GETOPT_LONG 174a32e9e42Smrg fprintf (file, _(" -r, --recurse recurse into subdirectories\n")); 175a32e9e42Smrg fprintf (file, _(" -v, --verbose be verbose\n")); 176a32e9e42Smrg fprintf (file, _(" -V, --version display font config version and exit\n")); 177a32e9e42Smrg fprintf (file, _(" -h, --help display this help and exit\n")); 1782c393a42Smrg#else 179a32e9e42Smrg fprintf (file, _(" -r (recurse) recurse into subdirectories\n")); 180a32e9e42Smrg fprintf (file, _(" -v (verbose) be verbose\n")); 181a32e9e42Smrg fprintf (file, _(" -V (version) display font config version and exit\n")); 182a32e9e42Smrg fprintf (file, _(" -h (help) display this help and exit\n")); 1832c393a42Smrg#endif 184a6844aabSmrg exit (error); 1852c393a42Smrg} 1862c393a42Smrg 1872c393a42Smrg/* 1882c393a42Smrg * return the path from the directory containing 'cache' to 'file' 1892c393a42Smrg */ 1902c393a42Smrg 1912c393a42Smrgstatic const FcChar8 * 1922c393a42Smrgfile_base_name (const FcChar8 *cache, const FcChar8 *file) 1932c393a42Smrg{ 1942c393a42Smrg int cache_len = strlen ((char *) cache); 1952c393a42Smrg 1962c393a42Smrg if (!strncmp ((char *) cache, (char *) file, cache_len) && file[cache_len] == '/') 1972c393a42Smrg return file + cache_len + 1; 1982c393a42Smrg return file; 1992c393a42Smrg} 2002c393a42Smrg 2012c393a42Smrg#define FC_FONT_FILE_DIR ((FcChar8 *) ".dir") 2022c393a42Smrg 2032c393a42Smrgstatic FcBool 2042c393a42Smrgcache_print_set (FcFontSet *set, FcStrSet *dirs, const FcChar8 *base_name, FcBool verbose) 2052c393a42Smrg{ 206ca08ab68Smrg FcChar8 *dir; 207ca08ab68Smrg const FcChar8 *base; 2082c393a42Smrg int n; 2092c393a42Smrg int ndir = 0; 2102c393a42Smrg FcStrList *list; 2112c393a42Smrg 2122c393a42Smrg list = FcStrListCreate (dirs); 2132c393a42Smrg if (!list) 2142c393a42Smrg goto bail2; 2152c393a42Smrg 2162c393a42Smrg while ((dir = FcStrListNext (list))) 2172c393a42Smrg { 2182c393a42Smrg base = file_base_name (base_name, dir); 2192c393a42Smrg if (!write_string (stdout, base)) 2202c393a42Smrg goto bail3; 2212c393a42Smrg if (PUTC (' ', stdout) == EOF) 2222c393a42Smrg goto bail3; 2232c393a42Smrg if (!write_int (stdout, 0)) 2242c393a42Smrg goto bail3; 2252c393a42Smrg if (PUTC (' ', stdout) == EOF) 2262c393a42Smrg goto bail3; 2272c393a42Smrg if (!write_string (stdout, FC_FONT_FILE_DIR)) 2282c393a42Smrg goto bail3; 2292c393a42Smrg if (PUTC ('\n', stdout) == EOF) 2302c393a42Smrg goto bail3; 2312c393a42Smrg ndir++; 2322c393a42Smrg } 2332c393a42Smrg 2342c393a42Smrg for (n = 0; n < set->nfont; n++) 2352c393a42Smrg { 2362c393a42Smrg FcPattern *font = set->fonts[n]; 237ca08ab68Smrg FcChar8 *s; 2382c393a42Smrg 239ca08ab68Smrg s = FcPatternFormat (font, (const FcChar8 *) "%{=fccat}\n"); 240ca08ab68Smrg if (s) 241ca08ab68Smrg { 242ca08ab68Smrg printf ("%s", s); 243ca08ab68Smrg FcStrFree (s); 244ca08ab68Smrg } 2452c393a42Smrg } 2462c393a42Smrg if (verbose && !set->nfont && !ndir) 2472c393a42Smrg printf ("<empty>\n"); 248ca08ab68Smrg 2492c393a42Smrg FcStrListDone (list); 2502c393a42Smrg 2512c393a42Smrg return FcTrue; 252ca08ab68Smrg 2532c393a42Smrgbail3: 2542c393a42Smrg FcStrListDone (list); 2552c393a42Smrgbail2: 2562c393a42Smrg return FcFalse; 2572c393a42Smrg} 2582c393a42Smrg 2592c393a42Smrgint 2602c393a42Smrgmain (int argc, char **argv) 2612c393a42Smrg{ 2622c393a42Smrg int i; 2632c393a42Smrg int ret = 0; 2642c393a42Smrg FcFontSet *fs; 2652c393a42Smrg FcStrSet *dirs; 2662c393a42Smrg FcStrSet *args = NULL; 2672c393a42Smrg FcStrList *arglist; 2682c393a42Smrg FcCache *cache; 2692c393a42Smrg FcConfig *config; 2702c393a42Smrg FcChar8 *arg; 2712c393a42Smrg int verbose = 0; 2722c393a42Smrg int recurse = 0; 2732c393a42Smrg FcBool first = FcTrue; 2742c393a42Smrg#if HAVE_GETOPT_LONG || HAVE_GETOPT 2752c393a42Smrg int c; 2762c393a42Smrg 277a32e9e42Smrg setlocale (LC_ALL, ""); 2782c393a42Smrg#if HAVE_GETOPT_LONG 279a6844aabSmrg while ((c = getopt_long (argc, argv, "Vvrh", longopts, NULL)) != -1) 2802c393a42Smrg#else 281a6844aabSmrg while ((c = getopt (argc, argv, "Vvrh")) != -1) 2822c393a42Smrg#endif 2832c393a42Smrg { 2842c393a42Smrg switch (c) { 2852c393a42Smrg case 'V': 2862c393a42Smrg fprintf (stderr, "fontconfig version %d.%d.%d\n", 2872c393a42Smrg FC_MAJOR, FC_MINOR, FC_REVISION); 2882c393a42Smrg exit (0); 2892c393a42Smrg case 'v': 2902c393a42Smrg verbose++; 2912c393a42Smrg break; 2922c393a42Smrg case 'r': 2932c393a42Smrg recurse++; 2942c393a42Smrg break; 295a6844aabSmrg case 'h': 296a6844aabSmrg usage (argv[0], 0); 2972c393a42Smrg default: 298a6844aabSmrg usage (argv[0], 1); 2992c393a42Smrg } 3002c393a42Smrg } 3012c393a42Smrg i = optind; 3022c393a42Smrg#else 3032c393a42Smrg i = 1; 3042c393a42Smrg#endif 3052c393a42Smrg 3062c393a42Smrg config = FcInitLoadConfig (); 3072c393a42Smrg if (!config) 3082c393a42Smrg { 309a32e9e42Smrg fprintf (stderr, _("%s: Can't initialize font config library\n"), argv[0]); 3102c393a42Smrg return 1; 3112c393a42Smrg } 3122c393a42Smrg FcConfigSetCurrent (config); 313953daebaSmrg FcConfigDestroy (config); 3142c393a42Smrg 3152c393a42Smrg args = FcStrSetCreate (); 3162c393a42Smrg if (!args) 3172c393a42Smrg { 318a32e9e42Smrg fprintf (stderr, _("%s: malloc failure\n"), argv[0]); 3192c393a42Smrg return 1; 3202c393a42Smrg } 3212c393a42Smrg if (i < argc) 3222c393a42Smrg { 3232c393a42Smrg for (; i < argc; i++) 3242c393a42Smrg { 3252c393a42Smrg if (!FcStrSetAddFilename (args, (const FcChar8 *) argv[i])) 3262c393a42Smrg { 327a32e9e42Smrg fprintf (stderr, _("%s: malloc failure\n"), argv[0]); 3282c393a42Smrg return 1; 3292c393a42Smrg } 3302c393a42Smrg } 3312c393a42Smrg } 3322c393a42Smrg else 3332c393a42Smrg { 3342c393a42Smrg recurse++; 3352c393a42Smrg arglist = FcConfigGetFontDirs (config); 3362c393a42Smrg while ((arg = FcStrListNext (arglist))) 3372c393a42Smrg if (!FcStrSetAdd (args, arg)) 3382c393a42Smrg { 339a32e9e42Smrg fprintf (stderr, _("%s: malloc failure\n"), argv[0]); 3402c393a42Smrg return 1; 3412c393a42Smrg } 3422c393a42Smrg FcStrListDone (arglist); 3432c393a42Smrg } 3442c393a42Smrg arglist = FcStrListCreate (args); 3452c393a42Smrg if (!arglist) 3462c393a42Smrg { 347a32e9e42Smrg fprintf (stderr, _("%s: malloc failure\n"), argv[0]); 3482c393a42Smrg return 1; 3492c393a42Smrg } 350953daebaSmrg FcStrSetDestroy (args); 3512c393a42Smrg 3522c393a42Smrg while ((arg = FcStrListNext (arglist))) 3532c393a42Smrg { 3542c393a42Smrg int j; 3552c393a42Smrg FcChar8 *cache_file = NULL; 3562c393a42Smrg struct stat file_stat; 357953daebaSmrg 358953daebaSmrg /* reset errno */ 359953daebaSmrg errno = 0; 3602c393a42Smrg if (FcFileIsDir (arg)) 3612c393a42Smrg cache = FcDirCacheLoad (arg, config, &cache_file); 3622c393a42Smrg else 3632c393a42Smrg cache = FcDirCacheLoadFile (arg, &file_stat); 3642c393a42Smrg if (!cache) 3652c393a42Smrg { 366953daebaSmrg if (errno != 0) 367953daebaSmrg perror ((char *) arg); 368953daebaSmrg else 369953daebaSmrg fprintf (stderr, "%s: Unable to load the cache: %s\n", argv[0], arg); 3702c393a42Smrg ret++; 3712c393a42Smrg continue; 3722c393a42Smrg } 3732c393a42Smrg 3742c393a42Smrg dirs = FcStrSetCreate (); 3752c393a42Smrg fs = FcCacheCopySet (cache); 3762c393a42Smrg for (j = 0; j < FcCacheNumSubdir (cache); j++) 3772c393a42Smrg { 3782c393a42Smrg FcStrSetAdd (dirs, FcCacheSubdir (cache, j)); 3792c393a42Smrg if (recurse) 3802c393a42Smrg FcStrSetAdd (args, FcCacheSubdir (cache, j)); 3812c393a42Smrg } 3822c393a42Smrg 3832c393a42Smrg if (verbose) 3842c393a42Smrg { 3852c393a42Smrg if (!first) 3862c393a42Smrg printf ("\n"); 387a32e9e42Smrg printf (_("Directory: %s\nCache: %s\n--------\n"), 3882c393a42Smrg FcCacheDir(cache), cache_file ? cache_file : arg); 3892c393a42Smrg first = FcFalse; 3902c393a42Smrg } 3912c393a42Smrg cache_print_set (fs, dirs, FcCacheDir (cache), verbose); 3922c393a42Smrg 3932c393a42Smrg FcStrSetDestroy (dirs); 3942c393a42Smrg 3952c393a42Smrg FcFontSetDestroy (fs); 3962c393a42Smrg FcDirCacheUnload (cache); 3972c393a42Smrg if (cache_file) 3982c393a42Smrg FcStrFree (cache_file); 3992c393a42Smrg } 400953daebaSmrg FcStrListDone (arglist); 4012c393a42Smrg 402ca08ab68Smrg FcFini (); 4032c393a42Smrg return 0; 4042c393a42Smrg} 405