Revive FcConfigScan() (bug #17121)
[platform/upstream/fontconfig.git] / src / fcdir.c
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  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL KEITH PACKARD 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
28 FcBool
29 FcFileIsDir (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
38 static FcBool
39 FcFileScanFontConfig (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
99 FcBool
100 FcFileScanConfig (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
112 FcBool
113 FcFileScan (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, NULL);
121 }
122
123 /*
124  * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage
125  */
126 static int
127 cmpstringp(const void *p1, const void *p2)
128 {
129     return strcmp(* (char **) p1, * (char **) p2);
130 }
131
132 FcBool
133 FcDirScanConfig (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     
209 bail2:
210     FcStrSetDestroy (files);
211 bail1:
212     closedir (d);
213 bail:
214     return ret;
215 }
216
217 FcBool
218 FcDirScan (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, NULL);
229 }
230
231 /*
232  * Scan the specified directory and construct a cache of its contents
233  */
234 FcCache *
235 FcDirCacheScan (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  */
302 FcCache *
303 FcDirCacheRead (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
321 FcBool
322 FcDirSave (FcFontSet *set, FcStrSet * dirs, const FcChar8 *dir)
323 {
324     return FcFalse; /* XXX deprecated */
325 }
326 #define __fcdir__
327 #include "fcaliastail.h"
328 #undef __fcdir__