fc-cat.c 9.97 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*
 * $RCSId: xc/lib/fontconfig/fc-cache/fc-cache.c,v 1.8tsi Exp $
 *
 * Copyright © 2002 Keith Packard
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Keith Packard not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Keith Packard makes no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#include <fontconfig/fontconfig.h>
#include <../src/fccache.c>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
30
#include <libgen.h>
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#else
#ifdef linux
#define HAVE_GETOPT_LONG 1
#endif
#define HAVE_GETOPT 1
#endif

#ifndef HAVE_GETOPT
#define HAVE_GETOPT 0
#endif
#ifndef HAVE_GETOPT_LONG
#define HAVE_GETOPT_LONG 0
#endif

#if HAVE_GETOPT_LONG
#undef  _GNU_SOURCE
#define _GNU_SOURCE
#include <getopt.h>
const struct option longopts[] = {
    {"version", 0, 0, 'V'},
    {"help", 0, 0, '?'},
    {NULL,0,0,0},
};
#else
#if HAVE_GETOPT
extern char *optarg;
extern int optind, opterr, optopt;
#endif
#endif

/*
 * POSIX has broken stdio so that getc must do thread-safe locking,
 * this is a serious performance problem for applications doing large
 * amounts of IO with getc (as is done here).  If available, use
 * the getc_unlocked varient instead.
 */
 
#if defined(getc_unlocked) || defined(_IO_getc_unlocked)
#define GETC(f) getc_unlocked(f)
#define PUTC(c,f) putc_unlocked(c,f)
#else
#define GETC(f) getc(f)
#define PUTC(c,f) putc(c,f)
#endif

Patrick Lam's avatar
Patrick Lam committed
81
FcBool
Patrick Lam's avatar
Patrick Lam committed
82
FcCachePrintSet (FcFontSet *set, FcStrSet *dirs, char *base_name);
Patrick Lam's avatar
Patrick Lam committed
83

84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
static FcBool
FcCacheWriteChars (FILE *f, const FcChar8 *chars)
{
    FcChar8    c;
    while ((c = *chars++))
    {
	switch (c) {
	case '"':
	case '\\':
	    if (PUTC ('\\', f) == EOF)
		return FcFalse;
	    /* fall through */
	default:
	    if (PUTC (c, f) == EOF)
		return FcFalse;
	}
    }
    return FcTrue;
}

static FcBool
FcCacheWriteUlong (FILE *f, unsigned long t)
{
    int	    pow;
    unsigned long   temp, digit;

    temp = t;
    pow = 1;
    while (temp >= 10)
    {
	temp /= 10;
	pow *= 10;
    }
    temp = t;
    while (pow)
    {
	digit = temp / pow;
	if (PUTC ((char) digit + '0', f) == EOF)
	    return FcFalse;
	temp = temp - pow * digit;
	pow = pow / 10;
    }
    return FcTrue;
}

static FcBool
FcCacheWriteInt (FILE *f, int i)
{
    return FcCacheWriteUlong (f, (unsigned long) i);
}

static FcBool
FcCacheWriteStringOld (FILE *f, const FcChar8 *string)
{

    if (PUTC ('"', f) == EOF)
	return FcFalse;
    if (!FcCacheWriteChars (f, string))
	return FcFalse;
    if (PUTC ('"', f) == EOF)
	return FcFalse;
    return FcTrue;
}

static void
usage (char *program)
{
#if HAVE_GETOPT_LONG
    fprintf (stderr, "usage: %s [-V?] [--version] [--help] <fonts.cache-2>\n",
	     program);
#else
    fprintf (stderr, "usage: %s [-fsvV?] <fonts.cache-2>\n",
	     program);
#endif
    fprintf (stderr, "Reads font information caches in <fonts.cache-2>\n");
    fprintf (stderr, "\n");
#if HAVE_GETOPT_LONG
    fprintf (stderr, "  -V, --version        display font config version and exit\n");
    fprintf (stderr, "  -?, --help           display this help and exit\n");
#else
    fprintf (stderr, "  -V         (version) display font config version and exit\n");
    fprintf (stderr, "  -?         (help)    display this help and exit\n");
#endif
    exit (1);
}

