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