fcdir.c revision a6844aab
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
102c393a42Smrg * documentation, and that the name of Keith Packard not be used in
112c393a42Smrg * advertising or publicity pertaining to distribution of the software without
122c393a42Smrg * specific, written prior permission.  Keith Packard makes 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
33a6844aabSmrg    if (FcStat ((const char *) file, &statb) != 0)
342c393a42Smrg	return FcFalse;
352c393a42Smrg    return S_ISDIR(statb.st_mode);
362c393a42Smrg}
372c393a42Smrg
382c393a42Smrgstatic FcBool
392c393a42SmrgFcFileScanFontConfig (FcFontSet		*set,
402c393a42Smrg		      FcBlanks		*blanks,
412c393a42Smrg		      const FcChar8	*file,
422c393a42Smrg		      FcConfig		*config)
432c393a42Smrg{
442c393a42Smrg    FcPattern	*font;
452c393a42Smrg    FcBool	ret = FcTrue;
462c393a42Smrg    int		id;
472c393a42Smrg    int		count = 0;
482c393a42Smrg
492c393a42Smrg    id = 0;
502c393a42Smrg    do
512c393a42Smrg    {
522c393a42Smrg	font = 0;
532c393a42Smrg	/*
542c393a42Smrg	 * Nothing in the cache, scan the file
552c393a42Smrg	 */
562c393a42Smrg	if (FcDebug () & FC_DBG_SCAN)
572c393a42Smrg	{
582c393a42Smrg	    printf ("\tScanning file %s...", file);
592c393a42Smrg	    fflush (stdout);
602c393a42Smrg	}
612c393a42Smrg	font = FcFreeTypeQuery (file, id, blanks, &count);
622c393a42Smrg	if (FcDebug () & FC_DBG_SCAN)
632c393a42Smrg	    printf ("done\n");
642c393a42Smrg
652c393a42Smrg	/*
662c393a42Smrg	 * Edit pattern with user-defined rules
672c393a42Smrg	 */
682c393a42Smrg	if (font && config && !FcConfigSubstituteWithPat (config, font, NULL, FcMatchScan))
692c393a42Smrg	{
702c393a42Smrg	    FcPatternDestroy (font);
712c393a42Smrg	    font = NULL;
722c393a42Smrg	    ret = FcFalse;
732c393a42Smrg	}
742c393a42Smrg
752c393a42Smrg	/*
762c393a42Smrg	 * Add the font
772c393a42Smrg	 */
782c393a42Smrg	if (font && (!config || FcConfigAcceptFont (config, font)))
792c393a42Smrg	{
802c393a42Smrg	    if (FcDebug() & FC_DBG_SCANV)
812c393a42Smrg	    {
822c393a42Smrg		printf ("Final font pattern:\n");
832c393a42Smrg		FcPatternPrint (font);
842c393a42Smrg	    }
852c393a42Smrg	    if (!FcFontSetAdd (set, font))
862c393a42Smrg	    {
872c393a42Smrg		FcPatternDestroy (font);
882c393a42Smrg		font = NULL;
892c393a42Smrg		ret = FcFalse;
902c393a42Smrg	    }
912c393a42Smrg	}
922c393a42Smrg	else if (font)
932c393a42Smrg	    FcPatternDestroy (font);
942c393a42Smrg	id++;
952c393a42Smrg    } while (font && ret && id < count);
962c393a42Smrg    return ret;
972c393a42Smrg}
982c393a42Smrg
992c393a42SmrgFcBool
1002c393a42SmrgFcFileScanConfig (FcFontSet	*set,
1012c393a42Smrg		  FcStrSet	*dirs,
1022c393a42Smrg		  FcBlanks	*blanks,
1032c393a42Smrg		  const FcChar8	*file,
1042c393a42Smrg		  FcConfig	*config)
1052c393a42Smrg{
1062c393a42Smrg    if (FcFileIsDir (file))
1072c393a42Smrg	return FcStrSetAdd (dirs, file);
1082c393a42Smrg    else
1092c393a42Smrg	return FcFileScanFontConfig (set, blanks, file, config);
1102c393a42Smrg}
1112c393a42Smrg
1122c393a42SmrgFcBool
1132c393a42SmrgFcFileScan (FcFontSet	    *set,
1142c393a42Smrg	    FcStrSet	    *dirs,
1152c393a42Smrg	    FcFileCache	    *cache, /* XXX unused */
1162c393a42Smrg	    FcBlanks	    *blanks,
1172c393a42Smrg	    const FcChar8   *file,
1182c393a42Smrg	    FcBool	    force)
1192c393a42Smrg{
120a6844aabSmrg    return FcFileScanConfig (set, dirs, blanks, file, FcConfigGetCurrent ());
1212c393a42Smrg}
1222c393a42Smrg
1232c393a42Smrg/*
1242c393a42Smrg * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage
1252c393a42Smrg */
1262c393a42Smrgstatic int
1272c393a42Smrgcmpstringp(const void *p1, const void *p2)
1282c393a42Smrg{
1292c393a42Smrg    return strcmp(* (char **) p1, * (char **) p2);
1302c393a42Smrg}
1312c393a42Smrg
132a6844aabSmrgFcBool
133a6844aabSmrgFcDirScanConfig (FcFontSet	*set,
134a6844aabSmrg		 FcStrSet	*dirs,
135a6844aabSmrg		 FcBlanks	*blanks,
136a6844aabSmrg		 const FcChar8	*dir,
137a6844aabSmrg		 FcBool		force, /* XXX unused */
138a6844aabSmrg		 FcConfig	*config)
1392c393a42Smrg{
1402c393a42Smrg    DIR			*d;
1412c393a42Smrg    struct dirent	*e;
1422c393a42Smrg    FcStrSet		*files;
1432c393a42Smrg    FcChar8		*file;
1442c393a42Smrg    FcChar8		*base;
1452c393a42Smrg    FcBool		ret = FcTrue;
1462c393a42Smrg    int			i;
1472c393a42Smrg
148a6844aabSmrg    if (!force)
149a6844aabSmrg	return FcFalse;
150a6844aabSmrg
151a6844aabSmrg    if (!set && !dirs)
152a6844aabSmrg	return FcTrue;
153a6844aabSmrg
154a6844aabSmrg    if (!blanks)
155a6844aabSmrg	blanks = FcConfigGetBlanks (config);
1562c393a42Smrg
1572c393a42Smrg    /* freed below */
1582c393a42Smrg    file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
1592c393a42Smrg    if (!file) {
1602c393a42Smrg	ret = FcFalse;
1612c393a42Smrg	goto bail;
1622c393a42Smrg    }
1632c393a42Smrg
1642c393a42Smrg    strcpy ((char *) file, (char *) dir);
1652c393a42Smrg    strcat ((char *) file, "/");
1662c393a42Smrg    base = file + strlen ((char *) file);
1672c393a42Smrg
1682c393a42Smrg    if (FcDebug () & FC_DBG_SCAN)
1692c393a42Smrg	printf ("\tScanning dir %s\n", dir);
1702c393a42Smrg
1712c393a42Smrg    d = opendir ((char *) dir);
1722c393a42Smrg    if (!d)
1732c393a42Smrg    {
1742c393a42Smrg	/* Don't complain about missing directories */
175a6844aabSmrg	if (errno != ENOENT)
1762c393a42Smrg	    ret = FcFalse;
177a6844aabSmrg	goto bail;
1782c393a42Smrg    }
1792c393a42Smrg
1802c393a42Smrg    files = FcStrSetCreate ();
1812c393a42Smrg    if (!files)
1822c393a42Smrg    {
1832c393a42Smrg	ret = FcFalse;
1842c393a42Smrg	goto bail1;
1852c393a42Smrg    }
1862c393a42Smrg    while ((e = readdir (d)))
1872c393a42Smrg    {
1882c393a42Smrg	if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN)
1892c393a42Smrg	{
1902c393a42Smrg	    strcpy ((char *) base, (char *) e->d_name);
1912c393a42Smrg	    if (!FcStrSetAdd (files, file)) {
1922c393a42Smrg		ret = FcFalse;
1932c393a42Smrg		goto bail2;
1942c393a42Smrg	    }
1952c393a42Smrg	}
1962c393a42Smrg    }
1972c393a42Smrg
1982c393a42Smrg    /*
1992c393a42Smrg     * Sort files to make things prettier
2002c393a42Smrg     */
2012c393a42Smrg    qsort(files->strs, files->num, sizeof(FcChar8 *), cmpstringp);
202a6844aabSmrg
2032c393a42Smrg    /*
2042c393a42Smrg     * Scan file files to build font patterns
2052c393a42Smrg     */
2062c393a42Smrg    for (i = 0; i < files->num; i++)
2072c393a42Smrg	FcFileScanConfig (set, dirs, blanks, files->strs[i], config);
2082c393a42Smrg
209a6844aabSmrgbail2:
210a6844aabSmrg    FcStrSetDestroy (files);
211a6844aabSmrgbail1:
212a6844aabSmrg    closedir (d);
213a6844aabSmrgbail:
214a6844aabSmrg    return ret;
215a6844aabSmrg}
216a6844aabSmrg
217a6844aabSmrgFcBool
218a6844aabSmrgFcDirScan (FcFontSet	    *set,
219a6844aabSmrg	   FcStrSet	    *dirs,
220a6844aabSmrg	   FcFileCache	    *cache, /* XXX unused */
221a6844aabSmrg	   FcBlanks	    *blanks,
222a6844aabSmrg	   const FcChar8    *dir,
223a6844aabSmrg	   FcBool	    force /* XXX unused */)
224a6844aabSmrg{
225a6844aabSmrg    if (cache || !force)
226a6844aabSmrg	return FcFalse;
227a6844aabSmrg
228a6844aabSmrg    return FcDirScanConfig (set, dirs, blanks, dir, force, FcConfigGetCurrent ());
229a6844aabSmrg}
230a6844aabSmrg
231a6844aabSmrg/*
232a6844aabSmrg * Scan the specified directory and construct a cache of its contents
233a6844aabSmrg */
234a6844aabSmrgFcCache *
235a6844aabSmrgFcDirCacheScan (const FcChar8 *dir, FcConfig *config)
236a6844aabSmrg{
237a6844aabSmrg    FcStrSet		*dirs;
238a6844aabSmrg    FcBool		ret = FcTrue;
239a6844aabSmrg    FcFontSet		*set;
240a6844aabSmrg    FcCache		*cache = NULL;
241a6844aabSmrg    struct stat		dir_stat;
242a6844aabSmrg
243a6844aabSmrg    if (FcDebug () & FC_DBG_FONTSET)
244a6844aabSmrg	printf ("cache scan dir %s\n", dir);
245a6844aabSmrg
246a6844aabSmrg    if (FcStat ((char *) dir, &dir_stat) < 0)
247a6844aabSmrg    {
248a6844aabSmrg	if (errno != ENOENT)
249a6844aabSmrg	    ret = FcFalse;
250a6844aabSmrg	goto bail;
251a6844aabSmrg    }
252a6844aabSmrg
253a6844aabSmrg    set = FcFontSetCreate();
254a6844aabSmrg    if (!set)
255a6844aabSmrg    {
256a6844aabSmrg	ret = FcFalse;
257a6844aabSmrg	goto bail;
258a6844aabSmrg    }
259a6844aabSmrg
260a6844aabSmrg    dirs = FcStrSetCreate ();
261a6844aabSmrg    if (!dirs)
262a6844aabSmrg    {
263a6844aabSmrg	ret = FcFalse;
264a6844aabSmrg	goto bail1;
265a6844aabSmrg    }
266a6844aabSmrg
267a6844aabSmrg    /*
268a6844aabSmrg     * Scan the dir
269a6844aabSmrg     */
270a6844aabSmrg    if (!FcDirScanConfig (set, dirs, NULL, dir, FcTrue, config))
271a6844aabSmrg    {
272a6844aabSmrg	ret = FcFalse;
273a6844aabSmrg	goto bail2;
274a6844aabSmrg    }
275a6844aabSmrg
2762c393a42Smrg    /*
2772c393a42Smrg     * Build the cache object
2782c393a42Smrg     */
2792c393a42Smrg    cache = FcDirCacheBuild (set, dir, &dir_stat, dirs);
2802c393a42Smrg    if (!cache)
281a6844aabSmrg    {
282a6844aabSmrg	ret = FcFalse;
283a6844aabSmrg	goto bail2;
284a6844aabSmrg    }
2852c393a42Smrg
2862c393a42Smrg    /*
2872c393a42Smrg     * Write out the cache file, ignoring any troubles
2882c393a42Smrg     */
2892c393a42Smrg    FcDirCacheWrite (cache, config);
2902c393a42Smrg
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    if (config && !FcConfigAcceptFilename (config, dir))
3082c393a42Smrg	return NULL;
3092c393a42Smrg
3102c393a42Smrg    /* Try to use existing cache file */
3112c393a42Smrg    if (!force)
3122c393a42Smrg	cache = FcDirCacheLoad (dir, config, NULL);
3132c393a42Smrg
3142c393a42Smrg    /* Not using existing cache file, construct new cache */
3152c393a42Smrg    if (!cache)
3162c393a42Smrg	cache = FcDirCacheScan (dir, config);
3172c393a42Smrg
3182c393a42Smrg    return cache;
3192c393a42Smrg}
3202c393a42Smrg
3212c393a42SmrgFcBool
3222c393a42SmrgFcDirSave (FcFontSet *set, FcStrSet * dirs, const FcChar8 *dir)
3232c393a42Smrg{
3242c393a42Smrg    return FcFalse; /* XXX deprecated */
3252c393a42Smrg}
3262c393a42Smrg#define __fcdir__
3272c393a42Smrg#include "fcaliastail.h"
3282c393a42Smrg#undef __fcdir__
329