364 lines · 5.6 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <ctype.h> #define	WHITESPACE(c)		((c) == ' ' || (c) == '\t' || (c) == '\n')#define	SPACE(c)			((c) == ' ' || (c) == '\t') int fflag; enum {	P9BITLEN 	= 12,}; typedef struct {	char	*b;	char	*file;	char	*slash;	Dir	*d;} Slurp; intslurp(char* fil, int fd, int (*f)(Slurp*)){	Slurp S;	int n;	vlong l; 	memset(&S, 0, sizeof S);	S.d = dirfstat(fd);	if(!S.d)		return 0;	l = S.d->length;	S.b = malloc(S.d->length+1);	if(!S.b)		sysfatal("malloc");	seek(fd, 0, 0);	if(readn(fd, S.b, l) != l){		n = 0;		goto done;	}	S.b[l] = 0;	S.file = fil;	S.slash = strrchr(S.file, '/'); 	n = f(&S);done:	free(S.d);	free(S.b);	return n;} /* * pick up a number with * syntax _*[0-9]+_ */intp9bitnum(char *bp){	int n, c, len; 	len = P9BITLEN;	while(*bp == ' ') {		bp++;		len--;		if(len <= 0)			return -1;	}	n = 0;	while(len > 1) {		c = *bp++;		if(!isdigit(c))			return -1;		n = n*10 + c-'0';		len--;	}	if(*bp != ' ')		return -1;	return n;} intdepthof(char *s, int *newp){	char *es;	int d; 	*newp = 0;	es = s+12;	while(s<es && *s==' ')		s++;	if(s == es)		return -1;	if('0'<=*s && *s<='9')		return 1<<strtol(s, 0, 0); 	*newp = 1;	d = 0;	while(s<es && *s!=' '){		s++;	/* skip letter */		d += strtoul(s, &s, 10);	}		switch(d){	case 32:	case 24:	case 16:	case 8:	case 4:	case 2:	case 1:		return d;	}	return -1;} intp9subfont(char *p){	int n, h, a; 	n = p9bitnum(p + 0*P9BITLEN);	/* char count */	if (n < 0)		return 0;	h = p9bitnum(p + 1*P9BITLEN);	/* height */	if (h < 0)		return 0;	a = p9bitnum(p + 2*P9BITLEN);	/* ascent */	if (a < 0)		return 0;	return 1;} intcfontlen(char* buf, char* bufe, int, int, int loy, int, int hiy){	int miny, maxy, nb;	char *p; 	p = buf+5*P9BITLEN;	for(miny = loy; p+24 <= bufe && miny != hiy; p += 24+nb){		maxy = atoi(p+0*P9BITLEN);		nb = atoi(p+1*P9BITLEN);		if(maxy<=loy || hiy<maxy){			werrstr("cimage: bady");			return -1;		}		miny = maxy;	}	if(miny == hiy)		return p-buf;	werrstr("cimage: short file");	return -1;} intfontlen(char*, char*, int dep, int lox, int loy, int hix, int hiy){	int px, t, len; 	if(dep < 8){		px = 8/dep;	/* pixels per byte */		/* set l to number of bytes of data per scan line */		if(lox >= 0)			len = (hix+px-1)/px - lox/px;		else{	/* make positive before divide */			t = (-lox)+px-1;			t = (t/px)*px;			len = (t+hix+px-1)/px;		}	}else		len = (hix-lox)*dep/8;	return len*(hiy-loy) + 5*P9BITLEN;} intisp9bit(Slurp* S){	int dep, lox, loy, hix, hiy, new;	long len;	char *buf, *bufe;	int (*lenfn)(char*, char*, int, int, int, int, int); 	buf = S->b;	lenfn = fontlen;	if(strncmp(buf, "compressed\n", 11) == 0){		lenfn = cfontlen;		buf += 11;	}	bufe = S->b+S->d->length;	if(bufe - buf < 5*P9BITLEN){		werrstr("image: short file");		return 0;	}	dep = depthof(buf + 0*P9BITLEN, &new);	lox = p9bitnum(buf + 1*P9BITLEN);	loy = p9bitnum(buf + 2*P9BITLEN);	hix = p9bitnum(buf + 3*P9BITLEN);	hiy = p9bitnum(buf + 4*P9BITLEN);	if(dep < 0 || lox < 0 || loy < 0 || hix < 0 || hiy < 0){		werrstr("image: bad rectangle");		return 0;	}	if(lox>hix|| loy>hiy){		werrstr("image: bad rectangle");		return 0;	}	len = lenfn(buf, bufe, dep, lox, loy, hix, hiy);	if(len < 0){		werrstr("image: bady");		return 0;	}	if(S->d->length < len+3*P9BITLEN) {		werrstr("image: no font info");		return 0;	}	if (p9subfont(buf+len))		return 1;	werrstr("image: bad font info");	return 0;} intgetfontnum(char *cp, char **rp){	char *p;	ulong l; 	*rp = cp;	l = strtoul(cp, &p, 0);	if(p == cp || !WHITESPACE(*p))		return 0;	if(l > Runemax)		return 0;	*rp = p;	return 1;} intfchk(char *p, int m){	int fd, r; 	fd = open(p, m);	if(-1 == fd)		return -1;	if(fflag)		r = 0;	else		r = slurp(p, fd, isp9bit);	close(fd);	return r;} intfaccess(char *p, int m){	char* s;	int i, r, err; 	r = fchk(p, m);	if(r != -1)		return r;	s = p + strlen(p);	r = 0;	for(i = 0; i < 2; i++) {		snprint(s, 4, ".%d", i);		err = fchk(p, m);		*s = 0;		if(r != -1)			r = err;	}	return r;}	intisp9font(Slurp *S){	char *p, *cp;	int i, n, err;	char path[1024 + 1 + 3]; 	cp = S->b;	if (!getfontnum(cp, &cp)){	/* height */		fprint(2, "%s:1 height\n", S->file);		return 0;	}	if (!getfontnum(cp, &cp)){	/* ascent */		fprint(2, "%s:1 ascent\n", S->file);		return 0;	}	while(WHITESPACE(*cp))		cp++;	for (err = 0, i = 0; strchr(cp, '\n'); i++) {		if (!getfontnum(cp, &cp)){	/* min */			fprint(2, "%s:%d ascent\n", S->file, i+1);			return 0;		}		if (!getfontnum(cp, &cp)){	/* max */			fprint(2, "%s:%d ascent\n", S->file, i+1);			return 0;		}		getfontnum(cp, &cp);	/* offset -- not required */		while(SPACE(*cp))			cp++;		for(p = cp; !WHITESPACE(*cp); cp++)			;			/* construct a path name, if needed */		n = 0;		if (*p != '/' && S->slash) {			n = S->slash-S->file+1;			if (n < sizeof path)				memcpy(path, S->file, n);			else n = 0;		}		if (n+cp-p < sizeof path - sizeof ".00") {			memcpy(path+n, p, cp-p);			n += cp-p;			path[n] = 0;			if(faccess(path, AEXIST) < 0){				fprint(2, "%s:%d (%s) %r\n", S->file, i+1, path);				err++;			}		}		while(WHITESPACE(*cp))			cp++;	}	if(err)		return 0;	return i;} voidmain(int argc, char **argv){	int fd, err, n; 	ARGBEGIN{	case 'f':		fflag = 1;		break;	default:		fprint(2, "usage: chkfont [-f] font\n");		exits("usage");	}ARGEND 	err = 0;	if(argc>0)		for(; *argv; argv++){			fd = open(*argv, OREAD);			n = -1;			if(-1 == fd)				fprint(2, "%s: %r\n", *argv);			else				n = slurp(*argv, fd, isp9font);			close(fd);			if(n < 1)				err++;		}	else		err = slurp("<stdin>", 0, isp9font);	if(err)		exits("bad");	exits("");}