root/usr/src/cmd/troff/troff.d/ta.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/*        All Rights Reserved   */

/*
 * University Copyright- Copyright (c) 1982, 1986, 1988
 * The Regents of the University of California
 * All Rights Reserved
 *
 * University Acknowledgment- Portions of this document are derived from
 * software developed by the University of California, Berkeley, and its
 * contributors.
 */

/*
 *      drive hp2621 terminal
 *      just to see stuff quickly. like troff -a
 */

/*
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
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 (exactly 2 digits!), then print c
                (this wart is an optimization that shrinks output file size
                 about 35% and run-time about 15% while preserving ascii-ness)
w       paddable word space - no action needed
nb a    end of line (information only -- no action needed)
        b = space before line, a = after
pn      begin page n
#...\n  comment
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 x y u v      arc counter-clockwise from here to u,v from center
                                with center x,y from here
        D~ x y x y ...  wiggly line by x,y then x,y ...
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 character slant to n

        Subcommands like "i" are often spelled out like "init".
*/

#include        <stdio.h>
#include        <stdarg.h>
#include        <signal.h>
#include        <ctype.h>

#include "dev.h"
#define NFONT   10

int     output  = 0;    /* do we do output at all? */
int     nolist  = 0;    /* output page list if > 0 */
int     olist[20];      /* pairs of page numbers */

int     erase   = 1;
float   aspect  = 1.5;  /* default aspect ratio */
int     wflag   = 0;    /* wait, looping, for new input if on */
void    (*sigint)(int);
void    (*sigquit)(int);
void    done(void);
int     error(int, char *, ...);

struct dev dev;
struct font *fontbase[NFONT];
short   psizes[]        ={ 11, 16, 22, 36, 0};  /* approx sizes available */
short   *pstab          = psizes;
int     nsizes  = 1;
int     nfonts;
int     smnt;   /* index of first special font */
int     nchtab;
char    *chname;
short   *chtab;
char    *fitab[NFONT];
char    *widthtab[NFONT];       /* widtab would be a better name */
char    *codetab[NFONT];        /* device codes */

#define FATAL   1
#define BMASK   0377
int     dbg     = 0;
int     res     = 972;          /* input assumed computed according to this resolution */
                                /* initial value to avoid 0 divide */
FILE    *tf     = stdout;       /* output file */
char    *fontdir        = "/usr/lib/font";
extern char devname[];

FILE *fp = stdin;       /* input file pointer */

int     nowait = 0;     /* 0 => wait at bottom of each page */

int
main(int argc, char **argv)
{
        char buf[BUFSIZ];

        setbuf(stdout, buf);
        while (argc > 1 && argv[1][0] == '-') {
                switch (argv[1][1]) {
                case 'a':
                        aspect = atof(&argv[1][2]);
                        break;
                case 'e':
                        erase = 0;
                        break;
                case 'o':
                        outlist(&argv[1][2]);
                        break;
                case 'd':
                        dbg = atoi(&argv[1][2]);
                        if (dbg == 0) dbg = 1;
                        break;
                case 'w':       /* no wait at bottom of page */
                        nowait = 1;
                        break;
                }
                argc--;
                argv++;
        }

        if (argc <= 1)
                conv(stdin);
        else
                while (--argc > 0) {
                        if (strcmp(*++argv, "-") == 0)
                                fp = stdin;
                        else if ((fp = fopen(*argv, "r")) == NULL)
                                error(FATAL, "can't open %s", *argv);
                        conv(fp);
                        fclose(fp);
                }
        done();

        return (0);
}

int
outlist(char *s)        /* process list of page numbers to be printed */
{
        int n1, n2, i;

        nolist = 0;
        while (*s) {
                n1 = 0;
                if (isdigit((unsigned char)*s))
                        do
                                n1 = 10 * n1 + *s++ - '0';
                        while (isdigit((unsigned char)*s));
                else
                        n1 = -9999;
                n2 = n1;
                if (*s == '-') {
                        s++;
                        n2 = 0;
                        if (isdigit((unsigned char)*s))
                                do
                                        n2 = 10 * n2 + *s++ - '0';
                                while (isdigit((unsigned char)*s));
                        else
                                n2 = 9999;
                }
                olist[nolist++] = n1;
                olist[nolist++] = n2;
                if (*s != '\0')
                        s++;
        }
        olist[nolist] = 0;
        if (dbg)
                for (i=0; i<nolist; i += 2)
                        printf("%3d %3d\n", olist[i], olist[i+1]);

        return (0);
}

int
in_olist(int n) /* is n in olist? */
{
        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);
}