170
static FcBool 
Patrick Lam's avatar
Patrick Lam committed
171
FcCacheGlobalFileReadAndPrint (FcFontSet * set, FcStrSet *dirs, char *cache_file)
172
173
174
175
176
{
    char		name_buf[8192];
    int fd;
    char * current_arch_machine_name;
    char candidate_arch_machine_name[9+MACHINE_SIGNATURE_SIZE];
177
    char 		subdirName[FC_MAX_FILE_LEN + 1 + 12 + 1];
178
179
180
181
182
183
184
185
186
187
    off_t current_arch_start = 0;

    if (!cache_file)
	goto bail;

    current_arch_machine_name = FcCacheMachineSignature();
    fd = open(cache_file, O_RDONLY);
    if (fd == -1)
	goto bail;

Patrick Lam's avatar
Patrick Lam committed
188
    current_arch_start = FcCacheSkipToArch(fd, current_arch_machine_name);
189
190
191
192
193
194
195
196
197
198
    if (current_arch_start < 0)
	goto bail1;

    lseek (fd, current_arch_start, SEEK_SET);
    if (FcCacheReadString (fd, candidate_arch_machine_name, 
			   sizeof (candidate_arch_machine_name)) == 0)
	goto bail1;

    while (1) 
    {
Patrick Lam's avatar
Patrick Lam committed
199
	char * dir, * ls;
200
201
202
203
204
205
	FcCacheReadString (fd, name_buf, sizeof (name_buf));
	if (!strlen(name_buf))
	    break;
	printf ("fc-cat: printing global cache contents for dir %s\n", 
		name_buf);

206
207
208
209
210
211
212
213
214
	do
	{
	    if (!FcCacheReadString (fd, subdirName, 
				    sizeof (subdirName)) ||
		!strlen (subdirName))
		break;
	    /* then don't do anything with subdirName. */
	} while (1);

215
	if (!FcDirCacheConsume (fd, name_buf, set, 0))
216
217
	    goto bail1;

218
219
220
221
222
	dir = malloc (strlen (name_buf) + 2);
	if (!dir)
	    goto bail1;

	strcpy (dir, name_buf);
Patrick Lam's avatar
Patrick Lam committed
223
224
225
226
	strcat (dir, "/");

	FcCachePrintSet (set, dirs, dir);
	free (dir);
227
228
229
230
231
232
233
234
235
236
237

	FcFontSetDestroy (set);
	set = FcFontSetCreate();
    }

 bail1:
    close (fd);
 bail:
    return FcFalse;
}

238
/* read serialized state from the cache file */
Patrick Lam's avatar
Patrick Lam committed
239
240
static char *
FcCacheFileRead (FcFontSet * set, FcStrSet *dirs, char *cache_file)
241
242
243
244
245
246
{
    int fd;
    char * current_arch_machine_name;
    char candidate_arch_machine_name[9+MACHINE_SIGNATURE_SIZE];
    off_t current_arch_start = 0;
    char subdirName[FC_MAX_FILE_LEN + 1 + 12 + 1];
Patrick Lam's avatar
Patrick Lam committed
247
248
    static char name_buf[8192], *dir;
    FcChar8 * ls;
249
250
251
252
253
254
255
256
257

    if (!cache_file)
        goto bail;

    current_arch_machine_name = FcCacheMachineSignature();
    fd = open(cache_file, O_RDONLY);
    if (fd == -1)
        goto bail;

258
259
260
    FcCacheReadString (fd, name_buf, sizeof (name_buf));
    if (!strlen (name_buf))
	goto bail;
Patrick Lam's avatar
Patrick Lam committed
261
262
263
    if (strcmp (name_buf, FC_GLOBAL_MAGIC_COOKIE) == 0)
	goto bail;
    printf ("fc-cat: printing directory cache for cache which would be named %s\n", 
264
265
	    name_buf);

Patrick Lam's avatar
Patrick Lam committed
266
    current_arch_start = FcCacheSkipToArch(fd, current_arch_machine_name);
267
268
269
270
271
272
    if (current_arch_start < 0)
        goto bail1;

    while (strlen(FcCacheReadString (fd, subdirName, sizeof (subdirName))) > 0)
        FcStrSetAdd (dirs, (FcChar8 *)subdirName);

Patrick Lam's avatar
Patrick Lam committed
273
274
275
276
277
    dir = strdup(name_buf);
    ls = FcStrLastSlash ((FcChar8 *)dir);
    if (ls)
	*ls = 0;

278
    if (!FcDirCacheConsume (fd, dir, set, 0))
Patrick Lam's avatar
Patrick Lam committed
279
280
281
	goto bail2;
    free (dir);

282
    close(fd);
Patrick Lam's avatar
Patrick Lam committed
283
284
285
286
    return name_buf;

 bail2:
    free (dir);
287
288
289
290

 bail1:
    close (fd);
 bail:
Patrick Lam's avatar
Patrick Lam committed
291
    return 0;
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
}

/*
 * return the path from the directory containing 'cache' to 'file'
 */

