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