diff options
Diffstat (limited to 'nx-X11/lib/Xft1/xftcache.c')
-rw-r--r-- | nx-X11/lib/Xft1/xftcache.c | 608 |
1 files changed, 608 insertions, 0 deletions
diff --git a/nx-X11/lib/Xft1/xftcache.c b/nx-X11/lib/Xft1/xftcache.c new file mode 100644 index 000000000..13e20a92b --- /dev/null +++ b/nx-X11/lib/Xft1/xftcache.c @@ -0,0 +1,608 @@ +/* + * $XFree86: xc/lib/Xft/xftcache.c,v 1.2 2001/06/11 22:53:30 keithp Exp $ + * + * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "xftint.h" + +typedef struct _XftFileCacheEnt { + struct _XftFileCacheEnt *next; + unsigned int hash; + char *file; + int id; + time_t time; + char *name; + Bool referenced; +} XftFileCacheEnt; + +#define HASH_SIZE 509 + +typedef struct _XftFileCache { + XftFileCacheEnt *ents[HASH_SIZE]; + Bool updated; + int entries; + int referenced; +} XftFileCache; + +static XftFileCache _XftFileCache; + +static unsigned int +_XftFileCacheHash (char *string) +{ + unsigned int h = 0; + char c; + + while ((c = *string++)) + h = (h << 1) ^ c; + return h; +} + +char * +XftFileCacheFind (char *file, int id, int *count) +{ + XftFileCache *cache; + unsigned int hash; + char *match; + XftFileCacheEnt *c, *name; + int maxid; + struct stat statb; + + cache = &_XftFileCache; + match = file; + + hash = _XftFileCacheHash (match); + name = 0; + maxid = -1; + for (c = cache->ents[hash % HASH_SIZE]; c; c = c->next) + { + if (c->hash == hash && !strcmp (match, c->file)) + { + if (c->id > maxid) + maxid = c->id; + if (c->id == id) + { + if (stat (file, &statb) < 0) + { + if (_XftFontDebug () & XFT_DBG_CACHE) + printf (" file missing\n"); + return 0; + } + if (statb.st_mtime != c->time) + { + if (_XftFontDebug () & XFT_DBG_CACHE) + printf (" timestamp mismatch (was %d is %d)\n", + (int) c->time, (int) statb.st_mtime); + return 0; + } + if (!c->referenced) + { + cache->referenced++; + c->referenced = True; + } + name = c; + } + } + } + if (!name) + return 0; + *count = maxid + 1; + return name->name; +} + +/* + * Cache file syntax is quite simple: + * + * "file_name" id time "font_name" \n + */ + +static Bool +_XftFileCacheReadString (FILE *f, char *dest, int len) +{ + int c; + Bool escape; + + while ((c = getc (f)) != EOF) + if (c == '"') + break; + if (c == EOF) + return False; + if (len == 0) + return False; + + escape = False; + while ((c = getc (f)) != EOF) + { + if (!escape) + { + switch (c) { + case '"': + *dest++ = '\0'; + return True; + case '\\': + escape = True; + continue; + } + } + if (--len <= 1) + return False; + *dest++ = c; + escape = False; + } + return False; +} + +static Bool +_XftFileCacheReadUlong (FILE *f, unsigned long *dest) +{ + unsigned long t; + int c; + + while ((c = getc (f)) != EOF) + { + if (!isspace (c)) + break; + } + if (c == EOF) + return False; + t = 0; + for (;;) + { + if (c == EOF || isspace (c)) + break; + if (!isdigit (c)) + return False; + t = t * 10 + (c - '0'); + c = getc (f); + } + *dest = t; + return True; +} + +static Bool +_XftFileCacheReadInt (FILE *f, int *dest) +{ + unsigned long t; + Bool ret; + + ret = _XftFileCacheReadUlong (f, &t); + if (ret) + *dest = (int) t; + return ret; +} + +static Bool +_XftFileCacheReadTime (FILE *f, time_t *dest) +{ + unsigned long t; + Bool ret; + + ret = _XftFileCacheReadUlong (f, &t); + if (ret) + *dest = (time_t) t; + return ret; +} + +static Bool +_XftFileCacheAdd (XftFileCache *cache, + char *file, + int id, + time_t time, + char *name, + Bool replace) +{ + XftFileCacheEnt *c; + XftFileCacheEnt **prev, *old; + unsigned int hash; + + if (_XftFontDebug () & XFT_DBG_CACHE) + { + printf ("%s face %s/%d as %s\n", replace ? "Replace" : "Add", + file, id, name); + } + hash = _XftFileCacheHash (file); + for (prev = &cache->ents[hash % HASH_SIZE]; + (old = *prev); + prev = &(*prev)->next) + { + if (old->hash == hash && old->id == id && !strcmp (old->file, file)) + break; + } + if (*prev) + { + if (!replace) + return False; + + old = *prev; + if (old->referenced) + cache->referenced--; + *prev = old->next; + free (old); + cache->entries--; + } + + c = malloc (sizeof (XftFileCacheEnt) + + strlen (file) + 1 + + strlen (name) + 1); + if (!c) + return False; + c->next = *prev; + *prev = c; + c->hash = hash; + c->file = (char *) (c + 1); + c->id = id; + c->name = c->file + strlen (file) + 1; + strcpy (c->file, file); + c->time = time; + c->referenced = replace; + strcpy (c->name, name); + cache->entries++; + return True; +} + +void +XftFileCacheDispose (void) +{ + XftFileCache *cache; + XftFileCacheEnt *c, *next; + int h; + + cache = &_XftFileCache; + + for (h = 0; h < HASH_SIZE; h++) + { + for (c = cache->ents[h]; c; c = next) + { + next = c->next; + free (c); + } + cache->ents[h] = 0; + } + cache->entries = 0; + cache->referenced = 0; + cache->updated = False; +} + +void +XftFileCacheLoad (char *cache_file) +{ + XftFileCache *cache; + FILE *f; + char file[8192]; + int id; + time_t time; + char name[8192]; + + f = fopen (cache_file, "r"); + if (!f) + return; + + cache = &_XftFileCache; + + cache->updated = False; + while (_XftFileCacheReadString (f, file, sizeof (file)) && + _XftFileCacheReadInt (f, &id) && + _XftFileCacheReadTime (f, &time) && + _XftFileCacheReadString (f, name, sizeof (name))) + { + (void) _XftFileCacheAdd (cache, file, id, time, name, False); + } + fclose (f); +} + +Bool +XftFileCacheUpdate (char *file, int id, char *name) +{ + XftFileCache *cache; + char *match; + struct stat statb; + Bool ret; + + cache = &_XftFileCache; + match = file; + + if (stat (file, &statb) < 0) + return False; + ret = _XftFileCacheAdd (cache, match, id, + statb.st_mtime, name, True); + if (ret) + cache->updated = True; + return ret; +} + +static Bool +_XftFileCacheWriteString (FILE *f, char *string) +{ + char c; + + if (putc ('"', f) == EOF) + return False; + while ((c = *string++)) + { + switch (c) { + case '"': + case '\\': + if (putc ('\\', f) == EOF) + return False; + /* fall through */ + default: + if (putc (c, f) == EOF) + return False; + } + } + if (putc ('"', f) == EOF) + return False; + return True; +} + +static Bool +_XftFileCacheWriteUlong (FILE *f, unsigned long t) +{ + int pow; + unsigned long temp, digit; + + temp = t; + pow = 1; + while (temp >= 10) + { + temp /= 10; + pow *= 10; + } + temp = t; + while (pow) + { + digit = temp / pow; + if (putc ((char) digit + '0', f) == EOF) + return False; + temp = temp - pow * digit; + pow = pow / 10; + } + return True; +} + +static Bool +_XftFileCacheWriteInt (FILE *f, int i) +{ + return _XftFileCacheWriteUlong (f, (unsigned long) i); +} + +static Bool +_XftFileCacheWriteTime (FILE *f, time_t t) +{ + return _XftFileCacheWriteUlong (f, (unsigned long) t); +} + +Bool +XftFileCacheSave (char *cache_file) +{ + XftFileCache *cache; + char *lck; + char *tmp; + FILE *f; + int h; + XftFileCacheEnt *c; + + cache = &_XftFileCache; + + if (!cache->updated && cache->referenced == cache->entries) + return True; + + lck = malloc (strlen (cache_file)*2 + 4); + if (!lck) + goto bail0; + tmp = lck + strlen (cache_file) + 2; + strcpy (lck, cache_file); + strcat (lck, "L"); + strcpy (tmp, cache_file); + strcat (tmp, "T"); + if (link (lck, cache_file) < 0 && errno != ENOENT) + goto bail1; + if (access (tmp, F_OK) == 0) + goto bail2; + f = fopen (tmp, "w"); + if (!f) + goto bail2; + + for (h = 0; h < HASH_SIZE; h++) + { + for (c = cache->ents[h]; c; c = c->next) + { + if (!c->referenced) + continue; + if (!_XftFileCacheWriteString (f, c->file)) + goto bail4; + if (putc (' ', f) == EOF) + goto bail4; + if (!_XftFileCacheWriteInt (f, c->id)) + goto bail4; + if (putc (' ', f) == EOF) + goto bail4; + if (!_XftFileCacheWriteTime (f, c->time)) + goto bail4; + if (putc (' ', f) == EOF) + goto bail4; + if (!_XftFileCacheWriteString (f, c->name)) + goto bail4; + if (putc ('\n', f) == EOF) + goto bail4; + } + } + + if (fclose (f) == EOF) + goto bail3; + + if (rename (tmp, cache_file) < 0) + goto bail3; + + unlink (lck); + cache->updated = False; + return True; + +bail4: + fclose (f); +bail3: + unlink (tmp); +bail2: + unlink (lck); +bail1: + free (lck); +bail0: + return False; +} + +Bool +XftFileCacheReadDir (XftFontSet *set, const char *cache_file) +{ + XftPattern *font; + FILE *f; + char *path; + char *base; + char file[8192]; + int id; + char name[8192]; + Bool ret = False; + + if (_XftFontDebug () & XFT_DBG_CACHE) + { + printf ("XftFileCacheReadDir cache_file \"%s\"\n", cache_file); + } + + f = fopen (cache_file, "r"); + if (!f) + { + if (_XftFontDebug () & XFT_DBG_CACHE) + { + printf (" no cache file\n"); + } + goto bail0; + } + + base = strrchr (cache_file, '/'); + if (!base) + goto bail1; + base++; + path = malloc (base - cache_file + 8192 + 1); + if (!path) + goto bail1; + memcpy (path, cache_file, base - cache_file); + base = path + (base - cache_file); + + while (_XftFileCacheReadString (f, file, sizeof (file)) && + _XftFileCacheReadInt (f, &id) && + _XftFileCacheReadString (f, name, sizeof (name))) + { + font = XftNameParse (name); + if (font) + { + strcpy (base, file); + if (_XftFontDebug () & XFT_DBG_CACHEV) + { + printf (" dir cache file \"%s\"\n", file); + } + XftPatternAddString (font, XFT_FILE, path); + if (!XftFontSetAdd (set, font)) + goto bail2; + } + } + if (_XftFontDebug () & XFT_DBG_CACHE) + { + printf (" cache loaded\n"); + } + + ret = True; +bail2: + free (path); +bail1: + fclose (f); +bail0: + return ret; +} + +Bool +XftFileCacheWriteDir (XftFontSet *set, const char *cache_file) +{ + XftPattern *font; + FILE *f; + char name[8192]; + char *file, *base; + int n; + int id; + + if (_XftFontDebug () & XFT_DBG_CACHE) + printf ("XftFileCacheWriteDir cache_file \"%s\"\n", cache_file); + + f = fopen (cache_file, "w"); + if (!f) + { + if (_XftFontDebug () & XFT_DBG_CACHE) + printf (" can't create \"%s\"\n", cache_file); + goto bail0; + } + for (n = 0; n < set->nfont; n++) + { + font = set->fonts[n]; + if (XftPatternGetString (font, XFT_FILE, 0, &file) != XftResultMatch) + goto bail1; + base = strrchr (file, '/'); + if (base) + base = base + 1; + else + base = file; + if (XftPatternGetInteger (font, XFT_INDEX, 0, &id) != XftResultMatch) + goto bail1; + if (!XftNameUnparse (font, name, sizeof (name))) + goto bail1; + if (_XftFontDebug () & XFT_DBG_CACHEV) + printf (" write file \"%s\"\n", base); + if (!_XftFileCacheWriteString (f, base)) + goto bail1; + if (putc (' ', f) == EOF) + goto bail1; + if (!_XftFileCacheWriteInt (f, id)) + goto bail1; + if (putc (' ', f) == EOF) + goto bail1; + if (!_XftFileCacheWriteString (f, name)) + goto bail1; + if (putc ('\n', f) == EOF) + goto bail1; + } + if (fclose (f) == EOF) + goto bail0; + + if (_XftFontDebug () & XFT_DBG_CACHE) + printf (" cache written\n"); + return True; + +bail1: + fclose (f); +bail0: + unlink (cache_file); + return False; +} |