static const FcChar8 *
FcFileBaseName (const char *cache, const FcChar8 *file)
{
    const FcChar8   *cache_slash;

    cache_slash = FcStrLastSlash ((const FcChar8 *)cache);
    if (cache_slash && !strncmp ((const char *) cache, (const char *) file,
				 (cache_slash + 1) - (const FcChar8 *)cache))
	return file + ((cache_slash + 1) - (const FcChar8 *)cache);
    return file;
}

FcBool
Patrick Lam's avatar
Patrick Lam committed
311
FcCachePrintSet (FcFontSet *set, FcStrSet *dirs, char *base_name)
312
313
314
315
{
    FcPattern	    *font;
    FcChar8	    *name, *dir;
    const FcChar8   *file, *base;
Patrick Lam's avatar
Patrick Lam committed
316
    int		    ret;
317
318
319
320
321
322
323
324
325
326
    int		    n;
    int		    id;
    FcStrList	    *list;

    list = FcStrListCreate (dirs);
    if (!list)
	goto bail2;
    
    while ((dir = FcStrListNext (list)))
    {
Patrick Lam's avatar
Patrick Lam committed
327
	base = FcFileBaseName (base_name, dir);
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
	if (!FcCacheWriteStringOld (stdout, base))
	    goto bail3;
	if (PUTC (' ', stdout) == EOF)
	    goto bail3;
	if (!FcCacheWriteInt (stdout, 0))
	    goto bail3;
        if (PUTC (' ', stdout) == EOF)
	    goto bail3;
	if (!FcCacheWriteStringOld (stdout, FC_FONT_FILE_DIR))
	    goto bail3;
	if (PUTC ('\n', stdout) == EOF)
	    goto bail3;
    }
    
    for (n = 0; n < set->nfont; n++)
    {
	font = set->fonts[n];
	if (FcPatternGetString (font, FC_FILE, 0, (FcChar8 **) &file) != FcResultMatch)
	    goto bail3;
Patrick Lam's avatar
Patrick Lam committed
347
	base = FcFileBaseName (base_name, file);
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
	if (FcPatternGetInteger (font, FC_INDEX, 0, &id) != FcResultMatch)
	    goto bail3;
	if (FcDebug () & FC_DBG_CACHEV)
	    printf (" write file \"%s\"\n", base);
	if (!FcCacheWriteStringOld (stdout, base))
	    goto bail3;
	if (PUTC (' ', stdout) == EOF)
	    goto bail3;
	if (!FcCacheWriteInt (stdout, id))
	    goto bail3;
        if (PUTC (' ', stdout) == EOF)
	    goto bail3;
	name = FcNameUnparse (font);
	if (!name)
	    goto bail3;
	ret = FcCacheWriteStringOld (stdout, name);
	FcStrFree (name);
	if (!ret)
	    goto bail3;
	if (PUTC ('\n', stdout) == EOF)
	    goto bail3;
    }
    
    FcStrListDone (list);

    return FcTrue;
    
bail3:
    FcStrListDone (list);
bail2:
    return FcFalse;
}

int
main (int argc, char **argv)
{
    int		i;
#if HAVE_GETOPT_LONG || HAVE_GETOPT
    int		c;
    FcFontSet	*fs = FcFontSetCreate();
    FcStrSet    *dirs = FcStrSetCreate();
Patrick Lam's avatar
Patrick Lam committed
389
    char	*name_buf;
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410

#if HAVE_GETOPT_LONG
    while ((c = getopt_long (argc, argv, "fsVv?", longopts, NULL)) != -1)
#else
    while ((c = getopt (argc, argv, "fsVv?")) != -1)
#endif
    {
	switch (c) {
	case 'V':
	    fprintf (stderr, "fontconfig version %d.%d.%d\n", 
		     FC_MAJOR, FC_MINOR, FC_REVISION);
	    exit (0);
	default:
	    usage (argv[0]);
	}
    }
    i = optind;
#else
    i = 1;
#endif

411
412
413
    if (i >= argc)
        usage (argv[0]);

Patrick Lam's avatar
Patrick Lam committed
414
415
    if (name_buf = FcCacheFileRead (fs, dirs, argv[i]))
	FcCachePrintSet (fs, dirs, name_buf);
416
417
418
419
    else
    {
        FcStrSetDestroy (dirs);
        dirs = FcStrSetCreate ();
Patrick Lam's avatar
Patrick Lam committed
420
        if (FcCacheGlobalFileReadAndPrint (fs, dirs, argv[i]))
421
422
            ;
    }
423
424
425
426
427
428

    FcStrSetDestroy (dirs);
    FcFontSetDestroy (fs);

    return 0;
}