f505bf533b3396641c25296589a6d2cb3de0b92d
[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     FcPattern           *font;
49     FcBool              ret = FcTrue;
50     int                 count = 0;
51     
52     if (config && !FcConfigAcceptFilename (config, file))
53         return FcTrue;
54
55     if (FcFileIsDir (file))
56         return FcStrSetAdd (dirs, file);
57
58     id = 0;
59     do
60     {
61         font = 0;
62         /*
63          * Nothing in the cache, scan the file
64          */
65         if (FcDebug () & FC_DBG_SCAN)
66         {
67             printf ("\tScanning file %s...", file);
68             fflush (stdout);
69         }
70         font = FcFreeTypeQuery (file, id, blanks, &count);
71         if (FcDebug () & FC_DBG_SCAN)
72             printf ("done\n");
73         /*
74          * Add the font
75          */
76         if (font && (!config || FcConfigAcceptFont (config, font)))
77         {
78             if (!FcFontSetAdd (set, font))
79             {
80                 FcPatternDestroy (font);
81                 font = 0;
82                 ret = FcFalse;
83             }
84         }
85         else if (font)
86             FcPatternDestroy (font);
87         id++;
88     } while (font && ret && id < count);
89     return ret;
90 }
91
92 FcBool
93 FcFileScan (FcFontSet       *set,
94             FcStrSet        *dirs,
95             FcGlobalCache   *cache,
96             FcBlanks        *blanks,
97             const FcChar8   *file,
98             FcBool          force)
99 {
100     return FcFileScanConfig (set, dirs, cache, blanks, file, force, 0);
101 }
102
103 /*
104  * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage
105  */
106
107 static int
108 cmpstringp(const void *p1, const void *p2)
109 {
110     return strcmp(* (char **) p1, * (char **) p2);
111 }
112
113 /*
114  * Scan 'dir', adding font files to 'set' and
115  * subdirectories to 'dirs'
116  */
117
118 FcBool
119 FcDirScanConfig (FcFontSet      *set,
120                  FcStrSet       *dirs,
121                  FcGlobalCache  *cache,
122                  FcBlanks       *blanks,
123                  const FcChar8  *dir,
124                  FcBool         force,
125                  FcConfig       *config)
126 {
127     DIR                 *d;
128     struct dirent       *e;
129     FcChar8             **dirlist;
130     int                 dirlistlen, dirlistalloc;
131     FcChar8             *file;
132     const FcChar8       *d_can = 0;
133     FcChar8             *base;
134     FcBool              ret = FcTrue;
135     FcFontSet           *tmpSet;
136     int                 i;
137
138     if (config && !FcConfigAcceptFilename (config, dir))
139         return FcTrue;
140
141     if (config)
142         d_can = FcConfigNormalizeFontDir (config, dir);
143     if (d_can)
144         dir = d_can;
145
146     if (!force)
147     {
148         /*
149          * Check ~/.fonts.cache-<version> file
150          */
151         if (cache && FcGlobalCacheReadDir (set, dirs, cache, (char *)dir, config))
152             return FcTrue;
153
154         if (FcDirCacheValid (dir) && 
155             FcDirCacheHasCurrentArch (dir) &&
156             FcDirCacheRead (set, dirs, dir, config))
157             return FcTrue;
158     }
159     
160     /* freed below */
161     file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
162     if (!file)
163         return FcFalse;
164
165     strcpy ((char *) file, (char *) dir);
166     strcat ((char *) file, "/");
167     base = file + strlen ((char *) file);
168     
169     if (FcDebug () & FC_DBG_SCAN)
170         printf ("\tScanning dir %s\n", dir);
171         
172     d = opendir ((char *) dir);
173     if (!d)
174     {
175         free (file);
176         /* Don't complain about missing directories */
177         if (errno == ENOENT)
178             return FcTrue;
179         return FcFalse;
180     }
181
182     tmpSet = FcFontSetCreate();
183     if (!tmpSet)
184     {   
185         free (file);
186         return FcFalse;
187     }
188
189     dirlistlen = 0;
190     dirlistalloc = 8;
191     dirlist = malloc(dirlistalloc * sizeof(FcChar8 *));
192     if (!dirlist)
193        return FcFalse;
194     while ((e = readdir (d)))
195     {
196         if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN)
197         {
198             if (dirlistlen == dirlistalloc)
199             {
200                 dirlistalloc *= 2;
201                 dirlist = realloc(dirlist, dirlistalloc * sizeof(FcChar8 *));
202                 if (!dirlist)
203                     return FcFalse;
204             }
205             dirlist[dirlistlen] = malloc(strlen (e->d_name) + 1);
206             if (!dirlist[dirlistlen])
207                 return FcFalse;
208             strcpy((char *)dirlist[dirlistlen], e->d_name);
209             dirlistlen++;
210         }
211     }
212     qsort(dirlist, dirlistlen, sizeof(FcChar8 *), cmpstringp);
213     i = 0;
214     while (ret && i < dirlistlen)
215     {
216         strcpy ((char *) base, (char *) dirlist[i]);
217         ret = FcFileScanConfig (tmpSet, dirs, cache, blanks, file, force, config);
218         i++;
219     }
220     for (i = 0; i < dirlistlen; i++)
221         free(dirlist[i]);
222     free (dirlist);
223     free (file);
224     closedir (d);
225     /*
226      * Now that the directory has been scanned,
227      * add the cache entry 
228      */
229     if (ret && cache)
230         FcGlobalCacheUpdate (cache, dirs, (char *)dir, tmpSet, config);
231
232     for (i = 0; i < tmpSet->nfont; i++)
233         FcFontSetAdd (set, tmpSet->fonts[i]);
234
235     if (tmpSet->fonts)
236     {
237         FcMemFree (FC_MEM_FONTPTR, tmpSet->sfont * sizeof (FcPattern *));
238         free (tmpSet->fonts);
239     }
240     FcMemFree (FC_MEM_FONTSET, sizeof (FcFontSet));
241     free (tmpSet);
242         
243     return ret;
244 }
245
246 FcBool
247 FcDirScan (FcFontSet        *set,
248            FcStrSet         *dirs,
249            FcGlobalCache    *cache,
250            FcBlanks         *blanks,
251            const FcChar8    *dir,
252            FcBool           force)
253 {
254     return FcDirScanConfig (set, dirs, cache, blanks, dir, force, 0);
255 }
256
257 FcBool
258 FcDirSave (FcFontSet *set, FcStrSet * dirs, const FcChar8 *dir)
259 {
260     return FcDirCacheWrite (set, dirs, dir);
261 }