@@ 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();*/
}