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