int
conv(FILE *fp)
{
        int c, k;
        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 ' ':
                case 0:         /* occasional noise creeps in */
                        break;
                case '{':       /* push down current environment */
                        t_push();
                        break;
                case '}':
                        t_pop();
                        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':
                        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 '~':       /* wiggly line */
                                drawwig(buf+1);
                                break;
                        default:
                                error(FATAL, "unknown drawing function %s\n", buf);
                                break;
                        }
                        break;
                case 's':
                        fscanf(fp, "%d", &n);   /* ignore fractional sizes */
                        setsize(t_size(n));
                        break;
                case 'f':
                        fscanf(fp, "%s", str);
                        setfont(t_font(str));
                        break;
                case 'H':       /* absolute horizontal motion */
                        /* fscanf(fp, "%d", &n); */
                        while ((c = getc(fp)) == ' ')
                                ;
                        k = 0;
                        do {
                                k = 10 * k + c - '0';
                        } while (isdigit(c = getc(fp)));
                        ungetc(c, fp);
                        hgoto(k);
                        break;
                case 'h':       /* relative horizontal motion */
                        /* fscanf(fp, "%d", &n); */
                        while ((c = getc(fp)) == ' ')
                                ;
                        k = 0;
                        do {
                                k = 10 * k + c - '0';
                        } while (isdigit(c = getc(fp)));
                        ungetc(c, fp);
                        hmot(k);
                        break;
                case 'w':       /* word space */
                        putc(' ', stdout);
                        break;
                case 'V':
                        fscanf(fp, "%d", &n);
                        vgoto(n);
                        break;
                case 'v':
                        fscanf(fp, "%d", &n);
                        vmot(n);
                        break;
                case 'p':       /* new page */
                        fscanf(fp, "%d", &n);
                        t_page(n);
                        break;
                case 'n':       /* end of line */
                        while (getc(fp) != '\n')
                                ;
                        t_newline();
                        break;
                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();
                }
        }

        return (0);
}

int
devcntrl(FILE *fp)      /* interpret device control functions */
{
        char str[20];
        int c, n;

        fscanf(fp, "%s", str);
        switch (str[0]) {       /* crude for now */
        case 'i':       /* initialize */
                fileinit();
                t_init(0);
                break;
        case 'T':       /* device name */
                fscanf(fp, "%s", devname);
                break;
        case 't':       /* trailer */
                t_trailer();
                break;
        case 'p':       /* pause -- can restart */
                t_reset('p');
                break;
        case 's':       /* stop */
                t_reset('s');
                break;
        case 'r':       /* resolution assumed when prepared */
                fscanf(fp, "%d", &res);
                break;
        case 'f':       /* font used */
                fscanf(fp, "%d %s", &n, str);
                loadfont(n, str);
                break;
        }
        while (getc(fp) != '\n')        /* skip rest of input line */
                ;

        return (0);
}

int
fileinit(void)  /* read in font and code files, etc. */
{
        return (0);
}

int
fontprint(int i)        /* debugging print of font i (0,...) */
{
        return (0);
}

int
loadcode(int n, int nw) /* load codetab on position n (0...); #chars is nw */
{
        return (0);
}

int
loadfont(int n, char *s) /* load font info for font s on position n (1...) */
{
        return (0);
}

int
error(int f, char *fmt, ...)
{
        va_list ap;

        fprintf(stderr, "ta: ");
        va_start(ap, fmt);
        (void) vfprintf(stderr, fmt, ap);
        va_end(ap);
        fprintf(stderr, "\n");
        if (f)
                exit(1);

        return (0);
}


/*
        Here beginneth all the stuff that really depends
        on the 202 (we hope).
*/


char    devname[20]     = "hp2621";

#define ESC     033
#define HOME    'H'
#define CLEAR   'J'
#define FF      014

int     size    = 1;
int     font    = 1;            /* current font */
int     hpos;           /* horizontal position where we are supposed to be next (left = 0) */
int     vpos;           /* current vertical position (down positive) */

int     horig;          /* h origin of current block; hpos rel to this */
int     vorig;          /* v origin of current block; vpos rel to this */

int     DX      = 10;   /* step size in x for drawing */
int     DY      = 10;   /* step size in y for drawing */
int     drawdot = '.';  /* draw with this character */
int     drawsize = 1;   /* shrink by this factor when drawing */

int
t_init(int reinit)      /* initialize device */
{
        int i, j;

        fflush(stdout);
        hpos = vpos = 0;

        return (0);
}

#define MAXSTATE        5

struct state {
        int     ssize;
        int     sfont;
        int     shpos;
        int     svpos;
        int     shorig;
        int     svorig;
};
struct  state   state[MAXSTATE];
struct  state   *statep = state;

