fcdir.c revision a6844aab
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 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 * 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 ((const char *) 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 && !FcConfigSubstituteWithPat (config, font, NULL, FcMatchScan))
69	{
70	    FcPatternDestroy (font);
71	    font = NULL;
72	    ret = FcFalse;
73	}
74
75	/*
76	 * Add the font
77	 */
78	if (font && (!config || FcConfigAcceptFont (config, 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    return ret;
215}
216
217FcBool
218FcDirScan (FcFontSet	    *set,
219	   FcStrSet	    *dirs,
220	   FcFileCache	    *cache, /* XXX unused */
221	   FcBlanks	    *blanks,
222	   const FcChar8    *dir,
223	   FcBool	    force /* XXX unused */)
224{
225    if (cache || !force)
226	return FcFalse;
227
228    return FcDirScanConfig (set, dirs, blanks, dir, force, FcConfigGetCurrent ());
229}
230
231/*
232 * Scan the specified directory and construct a cache of its contents
233 */
234FcCache *
235FcDirCacheScan (const FcChar8 *dir, FcConfig *config)
236{
237    FcStrSet		*dirs;
238    FcBool		ret = FcTrue;
239    FcFontSet		*set;
240    FcCache		*cache = NULL;
241    struct stat		dir_stat;
242
243    if (FcDebug () & FC_DBG_FONTSET)
244	printf ("cache scan dir %s\n", dir);
245
246    if (FcStat ((char *) dir, &dir_stat) < 0)
247    {
248	if (errno != ENOENT)
249	    ret = FcFalse;
250	goto bail;
251    }
252
253    set = FcFontSetCreate();
254    if (!set)
255    {
256	ret = FcFalse;
257	goto bail;
258    }
259
260    dirs = FcStrSetCreate ();
261    if (!dirs)
262    {
263	ret = FcFalse;
264	goto bail1;
265    }
266
267    /*
268     * Scan the dir
269     */
270    if (!FcDirScanConfig (set, dirs, NULL, dir, FcTrue, config))
271    {
272	ret = FcFalse;
273	goto bail2;
274    }
275
276    /*
277     * Build the cache object
278     */
279    cache = FcDirCacheBuild (set, dir, &dir_stat, dirs);
280    if (!cache)
281    {
282	ret = FcFalse;
283	goto bail2;
284    }
285
286    /*
287     * Write out the cache file, ignoring any troubles
288     */
289    FcDirCacheWrite (cache, config);
290
291 bail2:
292    FcStrSetDestroy (dirs);
293 bail1:
294    FcFontSetDestroy (set);
295 bail:
296    return cache;
297}
298
299/*
300 * Read (or construct) the cache for a directory
301 */
302FcCache *
303FcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config)
304{
305    FcCache		*cache = NULL;
306
307    if (config && !FcConfigAcceptFilename (config, dir))
308	return NULL;
309
310    /* Try to use existing cache file */
311    if (!force)
312	cache = FcDirCacheLoad (dir, config, NULL);
313
314    /* Not using existing cache file, construct new cache */
315    if (!cache)
316	cache = FcDirCacheScan (dir, config);
317
318    return cache;
319}
320
321FcBool
322FcDirSave (FcFontSet *set, FcStrSet * dirs, const FcChar8 *dir)
323{
324    return FcFalse; /* XXX deprecated */
325}
326#define __fcdir__
327#include "fcaliastail.h"
328#undef __fcdir__
329