fc-cat.c revision ca08ab68
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/*
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
153ca08ab68Smrg    fprintf (file, "usage: %s [-rv] [--recurse] [--verbose] [*-%s" FC_CACHE_SUFFIX "|directory]...\n",
1542c393a42Smrg	     program, FC_ARCHITECTURE);
155a6844aabSmrg    fprintf (file, "       %s [-Vh] [--version] [--help]\n", program);
1562c393a42Smrg#else
157ca08ab68Smrg    fprintf (file, "usage: %s [-rvVh] [*-%s" FC_CACHE_SUFFIX "|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{
197ca08ab68Smrg    FcChar8	    *dir;
198ca08ab68Smrg    const FcChar8   *base;
1992c393a42Smrg    int		    n;
2002c393a42Smrg    int		    ndir = 0;
2012c393a42Smrg    FcStrList	    *list;
2022c393a42Smrg
2032c393a42Smrg    list = FcStrListCreate (dirs);
2042c393a42Smrg    if (!list)
2052c393a42Smrg	goto bail2;
2062c393a42Smrg
2072c393a42Smrg    while ((dir = FcStrListNext (list)))
2082c393a42Smrg    {
2092c393a42Smrg	base = file_base_name (base_name, dir);
2102c393a42Smrg	if (!write_string (stdout, base))
2112c393a42Smrg	    goto bail3;
2122c393a42Smrg	if (PUTC (' ', stdout) == EOF)
2132c393a42Smrg	    goto bail3;
2142c393a42Smrg	if (!write_int (stdout, 0))
2152c393a42Smrg	    goto bail3;
2162c393a42Smrg        if (PUTC (' ', stdout) == EOF)
2172c393a42Smrg	    goto bail3;
2182c393a42Smrg	if (!write_string (stdout, FC_FONT_FILE_DIR))
2192c393a42Smrg	    goto bail3;
2202c393a42Smrg	if (PUTC ('\n', stdout) == EOF)
2212c393a42Smrg	    goto bail3;
2222c393a42Smrg	ndir++;
2232c393a42Smrg    }
2242c393a42Smrg
2252c393a42Smrg    for (n = 0; n < set->nfont; n++)
2262c393a42Smrg    {
2272c393a42Smrg	FcPattern   *font = set->fonts[n];
228ca08ab68Smrg	FcChar8 *s;
2292c393a42Smrg
230ca08ab68Smrg	s = FcPatternFormat (font, (const FcChar8 *) "%{=fccat}\n");
231ca08ab68Smrg	if (s)
232ca08ab68Smrg	{
233ca08ab68Smrg	    printf ("%s", s);
234ca08ab68Smrg	    FcStrFree (s);
235ca08ab68Smrg	}
2362c393a42Smrg    }
2372c393a42Smrg    if (verbose && !set->nfont && !ndir)
2382c393a42Smrg	printf ("<empty>\n");
239ca08ab68Smrg
2402c393a42Smrg    FcStrListDone (list);
2412c393a42Smrg
2422c393a42Smrg    return FcTrue;
243ca08ab68Smrg
2442c393a42Smrgbail3:
2452c393a42Smrg    FcStrListDone (list);
2462c393a42Smrgbail2:
2472c393a42Smrg    return FcFalse;
2482c393a42Smrg}
2492c393a42Smrg
2502c393a42Smrgint
2512c393a42Smrgmain (int argc, char **argv)
2522c393a42Smrg{
2532c393a42Smrg    int		i;
2542c393a42Smrg    int		ret = 0;
2552c393a42Smrg    FcFontSet	*fs;
2562c393a42Smrg    FcStrSet    *dirs;
2572c393a42Smrg    FcStrSet	*args = NULL;
2582c393a42Smrg    FcStrList	*arglist;
2592c393a42Smrg    FcCache	*cache;
2602c393a42Smrg    FcConfig	*config;
2612c393a42Smrg    FcChar8	*arg;
2622c393a42Smrg    int		verbose = 0;
2632c393a42Smrg    int		recurse = 0;
2642c393a42Smrg    FcBool	first = FcTrue;
2652c393a42Smrg#if HAVE_GETOPT_LONG || HAVE_GETOPT
2662c393a42Smrg    int		c;
2672c393a42Smrg
2682c393a42Smrg#if HAVE_GETOPT_LONG
269a6844aabSmrg    while ((c = getopt_long (argc, argv, "Vvrh", longopts, NULL)) != -1)
2702c393a42Smrg#else
271a6844aabSmrg    while ((c = getopt (argc, argv, "Vvrh")) != -1)
2722c393a42Smrg#endif
2732c393a42Smrg    {
2742c393a42Smrg	switch (c) {
2752c393a42Smrg	case 'V':
2762c393a42Smrg	    fprintf (stderr, "fontconfig version %d.%d.%d\n",
2772c393a42Smrg		     FC_MAJOR, FC_MINOR, FC_REVISION);
2782c393a42Smrg	    exit (0);
2792c393a42Smrg	case 'v':
2802c393a42Smrg	    verbose++;
2812c393a42Smrg	    break;
2822c393a42Smrg	case 'r':
2832c393a42Smrg	    recurse++;
2842c393a42Smrg	    break;
285a6844aabSmrg	case 'h':
286a6844aabSmrg	    usage (argv[0], 0);
2872c393a42Smrg	default:
288a6844aabSmrg	    usage (argv[0], 1);
2892c393a42Smrg	}
2902c393a42Smrg    }
2912c393a42Smrg    i = optind;
2922c393a42Smrg#else
2932c393a42Smrg    i = 1;
2942c393a42Smrg#endif
2952c393a42Smrg
2962c393a42Smrg    config = FcInitLoadConfig ();
2972c393a42Smrg    if (!config)
2982c393a42Smrg    {
2992c393a42Smrg	fprintf (stderr, "%s: Can't init font config library\n", argv[0]);
3002c393a42Smrg	return 1;
3012c393a42Smrg    }
3022c393a42Smrg    FcConfigSetCurrent (config);
3032c393a42Smrg
3042c393a42Smrg    args = FcStrSetCreate ();
3052c393a42Smrg    if (!args)
3062c393a42Smrg    {
3072c393a42Smrg	fprintf (stderr, "%s: malloc failure\n", argv[0]);
3082c393a42Smrg	return 1;
3092c393a42Smrg    }
3102c393a42Smrg    if (i < argc)
3112c393a42Smrg    {
3122c393a42Smrg	for (; i < argc; i++)
3132c393a42Smrg	{
3142c393a42Smrg	    if (!FcStrSetAddFilename (args, (const FcChar8 *) argv[i]))
3152c393a42Smrg	    {
3162c393a42Smrg		fprintf (stderr, "%s: malloc failure\n", argv[0]);
3172c393a42Smrg		return 1;
3182c393a42Smrg	    }
3192c393a42Smrg	}
3202c393a42Smrg	arglist = FcStrListCreate (args);
3212c393a42Smrg	if (!arglist)
3222c393a42Smrg	{
3232c393a42Smrg	    fprintf (stderr, "%s: malloc failure\n", argv[0]);
3242c393a42Smrg	    return 1;
3252c393a42Smrg	}
3262c393a42Smrg    }
3272c393a42Smrg    else
3282c393a42Smrg    {
3292c393a42Smrg	recurse++;
3302c393a42Smrg	arglist = FcConfigGetFontDirs (config);
3312c393a42Smrg	while ((arg = FcStrListNext (arglist)))
3322c393a42Smrg	    if (!FcStrSetAdd (args, arg))
3332c393a42Smrg	    {
3342c393a42Smrg		fprintf (stderr, "%s: malloc failure\n", argv[0]);
3352c393a42Smrg		return 1;
3362c393a42Smrg	    }
3372c393a42Smrg	FcStrListDone (arglist);
3382c393a42Smrg    }
3392c393a42Smrg    arglist = FcStrListCreate (args);
3402c393a42Smrg    if (!arglist)
3412c393a42Smrg    {
3422c393a42Smrg	fprintf (stderr, "%s: malloc failure\n", argv[0]);
3432c393a42Smrg	return 1;
3442c393a42Smrg    }
3452c393a42Smrg
3462c393a42Smrg    while ((arg = FcStrListNext (arglist)))
3472c393a42Smrg    {
3482c393a42Smrg	int	    j;
3492c393a42Smrg	FcChar8	    *cache_file = NULL;
3502c393a42Smrg	struct stat file_stat;
3512c393a42Smrg
3522c393a42Smrg	if (FcFileIsDir (arg))
3532c393a42Smrg	    cache = FcDirCacheLoad (arg, config, &cache_file);
3542c393a42Smrg	else
3552c393a42Smrg	    cache = FcDirCacheLoadFile (arg, &file_stat);
3562c393a42Smrg	if (!cache)
3572c393a42Smrg	{
3582c393a42Smrg	    perror ((char *) arg);
3592c393a42Smrg	    ret++;
3602c393a42Smrg	    continue;
3612c393a42Smrg	}
3622c393a42Smrg
3632c393a42Smrg	dirs = FcStrSetCreate ();
3642c393a42Smrg	fs = FcCacheCopySet (cache);
3652c393a42Smrg	for (j = 0; j < FcCacheNumSubdir (cache); j++)
3662c393a42Smrg	{
3672c393a42Smrg	    FcStrSetAdd (dirs, FcCacheSubdir (cache, j));
3682c393a42Smrg	    if (recurse)
3692c393a42Smrg		FcStrSetAdd (args, FcCacheSubdir (cache, j));
3702c393a42Smrg	}
3712c393a42Smrg
3722c393a42Smrg	if (verbose)
3732c393a42Smrg	{
3742c393a42Smrg	    if (!first)
3752c393a42Smrg		printf ("\n");
3762c393a42Smrg	    printf ("Directory: %s\nCache: %s\n--------\n",
3772c393a42Smrg		    FcCacheDir(cache), cache_file ? cache_file : arg);
3782c393a42Smrg	    first = FcFalse;
3792c393a42Smrg	}
3802c393a42Smrg        cache_print_set (fs, dirs, FcCacheDir (cache), verbose);
3812c393a42Smrg
3822c393a42Smrg	FcStrSetDestroy (dirs);
3832c393a42Smrg
3842c393a42Smrg	FcFontSetDestroy (fs);
3852c393a42Smrg	FcDirCacheUnload (cache);
3862c393a42Smrg	if (cache_file)
3872c393a42Smrg	    FcStrFree (cache_file);
3882c393a42Smrg    }
3892c393a42Smrg
390ca08ab68Smrg    FcFini ();
3912c393a42Smrg    return 0;
3922c393a42Smrg}
393