~aleteoryx/9c

eff663502098cb6d657e23577997bea7cef00a3e — glenda 11 days ago ebf35e0
use memdraw properly, checkmapfile
1 files changed, 273 insertions(+), 140 deletions(-)

M ufx2font.c
M ufx2font.c => ufx2font.c +273 -140
@@ 1,6 1,8 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include <memdraw.h>


/* entry has 1 byte in widtab + 8 bytes per tile */


@@ 18,6 20,8 @@ enum{
struct MapRule{
	struct MapRule *next;

	uint linum;

	uchar ty;
	uint start, end;
};


@@ 43,10 47,9 @@ struct GlyphInfo{
	uchar top, bottom, left, width;
};


struct RawImage{
	char chan[12], minx[12], miny[12], maxx[12], maxy[12];
	uchar data[];
struct RawSubfont{
	char n[12], height[12], ascent[12];
	uchar entries[][6];
};




@@ 58,7 61,7 @@ struct MapFile *mapfiles, *lastmf;
uchar wasmferr, wasreaderr;

struct GlyphInfo *glyphs;
struct RawImage *glyphbuf;
Memimage *glyphimg;


void


@@ 73,6 76,12 @@ readtoken(Biobuf *b, char **line, uint *linum)
{
	char *ret, *p;

	if(b->aux != nil){
		ret = b->aux;
		b->aux = nil;
		return ret;
	}

	while(*line != nil){
		p = *line;
		while(p[0] != '\0' && strchr("\t\r ", p[0]) != nil)


@@ 98,6 107,11 @@ readtoken(Biobuf *b, char **line, uint *linum)

	return nil;
}
void
unreadtoken(Biobuf *b, char *tok)
{
	b->aux = tok;
}
#pragma varargck argpos mferr 3
void
mferr(char *file, uint linum, char *fmt, ...)


@@ 115,13 129,150 @@ mferr(char *file, uint linum, char *fmt, ...)

	wasmferr = 1;
}
struct MapRule *
parsemaprule(char *file, Biobuf *b, char **line, uint *linum)
{
	struct MapRule *ret;
	char *tok, *p;

	tok = readtoken(b, line, linum);
	if(tok == nil)
		return nil;

	ret = malloc(sizeof(struct MapRule));
	ret->next = nil;
	ret->linum = *linum;

	if(strcmp(tok, "blank") == 0){
		ret->ty = MR_BLANK;
		return ret;
	}else if(tok[0] == '-'){	/* e.g. -0x4f */
		tok++;
		ret->ty = MR_RANGE;
		ret->start = 0;
		ret->end = strtoul(tok, &p, 0);
		if(tok == p || p[0] != '\0'){
			mferr(file, *linum, "bad upper glyph bound");
			free(ret);
			return nil;
		}
		return ret;
	}


	ret->start = strtoul(tok, &p, 0);
	if(tok == p){
		unreadtoken(b, tok);
		free(ret);
		return nil;
	}else if(p[0] == '\0'){
		ret->ty = MR_SINGLE;
		return ret;
	}else if(p[0] != '-'){
		mferr(file, *linum, "bad lower glyph bound");
		free(ret);
		return nil;
	}


	ret->ty = MR_RANGE;

	tok = p+1;
	if(tok[0] == '\0'){	/* e.g. 0x80- */
		ret->end = nglyphs - 1;
		return ret;
	}
	ret->end = strtoul(tok, &p, 0);
	if(tok == p || p[0] != '\0'){
		mferr(file, *linum, "bad upper glyph bound");
		free(ret);
		return nil;
	}

	return ret;
}
struct Mapping *
parsemapping(char *file, Biobuf *b, char **line, uint *linum)
{
	struct Mapping *ret;
	struct MapRule *rlast = nil, *r;
	char *tok, *p;

	tok = readtoken(b, line, linum);
	if(tok == nil){
		mferr(file, *linum, "unexpected eof");
		return nil;
	}

	ret = malloc(sizeof(struct Mapping));
	ret->linum = *linum;
	ret->rules = nil;
	ret->next = nil;

	ret->start = strtoul(tok, &p, 0);
	if(tok == p){
		mferr(file, *linum, "empty lower rune bound");
		free(ret);
		return nil;
	}
	tok = p;

	if(tok[0] == '\0'){	/* 1:1 mapping */
		tok = readtoken(b, line, linum);
		if(tok == nil){
			mferr(file, *linum, "unexpected eof");
			free(ret);
			return nil;
		}
		ret->idx = strtoul(tok, &p, 0);
		
		if(tok == p || p[0] != '\0'){
			mferr(file, *linum, "bad glyph index");
			free(ret);
			return nil;
		}

		return ret;
	}else if(tok[0] != '-'){
		mferr(file, *linum, "bad rune range");
		free(ret);
		return nil;
	}
	tok++;

	/* many:many mapping */
	ret->end = strtoul(tok, &p, 0);
	if(tok == p){
		mferr(file, *linum, "empty upper rune bound");
		free(ret);
		return nil;
	}else if(p[0] != '\0'){
		mferr(file, *linum, "bad upper rune bound");
		free(ret);
		return nil;
	}

	while((r = parsemaprule(file, b, line, linum)) != nil){
		if(rlast == nil)
			ret->rules = rlast = r;
		else
			rlast = rlast->next = r;
	}

	if(rlast == nil){
		mferr(file, *linum, "unexpected eof");
		free(ret);
		return nil;
	}

	return ret;
}
void
_parsemapfile(Biobuf *b, struct MapFile *mf)
{
	char *line, *tok, *p;
	char *line, *tok;
	uint linum = 1;
	struct Mapping *mlast = nil;
	struct MapRule *rlast;
	struct Mapping *mlast = nil, *m;

	wasreaderr = 0;
	line = Brdline(b, '\n');


@@ 131,120 282,21 @@ _parsemapfile(Biobuf *b, struct MapFile *mf)
		return;
	}

	tok = readtoken(b, &line, &linum);
	while(tok != nil){
	while((tok = readtoken(b, &line, &linum)) != nil){
		if(strcmp(tok, "mapping") == 0){
			if(mlast == nil)
				mf->mappings = mlast = malloc(sizeof(struct Mapping));
			else
				mlast = mlast->next = malloc(sizeof(struct Mapping));

			mlast->linum = linum;
			mlast->rules = nil;
			mlast->next = nil;

			tok = readtoken(b, &line, &linum);
			if(tok == nil){
				mferr(mf->file, linum, "unexpected eof");
				return;
			}

			mlast->start = strtoul(tok, &p, 0);
			if(tok == p){
				mferr(mf->file, linum, "empty lower rune bound");
				return;
			}
			tok = p;

			if(tok[0] == '\0'){	/* 1:1 mapping */
				tok = readtoken(b, &line, &linum);
				if(tok == nil){
					mferr(mf->file, linum, "unexpected eof");
					return;
				}
				mlast->idx = strtoul(tok, &p, 0);
				
				if(tok == p || p[0] != '\0'){
					mferr(mf->file, linum, "bad glyph index");
					return;
				}

				tok = readtoken(b, &line, &linum);
			m = parsemapping(mf->file, b, &line, &linum);
			if(m == nil)
				continue;
			}else if(tok[0] != '-'){
				mferr(mf->file, linum, "bad rune range");
				return;
			}
			tok++;

			/* many:many mapping */
			mlast->end = strtoul(tok, &p, 0);
			if(tok == p){
				mferr(mf->file, linum, "empty upper rune bound");
				return;
			}else if(p[0] != '\0'){
				mferr(mf->file, linum, "bad upper rune bound");
				return;
			}

			rlast = nil;
			while((tok = readtoken(b, &line, &linum)) != nil){
				if(rlast == nil)
					mlast->rules = rlast = malloc(sizeof(struct MapRule));
				else
					rlast = rlast->next = malloc(sizeof(struct MapRule));

				rlast->next = nil;

				if(strcmp(tok, "blank") == 0){
					rlast->ty = MR_BLANK;
					continue;
				}else if(tok[0] == '-'){	/* e.g. -0x4f */
					tok++;
					rlast->ty = MR_RANGE;
					rlast->start = 0;
					rlast->end = strtoul(tok, &p, 0);
					if(tok == p || p[0] != '\0'){
						mferr(mf->file, linum, "bad upper glyph bound");
						return;
					}
					continue;
				}

				rlast->start = strtoul(tok, &p, 0);
				if(tok == p)
					break;	/* return to toplevel parser */
				else if(p[0] == '\0'){
					rlast->ty = MR_SINGLE;
					continue;
				}else if(p[0] != '-'){
					mferr(mf->file, linum, "bad lower glyph bound");
					return;
				}

				rlast->ty = MR_RANGE;

				tok = p+1;
				if(tok[0] == '\0'){	/* e.g. 0x80- */
					rlast->end = nglyphs - 1;
					continue;
				}
				rlast->end = strtoul(tok, &p, 0);
				if(tok == p || p[0] != '\0'){
					mferr(mf->file, linum, "bad upper glyph bound");
					return;
				}
			} /* end while */

			if(rlast == nil){
				mferr(mf->file, linum, "unexpected eof");
				return;
			}
			if(mlast == nil)
				mf->mappings = mlast = m;
			else
				mlast = mlast->next = m;
		}else{
			mferr(mf->file, linum, "unknown verb %s", tok);
			return;
		}
	} /* end while */
	}
}
void
parsemapfile(struct MapFile *mf)


@@ 306,8 358,77 @@ addmapfile(char *file)
	parsemapfile(lastmf);
}
void
testmappingoverlap(char *file, struct Mapping *a, struct Mapping *b)
{
	uchar res = 0;
	struct Mapping *tmp;

	if(a->rules == nil){
		tmp = a; a = b; b = tmp;
	}

	if(a->rules == nil){
		if(a->start == b->start)
			res = 1;
	}else if(b->rules == nil){
		if(a->start <= b->start && b->start <= a->end)
			res = 1;
	}else{
		if(a->start > b->start){
			tmp = a; a = b; b = tmp;
		}
		if(a->end >= b->start)
			res = 1;
	}

	if(res)
		mferr(file, a->linum, "overlaps mapping on line %ud", b->linum);
}
void
testmappingrange(char *file, struct Mapping *m)
{
	struct MapRule *r;
	int nrunes, n = 0;

	for(r = m->rules; r != nil; r = r->next){
		if((r->ty != MR_BLANK && r->start >= nglyphs) ||
			(r->ty == MR_RANGE && r->end >= nglyphs))
			mferr(file, r->linum, "glyphs out of range");

		if(r->ty == MR_RANGE)
			n += r->end - r->start;
		n++;
	}

	nrunes = (m->end-m->start+1);

	if(nrunes != n)
		mferr(file, m->linum, "# runes != # glyphs (%d != %d)", nrunes, n);
}
void
checkmapfiles(void)
{
	struct MapFile *mf;
	struct Mapping *p1, *p2;

	if(wasmferr)
		exits("mapfile");

	for(mf = mapfiles; mf != nil; mf = mf->next){
		for(p1 = mf->mappings; p1 != nil; p1 = p1->next){
			if(p1->rules != nil && p1->start > p1->end)
				mferr(mf->file, p1->linum, "rune start > rune end");

			if(p1->rules != nil)
				testmappingrange(mf->file, p1);
			else if(p1->idx >= nglyphs)
				mferr(mf->file, p1->linum, "glyph out of range");

			for(p2 = p1->next; p2 != nil; p2 = p2->next)
				testmappingoverlap(mf->file, p1, p2);
		}
	}

	if(wasmferr)
		exits("mapfile");
}


