ref: 44143b94e3e716ffd9ebd1b5e08b9fcb69f22dd5
dir: /sys/src/cmd/aux/mnihongo/mnihongo.c/
/* output language from troff: all numbers are character strings sn size in points fn font as number from 1-n cx ascii character x Cxyz funny char xyz. terminated by white space Nn absolute character number n on this font. ditto Hn go to absolute horizontal position n Vn go to absolute vertical position n (down is positive) hn go n units horizontally (relative) vn ditto vertically nnc move right nn, then print c (exactly 2 digits!) (this wart is an optimization that shrinks output file size about 35% and run-time about 15% while preserving ascii-ness) Dt ...\n draw operation 't': Dl x y line from here by x,y Dc d circle of diameter d with left side here De x y ellipse of axes x,y with left side here Da dx dy dx dy arc counter-clockwise, center at dx,dx, end at dx,dy D~ x y x y ... wiggly line by x,y then x,y ... nb a end of line (information only -- no action needed) w paddable word space -- no action needed b = space before line, a = after p new page begins -- set v to 0 #...\n comment x ...\n device control functions: x i init x T s name of device is s x r n h v resolution is n/inch h = min horizontal motion, v = min vert x p pause (can restart) x s stop -- done for ever x t generate trailer x f n s font position n contains font s x H n set character height to n x S n set slant to N Subcommands like "i" are often spelled out like "init". */ #include <u.h> #include <libc.h> #include <draw.h> #include <memdraw.h> #include <bio.h> #define hmot(n) hpos += n #define hgoto(n) hpos = n #define vmot(n) vgoto(vpos + n) #define vgoto(n) vpos = n #define putchar(x) Bprint(&bout, "%C", x) int hpos; /* horizontal position where we are supposed to be next (left = 0) */ int vpos; /* current vertical position (down positive) */ char *fontfile = "/lib/font/bit/pelm/unicode.9x24.font"; char *pschar(char *, char *hex, int *wid, int *ht); void memopenfont(char *); int kanji(char *); void Bgetstr(Biobuf *bp, char *s); void Bgetline(Biobuf *bp, char *s); void Bgetint(Biobuf *bp, int *n); Biobuf bin, bout; Memimage *white; void main(void) { int c, n; char str[100], *args[10]; int jfont, curfont; Binit(&bin, 0, OREAD); Binit(&bout, 1, OWRITE); memimageinit(); white = allocmemimage(Rect(0, 0, 1, 1), GREY1); if(white == nil) sysfatal("allocmemimage: %r"); memfillcolor(white, DWhite); white->flags |= Frepl; memopenfont(fontfile); jfont = -1; curfont = 1; while ((c = Bgetc(&bin)) >= 0) { switch (c) { case '\n': /* when input is text */ case ' ': case '\0': /* occasional noise creeps in */ putchar(c); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* two motion digits plus a character */ putchar(c); /* digit 1 */ n = (c-'0')*10; c = Bgetc(&bin); putchar(c); /* digit 2 */ n += c - '0'; hmot(n); putchar(Bgetc(&bin)); /* char itself */ break; case 'c': /* single character */ c = Bgetrune(&bin); if(c==' ') /* why does this happen? it's troff - bwk */ break; else if(jfont == curfont){ Bungetrune(&bin); Bgetstr(&bin, str); kanji(str); }else{ putchar('c'); putchar(c); } break; case 'C': Bgetstr(&bin, str); Bprint(&bout, "C%s", str); break; case 'f': Bgetstr(&bin, str); curfont = atoi(str); if(curfont < 0 || curfont > 20) curfont = 1; /* sanity */ Bprint(&bout, "%c%s", c, str); break; case 'N': /* absolute character number */ case 's': case 'p': /* new page */ Bgetint(&bin, &n); Bprint(&bout, "%c%d", c, n); break; case 'H': /* absolute horizontal motion */ Bgetint(&bin, &n); Bprint(&bout, "%c%d", c, n); hgoto(n); break; case 'h': /* relative horizontal motion */ Bgetint(&bin, &n); Bprint(&bout, "%c%d", c, n); hmot(n); break; case 'V': Bgetint(&bin, &n); Bprint(&bout, "%c%d", c, n); vgoto(n); break; case 'v': Bgetint(&bin, &n); Bprint(&bout, "%c%d", c, n); vmot(n); break; case 'w': /* word space */ putchar(c); break; case 'x': /* device control */ Bgetline(&bin, str); Bprint(&bout, "%c%s", c, str); if(tokenize(str, args, 10)>2 && args[0][0]=='f' && ('0'<=args[1][0] && args[1][0]<='9')){ if(strncmp(args[2], "Jp", 2) == 0) jfont = atoi(args[1]); else if(atoi(args[1]) == jfont) jfont = -1; } break; case 'D': /* draw function */ case 'n': /* end of line */ case '#': /* comment */ Bgetline(&bin, str); Bprint(&bout, "%c%s", c, str); break; default: fprint(2, "mnihongo: unknown input character %o %c\n", c, c); exits("error"); } } } struct { int s, e; char *path; Memsubfont *f; } fonts[128]; static int nfonts; void memopenfont(char *name) { Biobuf *b; int i; char *s, *p, *p2; b = Bopen(name, OREAD); for(i = 0; s = Brdline(b, '\n'); i++){ if(i == 0) continue; s[Blinelen(b)-1] = '\0'; fonts[i].s = strtol(s, &p, 0); if(s == p || *p == '\0') goto Invalid; p++; fonts[i].e = strtol(p, &p2, 0); if(p == p2 || *p2 == '\0') goto Invalid; p = p2 + 1; if(*p == '/') fonts[i].path = strdup(p); else { fonts[i].path = smprint("/lib/font/bit/pelm/%s", p); cleanname(fonts[i].path); } } nfonts = i; if(nfonts == 0){ Invalid: sysfatal("%s is an invalid font file", name); } Bterm(b); } Memsubfont* memgetfont(Rune r) { int i; for(i = 0; i < nfonts; i++){ if(r >= fonts[i].s && r < fonts[i].e){ if(fonts[i].f == nil){ fonts[i].f = openmemsubfont(fonts[i].path, fonts[i].s); if(fonts[i].f == nil) sysfatal("failed to open subfont: %r"); } return fonts[i].f; } } return nil; } int kanji(char *s) /* very special pleading */ { /* dump as kanji char if looks like one */ Rune r; char hex[500]; int size = 10, ht, wid; chartorune(&r, s); pschar(s, hex, &wid, &ht); Bprint(&bout, "x X PS save %d %d m\n", hpos, vpos); Bprint(&bout, "x X PS currentpoint translate %d %d scale ptsize dup scale\n", size, size); Bprint(&bout, "x X PS %d %d true [%d 0 0 -%d 0 %d]\n", wid, ht, wid, wid, ht-2); /* kludge; ought to use ->ascent */ Bprint(&bout, "x X PS {<%s>}\n", hex); Bprint(&bout, "x X PS imagemask restore\n"); return 1; } char* pschar(char *s, char *hex, int *wid, int *ht) { Point chpt, spt; Memimage *b; Memsubfont *f; uchar rowdata[100]; char *hp = hex; int y, i; Rune r; chartorune(&r, s); f = memgetfont(r); chpt = memsubfontwidth(f, s); /* bounding box of char */ *wid = ((chpt.x+7) / 8) * 8; *ht = chpt.y; /* postscript is backwards to video, so draw white (ones) on black (zeros) */ white->clipr = Rpt(ZP, chpt); b = allocmemimage(white->clipr, GREY1); if(b == nil) sysfatal("allocmemimage: %r"); memfillcolor(b, DBlack); spt = memimagestring(b, Pt(0,0), white, ZP, f, s); /* put it there */ /* Bprint(&bout, "chpt %P, spt %P, wid,ht %d,%d\n", chpt, spt, *wid, *ht); /* Bflush(&bout); */ for (y = 0; y < chpt.y; y++) { /* read bits a row at a time */ memset(rowdata, 0, sizeof rowdata); unloadmemimage(b, Rect(0, y, chpt.x, y+1), rowdata, sizeof rowdata); for (i = 0; i < spt.x; i += 8) { /* 8 == byte */ sprint(hp, "%2.2x", rowdata[i/8]); hp += 2; } } *hp = 0; freememimage(b); return hex; } void Bgetstr(Biobuf *bp, char *s) /* get a string */ { int c; while ((c = Bgetc(bp)) >= 0) { if (c == ' ' || c == '\t' || c == '\n') { Bungetc(bp); break; } *s++ = c; } *s = 0; } void Bgetline(Biobuf *bp, char *s) /* get a line, including newline */ { int c; while ((c = Bgetc(bp)) >= 0) { *s++ = c; if (c == '\n') break; } *s = 0; } void Bgetint(Biobuf *bp, int *n) /* get an integer */ { double d; Bgetd(bp, &d); *n = d; }