fc-cat.c revision a6844aab
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
102c393a42Smrg * documentation, and that the name of Keith Packard not be used in
112c393a42Smrg * advertising or publicity pertaining to distribution of the software without
122c393a42Smrg * specific, written prior permission.  Keith Packard makes 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>
352c393a42Smrg#include "../fc-arch/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/*
702c393a42Smrg * POSIX has broken stdio so that getc must do thread-safe locking,
712c393a42Smrg * this is a serious performance problem for applications doing large
722c393a42Smrg * amounts of IO with getc (as is done here).  If available, use
732c393a42Smrg * the getc_unlocked varient instead.
742c393a42Smrg */
752c393a42Smrg
762c393a42Smrg#if defined(getc_unlocked) || defined(_IO_getc_unlocked)
772c393a42Smrg#define GETC(f) getc_unlocked(f)
782c393a42Smrg#define PUTC(c,f) putc_unlocked(c,f)
792c393a42Smrg#else
802c393a42Smrg#define GETC(f) getc(f)
812c393a42Smrg#define PUTC(c,f) putc(c,f)
822c393a42Smrg#endif
832c393a42Smrg
842c393a42Smrgstatic FcBool
852c393a42Smrgwrite_chars (FILE *f, const FcChar8 *chars)
862c393a42Smrg{
872c393a42Smrg    FcChar8    c;
882c393a42Smrg    while ((c = *chars++))
892c393a42Smrg    {
902c393a42Smrg	switch (c) {
912c393a42Smrg	case '"':
922c393a42Smrg	case '\\':
932c393a42Smrg	    if (PUTC ('\\', f) == EOF)
942c393a42Smrg		return FcFalse;
952c393a42Smrg	    /* fall through */
962c393a42Smrg	default:
972c393a42Smrg	    if (PUTC (c, f) == EOF)
982c393a42Smrg		return FcFalse;
992c393a42Smrg	}
1002c393a42Smrg    }
1012c393a42Smrg    return FcTrue;
1022c393a42Smrg}
1032c393a42Smrg
1042c393a42Smrgstatic FcBool
1052c393a42Smrgwrite_ulong (FILE *f, unsigned long t)
1062c393a42Smrg{
1072c393a42Smrg    int	    pow;
1082c393a42Smrg    unsigned long   temp, digit;
1092c393a42Smrg
1102c393a42Smrg    temp = t;
1112c393a42Smrg    pow = 1;
1122c393a42Smrg    while (temp >= 10)
1132c393a42Smrg    {
1142c393a42Smrg	temp /= 10;
1152c393a42Smrg	pow *= 10;
1162c393a42Smrg    }
1172c393a42Smrg    temp = t;
1182c393a42Smrg    while (pow)
1192c393a42Smrg    {
1202c393a42Smrg	digit = temp / pow;
1212c393a42Smrg	if (PUTC ((char) digit + '0', f) == EOF)
1222c393a42Smrg	    return FcFalse;
1232c393a42Smrg	temp = temp - pow * digit;
1242c393a42Smrg	pow = pow / 10;
1252c393a42Smrg    }
1262c393a42Smrg    return FcTrue;
1272c393a42Smrg}
1282c393a42Smrg
1292c393a42Smrgstatic FcBool
1302c393a42Smrgwrite_int (FILE *f, int i)
1312c393a42Smrg{
1322c393a42Smrg    return write_ulong (f, (unsigned long) i);
1332c393a42Smrg}
1342c393a42Smrg
1352c393a42Smrgstatic FcBool
1362c393a42Smrgwrite_string (FILE *f, const FcChar8 *string)
1372c393a42Smrg{
1382c393a42Smrg
1392c393a42Smrg    if (PUTC ('"', f) == EOF)
1402c393a42Smrg	return FcFalse;
1412c393a42Smrg    if (!write_chars (f, string))
1422c393a42Smrg	return FcFalse;
1432c393a42Smrg    if (PUTC ('"', f) == EOF)
1442c393a42Smrg	return FcFalse;
1452c393a42Smrg    return FcTrue;
1462c393a42Smrg}
1472c393a42Smrg
1482c393a42Smrgstatic void
149a6844aabSmrgusage (char *program, int error)
1502c393a42Smrg{
151a6844aabSmrg    FILE *file = error ? stderr : stdout;
1522c393a42Smrg#if HAVE_GETOPT_LONG
153a6844aabSmrg    fprintf (file, "usage: %s [-rv] [--recurse] [--verbose] [*-%s.cache-2|directory]...\n",
1542c393a42Smrg	     program, FC_ARCHITECTURE);
155a6844aabSmrg    fprintf (file, "       %s [-Vh] [--version] [--help]\n", program);
1562c393a42Smrg#else
157a6844aabSmrg    fprintf (file, "usage: %s [-rvVh] [*-%s.cache-2|directory]...\n",
1582c393a42Smrg	     program, FC_ARCHITECTURE);
1592c393a42Smrg#endif
160a6844aabSmrg    fprintf (file, "Reads font information cache from:\n");
161a6844aabSmrg    fprintf (file, " 1) specified fontconfig cache file\n");
162a6844aabSmrg    fprintf (file, " 2) related to a particular font directory\n");
163a6844aabSmrg    fprintf (file, "\n");
1642c393a42Smrg#if HAVE_GETOPT_LONG
165a6844aabSmrg    fprintf (file, "  -r, --recurse        recurse into subdirectories\n");
166a6844aabSmrg    fprintf (file, "  -v, --verbose        be verbose\n");
167a6844aabSmrg    fprintf (file, "  -V, --version        display font config version and exit\n");
168a6844aabSmrg    fprintf (file, "  -h, --help           display this help and exit\n");
1692c393a42Smrg#else
170a6844aabSmrg    fprintf (file, "  -r         (recurse) recurse into subdirectories\n");
171a6844aabSmrg    fprintf (file, "  -v         (verbose) be verbose\n");
172a6844aabSmrg    fprintf (file, "  -V         (version) display font config version and exit\n");
173a6844aabSmrg    fprintf (file, "  -h         (help)    display this help and exit\n");
1742c393a42Smrg#endif
175a6844aabSmrg    exit (error);
1762c393a42Smrg}
1772c393a42Smrg
1782c393a42Smrg/*
1792c393a42Smrg * return the path from the directory containing 'cache' to 'file'
1802c393a42Smrg */
1812c393a42Smrg
1822c393a42Smrgstatic const FcChar8 *
1832c393a42Smrgfile_base_name (const FcChar8 *cache, const FcChar8 *file)
1842c393a42Smrg{
1852c393a42Smrg    int		    cache_len = strlen ((char *) cache);
1862c393a42Smrg
1872c393a42Smrg    if (!strncmp ((char *) cache, (char *) file, cache_len) && file[cache_len] == '/')
1882c393a42Smrg	return file + cache_len + 1;
1892c393a42Smrg    return file;
1902c393a42Smrg}
1912c393a42Smrg
1922c393a42Smrg#define FC_FONT_FILE_DIR	((FcChar8 *) ".dir")
1932c393a42Smrg
1942c393a42Smrgstatic FcBool
1952c393a42Smrgcache_print_set (FcFontSet *set, FcStrSet *dirs, const FcChar8 *base_name, FcBool verbose)
1962c393a42Smrg{
1972c393a42Smrg    FcChar8	    *name, *dir;
1982c393a42Smrg    const FcChar8   *file, *base;
1992c393a42Smrg    int		    ret;
2002c393a42Smrg    int		    n;
2012c393a42Smrg    int		    id;
2022c393a42Smrg    int		    ndir = 0;
2032c393a42Smrg    FcStrList	    *list;
2042c393a42Smrg
2052c393a42Smrg    list = FcStrListCreate (dirs);
2062c393a42Smrg    if (!list)
2072c393a42Smrg	goto bail2;
2082c393a42Smrg
2092c393a42Smrg    while ((dir = FcStrListNext (list)))
2102c393a42Smrg    {
2112c393a42Smrg	base = file_base_name (base_name, dir);
2122c393a42Smrg	if (!write_string (stdout, base))
2132c393a42Smrg	    goto bail3;
2142c393a42Smrg	if (PUTC (' ', stdout) == EOF)
2152c393a42Smrg	    goto bail3;
2162c393a42Smrg	if (!write_int (stdout, 0))
2172c393a42Smrg	    goto bail3;
2182c393a42Smrg        if (PUTC (' ', stdout) == EOF)
2192c393a42Smrg	    goto bail3;
2202c393a42Smrg	if (!write_string (stdout, FC_FONT_FILE_DIR))
2212c393a42Smrg	    goto bail3;
2222c393a42Smrg	if (PUTC ('\n', stdout) == EOF)
2232c393a42Smrg	    goto bail3;
2242c393a42Smrg	ndir++;
2252c393a42Smrg    }
2262c393a42Smrg
2272c393a42Smrg    for (n = 0; n < set->nfont; n++)
2282c393a42Smrg    {
2292c393a42Smrg	FcPattern   *font = set->fonts[n];
2302c393a42Smrg
2312c393a42Smrg	if (FcPatternGetString (font, FC_FILE, 0, (FcChar8 **) &file) != FcResultMatch)
2322c393a42Smrg	    goto bail3;
2332c393a42Smrg	base = file_base_name (base_name, file);
2342c393a42Smrg	if (FcPatternGetInteger (font, FC_INDEX, 0, &id) != FcResultMatch)
2352c393a42Smrg	    goto bail3;
2362c393a42Smrg	if (!write_string (stdout, base))
2372c393a42Smrg	    goto bail3;
2382c393a42Smrg	if (PUTC (' ', stdout) == EOF)
2392c393a42Smrg	    goto bail3;
2402c393a42Smrg	if (!write_int (stdout, id))
2412c393a42Smrg	    goto bail3;
2422c393a42Smrg        if (PUTC (' ', stdout) == EOF)
2432c393a42Smrg	    goto bail3;
2442c393a42Smrg	name = FcNameUnparse (font);
2452c393a42Smrg	if (!name)
2462c393a42Smrg	    goto bail3;
2472c393a42Smrg	ret = write_string (stdout, name);
2482c393a42Smrg	FcStrFree (name);
2492c393a42Smrg	if (!ret)
2502c393a42Smrg	    goto bail3;
2512c393a42Smrg	if (PUTC ('\n', stdout) == EOF)
2522c393a42Smrg	    goto bail3;
2532c393a42Smrg    }
2542c393a42Smrg    if (verbose && !set->nfont && !ndir)
2552c393a42Smrg	printf ("<empty>\n");
2562c393a42Smrg
2572c393a42Smrg    FcStrListDone (list);
2582c393a42Smrg
2592c393a42Smrg    return FcTrue;
2602c393a42Smrg
2612c393a42Smrgbail3:
2622c393a42Smrg    FcStrListDone (list);
2632c393a42Smrgbail2:
2642c393a42Smrg    return FcFalse;
2652c393a42Smrg}
2662c393a42Smrg
2672c393a42Smrgint
2682c393a42Smrgmain (int argc, char **argv)
2692c393a42Smrg{
2702c393a42Smrg    int		i;
2712c393a42Smrg    int		ret = 0;
2722c393a42Smrg    FcFontSet	*fs;
2732c393a42Smrg    FcStrSet    *dirs;
2742c393a42Smrg    FcStrSet	*args = NULL;
2752c393a42Smrg    FcStrList	*arglist;
2762c393a42Smrg    FcCache	*cache;
2772c393a42Smrg    FcConfig	*config;
2782c393a42Smrg    FcChar8	*arg;
2792c393a42Smrg    int		verbose = 0;
2802c393a42Smrg    int		recurse = 0;
2812c393a42Smrg    FcBool	first = FcTrue;
2822c393a42Smrg#if HAVE_GETOPT_LONG || HAVE_GETOPT
2832c393a42Smrg    int		c;
2842c393a42Smrg
2852c393a42Smrg#if HAVE_GETOPT_LONG
286a6844aabSmrg    while ((c = getopt_long (argc, argv, "Vvrh", longopts, NULL)) != -1)
2872c393a42Smrg#else
288a6844aabSmrg    while ((c = getopt (argc, argv, "Vvrh")) != -1)
2892c393a42Smrg#endif
2902c393a42Smrg    {
2912c393a42Smrg	switch (c) {
2922c393a42Smrg	case 'V':
2932c393a42Smrg	    fprintf (stderr, "fontconfig version %d.%d.%d\n",
2942c393a42Smrg		     FC_MAJOR, FC_MINOR, FC_REVISION);
2952c393a42Smrg	    exit (0);
2962c393a42Smrg	case 'v':
2972c393a42Smrg	    verbose++;
2982c393a42Smrg	    break;
2992c393a42Smrg	case 'r':
3002c393a42Smrg	    recurse++;
3012c393a42Smrg	    break;
302a6844aabSmrg	case 'h':
303a6844aabSmrg	    usage (argv[0], 0);
3042c393a42Smrg	default:
305a6844aabSmrg	    usage (argv[0], 1);
3062c393a42Smrg	}
3072c393a42Smrg    }
3082c393a42Smrg    i = optind;
3092c393a42Smrg#else
3102c393a42Smrg    i = 1;
3112c393a42Smrg#endif
3122c393a42Smrg
3132c393a42Smrg    config = FcInitLoadConfig ();
3142c393a42Smrg    if (!config)
3152c393a42Smrg    {
3162c393a42Smrg	fprintf (stderr, "%s: Can't init font config library\n", argv[0]);
3172c393a42Smrg	return 1;
3182c393a42Smrg    }
3192c393a42Smrg    FcConfigSetCurrent (config);
3202c393a42Smrg
3212c393a42Smrg    args = FcStrSetCreate ();
3222c393a42Smrg    if (!args)
3232c393a42Smrg    {
3242c393a42Smrg	fprintf (stderr, "%s: malloc failure\n", argv[0]);
3252c393a42Smrg	return 1;
3262c393a42Smrg    }
3272c393a42Smrg    if (i < argc)
3282c393a42Smrg    {
3292c393a42Smrg	for (; i < argc; i++)
3302c393a42Smrg	{
3312c393a42Smrg	    if (!FcStrSetAddFilename (args, (const FcChar8 *) argv[i]))
3322c393a42Smrg	    {
3332c393a42Smrg		fprintf (stderr, "%s: malloc failure\n", argv[0]);
3342c393a42Smrg		return 1;
3352c393a42Smrg	    }
3362c393a42Smrg	}
3372c393a42Smrg	arglist = FcStrListCreate (args);
3382c393a42Smrg	if (!arglist)
3392c393a42Smrg	{
3402c393a42Smrg	    fprintf (stderr, "%s: malloc failure\n", argv[0]);
3412c393a42Smrg	    return 1;
3422c393a42Smrg	}
3432c393a42Smrg    }
3442c393a42Smrg    else
3452c393a42Smrg    {
3462c393a42Smrg	recurse++;
3472c393a42Smrg	arglist = FcConfigGetFontDirs (config);
3482c393a42Smrg	while ((arg = FcStrListNext (arglist)))
3492c393a42Smrg	    if (!FcStrSetAdd (args, arg))
3502c393a42Smrg	    {
3512c393a42Smrg		fprintf (stderr, "%s: malloc failure\n", argv[0]);
3522c393a42Smrg		return 1;
3532c393a42Smrg	    }
3542c393a42Smrg	FcStrListDone (arglist);
3552c393a42Smrg    }
3562c393a42Smrg    arglist = FcStrListCreate (args);
3572c393a42Smrg    if (!arglist)
3582c393a42Smrg    {
3592c393a42Smrg	fprintf (stderr, "%s: malloc failure\n", argv[0]);
3602c393a42Smrg	return 1;
3612c393a42Smrg    }
3622c393a42Smrg
3632c393a42Smrg    while ((arg = FcStrListNext (arglist)))
3642c393a42Smrg    {
3652c393a42Smrg	int	    j;
3662c393a42Smrg	FcChar8	    *cache_file = NULL;
3672c393a42Smrg	struct stat file_stat;
3682c393a42Smrg
3692c393a42Smrg	if (FcFileIsDir (arg))
3702c393a42Smrg	    cache = FcDirCacheLoad (arg, config, &cache_file);
3712c393a42Smrg	else
3722c393a42Smrg	    cache = FcDirCacheLoadFile (arg, &file_stat);
3732c393a42Smrg	if (!cache)
3742c393a42Smrg	{
3752c393a42Smrg	    perror ((char *) arg);
3762c393a42Smrg	    ret++;
3772c393a42Smrg	    continue;
3782c393a42Smrg	}
3792c393a42Smrg
3802c393a42Smrg	dirs = FcStrSetCreate ();
3812c393a42Smrg	fs = FcCacheCopySet (cache);
3822c393a42Smrg	for (j = 0; j < FcCacheNumSubdir (cache); j++)
3832c393a42Smrg	{
3842c393a42Smrg	    FcStrSetAdd (dirs, FcCacheSubdir (cache, j));
3852c393a42Smrg	    if (recurse)
3862c393a42Smrg		FcStrSetAdd (args, FcCacheSubdir (cache, j));
3872c393a42Smrg	}
3882c393a42Smrg
3892c393a42Smrg	if (verbose)
3902c393a42Smrg	{
3912c393a42Smrg	    if (!first)
3922c393a42Smrg		printf ("\n");
3932c393a42Smrg	    printf ("Directory: %s\nCache: %s\n--------\n",
3942c393a42Smrg		    FcCacheDir(cache), cache_file ? cache_file : arg);
3952c393a42Smrg	    first = FcFalse;
3962c393a42Smrg	}
3972c393a42Smrg        cache_print_set (fs, dirs, FcCacheDir (cache), verbose);
3982c393a42Smrg
3992c393a42Smrg	FcStrSetDestroy (dirs);
4002c393a42Smrg
4012c393a42Smrg	FcFontSetDestroy (fs);
4022c393a42Smrg	FcDirCacheUnload (cache);
4032c393a42Smrg	if (cache_file)
4042c393a42Smrg	    FcStrFree (cache_file);
4052c393a42Smrg    }
4062c393a42Smrg
4072c393a42Smrg    return 0;
4082c393a42Smrg}
409