fcdir.c revision 6fc018e4
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		      FcBlanks		*blanks,
652c393a42Smrg		      const FcChar8	*file,
662c393a42Smrg		      FcConfig		*config)
672c393a42Smrg{
682c393a42Smrg    FcPattern	*font;
692c393a42Smrg    FcBool	ret = FcTrue;
702c393a42Smrg    int		id;
712c393a42Smrg    int		count = 0;
72ca08ab68Smrg
732c393a42Smrg    id = 0;
742c393a42Smrg    do
752c393a42Smrg    {
762c393a42Smrg	font = 0;
772c393a42Smrg	/*
782c393a42Smrg	 * Nothing in the cache, scan the file
792c393a42Smrg	 */
802c393a42Smrg	if (FcDebug () & FC_DBG_SCAN)
812c393a42Smrg	{
822c393a42Smrg	    printf ("\tScanning file %s...", file);
832c393a42Smrg	    fflush (stdout);
842c393a42Smrg	}
852c393a42Smrg	font = FcFreeTypeQuery (file, id, blanks, &count);
862c393a42Smrg	if (FcDebug () & FC_DBG_SCAN)
872c393a42Smrg	    printf ("done\n");
882c393a42Smrg
892c393a42Smrg	/*
902c393a42Smrg	 * Edit pattern with user-defined rules
912c393a42Smrg	 */
92ca08ab68Smrg	if (font && config && !FcConfigSubstitute (config, font, FcMatchScan))
932c393a42Smrg	{
942c393a42Smrg	    FcPatternDestroy (font);
952c393a42Smrg	    font = NULL;
962c393a42Smrg	    ret = FcFalse;
972c393a42Smrg	}
982c393a42Smrg
992c393a42Smrg	/*
1002c393a42Smrg	 * Add the font
1012c393a42Smrg	 */
102ca08ab68Smrg	if (font)
1032c393a42Smrg	{
1042c393a42Smrg	    if (FcDebug() & FC_DBG_SCANV)
1052c393a42Smrg	    {
1062c393a42Smrg		printf ("Final font pattern:\n");
1072c393a42Smrg		FcPatternPrint (font);
1082c393a42Smrg	    }
1092c393a42Smrg	    if (!FcFontSetAdd (set, font))
1102c393a42Smrg	    {
1112c393a42Smrg		FcPatternDestroy (font);
1122c393a42Smrg		font = NULL;
1132c393a42Smrg		ret = FcFalse;
1142c393a42Smrg	    }
1152c393a42Smrg	}
1162c393a42Smrg	else if (font)
1172c393a42Smrg	    FcPatternDestroy (font);
1182c393a42Smrg	id++;
1192c393a42Smrg    } while (font && ret && id < count);
1202c393a42Smrg    return ret;
1212c393a42Smrg}
1222c393a42Smrg
1232c393a42SmrgFcBool
1242c393a42SmrgFcFileScanConfig (FcFontSet	*set,
1252c393a42Smrg		  FcStrSet	*dirs,
1262c393a42Smrg		  FcBlanks	*blanks,
1272c393a42Smrg		  const FcChar8	*file,
1282c393a42Smrg		  FcConfig	*config)
1292c393a42Smrg{
1302c393a42Smrg    if (FcFileIsDir (file))
1312c393a42Smrg	return FcStrSetAdd (dirs, file);
1322c393a42Smrg    else
1332c393a42Smrg	return FcFileScanFontConfig (set, blanks, file, config);
1342c393a42Smrg}
1352c393a42Smrg
1362c393a42SmrgFcBool
1372c393a42SmrgFcFileScan (FcFontSet	    *set,
1382c393a42Smrg	    FcStrSet	    *dirs,
139c9710b42Smrg	    FcFileCache	    *cache FC_UNUSED,
1402c393a42Smrg	    FcBlanks	    *blanks,
1412c393a42Smrg	    const FcChar8   *file,
142c9710b42Smrg	    FcBool	    force FC_UNUSED)
1432c393a42Smrg{
144a6844aabSmrg    return FcFileScanConfig (set, dirs, blanks, file, FcConfigGetCurrent ());
1452c393a42Smrg}
1462c393a42Smrg
1472c393a42Smrg/*
1482c393a42Smrg * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage
1492c393a42Smrg */
1502c393a42Smrgstatic int
1512c393a42Smrgcmpstringp(const void *p1, const void *p2)
1522c393a42Smrg{
1532c393a42Smrg    return strcmp(* (char **) p1, * (char **) p2);
1542c393a42Smrg}
1552c393a42Smrg
156a6844aabSmrgFcBool
157a6844aabSmrgFcDirScanConfig (FcFontSet	*set,
158a6844aabSmrg		 FcStrSet	*dirs,
159a6844aabSmrg		 FcBlanks	*blanks,
160a6844aabSmrg		 const FcChar8	*dir,
161a6844aabSmrg		 FcBool		force, /* XXX unused */
162a6844aabSmrg		 FcConfig	*config)
1632c393a42Smrg{
1642c393a42Smrg    DIR			*d;
1652c393a42Smrg    struct dirent	*e;
1662c393a42Smrg    FcStrSet		*files;
1672c393a42Smrg    FcChar8		*file;
1682c393a42Smrg    FcChar8		*base;
1692c393a42Smrg    FcBool		ret = FcTrue;
1702c393a42Smrg    int			i;
1712c393a42Smrg
172a6844aabSmrg    if (!force)
173a6844aabSmrg	return FcFalse;
174a6844aabSmrg
175a6844aabSmrg    if (!set && !dirs)
176a6844aabSmrg	return FcTrue;
177a6844aabSmrg
178a6844aabSmrg    if (!blanks)
179a6844aabSmrg	blanks = FcConfigGetBlanks (config);
1802c393a42Smrg
1812c393a42Smrg    /* freed below */
1822c393a42Smrg    file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
1832c393a42Smrg    if (!file) {
1842c393a42Smrg	ret = FcFalse;
1852c393a42Smrg	goto bail;
1862c393a42Smrg    }
1872c393a42Smrg
1882c393a42Smrg    strcpy ((char *) file, (char *) dir);
1892c393a42Smrg    strcat ((char *) file, "/");
1902c393a42Smrg    base = file + strlen ((char *) file);
191ca08ab68Smrg
1922c393a42Smrg    if (FcDebug () & FC_DBG_SCAN)
1932c393a42Smrg	printf ("\tScanning dir %s\n", dir);
1942c393a42Smrg
1952c393a42Smrg    d = opendir ((char *) dir);
1962c393a42Smrg    if (!d)
1972c393a42Smrg    {
1982c393a42Smrg	/* Don't complain about missing directories */
199a6844aabSmrg	if (errno != ENOENT)
2002c393a42Smrg	    ret = FcFalse;
201a6844aabSmrg	goto bail;
2022c393a42Smrg    }
2032c393a42Smrg
2042c393a42Smrg    files = FcStrSetCreate ();
2052c393a42Smrg    if (!files)
2062c393a42Smrg    {
2072c393a42Smrg	ret = FcFalse;
2082c393a42Smrg	goto bail1;
2092c393a42Smrg    }
2102c393a42Smrg    while ((e = readdir (d)))
2112c393a42Smrg    {
2122c393a42Smrg	if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN)
2132c393a42Smrg	{
2142c393a42Smrg	    strcpy ((char *) base, (char *) e->d_name);
2152c393a42Smrg	    if (!FcStrSetAdd (files, file)) {
2162c393a42Smrg		ret = FcFalse;
2172c393a42Smrg		goto bail2;
2182c393a42Smrg	    }
2192c393a42Smrg	}
2202c393a42Smrg    }
2212c393a42Smrg
2222c393a42Smrg    /*
2232c393a42Smrg     * Sort files to make things prettier
2242c393a42Smrg     */
2252c393a42Smrg    qsort(files->strs, files->num, sizeof(FcChar8 *), cmpstringp);
226a6844aabSmrg
2272c393a42Smrg    /*
2282c393a42Smrg     * Scan file files to build font patterns
2292c393a42Smrg     */
2302c393a42Smrg    for (i = 0; i < files->num; i++)
2312c393a42Smrg	FcFileScanConfig (set, dirs, blanks, files->strs[i], config);
232ca08ab68Smrg
233a6844aabSmrgbail2:
234a6844aabSmrg    FcStrSetDestroy (files);
235a6844aabSmrgbail1:
236a6844aabSmrg    closedir (d);
237a6844aabSmrgbail:
238ca08ab68Smrg    if (file)
239ca08ab68Smrg	free (file);
240ca08ab68Smrg
241a6844aabSmrg    return ret;
242a6844aabSmrg}
243a6844aabSmrg
244a6844aabSmrgFcBool
245a6844aabSmrgFcDirScan (FcFontSet	    *set,
246a6844aabSmrg	   FcStrSet	    *dirs,
247a6844aabSmrg	   FcFileCache	    *cache, /* XXX unused */
248a6844aabSmrg	   FcBlanks	    *blanks,
249a6844aabSmrg	   const FcChar8    *dir,
250a6844aabSmrg	   FcBool	    force /* XXX unused */)
251a6844aabSmrg{
252a6844aabSmrg    if (cache || !force)
253a6844aabSmrg	return FcFalse;
254a6844aabSmrg
255a6844aabSmrg    return FcDirScanConfig (set, dirs, blanks, dir, force, FcConfigGetCurrent ());
256a6844aabSmrg}
257a6844aabSmrg
258a6844aabSmrg/*
259a6844aabSmrg * Scan the specified directory and construct a cache of its contents
260a6844aabSmrg */
261a6844aabSmrgFcCache *
262a6844aabSmrgFcDirCacheScan (const FcChar8 *dir, FcConfig *config)
263a6844aabSmrg{
264a6844aabSmrg    FcStrSet		*dirs;
265a6844aabSmrg    FcFontSet		*set;
266a6844aabSmrg    FcCache		*cache = NULL;
267a6844aabSmrg    struct stat		dir_stat;
268a6844aabSmrg
269a6844aabSmrg    if (FcDebug () & FC_DBG_FONTSET)
270a6844aabSmrg	printf ("cache scan dir %s\n", dir);
271a6844aabSmrg
272ca08ab68Smrg    if (FcStatChecksum (dir, &dir_stat) < 0)
273a6844aabSmrg	goto bail;
274a6844aabSmrg
275a6844aabSmrg    set = FcFontSetCreate();
276a6844aabSmrg    if (!set)
277a6844aabSmrg	goto bail;
278a6844aabSmrg
279a6844aabSmrg    dirs = FcStrSetCreate ();
280a6844aabSmrg    if (!dirs)
281a6844aabSmrg	goto bail1;
282a6844aabSmrg
283a6844aabSmrg    /*
284a6844aabSmrg     * Scan the dir
285a6844aabSmrg     */
286a6844aabSmrg    if (!FcDirScanConfig (set, dirs, NULL, dir, FcTrue, config))
287a6844aabSmrg	goto bail2;
288a6844aabSmrg
2892c393a42Smrg    /*
2902c393a42Smrg     * Build the cache object
2912c393a42Smrg     */
2922c393a42Smrg    cache = FcDirCacheBuild (set, dir, &dir_stat, dirs);
2932c393a42Smrg    if (!cache)
294a6844aabSmrg	goto bail2;
295ca08ab68Smrg
2962c393a42Smrg    /*
2972c393a42Smrg     * Write out the cache file, ignoring any troubles
2982c393a42Smrg     */
2992c393a42Smrg    FcDirCacheWrite (cache, config);
300ca08ab68Smrg
3012c393a42Smrg bail2:
302a6844aabSmrg    FcStrSetDestroy (dirs);
3032c393a42Smrg bail1:
3042c393a42Smrg    FcFontSetDestroy (set);
3052c393a42Smrg bail:
3062c393a42Smrg    return cache;
3072c393a42Smrg}
3082c393a42Smrg
3092c393a42Smrg/*
3102c393a42Smrg * Read (or construct) the cache for a directory
3112c393a42Smrg */
3122c393a42SmrgFcCache *
3132c393a42SmrgFcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config)
3142c393a42Smrg{
3152c393a42Smrg    FcCache		*cache = NULL;
3162c393a42Smrg
3172c393a42Smrg    /* Try to use existing cache file */
3182c393a42Smrg    if (!force)
3192c393a42Smrg	cache = FcDirCacheLoad (dir, config, NULL);
320ca08ab68Smrg
3212c393a42Smrg    /* Not using existing cache file, construct new cache */
3222c393a42Smrg    if (!cache)
3232c393a42Smrg	cache = FcDirCacheScan (dir, config);
324ca08ab68Smrg
3252c393a42Smrg    return cache;
3262c393a42Smrg}
3272c393a42Smrg
3282c393a42SmrgFcBool
329c9710b42SmrgFcDirSave (FcFontSet *set FC_UNUSED, FcStrSet * dirs FC_UNUSED, const FcChar8 *dir FC_UNUSED)
3302c393a42Smrg{
3312c393a42Smrg    return FcFalse; /* XXX deprecated */
3322c393a42Smrg}
3332c393a42Smrg#define __fcdir__
3342c393a42Smrg#include "fcaliastail.h"
3352c393a42Smrg#undef __fcdir__
336