fcdir.c revision 6fc018e4
1/*
2 * fontconfig/src/fcdir.c
3 *
4 * Copyright © 2000 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#include "fcint.h"
26#include <dirent.h>
27
28FcBool
29FcFileIsDir (const FcChar8 *file)
30{
31    struct stat	    statb;
32
33    if (FcStat (file, &statb) != 0)
34	return FcFalse;
35    return S_ISDIR(statb.st_mode);
36}
37
38FcBool
39FcFileIsLink (const FcChar8 *file)
40{
41#if HAVE_LSTAT
42    struct stat statb;
43
44    if (lstat ((const char *)file, &statb) != 0)
45	return FcFalse;
46    return S_ISLNK (statb.st_mode);
47#else
48    return FcFalse;
49#endif
50}
51
52FcBool
53FcFileIsFile (const FcChar8 *file)
54{
55    struct stat statb;
56
57    if (FcStat (file, &statb) != 0)
58	return FcFalse;
59    return S_ISREG (statb.st_mode);
60}
61
62static FcBool
63FcFileScanFontConfig (FcFontSet		*set,
64		      FcBlanks		*blanks,
65		      const FcChar8	*file,
66		      FcConfig		*config)
67{
68    FcPattern	*font;
69    FcBool	ret = FcTrue;
70    int		id;
71    int		count = 0;
72
73    id = 0;
74    do
75    {
76	font = 0;
77	/*
78	 * Nothing in the cache, scan the file
79	 */
80	if (FcDebug () & FC_DBG_SCAN)
81	{
82	    printf ("\tScanning file %s...", file);
83	    fflush (stdout);
84	}
85	font = FcFreeTypeQuery (file, id, blanks, &count);
86	if (FcDebug () & FC_DBG_SCAN)
87	    printf ("done\n");
88
89	/*
90	 * Edit pattern with user-defined rules
91	 */
92	if (font && config && !FcConfigSubstitute (config, font, FcMatchScan))
93	{
94	    FcPatternDestroy (font);
95	    font = NULL;
96	    ret = FcFalse;
97	}
98
99	/*
100	 * Add the font
101	 */
102	if (font)
103	{
104	    if (FcDebug() & FC_DBG_SCANV)
105	    {
106		printf ("Final font pattern:\n");
107		FcPatternPrint (font);
108	    }
109	    if (!FcFontSetAdd (set, font))
110	    {
111		FcPatternDestroy (font);
112		font = NULL;
113		ret = FcFalse;
114	    }
115	}
116	else if (font)
117	    FcPatternDestroy (font);
118	id++;
119    } while (font && ret && id < count);
120    return ret;
121}
122
123FcBool
124FcFileScanConfig (FcFontSet	*set,
125		  FcStrSet	*dirs,
126		  FcBlanks	*blanks,
127		  const FcChar8	*file,
128		  FcConfig	*config)
129{
130    if (FcFileIsDir (file))
131	return FcStrSetAdd (dirs, file);
132    else
133	return FcFileScanFontConfig (set, blanks, file, config);
134}
135
136FcBool
137FcFileScan (FcFontSet	    *set,
138	    FcStrSet	    *dirs,
139	    FcFileCache	    *cache FC_UNUSED,
140	    FcBlanks	    *blanks,
141	    const FcChar8   *file,
142	    FcBool	    force FC_UNUSED)
143{
144    return FcFileScanConfig (set, dirs, blanks, file, FcConfigGetCurrent ());
145}
146
147/*
148 * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage
149 */
150static int
151cmpstringp(const void *p1, const void *p2)
152{
153    return strcmp(* (char **) p1, * (char **) p2);
154}
155
156FcBool
157FcDirScanConfig (FcFontSet	*set,
158		 FcStrSet	*dirs,
159		 FcBlanks	*blanks,
160		 const FcChar8	*dir,
161		 FcBool		force, /* XXX unused */
162		 FcConfig	*config)
163{
164    DIR			*d;
165    struct dirent	*e;
166    FcStrSet		*files;
167    FcChar8		*file;
168    FcChar8		*base;
169    FcBool		ret = FcTrue;
170    int			i;
171
172    if (!force)
173	return FcFalse;
174
175    if (!set && !dirs)
176	return FcTrue;
177
178    if (!blanks)
179	blanks = FcConfigGetBlanks (config);
180
181    /* freed below */
182    file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
183    if (!file) {
184	ret = FcFalse;
185	goto bail;
186    }
187
188    strcpy ((char *) file, (char *) dir);
189    strcat ((char *) file, "/");
190    base = file + strlen ((char *) file);
191
192    if (FcDebug () & FC_DBG_SCAN)
193	printf ("\tScanning dir %s\n", dir);
194
195    d = opendir ((char *) dir);
196    if (!d)
197    {
198	/* Don't complain about missing directories */
199	if (errno != ENOENT)
200	    ret = FcFalse;
201	goto bail;
202    }
203
204    files = FcStrSetCreate ();
205    if (!files)
206    {
207	ret = FcFalse;
208	goto bail1;
209    }
210    while ((e = readdir (d)))
211    {
212	if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN)
213	{
214	    strcpy ((char *) base, (char *) e->d_name);
215	    if (!FcStrSetAdd (files, file)) {
216		ret = FcFalse;
217		goto bail2;
218	    }
219	}
220    }
221
222    /*
223     * Sort files to make things prettier
224     */
225    qsort(files->strs, files->num, sizeof(FcChar8 *), cmpstringp);
226
227    /*
228     * Scan file files to build font patterns
229     */
230    for (i = 0; i < files->num; i++)
231	FcFileScanConfig (set, dirs, blanks, files->strs[i], config);
232
233bail2:
234    FcStrSetDestroy (files);
235bail1:
236    closedir (d);
237bail:
238    if (file)
239	free (file);
240
241    return ret;
242}
243
244FcBool
245FcDirScan (FcFontSet	    *set,
246	   FcStrSet	    *dirs,
247	   FcFileCache	    *cache, /* XXX unused */
248	   FcBlanks	    *blanks,
249	   const FcChar8    *dir,
250	   FcBool	    force /* XXX unused */)
251{
252    if (cache || !force)
253	return FcFalse;
254
255    return FcDirScanConfig (set, dirs, blanks, dir, force, FcConfigGetCurrent ());
256}
257
258/*
259 * Scan the specified directory and construct a cache of its contents
260 */
261FcCache *
262FcDirCacheScan (const FcChar8 *dir, FcConfig *config)
263{
264    FcStrSet		*dirs;
265    FcFontSet		*set;
266    FcCache		*cache = NULL;
267    struct stat		dir_stat;
268
269    if (FcDebug () & FC_DBG_FONTSET)
270	printf ("cache scan dir %s\n", dir);
271
272    if (FcStatChecksum (dir, &dir_stat) < 0)
273	goto bail;
274
275    set = FcFontSetCreate();
276    if (!set)
277	goto bail;
278
279    dirs = FcStrSetCreate ();
280    if (!dirs)
281	goto bail1;
282
283    /*
284     * Scan the dir
285     */
286    if (!FcDirScanConfig (set, dirs, NULL, dir, FcTrue, config))
287	goto bail2;
288
289    /*
290     * Build the cache object
291     */
292    cache = FcDirCacheBuild (set, dir, &dir_stat, dirs);
293    if (!cache)
294	goto bail2;
295
296    /*
297     * Write out the cache file, ignoring any troubles
298     */
299    FcDirCacheWrite (cache, config);
300
301 bail2:
302    FcStrSetDestroy (dirs);
303 bail1:
304    FcFontSetDestroy (set);
305 bail:
306    return cache;
307}
308
309/*
310 * Read (or construct) the cache for a directory
311 */
312FcCache *
313FcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config)
314{
315    FcCache		*cache = NULL;
316
317    /* Try to use existing cache file */
318    if (!force)
319	cache = FcDirCacheLoad (dir, config, NULL);
320
321    /* Not using existing cache file, construct new cache */
322    if (!cache)
323	cache = FcDirCacheScan (dir, config);
324
325    return cache;
326}
327
328FcBool
329FcDirSave (FcFontSet *set FC_UNUSED, FcStrSet * dirs FC_UNUSED, const FcChar8 *dir FC_UNUSED)
330{
331    return FcFalse; /* XXX deprecated */
332}
333#define __fcdir__
334#include "fcaliastail.h"
335#undef __fcdir__
336