2 * $XFree86: xc/lib/fontconfig/src/fccache.c,v 1.4 2002/03/01 01:00:54 keithp Exp $
4 * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
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 FcFileCacheHash (const FcChar8 *string)
33 while ((c = *string++))
39 FcFileCacheFind (FcFileCache *cache,
46 FcFileCacheEnt *c, *name;
52 hash = FcFileCacheHash (match);
55 for (c = cache->ents[hash % FC_FILE_CACHE_HASH_SIZE]; c; c = c->next)
57 if (c->hash == hash && !strcmp ((const char *) match, (const char *) c->file))
63 if (stat ((char *) file, &statb) < 0)
65 if (FcDebug () & FC_DBG_CACHE)
66 printf (" file missing\n");
69 if (statb.st_mtime != c->time)
71 if (FcDebug () & FC_DBG_CACHE)
72 printf (" timestamp mismatch (was %d is %d)\n",
73 (int) c->time, (int) statb.st_mtime);
79 c->referenced = FcTrue;
92 * Cache file syntax is quite simple:
94 * "file_name" id time "font_name" \n
98 FcFileCacheReadString (FILE *f, FcChar8 *dest, int len)
106 while ((c = getc (f)) != EOF)
118 while ((c = getc (f)) != EOF)
133 FcChar8 *new = malloc (size * 2);
136 memcpy (new, d, size);
153 FcFileCacheReadUlong (FILE *f, unsigned long *dest)
158 while ((c = getc (f)) != EOF)
168 if (c == EOF || isspace (c))
172 t = t * 10 + (c - '0');
180 FcFileCacheReadInt (FILE *f, int *dest)
185 ret = FcFileCacheReadUlong (f, &t);
192 FcFileCacheReadTime (FILE *f, time_t *dest)
197 ret = FcFileCacheReadUlong (f, &t);
204 FcFileCacheAdd (FcFileCache *cache,
212 FcFileCacheEnt **prev, *old;
215 if (FcDebug () & FC_DBG_CACHE)
217 printf ("%s face %s/%d as %s\n", replace ? "Replace" : "Add",
220 hash = FcFileCacheHash (file);
221 for (prev = &cache->ents[hash % FC_FILE_CACHE_HASH_SIZE];
223 prev = &(*prev)->next)
225 if (old->hash == hash && old->id == id && !strcmp ((const char *) old->file,
226 (const char *) file))
242 c = malloc (sizeof (FcFileCacheEnt) +
243 strlen ((char *) file) + 1 +
244 strlen ((char *) name) + 1);
250 c->file = (FcChar8 *) (c + 1);
252 c->name = c->file + strlen ((char *) file) + 1;
253 strcpy ((char *) c->file, (const char *) file);
255 c->referenced = replace;
256 strcpy ((char *) c->name, (const char *) name);
262 FcFileCacheCreate (void)
267 cache = malloc (sizeof (FcFileCache));
270 for (h = 0; h < FC_FILE_CACHE_HASH_SIZE; h++)
273 cache->referenced = 0;
274 cache->updated = FcFalse;
279 FcFileCacheDestroy (FcFileCache *cache)
281 FcFileCacheEnt *c, *next;
284 for (h = 0; h < FC_FILE_CACHE_HASH_SIZE; h++)
286 for (c = cache->ents[h]; c; c = next)
296 FcFileCacheLoad (FcFileCache *cache,
297 const FcChar8 *cache_file)
300 FcChar8 file_buf[8192], *file;
303 FcChar8 name_buf[8192], *name;
305 f = fopen ((char *) cache_file, "r");
309 cache->updated = FcFalse;
312 while ((file = FcFileCacheReadString (f, file_buf, sizeof (file_buf))) &&
313 FcFileCacheReadInt (f, &id) &&
314 FcFileCacheReadTime (f, &time) &&
315 (name = FcFileCacheReadString (f, name_buf, sizeof (name_buf))))
317 (void) FcFileCacheAdd (cache, file, id, time, name, FcFalse);
318 if (file != file_buf)
320 if (name != name_buf)
325 if (file && file != file_buf)
327 if (name && name != name_buf)
333 FcFileCacheUpdate (FcFileCache *cache,
338 const FcChar8 *match;
344 if (stat ((char *) file, &statb) < 0)
346 ret = FcFileCacheAdd (cache, match, id,
347 statb.st_mtime, name, FcTrue);
349 cache->updated = FcTrue;
354 FcFileCacheWriteString (FILE *f, const FcChar8 *string)
358 if (putc ('"', f) == EOF)
360 while ((c = *string++))
365 if (putc ('\\', f) == EOF)
369 if (putc (c, f) == EOF)
373 if (putc ('"', f) == EOF)
379 FcFileCacheWriteUlong (FILE *f, unsigned long t)
382 unsigned long temp, digit;
395 if (putc ((char) digit + '0', f) == EOF)
397 temp = temp - pow * digit;
404 FcFileCacheWriteInt (FILE *f, int i)
406 return FcFileCacheWriteUlong (f, (unsigned long) i);
410 FcFileCacheWriteTime (FILE *f, time_t t)
412 return FcFileCacheWriteUlong (f, (unsigned long) t);
416 FcFileCacheSave (FcFileCache *cache,
417 const FcChar8 *cache_file)
424 if (!cache->updated && cache->referenced == cache->entries)
427 /* Set-UID programs can't safely update the cache */
428 if (getuid () != geteuid ())
431 atomic = FcAtomicCreate (cache_file);
434 if (!FcAtomicLock (atomic))
436 f = fopen ((char *) FcAtomicNewFile(atomic), "w");
440 for (h = 0; h < FC_FILE_CACHE_HASH_SIZE; h++)
442 for (c = cache->ents[h]; c; c = c->next)
446 if (!FcFileCacheWriteString (f, c->file))
448 if (putc (' ', f) == EOF)
450 if (!FcFileCacheWriteInt (f, c->id))
452 if (putc (' ', f) == EOF)
454 if (!FcFileCacheWriteTime (f, c->time))
456 if (putc (' ', f) == EOF)
458 if (!FcFileCacheWriteString (f, c->name))
460 if (putc ('\n', f) == EOF)
465 if (fclose (f) == EOF)
468 if (!FcAtomicReplaceOrig (atomic))
471 FcAtomicUnlock (atomic);
472 FcAtomicDestroy (atomic);
474 cache->updated = FcFalse;
480 FcAtomicDeleteNew (atomic);
482 FcAtomicUnlock (atomic);
484 FcAtomicDestroy (atomic);
490 FcFileCacheValid (const FcChar8 *cache_file)
492 FcChar8 *dir = FcStrDirname (cache_file);
493 struct stat file_stat, dir_stat;
497 if (stat ((char *) dir, &dir_stat) < 0)
503 if (stat ((char *) cache_file, &file_stat) < 0)
506 * If the directory has been modified more recently than
507 * the cache file, the cache is not valid
509 if (dir_stat.st_mtime - file_stat.st_mtime > 0)
515 FcFileCacheReadDir (FcFontSet *set, FcStrSet *dirs, const FcChar8 *cache_file)
523 FcChar8 file_buf[8192], *file;
524 FcChar8 name_buf[8192], *name;
525 FcChar8 path_buf[8192], *path;
526 FcBool ret = FcFalse;
528 if (FcDebug () & FC_DBG_CACHE)
530 printf ("FcFileCacheReadDir cache_file \"%s\"\n", cache_file);
533 f = fopen ((char *) cache_file, "r");
536 if (FcDebug () & FC_DBG_CACHE)
538 printf (" no cache file\n");
543 if (!FcFileCacheValid (cache_file))
545 if (FcDebug () & FC_DBG_CACHE)
547 printf (" cache file older than directory\n");
552 base = (FcChar8 *) strrchr ((char *) cache_file, '/');
556 dir_len = base - cache_file;
557 if (dir_len < sizeof (path_buf))
558 strncpy ((char *) path_buf, (const char *) cache_file, dir_len);
563 while ((file = FcFileCacheReadString (f, file_buf, sizeof (file_buf))) &&
564 FcFileCacheReadInt (f, &id) &&
565 (name = FcFileCacheReadString (f, name_buf, sizeof (name_buf))))
567 file_len = strlen ((const char *) file);
568 if (dir_len + file_len + 1 > sizeof (path_buf))
570 path = malloc (dir_len + file_len + 1);
573 strncpy ((char *) path, (const char *) cache_file, dir_len);
578 strcpy ((char *) path + dir_len, (const char *) file);
579 if (!FcStrCmp (name, FC_FONT_FILE_DIR))
581 if (FcDebug () & FC_DBG_CACHEV)
583 printf (" dir cache dir \"%s\"\n", path);
585 if (!FcStrSetAdd (dirs, path))
590 font = FcNameParse (name);
593 if (FcDebug () & FC_DBG_CACHEV)
595 printf (" dir cache file \"%s\"\n", file);
597 FcPatternAddString (font, FC_FILE, path);
598 if (!FcFontSetAdd (set, font))
602 if (path != path_buf)
604 if (file != file_buf)
606 if (name != name_buf)
608 path = file = name = 0;
610 if (FcDebug () & FC_DBG_CACHE)
612 printf (" cache loaded\n");
617 if (path && path != path_buf)
619 if (file && file != file_buf)
621 if (name && name != name_buf)
630 * return the path from the directory containing 'cache' to 'file'
633 static const FcChar8 *
634 FcFileBaseName (const FcChar8 *cache, const FcChar8 *file)
636 const FcChar8 *cache_slash;
638 cache_slash = (const FcChar8 *) strrchr ((const char *) cache, '/');
639 if (cache_slash && !strncmp ((const char *) cache, (const char *) file,
640 (cache_slash + 1) - cache))
641 return file + ((cache_slash + 1) - cache);
646 FcFileCacheWriteDir (FcFontSet *set, FcStrSet *dirs, const FcChar8 *cache_file)
651 const FcChar8 *file, *base;
658 if (FcDebug () & FC_DBG_CACHE)
659 printf ("FcFileCacheWriteDir cache_file \"%s\"\n", cache_file);
661 f = fopen ((char *) cache_file, "w");
664 if (FcDebug () & FC_DBG_CACHE)
665 printf (" can't create \"%s\"\n", cache_file);
669 list = FcStrListCreate (dirs);
673 while ((dir = FcStrListNext (list)))
675 base = FcFileBaseName (cache_file, dir);
676 if (!FcFileCacheWriteString (f, base))
678 if (putc (' ', f) == EOF)
680 if (!FcFileCacheWriteInt (f, 0))
682 if (putc (' ', f) == EOF)
684 if (!FcFileCacheWriteString (f, FC_FONT_FILE_DIR))
686 if (putc ('\n', f) == EOF)
690 for (n = 0; n < set->nfont; n++)
692 font = set->fonts[n];
693 if (FcPatternGetString (font, FC_FILE, 0, (FcChar8 **) &file) != FcResultMatch)
695 base = FcFileBaseName (cache_file, file);
696 if (FcPatternGetInteger (font, FC_INDEX, 0, &id) != FcResultMatch)
698 if (FcDebug () & FC_DBG_CACHEV)
699 printf (" write file \"%s\"\n", base);
700 if (!FcFileCacheWriteString (f, base))
702 if (putc (' ', f) == EOF)
704 if (!FcFileCacheWriteInt (f, id))
706 if (putc (' ', f) == EOF)
708 name = FcNameUnparse (font);
711 ret = FcFileCacheWriteString (f, name);
715 if (putc ('\n', f) == EOF)
719 FcStrListDone (list);
721 if (fclose (f) == EOF)
724 if (FcDebug () & FC_DBG_CACHE)
725 printf (" cache written\n");
729 FcStrListDone (list);
733 unlink ((char *) cache_file);