/* 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 #include #include #include #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); int kanji(char *); void Bgetstr(Biobuf *bp, char *s); void Bgetline(Biobuf *bp, char *s); void Bgetint(Biobuf *bp, int *n); Biobuf bin, bout; void main(void) { int c, n; char str[100], *args[10]; int jfont, curfont; if(initdraw(0, fontfile, 0) < 0){ fprint(2, "mnihongo: can't initialize display: %r\n"); exits("open"); } Binit(&bin, 0, OREAD); Binit(&bout, 1, OWRITE); 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"); } } } 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; Image *b; uchar rowdata[100]; char *hp = hex; int y, i; chpt = stringsize(font, 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) */ b = allocimage(display, Rpt(ZP, chpt), GREY1, 0, DBlack); /* place to put it */ spt = string(b, Pt(0,0), display->white, ZP, font, 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); unloadimage(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; freeimage(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; }