2 * $RCSId: xc/lib/fontconfig/src/fccache.c,v 1.12 2002/08/22 07:36:44 keithp Exp $
4 * Copyright © 2000 Keith Packard
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.
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.
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.
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)
38 #define GETC(f) getc(f)
39 #define PUTC(c,f) putc(c,f)
42 #define FC_DBG_CACHE_REF 1024
45 FcCacheReadString (FILE *f, FcChar8 *dest, int len)
53 while ((c = GETC (f)) != EOF)
65 while ((c = GETC (f)) != EOF)
80 FcChar8 *new = malloc (size * 2); /* freed in caller */
83 memcpy (new, d, size);
100 FcCacheReadUlong (FILE *f, unsigned long *dest)
105 while ((c = GETC (f)) != EOF)
115 if (c == EOF || isspace (c))
119 t = t * 10 + (c - '0');
127 FcCacheReadInt (FILE *f, int *dest)
132 ret = FcCacheReadUlong (f, &t);
139 FcCacheReadTime (FILE *f, time_t *dest)
144 ret = FcCacheReadUlong (f, &t);
151 FcCacheWriteChars (FILE *f, const FcChar8 *chars)
154 while ((c = *chars++))
159 if (PUTC ('\\', f) == EOF)
163 if (PUTC (c, f) == EOF)
171 FcCacheWriteString (FILE *f, const FcChar8 *string)
174 if (PUTC ('"', f) == EOF)
176 if (!FcCacheWriteChars (f, string))
178 if (PUTC ('"', f) == EOF)
184 FcCacheWritePath (FILE *f, const FcChar8 *dir, const FcChar8 *file)
186 if (PUTC ('"', f) == EOF)
189 if (!FcCacheWriteChars (f, dir))
193 dir[strlen((const char *) dir) - 1] != '/' &&
194 dir[strlen((const char *) dir) - 1] != '\\')
196 if (!FcCacheWriteChars (f, "\\"))
200 if (dir && dir[strlen((const char *) dir) - 1] != '/')
201 if (PUTC ('/', f) == EOF)
204 if (!FcCacheWriteChars (f, file))
206 if (PUTC ('"', f) == EOF)
212 FcCacheWriteUlong (FILE *f, unsigned long t)
215 unsigned long temp, digit;
228 if (PUTC ((char) digit + '0', f) == EOF)
230 temp = temp - pow * digit;
237 FcCacheWriteInt (FILE *f, int i)
239 return FcCacheWriteUlong (f, (unsigned long) i);
243 FcCacheWriteTime (FILE *f, time_t t)
245 return FcCacheWriteUlong (f, (unsigned long) t);
249 FcCacheFontSetAdd (FcFontSet *set,
257 FcChar8 path_buf[8192], *path;
259 FcBool ret = FcFalse;
264 len = (dir_len + 1 + strlen ((const char *) file) + 1);
265 if (len > sizeof (path_buf))
267 path = malloc (len); /* freed down below */
271 strncpy ((char *) path, (const char *) dir, dir_len);
273 if (dir[dir_len - 1] != '/' && dir[dir_len - 1] != '\\' )
274 path[dir_len++] = '\\';
276 if (dir[dir_len - 1] != '/')
277 path[dir_len++] = '/';
279 strcpy ((char *) path + dir_len, (const char *) file);
280 if (config && !FcConfigAcceptFilename (config, path))
282 else if (!FcStrCmp (name, FC_FONT_FILE_DIR))
284 if (FcDebug () & FC_DBG_CACHEV)
285 printf (" dir cache dir \"%s\"\n", path);
286 ret = FcStrSetAdd (dirs, path);
288 else if (!FcStrCmp (name, FC_FONT_FILE_INVALID))
294 font = FcNameParse (name);
299 if (FcDebug () & FC_DBG_CACHEV)
300 printf (" dir cache file \"%s\"\n", file);
301 ret = FcPatternAddString (font, FC_FILE, path);
303 * Make sure the pattern has the file name as well as
304 * already containing at least one family name.
307 FcPatternGetString (font, FC_FAMILY, 0, &family) == FcResultMatch &&
308 (!config || FcConfigAcceptFont (config, font)))
310 frozen = FcPatternFreeze (font);
313 ret = FcFontSetAdd (set, frozen);
315 FcPatternDestroy (font);
318 if (path != path_buf) free (path);
324 FcCacheHash (const FcChar8 *string, int len)
329 while (len-- && (c = *string++))
335 * Verify the saved timestamp for a file
338 FcGlobalCacheCheckTime (const FcChar8 *file, FcGlobalCacheInfo *info)
342 if (stat ((char *) file, &statb) < 0)
344 if (FcDebug () & FC_DBG_CACHE)
345 printf (" file %s missing\n", file);
348 if (statb.st_mtime != info->time)
350 if (FcDebug () & FC_DBG_CACHE)
351 printf (" timestamp mismatch (was %d is %d)\n",
352 (int) info->time, (int) statb.st_mtime);
359 FcGlobalCacheReferenced (FcGlobalCache *cache,
360 FcGlobalCacheInfo *info)
362 if (!info->referenced)
364 info->referenced = FcTrue;
366 if (FcDebug () & FC_DBG_CACHE_REF)
367 printf ("Reference %d %s\n", cache->referenced, info->file);
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
377 typedef struct _FcFilePathInfo {
381 unsigned int base_hash;
384 static FcFilePathInfo
385 FcFilePathInfoGet (const FcChar8 *path)
390 slash = FcStrLastSlash (path);
394 i.dir_len = slash - path;
401 i.dir = (const FcChar8 *) ".";
405 i.base_hash = FcCacheHash (i.base, -1);
410 FcGlobalCacheDirGet (FcGlobalCache *cache,
413 FcBool create_missing)
415 unsigned int hash = FcCacheHash (dir, len);
416 FcGlobalCacheDir *d, **prev;
418 for (prev = &cache->ents[hash % FC_GLOBAL_CACHE_DIR_HASH_SIZE];
420 prev = &(*prev)->next)
422 if (d->info.hash == hash && d->len == len &&
423 !strncmp ((const char *) d->info.file,
424 (const char *) dir, len))
432 d = malloc (sizeof (FcGlobalCacheDir) + len + 1);
435 FcMemAlloc (FC_MEM_CACHE, sizeof (FcGlobalCacheDir) + len + 1);
439 d->info.file = (FcChar8 *) (d + 1);
440 strncpy ((char *) d->info.file, (const char *) dir, len);
441 d->info.file[len] = '\0';
443 d->info.referenced = FcFalse;
445 for (i = 0; i < FC_GLOBAL_CACHE_FILE_HASH_SIZE; i++)
452 static FcGlobalCacheInfo *
453 FcGlobalCacheDirAdd (FcGlobalCache *cache,
457 FcBool create_missing)
461 FcGlobalCacheSubdir *subdir;
462 FcGlobalCacheDir *parent;
464 i = FcFilePathInfoGet (dir);
465 parent = FcGlobalCacheDirGet (cache, i.dir, i.dir_len, create_missing);
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.
475 if (!parent || (!create_missing &&
476 (!parent->info.referenced ||
477 (parent->info.time == 0))))
480 * Add this directory to the cache
482 d = FcGlobalCacheDirGet (cache, dir, strlen ((const char *) dir), FcTrue);
487 * Add this directory to the subdirectory list of the parent
489 subdir = malloc (sizeof (FcGlobalCacheSubdir));
492 FcMemAlloc (FC_MEM_CACHE, sizeof (FcGlobalCacheSubdir));
494 subdir->next = parent->subdirs;
495 parent->subdirs = subdir;
500 FcGlobalCacheDirDestroy (FcGlobalCacheDir *d)
502 FcGlobalCacheFile *f, *next;
504 FcGlobalCacheSubdir *s, *nexts;
506 for (h = 0; h < FC_GLOBAL_CACHE_FILE_HASH_SIZE; h++)
507 for (f = d->ents[h]; f; f = next)
510 FcMemFree (FC_MEM_CACHE, sizeof (FcGlobalCacheFile) +
511 strlen ((char *) f->info.file) + 1 +
512 strlen ((char *) f->name) + 1);
515 for (s = d->subdirs; s; s = nexts)
518 FcMemFree (FC_MEM_CACHE, sizeof (FcGlobalCacheSubdir));
521 FcMemFree (FC_MEM_CACHE, sizeof (FcGlobalCacheDir) + d->len + 1);
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
532 FcGlobalCacheReferenceSubdir (FcGlobalCache *cache,
535 FcGlobalCacheInfo *info;
536 info = FcGlobalCacheDirAdd (cache, dir, 0, FcFalse, FcFalse);
537 if (info && !info->referenced)
539 info->referenced = FcTrue;
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.
550 FcGlobalCacheScanDir (FcFontSet *set,
552 FcGlobalCache *cache,
556 FcGlobalCacheDir *d = FcGlobalCacheDirGet (cache, dir,
557 strlen ((const char *) dir),
559 FcGlobalCacheFile *f;
562 FcGlobalCacheSubdir *subdir;
563 FcBool any_in_cache = FcFalse;
565 if (FcDebug() & FC_DBG_CACHE)
566 printf ("FcGlobalCacheScanDir %s\n", dir);
570 if (FcDebug () & FC_DBG_CACHE)
571 printf ("\tNo dir cache entry\n");
576 * See if the timestamp recorded in the global cache
577 * matches the directory time, if not, return False
579 if (!FcGlobalCacheCheckTime (d->info.file, &d->info))
581 if (FcDebug () & FC_DBG_CACHE)
582 printf ("\tdir cache entry time mismatch\n");
587 * Add files from 'dir' to the fontset
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)
593 if (FcDebug() & FC_DBG_CACHEV)
594 printf ("FcGlobalCacheScanDir add file %s\n", f->info.file);
595 any_in_cache = FcTrue;
596 if (!FcCacheFontSetAdd (set, dirs, dir, dir_len,
597 f->info.file, f->name, config))
599 cache->broken = FcTrue;
602 FcGlobalCacheReferenced (cache, &f->info);
605 * Add directories in 'dir' to 'dirs'
607 for (subdir = d->subdirs; subdir; subdir = subdir->next)
609 FcFilePathInfo info = FcFilePathInfoGet (subdir->ent->info.file);
611 any_in_cache = FcTrue;
612 if (!FcCacheFontSetAdd (set, dirs, dir, dir_len,
613 info.base, FC_FONT_FILE_DIR, config))
615 cache->broken = FcTrue;
618 FcGlobalCacheReferenced (cache, &subdir->ent->info);
621 FcGlobalCacheReferenced (cache, &d->info);
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
635 * Locate the cache entry for a particular file
638 FcGlobalCacheFileGet (FcGlobalCache *cache,
643 FcFilePathInfo i = FcFilePathInfoGet (file);
644 FcGlobalCacheDir *d = FcGlobalCacheDirGet (cache, i.dir,
646 FcGlobalCacheFile *f, *match = 0;
651 for (f = d->ents[i.base_hash % FC_GLOBAL_CACHE_FILE_HASH_SIZE]; f; f = f->next)
653 if (f->info.hash == i.base_hash &&
654 !strcmp ((const char *) f->info.file, (const char *) i.base))
668 * Add a file entry to the cache
670 static FcGlobalCacheInfo *
671 FcGlobalCacheFileAdd (FcGlobalCache *cache,
678 FcFilePathInfo i = FcFilePathInfoGet (path);
679 FcGlobalCacheDir *d = FcGlobalCacheDirGet (cache, i.dir,
681 FcGlobalCacheFile *f, **prev;
686 for (prev = &d->ents[i.base_hash % FC_GLOBAL_CACHE_FILE_HASH_SIZE];
688 prev = &(*prev)->next)
690 if (f->info.hash == i.base_hash &&
692 !strcmp ((const char *) f->info.file, (const char *) i.base))
703 if (f->info.referenced)
706 FcMemFree (FC_MEM_CACHE, sizeof (FcGlobalCacheFile) +
707 strlen ((char *) f->info.file) + 1 +
708 strlen ((char *) f->name) + 1);
711 size = (sizeof (FcGlobalCacheFile) +
712 strlen ((char *) i.base) + 1 +
713 strlen ((char *) name) + 1);
717 FcMemAlloc (FC_MEM_CACHE, size);
720 f->info.hash = i.base_hash;
721 f->info.file = (FcChar8 *) (f + 1);
723 f->info.referenced = FcFalse;
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);
732 FcGlobalCacheCreate (void)
734 FcGlobalCache *cache;
737 cache = malloc (sizeof (FcGlobalCache));
740 FcMemAlloc (FC_MEM_CACHE, sizeof (FcGlobalCache));
741 for (h = 0; h < FC_GLOBAL_CACHE_DIR_HASH_SIZE; h++)
744 cache->referenced = 0;
745 cache->updated = FcFalse;
746 cache->broken = FcFalse;
751 FcGlobalCacheDestroy (FcGlobalCache *cache)
753 FcGlobalCacheDir *d, *next;
756 for (h = 0; h < FC_GLOBAL_CACHE_DIR_HASH_SIZE; h++)
758 for (d = cache->ents[h]; d; d = next)
761 FcGlobalCacheDirDestroy (d);
764 FcMemFree (FC_MEM_CACHE, sizeof (FcGlobalCache));
769 * Cache file syntax is quite simple:
771 * "file_name" id time "font_name" \n
775 FcGlobalCacheLoad (FcGlobalCache *cache,
776 const FcChar8 *cache_file)
779 FcChar8 file_buf[8192], *file;
782 FcChar8 name_buf[8192], *name;
783 FcGlobalCacheInfo *info;
785 f = fopen ((char *) cache_file, "r");
789 cache->updated = FcFalse;
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))))
797 if (FcDebug () & FC_DBG_CACHEV)
798 printf ("FcGlobalCacheLoad \"%s\" \"%20.20s\"\n", file, name);
799 if (!FcStrCmp (name, FC_FONT_FILE_DIR))
800 info = FcGlobalCacheDirAdd (cache, file, time, FcFalse, FcTrue);
802 info = FcGlobalCacheFileAdd (cache, file, id, time, name, FcFalse);
804 cache->broken = FcTrue;
807 if (FcDebug () & FC_DBG_CACHE_REF)
808 printf ("FcGlobalCacheLoad entry %d %s\n",
809 cache->entries, file);
810 if (file != file_buf)
812 if (name != name_buf)
817 if (file && file != file_buf)
819 if (name && name != name_buf)
825 FcGlobalCacheUpdate (FcGlobalCache *cache,
830 const FcChar8 *match;
832 FcGlobalCacheInfo *info;
836 if (stat ((char *) file, &statb) < 0)
838 if (S_ISDIR (statb.st_mode))
839 info = FcGlobalCacheDirAdd (cache, file, statb.st_mtime,
842 info = FcGlobalCacheFileAdd (cache, file, id, statb.st_mtime,
846 FcGlobalCacheReferenced (cache, info);
847 cache->updated = FcTrue;
850 cache->broken = FcTrue;
855 FcGlobalCacheSave (FcGlobalCache *cache,
856 const FcChar8 *cache_file)
859 int dir_hash, file_hash;
860 FcGlobalCacheDir *dir;
861 FcGlobalCacheFile *file;
864 if (!cache->updated && cache->referenced == cache->entries)
870 #if defined (HAVE_GETUID) && defined (HAVE_GETEUID)
871 /* Set-UID programs can't safely update the cache */
872 if (getuid () != geteuid ())
876 atomic = FcAtomicCreate (cache_file);
879 if (!FcAtomicLock (atomic))
881 f = fopen ((char *) FcAtomicNewFile(atomic), "w");
885 for (dir_hash = 0; dir_hash < FC_GLOBAL_CACHE_DIR_HASH_SIZE; dir_hash++)
887 for (dir = cache->ents[dir_hash]; dir; dir = dir->next)
889 if (!dir->info.referenced)
891 if (!FcCacheWriteString (f, dir->info.file))
893 if (PUTC (' ', f) == EOF)
895 if (!FcCacheWriteInt (f, 0))
897 if (PUTC (' ', f) == EOF)
899 if (!FcCacheWriteTime (f, dir->info.time))
901 if (PUTC (' ', f) == EOF)
903 if (!FcCacheWriteString (f, (FcChar8 *) FC_FONT_FILE_DIR))
905 if (PUTC ('\n', f) == EOF)
908 for (file_hash = 0; file_hash < FC_GLOBAL_CACHE_FILE_HASH_SIZE; file_hash++)
910 for (file = dir->ents[file_hash]; file; file = file->next)
912 if (!file->info.referenced)
914 if (!FcCacheWritePath (f, dir->info.file, file->info.file))
916 if (PUTC (' ', f) == EOF)
918 if (!FcCacheWriteInt (f, file->id < 0 ? 0 : file->id))
920 if (PUTC (' ', f) == EOF)
922 if (!FcCacheWriteTime (f, file->info.time))
924 if (PUTC (' ', f) == EOF)
926 if (!FcCacheWriteString (f, file->name))
928 if (PUTC ('\n', f) == EOF)
935 if (fclose (f) == EOF)
938 if (!FcAtomicReplaceOrig (atomic))
941 FcAtomicUnlock (atomic);
942 FcAtomicDestroy (atomic);
944 cache->updated = FcFalse;
950 FcAtomicDeleteNew (atomic);
952 FcAtomicUnlock (atomic);
954 FcAtomicDestroy (atomic);
960 FcDirCacheValid (const FcChar8 *dir)
962 FcChar8 *cache_file = FcStrPlus (dir, (FcChar8 *) "/" FC_DIR_CACHE_FILE);
963 struct stat file_stat, dir_stat;
965 if (stat ((char *) dir, &dir_stat) < 0)
967 FcStrFree (cache_file);
970 if (stat ((char *) cache_file, &file_stat) < 0)
972 FcStrFree (cache_file);
975 FcStrFree (cache_file);
977 * If the directory has been modified more recently than
978 * the cache file, the cache is not valid
980 if (dir_stat.st_mtime - file_stat.st_mtime > 0)
986 FcDirCacheReadDir (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir, FcConfig *config)
988 FcChar8 *cache_file = FcStrPlus (dir, (FcChar8 *) "/" FC_DIR_CACHE_FILE);
993 FcChar8 file_buf[8192], *file;
994 FcChar8 name_buf[8192], *name;
995 FcBool ret = FcFalse;
1000 if (FcDebug () & FC_DBG_CACHE)
1001 printf ("FcDirCacheReadDir cache_file \"%s\"\n", cache_file);
1003 f = fopen ((char *) cache_file, "r");
1006 if (FcDebug () & FC_DBG_CACHE)
1007 printf (" no cache file\n");
1011 if (!FcDirCacheValid (dir))
1013 if (FcDebug () & FC_DBG_CACHE)
1014 printf (" cache file older than directory\n");
1018 base = (FcChar8 *) strrchr ((char *) cache_file, '/');
1022 dir_len = base - cache_file;
1026 while ((file = FcCacheReadString (f, file_buf, sizeof (file_buf))) &&
1027 FcCacheReadInt (f, &id) &&
1028 (name = FcCacheReadString (f, name_buf, sizeof (name_buf))))
1030 if (!FcCacheFontSetAdd (set, dirs, cache_file, dir_len,
1031 file, name, config))
1033 if (file != file_buf)
1035 if (name != name_buf)
1039 if (FcDebug () & FC_DBG_CACHE)
1040 printf (" cache loaded\n");
1044 if (file && file != file_buf)
1046 if (name && name != name_buf)
1051 FcStrFree (cache_file);
1057 * return the path from the directory containing 'cache' to 'file'
1060 static const FcChar8 *
1061 FcFileBaseName (const FcChar8 *cache, const FcChar8 *file)
1063 const FcChar8 *cache_slash;
1065 cache_slash = FcStrLastSlash (cache);
1066 if (cache_slash && !strncmp ((const char *) cache, (const char *) file,
1067 (cache_slash + 1) - cache))
1068 return file + ((cache_slash + 1) - cache);
1073 FcDirCacheWriteDir (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir)
1075 FcChar8 *cache_file = FcStrPlus (dir, (FcChar8 *) "/" FC_DIR_CACHE_FILE);
1079 const FcChar8 *file, *base;
1087 if (FcDebug () & FC_DBG_CACHE)
1088 printf ("FcDirCacheWriteDir cache_file \"%s\"\n", cache_file);
1090 f = fopen ((char *) cache_file, "w");
1093 if (FcDebug () & FC_DBG_CACHE)
1094 printf (" can't create \"%s\"\n", cache_file);
1098 list = FcStrListCreate (dirs);
1102 while ((dir = FcStrListNext (list)))
1104 base = FcFileBaseName (cache_file, dir);
1105 if (!FcCacheWriteString (f, base))
1107 if (PUTC (' ', f) == EOF)
1109 if (!FcCacheWriteInt (f, 0))
1111 if (PUTC (' ', f) == EOF)
1113 if (!FcCacheWriteString (f, FC_FONT_FILE_DIR))
1115 if (PUTC ('\n', f) == EOF)
1119 for (n = 0; n < set->nfont; n++)
1121 font = set->fonts[n];
1122 if (FcPatternGetString (font, FC_FILE, 0, (FcChar8 **) &file) != FcResultMatch)
1124 base = FcFileBaseName (cache_file, file);
1125 if (FcPatternGetInteger (font, FC_INDEX, 0, &id) != FcResultMatch)
1127 if (FcDebug () & FC_DBG_CACHEV)
1128 printf (" write file \"%s\"\n", base);
1129 if (!FcCacheWriteString (f, base))
1131 if (PUTC (' ', f) == EOF)
1133 if (!FcCacheWriteInt (f, id))
1135 if (PUTC (' ', f) == EOF)
1137 name = FcNameUnparse (font);
1140 ret = FcCacheWriteString (f, name);
1144 if (PUTC ('\n', f) == EOF)
1148 FcStrListDone (list);
1150 if (fclose (f) == EOF)
1153 FcStrFree (cache_file);
1155 if (FcDebug () & FC_DBG_CACHE)
1156 printf (" cache written\n");
1160 FcStrListDone (list);
1164 unlink ((char *) cache_file);
1165 FcStrFree (cache_file);
1171 FcCacheClearStatic()
1173 FcFontSetClearStatic();
1174 FcPatternClearStatic();
1175 FcValueListClearStatic();
1176 FcObjectClearStatic();
1177 FcMatrixClearStatic();
1178 FcCharSetClearStatic();
1179 FcLangSetClearStatic();
1183 FcCachePrepareSerialize (FcConfig * config)
1186 for (i = FcSetSystem; i <= FcSetApplication; i++)
1187 if (config->fonts[i] && !FcFontSetPrepareSerialize(config->fonts[i]))
1193 FcCacheSerialize (FcConfig * config)
1196 for (i = FcSetSystem; i <= FcSetApplication; i++)
1197 if (config->fonts[i] && !FcFontSetSerialize(config->fonts[i]))