int
t_push(void)    /* begin a new block */
{
        hflush();
        statep->ssize = size;
        statep->sfont = font;
        statep->shorig = horig;
        statep->svorig = vorig;
        statep->shpos = hpos;
        statep->svpos = vpos;
        horig = hpos;
        vorig = vpos;
        hpos = vpos = 0;
        if (statep++ >= state+MAXSTATE)
                error(FATAL, "{ nested too deep");
        hpos = vpos = 0;

        return (0);
}

int
t_pop(void)     /* pop to previous state */
{
        if (--statep < state)
                error(FATAL, "extra }");
        size = statep->ssize;
        font = statep->sfont;
        hpos = statep->shpos;
        vpos = statep->svpos;
        horig = statep->shorig;
        vorig = statep->svorig;

        return (0);
}

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
t_page(int 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 (0);
        }
        /* have just printed something, and seen p<n> for next one */
        putpage();
        fflush(stdout);
        if (nowait)
                return (0);

  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 (0);
        case '!':
                callunix(&buf[1]);
                fputs("!\n", stderr);
                break;
        case 'e':
                erase = 1 - erase;
                break;
        case 'w':
                wflag = 1 - wflag;
                break;
        case 'a':
                aspect = atof(&buf[1]);
                break;
        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 (0);
        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 (0);
        case 'o':
                outlist(&buf[1]);
                output = 0;
                t_init(1);
                return (0);
        case '?':
                fputs("!cmd     unix cmd\n", stderr);
                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);
                fputs("en       n=0 -> don't erase; n=1 -> erase\n", stderr);
                fputs("an       sets aspect ratio to n\n", stderr);
                break;
        default:
                fputs("?\n", stderr);
                break;
        }
        goto next;
}

int
putpage(void)
{
        int i, j, k;

        fflush(stdout);

        return (0);
}

int
t_newline(void) /* do whatever for the end of a line */
{
        printf("\n");
        hpos = 0;

        return (0);
}

int
t_size(int n)   /* convert integer to internal size number*/
{
        return (0);
}

int
t_font(char *s) /* convert string to internal font number */
{
        return (0);
}

int
t_text(char *s) /* print string s as text */
{
        int c, w=0;
        char str[100];

        if (!output)
                return (0);
        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(w);
        }

        return (0);
}

int
t_reset(int c)
{
        int n;

        output = 1;
        fflush(stdout);
        if (c == 's')
                t_page(9999);

        return (0);
}

int
t_trailer(void)
{
        return (0);
}

int
hgoto(int n)
{
        hpos = n;       /* this is where we want to be */
                        /* before printing a character, */
                        /* have to make sure it's true */

        return (0);
}

int
hmot(int n)     /* generate n units of horizontal motion */
{
        hgoto(hpos + n);

        return (0);
}

int
hflush(void)    /* actual horizontal output occurs here */
{
        return (0);
}

int
vgoto(int n)
{
        vpos = n;

        return (0);
}

int
vmot(int n)     /* generate n units of vertical motion */
{
        vgoto(vpos + n);        /* ignores rounding */

        return (0);
}

int
put1s(char *s)  /* s is a funny char name */
{
        int i;
        char *p;
        extern char *spectab[];
        static char prev[10] = "";
        static int previ;

        if (!output)
                return (0);
        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++)
                        putc(*p, stdout);
        } else
                prev[0] = 0;

        return (0);
}

int
put1(int c)     /* output char c */
{
        if (!output)
                return (0);
        putc(c, stdout);

        return (0);
}

int
setsize(int n)  /* set point size to n (internal) */
{
        return (0);
}

int
t_fp(int n, char *s)    /* font position n now contains font s */
{
        return (0);
}

int
setfont(int n)  /* set font to n */
{
        return (0);
}

void done(void)
{
        output = 1;
        putpage();
        fflush(stdout);
        exit(0);
}

int
callunix(char line[])
{
        int rc, status, unixpid;
        if( (unixpid=fork())==0 ) {
                signal(SIGINT,sigint); signal(SIGQUIT,sigquit);
                close(0); dup(2);
                execl("/bin/sh", "-sh", "-c", line, 0);
                exit(255);
        }
        else if(unixpid == -1)
                return (0);
        else{   signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN);
                while( (rc = wait(&status)) != unixpid && rc != -1 ) ;
                signal(SIGINT,(void(*)())done); signal(SIGQUIT,sigquit);
        }

        return (0);
}

int
readch(void)
{
        char c;
        if (read(2,&c,1)<1) c=0;
        return(c);
}

char *spectab[] ={
        "em", "-",
        "hy", "-",
        "en", "-",
        "ru", "_",
        "l.", ".",
        "br", "|",
        "vr", "|",
        "fm", "'",
        "or", "|",
        0, 0,
};