10 enum /* number of deleted faces to cache */
15 static Facefile *facefiles;
20 * Loading the files is slow enough on a dial-up line to be worth this trouble
22 typedef struct Readcache Readcache;
31 static Readcache *rcache;
48 fsdirlen(CFsys *fs,char *s)
90 if((fd = open(s, OREAD)) < 0
91 || (n = readn(fd, p, len)) < 0) {
108 for(l=&rcache, r=*l; r; l=&r->next, r=*l) {
109 if(strcmp(r->file, s) != 0)
113 * if it's less than 30 seconds since we read it, or it
114 * hasn't changed, send back our copy
116 if(time(0) - r->rdtime < 30)
117 return strdup(r->data);
118 if(dirmtime(s) == r->mtime) {
120 return strdup(r->data);
123 /* out of date, remove this and fall out of loop */
136 if((p = doreadfile(s)) == nil)
139 r = malloc(sizeof(*r));
143 r->file = estrdup(s);
148 return strdup(r->data);
153 translatedomain(char *dom)
155 static char buf[200];
156 char *p, *ep, *q, *nextp, *file;
160 if(dom == nil || *dom == 0)
163 if((file = readfile(unsharp("#9/face/.machinelist"))) == nil)
166 for(p=file; p; p=nextp) {
167 if(nextp = strchr(p, '\n'))
170 if(*p == '#' || (q = strpbrk(p, " \t")) == nil || q-p > sizeof(buf)-2)
174 ebuf = buf+(1+(q-p));
175 strncpy(bbuf, p, ebuf-bbuf);
179 if(ebuf[-1] != '$') {
184 if((exp = regcomp(bbuf)) == nil){
185 fprint(2, "bad regexp in machinelist: %s\n", bbuf);
189 if(regexec(exp, dom, 0, 0)){
192 q += strspn(q, " \t");
193 if(ep-q+2 > sizeof buf) {
194 fprint(2, "huge replacement in machinelist: %.*s\n", utfnlen(q, ep-q), q);
195 exits("bad big replacement");
197 strncpy(buf, q, ep-q);
200 while(ebuf > buf && (ebuf[-1] == ' ' || ebuf[-1] == '\t'))
213 tryfindpicture_user(char *dom, char *user, int depth)
215 static char buf[200];
216 char *p, *q, *nextp, *file;
220 home = getenv("home");
222 home = getenv("HOME");
226 sprint(buf, "%s/lib/face/48x48x%d/.dict", home, depth);
227 if((file = readfile(buf)) == nil)
230 snprint(buf, sizeof buf, "%s/%s", dom, user);
232 for(p=file; p; p=nextp) {
233 if(nextp = strchr(p, '\n'))
236 if(*p == '#' || (q = strpbrk(p, " \t")) == nil)
240 if(strcmp(buf, p) == 0) {
241 q += strspn(q, " \t");
242 q = buf+snprint(buf, sizeof buf, "%s/lib/face/48x48x%d/%s", home, depth, q);
243 while(q > buf && (q[-1] == ' ' || q[-1] == '\t'))
254 tryfindpicture_global(char *dom, char *user, int depth)
256 static char buf[200];
257 char *p, *q, *nextp, *file;
259 sprint(buf, "#9/face/48x48x%d/.dict", depth);
260 if((file = readfile(unsharp(buf))) == nil)
263 snprint(buf, sizeof buf, "%s/%s", dom, user);
265 for(p=file; p; p=nextp) {
266 if(nextp = strchr(p, '\n'))
269 if(*p == '#' || (q = strpbrk(p, " \t")) == nil)
273 if(strcmp(buf, p) == 0) {
274 q += strspn(q, " \t");
275 q = buf+snprint(buf, sizeof buf, "#9/face/48x48x%d/%s", depth, q);
276 while(q > buf && (q[-1] == ' ' || q[-1] == '\t'))
287 tryfindpicture(char *dom, char *user, int depth)
291 if((result = tryfindpicture_user(dom, user, depth)) != nil)
294 return tryfindpicture_global(dom, user, depth);
298 tryfindfile(char *dom, char *user, int depth)
303 for(p=dom; p; (p=strchr(p, '.')) && p++)
304 if(q = tryfindpicture(p, user, depth))
314 findfile(Face *f, char *dom, char *user)
320 facedom = getenv("facedom");
325 dom = translatedomain(dom);
332 depth = screen->depth;
338 if(p = tryfindfile(dom, user, depth))
341 p = tryfindfile(dom, "unknown", depth);
342 if(p != nil || strcmp(dom, facedom)==0)
344 return tryfindfile("unknown", "unknown", depth);
351 Facefile *f, *next, **lf;
354 for(f=facefiles; f!=nil; f=next){
361 if(f->image != display->black && f->image != display->white)
371 freefacefile(Facefile *f)
373 if(f==nil || f->ref-->1)
380 myallocimage(ulong chan)
383 img = allocimage(display, Rect(0,0,Facesize,Facesize), chan, 0, DNofill);
386 img = allocimage(display, Rect(0,0,Facesize,Facesize), chan, 0, DNofill);
395 readbit(int fd, ulong chan)
397 char buf[4096], hx[4], *p;
398 uchar data[Facesize*Facesize]; /* more than enough */
399 int nhx, i, n, ndata, nbit;
402 n = readn(fd, buf, sizeof buf);
411 nbit = chantodepth(chan);
412 ndata = (Facesize*Facesize*nbit)/8;
415 p = strpbrk(p+1, "0123456789abcdefABCDEF");
418 if(p[0] == '0' && p[1] == 'x')
424 i = strtoul(hx, 0, 16);
430 return allocimage(display, Rect(0,0,Facesize,Facesize), CMAP8, 0, 0x88888888);
432 img = myallocimage(chan);
435 loadimage(img, img->r, data, ndata);
448 uchar data[Facesize*Facesize];
449 uchar mdata[(Facesize*Facesize)/8];
453 for(f=facefiles; f!=nil; f=f->next){
454 if(strcmp(fn, f->file) == 0){
457 if(time(0) - f->rdtime >= 30) {
458 if(dirmtime(fn) != f->mtime){
469 if((fd = open(fn, OREAD)) < 0)
472 if(readn(fd, buf, sizeof buf) != sizeof buf){
480 if(buf[0] == '0' && buf[1] == 'x'){
481 /* greyscale faces are just masks that we draw black through! */
482 if(buf[2+8] == ',') /* ldepth 1 */
483 mask = readbit(fd, GREY2);
485 mask = readbit(fd, GREY1);
486 face = display->black;
488 face = readimage(display, fd, 0);
491 else if(face->chan == GREY4 || face->chan == GREY8){ /* greyscale: use inversion as mask */
492 mask = myallocimage(face->chan);
493 /* okay if mask is nil: that will copy the image white background and all */
497 /* invert greyscale image */
498 draw(mask, mask->r, display->white, nil, ZP);
499 gendraw(mask, mask->r, display->black, ZP, face, face->r.min);
501 face = display->black;
502 }else if(face->depth == 8){ /* snarf the bytes back and do a fill. */
503 mask = myallocimage(GREY1);
506 if(unloadimage(face, face->r, data, Facesize*Facesize) != Facesize*Facesize){
512 for(y=0; y<Facesize; y++){
513 for(x=0; x<Facesize; x++){
515 if(data[Facesize*y+x] != 0xFF)
521 if(loadimage(mask, mask->r, mdata, sizeof mdata) != sizeof mdata){
529 /* always add at beginning of list, so updated files don't collide in cache */
531 f = emalloc(sizeof(Facefile));
532 f->file = estrdup(fn);
554 fn = findfile(f, f->str[Sdomain], f->str[Suser]);
556 if(strstr(fn, "unknown"))
558 f->file = readface(fn);
561 f->bit = f->file->image;
562 f->mask = f->file->mask;
564 /* if returns nil, this is still ok: draw(nil) works */
565 f->bit = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DYellow);
566 replclipr(f->bit, 1, Rect(0, 0, Facesize, Facesize));