ad64ca83c21b896d07bc538348c6ae03d93147d4
[platform/upstream/fontconfig.git] / src / fcdir.c
1 /*
2  * $RCSId: xc/lib/fontconfig/src/fcdir.c,v 1.9 2002/08/31 22:17:32 keithp Exp $
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 (stat ((const char *) file, &statb) != 0)
34         return FcFalse;
35     return S_ISDIR(statb.st_mode);
36 }
37
38 FcBool
39 FcFileScanConfig (FcFontSet     *set,
40                   FcStrSet      *dirs,
41                   FcGlobalCache *cache,
42                   FcBlanks      *blanks,
43                   const FcChar8 *file,
44                   FcBool        force,
45                   FcConfig      *config)
46 {
47     int                 id;
48     FcChar8             *name;
49     FcPattern           *font;
50     FcBool              ret = FcTrue;
51     FcBool              isDir;
52     int                 count = 0;
53     FcGlobalCacheFile   *cache_file;
54     FcGlobalCacheDir    *cache_dir;
55     FcBool              need_scan;
56     
57     if (config && !FcConfigAcceptFilename (config, file))
58         return FcTrue;
59
60     if (force)
61         cache = 0;
62     id = 0;
63     do
64     {
65         need_scan = FcTrue;
66         font = 0;
67         /*
68          * Check the cache
69          */
70         if (cache)
71         {
72             if ((cache_file = FcGlobalCacheFileGet (cache, file, id, &count)))
73             {
74                 /*
75                  * Found a cache entry for the file
76                  */
77                 if (FcGlobalCacheCheckTime (file, &cache_file->info))
78                 {
79                     name = cache_file->name;
80                     need_scan = FcFalse;
81                     FcGlobalCacheReferenced (cache, &cache_file->info);
82                     /* "." means the file doesn't contain a font */
83                     if (FcStrCmp (name, FC_FONT_FILE_INVALID) != 0)
84                     {
85                         font = FcNameParse (name);
86                         if (font)
87                             if (!FcPatternAddString (font, FC_FILE, file))
88                                 ret = FcFalse;
89                     }
90                 }
91             }
92             else if ((cache_dir = FcGlobalCacheDirGet (cache, file,
93                                                        strlen ((const char *) file),
94                                                        FcFalse)))
95             {
96                 if (FcGlobalCacheCheckTime (cache_dir->info.file, 
97                                             &cache_dir->info))
98                 {
99                     font = 0;
100                     need_scan = FcFalse;
101                     FcGlobalCacheReferenced (cache, &cache_dir->info);
102                     if (!FcStrSetAdd (dirs, file))
103                         ret = FcFalse;
104                 }
105             }
106         }
107         /*
108          * Nothing in the cache, scan the file
109          */
110         if (need_scan)
111         {
112             if (FcDebug () & FC_DBG_SCAN)
113             {
114                 printf ("\tScanning file %s...", file);
115                 fflush (stdout);
116             }
117             font = FcFreeTypeQuery (file, id, blanks, &count);
118             if (FcDebug () & FC_DBG_SCAN)
119                 printf ("done\n");
120             isDir = FcFalse;
121             if (!font && FcFileIsDir (file))
122             {
123                 isDir = FcTrue;
124                 ret = FcStrSetAdd (dirs, file);
125             }
126             /*
127              * Update the cache
128              */
129             if (cache && font)
130             {
131                 FcChar8 *unparse;
132
133                 unparse = FcNameUnparse (font);
134                 if (unparse)
135                 {
136                     (void) FcGlobalCacheUpdate (cache, file, id, unparse);
137                     FcStrFree (unparse);
138                 }
139             }
140         }
141         /*
142          * Add the font
143          */
144         if (font && (!config || FcConfigAcceptFont (config, font)))
145         {
146             if (!FcFontSetAdd (set, font))
147             {
148                 FcPatternDestroy (font);
149                 font = 0;
150                 ret = FcFalse;
151             }
152         }
153         else if (font)
154             FcPatternDestroy (font);
155         id++;
156     } while (font && ret && id < count);
157     return ret;
158 }
159
160 FcBool
161 FcFileScan (FcFontSet       *set,
162             FcStrSet        *dirs,
163             FcGlobalCache   *cache,
164             FcBlanks        *blanks,
165             const FcChar8   *file,
166             FcBool          force)
167 {
168     return FcFileScanConfig (set, dirs, cache, blanks, file, force, 0);
169 }
170
171 /*
172  * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage
173  */
174
175 static int
176 cmpstringp(const void *p1, const void *p2)
177 {
178     return strcmp(* (char **) p1, * (char **) p2);
179 }
180
181 /*
182  * Scan 'dir', adding font files to 'set' and
183  * subdirectories to 'dirs'
184  */
185
186 FcBool
187 FcDirScanConfig (FcFontSet      *set,
188                  FcStrSet       *dirs,
189                  FcGlobalCache  *cache,
190                  FcBlanks       *blanks,
191                  const FcChar8  *dir,
192                  FcBool         force,
193                  FcConfig       *config)
194 {
195     DIR                 *d;
196     struct dirent       *e;
197     FcChar8             **dirlist;
198     int                 dirlistlen, dirlistalloc;
199     FcChar8             *file;
200     FcChar8             *base;
201     FcBool              ret = FcTrue;
202     int                 i;
203
204     if (config && !FcConfigAcceptFilename (config, dir))
205         return FcTrue;
206
207     if (!force)
208     {
209         /*
210          * Check fonts.cache-<version> file
211          */
212         if (FcDirCacheReadDir (set, dirs, dir, config))
213         {
214             if (cache)
215                 FcGlobalCacheReferenceSubdir (cache, dir);
216             return FcTrue;
217         }
218     
219         /*
220          * Check ~/.fonts.cache-<version> file
221          */
222         if (cache && FcGlobalCacheScanDir (set, dirs, cache, dir, config))
223             return FcTrue;
224     }
225     
226     /* freed below */
227     file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
228     if (!file)
229         return FcFalse;
230
231     strcpy ((char *) file, (char *) dir);
232     strcat ((char *) file, "/");
233     base = file + strlen ((char *) file);
234     
235     if (FcDebug () & FC_DBG_SCAN)
236         printf ("\tScanning dir %s\n", dir);
237         
238     d = opendir ((char *) dir);
239     
240     if (!d)
241     {
242         free (file);
243         /* Don't complain about missing directories */
244         if (errno == ENOENT)
245             return FcTrue;
246         return FcFalse;
247     }
248     dirlistlen = 0;
249     dirlistalloc = 8;
250     dirlist = malloc(dirlistalloc * sizeof(FcChar8 *));
251     if (!dirlist)
252        return FcFalse;
253     while ((e = readdir (d)))
254     {
255         if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN)
256         {
257             if (dirlistlen == dirlistalloc)
258             {
259                 dirlistalloc *= 2;
260                 dirlist = realloc(dirlist, dirlistalloc * sizeof(FcChar8 *));
261                 if (!dirlist)
262                     return FcFalse;
263             }
264             dirlist[dirlistlen] = malloc(strlen (e->d_name) + 1);
265             if (!dirlist[dirlistlen])
266                 return FcFalse;
267             strcpy(dirlist[dirlistlen], e->d_name);
268             dirlistlen++;
269         }
270     }
271     qsort(dirlist, dirlistlen, sizeof(FcChar8 *), cmpstringp);
272     i = 0;
273     while (ret && i < dirlistlen)
274     {
275         strcpy ((char *) base, (char *) dirlist[i]);
276         ret = FcFileScanConfig (set, dirs, cache, blanks, file, force, config);
277         i++;
278     }
279     for (i = 0; i < dirlistlen; i++)
280         free(dirlist[i]);
281     free (dirlist);
282     free (file);
283     closedir (d);
284     /*
285      * Now that the directory has been scanned,
286      * add the cache entry 
287      */
288     if (ret && cache)
289         FcGlobalCacheUpdate (cache, dir, 0, 0);
290         
291     return ret;
292 }
293
294 FcBool
295 FcDirScan (FcFontSet        *set,
296            FcStrSet         *dirs,
297            FcGlobalCache    *cache,
298            FcBlanks         *blanks,
299            const FcChar8    *dir,
300            FcBool           force)
301 {
302     return FcDirScanConfig (set, dirs, cache, blanks, dir, force, 0);
303 }
304
305 FcBool
306 FcDirSave (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir)
307 {
308     return FcDirCacheWriteDir (set, dirs, dir);
309 }