Imported Upstream version 2.13.0
[platform/upstream/fontconfig.git] / fc-cat / fc-cat.c
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 #include <unistd.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <errno.h>
43
44 #ifdef ENABLE_NLS
45 #include <libintl.h>
46 #define _(x)            (dgettext(GETTEXT_PACKAGE, x))
47 #else
48 #define dgettext(d, s)  (s)
49 #define _(x)            (x)
50 #endif
51
52 #ifndef HAVE_GETOPT
53 #define HAVE_GETOPT 0
54 #endif
55 #ifndef HAVE_GETOPT_LONG
56 #define HAVE_GETOPT_LONG 0
57 #endif
58
59 #if HAVE_GETOPT_LONG
60 #undef  _GNU_SOURCE
61 #define _GNU_SOURCE
62 #include <getopt.h>
63 const struct option longopts[] = {
64     {"version", 0, 0, 'V'},
65     {"verbose", 0, 0, 'v'},
66     {"recurse", 0, 0, 'r'},
67     {"help", 0, 0, 'h'},
68     {NULL,0,0,0},
69 };
70 #else
71 #if HAVE_GETOPT
72 extern char *optarg;
73 extern int optind, opterr, optopt;
74 #endif
75 #endif
76
77 /*
78  * POSIX has broken stdio so that putc must do thread-safe locking,
79  * this is a serious performance problem for applications doing large
80  * amounts of IO with putc (as is done here).  If available, use
81  * the putc_unlocked varient instead.
82  */
83  
84 #if defined(putc_unlocked) || defined(_IO_putc_unlocked)
85 #define PUTC(c,f) putc_unlocked(c,f)
86 #else
87 #define PUTC(c,f) putc(c,f)
88 #endif
89
90 static FcBool
91 write_chars (FILE *f, const FcChar8 *chars)
92 {
93     FcChar8    c;
94     while ((c = *chars++))
95     {
96         switch (c) {
97         case '"':
98         case '\\':
99             if (PUTC ('\\', f) == EOF)
100                 return FcFalse;
101             /* fall through */
102         default:
103             if (PUTC (c, f) == EOF)
104                 return FcFalse;
105         }
106     }
107     return FcTrue;
108 }
109
110 static FcBool
111 write_ulong (FILE *f, unsigned long t)
112 {
113     int     pow;
114     unsigned long   temp, digit;
115
116     temp = t;
117     pow = 1;
118     while (temp >= 10)
119     {
120         temp /= 10;
121         pow *= 10;
122     }
123     temp = t;
124     while (pow)
125     {
126         digit = temp / pow;
127         if (PUTC ((char) digit + '0', f) == EOF)
128             return FcFalse;
129         temp = temp - pow * digit;
130         pow = pow / 10;
131     }
132     return FcTrue;
133 }
134
135 static FcBool
136 write_int (FILE *f, int i)
137 {
138     return write_ulong (f, (unsigned long) i);
139 }
140
141 static FcBool
142 write_string (FILE *f, const FcChar8 *string)
143 {
144
145     if (PUTC ('"', f) == EOF)
146         return FcFalse;
147     if (!write_chars (f, string))
148         return FcFalse;
149     if (PUTC ('"', f) == EOF)
150         return FcFalse;
151     return FcTrue;
152 }
153
154 static void
155 usage (char *program, int error)
156 {
157     FILE *file = error ? stderr : stdout;
158 #if HAVE_GETOPT_LONG
159     fprintf (file, _("usage: %s [-rv] [--recurse] [--verbose] [*-%s" FC_CACHE_SUFFIX "|directory]...\n"),
160              program, FC_ARCHITECTURE);
161     fprintf (file, "       %s [-Vh] [--version] [--help]\n", program);
162 #else
163     fprintf (file, _("usage: %s [-rvVh] [*-%s" FC_CACHE_SUFFIX "|directory]...\n"),
164              program, FC_ARCHITECTURE);
165 #endif
166     fprintf (file, _("Reads font information cache from:\n"));
167     fprintf (file, _(" 1) specified fontconfig cache file\n"));
168     fprintf (file, _(" 2) related to a particular font directory\n"));
169     fprintf (file, "\n");
170 #if HAVE_GETOPT_LONG
171     fprintf (file, _("  -r, --recurse        recurse into subdirectories\n"));
172     fprintf (file, _("  -v, --verbose        be verbose\n"));
173     fprintf (file, _("  -V, --version        display font config version and exit\n"));
174     fprintf (file, _("  -h, --help           display this help and exit\n"));
175 #else
176     fprintf (file, _("  -r         (recurse) recurse into subdirectories\n"));
177     fprintf (file, _("  -v         (verbose) be verbose\n"));
178     fprintf (file, _("  -V         (version) display font config version and exit\n"));
179     fprintf (file, _("  -h         (help)    display this help and exit\n"));
180 #endif
181     exit (error);
182 }
183
184 /*
185  * return the path from the directory containing 'cache' to 'file'
186  */
187
188 static const FcChar8 *
189 file_base_name (const FcChar8 *cache, const FcChar8 *file)
190 {
191     int             cache_len = strlen ((char *) cache);
192
193     if (!strncmp ((char *) cache, (char *) file, cache_len) && file[cache_len] == '/')
194         return file + cache_len + 1;
195     return file;
196 }
197
198 #define FC_FONT_FILE_DIR        ((FcChar8 *) ".dir")
199
200 static FcBool
201 cache_print_set (FcFontSet *set, FcStrSet *dirs, const FcChar8 *base_name, FcBool verbose)
202 {
203     FcChar8         *dir;
204     const FcChar8   *base;
205     int             n;
206     int             ndir = 0;
207     FcStrList       *list;
208
209     list = FcStrListCreate (dirs);
210     if (!list)
211         goto bail2;
212     
213     while ((dir = FcStrListNext (list)))
214     {
215         base = file_base_name (base_name, dir);
216         if (!write_string (stdout, base))
217             goto bail3;
218         if (PUTC (' ', stdout) == EOF)
219             goto bail3;
220         if (!write_int (stdout, 0))
221             goto bail3;
222         if (PUTC (' ', stdout) == EOF)
223             goto bail3;
224         if (!write_string (stdout, FC_FONT_FILE_DIR))
225             goto bail3;
226         if (PUTC ('\n', stdout) == EOF)
227             goto bail3;
228         ndir++;
229     }
230     
231     for (n = 0; n < set->nfont; n++)
232     {
233         FcPattern   *font = set->fonts[n];
234         FcChar8 *s;
235
236         s = FcPatternFormat (font, (const FcChar8 *) "%{=fccat}\n");
237         if (s)
238         {
239             printf ("%s", s);
240             FcStrFree (s);
241         }
242     }
243     if (verbose && !set->nfont && !ndir)
244         printf ("<empty>\n");
245
246     FcStrListDone (list);
247
248     return FcTrue;
249
250 bail3:
251     FcStrListDone (list);
252 bail2:
253     return FcFalse;
254 }
255
256 int
257 main (int argc, char **argv)
258 {
259     int         i;
260     int         ret = 0;
261     FcFontSet   *fs;
262     FcStrSet    *dirs;
263     FcStrSet    *args = NULL;
264     FcStrList   *arglist;
265     FcCache     *cache;
266     FcConfig    *config;
267     FcChar8     *arg;
268     int         verbose = 0;
269     int         recurse = 0;
270     FcBool      first = FcTrue;
271 #if HAVE_GETOPT_LONG || HAVE_GETOPT
272     int         c;
273
274 #if HAVE_GETOPT_LONG
275     while ((c = getopt_long (argc, argv, "Vvrh", longopts, NULL)) != -1)
276 #else
277     while ((c = getopt (argc, argv, "Vvrh")) != -1)
278 #endif
279     {
280         switch (c) {
281         case 'V':
282             fprintf (stderr, "fontconfig version %d.%d.%d\n", 
283                      FC_MAJOR, FC_MINOR, FC_REVISION);
284             exit (0);
285         case 'v':
286             verbose++;
287             break;
288         case 'r':
289             recurse++;
290             break;
291         case 'h':
292             usage (argv[0], 0);
293         default:
294             usage (argv[0], 1);
295         }
296     }
297     i = optind;
298 #else
299     i = 1;
300 #endif
301
302     config = FcInitLoadConfig ();
303     if (!config)
304     {
305         fprintf (stderr, _("%s: Can't initialize font config library\n"), argv[0]);
306         return 1;
307     }
308     FcConfigSetCurrent (config);
309     FcConfigDestroy (config);
310     
311     args = FcStrSetCreate ();
312     if (!args)
313     {
314         fprintf (stderr, _("%s: malloc failure\n"), argv[0]);
315         return 1;
316     }
317     if (i < argc)
318     {
319         for (; i < argc; i++)
320         {
321             if (!FcStrSetAddFilename (args, (const FcChar8 *) argv[i]))
322             {
323                 fprintf (stderr, _("%s: malloc failure\n"), argv[0]);
324                 return 1;
325             }
326         }
327     }
328     else
329     {
330         recurse++;
331         arglist = FcConfigGetFontDirs (config);
332         while ((arg = FcStrListNext (arglist)))
333             if (!FcStrSetAdd (args, arg))
334             {
335                 fprintf (stderr, _("%s: malloc failure\n"), argv[0]);
336                 return 1;
337             }
338         FcStrListDone (arglist);
339     }
340     arglist = FcStrListCreate (args);
341     if (!arglist)
342     {
343         fprintf (stderr, _("%s: malloc failure\n"), argv[0]);
344         return 1;
345     }
346     FcStrSetDestroy (args);
347
348     while ((arg = FcStrListNext (arglist)))
349     {
350         int         j;
351         FcChar8     *cache_file = NULL;
352         struct stat file_stat;
353
354         /* reset errno */
355         errno = 0;
356         if (FcFileIsDir (arg))
357             cache = FcDirCacheLoad (arg, config, &cache_file);
358         else
359             cache = FcDirCacheLoadFile (arg, &file_stat);
360         if (!cache)
361         {
362             if (errno != 0)
363                 perror ((char *) arg);
364             else
365                 fprintf (stderr, "%s: Unable to load the cache: %s\n", argv[0], arg);
366             ret++;
367             continue;
368         }
369         
370         dirs = FcStrSetCreate ();
371         fs = FcCacheCopySet (cache);
372         for (j = 0; j < FcCacheNumSubdir (cache); j++) 
373         {
374             FcStrSetAdd (dirs, FcCacheSubdir (cache, j));
375             if (recurse)
376                 FcStrSetAdd (args, FcCacheSubdir (cache, j));
377         }
378
379         if (verbose)
380         {
381             if (!first)
382                 printf ("\n");
383             printf (_("Directory: %s\nCache: %s\n--------\n"),
384                     FcCacheDir(cache), cache_file ? cache_file : arg);
385             first = FcFalse;
386         }
387         cache_print_set (fs, dirs, FcCacheDir (cache), verbose);
388
389         FcStrSetDestroy (dirs);
390
391         FcFontSetDestroy (fs);
392         FcDirCacheUnload (cache);
393         if (cache_file)
394             FcStrFree (cache_file);
395     }
396     FcStrListDone (arglist);
397
398     FcFini ();
399     return 0;
400 }