@@ 0,0 1,337 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+
+/* entry has 1 byte in widtab + 8 bytes per tile */
+#define ufxlen(n) (1 + ((n)*(n)*8))
+
+
+enum{
+ MR_BLANK,
+ MR_SINGLE,
+ MR_RANGE
+};
+struct MapRule{
+ struct MapRule *next;
+
+ uchar ty;
+ uint start, end;
+};
+struct Mapping{
+ struct Mapping *next;
+
+ uint linum;
+
+ Rune start;
+ union {Rune end; uint idx;};
+ struct MapRule *rules;
+};
+struct MapFile{
+ struct MapFile *next;
+
+ char *file;
+
+ struct Mapping *mappings;
+};
+
+
+uint fwidth, nglyphs;
+
+uchar setconv, donaive, doholes;
+struct MapFile *mapfiles, *lastmf;
+
+uchar wasmferr, wasreaderr;
+
+
+void
+bioerr(char *s)
+{
+ wasreaderr = 1;
+ wasmferr = 1;
+ fprint(2, "%s: %s\n", argv0, s);
+}
+char *
+readtoken(Biobuf *b, char **line, uint *linum)
+{
+ char *ret, *p;
+
+ while(*line != nil){
+ p = *line;
+ while(p[0] != '\0' && strchr("\t\r ", p[0]) != nil)
+ p++;
+
+ if(strchr("#;\n", p[0]) != nil){
+ *line = Brdline(b, '\n');
+ (*linum)++;
+ continue;
+ }
+ ret = p;
+
+ while(strchr("\t\r\n ", p[0]) == nil)
+ p++;
+
+ *line = p;
+ if(p[0] != '\n')
+ (*line)++;
+ p[0] = '\0';
+
+ return ret;
+ }
+
+ return nil;
+}
+#pragma varargck argpos mferr 3
+void
+mferr(char *file, uint linum, char *fmt, ...)
+{
+ char buf[1024];
+ va_list va;
+
+ va_start(va, fmt);
+ vsnprint(buf, sizeof(buf), fmt, va);
+ va_end(va);
+ if(linum != 0)
+ fprint(2, "%s: %s:%ud: %s\n", argv0, file, linum, buf);
+ else
+ fprint(2, "%s: %s: %s\n", argv0, file, buf);
+
+ wasmferr = 1;
+}
+void
+_parsemapfile(Biobuf *b, struct MapFile *mf)
+{
+ char *line, *tok, *p;
+ uint linum = 1;
+ struct Mapping *mlast = nil;
+ struct MapRule *rlast;
+
+ wasreaderr = 0;
+ line = Brdline(b, '\n');
+ if(line == nil){
+ if(!wasreaderr)
+ fprint(2, "%s: warn: %s: empty file\n", argv0, mf->file);
+ return;
+ }
+
+ tok = readtoken(b, &line, &linum);
+ while(tok != 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);
+ 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;
+ }
+ }else{
+ mferr(mf->file, linum, "unknown verb %s", tok);
+ return;
+ }
+ } /* end while */
+}
+void
+parsemapfile(struct MapFile *mf)
+{
+ Biobuf *b;
+
+ b = Bopen(mf->file, OREAD);
+ if(b == nil){
+ fprint(2, "%s: %r\n", argv0);
+ wasmferr = 1;
+ return;
+ }
+ Blethal(b, bioerr);
+
+ _parsemapfile(b, mf);
+
+ Bterm(b);
+}
+void
+printmapfile(struct MapFile *mf)
+{
+ struct Mapping *mp;
+ struct MapRule *rp;
+
+ print("mapfile: %s\n", mf->file);
+
+ for(mp = mf->mappings; mp != nil; mp = mp->next){
+ if(mp->rules == nil)
+ print("\t%ud: %ux => %ux\n", mp->linum, mp->start, mp->idx);
+ else{
+ print("\t%ud: %ux - %ux =>\n", mp->linum, mp->start, mp->end);
+ for(rp = mp->rules; rp != nil; rp = rp->next){
+ switch(rp->ty){
+ case MR_SINGLE:
+ print("\t\t%ux\n", rp->start);
+ break;
+ case MR_RANGE:
+ print("\t\t%ux - %ux\n", rp->start, rp->end);
+ break;
+ case MR_BLANK:
+ print("\t\tblank\n");
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s [-nh] [-m mapfile] [-l length] [-x width] in.ufx out/\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ char *infile, *outdir;
+ struct MapFile *mf;
+
+ ARGBEGIN{
+ case 'l':
+ nglyphs = atoi(EARGF(usage()));
+ break;
+ case 'x':
+ fwidth = atoi(EARGF(usage()));
+ break;
+ case 'n':
+ setconv = 1;
+ donaive = 1;
+ break;
+ case 'h':
+ setconv = 1;
+ doholes = 1;
+ break;
+ case 'm':
+ setconv = 1;
+ if(lastmf == nil)
+ mapfiles = lastmf = malloc(sizeof(struct MapFile));
+ else
+ lastmf = lastmf->next = malloc(sizeof(struct MapFile));
+ lastmf->file = EARGF(usage());
+ lastmf->next = nil;
+ lastmf->mappings = nil;
+ break;
+ default:
+ usage();
+ }ARGEND;
+
+ if(argv0 == nil)
+ argv0 = "ufx2font";
+
+ if(argc != 2)
+ usage();
+
+
+ // TODO: calculate length etc etc
+
+ for(mf = mapfiles; mf != nil; mf = mf->next)
+ parsemapfile(mf);
+ if(wasmferr)
+ exits("mapfile");
+ for(mf = mapfiles; mf != nil; mf = mf->next)
+ printmapfile(mf);
+}