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