10 enum /* number of deleted faces to cache */
15 static Facefile *facefiles;
19 static char *homeface;
22 * Loading the files is slow enough on a dial-up line to be worth this trouble
24 typedef struct Readcache Readcache;
33 static Readcache *rcache;
50 fsdirlen(CFsys *fs,char *s)
92 if((fd = open(s, OREAD)) < 0
93 || (n = readn(fd, p, len)) < 0) {
110 for(l=&rcache, r=*l; r; l=&r->next, r=*l) {
111 if(strcmp(r->file, s) != 0)
115 * if it's less than 30 seconds since we read it, or it
116 * hasn't changed, send back our copy
118 if(time(0) - r->rdtime < 30)
119 return strdup(r->data);
120 if(dirmtime(s) == r->mtime) {
122 return strdup(r->data);
125 /* out of date, remove this and fall out of loop */
138 if((p = doreadfile(s)) == nil)
141 r = malloc(sizeof(*r));
145 r->file = estrdup(s);
150 return strdup(r->data);
154 translatedomain(char *dom, char *list)
156 static char buf[200];
157 char *p, *ep, *q, *nextp, *file;
161 if(dom == nil || *dom == 0)
164 if(list == nil || (file = readfile(list)) == nil)
167 for(p=file; p; p=nextp) {
168 if(nextp = strchr(p, '\n'))
171 if(*p == '#' || (q = strpbrk(p, " \t")) == nil || q-p > sizeof(buf)-2)
175 ebuf = buf+(1+(q-p));
176 strncpy(bbuf, p, ebuf-bbuf);
180 if(ebuf[-1] != '$') {
185 if((exp = regcomp(bbuf)) == nil){
186 fprint(2, "bad regexp in machinelist: %s\n", bbuf);
190 if(regexec(exp, dom, 0, 0)){
193 q += strspn(q, " \t");
194 if(ep-q+2 > sizeof buf) {
195 fprint(2, "huge replacement in machinelist: %.*s\n", utfnlen(q, ep-q), q);
196 exits("bad big replacement");
198 strncpy(buf, q, ep-q);
201 while(ebuf > buf && (ebuf[-1] == ' ' || ebuf[-1] == '\t'))
214 tryfindpicture(char *dom, char *user, char *dir, char *dict)
216 static char buf[1024];
217 char *file, *p, *nextp, *q;
219 if((file = readfile(dict)) == nil)
222 snprint(buf, sizeof buf, "%s/%s", dom, user);
224 for(p=file; p; p=nextp){
225 if(nextp = strchr(p, '\n'))
228 if(*p == '#' || (q = strpbrk(p, " \t")) == nil)
232 if(strcmp(buf, p) == 0){
233 q += strspn(q, " \t");
234 snprint(buf, sizeof buf, "%s/%s", dir, q);
236 while(q > buf && (q[-1] == ' ' || q[-1] == '\t'))
247 estrstrdup(char *a, char *b)
251 t = emalloc(strlen(a)+strlen(b)+1);
258 tryfindfiledir(char *dom, char *user, char *dir)
260 char *dict, *ndir, *x, *odom;
266 * If this directory has a .machinelist, use it.
268 x = estrstrdup(dir, "/.machinelist");
269 dom = estrdup(translatedomain(dom, x));
272 * If this directory has a .dict, use it.
274 dict = estrstrdup(dir, "/.dict");
275 if(access(dict, AEXIST) >= 0){
276 x = tryfindpicture(dom, user, dir, dict);
284 * If not, recurse into subdirectories.
285 * Ignore 48x48xN directories for now.
287 if((fd = open(dir, OREAD)) < 0)
289 while((n = dirread(fd, &d)) > 0){
291 if((d[i].mode&DMDIR)&& strncmp(d[i].name, "48x48x", 6) != 0){
292 ndir = emalloc(strlen(dir)+1+strlen(d[i].name)+1);
295 strcat(ndir, d[i].name);
296 if((x = tryfindfiledir(dom, user, ndir)) != nil){
310 * Handle 48x48xN directories in the right order.
312 ndir = estrstrdup(dir, "/48x48x8");
313 for(i=8; i>0; i>>=1){
314 ndir[strlen(ndir)-1] = i+'0';
315 if(access(ndir, AEXIST) >= 0 && (x = tryfindfiledir(dom, user, ndir)) != nil){
327 tryfindfile(char *dom, char *user)
332 if(homeface && (p = tryfindfiledir(dom, user, homeface)) != nil)
334 if((p = tryfindfiledir(dom, user, libface)) != nil)
336 if((dom = strchr(dom, '.')) == nil)
344 findfile(Face *f, char *dom, char *user)
349 facedom = getenv("facedom");
354 libface = unsharp("#9/face");
356 homeface = smprint("%s/lib/face", getenv("HOME"));
362 if((p = tryfindfile(dom, user)) != nil)
365 p = tryfindfile(dom, "unknown");
366 if(p != nil || strcmp(dom, facedom) == 0)
368 return tryfindfile("unknown", "unknown");
375 Facefile *f, *next, **lf;
378 for(f=facefiles; f!=nil; f=next){
385 if(f->image != display->black && f->image != display->white)
395 freefacefile(Facefile *f)
397 if(f==nil || f->ref-->1)
404 myallocimage(ulong chan)
407 img = allocimage(display, Rect(0,0,Facesize,Facesize), chan, 0, DNofill);
410 img = allocimage(display, Rect(0,0,Facesize,Facesize), chan, 0, DNofill);
419 readbit(int fd, ulong chan)
421 char buf[4096], hx[4], *p;
422 uchar data[Facesize*Facesize]; /* more than enough */
423 int nhx, i, n, ndata, nbit;
426 n = readn(fd, buf, sizeof buf);
435 nbit = chantodepth(chan);
436 ndata = (Facesize*Facesize*nbit)/8;
439 p = strpbrk(p+1, "0123456789abcdefABCDEF");
442 if(p[0] == '0' && p[1] == 'x')
448 i = strtoul(hx, 0, 16);
454 return allocimage(display, Rect(0,0,Facesize,Facesize), CMAP8, 0, 0x88888888);
456 img = myallocimage(chan);
459 loadimage(img, img->r, data, ndata);
472 uchar data[Facesize*Facesize];
473 uchar mdata[(Facesize*Facesize)/8];
477 for(f=facefiles; f!=nil; f=f->next){
478 if(strcmp(fn, f->file) == 0){
481 if(time(0) - f->rdtime >= 30) {
482 if(dirmtime(fn) != f->mtime){
493 if((fd = open(fn, OREAD)) < 0)
496 if(readn(fd, buf, sizeof buf) != sizeof buf){
504 if(buf[0] == '0' && buf[1] == 'x'){
505 /* greyscale faces are just masks that we draw black through! */
506 if(buf[2+8] == ',') /* ldepth 1 */
507 mask = readbit(fd, GREY2);
509 mask = readbit(fd, GREY1);
510 face = display->black;
512 face = readimage(display, fd, 0);
515 else if(face->chan == GREY4 || face->chan == GREY8){ /* greyscale: use inversion as mask */
516 mask = myallocimage(face->chan);
517 /* okay if mask is nil: that will copy the image white background and all */
521 /* invert greyscale image */
522 draw(mask, mask->r, display->white, nil, ZP);
523 gendraw(mask, mask->r, display->black, ZP, face, face->r.min);
525 face = display->black;
526 }else if(face->depth == 8){ /* snarf the bytes back and do a fill. */
527 mask = myallocimage(GREY1);
530 if(unloadimage(face, face->r, data, Facesize*Facesize) != Facesize*Facesize){
536 for(y=0; y<Facesize; y++){
537 for(x=0; x<Facesize; x++){
539 if(data[Facesize*y+x] != 0xFF)
545 if(loadimage(mask, mask->r, mdata, sizeof mdata) != sizeof mdata){
553 /* always add at beginning of list, so updated files don't collide in cache */
555 f = emalloc(sizeof(Facefile));
556 f->file = estrdup(fn);
578 fn = findfile(f, f->str[Sdomain], f->str[Suser]);
580 if(strstr(fn, "unknown"))
582 f->file = readface(fn);
585 f->bit = f->file->image;
586 f->mask = f->file->mask;
588 /* if returns nil, this is still ok: draw(nil) works */
589 f->bit = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DYellow);
590 replclipr(f->bit, 1, Rect(0, 0, Facesize, Facesize));