@@ 379,25 500,13 @@ loadwidths(Biobuf *b, char *file)
}

void
allocrawimage(void)
allocglyphimg(void)
{
	char buf[13];
	uint imglen;

		/*    cols * rows    */
	imglen = glyphedge * nglyphs*fwidth;
	glyphbuf = malloc(sizeof(struct RawImage) + imglen);

	memcpy(glyphbuf->chan, "         k1 ", 12);
	memcpy(glyphbuf->minx, "          0 ", 12);
	memcpy(glyphbuf->miny, "          0 ", 12);
	Rectangle dims = Rect(0,0, nglyphs*fwidth*8,glyphedge);

	snprint(buf, 12, "%11d ", nglyphs*fwidth*8);
	memcpy(glyphbuf->maxx, buf, 11);
	snprint(buf, 12, "%11d ", glyphedge);
	memcpy(glyphbuf->maxy, buf, 11);

	memset(glyphbuf->data, 0, imglen);
	glyphimg = allocmemimage(dims, strtochan("k1"));
	if(glyphimg == nil)
		sysfatal("%r");
}

uchar


@@ 434,12 543,14 @@ void
storeglyph(uint i, uchar *bitmap)
{
	uint y, x;
	ulong dstidx, srcidx;
	ulong srcidx;
	Point dst;

	for(x = 0; x < fwidth; x++){
		for(y = 0; y < glyphedge; y++){
			dstidx = (i*fwidth)+x+(y*fwidth*nglyphs);
			srcidx = y+(x*glyphedge);
			glyphbuf->data[dstidx] = bitmap[srcidx];
			dst = Pt((i*fwidth+x)*8, y);
			*byteaddr(glyphimg, dst) = bitmap[srcidx];
		}
	}
}


