fcdir.c revision c9710b42
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
522c393a42Smrgstatic FcBool
532c393a42SmrgFcFileScanFontConfig (FcFontSet		*set,
542c393a42Smrg		      FcBlanks		*blanks,
552c393a42Smrg		      const FcChar8	*file,
562c393a42Smrg		      FcConfig		*config)
572c393a42Smrg{
582c393a42Smrg    FcPattern	*font;
592c393a42Smrg    FcBool	ret = FcTrue;
602c393a42Smrg    int		id;
612c393a42Smrg    int		count = 0;
62ca08ab68Smrg
632c393a42Smrg    id = 0;
642c393a42Smrg    do
652c393a42Smrg    {
662c393a42Smrg	font = 0;
672c393a42Smrg	/*
682c393a42Smrg	 * Nothing in the cache, scan the file
692c393a42Smrg	 */
702c393a42Smrg	if (FcDebug () & FC_DBG_SCAN)
712c393a42Smrg	{
722c393a42Smrg	    printf ("\tScanning file %s...", file);
732c393a42Smrg	    fflush (stdout);
742c393a42Smrg	}
752c393a42Smrg	font = FcFreeTypeQuery (file, id, blanks, &count);
762c393a42Smrg	if (FcDebug () & FC_DBG_SCAN)
772c393a42Smrg	    printf ("done\n");
782c393a42Smrg
792c393a42Smrg	/*
802c393a42Smrg	 * Edit pattern with user-defined rules
812c393a42Smrg	 */
82ca08ab68Smrg	if (font && config && !FcConfigSubstitute (config, font, FcMatchScan))
832c393a42Smrg	{
842c393a42Smrg	    FcPatternDestroy (font);
852c393a42Smrg	    font = NULL;
862c393a42Smrg	    ret = FcFalse;
872c393a42Smrg	}
882c393a42Smrg
892c393a42Smrg	/*
902c393a42Smrg	 * Add the font
912c393a42Smrg	 */
92ca08ab68Smrg	if (font)
932c393a42Smrg	{
942c393a42Smrg	    if (FcDebug() & FC_DBG_SCANV)
952c393a42Smrg	    {
962c393a42Smrg		printf ("Final font pattern:\n");
972c393a42Smrg		FcPatternPrint (font);
982c393a42Smrg	    }
992c393a42Smrg	    if (!FcFontSetAdd (set, font))
1002c393a42Smrg	    {
1012c393a42Smrg		FcPatternDestroy (font);
1022c393a42Smrg		font = NULL;
1032c393a42Smrg		ret = FcFalse;
1042c393a42Smrg	    }
1052c393a42Smrg	}
1062c393a42Smrg	else if (font)
1072c393a42Smrg	    FcPatternDestroy (font);
1082c393a42Smrg	id++;
1092c393a42Smrg    } while (font && ret && id < count);
1102c393a42Smrg    return ret;
1112c393a42Smrg}
1122c393a42Smrg
1132c393a42SmrgFcBool
1142c393a42SmrgFcFileScanConfig (FcFontSet	*set,
1152c393a42Smrg		  FcStrSet	*dirs,
1162c393a42Smrg		  FcBlanks	*blanks,
1172c393a42Smrg		  const FcChar8	*file,
1182c393a42Smrg		  FcConfig	*config)
1192c393a42Smrg{
1202c393a42Smrg    if (FcFileIsDir (file))
1212c393a42Smrg	return FcStrSetAdd (dirs, file);
1222c393a42Smrg    else
1232c393a42Smrg	return FcFileScanFontConfig (set, blanks, file, config);
1242c393a42Smrg}
1252c393a42Smrg
1262c393a42SmrgFcBool
1272c393a42SmrgFcFileScan (FcFontSet	    *set,
1282c393a42Smrg	    FcStrSet	    *dirs,
129c9710b42Smrg	    FcFileCache	    *cache FC_UNUSED,
1302c393a42Smrg	    FcBlanks	    *blanks,
1312c393a42Smrg	    const FcChar8   *file,
132c9710b42Smrg	    FcBool	    force FC_UNUSED)
1332c393a42Smrg{
134a6844aabSmrg    return FcFileScanConfig (set, dirs, blanks, file, FcConfigGetCurrent ());
1352c393a42Smrg}
1362c393a42Smrg
1372c393a42Smrg/*
1382c393a42Smrg * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage
1392c393a42Smrg */
1402c393a42Smrgstatic int
1412c393a42Smrgcmpstringp(const void *p1, const void *p2)
1422c393a42Smrg{
1432c393a42Smrg    return strcmp(* (char **) p1, * (char **) p2);
1442c393a42Smrg}
1452c393a42Smrg
146a6844aabSmrgFcBool
147a6844aabSmrgFcDirScanConfig (FcFontSet	*set,
148a6844aabSmrg		 FcStrSet	*dirs,
149a6844aabSmrg		 FcBlanks	*blanks,
150a6844aabSmrg		 const FcChar8	*dir,
151a6844aabSmrg		 FcBool		force, /* XXX unused */
152a6844aabSmrg		 FcConfig	*config)
1532c393a42Smrg{
1542c393a42Smrg    DIR			*d;
1552c393a42Smrg    struct dirent	*e;
1562c393a42Smrg    FcStrSet		*files;
1572c393a42Smrg    FcChar8		*file;
1582c393a42Smrg    FcChar8		*base;
1592c393a42Smrg    FcBool		ret = FcTrue;
1602c393a42Smrg    int			i;
1612c393a42Smrg
162a6844aabSmrg    if (!force)
163a6844aabSmrg	return FcFalse;
164a6844aabSmrg
165a6844aabSmrg    if (!set && !dirs)
166a6844aabSmrg	return FcTrue;
167a6844aabSmrg
168a6844aabSmrg    if (!blanks)
169a6844aabSmrg	blanks = FcConfigGetBlanks (config);
1702c393a42Smrg
1712c393a42Smrg    /* freed below */
1722c393a42Smrg    file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
1732c393a42Smrg    if (!file) {
1742c393a42Smrg	ret = FcFalse;
1752c393a42Smrg	goto bail;
1762c393a42Smrg    }
1772c393a42Smrg
1782c393a42Smrg    strcpy ((char *) file, (char *) dir);
1792c393a42Smrg    strcat ((char *) file, "/");
1802c393a42Smrg    base = file + strlen ((char *) file);
181ca08ab68Smrg
1822c393a42Smrg    if (FcDebug () & FC_DBG_SCAN)
1832c393a42Smrg	printf ("\tScanning dir %s\n", dir);
1842c393a42Smrg
1852c393a42Smrg    d = opendir ((char *) dir);
1862c393a42Smrg    if (!d)
1872c393a42Smrg    {
1882c393a42Smrg	/* Don't complain about missing directories */
189a6844aabSmrg	if (errno != ENOENT)
1902c393a42Smrg	    ret = FcFalse;
191a6844aabSmrg	goto bail;
1922c393a42Smrg    }
1932c393a42Smrg
1942c393a42Smrg    files = FcStrSetCreate ();
1952c393a42Smrg    if (!files)
1962c393a42Smrg    {
1972c393a42Smrg	ret = FcFalse;
1982c393a42Smrg	goto bail1;
1992c393a42Smrg    }
2002c393a42Smrg    while ((e = readdir (d)))
2012c393a42Smrg    {
2022c393a42Smrg	if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN)
2032c393a42Smrg	{
2042c393a42Smrg	    strcpy ((char *) base, (char *) e->d_name);
2052c393a42Smrg	    if (!FcStrSetAdd (files, file)) {
2062c393a42Smrg		ret = FcFalse;
2072c393a42Smrg		goto bail2;
2082c393a42Smrg	    }
2092c393a42Smrg	}
2102c393a42Smrg    }
2112c393a42Smrg
2122c393a42Smrg    /*
2132c393a42Smrg     * Sort files to make things prettier
2142c393a42Smrg     */
2152c393a42Smrg    qsort(files->strs, files->num, sizeof(FcChar8 *), cmpstringp);
216a6844aabSmrg
2172c393a42Smrg    /*
2182c393a42Smrg     * Scan file files to build font patterns
2192c393a42Smrg     */
2202c393a42Smrg    for (i = 0; i < files->num; i++)
2212c393a42Smrg	FcFileScanConfig (set, dirs, blanks, files->strs[i], config);
222ca08ab68Smrg
223a6844aabSmrgbail2:
224a6844aabSmrg    FcStrSetDestroy (files);
225a6844aabSmrgbail1:
226a6844aabSmrg    closedir (d);
227a6844aabSmrgbail:
228ca08ab68Smrg    if (file)
229ca08ab68Smrg	free (file);
230ca08ab68Smrg
231a6844aabSmrg    return ret;
232a6844aabSmrg}
233a6844aabSmrg
234a6844aabSmrgFcBool
235a6844aabSmrgFcDirScan (FcFontSet	    *set,
236a6844aabSmrg	   FcStrSet	    *dirs,
237a6844aabSmrg	   FcFileCache	    *cache, /* XXX unused */
238a6844aabSmrg	   FcBlanks	    *blanks,
239a6844aabSmrg	   const FcChar8    *dir,
240a6844aabSmrg	   FcBool	    force /* XXX unused */)
241a6844aabSmrg{
242a6844aabSmrg    if (cache || !force)
243a6844aabSmrg	return FcFalse;
244a6844aabSmrg
245a6844aabSmrg    return FcDirScanConfig (set, dirs, blanks, dir, force, FcConfigGetCurrent ());
246a6844aabSmrg}
247a6844aabSmrg
248a6844aabSmrg/*
249a6844aabSmrg * Scan the specified directory and construct a cache of its contents
250a6844aabSmrg */
251a6844aabSmrgFcCache *
252a6844aabSmrgFcDirCacheScan (const FcChar8 *dir, FcConfig *config)
253a6844aabSmrg{
254a6844aabSmrg    FcStrSet		*dirs;
255a6844aabSmrg    FcFontSet		*set;
256a6844aabSmrg    FcCache		*cache = NULL;
257a6844aabSmrg    struct stat		dir_stat;
258a6844aabSmrg
259a6844aabSmrg    if (FcDebug () & FC_DBG_FONTSET)
260a6844aabSmrg	printf ("cache scan dir %s\n", dir);
261a6844aabSmrg
262ca08ab68Smrg    if (FcStatChecksum (dir, &dir_stat) < 0)
263a6844aabSmrg	goto bail;
264a6844aabSmrg
265a6844aabSmrg    set = FcFontSetCreate();
266a6844aabSmrg    if (!set)
267a6844aabSmrg	goto bail;
268a6844aabSmrg
269a6844aabSmrg    dirs = FcStrSetCreate ();
270a6844aabSmrg    if (!dirs)
271a6844aabSmrg	goto bail1;
272a6844aabSmrg
273a6844aabSmrg    /*
274a6844aabSmrg     * Scan the dir
275a6844aabSmrg     */
276a6844aabSmrg    if (!FcDirScanConfig (set, dirs, NULL, dir, FcTrue, config))
277a6844aabSmrg	goto bail2;
278a6844aabSmrg
2792c393a42Smrg    /*
2802c393a42Smrg     * Build the cache object
2812c393a42Smrg     */
2822c393a42Smrg    cache = FcDirCacheBuild (set, dir, &dir_stat, dirs);
2832c393a42Smrg    if (!cache)
284a6844aabSmrg	goto bail2;
285ca08ab68Smrg
2862c393a42Smrg    /*
2872c393a42Smrg     * Write out the cache file, ignoring any troubles
2882c393a42Smrg     */
2892c393a42Smrg    FcDirCacheWrite (cache, config);
290ca08ab68Smrg
2912c393a42Smrg bail2:
292a6844aabSmrg    FcStrSetDestroy (dirs);
2932c393a42Smrg bail1:
2942c393a42Smrg    FcFontSetDestroy (set);
2952c393a42Smrg bail:
2962c393a42Smrg    return cache;
2972c393a42Smrg}
2982c393a42Smrg
2992c393a42Smrg/*
3002c393a42Smrg * Read (or construct) the cache for a directory
3012c393a42Smrg */
3022c393a42SmrgFcCache *
3032c393a42SmrgFcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config)
3042c393a42Smrg{
3052c393a42Smrg    FcCache		*cache = NULL;
3062c393a42Smrg
3072c393a42Smrg    /* Try to use existing cache file */
3082c393a42Smrg    if (!force)
3092c393a42Smrg	cache = FcDirCacheLoad (dir, config, NULL);
310ca08ab68Smrg
3112c393a42Smrg    /* Not using existing cache file, construct new cache */
3122c393a42Smrg    if (!cache)
3132c393a42Smrg	cache = FcDirCacheScan (dir, config);
314ca08ab68Smrg
3152c393a42Smrg    return cache;
3162c393a42Smrg}
3172c393a42Smrg
3182c393a42SmrgFcBool
319c9710b42SmrgFcDirSave (FcFontSet *set FC_UNUSED, FcStrSet * dirs FC_UNUSED, const FcChar8 *dir FC_UNUSED)
3202c393a42Smrg{
3212c393a42Smrg    return FcFalse; /* XXX deprecated */
3222c393a42Smrg}
3232c393a42Smrg#define __fcdir__
3242c393a42Smrg#include "fcaliastail.h"
3252c393a42Smrg#undef __fcdir__
326