⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 facedb.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#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 */			mask = readbit(fd, GREY2);		else			mask = readbit(fd, GREY1);		face = display->black;	}else{		face = readimage(display, fd, 0);		if(face == nil)			goto Done;		else if(face->chan == GREY4 || face->chan == GREY8){	/* greyscale: use inversion as mask */			mask = myallocimage(face->chan);			/* okay if mask is nil: that will copy the image white background and all */			if(mask == nil)				goto Done;			/* invert greyscale image */			draw(mask, mask->r, display->white, nil, ZP);			gendraw(mask, mask->r, display->black, ZP, face, face->r.min);			freeimage(face);			face = display->black;		}else if(face->depth == 8){	/* snarf the bytes back and do a fill. */			mask = myallocimage(GREY1);			if(mask == nil)				goto Done;			if(unloadimage(face, face->r, data, Facesize*Facesize) != Facesize*Facesize){					freeimage(mask);				goto Done;			}			bits = 0;			p = mdata;			for(y=0; y<Facesize; y++){				for(x=0; x<Facesize; x++){						bits <<= 1;					if(data[Facesize*y+x] != 0xFF)						bits |= 1;					if((x&7) == 7)						*p++ = bits&0xFF;				}			}			if(loadimage(mask, mask->r, mdata, sizeof mdata) != sizeof mdata){				freeimage(mask);				goto Done;			}		}	}Done:	/* always add at beginning of list, so updated files don't collide in cache */	if(f == nil){		f = emalloc(sizeof(Facefile));		f->file = estrdup(fn);		d = dirfstat(fd);		if(d != nil){			f->mtime = d->mtime;			free(d);		}		f->next = facefiles;		facefiles = f;	}	f->ref++;	f->image = face;	f->mask = mask;	f->rdtime = time(0);	close(fd);	return f;}voidfindbit(Face *f){	char *fn;	fn = findfile(f, f->str[Sdomain], f->str[Suser]);	if(fn) {		if(strstr(fn, "unknown"))			f->unknown = 1;		f->file = readface(fn);	}	if(f->file){		f->bit = f->file->image;		f->mask = f->file->mask;	}else{		/* if returns nil, this is still ok: draw(nil) works */		f->bit = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DYellow);		replclipr(f->bit, 1, Rect(0, 0, Facesize, Facesize));		f->mask = nil;	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -