/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <draw.h>#include <plumb.h>#include <regexp.h>#include <bio.h>#include "faces.h" enum /* number of deleted faces to cache */{ Nsave = 20,}; static Facefile *facefiles;static int nsaved;static char *facedom;static char *homeface; /* * Loading the files is slow enough on a dial-up line to be worth this trouble */typedef struct Readcache Readcache;struct Readcache { char *file; char *data; long mtime; long rdtime; Readcache *next;}; static Readcache *rcache; ulongdirlen(char *s){ Dir *d; ulong len; d = dirstat(s); if(d == nil) return 0; len = d->length; free(d); return len;} ulongdirmtime(char *s){ Dir *d; ulong t; d = dirstat(s); if(d == nil) return 0; t = d->mtime; free(d); return t;} static char*doreadfile(char *s){ char *p; int fd, n; ulong len; len = dirlen(s); if(len == 0) return nil; p = malloc(len+1); if(p == nil) return nil; if((fd = open(s, OREAD)) < 0 || (n = readn(fd, p, len)) < 0) { close(fd); free(p); return nil; } p[n] = '\0'; return p;} static char*readfile(char *s){ Readcache *r, **l; char *p; ulong mtime; for(l=&rcache, r=*l; r; l=&r->next, r=*l) { if(strcmp(r->file, s) != 0) continue; /* * if it's less than 30 seconds since we read it, or it * hasn't changed, send back our copy */ if(time(0) - r->rdtime < 30) return strdup(r->data); if(dirmtime(s) == r->mtime) { r->rdtime = time(0); return strdup(r->data); } /* out of date, remove this and fall out of loop */ *l = r->next; free(r->file); free(r->data); free(r); break; } /* add to cache */ mtime = dirmtime(s); if(mtime == 0) return nil; if((p = doreadfile(s)) == nil) return nil; r = malloc(sizeof(*r)); if(r == nil) return nil; r->mtime = mtime; r->file = estrdup(s); r->data = p; r->rdtime = time(0); r->next = rcache; rcache = r; return strdup(r->data);} static char*translatedomain(char *dom, char *list){ static char buf[200]; char *p, *ep, *q, *nextp, *file; char *bbuf, *ebuf; Reprog *exp; if(dom == nil || *dom == 0) return nil; if(list == nil || (file = readfile(list)) == nil) return dom; for(p=file; p; p=nextp) { if(nextp = strchr(p, '\n')) *nextp++ = '\0'; if(*p == '#' || (q = strpbrk(p, " \t")) == nil || q-p > sizeof(buf)-2) continue; bbuf = buf+1; ebuf = buf+(1+(q-p)); strncpy(bbuf, p, ebuf-bbuf); *ebuf = 0; if(*bbuf != '^') *--bbuf = '^'; if(ebuf[-1] != '$') { *ebuf++ = '$'; *ebuf = 0; } if((exp = regcomp(bbuf)) == nil){ fprint(2, "bad regexp in machinelist: %s\n", bbuf); killall("regexp"); } if(regexec(exp, dom, 0, 0)){ free(exp); ep = p+strlen(p); q += strspn(q, " \t"); if(ep-q+2 > sizeof buf) { fprint(2, "huge replacement in machinelist: %.*s\n", utfnlen(q, ep-q), q); exits("bad big replacement"); } strncpy(buf, q, ep-q); ebuf = buf+(ep-q); *ebuf = 0; while(ebuf > buf && (ebuf[-1] == ' ' || ebuf[-1] == '\t')) *--ebuf = 0; free(file); return buf; } free(exp); } free(file); return dom;} static char*tryfindpicture(char *dom, char *user, char *dir, char *dict){ static char buf[1024]; char *file, *p, *nextp, *q; if((file = readfile(dict)) == nil) return nil; snprint(buf, sizeof buf, "%s/%s", dom, user); for(p=file; p; p=nextp){ if(nextp = strchr(p, '\n')) *nextp++ = '\0'; if(*p == '#' || (q = strpbrk(p, " \t")) == nil) continue; *q++ = 0; if(strcmp(buf, p) == 0){ q += strspn(q, " \t"); snprint(buf, sizeof buf, "%s/%s", dir, q); q = buf+strlen(buf); while(q > buf && (q[-1] == ' ' || q[-1] == '\t')) *--q = 0; free(file); return estrdup(buf); } } free(file); return nil;} static char*estrstrdup(char *a, char *b){ char *t; t = emalloc(strlen(a)+strlen(b)+1); strcpy(t, a); strcat(t, b); return t;} static char*tryfindfiledir(char *dom, char *user, char *dir){ char *dict, *ndir, *x; int fd; int i, n; Dir *d; /* * If this directory has a .machinelist, use it. */ x = estrstrdup(dir, "/.machinelist"); dom = estrdup(translatedomain(dom, x)); free(x); /* * If this directory has a .dict, use it. */ dict = estrstrdup(dir, "/.dict"); if(access(dict, AEXIST) >= 0){ x = tryfindpicture(dom, user, dir, dict); free(dict); free(dom); return x; } free(dict); /* * If not, recurse into subdirectories. * Ignore 512x512 directories. * Save 48x48 directories for later. */ if((fd = open(dir, OREAD)) < 0) return nil; while((n = dirread(fd, &d)) > 0){ for(i=0; i<n; i++){ if((d[i].mode&DMDIR) && strncmp(d[i].name, "512x", 4) != 0 && strncmp(d[i].name, "48x48x", 6) != 0){ ndir = emalloc(strlen(dir)+1+strlen(d[i].name)+1); strcpy(ndir, dir); strcat(ndir, "/"); strcat(ndir, d[i].name); if((x = tryfindfiledir(dom, user, ndir)) != nil){ free(ndir); free(d); close(fd); free(dom); return x; } } } free(d); } close(fd); /* * Handle 48x48 directories in the right order. */ ndir = estrstrdup(dir, "/48x48x8"); for(i=8; i>0; i>>=1){ ndir[strlen(ndir)-1] = i+'0'; if(access(ndir, AEXIST) >= 0 && (x = tryfindfiledir(dom, user, ndir)) != nil){ free(ndir); free(dom); return x; } } free(ndir); free(dom); return nil;} static char*tryfindfile(char *dom, char *user){ char *p; while(dom && *dom){ if(homeface && (p = tryfindfiledir(dom, user, homeface)) != nil) return p; if((p = tryfindfiledir(dom, user, "/lib/face")) != nil) return p; if((dom = strchr(dom, '.')) == nil) break; dom++; } return nil;} char*findfile(Face *f, char *dom, char *user){ char *p; if(facedom == nil){ facedom = getenv("facedom"); if(facedom == nil) facedom = DEFAULT; } if(dom == nil) dom = facedom; if(homeface == nil) homeface = smprint("%s/lib/face", getenv("home")); f->unknown = 0; if((p = tryfindfile(dom, user)) != nil) return p; f->unknown = 1; p = tryfindfile(dom, "unknown"); if(p != nil || strcmp(dom, facedom) == 0) return p; return tryfindfile("unknown", "unknown");} staticvoidclearsaved(void){ Facefile *f, *next, **lf; lf = &facefiles; for(f=facefiles; f!=nil; f=next){ next = f->next; if(f->ref > 0){ *lf = f; lf = &(f->next); continue; } if(f->image != display->black && f->image != display->white) freeimage(f->image); free(f->file); free(f); } *lf = nil; nsaved = 0;} voidfreefacefile(Facefile *f){ if(f==nil || f->ref-->1) return; if(++nsaved > Nsave) clearsaved();} static Image*myallocimage(ulong chan){ Image *img; img = allocimage(display, Rect(0,0,Facesize,Facesize), chan, 0, DNofill); if(img == nil){ clearsaved(); img = allocimage(display, Rect(0,0,Facesize,Facesize), chan, 0, DNofill); if(img == nil) return nil; } return img;} static Image*readbit(int fd, ulong chan){ char buf[4096], hx[4], *p; uchar data[Facesize*Facesize]; /* more than enough */ int nhx, i, n, ndata, nbit; Image *img; n = readn(fd, buf, sizeof buf); if(n <= 0) return nil; if(n >= sizeof buf) n = sizeof(buf)-1; buf[n] = '\0'; n = 0; nhx = 0; nbit = chantodepth(chan); ndata = (Facesize*Facesize*nbit)/8; p = buf; while(n < ndata) { p = strpbrk(p+1, "0123456789abcdefABCDEF"); if(p == nil) break; if(p[0] == '0' && p[1] == 'x') continue; hx[nhx] = *p; if(++nhx == 2) { hx[nhx] = 0; i = strtoul(hx, 0, 16); data[n++] = i; nhx = 0; } } if(n < ndata) return allocimage(display, Rect(0,0,Facesize,Facesize), CMAP8, 0, 0x88888888); img = myallocimage(chan); if(img == nil) return nil; loadimage(img, img->r, data, ndata); return img;} static Facefile*readface(char *fn){ int x, y, fd; uchar bits; uchar *p; Image *mask; Image *face; char buf[16]; uchar data[Facesize*Facesize]; uchar mdata[(Facesize*Facesize)/8]; Facefile *f; Dir *d; for(f=facefiles; f!=nil; f=f->next){ if(strcmp(fn, f->file) == 0){ if(f->image == nil) break; if(time(0) - f->rdtime >= 30) { if(dirmtime(fn) != f->mtime){ f = nil; break; } f->rdtime = time(0); } f->ref++; return f; } } if((fd = open(fn, OREAD)) < 0) return nil; if(readn(fd, buf, sizeof buf) != sizeof buf){ close(fd); return nil; } seek(fd, 0, 0); mask = nil; if(buf[0] == '0' && buf[1] == 'x'){ /* greyscale faces are just masks that we draw black through! */ if(buf[2+8] == ',') /* ldepth 1 */Lines 1–500 of 587. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h> #include <libc.h> #include <draw.h> #include <plumb.h> #include <regexp.h> #include <bio.h> #include "faces.h" enum /* number of deleted faces to cache */ { Nsave = 20, }; static Facefile *facefiles; static int nsaved; static char *facedom; static char *homeface; /* * Loading the files is slow enough on a dial-up line to be worth this trouble */ typedef struct Readcache Readcache; struct Readcache { char *file; char *data; long mtime; long rdtime; Readcache *next; }; static Readcache *rcache; ulong dirlen(char *s) { Dir *d; ulong len; d = dirstat(s); if(d == nil) return 0; len = d->length; free(d); return len; } ulong dirmtime(char *s) { Dir *d; ulong t; d = dirstat(s); if(d == nil) return 0; t = d->mtime; free(d); return t; } static char* doreadfile(char *s) { char *p; int fd, n; ulong len; len = dirlen(s); if(len == 0) return nil; p = malloc(len+1); if(p == nil) return nil; if((fd = open(s, OREAD)) < 0 || (n = readn(fd, p, len)) < 0) { close(fd); free(p); return nil; } p[n] = '\0'; return p; } static char* readfile(char *s) { Readcache *r, **l; char *p; ulong mtime; for(l=&rcache, r=*l; r; l=&r->next, r=*l) { if(strcmp(r->file, s) != 0) continue; /* * if it's less than 30 seconds since we read it, or it * hasn't changed, send back our copy */ if(time(0) - r->rdtime < 30) return strdup(r->data); if(dirmtime(s) == r->mtime) { r->rdtime = time(0); return strdup(r->data); } /* out of date, remove this and fall out of loop */ *l = r->next; free(r->file); free(r->data); free(r); break; } /* add to cache */ mtime = dirmtime(s); if(mtime == 0) return nil; if((p = doreadfile(s)) == nil) return nil; r = malloc(sizeof(*r)); if(r == nil) return nil; r->mtime = mtime; r->file = estrdup(s); r->data = p; r->rdtime = time(0); r->next = rcache; rcache = r; return strdup(r->data); } static char* translatedomain(char *dom, char *list) { static char buf[200]; char *p, *ep, *q, *nextp, *file; char *bbuf, *ebuf; Reprog *exp; if(dom == nil || *dom == 0) return nil; if(list == nil || (file = readfile(list)) == nil) return dom; for(p=file; p; p=nextp) { if(nextp = strchr(p, '\n')) *nextp++ = '\0'; if(*p == '#' || (q = strpbrk(p, " \t")) == nil || q-p > sizeof(buf)-2) continue; bbuf = buf+1; ebuf = buf+(1+(q-p)); strncpy(bbuf, p, ebuf-bbuf); *ebuf = 0; if(*bbuf != '^') *--bbuf = '^'; if(ebuf[-1] != '$') { *ebuf++ = '$'; *ebuf = 0; } if((exp = regcomp(bbuf)) == nil){ fprint(2, "bad regexp in machinelist: %s\n", bbuf); killall("regexp"); } if(regexec(exp, dom, 0, 0)){ free(exp); ep = p+strlen(p); q += strspn(q, " \t"); if(ep-q+2 > sizeof buf) { fprint(2, "huge replacement in machinelist: %.*s\n", utfnlen(q, ep-q), q); exits("bad big replacement"); } strncpy(buf, q, ep-q); ebuf = buf+(ep-q); *ebuf = 0; while(ebuf > buf && (ebuf[-1] == ' ' || ebuf[-1] == '\t')) *--ebuf = 0; free(file); return buf; } free(exp); } free(file); return dom; } static char* tryfindpicture(char *dom, char *user, char *dir, char *dict) { static char buf[1024]; char *file, *p, *nextp, *q; if((file = readfile(dict)) == nil) return nil; snprint(buf, sizeof buf, "%s/%s", dom, user); for(p=file; p; p=nextp){ if(nextp = strchr(p, '\n')) *nextp++ = '\0'; if(*p == '#' || (q = strpbrk(p, " \t")) == nil) continue; *q++ = 0; if(strcmp(buf, p) == 0){ q += strspn(q, " \t"); snprint(buf, sizeof buf, "%s/%s", dir, q); q = buf+strlen(buf); while(q > buf && (q[-1] == ' ' || q[-1] == '\t')) *--q = 0; free(file); return estrdup(buf); } } free(file); return nil; } static char* estrstrdup(char *a, char *b) { char *t; t = emalloc(strlen(a)+strlen(b)+1); strcpy(t, a); strcat(t, b); return t; } static char* tryfindfiledir(char *dom, char *user, char *dir) { char *dict, *ndir, *x; int fd; int i, n; Dir *d; /* * If this directory has a .machinelist, use it. */ x = estrstrdup(dir, "/.machinelist"); dom = estrdup(translatedomain(dom, x)); free(x); /* * If this directory has a .dict, use it. */ dict = estrstrdup(dir, "/.dict"); if(access(dict, AEXIST) >= 0){ x = tryfindpicture(dom, user, dir, dict); free(dict); free(dom); return x; } free(dict); /* * If not, recurse into subdirectories. * Ignore 512x512 directories. * Save 48x48 directories for later. */ if((fd = open(dir, OREAD)) < 0) return nil; while((n = dirread(fd, &d)) > 0){ for(i=0; i<n; i++){ if((d[i].mode&DMDIR) && strncmp(d[i].name, "512x", 4) != 0 && strncmp(d[i].name, "48x48x", 6) != 0){ ndir = emalloc(strlen(dir)+1+strlen(d[i].name)+1); strcpy(ndir, dir); strcat(ndir, "/"); strcat(ndir, d[i].name); if((x = tryfindfiledir(dom, user, ndir)) != nil){ free(ndir); free(d); close(fd); free(dom); return x; } } } free(d); } close(fd); /* * Handle 48x48 directories in the right order. */ ndir = estrstrdup(dir, "/48x48x8"); for(i=8; i>0; i>>=1){ ndir[strlen(ndir)-1] = i+'0'; if(access(ndir, AEXIST) >= 0 && (x = tryfindfiledir(dom, user, ndir)) != nil){ free(ndir); free(dom); return x; } } free(ndir); free(dom); return nil; } static char* tryfindfile(char *dom, char *user) { char *p; while(dom && *dom){ if(homeface && (p = tryfindfiledir(dom, user, homeface)) != nil) return p; if((p = tryfindfiledir(dom, user, "/lib/face")) != nil) return p; if((dom = strchr(dom, '.')) == nil) break; dom++; } return nil; } char* findfile(Face *f, char *dom, char *user) { char *p; if(facedom == nil){ facedom = getenv("facedom"); if(facedom == nil) facedom = DEFAULT; } if(dom == nil) dom = facedom; if(homeface == nil) homeface = smprint("%s/lib/face", getenv("home")); f->unknown = 0; if((p = tryfindfile(dom, user)) != nil) return p; f->unknown = 1; p = tryfindfile(dom, "unknown"); if(p != nil || strcmp(dom, facedom) == 0) return p; return tryfindfile("unknown", "unknown"); } static void clearsaved(void) { Facefile *f, *next, **lf; lf = &facefiles; for(f=facefiles; f!=nil; f=next){ next = f->next; if(f->ref > 0){ *lf = f; lf = &(f->next); continue; } if(f->image != display->black && f->image != display->white) freeimage(f->image); free(f->file); free(f); } *lf = nil; nsaved = 0; } void freefacefile(Facefile *f) { if(f==nil || f->ref-->1) return; if(++nsaved > Nsave) clearsaved(); } static Image* myallocimage(ulong chan) { Image *img; img = allocimage(display, Rect(0,0,Facesize,Facesize), chan, 0, DNofill); if(img == nil){ clearsaved(); img = allocimage(display, Rect(0,0,Facesize,Facesize), chan, 0, DNofill); if(img == nil) return nil; } return img; } static Image* readbit(int fd, ulong chan) { char buf[4096], hx[4], *p; uchar data[Facesize*Facesize]; /* more than enough */ int nhx, i, n, ndata, nbit; Image *img; n = readn(fd, buf, sizeof buf); if(n <= 0) return nil; if(n >= sizeof buf) n = sizeof(buf)-1; buf[n] = '\0'; n = 0; nhx = 0; nbit = chantodepth(chan); ndata = (Facesize*Facesize*nbit)/8; p = buf; while(n < ndata) { p = strpbrk(p+1, "0123456789abcdefABCDEF"); if(p == nil) break; if(p[0] == '0' && p[1] == 'x') continue; hx[nhx] = *p; if(++nhx == 2) { hx[nhx] = 0; i = strtoul(hx, 0, 16); data[n++] = i; nhx = 0; } } if(n < ndata) return allocimage(display, Rect(0,0,Facesize,Facesize), CMAP8, 0, 0x88888888); img = myallocimage(chan); if(img == nil) return nil; loadimage(img, img->r, data, ndata); return img; } static Facefile* readface(char *fn) { int x, y, fd; uchar bits; uchar *p; Image *mask; Image *face; char buf[16]; uchar data[Facesize*Facesize]; uchar mdata[(Facesize*Facesize)/8]; Facefile *f; Dir *d; for(f=facefiles; f!=nil; f=f->next){ if(strcmp(fn, f->file) == 0){ if(f->image == nil) break; if(time(0) - f->rdtime >= 30) { if(dirmtime(fn) != f->mtime){ f = nil; break; } f->rdtime = time(0); } f->ref++; return f; } } if((fd = open(fn, OREAD)) < 0) return nil; if(readn(fd, buf, sizeof buf) != sizeof buf){ close(fd); return nil; } seek(fd, 0, 0); mask = nil; if(buf[0] == '0' && buf[1] == 'x'){ /* greyscale faces are just masks that we draw black through! */ if(buf[2+8] == ',') /* ldepth 1 */