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