]> git.wh0rd.org Git - fontconfig.git/blob - fc-cat/fc-cat.c
Add codepath for reading global cache files as well.
[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 #include <fontconfig/fontconfig.h>
26 #include <../src/fccache.c>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <libgen.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <errno.h>
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #else
37 #ifdef linux
38 #define HAVE_GETOPT_LONG 1
39 #endif
40 #define HAVE_GETOPT 1
41 #endif
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     {"help", 0, 0, '?'},
57     {NULL,0,0,0},
58 };
59 #else
60 #if HAVE_GETOPT
61 extern char *optarg;
62 extern int optind, opterr, optopt;
63 #endif
64 #endif
65
66 /*
67  * POSIX has broken stdio so that getc must do thread-safe locking,
68  * this is a serious performance problem for applications doing large
69  * amounts of IO with getc (as is done here).  If available, use
70  * the getc_unlocked varient instead.
71  */
72  
73 #if defined(getc_unlocked) || defined(_IO_getc_unlocked)
74 #define GETC(f) getc_unlocked(f)
75 #define PUTC(c,f) putc_unlocked(c,f)
76 #else
77 #define GETC(f) getc(f)
78 #define PUTC(c,f) putc(c,f)
79 #endif
80
81 static FcBool
82 FcCacheWriteChars (FILE *f, const FcChar8 *chars)
83 {
84     FcChar8    c;
85     while ((c = *chars++))
86     {
87         switch (c) {
88         case '"':
89         case '\\':
90             if (PUTC ('\\', f) == EOF)
91                 return FcFalse;
92             /* fall through */
93         default:
94             if (PUTC (c, f) == EOF)
95                 return FcFalse;
96         }
97     }
98     return FcTrue;
99 }
100
101 static FcBool
102 FcCacheWriteUlong (FILE *f, unsigned long t)
103 {
104     int     pow;
105     unsigned long   temp, digit;
106
107     temp = t;
108     pow = 1;
109     while (temp >= 10)
110     {
111         temp /= 10;
112         pow *= 10;
113     }
114     temp = t;
115     while (pow)
116     {
117         digit = temp / pow;
118         if (PUTC ((char) digit + '0', f) == EOF)
119             return FcFalse;
120         temp = temp - pow * digit;
121         pow = pow / 10;
122     }
123     return FcTrue;
124 }
125
126 static FcBool
127 FcCacheWriteInt (FILE *f, int i)
128 {
129     return FcCacheWriteUlong (f, (unsigned long) i);
130 }
131
132 static FcBool
133 FcCacheWriteStringOld (FILE *f, const FcChar8 *string)
134 {
135
136     if (PUTC ('"', f) == EOF)
137         return FcFalse;
138     if (!FcCacheWriteChars (f, string))
139         return FcFalse;
140     if (PUTC ('"', f) == EOF)
141         return FcFalse;
142     return FcTrue;
143 }
144
145 static void
146 usage (char *program)
147 {
148 #if HAVE_GETOPT_LONG
149     fprintf (stderr, "usage: %s [-V?] [--version] [--help] <fonts.cache-2>\n",
150              program);
151 #else
152     fprintf (stderr, "usage: %s [-fsvV?] <fonts.cache-2>\n",
153              program);
154 #endif
155     fprintf (stderr, "Reads font information caches in <fonts.cache-2>\n");
156     fprintf (stderr, "\n");
157 #if HAVE_GETOPT_LONG
158     fprintf (stderr, "  -V, --version        display font config version and exit\n");
159     fprintf (stderr, "  -?, --help           display this help and exit\n");
160 #else
161     fprintf (stderr, "  -V         (version) display font config version and exit\n");
162     fprintf (stderr, "  -?         (help)    display this help and exit\n");
163 #endif
164     exit (1);
165 }
166
167 static FcBool 
168 FcCacheGlobalFileReadAndPrint (FcFontSet * set, FcStrSet *dirs, char * dir, char *cache_file)
169 {
170     char                name_buf[8192];
171     int fd;
172     FcGlobalCacheDir    *d, *next;
173     char * current_arch_machine_name;
174     char candidate_arch_machine_name[9+MACHINE_SIGNATURE_SIZE];
175     off_t current_arch_start = 0;
176     char subdirName[FC_MAX_FILE_LEN + 1 + 12 + 1];
177
178     if (!cache_file)
179         goto bail;
180
181     current_arch_machine_name = FcCacheMachineSignature();
182     fd = open(cache_file, O_RDONLY);
183     if (fd == -1)
184         goto bail;
185
186     current_arch_start = FcCacheSkipToArch(fd, current_arch_machine_name);
187     if (current_arch_start < 0)
188         goto bail1;
189
190     lseek (fd, current_arch_start, SEEK_SET);
191     if (FcCacheReadString (fd, candidate_arch_machine_name, 
192                            sizeof (candidate_arch_machine_name)) == 0)
193         goto bail1;
194
195     while (1) 
196     {
197         off_t targ;
198
199         FcCacheReadString (fd, name_buf, sizeof (name_buf));
200         if (!strlen(name_buf))
201             break;
202         printf ("fc-cat: printing global cache contents for dir %s\n", 
203                 name_buf);
204
205         if (!FcDirCacheConsume (fd, dir, set))
206             goto bail1;
207
208         FcCachePrintSet (set, dirs, name_buf);
209
210         FcFontSetDestroy (set);
211         set = FcFontSetCreate();
212     }
213
214  bail1:
215     close (fd);
216  bail:
217     return FcFalse;
218 }
219
220 /* read serialized state from the cache file */
221 static FcBool
222 FcCacheFileRead (FcFontSet * set, FcStrSet *dirs, char * dir, char *cache_file)
223 {
224     int fd;
225     char * current_arch_machine_name;
226     char candidate_arch_machine_name[9+MACHINE_SIGNATURE_SIZE];
227     off_t current_arch_start = 0;
228     char subdirName[FC_MAX_FILE_LEN + 1 + 12 + 1];
229
230     if (!cache_file)
231         goto bail;
232
233     current_arch_machine_name = FcCacheMachineSignature();
234     fd = open(cache_file, O_RDONLY);
235     if (fd == -1)
236         goto bail;
237
238     current_arch_start = FcCacheSkipToArch(fd, current_arch_machine_name);
239     if (current_arch_start < 0)
240         goto bail1;
241
242     lseek (fd, current_arch_start, SEEK_SET);
243     if (FcCacheReadString (fd, candidate_arch_machine_name, 
244                            sizeof (candidate_arch_machine_name)) == 0)
245         goto bail1;
246
247     while (strlen(FcCacheReadString (fd, subdirName, sizeof (subdirName))) > 0)
248         FcStrSetAdd (dirs, (FcChar8 *)subdirName);
249
250     if (!FcDirCacheConsume (fd, dir, set))
251         goto bail1;
252         
253     close(fd);
254     return FcTrue;
255
256  bail1:
257     close (fd);
258  bail:
259     return FcFalse;
260 }
261
262 /*
263  * return the path from the directory containing 'cache' to 'file'
264  */
265
266 static const FcChar8 *
267 FcFileBaseName (const char *cache, const FcChar8 *file)
268 {
269     const FcChar8   *cache_slash;
270
271     cache_slash = FcStrLastSlash ((const FcChar8 *)cache);
272     if (cache_slash && !strncmp ((const char *) cache, (const char *) file,
273                                  (cache_slash + 1) - (const FcChar8 *)cache))
274         return file + ((cache_slash + 1) - (const FcChar8 *)cache);
275     return file;
276 }
277
278 FcBool
279 FcCachePrintSet (FcFontSet *set, FcStrSet *dirs, char *cache_file)
280 {
281     FcPattern       *font;
282     FcChar8         *name, *dir;
283     const FcChar8   *file, *base;
284     int             ret;
285     int             n;
286     int             id;
287     FcStrList       *list;
288
289     list = FcStrListCreate (dirs);
290     if (!list)
291         goto bail2;
292     
293     while ((dir = FcStrListNext (list)))
294     {
295         base = FcFileBaseName (cache_file, dir);
296         if (!FcCacheWriteStringOld (stdout, base))
297             goto bail3;
298         if (PUTC (' ', stdout) == EOF)
299             goto bail3;
300         if (!FcCacheWriteInt (stdout, 0))
301             goto bail3;
302         if (PUTC (' ', stdout) == EOF)
303             goto bail3;
304         if (!FcCacheWriteStringOld (stdout, FC_FONT_FILE_DIR))
305             goto bail3;
306         if (PUTC ('\n', stdout) == EOF)
307             goto bail3;
308     }
309     
310     for (n = 0; n < set->nfont; n++)
311     {
312         font = set->fonts[n];
313         if (FcPatternGetString (font, FC_FILE, 0, (FcChar8 **) &file) != FcResultMatch)
314             goto bail3;
315         base = FcFileBaseName (cache_file, file);
316         if (FcPatternGetInteger (font, FC_INDEX, 0, &id) != FcResultMatch)
317             goto bail3;
318         if (FcDebug () & FC_DBG_CACHEV)
319             printf (" write file \"%s\"\n", base);
320         if (!FcCacheWriteStringOld (stdout, base))
321             goto bail3;
322         if (PUTC (' ', stdout) == EOF)
323             goto bail3;
324         if (!FcCacheWriteInt (stdout, id))
325             goto bail3;
326         if (PUTC (' ', stdout) == EOF)
327             goto bail3;
328         name = FcNameUnparse (font);
329         if (!name)
330             goto bail3;
331         ret = FcCacheWriteStringOld (stdout, name);
332         FcStrFree (name);
333         if (!ret)
334             goto bail3;
335         if (PUTC ('\n', stdout) == EOF)
336             goto bail3;
337     }
338     
339     FcStrListDone (list);
340
341     return FcTrue;
342     
343 bail3:
344     FcStrListDone (list);
345 bail2:
346 bail1:
347 bail0:
348     return FcFalse;
349 }
350
351 int
352 main (int argc, char **argv)
353 {
354     int         i;
355 #if HAVE_GETOPT_LONG || HAVE_GETOPT
356     int         c;
357     FcFontSet   *fs = FcFontSetCreate();
358     FcStrSet    *dirs = FcStrSetCreate();
359
360 #if HAVE_GETOPT_LONG
361     while ((c = getopt_long (argc, argv, "fsVv?", longopts, NULL)) != -1)
362 #else
363     while ((c = getopt (argc, argv, "fsVv?")) != -1)
364 #endif
365     {
366         switch (c) {
367         case 'V':
368             fprintf (stderr, "fontconfig version %d.%d.%d\n", 
369                      FC_MAJOR, FC_MINOR, FC_REVISION);
370             exit (0);
371         default:
372             usage (argv[0]);
373         }
374     }
375     i = optind;
376 #else
377     i = 1;
378 #endif
379
380     if (i >= argc)
381         usage (argv[0]);
382
383     if (FcCacheFileRead (fs, dirs, dirname (strdup(argv[i])), argv[i]))
384         FcCachePrintSet (fs, dirs, argv[i]);
385     else
386     {
387         FcStrSetDestroy (dirs);
388         dirs = FcStrSetCreate ();
389         if (FcCacheGlobalFileReadAndPrint (fs, dirs, dirname (strdup (argv[i])),
390                                            argv[i]))
391             ;
392     }
393
394     FcStrSetDestroy (dirs);
395     FcFontSetDestroy (fs);
396
397     return 0;
398 }