ref: a6e5d4bae6075c741a39fcba62a365d9dffaed93
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;
}