86493b7274f9cd0db21ad1c037ea411d4a2838eb
[platform/upstream/fontconfig.git] / src / fcdir.c
1 /*
2  * $XFree86: xc/lib/fontconfig/src/fcdir.c,v 1.9 2002/08/31 22:17:32 keithp Exp $
3  *
4  * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
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 static 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 FcFileScan (FcFontSet       *set,
40             FcStrSet        *dirs,
41             FcGlobalCache   *cache,
42             FcBlanks        *blanks,
43             const FcChar8   *file,
44             FcBool          force)
45 {
46     int                 id;
47     FcChar8             *name;
48     FcPattern           *font;
49     FcBool              ret = FcTrue;
50     FcBool              isDir;
51     int                 count = 0;
52     FcGlobalCacheFile   *cache_file;
53     FcGlobalCacheDir    *cache_dir;
54     FcBool              need_scan;
55     
56     if (force)
57         cache = 0;
58     id = 0;
59     do
60     {
61         need_scan = FcTrue;
62         font = 0;
63         /*
64          * Check the cache
65          */
66         if (cache)
67         {
68             if ((cache_file = FcGlobalCacheFileGet (cache, file, id, &count)))
69             {
70                 /*
71                  * Found a cache entry for the file
72                  */
73                 if (FcGlobalCacheCheckTime (&cache_file->info))
74                 {
75                     name = cache_file->name;
76                     need_scan = FcFalse;
77                     FcGlobalCacheReferenced (cache, &cache_file->info);
78                     /* "." means the file doesn't contain a font */
79                     if (FcStrCmp (name, FC_FONT_FILE_INVALID) != 0)
80                     {
81                         font = FcNameParse (name);
82                         if (font)
83                             if (!FcPatternAddString (font, FC_FILE, file))
84                                 ret = FcFalse;
85                     }
86                 }
87             }
88             else if ((cache_dir = FcGlobalCacheDirGet (cache, file,
89                                                        strlen ((const char *) file),
90                                                        FcFalse)))
91             {
92                 if (FcGlobalCacheCheckTime (&cache_dir->info))
93                 {
94                     font = 0;
95                     need_scan = FcFalse;
96                     FcGlobalCacheReferenced (cache, &cache_dir->info);
97                     if (!FcStrSetAdd (dirs, file))
98                         ret = FcFalse;
99                 }
100             }
101         }
102         /*
103          * Nothing in the cache, scan the file
104          */
105         if (need_scan)
106         {
107             if (FcDebug () & FC_DBG_SCAN)
108             {
109                 printf ("\tScanning file %s...", file);
110                 fflush (stdout);
111             }
112             font = FcFreeTypeQuery (file, id, blanks, &count);
113             if (FcDebug () & FC_DBG_SCAN)
114                 printf ("done\n");
115             isDir = FcFalse;
116             if (!font && FcFileIsDir (file))
117             {
118                 isDir = FcTrue;
119                 ret = FcStrSetAdd (dirs, file);
120             }
121             /*
122              * Update the cache
123              */
124             if (cache && font)
125             {
126                 FcChar8 *unparse;
127
128                 unparse = FcNameUnparse (font);
129                 if (unparse)
130                 {
131                     (void) FcGlobalCacheUpdate (cache, file, id, unparse);
132                     FcStrFree (unparse);
133                 }
134             }
135         }
136         /*
137          * Add the font
138          */
139         if (font)
140         {
141             if (!FcFontSetAdd (set, font))
142             {
143                 FcPatternDestroy (font);
144                 font = 0;
145                 ret = FcFalse;
146             }
147         }
148         id++;
149     } while (font && ret && id < count);
150     return ret;
151 }
152
153 #define FC_MAX_FILE_LEN     4096
154
155 /*
156  * Scan 'dir', adding font files to 'set' and
157  * subdirectories to 'dirs'
158  */
159
160 FcBool
161 FcDirScan (FcFontSet        *set,
162            FcStrSet         *dirs,
163            FcGlobalCache    *cache,
164            FcBlanks         *blanks,
165            const FcChar8    *dir,
166            FcBool           force)
167 {
168     DIR                 *d;
169     struct dirent       *e;
170     FcChar8             *file;
171     FcChar8             *base;
172     FcBool              ret = FcTrue;
173
174     if (!force)
175     {
176         /*
177          * Check fonts.cache-<version> file
178          */
179         if (FcDirCacheReadDir (set, dirs, dir))
180         {
181             if (cache)
182                 FcGlobalCacheReferenceSubdir (cache, dir);
183             return FcTrue;
184         }
185     
186         /*
187          * Check ~/.fonts.cache-<version> file
188          */
189         if (cache && FcGlobalCacheScanDir (set, dirs, cache, dir))
190             return FcTrue;
191     }
192     
193     /* freed below */
194     file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
195     if (!file)
196         return FcFalse;
197
198     strcpy ((char *) file, (char *) dir);
199     strcat ((char *) file, "/");
200     base = file + strlen ((char *) file);
201     
202     d = opendir ((char *) dir);
203     
204     if (!d)
205     {
206         free (file);
207         /* Don't complain about missing directories */
208         if (errno == ENOENT)
209             return FcTrue;
210         return FcFalse;
211     }
212     while (ret && (e = readdir (d)))
213     {
214         if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN)
215         {
216             strcpy ((char *) base, (char *) e->d_name);
217             ret = FcFileScan (set, dirs, cache, blanks, file, force);
218         }
219     }
220     free (file);
221     closedir (d);
222     /*
223      * Now that the directory has been scanned,
224      * add the cache entry 
225      */
226     if (ret && cache)
227         FcGlobalCacheUpdate (cache, dir, 0, 0);
228         
229     return ret;
230 }
231
232 FcBool
233 FcDirSave (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir)
234 {
235     return FcDirCacheWriteDir (set, dirs, dir);
236 }