date and time created 83/07/24 12:43:31 by slatteng
[unix-history] / usr / src / local / ditroff / ditroff.old.okeeffe / driver / dterm.c
/* @(#)dterm.c 1.1 (Berkeley) %G%"
*
* Converts ditroff output to text on a terminal. It is NOT meant to
* produce readable output, but is to show one how one's paper is (in
* general) formatted - what will go where on which page.
*
* options:
*
* -hn set horizontal resolution to n (in characters per inch;
* default is 10.0).
*
* -vn set vertical resolution (default is 6.0).
*
* -ln set maximum output line-length to n (default is 79).
*
* -olist output page list - as in troff.
*
* -c continue at end of page. Default is to stop at the end
* of each page, print "dterm:" and wait for a command.
* Type ? to get a list of available commands.
*
* -w sets h = 20, v = 12, l = 131, also sets -c to allow for
* extra-wide printouts on the printer.
*/
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#define FATAL 1
#define PGWIDTH 133
#define PGHEIGHT 110
#define LINELEN 78
#define hgoto(n) hpos = n
#define vgoto(n) vpos = n
#define hmot(n) hpos += n
#define vmot(n) vpos += n
#define sgn(n) ((n > 0) ? 1 : ((n < 0) ? -1 : 0))
#define abs(n) ((n) >= 0 ? (n) : -(n))
#define max(x,y) ((x) > (y) ? (x) : (y))
#define min(x,y) ((x) < (y) ? (x) : (y))
#define arcmove(x,y) { hgoto(x); vmot(-vpos-(y)); }
#define sqr(x) (long int)(x)*(x)
char SccsId [] = "@(#)dterm.c 1.1 (Berkeley) %G%";
char *spectab[] ={
"em", "-", "hy", "-", "en", "-", "ru", "_", "l.", ".", "L.", ".",
"br", "|", "vr", "|", "fm", "'", "or", "|",
0, 0,
};
int keepon = 0; /* flag: Do we not stop at the end of each page? */
int output = 0; /* do we do output at all? */
int nolist = 0; /* output page list if > 0 */
int olist[20]; /* pairs of page numbers */
float hscale = 10.0; /* characters and lines per inch for output device */
float vscale = 6.0; /* (defaults are for printer) */
FILE *fp = stdin; /* input file pointer */
char pagebuf[PGHEIGHT][PGWIDTH];
int minh = PGWIDTH;
int maxh = 0;
int minv = PGHEIGHT;
int maxv = 0;
int linelen = LINELEN;
int hpos; /* horizontal position to be next (left = 0) */
int vpos; /* current vertical position (down positive) */
int np; /* number of pages seen */
int npmax; /* high-water mark of np */
int pgnum[40]; /* their actual numbers */
long pgadr[40]; /* their seek addresses */
int DP = 10; /* step size for drawing */
int drawdot = '.'; /* draw with this character */
int drawsize = 1; /* shrink by this factor when drawing */
int maxdots = 32000; /* maximum number of dots in an object */
main(argc, argv)
int argc;
char **argv;
{
argv++;
while (argc > 1 && **argv == '-') {
switch (*(++*argv)) {
case 'l':
linelen = atoi(++*argv) - 1;
break;
case 'h':
hscale = atof(++*argv);
break;
case 'v':
vscale = atof(++*argv);
break;
case 'o':
outlist(++*argv);
break;
case 'c':
keepon = 1;
break;
case 'w':
hscale = 20.0;
vscale = 12.0;
linelen = 131;
keepon = 1;
break;
}
argc--;
argv++;
}
if (argc <= 1)
conv(stdin);
else
while (--argc) {
if (strcmp(*argv, "-") == 0)
fp = stdin;
else if ((fp = fopen(*argv, "r")) == NULL)
error(FATAL, "can't open %s", *argv);
conv(fp);
fclose(fp);
argv++;
}
done();
}
outlist(s) /* process list of page numbers to be printed */
char *s;
{
int n1, n2, i;
nolist = 0;
while (*s) {
n1 = 0;
if (isdigit(*s))
do
n1 = 10 * n1 + *s++ - '0';
while (isdigit(*s));
else
n1 = -9999;
n2 = n1;
if (*s == '-') {
s++;
n2 = 0;
if (isdigit(*s))
do
n2 = 10 * n2 + *s++ - '0';
while (isdigit(*s));
else
n2 = 9999;
}
olist[nolist++] = n1;
olist[nolist++] = n2;
if (*s != '\0')
s++;
}
olist[nolist] = 0;
}
in_olist(n) /* is n in olist? */
int n;
{
int i;
if (nolist == 0)
return(1); /* everything is included */
for (i = 0; i < nolist; i += 2)
if (n >= olist[i] && n <= olist[i+1])
return(1);
return(0);
}
conv(fp)
register FILE *fp;
{
register int c;
int m, n, i, n1, m1;
char str[100], buf[300];
while ((c = getc(fp)) != EOF) {
switch (c) {
case '\n': /* when input is text */
case '\t':
case ' ':
case 0:
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 */
hmot((c-'0')*10 + getc(fp)-'0');
put1(getc(fp));
break;
case 'c': /* single ascii character */
put1(getc(fp));
break;
case 'C': /* funny character */
fscanf(fp, "%s", str);
put1s(str);
break;
case 't': /* straight text */
fgets(buf, sizeof(buf), fp);
t_text(buf);
break;
case 'D': /* draw function */
fgets(buf, sizeof(buf), fp);
switch (buf[0]) {
case 'l': /* draw a line */
sscanf(buf+1, "%d %d", &n, &m);
drawline(n, m, ".");
break;
case 'c': /* circle */
sscanf(buf+1, "%d", &n);
drawcirc(n);
break;
case 'e': /* ellipse */
sscanf(buf+1, "%d %d", &m, &n);
drawellip(m, n);
break;
case 'a': /* arc */
sscanf(buf+1, "%d %d %d %d", &n, &m, &n1, &m1);
drawarc(n, m, n1, m1);
break;
case 'g': /* "gremlin" curve */
case '~': /* wiggly line */
drawwig(buf+1);
break;
case 't': /* thickness - not important */
case 's': /* style - not important */
break;
default:
error(FATAL,"unknown drawing command %s\n",buf);
break;
}
break;
case 's': /* point size - ignored */
fscanf(fp, "%d", &n);
break;
case 'f': /* font request - ignored */
fscanf(fp, "%s", str);
break;
case 'H': /* absolute horizontal motion */
fscanf(fp, "%d", &n);
hgoto(n);
break;
case 'h': /* relative horizontal motion */
fscanf(fp, "%d", &n);
hmot(n);
break;
case 'w': /* word space */
break;
case 'V': /* absolute vertical motion */
fscanf(fp, "%d", &n);
vgoto(n);
break;
case 'v': /* relative vertical motion */
fscanf(fp, "%d", &n);
vmot(n);
break;
case 'p': /* new page */
fscanf(fp, "%d", &n);
t_page(n);
break;
case 'n': /* end of line */
hpos = 0;
case '#': /* comment */
while (getc(fp) != '\n')
;
break;
case 'x': /* device control */
devcntrl(fp);
break;
default:
error(!FATAL, "unknown input character %o %c\n", c, c);
done();
}
}
}
devcntrl(fp) /* interpret device control functions */
FILE *fp;
{
int c, n;
char str[20];
fscanf(fp, "%s", str);
switch (str[0]) { /* crude for now */
case 'i': /* initialize */
t_init(0);
break;
case 'r': /* resolution assumed when prepared */
fscanf(fp, "%d", &n);
hscale = (float) n / hscale;
vscale = (float) n / vscale;
break;
case 'f': /* font used */
case 'T': /* device name */
case 't': /* trailer */
case 'p': /* pause -- can restart */
case 's': /* stop */
break;
}
while (getc(fp) != '\n') /* skip rest of input line */
;
}
/* error printing routine - first argument is a "fatal" flag */
error(f, s, a1, a2, a3, a4, a5, a6, a7) {
fprintf(stderr, "dterm: ");
fprintf(stderr, s, a1, a2, a3, a4, a5, a6, a7);
fprintf(stderr, "\n");
if (f) exit(1);
}
t_init(reinit) /* initialize device */
int reinit;
{
int i, j;
fflush(stdout);
hpos = vpos = 0;
for (i = 0; i < PGHEIGHT; i++)
for (j = 0; j < PGWIDTH; j++)
pagebuf[i][j] = ' ';
minh = PGWIDTH;
maxh = 0;
minv = PGHEIGHT;
maxv = 0;
}
/* just got "p#" command. print the current page and */
t_page(n) /* do whatever new page functions */
{
long ftell();
int c, m, i;
char buf[100], *bp;
pgnum[np++] = n;
pgadr[np] = ftell(fp);
if (np > npmax)
npmax = np;
if (output == 0) {
output = in_olist(n);
t_init(1);
return;
}
putpage();
fflush(stdout);
if (keepon) {
putchar('\f');
t_init(1);
return;
}
next:
for (bp = buf; (*bp = readch()); )
if (*bp++ == '\n')
break;
*bp = 0;
switch (buf[0]) {
case 0:
done();
break;
case '\n':
output = in_olist(n);
t_init(1);
return;
case '-':
case 'p':
m = atoi(&buf[1]) + 1;
if (fp == stdin) {
fputs("you can't; it's not a file\n", stderr);
break;
}
if (np - m <= 0) {
fputs("too far back\n", stderr);
break;
}
np -= m;
fseek(fp, pgadr[np], 0);
output = 1;
t_init(1);
return;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
m = atoi(&buf[0]);
for (i = 0; i < npmax; i++)
if (m == pgnum[i])
break;
if (i >= npmax || fp == stdin) {
fputs("you can't\n", stderr);
break;
}
np = i + 1;
fseek(fp, pgadr[np], 0);
output = 1;
t_init(1);
return;
case 'o':
outlist(&buf[1]);
output = 0;
t_init(1);
return;
case '?':
fputs("p print this page again\n", stderr);
fputs("-n go back n pages\n", stderr);
fputs("n print page n (previously printed)\n", stderr);
fputs("o... set the -o output list to ...\n", stderr);
break;
default:
fputs("?\n", stderr);
break;
}
goto next;
}
/* print the contents of the current page. puts out */
putpage() /* only the part of the page that's been written on */
{
int i, j, k;
fflush(stdout);
for (i = minv; i <= maxv; i++) {
for (k = maxh; pagebuf[i][k] == ' '; k--)
;
if (k > minh + linelen)
k = minh + linelen;
for (j = minh; j <= k; j++)
putchar(pagebuf[i][j]);
putchar('\n');
}
fflush(stdout);
}
t_text(s) /* print string s as text */
char *s;
{
int c;
char str[100];
if (!output)
return;
while ((c = *s++) != '\n') {
if (c == '\\') {
switch (c = *s++) {
case '\\':
case 'e':
put1('\\');
break;
case '(':
str[0] = *s++;
str[1] = *s++;
str[2] = '\0';
put1s(str);
break;
}
} else {
put1(c);
}
hmot(1);
}
}
put1s(s) /* s is a funny char name */
char *s;
{
int i;
char *p;
extern char *spectab[];
static char prev[10] = "";
static int previ;
if (!output)
return;
if (strcmp(s, prev) != 0) {
previ = -1;
for (i = 0; spectab[i] != 0; i += 2)
if (strcmp(spectab[i], s) == 0) {
strcpy(prev, s);
previ = i;
break;
}
}
if (previ >= 0) {
for (p = spectab[previ+1]; *p; p++)
store(*p);
} else
prev[0] = 0;
}
put1(c) /* output char c */
int c;
{
if (!output)
return;
store(c);
}
done()
{
output = 1;
putpage();
fflush(stdout);
exit(0);
}
readch ()
{
int c;
static FILE *rcf;
static nbol; /* 0 if at beginning of a line */
if (rcf == NULL) {
rcf = fopen ("/dev/tty", "r");
setbuf (rcf, NULL);
}
if (!nbol)
fprintf (stderr, "dterm: "); /* issue prompt */
if ((c = getc (rcf)) == EOF)
return 0;
nbol = (c != '\n');
return c;
}
store(c) /* put 'c' in the page at (hpos, vpos) */
{
register int i;
register int j;
i = hpos / hscale; /* scale the position to page coordinates */
j = vpos / vscale;
if (i >= PGWIDTH) i = PGWIDTH - 1; /* don't go over the edge */
else if (i < 0) i = 0;
if (j >= PGHEIGHT) j = PGHEIGHT - 1;
else if (j < 0) j = 0;
pagebuf[j][i] = c; /* write the character */
if (i > maxh) maxh = i; /* update the page bounds */
if (i < minh) minh = i;
if (j > maxv) maxv = j;
if (j < minv) minv = j;
}
drawline(dx, dy, s) /* draw line from here to dx, dy using s */
int dx, dy;
char *s;
{
register int xd;
register int yd;
register int i;
register int numdots;
int dirmot, perp;
int motincr, perpincr;
int ohpos, ovpos;
float val, slope;
float incrway;
ohpos = hpos;
ovpos = vpos;
xd = dx / DP;
yd = dy / DP;
if (xd == 0) {
numdots = abs (yd);
numdots = min(numdots, maxdots);
motincr = DP * sgn (yd);
for (i = 0; i < numdots; i++) {
vmot(motincr);
put1(drawdot);
}
} else
if (yd == 0) {
numdots = abs (xd);
motincr = DP * sgn (xd);
for (i = 0; i < numdots; i++) {
hmot(motincr);
put1(drawdot);
}
} else {
if (abs (xd) > abs (yd)) {
val = slope = (float) xd/yd;
numdots = abs (xd);
numdots = min(numdots, maxdots);
dirmot = 'h';
perp = 'v';
motincr = DP * sgn (xd);
perpincr = DP * sgn (yd);
} else {
val = slope = (float) yd/xd;
numdots = abs (yd);
numdots = min(numdots, maxdots);
dirmot = 'v';
perp = 'h';
motincr = DP * sgn (yd);
perpincr = DP * sgn (xd);
}
incrway = sgn ((int) slope);
for (i = 0; i < numdots; i++) {
val -= incrway;
if (dirmot == 'h')
hmot(motincr);
else
vmot(motincr);
if (val * slope < 0) {
if (perp == 'h')
hmot(perpincr);
else
vmot(perpincr);
val += slope;
}
put1(drawdot);
}
}
hgoto(ohpos + dx);
vgoto(ovpos + dy);
}
drawwig(s) /* draw wiggly line */
char *s;
{
int x[50], y[50], xp, yp, pxp, pyp;
float t1, t2, t3, w;
int i, j, numdots, N;
char temp[50], *p, *getstr();
p = s;
for (N = 2; (p=getstr(p,temp)) != NULL && N < sizeof(x)/sizeof(x[0]);) {
x[N] = atoi(temp);
p = getstr(p, temp);
y[N++] = atoi(temp);
}
x[0] = x[1] = hpos;
y[0] = y[1] = vpos;
for (i = 1; i < N; i++) {
x[i+1] += x[i];
y[i+1] += y[i];
}
x[N] = x[N-1];
y[N] = y[N-1];
pxp = pyp = -9999;
for (i = 0; i < N-1; i++) { /* interval */
numdots = (dist(x[i], y[i], x[i+1], y[i+1])
+ dist(x[i+1], y[i+1], x[i+2], y[i+2])) / 2;
numdots /= DP;
numdots = min(numdots, maxdots);
for (j = 0; j < numdots; j++) { /* points within */
w = (float) j / numdots;
t1 = 0.5 * w * w;
w = w - 0.5;
t2 = 0.75 - w * w;
w = w - 0.5;
t3 = 0.5 * w * w;
xp = t1 * x[i+2] + t2 * x[i+1] + t3 * x[i] + 0.5;
yp = t1 * y[i+2] + t2 * y[i+1] + t3 * y[i] + 0.5;
if (xp != pxp || yp != pyp) {
hgoto(xp);
vgoto(yp);
put1(drawdot);
pxp = xp;
pyp = yp;
}
}
}
}
/* copy next non-blank string from p to temp, update p */
char *getstr(p, temp)
char *p, *temp;
{
while (*p == ' ' || *p == '\t' || *p == '\n')
p++;
if (*p == '\0') {
temp[0] = 0;
return(NULL);
}
while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
*temp++ = *p++;
*temp = '\0';
return(p);
}
drawcirc(d)
{
int xc, yc;
xc = hpos;
yc = vpos;
conicarc(hpos + d/2, -vpos, hpos, -vpos, hpos, -vpos, d/2, d/2);
hgoto(xc + d); /* circle goes to right side */
vgoto(yc);
}
dist(x1, y1, x2, y2) /* integer distance from x1,y1 to x2,y2 */
{
float dx, dy;
dx = x2 - x1;
dy = y2 - y1;
return sqrt(dx*dx + dy*dy) + 0.5;
}
drawarc(dx1, dy1, dx2, dy2)
{
int x0, y0, x2, y2, r;
x0 = hpos + dx1; /* center */
y0 = vpos + dy1;
x2 = x0 + dx2; /* "to" */
y2 = y0 + dy2;
r = sqrt((float) dx1 * dx1 + (float) dy1 * dy1) + 0.5;
conicarc(x0, -y0, hpos, -vpos, x2, -y2, r, r);
}
drawellip(a, b)
{
int xc, yc;
xc = hpos;
yc = vpos;
conicarc(hpos + a/2, -vpos, hpos, -vpos, hpos, -vpos, a/2, b/2);
hgoto(xc + a);
vgoto(yc);
}
conicarc(x, y, x0, y0, x1, y1, a, b)
{
/* based on Bresenham, CACM Feb 77, pp 102-3 by Chris Van Wyk */
/* capitalized vars are an internal reference frame */
long dotcount = 0;
int xs, ys, xt, yt, Xs, Ys, qs, Xt, Yt, qt,
M1x, M1y, M2x, M2y, M3x, M3y,
Q, move, Xc, Yc;
int ox1, oy1;
long delta;
float xc, yc;
float radius, slope;
float xstep, ystep;
ox1 = x1;
oy1 = y1;
if (a != b) /* an arc of an ellipse; internally, think of circle */
if (a > b) {
xstep = (float)a / b;
ystep = 1;
radius = b;
} else {
xstep = 1;
ystep = (float)b / a;
radius = a;
}
else {
/* a circular arc; radius computed from center and first point */
xstep = ystep = 1;
radius = sqrt((float)(sqr(x0 - x) + sqr(y0 - y)));
}
xc = x0;
yc = y0;
/* now, use start and end point locations to figure out
the angle at which start and end happen; use these
angles with known radius to figure out where start
and end should be
*/
slope = atan2((double)(y0 - y), (double)(x0 - x) );
if (slope == 0.0 && x0 < x)
slope = 3.14159265;
x0 = x + radius * cos(slope) + 0.5;
y0 = y + radius * sin(slope) + 0.5;
slope = atan2((double)(y1 - y), (double)(x1 - x));
if (slope == 0.0 && x1 < x)
slope = 3.14159265;
x1 = x + radius * cos(slope) + 0.5;
y1 = y + radius * sin(slope) + 0.5;
/* step 2: translate to zero-centered circle */
xs = x0 - x;
ys = y0 - y;
xt = x1 - x;
yt = y1 - y;
/* step 3: normalize to first quadrant */
if (xs < 0)
if (ys < 0) {
Xs = abs(ys);
Ys = abs(xs);
qs = 3;
M1x = 0;
M1y = -1;
M2x = 1;
M2y = -1;
M3x = 1;
M3y = 0;
} else {
Xs = abs(xs);
Ys = abs(ys);
qs = 2;
M1x = -1;
M1y = 0;
M2x = -1;
M2y = -1;
M3x = 0;
M3y = -1;
}
else if (ys < 0) {
Xs = abs(xs);
Ys = abs(ys);
qs = 0;
M1x = 1;
M1y = 0;
M2x = 1;
M2y = 1;
M3x = 0;
M3y = 1;
} else {
Xs = abs(ys);
Ys = abs(xs);
qs = 1;
M1x = 0;
M1y = 1;
M2x = -1;
M2y = 1;
M3x = -1;
M3y = 0;
}
Xc = Xs;
Yc = Ys;
if (xt < 0)
if (yt < 0) {
Xt = abs(yt);
Yt = abs(xt);
qt = 3;
} else {
Xt = abs(xt);
Yt = abs(yt);
qt = 2;
}
else if (yt < 0) {
Xt = abs(xt);
Yt = abs(yt);
qt = 0;
} else {
Xt = abs(yt);
Yt = abs(xt);
qt = 1;
}
/* step 4: calculate number of quadrant crossings */
if (((4 + qt - qs) % 4 == 0) && (Xt <= Xs) && (Yt >= Ys))
Q = 3;
else
Q = (4 + qt - qs) % 4 - 1;
/* step 5: calculate initial decision difference */
delta = sqr(Xs + 1) + sqr(Ys - 1) - sqr(xs) - sqr(ys);
/* here begins the work of drawing. */
while ((Q >= 0) || ((Q > -2) && ((Xt > Xc) && (Yt < Yc)))) {
if (dotcount++ % DP == 0)
putdot((int)xc, (int)yc);
if (Yc < 0.5) {
/* reinitialize */
Xs = Xc = 0;
Ys = Yc = sqrt((float)(sqr(xs) + sqr(ys)));
delta = sqr(Xs + 1) + sqr(Ys - 1) - sqr(xs) - sqr(ys);
Q--;
M1x = M3x;
M1y = M3y;
{
int T;
T = M2y;
M2y = M2x;
M2x = -T;
T = M3y;
M3y = M3x;
M3x = -T;
}
} else {
if (delta <= 0)
if (2 * delta + 2 * Yc - 1 <= 0)
move = 1;
else
move = 2;
else if (2 * delta - 2 * Xc - 1 <= 0)
move = 2;
else
move = 3;
switch (move) {
case 1:
Xc++;
delta += 2 * Xc + 1;
xc += M1x * xstep;
yc += M1y * ystep;
break;
case 2:
Xc++;
Yc--;
delta += 2 * Xc - 2 * Yc + 2;
xc += M2x * xstep;
yc += M2y * ystep;
break;
case 3:
Yc--;
delta -= 2 * Yc + 1;
xc += M3x * xstep;
yc += M3y * ystep;
break;
}
}
}
drawline((int)xc-ox1,(int)yc-oy1,".");
}
putdot(x, y)
{
arcmove(x, y);
put1(drawdot);
}