fcdir.c revision a32e9e42
12c393a42Smrg/*
2a6844aabSmrg * fontconfig/src/fcdir.c
32c393a42Smrg *
42c393a42Smrg * Copyright © 2000 Keith Packard
52c393a42Smrg *
62c393a42Smrg * Permission to use, copy, modify, distribute, and sell this software and its
72c393a42Smrg * documentation for any purpose is hereby granted without fee, provided that
82c393a42Smrg * the above copyright notice appear in all copies and that both that
92c393a42Smrg * copyright notice and this permission notice appear in supporting
10ca08ab68Smrg * documentation, and that the name of the author(s) not be used in
112c393a42Smrg * advertising or publicity pertaining to distribution of the software without
12ca08ab68Smrg * specific, written prior permission.  The authors make no
132c393a42Smrg * representations about the suitability of this software for any purpose.  It
142c393a42Smrg * is provided "as is" without express or implied warranty.
152c393a42Smrg *
16a6844aabSmrg * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
172c393a42Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18a6844aabSmrg * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
192c393a42Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
202c393a42Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
212c393a42Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
222c393a42Smrg * PERFORMANCE OF THIS SOFTWARE.
232c393a42Smrg */
242c393a42Smrg
252c393a42Smrg#include "fcint.h"
262c393a42Smrg#include <dirent.h>
272c393a42Smrg
282c393a42SmrgFcBool
292c393a42SmrgFcFileIsDir (const FcChar8 *file)
302c393a42Smrg{
312c393a42Smrg    struct stat	    statb;
322c393a42Smrg
33ca08ab68Smrg    if (FcStat (file, &statb) != 0)
342c393a42Smrg	return FcFalse;
352c393a42Smrg    return S_ISDIR(statb.st_mode);
362c393a42Smrg}
372c393a42Smrg
38c9710b42SmrgFcBool
39c9710b42SmrgFcFileIsLink (const FcChar8 *file)
40c9710b42Smrg{
41c9710b42Smrg#if HAVE_LSTAT
42c9710b42Smrg    struct stat statb;
43c9710b42Smrg
44c9710b42Smrg    if (lstat ((const char *)file, &statb) != 0)
45c9710b42Smrg	return FcFalse;
46c9710b42Smrg    return S_ISLNK (statb.st_mode);
47c9710b42Smrg#else
48c9710b42Smrg    return FcFalse;
49c9710b42Smrg#endif
50c9710b42Smrg}
51c9710b42Smrg
526fc018e4SmrgFcBool
536fc018e4SmrgFcFileIsFile (const FcChar8 *file)
546fc018e4Smrg{
556fc018e4Smrg    struct stat statb;
566fc018e4Smrg
576fc018e4Smrg    if (FcStat (file, &statb) != 0)
586fc018e4Smrg	return FcFalse;
596fc018e4Smrg    return S_ISREG (statb.st_mode);
606fc018e4Smrg}
616fc018e4Smrg
622c393a42Smrgstatic FcBool
632c393a42SmrgFcFileScanFontConfig (FcFontSet		*set,
642c393a42Smrg		      const FcChar8	*file,
652c393a42Smrg		      FcConfig		*config)
662c393a42Smrg{
67a32e9e42Smrg    int		i;
682c393a42Smrg    FcBool	ret = FcTrue;
69a32e9e42Smrg    int		old_nfont = set->nfont;
70953daebaSmrg    const FcChar8 *sysroot = FcConfigGetSysRoot (config);
71953daebaSmrg
72a32e9e42Smrg    if (FcDebug () & FC_DBG_SCAN)
73a32e9e42Smrg    {
74a32e9e42Smrg	printf ("\tScanning file %s...", file);
75a32e9e42Smrg	fflush (stdout);
76a32e9e42Smrg    }
77a32e9e42Smrg
78a32e9e42Smrg    if (!FcFreeTypeQueryAll (file, -1, NULL, NULL, set))
79953daebaSmrg	return FcFalse;
80ca08ab68Smrg
81a32e9e42Smrg    if (FcDebug () & FC_DBG_SCAN)
82a32e9e42Smrg	printf ("done\n");
83953daebaSmrg
84a32e9e42Smrg    for (i = old_nfont; i < set->nfont; i++)
85a32e9e42Smrg    {
86a32e9e42Smrg	FcPattern *font = set->fonts[i];
87953daebaSmrg
88953daebaSmrg	/*
89953daebaSmrg	 * Get rid of sysroot here so that targeting scan rule may contains FC_FILE pattern
90953daebaSmrg	 * and they should usually expect without sysroot.
91953daebaSmrg	 */
92a32e9e42Smrg	if (sysroot)
93953daebaSmrg	{
94953daebaSmrg	    size_t len = strlen ((const char *)sysroot);
95953daebaSmrg	    FcChar8 *f = NULL;
96953daebaSmrg
97953daebaSmrg	    if (FcPatternObjectGetString (font, FC_FILE_OBJECT, 0, &f) == FcResultMatch &&
98953daebaSmrg		strncmp ((const char *)f, (const char *)sysroot, len) == 0)
99953daebaSmrg	    {
100953daebaSmrg		FcChar8 *s = FcStrdup (f);
101953daebaSmrg		FcPatternObjectDel (font, FC_FILE_OBJECT);
102953daebaSmrg		if (s[len] != '/')
103953daebaSmrg		    len--;
104953daebaSmrg		else if (s[len+1] == '/')
105953daebaSmrg		    len++;
106953daebaSmrg		FcPatternObjectAddString (font, FC_FILE_OBJECT, &s[len]);
107953daebaSmrg		FcStrFree (s);
108953daebaSmrg	    }
109953daebaSmrg	}
1102c393a42Smrg
1112c393a42Smrg	/*
1122c393a42Smrg	 * Edit pattern with user-defined rules
1132c393a42Smrg	 */
114a32e9e42Smrg	if (config && !FcConfigSubstitute (config, font, FcMatchScan))
1152c393a42Smrg	    ret = FcFalse;
1162c393a42Smrg
117a32e9e42Smrg	if (FcDebug() & FC_DBG_SCANV)
1182c393a42Smrg	{
119a32e9e42Smrg	    printf ("Final font pattern:\n");
120a32e9e42Smrg	    FcPatternPrint (font);
1212c393a42Smrg	}
122a32e9e42Smrg    }
123953daebaSmrg
1242c393a42Smrg    return ret;
1252c393a42Smrg}
1262c393a42Smrg
1272c393a42SmrgFcBool
1282c393a42SmrgFcFileScanConfig (FcFontSet	*set,
1292c393a42Smrg		  FcStrSet	*dirs,
1302c393a42Smrg		  const FcChar8	*file,
1312c393a42Smrg		  FcConfig	*config)
1322c393a42Smrg{
1332c393a42Smrg    if (FcFileIsDir (file))
134953daebaSmrg    {
135953daebaSmrg	const FcChar8 *sysroot = FcConfigGetSysRoot (config);
136953daebaSmrg	const FcChar8 *d = file;
137953daebaSmrg	size_t len;
138953daebaSmrg
139953daebaSmrg	if (sysroot)
140953daebaSmrg	{
141953daebaSmrg		len = strlen ((const char *)sysroot);
142953daebaSmrg		if (strncmp ((const char *)file, (const char *)sysroot, len) == 0)
143953daebaSmrg		{
144953daebaSmrg			if (file[len] != '/')
145953daebaSmrg				len--;
146953daebaSmrg			else if (file[len+1] == '/')
147953daebaSmrg				len++;
148953daebaSmrg			d = &file[len];
149953daebaSmrg		}
150953daebaSmrg	}
151953daebaSmrg	return FcStrSetAdd (dirs, d);
152953daebaSmrg    }
1532c393a42Smrg    else
154b09479dcSmrg    {
155b09479dcSmrg	if (set)
156a32e9e42Smrg	    return FcFileScanFontConfig (set, file, config);
157b09479dcSmrg	else
158b09479dcSmrg	    return FcTrue;
159b09479dcSmrg    }
1602c393a42Smrg}
1612c393a42Smrg
1622c393a42SmrgFcBool
1632c393a42SmrgFcFileScan (FcFontSet	    *set,
1642c393a42Smrg	    FcStrSet	    *dirs,
165c9710b42Smrg	    FcFileCache	    *cache FC_UNUSED,
166a32e9e42Smrg	    FcBlanks	    *blanks FC_UNUSED,
1672c393a42Smrg	    const FcChar8   *file,
168c9710b42Smrg	    FcBool	    force FC_UNUSED)
1692c393a42Smrg{
170a32e9e42Smrg    return FcFileScanConfig (set, dirs, file, FcConfigGetCurrent ());
1712c393a42Smrg}
1722c393a42Smrg
1732c393a42Smrg/*
1742c393a42Smrg * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage
1752c393a42Smrg */
1762c393a42Smrgstatic int
1772c393a42Smrgcmpstringp(const void *p1, const void *p2)
1782c393a42Smrg{
1792c393a42Smrg    return strcmp(* (char **) p1, * (char **) p2);
1802c393a42Smrg}
1812c393a42Smrg
182a6844aabSmrgFcBool
183a6844aabSmrgFcDirScanConfig (FcFontSet	*set,
184a6844aabSmrg		 FcStrSet	*dirs,
185a6844aabSmrg		 const FcChar8	*dir,
186a6844aabSmrg		 FcBool		force, /* XXX unused */
187a6844aabSmrg		 FcConfig	*config)
1882c393a42Smrg{
1892c393a42Smrg    DIR			*d;
1902c393a42Smrg    struct dirent	*e;
1912c393a42Smrg    FcStrSet		*files;
1922c393a42Smrg    FcChar8		*file;
1932c393a42Smrg    FcChar8		*base;
1942c393a42Smrg    FcBool		ret = FcTrue;
1952c393a42Smrg    int			i;
1962c393a42Smrg
197a6844aabSmrg    if (!force)
198a6844aabSmrg	return FcFalse;
199a6844aabSmrg
200a6844aabSmrg    if (!set && !dirs)
201a6844aabSmrg	return FcTrue;
202a6844aabSmrg
2032c393a42Smrg    /* freed below */
2042c393a42Smrg    file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2052c393a42Smrg    if (!file) {
2062c393a42Smrg	ret = FcFalse;
2072c393a42Smrg	goto bail;
2082c393a42Smrg    }
2092c393a42Smrg
2102c393a42Smrg    strcpy ((char *) file, (char *) dir);
2112c393a42Smrg    strcat ((char *) file, "/");
2122c393a42Smrg    base = file + strlen ((char *) file);
213ca08ab68Smrg
2142c393a42Smrg    if (FcDebug () & FC_DBG_SCAN)
2152c393a42Smrg	printf ("\tScanning dir %s\n", dir);
2162c393a42Smrg
2172c393a42Smrg    d = opendir ((char *) dir);
2182c393a42Smrg    if (!d)
2192c393a42Smrg    {
2202c393a42Smrg	/* Don't complain about missing directories */
221a6844aabSmrg	if (errno != ENOENT)
2222c393a42Smrg	    ret = FcFalse;
223a6844aabSmrg	goto bail;
2242c393a42Smrg    }
2252c393a42Smrg
226953daebaSmrg    files = FcStrSetCreateEx (FCSS_ALLOW_DUPLICATES | FCSS_GROW_BY_64);
2272c393a42Smrg    if (!files)
2282c393a42Smrg    {
2292c393a42Smrg	ret = FcFalse;
2302c393a42Smrg	goto bail1;
2312c393a42Smrg    }
2322c393a42Smrg    while ((e = readdir (d)))
2332c393a42Smrg    {
2342c393a42Smrg	if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN)
2352c393a42Smrg	{
2362c393a42Smrg	    strcpy ((char *) base, (char *) e->d_name);
2372c393a42Smrg	    if (!FcStrSetAdd (files, file)) {
2382c393a42Smrg		ret = FcFalse;
2392c393a42Smrg		goto bail2;
2402c393a42Smrg	    }
2412c393a42Smrg	}
2422c393a42Smrg    }
2432c393a42Smrg
2442c393a42Smrg    /*
2452c393a42Smrg     * Sort files to make things prettier
2462c393a42Smrg     */
2472c393a42Smrg    qsort(files->strs, files->num, sizeof(FcChar8 *), cmpstringp);
248a6844aabSmrg
2492c393a42Smrg    /*
2502c393a42Smrg     * Scan file files to build font patterns
2512c393a42Smrg     */
2522c393a42Smrg    for (i = 0; i < files->num; i++)
253a32e9e42Smrg	FcFileScanConfig (set, dirs, files->strs[i], config);
254ca08ab68Smrg
255a6844aabSmrgbail2:
256a6844aabSmrg    FcStrSetDestroy (files);
257a6844aabSmrgbail1:
258a6844aabSmrg    closedir (d);
259a6844aabSmrgbail:
260ca08ab68Smrg    if (file)
261ca08ab68Smrg	free (file);
262ca08ab68Smrg
263a6844aabSmrg    return ret;
264a6844aabSmrg}
265a6844aabSmrg
266a6844aabSmrgFcBool
267a6844aabSmrgFcDirScan (FcFontSet	    *set,
268a6844aabSmrg	   FcStrSet	    *dirs,
269a32e9e42Smrg	   FcFileCache	    *cache FC_UNUSED,
270a32e9e42Smrg	   FcBlanks	    *blanks FC_UNUSED,
271a6844aabSmrg	   const FcChar8    *dir,
272a32e9e42Smrg	   FcBool	    force FC_UNUSED)
273a6844aabSmrg{
274a6844aabSmrg    if (cache || !force)
275a6844aabSmrg	return FcFalse;
276a6844aabSmrg
277a32e9e42Smrg    return FcDirScanConfig (set, dirs, dir, force, FcConfigGetCurrent ());
278a6844aabSmrg}
279a6844aabSmrg
280a6844aabSmrg/*
281a6844aabSmrg * Scan the specified directory and construct a cache of its contents
282a6844aabSmrg */
283a6844aabSmrgFcCache *
284a6844aabSmrgFcDirCacheScan (const FcChar8 *dir, FcConfig *config)
285a6844aabSmrg{
286a6844aabSmrg    FcStrSet		*dirs;
287a6844aabSmrg    FcFontSet		*set;
288a6844aabSmrg    FcCache		*cache = NULL;
289a6844aabSmrg    struct stat		dir_stat;
290953daebaSmrg    const FcChar8	*sysroot = FcConfigGetSysRoot (config);
291953daebaSmrg    FcChar8		*d;
292a32e9e42Smrg#ifndef _WIN32
293953daebaSmrg    int			fd = -1;
294a32e9e42Smrg#endif
295953daebaSmrg
296953daebaSmrg    if (sysroot)
297953daebaSmrg	d = FcStrBuildFilename (sysroot, dir, NULL);
298953daebaSmrg    else
299953daebaSmrg	d = FcStrdup (dir);
300a6844aabSmrg
301a6844aabSmrg    if (FcDebug () & FC_DBG_FONTSET)
302953daebaSmrg	printf ("cache scan dir %s\n", d);
303a6844aabSmrg
304953daebaSmrg    if (FcStatChecksum (d, &dir_stat) < 0)
305a6844aabSmrg	goto bail;
306a6844aabSmrg
307a6844aabSmrg    set = FcFontSetCreate();
308a6844aabSmrg    if (!set)
309a6844aabSmrg	goto bail;
310a6844aabSmrg
311953daebaSmrg    dirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
312a6844aabSmrg    if (!dirs)
313a6844aabSmrg	goto bail1;
314a6844aabSmrg
315953daebaSmrg#ifndef _WIN32
316953daebaSmrg    fd = FcDirCacheLock (dir, config);
317953daebaSmrg#endif
318a6844aabSmrg    /*
319a6844aabSmrg     * Scan the dir
320a6844aabSmrg     */
321a32e9e42Smrg    if (!FcDirScanConfig (set, dirs, d, FcTrue, config))
322a6844aabSmrg	goto bail2;
323a6844aabSmrg
3242c393a42Smrg    /*
3252c393a42Smrg     * Build the cache object
3262c393a42Smrg     */
3272c393a42Smrg    cache = FcDirCacheBuild (set, dir, &dir_stat, dirs);
3282c393a42Smrg    if (!cache)
329a6844aabSmrg	goto bail2;
330ca08ab68Smrg
3312c393a42Smrg    /*
3322c393a42Smrg     * Write out the cache file, ignoring any troubles
3332c393a42Smrg     */
3342c393a42Smrg    FcDirCacheWrite (cache, config);
335ca08ab68Smrg
3362c393a42Smrg bail2:
337953daebaSmrg#ifndef _WIN32
338953daebaSmrg    FcDirCacheUnlock (fd);
339953daebaSmrg#endif
340a6844aabSmrg    FcStrSetDestroy (dirs);
3412c393a42Smrg bail1:
3422c393a42Smrg    FcFontSetDestroy (set);
3432c393a42Smrg bail:
344953daebaSmrg    FcStrFree (d);
345953daebaSmrg
3462c393a42Smrg    return cache;
3472c393a42Smrg}
3482c393a42Smrg
349b09479dcSmrgFcCache *
350b09479dcSmrgFcDirCacheRescan (const FcChar8 *dir, FcConfig *config)
351b09479dcSmrg{
352953daebaSmrg    FcCache *cache;
353b09479dcSmrg    FcCache *new = NULL;
354b09479dcSmrg    struct stat dir_stat;
355b09479dcSmrg    FcStrSet *dirs;
356953daebaSmrg    const FcChar8 *sysroot = FcConfigGetSysRoot (config);
357953daebaSmrg    FcChar8 *d = NULL;
358a32e9e42Smrg#ifndef _WIN32
359953daebaSmrg    int fd = -1;
360a32e9e42Smrg#endif
361b09479dcSmrg
362953daebaSmrg    cache = FcDirCacheLoad (dir, config, NULL);
363b09479dcSmrg    if (!cache)
364b09479dcSmrg	goto bail;
365953daebaSmrg
366953daebaSmrg    if (sysroot)
367953daebaSmrg	d = FcStrBuildFilename (sysroot, dir, NULL);
368953daebaSmrg    else
369953daebaSmrg	d = FcStrdup (dir);
370953daebaSmrg    if (FcStatChecksum (d, &dir_stat) < 0)
371953daebaSmrg	goto bail;
372953daebaSmrg    dirs = FcStrSetCreateEx (FCSS_GROW_BY_64);
373b09479dcSmrg    if (!dirs)
374b09479dcSmrg	goto bail;
375b09479dcSmrg
376953daebaSmrg#ifndef _WIN32
377953daebaSmrg    fd = FcDirCacheLock (dir, config);
378953daebaSmrg#endif
379b09479dcSmrg    /*
380b09479dcSmrg     * Scan the dir
381b09479dcSmrg     */
382a32e9e42Smrg    if (!FcDirScanConfig (NULL, dirs, d, FcTrue, config))
383b09479dcSmrg	goto bail1;
384b09479dcSmrg    /*
385b09479dcSmrg     * Rebuild the cache object
386b09479dcSmrg     */
387b09479dcSmrg    new = FcDirCacheRebuild (cache, &dir_stat, dirs);
388b09479dcSmrg    if (!new)
389b09479dcSmrg	goto bail1;
390b09479dcSmrg    FcDirCacheUnload (cache);
391b09479dcSmrg    /*
392b09479dcSmrg     * Write out the cache file, ignoring any troubles
393b09479dcSmrg     */
394b09479dcSmrg    FcDirCacheWrite (new, config);
395b09479dcSmrg
396b09479dcSmrgbail1:
397953daebaSmrg#ifndef _WIN32
398953daebaSmrg    FcDirCacheUnlock (fd);
399953daebaSmrg#endif
400b09479dcSmrg    FcStrSetDestroy (dirs);
401b09479dcSmrgbail:
402953daebaSmrg    if (d)
403953daebaSmrg	FcStrFree (d);
404953daebaSmrg
405b09479dcSmrg    return new;
406b09479dcSmrg}
407b09479dcSmrg
4082c393a42Smrg/*
4092c393a42Smrg * Read (or construct) the cache for a directory
4102c393a42Smrg */
4112c393a42SmrgFcCache *
4122c393a42SmrgFcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config)
4132c393a42Smrg{
4142c393a42Smrg    FcCache		*cache = NULL;
4152c393a42Smrg
416a32e9e42Smrg    FcDirCacheCreateUUID ((FcChar8 *) dir, FcFalse, config);
4172c393a42Smrg    /* Try to use existing cache file */
4182c393a42Smrg    if (!force)
4192c393a42Smrg	cache = FcDirCacheLoad (dir, config, NULL);
420ca08ab68Smrg
4212c393a42Smrg    /* Not using existing cache file, construct new cache */
4222c393a42Smrg    if (!cache)
4232c393a42Smrg	cache = FcDirCacheScan (dir, config);
424a32e9e42Smrg    if (cache)
425a32e9e42Smrg    {
426a32e9e42Smrg	FcFontSet *fs = FcCacheSet (cache);
427a32e9e42Smrg
428a32e9e42Smrg	if (cache->dirs_count == 0 && (!fs || fs->nfont == 0))
429a32e9e42Smrg	    FcDirCacheDeleteUUID (dir, config);
430a32e9e42Smrg    }
431ca08ab68Smrg
4322c393a42Smrg    return cache;
4332c393a42Smrg}
4342c393a42Smrg
4352c393a42SmrgFcBool
436c9710b42SmrgFcDirSave (FcFontSet *set FC_UNUSED, FcStrSet * dirs FC_UNUSED, const FcChar8 *dir FC_UNUSED)
4372c393a42Smrg{
4382c393a42Smrg    return FcFalse; /* XXX deprecated */
4392c393a42Smrg}
4402c393a42Smrg#define __fcdir__
4412c393a42Smrg#include "fcaliastail.h"
4422c393a42Smrg#undef __fcdir__
443