]>
Commit | Line | Data |
---|---|---|
24330d27 | 1 | /* |
4bd4418a | 2 | * $RCSId: xc/lib/fontconfig/src/fccache.c,v 1.12 2002/08/22 07:36:44 keithp Exp $ |
24330d27 | 3 | * |
46b51147 | 4 | * Copyright © 2000 Keith Packard |
24330d27 KP |
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 | ||
fa244f3d KP |
27 | /* |
28 | * POSIX has broken stdio so that getc must do thread-safe locking, | |
29 | * this is a serious performance problem for applications doing large | |
30 | * amounts of IO with getc (as is done here). If available, use | |
31 | * the getc_unlocked varient instead. | |
32 | */ | |
33 | ||
34 | #if defined(getc_unlocked) || defined(_IO_getc_unlocked) | |
35 | #define GETC(f) getc_unlocked(f) | |
36 | #define PUTC(c,f) putc_unlocked(c,f) | |
37 | #else | |
38 | #define GETC(f) getc(f) | |
39 | #define PUTC(c,f) putc(c,f) | |
40 | #endif | |
41 | ||
327a7fd4 | 42 | #define FC_DBG_CACHE_REF 1024 |
24330d27 | 43 | |
ccb3e93b | 44 | static FcChar8 * |
327a7fd4 | 45 | FcCacheReadString (FILE *f, FcChar8 *dest, int len) |
24330d27 | 46 | { |
ccb3e93b KP |
47 | int c; |
48 | FcBool escape; | |
49 | FcChar8 *d; | |
50 | int size; | |
51 | int i; | |
24330d27 | 52 | |
fa244f3d | 53 | while ((c = GETC (f)) != EOF) |
24330d27 KP |
54 | if (c == '"') |
55 | break; | |
56 | if (c == EOF) | |
57 | return FcFalse; | |
58 | if (len == 0) | |
59 | return FcFalse; | |
60 | ||
ccb3e93b KP |
61 | size = len; |
62 | i = 0; | |
63 | d = dest; | |
24330d27 | 64 | escape = FcFalse; |
fa244f3d | 65 | while ((c = GETC (f)) != EOF) |
24330d27 KP |
66 | { |
67 | if (!escape) | |
68 | { | |
69 | switch (c) { | |
70 | case '"': | |
ccb3e93b KP |
71 | c = '\0'; |
72 | break; | |
24330d27 KP |
73 | case '\\': |
74 | escape = FcTrue; | |
75 | continue; | |
76 | } | |
77 | } | |
ccb3e93b KP |
78 | if (i == size) |
79 | { | |
9dac3c59 | 80 | FcChar8 *new = malloc (size * 2); /* freed in caller */ |
ccb3e93b KP |
81 | if (!new) |
82 | break; | |
83 | memcpy (new, d, size); | |
84 | size *= 2; | |
85 | if (d != dest) | |
86 | free (d); | |
87 | d = new; | |
88 | } | |
89 | d[i++] = c; | |
90 | if (c == '\0') | |
91 | return d; | |
24330d27 KP |
92 | escape = FcFalse; |
93 | } | |
ccb3e93b KP |
94 | if (d != dest) |
95 | free (d); | |
96 | return 0; | |
24330d27 KP |
97 | } |
98 | ||
99 | static FcBool | |
327a7fd4 | 100 | FcCacheReadUlong (FILE *f, unsigned long *dest) |
24330d27 KP |
101 | { |
102 | unsigned long t; | |
103 | int c; | |
104 | ||
fa244f3d | 105 | while ((c = GETC (f)) != EOF) |
24330d27 KP |
106 | { |
107 | if (!isspace (c)) | |
108 | break; | |
109 | } | |
110 | if (c == EOF) | |
111 | return FcFalse; | |
112 | t = 0; | |
113 | for (;;) | |
114 | { | |
115 | if (c == EOF || isspace (c)) | |
116 | break; | |
117 | if (!isdigit (c)) | |
118 | return FcFalse; | |
119 | t = t * 10 + (c - '0'); | |
fa244f3d | 120 | c = GETC (f); |
24330d27 KP |
121 | } |
122 | *dest = t; | |
123 | return FcTrue; | |
124 | } | |
125 | ||
126 | static FcBool | |
327a7fd4 | 127 | FcCacheReadInt (FILE *f, int *dest) |
24330d27 KP |
128 | { |
129 | unsigned long t; | |
130 | FcBool ret; | |
131 | ||
327a7fd4 | 132 | ret = FcCacheReadUlong (f, &t); |
24330d27 KP |
133 | if (ret) |
134 | *dest = (int) t; | |
135 | return ret; | |
136 | } | |
137 | ||
138 | static FcBool | |
327a7fd4 | 139 | FcCacheReadTime (FILE *f, time_t *dest) |
24330d27 KP |
140 | { |
141 | unsigned long t; | |
142 | FcBool ret; | |
143 | ||
327a7fd4 | 144 | ret = FcCacheReadUlong (f, &t); |
24330d27 KP |
145 | if (ret) |
146 | *dest = (time_t) t; | |
147 | return ret; | |
148 | } | |
149 | ||
150 | static FcBool | |
327a7fd4 | 151 | FcCacheWriteChars (FILE *f, const FcChar8 *chars) |
24330d27 | 152 | { |
327a7fd4 KP |
153 | FcChar8 c; |
154 | while ((c = *chars++)) | |
155 | { | |
156 | switch (c) { | |
157 | case '"': | |
158 | case '\\': | |
fa244f3d | 159 | if (PUTC ('\\', f) == EOF) |
327a7fd4 KP |
160 | return FcFalse; |
161 | /* fall through */ | |
162 | default: | |
fa244f3d | 163 | if (PUTC (c, f) == EOF) |
327a7fd4 KP |
164 | return FcFalse; |
165 | } | |
166 | } | |
167 | return FcTrue; | |
168 | } | |
24330d27 | 169 | |
327a7fd4 KP |
170 | static FcBool |
171 | FcCacheWriteString (FILE *f, const FcChar8 *string) | |
172 | { | |
173 | ||
fa244f3d | 174 | if (PUTC ('"', f) == EOF) |
327a7fd4 KP |
175 | return FcFalse; |
176 | if (!FcCacheWriteChars (f, string)) | |
177 | return FcFalse; | |
fa244f3d | 178 | if (PUTC ('"', f) == EOF) |
327a7fd4 KP |
179 | return FcFalse; |
180 | return FcTrue; | |
181 | } | |
182 | ||
183 | static FcBool | |
184 | FcCacheWritePath (FILE *f, const FcChar8 *dir, const FcChar8 *file) | |
185 | { | |
fa244f3d | 186 | if (PUTC ('"', f) == EOF) |
327a7fd4 KP |
187 | return FcFalse; |
188 | if (dir) | |
189 | if (!FcCacheWriteChars (f, dir)) | |
190 | return FcFalse; | |
daeed6e0 TL |
191 | #ifdef _WIN32 |
192 | if (dir && | |
193 | dir[strlen((const char *) dir) - 1] != '/' && | |
194 | dir[strlen((const char *) dir) - 1] != '\\') | |
195 | { | |
196 | if (!FcCacheWriteChars (f, "\\")) | |
197 | return FcFalse; | |
198 | } | |
199 | #else | |
327a7fd4 | 200 | if (dir && dir[strlen((const char *) dir) - 1] != '/') |
fa244f3d | 201 | if (PUTC ('/', f) == EOF) |
327a7fd4 | 202 | return FcFalse; |
daeed6e0 | 203 | #endif |
327a7fd4 KP |
204 | if (!FcCacheWriteChars (f, file)) |
205 | return FcFalse; | |
fa244f3d | 206 | if (PUTC ('"', f) == EOF) |
327a7fd4 KP |
207 | return FcFalse; |
208 | return FcTrue; | |
209 | } | |
210 | ||
211 | static FcBool | |
212 | FcCacheWriteUlong (FILE *f, unsigned long t) | |
213 | { | |
214 | int pow; | |
215 | unsigned long temp, digit; | |
216 | ||
217 | temp = t; | |
218 | pow = 1; | |
219 | while (temp >= 10) | |
24330d27 | 220 | { |
327a7fd4 KP |
221 | temp /= 10; |
222 | pow *= 10; | |
24330d27 | 223 | } |
327a7fd4 KP |
224 | temp = t; |
225 | while (pow) | |
226 | { | |
227 | digit = temp / pow; | |
fa244f3d | 228 | if (PUTC ((char) digit + '0', f) == EOF) |
327a7fd4 KP |
229 | return FcFalse; |
230 | temp = temp - pow * digit; | |
231 | pow = pow / 10; | |
232 | } | |
233 | return FcTrue; | |
234 | } | |
235 | ||
236 | static FcBool | |
237 | FcCacheWriteInt (FILE *f, int i) | |
238 | { | |
239 | return FcCacheWriteUlong (f, (unsigned long) i); | |
240 | } | |
241 | ||
242 | static FcBool | |
243 | FcCacheWriteTime (FILE *f, time_t t) | |
244 | { | |
245 | return FcCacheWriteUlong (f, (unsigned long) t); | |
246 | } | |
247 | ||
248 | static FcBool | |
249 | FcCacheFontSetAdd (FcFontSet *set, | |
250 | FcStrSet *dirs, | |
251 | const FcChar8 *dir, | |
252 | int dir_len, | |
253 | const FcChar8 *file, | |
d47c9d6e KP |
254 | const FcChar8 *name, |
255 | FcConfig *config) | |
327a7fd4 KP |
256 | { |
257 | FcChar8 path_buf[8192], *path; | |
258 | int len; | |
259 | FcBool ret = FcFalse; | |
260 | FcPattern *font; | |
d8d73958 | 261 | FcPattern *frozen; |
327a7fd4 KP |
262 | |
263 | path = path_buf; | |
264 | len = (dir_len + 1 + strlen ((const char *) file) + 1); | |
265 | if (len > sizeof (path_buf)) | |
266 | { | |
9dac3c59 | 267 | path = malloc (len); /* freed down below */ |
327a7fd4 KP |
268 | if (!path) |
269 | return FcFalse; | |
270 | } | |
271 | strncpy ((char *) path, (const char *) dir, dir_len); | |
daeed6e0 TL |
272 | #ifdef _WIN32 |
273 | if (dir[dir_len - 1] != '/' && dir[dir_len - 1] != '\\' ) | |
274 | path[dir_len++] = '\\'; | |
275 | #else | |
327a7fd4 KP |
276 | if (dir[dir_len - 1] != '/') |
277 | path[dir_len++] = '/'; | |
daeed6e0 | 278 | #endif |
327a7fd4 | 279 | strcpy ((char *) path + dir_len, (const char *) file); |
d47c9d6e KP |
280 | if (config && !FcConfigAcceptFilename (config, path)) |
281 | ret = FcTrue; | |
282 | else if (!FcStrCmp (name, FC_FONT_FILE_DIR)) | |
327a7fd4 KP |
283 | { |
284 | if (FcDebug () & FC_DBG_CACHEV) | |
285 | printf (" dir cache dir \"%s\"\n", path); | |
286 | ret = FcStrSetAdd (dirs, path); | |
287 | } | |
288 | else if (!FcStrCmp (name, FC_FONT_FILE_INVALID)) | |
289 | { | |
290 | ret = FcTrue; | |
291 | } | |
292 | else | |
293 | { | |
294 | font = FcNameParse (name); | |
295 | if (font) | |
296 | { | |
fce87a18 KP |
297 | FcChar8 *family; |
298 | ||
327a7fd4 KP |
299 | if (FcDebug () & FC_DBG_CACHEV) |
300 | printf (" dir cache file \"%s\"\n", file); | |
d8d73958 | 301 | ret = FcPatternAddString (font, FC_FILE, path); |
fce87a18 KP |
302 | /* |
303 | * Make sure the pattern has the file name as well as | |
304 | * already containing at least one family name. | |
305 | */ | |
306 | if (ret && | |
307 | FcPatternGetString (font, FC_FAMILY, 0, &family) == FcResultMatch && | |
308 | (!config || FcConfigAcceptFont (config, font))) | |
d8d73958 KP |
309 | { |
310 | frozen = FcPatternFreeze (font); | |
311 | ret = (frozen != 0); | |
312 | if (ret) | |
313 | ret = FcFontSetAdd (set, frozen); | |
314 | } | |
315 | FcPatternDestroy (font); | |
327a7fd4 KP |
316 | } |
317 | } | |
318 | if (path != path_buf) free (path); | |
319 | return ret; | |
320 | ||
321 | } | |
322 | ||
323 | static unsigned int | |
c8d5753c | 324 | FcCacheHash (const FcChar8 *string, int len) |
327a7fd4 KP |
325 | { |
326 | unsigned int h = 0; | |
327 | FcChar8 c; | |
328 | ||
c8d5753c | 329 | while (len-- && (c = *string++)) |
327a7fd4 | 330 | h = (h << 1) ^ c; |
c8d5753c | 331 | return h; |
327a7fd4 KP |
332 | } |
333 | ||
334 | /* | |
335 | * Verify the saved timestamp for a file | |
336 | */ | |
337 | FcBool | |
a8386abc | 338 | FcGlobalCacheCheckTime (const FcChar8 *file, FcGlobalCacheInfo *info) |
327a7fd4 KP |
339 | { |
340 | struct stat statb; | |
341 | ||
a8386abc | 342 | if (stat ((char *) file, &statb) < 0) |
327a7fd4 KP |
343 | { |
344 | if (FcDebug () & FC_DBG_CACHE) | |
a8386abc | 345 | printf (" file %s missing\n", file); |
327a7fd4 KP |
346 | return FcFalse; |
347 | } | |
348 | if (statb.st_mtime != info->time) | |
349 | { | |
350 | if (FcDebug () & FC_DBG_CACHE) | |
351 | printf (" timestamp mismatch (was %d is %d)\n", | |
352 | (int) info->time, (int) statb.st_mtime); | |
353 | return FcFalse; | |
354 | } | |
355 | return FcTrue; | |
356 | } | |
357 | ||
358 | void | |
359 | FcGlobalCacheReferenced (FcGlobalCache *cache, | |
360 | FcGlobalCacheInfo *info) | |
361 | { | |
362 | if (!info->referenced) | |
363 | { | |
364 | info->referenced = FcTrue; | |
365 | cache->referenced++; | |
366 | if (FcDebug () & FC_DBG_CACHE_REF) | |
367 | printf ("Reference %d %s\n", cache->referenced, info->file); | |
368 | } | |
369 | } | |
370 | ||
371 | /* | |
372 | * Break a path into dir/base elements and compute the base hash | |
373 | * and the dir length. This is shared between the functions | |
374 | * which walk the file caches | |
375 | */ | |
376 | ||
377 | typedef struct _FcFilePathInfo { | |
378 | const FcChar8 *dir; | |
379 | int dir_len; | |
380 | const FcChar8 *base; | |
381 | unsigned int base_hash; | |
382 | } FcFilePathInfo; | |
383 | ||
384 | static FcFilePathInfo | |
385 | FcFilePathInfoGet (const FcChar8 *path) | |
386 | { | |
387 | FcFilePathInfo i; | |
388 | FcChar8 *slash; | |
389 | ||
daeed6e0 | 390 | slash = FcStrLastSlash (path); |
327a7fd4 KP |
391 | if (slash) |
392 | { | |
393 | i.dir = path; | |
394 | i.dir_len = slash - path; | |
395 | if (!i.dir_len) | |
396 | i.dir_len = 1; | |
397 | i.base = slash + 1; | |
398 | } | |
399 | else | |
400 | { | |
401 | i.dir = (const FcChar8 *) "."; | |
402 | i.dir_len = 1; | |
403 | i.base = path; | |
404 | } | |
c8d5753c | 405 | i.base_hash = FcCacheHash (i.base, -1); |
327a7fd4 KP |
406 | return i; |
407 | } | |
408 | ||
409 | FcGlobalCacheDir * | |
410 | FcGlobalCacheDirGet (FcGlobalCache *cache, | |
411 | const FcChar8 *dir, | |
412 | int len, | |
413 | FcBool create_missing) | |
414 | { | |
c8d5753c | 415 | unsigned int hash = FcCacheHash (dir, len); |
327a7fd4 KP |
416 | FcGlobalCacheDir *d, **prev; |
417 | ||
418 | for (prev = &cache->ents[hash % FC_GLOBAL_CACHE_DIR_HASH_SIZE]; | |
419 | (d = *prev); | |
24330d27 KP |
420 | prev = &(*prev)->next) |
421 | { | |
327a7fd4 KP |
422 | if (d->info.hash == hash && d->len == len && |
423 | !strncmp ((const char *) d->info.file, | |
424 | (const char *) dir, len)) | |
24330d27 KP |
425 | break; |
426 | } | |
327a7fd4 KP |
427 | if (!(d = *prev)) |
428 | { | |
429 | int i; | |
430 | if (!create_missing) | |
431 | return 0; | |
432 | d = malloc (sizeof (FcGlobalCacheDir) + len + 1); | |
433 | if (!d) | |
434 | return 0; | |
9dac3c59 | 435 | FcMemAlloc (FC_MEM_CACHE, sizeof (FcGlobalCacheDir) + len + 1); |
327a7fd4 KP |
436 | d->next = *prev; |
437 | *prev = d; | |
438 | d->info.hash = hash; | |
439 | d->info.file = (FcChar8 *) (d + 1); | |
440 | strncpy ((char *) d->info.file, (const char *) dir, len); | |
441 | d->info.file[len] = '\0'; | |
442 | d->info.time = 0; | |
443 | d->info.referenced = FcFalse; | |
444 | d->len = len; | |
445 | for (i = 0; i < FC_GLOBAL_CACHE_FILE_HASH_SIZE; i++) | |
446 | d->ents[i] = 0; | |
447 | d->subdirs = 0; | |
448 | } | |
449 | return d; | |
450 | } | |
451 | ||
452 | static FcGlobalCacheInfo * | |
453 | FcGlobalCacheDirAdd (FcGlobalCache *cache, | |
454 | const FcChar8 *dir, | |
455 | time_t time, | |
c4ab52dc KP |
456 | FcBool replace, |
457 | FcBool create_missing) | |
327a7fd4 KP |
458 | { |
459 | FcGlobalCacheDir *d; | |
460 | FcFilePathInfo i; | |
461 | FcGlobalCacheSubdir *subdir; | |
462 | FcGlobalCacheDir *parent; | |
463 | ||
c4ab52dc KP |
464 | i = FcFilePathInfoGet (dir); |
465 | parent = FcGlobalCacheDirGet (cache, i.dir, i.dir_len, create_missing); | |
466 | /* | |
467 | * Tricky here -- directories containing fonts.cache-1 files | |
468 | * need entries only when the parent doesn't have a cache file. | |
469 | * That is, when the parent already exists in the cache, is | |
470 | * referenced and has a "real" timestamp. The time of 0 is | |
471 | * special and marks directories which got stuck in the | |
472 | * global cache for this very reason. Yes, it could | |
473 | * use a separate boolean field, and probably should. | |
474 | */ | |
475 | if (!parent || (!create_missing && | |
476 | (!parent->info.referenced || | |
477 | (parent->info.time == 0)))) | |
478 | return 0; | |
327a7fd4 KP |
479 | /* |
480 | * Add this directory to the cache | |
481 | */ | |
482 | d = FcGlobalCacheDirGet (cache, dir, strlen ((const char *) dir), FcTrue); | |
483 | if (!d) | |
484 | return 0; | |
485 | d->info.time = time; | |
327a7fd4 KP |
486 | /* |
487 | * Add this directory to the subdirectory list of the parent | |
488 | */ | |
e712133c | 489 | subdir = malloc (sizeof (FcGlobalCacheSubdir)); |
327a7fd4 KP |
490 | if (!subdir) |
491 | return 0; | |
e712133c KP |
492 | FcMemAlloc (FC_MEM_CACHE, sizeof (FcGlobalCacheSubdir)); |
493 | subdir->ent = d; | |
327a7fd4 KP |
494 | subdir->next = parent->subdirs; |
495 | parent->subdirs = subdir; | |
496 | return &d->info; | |
497 | } | |
498 | ||
499 | static void | |
500 | FcGlobalCacheDirDestroy (FcGlobalCacheDir *d) | |
501 | { | |
502 | FcGlobalCacheFile *f, *next; | |
503 | int h; | |
504 | FcGlobalCacheSubdir *s, *nexts; | |
505 | ||
506 | for (h = 0; h < FC_GLOBAL_CACHE_FILE_HASH_SIZE; h++) | |
507 | for (f = d->ents[h]; f; f = next) | |
508 | { | |
509 | next = f->next; | |
9dac3c59 KP |
510 | FcMemFree (FC_MEM_CACHE, sizeof (FcGlobalCacheFile) + |
511 | strlen ((char *) f->info.file) + 1 + | |
512 | strlen ((char *) f->name) + 1); | |
327a7fd4 KP |
513 | free (f); |
514 | } | |
515 | for (s = d->subdirs; s; s = nexts) | |
516 | { | |
517 | nexts = s->next; | |
e712133c | 518 | FcMemFree (FC_MEM_CACHE, sizeof (FcGlobalCacheSubdir)); |
327a7fd4 KP |
519 | free (s); |
520 | } | |
9dac3c59 | 521 | FcMemFree (FC_MEM_CACHE, sizeof (FcGlobalCacheDir) + d->len + 1); |
327a7fd4 KP |
522 | free (d); |
523 | } | |
524 | ||
c4ab52dc KP |
525 | /* |
526 | * If the parent is in the global cache and referenced, add | |
527 | * an entry for 'dir' to the global cache. This is used | |
528 | * for directories with fonts.cache files | |
529 | */ | |
530 | ||
531 | void | |
532 | FcGlobalCacheReferenceSubdir (FcGlobalCache *cache, | |
533 | const FcChar8 *dir) | |
534 | { | |
535 | FcGlobalCacheInfo *info; | |
536 | info = FcGlobalCacheDirAdd (cache, dir, 0, FcFalse, FcFalse); | |
537 | if (info && !info->referenced) | |
538 | { | |
539 | info->referenced = FcTrue; | |
540 | cache->referenced++; | |
541 | } | |
542 | } | |
543 | ||
c8d5753c KP |
544 | /* |
545 | * Check to see if the global cache contains valid data for 'dir'. | |
546 | * If so, scan the global cache for files and directories in 'dir'. | |
547 | * else, return False. | |
548 | */ | |
327a7fd4 KP |
549 | FcBool |
550 | FcGlobalCacheScanDir (FcFontSet *set, | |
551 | FcStrSet *dirs, | |
552 | FcGlobalCache *cache, | |
d47c9d6e KP |
553 | const FcChar8 *dir, |
554 | FcConfig *config) | |
327a7fd4 KP |
555 | { |
556 | FcGlobalCacheDir *d = FcGlobalCacheDirGet (cache, dir, | |
557 | strlen ((const char *) dir), | |
558 | FcFalse); | |
559 | FcGlobalCacheFile *f; | |
560 | int h; | |
561 | int dir_len; | |
562 | FcGlobalCacheSubdir *subdir; | |
c8d5753c | 563 | FcBool any_in_cache = FcFalse; |
327a7fd4 KP |
564 | |
565 | if (FcDebug() & FC_DBG_CACHE) | |
566 | printf ("FcGlobalCacheScanDir %s\n", dir); | |
567 | ||
568 | if (!d) | |
569 | { | |
570 | if (FcDebug () & FC_DBG_CACHE) | |
571 | printf ("\tNo dir cache entry\n"); | |
572 | return FcFalse; | |
573 | } | |
574 | ||
c8d5753c KP |
575 | /* |
576 | * See if the timestamp recorded in the global cache | |
577 | * matches the directory time, if not, return False | |
578 | */ | |
a8386abc | 579 | if (!FcGlobalCacheCheckTime (d->info.file, &d->info)) |
327a7fd4 KP |
580 | { |
581 | if (FcDebug () & FC_DBG_CACHE) | |
582 | printf ("\tdir cache entry time mismatch\n"); | |
583 | return FcFalse; | |
584 | } | |
585 | ||
c8d5753c KP |
586 | /* |
587 | * Add files from 'dir' to the fontset | |
588 | */ | |
327a7fd4 KP |
589 | dir_len = strlen ((const char *) dir); |
590 | for (h = 0; h < FC_GLOBAL_CACHE_FILE_HASH_SIZE; h++) | |
591 | for (f = d->ents[h]; f; f = f->next) | |
592 | { | |
593 | if (FcDebug() & FC_DBG_CACHEV) | |
594 | printf ("FcGlobalCacheScanDir add file %s\n", f->info.file); | |
c8d5753c | 595 | any_in_cache = FcTrue; |
327a7fd4 | 596 | if (!FcCacheFontSetAdd (set, dirs, dir, dir_len, |
d47c9d6e | 597 | f->info.file, f->name, config)) |
327a7fd4 KP |
598 | { |
599 | cache->broken = FcTrue; | |
600 | return FcFalse; | |
601 | } | |
602 | FcGlobalCacheReferenced (cache, &f->info); | |
603 | } | |
c8d5753c KP |
604 | /* |
605 | * Add directories in 'dir' to 'dirs' | |
606 | */ | |
327a7fd4 KP |
607 | for (subdir = d->subdirs; subdir; subdir = subdir->next) |
608 | { | |
e712133c KP |
609 | FcFilePathInfo info = FcFilePathInfoGet (subdir->ent->info.file); |
610 | ||
c8d5753c | 611 | any_in_cache = FcTrue; |
327a7fd4 | 612 | if (!FcCacheFontSetAdd (set, dirs, dir, dir_len, |
d47c9d6e | 613 | info.base, FC_FONT_FILE_DIR, config)) |
327a7fd4 KP |
614 | { |
615 | cache->broken = FcTrue; | |
616 | return FcFalse; | |
617 | } | |
e712133c | 618 | FcGlobalCacheReferenced (cache, &subdir->ent->info); |
327a7fd4 KP |
619 | } |
620 | ||
621 | FcGlobalCacheReferenced (cache, &d->info); | |
622 | ||
c8d5753c KP |
623 | /* |
624 | * To recover from a bug in previous versions of fontconfig, | |
625 | * return FcFalse if no entries in the cache were found | |
626 | * for this directory. This will cause any empty directories | |
627 | * to get rescanned every time fontconfig is initialized. This | |
628 | * might get removed at some point when the older cache files are | |
629 | * presumably fixed. | |
630 | */ | |
631 | return any_in_cache; | |
327a7fd4 KP |
632 | } |
633 | ||
634 | /* | |
635 | * Locate the cache entry for a particular file | |
636 | */ | |
637 | FcGlobalCacheFile * | |
638 | FcGlobalCacheFileGet (FcGlobalCache *cache, | |
639 | const FcChar8 *file, | |
640 | int id, | |
641 | int *count) | |
642 | { | |
643 | FcFilePathInfo i = FcFilePathInfoGet (file); | |
644 | FcGlobalCacheDir *d = FcGlobalCacheDirGet (cache, i.dir, | |
645 | i.dir_len, FcFalse); | |
646 | FcGlobalCacheFile *f, *match = 0; | |
647 | int max = -1; | |
648 | ||
649 | if (!d) | |
650 | return 0; | |
651 | for (f = d->ents[i.base_hash % FC_GLOBAL_CACHE_FILE_HASH_SIZE]; f; f = f->next) | |
652 | { | |
653 | if (f->info.hash == i.base_hash && | |
654 | !strcmp ((const char *) f->info.file, (const char *) i.base)) | |
655 | { | |
656 | if (f->id == id) | |
657 | match = f; | |
658 | if (f->id > max) | |
659 | max = f->id; | |
660 | } | |
661 | } | |
662 | if (count) | |
a8386abc | 663 | *count = max + 1; |
327a7fd4 KP |
664 | return match; |
665 | } | |
666 | ||
667 | /* | |
668 | * Add a file entry to the cache | |
669 | */ | |
670 | static FcGlobalCacheInfo * | |
671 | FcGlobalCacheFileAdd (FcGlobalCache *cache, | |
672 | const FcChar8 *path, | |
673 | int id, | |
674 | time_t time, | |
675 | const FcChar8 *name, | |
676 | FcBool replace) | |
677 | { | |
678 | FcFilePathInfo i = FcFilePathInfoGet (path); | |
679 | FcGlobalCacheDir *d = FcGlobalCacheDirGet (cache, i.dir, | |
680 | i.dir_len, FcTrue); | |
681 | FcGlobalCacheFile *f, **prev; | |
9dac3c59 | 682 | int size; |
327a7fd4 KP |
683 | |
684 | if (!d) | |
685 | return 0; | |
686 | for (prev = &d->ents[i.base_hash % FC_GLOBAL_CACHE_FILE_HASH_SIZE]; | |
687 | (f = *prev); | |
688 | prev = &(*prev)->next) | |
689 | { | |
690 | if (f->info.hash == i.base_hash && | |
691 | f->id == id && | |
692 | !strcmp ((const char *) f->info.file, (const char *) i.base)) | |
693 | { | |
694 | break; | |
695 | } | |
696 | } | |
24330d27 KP |
697 | if (*prev) |
698 | { | |
699 | if (!replace) | |
327a7fd4 | 700 | return 0; |
24330d27 | 701 | |
327a7fd4 KP |
702 | f = *prev; |
703 | if (f->info.referenced) | |
24330d27 | 704 | cache->referenced--; |
327a7fd4 | 705 | *prev = f->next; |
9dac3c59 KP |
706 | FcMemFree (FC_MEM_CACHE, sizeof (FcGlobalCacheFile) + |
707 | strlen ((char *) f->info.file) + 1 + | |
708 | strlen ((char *) f->name) + 1); | |
327a7fd4 | 709 | free (f); |
24330d27 | 710 | } |
9dac3c59 KP |
711 | size = (sizeof (FcGlobalCacheFile) + |
712 | strlen ((char *) i.base) + 1 + | |
713 | strlen ((char *) name) + 1); | |
714 | f = malloc (size); | |
327a7fd4 KP |
715 | if (!f) |
716 | return 0; | |
9dac3c59 | 717 | FcMemAlloc (FC_MEM_CACHE, size); |
327a7fd4 KP |
718 | f->next = *prev; |
719 | *prev = f; | |
720 | f->info.hash = i.base_hash; | |
721 | f->info.file = (FcChar8 *) (f + 1); | |
722 | f->info.time = time; | |
723 | f->info.referenced = FcFalse; | |
724 | f->id = id; | |
725 | f->name = f->info.file + strlen ((char *) i.base) + 1; | |
726 | strcpy ((char *) f->info.file, (const char *) i.base); | |
727 | strcpy ((char *) f->name, (const char *) name); | |
728 | return &f->info; | |
24330d27 KP |
729 | } |
730 | ||
327a7fd4 KP |
731 | FcGlobalCache * |
732 | FcGlobalCacheCreate (void) | |
24330d27 | 733 | { |
327a7fd4 KP |
734 | FcGlobalCache *cache; |
735 | int h; | |
24330d27 | 736 | |
327a7fd4 | 737 | cache = malloc (sizeof (FcGlobalCache)); |
24330d27 KP |
738 | if (!cache) |
739 | return 0; | |
9dac3c59 | 740 | FcMemAlloc (FC_MEM_CACHE, sizeof (FcGlobalCache)); |
327a7fd4 | 741 | for (h = 0; h < FC_GLOBAL_CACHE_DIR_HASH_SIZE; h++) |
24330d27 KP |
742 | cache->ents[h] = 0; |
743 | cache->entries = 0; | |
744 | cache->referenced = 0; | |
745 | cache->updated = FcFalse; | |
bb356b68 | 746 | cache->broken = FcFalse; |
24330d27 KP |
747 | return cache; |
748 | } | |
749 | ||
750 | void | |
327a7fd4 | 751 | FcGlobalCacheDestroy (FcGlobalCache *cache) |
24330d27 | 752 | { |
327a7fd4 KP |
753 | FcGlobalCacheDir *d, *next; |
754 | int h; | |
24330d27 | 755 | |
327a7fd4 | 756 | for (h = 0; h < FC_GLOBAL_CACHE_DIR_HASH_SIZE; h++) |
24330d27 | 757 | { |
327a7fd4 | 758 | for (d = cache->ents[h]; d; d = next) |
24330d27 | 759 | { |
327a7fd4 KP |
760 | next = d->next; |
761 | FcGlobalCacheDirDestroy (d); | |
24330d27 KP |
762 | } |
763 | } | |
9dac3c59 | 764 | FcMemFree (FC_MEM_CACHE, sizeof (FcGlobalCache)); |
24330d27 KP |
765 | free (cache); |
766 | } | |
767 | ||
327a7fd4 KP |
768 | /* |
769 | * Cache file syntax is quite simple: | |
770 | * | |
771 | * "file_name" id time "font_name" \n | |
772 | */ | |
773 | ||
24330d27 | 774 | void |
327a7fd4 KP |
775 | FcGlobalCacheLoad (FcGlobalCache *cache, |
776 | const FcChar8 *cache_file) | |
24330d27 | 777 | { |
327a7fd4 KP |
778 | FILE *f; |
779 | FcChar8 file_buf[8192], *file; | |
780 | int id; | |
781 | time_t time; | |
782 | FcChar8 name_buf[8192], *name; | |
783 | FcGlobalCacheInfo *info; | |
24330d27 | 784 | |
ccb3e93b | 785 | f = fopen ((char *) cache_file, "r"); |
24330d27 KP |
786 | if (!f) |
787 | return; | |
788 | ||
789 | cache->updated = FcFalse; | |
ccb3e93b KP |
790 | file = 0; |
791 | name = 0; | |
327a7fd4 KP |
792 | while ((file = FcCacheReadString (f, file_buf, sizeof (file_buf))) && |
793 | FcCacheReadInt (f, &id) && | |
794 | FcCacheReadTime (f, &time) && | |
795 | (name = FcCacheReadString (f, name_buf, sizeof (name_buf)))) | |
24330d27 | 796 | { |
327a7fd4 KP |
797 | if (FcDebug () & FC_DBG_CACHEV) |
798 | printf ("FcGlobalCacheLoad \"%s\" \"%20.20s\"\n", file, name); | |
799 | if (!FcStrCmp (name, FC_FONT_FILE_DIR)) | |
c4ab52dc | 800 | info = FcGlobalCacheDirAdd (cache, file, time, FcFalse, FcTrue); |
327a7fd4 KP |
801 | else |
802 | info = FcGlobalCacheFileAdd (cache, file, id, time, name, FcFalse); | |
803 | if (!info) | |
804 | cache->broken = FcTrue; | |
805 | else | |
806 | cache->entries++; | |
807 | if (FcDebug () & FC_DBG_CACHE_REF) | |
808 | printf ("FcGlobalCacheLoad entry %d %s\n", | |
809 | cache->entries, file); | |
ccb3e93b KP |
810 | if (file != file_buf) |
811 | free (file); | |
812 | if (name != name_buf) | |
813 | free (name); | |
814 | file = 0; | |
815 | name = 0; | |
24330d27 | 816 | } |
ccb3e93b KP |
817 | if (file && file != file_buf) |
818 | free (file); | |
819 | if (name && name != name_buf) | |
820 | free (name); | |
24330d27 KP |
821 | fclose (f); |
822 | } | |
823 | ||
824 | FcBool | |
327a7fd4 KP |
825 | FcGlobalCacheUpdate (FcGlobalCache *cache, |
826 | const FcChar8 *file, | |
827 | int id, | |
828 | const FcChar8 *name) | |
24330d27 | 829 | { |
327a7fd4 KP |
830 | const FcChar8 *match; |
831 | struct stat statb; | |
832 | FcGlobalCacheInfo *info; | |
24330d27 KP |
833 | |
834 | match = file; | |
835 | ||
ccb3e93b | 836 | if (stat ((char *) file, &statb) < 0) |
24330d27 | 837 | return FcFalse; |
327a7fd4 KP |
838 | if (S_ISDIR (statb.st_mode)) |
839 | info = FcGlobalCacheDirAdd (cache, file, statb.st_mtime, | |
c4ab52dc | 840 | FcTrue, FcTrue); |
327a7fd4 KP |
841 | else |
842 | info = FcGlobalCacheFileAdd (cache, file, id, statb.st_mtime, | |
843 | name, FcTrue); | |
844 | if (info) | |
24330d27 | 845 | { |
327a7fd4 KP |
846 | FcGlobalCacheReferenced (cache, info); |
847 | cache->updated = FcTrue; | |
24330d27 | 848 | } |
327a7fd4 KP |
849 | else |
850 | cache->broken = FcTrue; | |
851 | return info != 0; | |
24330d27 KP |
852 | } |
853 | ||
854 | FcBool | |
327a7fd4 KP |
855 | FcGlobalCacheSave (FcGlobalCache *cache, |
856 | const FcChar8 *cache_file) | |
24330d27 | 857 | { |
327a7fd4 KP |
858 | FILE *f; |
859 | int dir_hash, file_hash; | |
860 | FcGlobalCacheDir *dir; | |
861 | FcGlobalCacheFile *file; | |
862 | FcAtomic *atomic; | |
24330d27 KP |
863 | |
864 | if (!cache->updated && cache->referenced == cache->entries) | |
865 | return FcTrue; | |
866 | ||
327a7fd4 KP |
867 | if (cache->broken) |
868 | return FcFalse; | |
869 | ||
daeed6e0 | 870 | #if defined (HAVE_GETUID) && defined (HAVE_GETEUID) |
a391da8f KP |
871 | /* Set-UID programs can't safely update the cache */ |
872 | if (getuid () != geteuid ()) | |
873 | return FcFalse; | |
daeed6e0 | 874 | #endif |
a391da8f | 875 | |
134f6011 KP |
876 | atomic = FcAtomicCreate (cache_file); |
877 | if (!atomic) | |
24330d27 | 878 | goto bail0; |
134f6011 | 879 | if (!FcAtomicLock (atomic)) |
24330d27 | 880 | goto bail1; |
134f6011 | 881 | f = fopen ((char *) FcAtomicNewFile(atomic), "w"); |
24330d27 KP |
882 | if (!f) |
883 | goto bail2; | |
884 | ||
327a7fd4 | 885 | for (dir_hash = 0; dir_hash < FC_GLOBAL_CACHE_DIR_HASH_SIZE; dir_hash++) |
24330d27 | 886 | { |
327a7fd4 | 887 | for (dir = cache->ents[dir_hash]; dir; dir = dir->next) |
24330d27 | 888 | { |
327a7fd4 | 889 | if (!dir->info.referenced) |
24330d27 | 890 | continue; |
327a7fd4 | 891 | if (!FcCacheWriteString (f, dir->info.file)) |
24330d27 | 892 | goto bail4; |
fa244f3d | 893 | if (PUTC (' ', f) == EOF) |
24330d27 | 894 | goto bail4; |
327a7fd4 | 895 | if (!FcCacheWriteInt (f, 0)) |
24330d27 | 896 | goto bail4; |
fa244f3d | 897 | if (PUTC (' ', f) == EOF) |
24330d27 | 898 | goto bail4; |
327a7fd4 | 899 | if (!FcCacheWriteTime (f, dir->info.time)) |
24330d27 | 900 | goto bail4; |
fa244f3d | 901 | if (PUTC (' ', f) == EOF) |
24330d27 | 902 | goto bail4; |
327a7fd4 | 903 | if (!FcCacheWriteString (f, (FcChar8 *) FC_FONT_FILE_DIR)) |
24330d27 | 904 | goto bail4; |
fa244f3d | 905 | if (PUTC ('\n', f) == EOF) |
24330d27 | 906 | goto bail4; |
327a7fd4 KP |
907 | |
908 | for (file_hash = 0; file_hash < FC_GLOBAL_CACHE_FILE_HASH_SIZE; file_hash++) | |
909 | { | |
910 | for (file = dir->ents[file_hash]; file; file = file->next) | |
911 | { | |
912 | if (!file->info.referenced) | |
913 | continue; | |
914 | if (!FcCacheWritePath (f, dir->info.file, file->info.file)) | |
915 | goto bail4; | |
fa244f3d | 916 | if (PUTC (' ', f) == EOF) |
327a7fd4 KP |
917 | goto bail4; |
918 | if (!FcCacheWriteInt (f, file->id < 0 ? 0 : file->id)) | |
919 | goto bail4; | |
fa244f3d | 920 | if (PUTC (' ', f) == EOF) |
327a7fd4 KP |
921 | goto bail4; |
922 | if (!FcCacheWriteTime (f, file->info.time)) | |
923 | goto bail4; | |
fa244f3d | 924 | if (PUTC (' ', f) == EOF) |
327a7fd4 KP |
925 | goto bail4; |
926 | if (!FcCacheWriteString (f, file->name)) | |
927 | goto bail4; | |
fa244f3d | 928 | if (PUTC ('\n', f) == EOF) |
327a7fd4 KP |
929 | goto bail4; |
930 | } | |
931 | } | |
24330d27 KP |
932 | } |
933 | } | |
934 | ||
935 | if (fclose (f) == EOF) | |
936 | goto bail3; | |
937 | ||
134f6011 | 938 | if (!FcAtomicReplaceOrig (atomic)) |
24330d27 KP |
939 | goto bail3; |
940 | ||
134f6011 KP |
941 | FcAtomicUnlock (atomic); |
942 | FcAtomicDestroy (atomic); | |
943 | ||
24330d27 KP |
944 | cache->updated = FcFalse; |
945 | return FcTrue; | |
946 | ||
947 | bail4: | |
948 | fclose (f); | |
949 | bail3: | |
134f6011 | 950 | FcAtomicDeleteNew (atomic); |
24330d27 | 951 | bail2: |
134f6011 | 952 | FcAtomicUnlock (atomic); |
24330d27 | 953 | bail1: |
134f6011 | 954 | FcAtomicDestroy (atomic); |
24330d27 KP |
955 | bail0: |
956 | return FcFalse; | |
957 | } | |
958 | ||
959 | FcBool | |
327a7fd4 | 960 | FcDirCacheValid (const FcChar8 *dir) |
179c3995 | 961 | { |
327a7fd4 | 962 | FcChar8 *cache_file = FcStrPlus (dir, (FcChar8 *) "/" FC_DIR_CACHE_FILE); |
179c3995 KP |
963 | struct stat file_stat, dir_stat; |
964 | ||
179c3995 KP |
965 | if (stat ((char *) dir, &dir_stat) < 0) |
966 | { | |
327a7fd4 | 967 | FcStrFree (cache_file); |
179c3995 KP |
968 | return FcFalse; |
969 | } | |
179c3995 | 970 | if (stat ((char *) cache_file, &file_stat) < 0) |
327a7fd4 KP |
971 | { |
972 | FcStrFree (cache_file); | |
179c3995 | 973 | return FcFalse; |
327a7fd4 KP |
974 | } |
975 | FcStrFree (cache_file); | |
179c3995 KP |
976 | /* |
977 | * If the directory has been modified more recently than | |
978 | * the cache file, the cache is not valid | |
979 | */ | |
980 | if (dir_stat.st_mtime - file_stat.st_mtime > 0) | |
981 | return FcFalse; | |
982 | return FcTrue; | |
983 | } | |
984 | ||
985 | FcBool | |
d47c9d6e | 986 | FcDirCacheReadDir (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir, FcConfig *config) |
24330d27 | 987 | { |
327a7fd4 | 988 | FcChar8 *cache_file = FcStrPlus (dir, (FcChar8 *) "/" FC_DIR_CACHE_FILE); |
24330d27 | 989 | FILE *f; |
ccb3e93b | 990 | FcChar8 *base; |
24330d27 | 991 | int id; |
179c3995 | 992 | int dir_len; |
179c3995 | 993 | FcChar8 file_buf[8192], *file; |
ccb3e93b | 994 | FcChar8 name_buf[8192], *name; |
24330d27 KP |
995 | FcBool ret = FcFalse; |
996 | ||
327a7fd4 KP |
997 | if (!cache_file) |
998 | goto bail0; | |
999 | ||
24330d27 | 1000 | if (FcDebug () & FC_DBG_CACHE) |
327a7fd4 | 1001 | printf ("FcDirCacheReadDir cache_file \"%s\"\n", cache_file); |
24330d27 | 1002 | |
ccb3e93b | 1003 | f = fopen ((char *) cache_file, "r"); |
24330d27 KP |
1004 | if (!f) |
1005 | { | |
1006 | if (FcDebug () & FC_DBG_CACHE) | |
24330d27 | 1007 | printf (" no cache file\n"); |
327a7fd4 | 1008 | goto bail1; |
24330d27 KP |
1009 | } |
1010 | ||
327a7fd4 | 1011 | if (!FcDirCacheValid (dir)) |
179c3995 KP |
1012 | { |
1013 | if (FcDebug () & FC_DBG_CACHE) | |
179c3995 | 1014 | printf (" cache file older than directory\n"); |
327a7fd4 | 1015 | goto bail2; |
179c3995 KP |
1016 | } |
1017 | ||
ccb3e93b | 1018 | base = (FcChar8 *) strrchr ((char *) cache_file, '/'); |
24330d27 | 1019 | if (!base) |
327a7fd4 | 1020 | goto bail2; |
24330d27 | 1021 | base++; |
179c3995 | 1022 | dir_len = base - cache_file; |
24330d27 | 1023 | |
ccb3e93b KP |
1024 | file = 0; |
1025 | name = 0; | |
327a7fd4 KP |
1026 | while ((file = FcCacheReadString (f, file_buf, sizeof (file_buf))) && |
1027 | FcCacheReadInt (f, &id) && | |
1028 | (name = FcCacheReadString (f, name_buf, sizeof (name_buf)))) | |
24330d27 | 1029 | { |
327a7fd4 | 1030 | if (!FcCacheFontSetAdd (set, dirs, cache_file, dir_len, |
d47c9d6e | 1031 | file, name, config)) |
327a7fd4 | 1032 | goto bail3; |
ccb3e93b KP |
1033 | if (file != file_buf) |
1034 | free (file); | |
1035 | if (name != name_buf) | |
1036 | free (name); | |
327a7fd4 | 1037 | file = name = 0; |
24330d27 KP |
1038 | } |
1039 | if (FcDebug () & FC_DBG_CACHE) | |
24330d27 | 1040 | printf (" cache loaded\n"); |
24330d27 KP |
1041 | |
1042 | ret = FcTrue; | |
327a7fd4 | 1043 | bail3: |
ccb3e93b KP |
1044 | if (file && file != file_buf) |
1045 | free (file); | |
1046 | if (name && name != name_buf) | |
1047 | free (name); | |
327a7fd4 | 1048 | bail2: |
24330d27 | 1049 | fclose (f); |
327a7fd4 | 1050 | bail1: |
9dac3c59 | 1051 | FcStrFree (cache_file); |
24330d27 KP |
1052 | bail0: |
1053 | return ret; | |
1054 | } | |
1055 | ||
179c3995 KP |
1056 | /* |
1057 | * return the path from the directory containing 'cache' to 'file' | |
1058 | */ | |
1059 | ||
1060 | static const FcChar8 * | |
1061 | FcFileBaseName (const FcChar8 *cache, const FcChar8 *file) | |
1062 | { | |
1063 | const FcChar8 *cache_slash; | |
1064 | ||
daeed6e0 | 1065 | cache_slash = FcStrLastSlash (cache); |
179c3995 KP |
1066 | if (cache_slash && !strncmp ((const char *) cache, (const char *) file, |
1067 | (cache_slash + 1) - cache)) | |
1068 | return file + ((cache_slash + 1) - cache); | |
1069 | return file; | |
1070 | } | |
1071 | ||
24330d27 | 1072 | FcBool |
327a7fd4 | 1073 | FcDirCacheWriteDir (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir) |
24330d27 | 1074 | { |
327a7fd4 | 1075 | FcChar8 *cache_file = FcStrPlus (dir, (FcChar8 *) "/" FC_DIR_CACHE_FILE); |
24330d27 KP |
1076 | FcPattern *font; |
1077 | FILE *f; | |
ccb3e93b KP |
1078 | FcChar8 *name; |
1079 | const FcChar8 *file, *base; | |
24330d27 KP |
1080 | int n; |
1081 | int id; | |
1082 | FcBool ret; | |
179c3995 | 1083 | FcStrList *list; |
24330d27 | 1084 | |
327a7fd4 KP |
1085 | if (!cache_file) |
1086 | goto bail0; | |
24330d27 | 1087 | if (FcDebug () & FC_DBG_CACHE) |
327a7fd4 | 1088 | printf ("FcDirCacheWriteDir cache_file \"%s\"\n", cache_file); |
24330d27 | 1089 | |
ccb3e93b | 1090 | f = fopen ((char *) cache_file, "w"); |
24330d27 KP |
1091 | if (!f) |
1092 | { | |
1093 | if (FcDebug () & FC_DBG_CACHE) | |
1094 | printf (" can't create \"%s\"\n", cache_file); | |
327a7fd4 | 1095 | goto bail1; |
24330d27 | 1096 | } |
179c3995 KP |
1097 | |
1098 | list = FcStrListCreate (dirs); | |
1099 | if (!list) | |
327a7fd4 | 1100 | goto bail2; |
179c3995 KP |
1101 | |
1102 | while ((dir = FcStrListNext (list))) | |
1103 | { | |
1104 | base = FcFileBaseName (cache_file, dir); | |
327a7fd4 KP |
1105 | if (!FcCacheWriteString (f, base)) |
1106 | goto bail3; | |
fa244f3d | 1107 | if (PUTC (' ', f) == EOF) |
327a7fd4 KP |
1108 | goto bail3; |
1109 | if (!FcCacheWriteInt (f, 0)) | |
1110 | goto bail3; | |
fa244f3d | 1111 | if (PUTC (' ', f) == EOF) |
327a7fd4 KP |
1112 | goto bail3; |
1113 | if (!FcCacheWriteString (f, FC_FONT_FILE_DIR)) | |
1114 | goto bail3; | |
fa244f3d | 1115 | if (PUTC ('\n', f) == EOF) |
327a7fd4 | 1116 | goto bail3; |
179c3995 KP |
1117 | } |
1118 | ||
24330d27 KP |
1119 | for (n = 0; n < set->nfont; n++) |
1120 | { | |
1121 | font = set->fonts[n]; | |
aae6f7d4 | 1122 | if (FcPatternGetString (font, FC_FILE, 0, (FcChar8 **) &file) != FcResultMatch) |
327a7fd4 | 1123 | goto bail3; |
179c3995 | 1124 | base = FcFileBaseName (cache_file, file); |
24330d27 | 1125 | if (FcPatternGetInteger (font, FC_INDEX, 0, &id) != FcResultMatch) |
327a7fd4 | 1126 | goto bail3; |
24330d27 KP |
1127 | if (FcDebug () & FC_DBG_CACHEV) |
1128 | printf (" write file \"%s\"\n", base); | |
327a7fd4 KP |
1129 | if (!FcCacheWriteString (f, base)) |
1130 | goto bail3; | |
fa244f3d | 1131 | if (PUTC (' ', f) == EOF) |
327a7fd4 KP |
1132 | goto bail3; |
1133 | if (!FcCacheWriteInt (f, id)) | |
1134 | goto bail3; | |
fa244f3d | 1135 | if (PUTC (' ', f) == EOF) |
327a7fd4 | 1136 | goto bail3; |
24330d27 KP |
1137 | name = FcNameUnparse (font); |
1138 | if (!name) | |
327a7fd4 KP |
1139 | goto bail3; |
1140 | ret = FcCacheWriteString (f, name); | |
9dac3c59 | 1141 | FcStrFree (name); |
24330d27 | 1142 | if (!ret) |
327a7fd4 | 1143 | goto bail3; |
fa244f3d | 1144 | if (PUTC ('\n', f) == EOF) |
327a7fd4 | 1145 | goto bail3; |
24330d27 | 1146 | } |
179c3995 KP |
1147 | |
1148 | FcStrListDone (list); | |
1149 | ||
24330d27 | 1150 | if (fclose (f) == EOF) |
327a7fd4 | 1151 | goto bail1; |
24330d27 | 1152 | |
9dac3c59 | 1153 | FcStrFree (cache_file); |
327a7fd4 | 1154 | |
24330d27 KP |
1155 | if (FcDebug () & FC_DBG_CACHE) |
1156 | printf (" cache written\n"); | |
1157 | return FcTrue; | |
1158 | ||
327a7fd4 | 1159 | bail3: |
179c3995 | 1160 | FcStrListDone (list); |
327a7fd4 | 1161 | bail2: |
24330d27 | 1162 | fclose (f); |
327a7fd4 | 1163 | bail1: |
ccb3e93b | 1164 | unlink ((char *) cache_file); |
9dac3c59 | 1165 | FcStrFree (cache_file); |
327a7fd4 | 1166 | bail0: |
24330d27 KP |
1167 | return FcFalse; |
1168 | } | |
cd2ec1a9 PL |
1169 | |
1170 | void | |
1171 | FcCacheClearStatic() | |
1172 | { | |
1173 | FcFontSetClearStatic(); | |
1174 | FcPatternClearStatic(); | |
1175 | FcValueListClearStatic(); | |
1176 | FcObjectClearStatic(); | |
1177 | FcMatrixClearStatic(); | |
1178 | FcCharSetClearStatic(); | |
1179 | FcLangSetClearStatic(); | |
1180 | } | |
1181 | ||
1182 | FcBool | |
1183 | FcCachePrepareSerialize (FcConfig * config) | |
1184 | { | |
1185 | int i; | |
1186 | for (i = FcSetSystem; i <= FcSetApplication; i++) | |
1187 | if (config->fonts[i] && !FcFontSetPrepareSerialize(config->fonts[i])) | |
1188 | return FcFalse; | |
1189 | return FcTrue; | |
1190 | } | |
1191 | ||
1192 | FcBool | |
1193 | FcCacheSerialize (FcConfig * config) | |
1194 | { | |
1195 | int i; | |
1196 | for (i = FcSetSystem; i <= FcSetApplication; i++) | |
1197 | if (config->fonts[i] && !FcFontSetSerialize(config->fonts[i])) | |
1198 | return FcFalse; | |
1199 | return FcTrue; | |
1200 | } |