Home | History | Annotate | Line # | Download | only in fc-cat
      1 /*
      2  * fontconfig/fc-cat/fc-cat.c
      3  *
      4  * Copyright  2002 Keith Packard
      5  *
      6  * Permission to use, copy, modify, distribute, and sell this software and its
      7  * documentation for any purpose is hereby granted without fee, provided that
      8  * the above copyright notice appear in all copies and that both that
      9  * copyright notice and this permission notice appear in supporting
     10  * documentation, and that the name of the author(s) not be used in
     11  * advertising or publicity pertaining to distribution of the software without
     12  * specific, written prior permission.  The authors make no
     13  * representations about the suitability of this software for any purpose.  It
     14  * is provided "as is" without express or implied warranty.
     15  *
     16  * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     18  * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     22  * PERFORMANCE OF THIS SOFTWARE.
     23  */
     24 
     25 #ifdef HAVE_CONFIG_H
     26 #include <config.h>
     27 #else
     28 #ifdef linux
     29 #define HAVE_GETOPT_LONG 1
     30 #endif
     31 #define HAVE_GETOPT 1
     32 #endif
     33 
     34 #include <fontconfig/fontconfig.h>
     35 #include "../src/fcarch.h"
     36 #include <stdio.h>
     37 #include <stdlib.h>
     38 #include <string.h>
     39 #ifdef HAVE_UNISTD_H
     40 #include <unistd.h>
     41 #endif
     42 #include <sys/types.h>
     43 #include <sys/stat.h>
     44 #include <errno.h>
     45 #include <locale.h>
     46 
     47 #ifdef ENABLE_NLS
     48 #include <libintl.h>
     49 #define _(x)		(dgettext(GETTEXT_PACKAGE, x))
     50 #else
     51 #define dgettext(d, s)	(s)
     52 #define _(x)		(x)
     53 #endif
     54 
     55 #ifndef HAVE_GETOPT
     56 #define HAVE_GETOPT 0
     57 #endif
     58 #ifndef HAVE_GETOPT_LONG
     59 #define HAVE_GETOPT_LONG 0
     60 #endif
     61 
     62 #if HAVE_GETOPT_LONG
     63 #undef  _GNU_SOURCE
     64 #define _GNU_SOURCE
     65 #include <getopt.h>
     66 const struct option longopts[] = {
     67     {"version", 0, 0, 'V'},
     68     {"verbose", 0, 0, 'v'},
     69     {"recurse", 0, 0, 'r'},
     70     {"help", 0, 0, 'h'},
     71     {NULL,0,0,0},
     72 };
     73 #else
     74 #if HAVE_GETOPT
     75 extern char *optarg;
     76 extern int optind, opterr, optopt;
     77 #endif
     78 #endif
     79 
     80 /*
     81  * POSIX has broken stdio so that putc must do thread-safe locking,
     82  * this is a serious performance problem for applications doing large
     83  * amounts of IO with putc (as is done here).  If available, use
     84  * the putc_unlocked variant instead.
     85  */
     86 
     87 #if defined(putc_unlocked) || defined(_IO_putc_unlocked)
     88 #define PUTC(c,f) putc_unlocked(c,f)
     89 #else
     90 #define PUTC(c,f) putc(c,f)
     91 #endif
     92 
     93 static FcBool
     94 write_chars (FILE *f, const FcChar8 *chars)
     95 {
     96     FcChar8    c;
     97     while ((c = *chars++))
     98     {
     99 	switch (c) {
    100 	case '"':
    101 	case '\\':
    102 	    if (PUTC ('\\', f) == EOF)
    103 		return FcFalse;
    104 	    /* fall through */
    105 	default:
    106 	    if (PUTC (c, f) == EOF)
    107 		return FcFalse;
    108 	}
    109     }
    110     return FcTrue;
    111 }
    112 
    113 static FcBool
    114 write_ulong (FILE *f, unsigned long t)
    115 {
    116     int	    pow;
    117     unsigned long   temp, digit;
    118 
    119     temp = t;
    120     pow = 1;
    121     while (temp >= 10)
    122     {
    123 	temp /= 10;
    124 	pow *= 10;
    125     }
    126     temp = t;
    127     while (pow)
    128     {
    129 	digit = temp / pow;
    130 	if (PUTC ((char) digit + '0', f) == EOF)
    131 	    return FcFalse;
    132 	temp = temp - pow * digit;
    133 	pow = pow / 10;
    134     }
    135     return FcTrue;
    136 }
    137 
    138 static FcBool
    139 write_int (FILE *f, int i)
    140 {
    141     return write_ulong (f, (unsigned long) i);
    142 }
    143 
    144 static FcBool
    145 write_string (FILE *f, const FcChar8 *string)
    146 {
    147 
    148     if (PUTC ('"', f) == EOF)
    149 	return FcFalse;
    150     if (!write_chars (f, string))
    151 	return FcFalse;
    152     if (PUTC ('"', f) == EOF)
    153 	return FcFalse;
    154     return FcTrue;
    155 }
    156 
    157 static void
    158 usage (char *program, int error)
    159 {
    160     FILE *file = error ? stderr : stdout;
    161 #if HAVE_GETOPT_LONG
    162     fprintf (file, _("usage: %s [-rv] [--recurse] [--verbose] [*-%s" FC_CACHE_SUFFIX "|directory]...\n"),
    163 	     program, FC_ARCHITECTURE);
    164     fprintf (file, "       %s [-Vh] [--version] [--help]\n", program);
    165 #else
    166     fprintf (file, _("usage: %s [-rvVh] [*-%s" FC_CACHE_SUFFIX "|directory]...\n"),
    167 	     program, FC_ARCHITECTURE);
    168 #endif
    169     fprintf (file, _("Reads font information cache from:\n"));
    170     fprintf (file, _(" 1) specified fontconfig cache file\n"));
    171     fprintf (file, _(" 2) related to a particular font directory\n"));
    172     fprintf (file, "\n");
    173 #if HAVE_GETOPT_LONG
    174     fprintf (file, _("  -r, --recurse        recurse into subdirectories\n"));
    175     fprintf (file, _("  -v, --verbose        be verbose\n"));
    176     fprintf (file, _("  -V, --version        display font config version and exit\n"));
    177     fprintf (file, _("  -h, --help           display this help and exit\n"));
    178 #else
    179     fprintf (file, _("  -r         (recurse) recurse into subdirectories\n"));
    180     fprintf (file, _("  -v         (verbose) be verbose\n"));
    181     fprintf (file, _("  -V         (version) display font config version and exit\n"));
    182     fprintf (file, _("  -h         (help)    display this help and exit\n"));
    183 #endif
    184     exit (error);
    185 }
    186 
    187 /*
    188  * return the path from the directory containing 'cache' to 'file'
    189  */
    190 
    191 static const FcChar8 *
    192 file_base_name (const FcChar8 *cache, const FcChar8 *file)
    193 {
    194     int		    cache_len = strlen ((char *) cache);
    195 
    196     if (!strncmp ((char *) cache, (char *) file, cache_len) && file[cache_len] == '/')
    197 	return file + cache_len + 1;
    198     return file;
    199 }
    200 
    201 #define FC_FONT_FILE_DIR	((FcChar8 *) ".dir")
    202 
    203 static FcBool
    204 cache_print_set (FcFontSet *set, FcStrSet *dirs, const FcChar8 *base_name, FcBool verbose)
    205 {
    206     FcChar8	    *dir;
    207     const FcChar8   *base;
    208     int		    n;
    209     int		    ndir = 0;
    210     FcStrList	    *list;
    211 
    212     list = FcStrListCreate (dirs);
    213     if (!list)
    214 	goto bail2;
    215 
    216     while ((dir = FcStrListNext (list)))
    217     {
    218 	base = file_base_name (base_name, dir);
    219 	if (!write_string (stdout, base))
    220 	    goto bail3;
    221 	if (PUTC (' ', stdout) == EOF)
    222 	    goto bail3;
    223 	if (!write_int (stdout, 0))
    224 	    goto bail3;
    225         if (PUTC (' ', stdout) == EOF)
    226 	    goto bail3;
    227 	if (!write_string (stdout, FC_FONT_FILE_DIR))
    228 	    goto bail3;
    229 	if (PUTC ('\n', stdout) == EOF)
    230 	    goto bail3;
    231 	ndir++;
    232     }
    233 
    234     for (n = 0; n < set->nfont; n++)
    235     {
    236 	FcPattern   *font = set->fonts[n];
    237 	FcChar8 *s;
    238 
    239 	s = FcPatternFormat (font, (const FcChar8 *) "%{=fccat}\n");
    240 	if (s)
    241 	{
    242 	    printf ("%s", s);
    243 	    FcStrFree (s);
    244 	}
    245     }
    246     if (verbose && !set->nfont && !ndir)
    247 	printf ("<empty>\n");
    248 
    249     FcStrListDone (list);
    250 
    251     return FcTrue;
    252 
    253 bail3:
    254     FcStrListDone (list);
    255 bail2:
    256     return FcFalse;
    257 }
    258 
    259 int
    260 main (int argc, char **argv)
    261 {
    262     int		i;
    263     int		ret = 0;
    264     FcFontSet	*fs;
    265     FcStrSet    *dirs;
    266     FcStrSet	*args = NULL;
    267     FcStrList	*arglist;
    268     FcCache	*cache;
    269     FcConfig	*config;
    270     FcChar8	*arg;
    271     int		verbose = 0;
    272     int		recurse = 0;
    273     FcBool	first = FcTrue;
    274 #if HAVE_GETOPT_LONG || HAVE_GETOPT
    275     int		c;
    276 
    277     setlocale (LC_ALL, "");
    278 #if HAVE_GETOPT_LONG
    279     while ((c = getopt_long (argc, argv, "Vvrh", longopts, NULL)) != -1)
    280 #else
    281     while ((c = getopt (argc, argv, "Vvrh")) != -1)
    282 #endif
    283     {
    284 	switch (c) {
    285 	case 'V':
    286 	    fprintf (stderr, "fontconfig version %d.%d.%d\n",
    287 		     FC_MAJOR, FC_MINOR, FC_REVISION);
    288 	    exit (0);
    289 	case 'v':
    290 	    verbose++;
    291 	    break;
    292 	case 'r':
    293 	    recurse++;
    294 	    break;
    295 	case 'h':
    296 	    usage (argv[0], 0);
    297 	default:
    298 	    usage (argv[0], 1);
    299 	}
    300     }
    301     i = optind;
    302 #else
    303     i = 1;
    304 #endif
    305 
    306     config = FcInitLoadConfig ();
    307     if (!config)
    308     {
    309 	fprintf (stderr, _("%s: Can't initialize font config library\n"), argv[0]);
    310 	return 1;
    311     }
    312     FcConfigSetCurrent (config);
    313     FcConfigDestroy (config);
    314 
    315     args = FcStrSetCreate ();
    316     if (!args)
    317     {
    318 	fprintf (stderr, _("%s: malloc failure\n"), argv[0]);
    319 	return 1;
    320     }
    321     if (i < argc)
    322     {
    323 	for (; i < argc; i++)
    324 	{
    325 	    if (!FcStrSetAddFilename (args, (const FcChar8 *) argv[i]))
    326 	    {
    327 		fprintf (stderr, _("%s: malloc failure\n"), argv[0]);
    328 		return 1;
    329 	    }
    330 	}
    331     }
    332     else
    333     {
    334 	recurse++;
    335 	arglist = FcConfigGetFontDirs (config);
    336 	while ((arg = FcStrListNext (arglist)))
    337 	    if (!FcStrSetAdd (args, arg))
    338 	    {
    339 		fprintf (stderr, _("%s: malloc failure\n"), argv[0]);
    340 		return 1;
    341 	    }
    342 	FcStrListDone (arglist);
    343     }
    344     arglist = FcStrListCreate (args);
    345     if (!arglist)
    346     {
    347 	fprintf (stderr, _("%s: malloc failure\n"), argv[0]);
    348 	return 1;
    349     }
    350     FcStrSetDestroy (args);
    351 
    352     while ((arg = FcStrListNext (arglist)))
    353     {
    354 	int	    j;
    355 	FcChar8	    *cache_file = NULL;
    356 	struct stat file_stat;
    357 
    358 	/* reset errno */
    359 	errno = 0;
    360 	if (FcFileIsDir (arg))
    361 	    cache = FcDirCacheLoad (arg, config, &cache_file);
    362 	else
    363 	    cache = FcDirCacheLoadFile (arg, &file_stat);
    364 	if (!cache)
    365 	{
    366 	    if (errno != 0)
    367 		perror ((char *) arg);
    368 	    else
    369 		fprintf (stderr, "%s: Unable to load the cache: %s\n", argv[0], arg);
    370 	    ret++;
    371 	    continue;
    372 	}
    373 
    374 	dirs = FcStrSetCreate ();
    375 	fs = FcCacheCopySet (cache);
    376 	for (j = 0; j < FcCacheNumSubdir (cache); j++)
    377 	{
    378 	    FcStrSetAdd (dirs, FcCacheSubdir (cache, j));
    379 	    if (recurse)
    380 		FcStrSetAdd (args, FcCacheSubdir (cache, j));
    381 	}
    382 
    383 	if (verbose)
    384 	{
    385 	    if (!first)
    386 		printf ("\n");
    387 	    printf (_("Directory: %s\nCache: %s\n--------\n"),
    388 		    FcCacheDir(cache), cache_file ? cache_file : arg);
    389 	    first = FcFalse;
    390 	}
    391         cache_print_set (fs, dirs, FcCacheDir (cache), verbose);
    392 
    393 	FcStrSetDestroy (dirs);
    394 
    395 	FcFontSetDestroy (fs);
    396 	FcDirCacheUnload (cache);
    397 	if (cache_file)
    398 	    FcStrFree (cache_file);
    399     }
    400     FcStrListDone (arglist);
    401 
    402     FcFini ();
    403     return 0;
    404 }
    405