@@ 493,7 604,7 @@ loadufx(char *infile)
	glyphs = malloc(nglyphs * sizeof(struct GlyphInfo));
	b = Bopen(infile, OREAD);

	allocrawimage();
	allocglyphimg();

	loadwidths(b, infile);
	loadglyphs(b);


@@ 503,6 614,14 @@ loadufx(char *infile)


void
makenaive(void)
{
	int fd;
	struct RawSubfont s;
}


void
usage(void)
{
	fprint(2,


@@ 516,6 635,7 @@ void
main(int argc, char **argv)
{
	char *infile, *outdir;
	int fd;

	ARGBEGIN{
	case 'l':


@@ 546,8 666,6 @@ main(int argc, char **argv)
	default:
		usage();
	}ARGEND;
	
	checkmapfiles();


	if(argv0 == nil)


@@ 563,9 681,24 @@ main(int argc, char **argv)
	if(baseline >= glyphedge)
		sysfatal("-b: baseline must be in range 1-width*8");

	checkmapfiles();

	loadufx(infile);

	int fd = create(outdir, OWRITE, 0644);
	write(fd, glyphbuf, sizeof(struct RawImage) + (glyphedge*nglyphs*fwidth));

	fd = create(outdir, OWRITE, 0777|DMDIR);
	if(fd < 0)
		sysfatal("%r");
	close(fd);
	chdir(outdir);

	fd = create("test", OWRITE, 0777);
	writememimage(fd, glyphimg);
	close(fd);

	if(!setconv || donaive)
		makenaive();
/*	if(!setconv || doholes)
		makeholes();
	makemapped();*/
}