tLet's try this.  It's BUGGERED. - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 5cedca1b69d020c32466f70843a11767773d7e3b
 (DIR) parent 76e6aca867e3e48ea04fbcf7284c45369a69829e
 (HTM) Author: rsc <devnull@localhost>
       Date:   Sat, 15 May 2004 23:24:00 +0000
       
       Let's try this.  It's BUGGERED.
       
       Diffstat:
         A src/cmd/eqn/diacrit.c               |      75 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/e.h                     |     166 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/eqn.c                   |     741 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/eqn.y                   |     140 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/eqnbox.c                |      24 ++++++++++++++++++++++++
         A src/cmd/eqn/font.c                  |      70 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/fromto.c                |      52 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/funny.c                 |      30 ++++++++++++++++++++++++++++++
         A src/cmd/eqn/glob.c                  |      35 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/input.c                 |     289 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/integral.c              |      30 ++++++++++++++++++++++++++++++
         A src/cmd/eqn/lex.c                   |     265 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/lookup.c                |     219 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/main.c                  |     333 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/mark.c                  |      19 +++++++++++++++++++
         A src/cmd/eqn/matrix.c                |      78 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/mkfile                  |      42 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/move.c                  |      19 +++++++++++++++++++
         A src/cmd/eqn/o.eqn                   |       0 
         A src/cmd/eqn/over.c                  |      35 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/paren.c                 |     135 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/pile.c                  |      76 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/prevy.tab.h             |      57 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/shift.c                 |     116 ++++++++++++++++++++++++++++++
         A src/cmd/eqn/size.c                  |      70 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/sqrt.c                  |      35 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/text.c                  |     318 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/tuning.c                |     153 +++++++++++++++++++++++++++++++
         A src/cmd/eqn/y.tab.h                 |      57 +++++++++++++++++++++++++++++++
         A src/cmd/grap/coord.c                |      71 +++++++++++++++++++++++++++++++
         A src/cmd/grap/find                   |       1 +
         A src/cmd/grap/for.c                  |      89 +++++++++++++++++++++++++++++++
         A src/cmd/grap/frame.c                |      71 +++++++++++++++++++++++++++++++
         A src/cmd/grap/grap.h                 |     236 +++++++++++++++++++++++++++++++
         A src/cmd/grap/grap.y                 |     396 +++++++++++++++++++++++++++++++
         A src/cmd/grap/grapl.lx               |     213 +++++++++++++++++++++++++++++++
         A src/cmd/grap/input.c                |     580 +++++++++++++++++++++++++++++++
         A src/cmd/grap/label.c                |     123 +++++++++++++++++++++++++++++++
         A src/cmd/grap/main.c                 |     164 +++++++++++++++++++++++++++++++
         A src/cmd/grap/misc.c                 |     263 +++++++++++++++++++++++++++++++
         A src/cmd/grap/mkfile                 |      37 +++++++++++++++++++++++++++++++
         A src/cmd/grap/plot.c                 |     132 +++++++++++++++++++++++++++++++
         A src/cmd/grap/print.c                |     236 +++++++++++++++++++++++++++++++
         A src/cmd/grap/ticks.c                |     492 +++++++++++++++++++++++++++++++
         M src/cmd/mkfile                      |       2 +-
         A src/cmd/pic/arcgen.c                |     221 +++++++++++++++++++++++++++++++
         A src/cmd/pic/blockgen.c              |     226 +++++++++++++++++++++++++++++++
         A src/cmd/pic/boxgen.c                |     115 +++++++++++++++++++++++++++++++
         A src/cmd/pic/circgen.c               |     126 +++++++++++++++++++++++++++++++
         A src/cmd/pic/for.c                   |      95 ++++++++++++++++++++++++++++++
         A src/cmd/pic/input.c                 |     593 +++++++++++++++++++++++++++++++
         A src/cmd/pic/linegen.c               |     240 +++++++++++++++++++++++++++++++
         A src/cmd/pic/main.c                  |     282 +++++++++++++++++++++++++++++++
         A src/cmd/pic/makefile                |      39 +++++++++++++++++++++++++++++++
         A src/cmd/pic/misc.c                  |     436 +++++++++++++++++++++++++++++++
         A src/cmd/pic/mkfile                  |      38 +++++++++++++++++++++++++++++++
         A src/cmd/pic/movegen.c               |      86 ++++++++++++++++++++++++++++++
         A src/cmd/pic/pic.h                   |     219 +++++++++++++++++++++++++++++++
         A src/cmd/pic/picl.lx                 |     273 +++++++++++++++++++++++++++++++
         A src/cmd/pic/picy.y                  |     328 +++++++++++++++++++++++++++++++
         A src/cmd/pic/pltroff.c               |     357 +++++++++++++++++++++++++++++++
         A src/cmd/pic/prevy.tab.h             |      97 ++++++++++++++++++++++++++++++
         A src/cmd/pic/print.c                 |     238 +++++++++++++++++++++++++++++++
         A src/cmd/pic/symtab.c                |     104 +++++++++++++++++++++++++++++++
         A src/cmd/pic/textgen.c               |     115 +++++++++++++++++++++++++++++++
         A src/cmd/tbl/mkfile                  |      32 +++++++++++++++++++++++++++++++
         A src/cmd/tbl/t.h                     |     192 +++++++++++++++++++++++++++++++
         A src/cmd/tbl/t0.c                    |      49 +++++++++++++++++++++++++++++++
         A src/cmd/tbl/t1.c                    |      95 ++++++++++++++++++++++++++++++
         A src/cmd/tbl/t2.c                    |      25 +++++++++++++++++++++++++
         A src/cmd/tbl/t3.c                    |     104 +++++++++++++++++++++++++++++++
         A src/cmd/tbl/t4.c                    |     405 +++++++++++++++++++++++++++++++
         A src/cmd/tbl/t5.c                    |     198 +++++++++++++++++++++++++++++++
         A src/cmd/tbl/t6.c                    |     223 ++++++++++++++++++++++++++++++
         A src/cmd/tbl/t7.c                    |     150 +++++++++++++++++++++++++++++++
         A src/cmd/tbl/t8.c                    |     367 ++++++++++++++++++++++++++++++
         A src/cmd/tbl/t9.c                    |      76 +++++++++++++++++++++++++++++++
         A src/cmd/tbl/tb.c                    |     101 +++++++++++++++++++++++++++++++
         A src/cmd/tbl/tc.c                    |      65 +++++++++++++++++++++++++++++++
         A src/cmd/tbl/te.c                    |      75 +++++++++++++++++++++++++++++++
         A src/cmd/tbl/tf.c                    |      74 +++++++++++++++++++++++++++++++
         A src/cmd/tbl/tg.c                    |      81 ++++++++++++++++++++++++++++++
         A src/cmd/tbl/ti.c                    |      75 +++++++++++++++++++++++++++++++
         A src/cmd/tbl/tm.c                    |      65 +++++++++++++++++++++++++++++++
         A src/cmd/tbl/tr.c                    |      28 ++++++++++++++++++++++++++++
         A src/cmd/tbl/ts.c                    |      71 +++++++++++++++++++++++++++++++
         A src/cmd/tbl/tt.c                    |     127 +++++++++++++++++++++++++++++++
         A src/cmd/tbl/tu.c                    |     257 +++++++++++++++++++++++++++++++
         A src/cmd/tbl/tv.c                    |     183 +++++++++++++++++++++++++++++++
         A src/cmd/troff/FIXES                 |     821 ++++++++++++++++++++++++++++++
         A src/cmd/troff/README                |      31 +++++++++++++++++++++++++++++++
         A src/cmd/troff/cvt                   |      45 +++++++++++++++++++++++++++++++
         A src/cmd/troff/dwbinit.c             |     313 +++++++++++++++++++++++++++++++
         A src/cmd/troff/dwbinit.h             |      19 +++++++++++++++++++
         A src/cmd/troff/ext.h                 |     184 +++++++++++++++++++++++++++++++
         A src/cmd/troff/find                  |       1 +
         A src/cmd/troff/fns.h                 |     384 +++++++++++++++++++++++++++++++
         A src/cmd/troff/hytab.c               |     126 +++++++++++++++++++++++++++++++
         A src/cmd/troff/mbwc.c                |     165 +++++++++++++++++++++++++++++++
         A src/cmd/troff/mk.log                |     136 +++++++++++++++++++++++++++++++
         A src/cmd/troff/mkfile                |      58 ++++++++++++++++++++++++++++++
         A src/cmd/troff/n1.c                  |    1136 +++++++++++++++++++++++++++++++
         A src/cmd/troff/n10.c                 |     549 +++++++++++++++++++++++++++++++
         A src/cmd/troff/n2.c                  |     325 +++++++++++++++++++++++++++++++
         A src/cmd/troff/n3.c                  |     954 +++++++++++++++++++++++++++++++
         A src/cmd/troff/n4.c                  |     828 ++++++++++++++++++++++++++++++
         A src/cmd/troff/n5.c                  |    1149 +++++++++++++++++++++++++++++++
         A src/cmd/troff/n6.c                  |     362 +++++++++++++++++++++++++++++++
         A src/cmd/troff/n7.c                  |     834 +++++++++++++++++++++++++++++++
         A src/cmd/troff/n8.c                  |     540 +++++++++++++++++++++++++++++++
         A src/cmd/troff/n9.c                  |     488 +++++++++++++++++++++++++++++++
         A src/cmd/troff/ni.c                  |     390 +++++++++++++++++++++++++++++++
         A src/cmd/troff/suftab.c              |     612 +++++++++++++++++++++++++++++++
         A src/cmd/troff/t10.c                 |     512 +++++++++++++++++++++++++++++++
         A src/cmd/troff/t11.c                 |     255 +++++++++++++++++++++++++++++++
         A src/cmd/troff/t6.c                  |     881 ++++++++++++++++++++++++++++++
         A src/cmd/troff/tdef.h                |     670 +++++++++++++++++++++++++++++++
         A src/cmd/troff/unansi                |      49 +++++++++++++++++++++++++++++++
       
       118 files changed, 26947 insertions(+), 1 deletion(-)
       ---
 (DIR) diff --git a/src/cmd/eqn/diacrit.c b/src/cmd/eqn/diacrit.c
       t@@ -0,0 +1,75 @@
       +#include "e.h"
       +#include "y.tab.h"
       +
       +extern double Dvshift, Dhshift, Dh2shift, Dheight, Barv, Barh, Ubarv, Ubarh;
       +
       +void diacrit(int p1, int type)
       +{
       +        int c, t;
       +
       +        c = salloc();
       +        t = salloc();
       +        nrwid(p1, ps, p1);
       +        printf(".nr 10 %gm\n", max(REL(eht[p1]-ebase[p1]-1,ps), 0));        /* vert shift if high */
       +        if (type == HIGHBAR)
       +                printf(".nr 10 \\n(10+%gm\n", Dvshift);
       +        else if (type == LOWBAR)
       +                printf(".nr 10 0\n");
       +        else
       +                printf(".if \\n(ct>1 .nr 10 \\n(10+%gm\n", Dvshift);
       +        printf(".nr %d %gm\n", t, Dhshift);        /* horiz shift if high */
       +        printf(".if \\n(ct>1 .nr %d %gm\n", t, Dh2shift);        /* was .1 and .15 */
       +        switch (type) {
       +        case VEC:
       +                printf(".ds %d %s\n", c, lookup(deftbl, "vec_def")->cval);
       +                break;
       +        case DYAD:
       +                printf(".ds %d %s\n", c, lookup(deftbl, "dyad_def")->cval);
       +                break;
       +        case HAT:
       +                printf(".ds %d %s\n", c, lookup(deftbl, "hat_def")->cval);
       +                break;
       +        case TILDE:
       +                printf(".ds %d %s\n", c, lookup(deftbl, "tilde_def")->cval);
       +                break;
       +        case DOT:
       +                printf(".ds %d %s\n", c, lookup(deftbl, "dot_def")->cval);
       +                break;
       +        case DOTDOT:
       +                printf(".ds %d %s\n", c, lookup(deftbl, "dotdot_def")->cval);
       +                break;
       +        case BAR:
       +        case LOWBAR:
       +        case HIGHBAR:
       +                printf(".ds %d \\v'%gm'\\h'%gm'\\l'\\n(%du-%gm'\\h'%gm'\\v'%gm'\n",
       +                        c, -Barv, Barh, p1, 2*Barh, Barh, Barv);
       +                break;
       +        case UNDER:
       +                printf(".ds %d \\v'%gm'\\l'\\n(%du-%gm\\(ul'\\h'%gm'\\v'%gm'\n",
       +                        c, -Ubarv, p1, Ubarh, Ubarh, Ubarv);
       +                /* printf(".ds %d \\v'-%gm'\\l'\\n(%du\\(ul'\\v'%gm'\n",
       +                        c, Ubarv, p1, Ubarv);
       +                */
       +                printf(".nr %d 0\n", t);
       +                printf(".nr 10 0-.1m-%gm\n", REL(ebase[p1],ps));
       +                printf(".if \\n(ct%%2=1 .nr 10 0\\n(10-.1m\n");
       +                break;
       +        case UTILDE:
       +                printf(".ds %d %s\n", c, lookup(deftbl, "utilde_def")->cval);
       +                printf(".nr %d 0\n", t);
       +                printf(".nr 10 0-%gm\n", REL(ebase[p1],ps));
       +                printf(".if \\n(ct%%2=1 .nr 10 0\\n(10-%gm\n", 0.1);
       +                break;
       +        }
       +        nrwid(c, ps, c);
       +        if (lfont[p1] != ITAL)
       +                printf(".nr %d 0\n", t);
       +        printf(".as %d \\h'-\\n(%du-\\n(%du/2u+\\n(%du'\\v'0-\\n(10u'\\*(%d", 
       +                p1, p1, c, t, c);
       +        printf("\\v'\\n(10u'\\h'-\\n(%du+\\n(%du/2u-\\n(%du'\n", c, p1, t);
       +        if (type != UNDER && type != UTILDE)
       +                eht[p1] += EM(Dheight, ps);        /* was .15 */
       +        dprintf(".\tdiacrit: %c over S%d, lf=%c, rf=%c, h=%g, b=%g\n",
       +                type, p1, lfont[p1], rfont[p1], eht[p1], ebase[p1]);
       +        sfree(c); sfree(t);
       +}
 (DIR) diff --git a/src/cmd/eqn/e.h b/src/cmd/eqn/e.h
       t@@ -0,0 +1,166 @@
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +
       +enum charclass {
       +        OTHER, OLET, ILET, DIG, LPAR, RPAR, SLASH, PLUS, ILETF, ILETJ, VBAR,
       +        NONE, LAST
       +};
       +extern int class[LAST][LAST];
       +
       +#define        dprintf                if (dbg) printf
       +#define        max(x,y)        (((x) >= (y)) ? (x) : (y))        /* beware of side effects */
       +#define        min(x,y)        (((x) <= (y)) ? (x) : (y))
       +
       +extern        char        errbuf[200];
       +extern        char        *cmdname;
       +#define        ERROR        sprintf(errbuf,
       +#define        FATAL        ), error(1, errbuf)
       +#define        WARNING        ), error(0, errbuf)
       +#define        SYNTAX        ), yyerror(errbuf)
       +
       +#define        ROM        '1'
       +#define        ITAL        '2'
       +#define        BLD        '3'
       +#define        BDIT        '4'
       +
       +#define        DEFGAP        -999        /* default gap in piles */
       +
       +extern int        dbg;
       +extern int        ct;
       +extern int        lp[];
       +extern int        used[];                /* available registers */
       +extern int        ps;                /* dflt init pt size */
       +extern int        deltaps;        /* default change in ps */
       +extern int        dps_set;        /* 1 => -p option used */
       +extern int        gsize;                /* global size */
       +extern int        ft;                /* default font */
       +extern int        display;        /* 1 => inline, 0 => .EQ/.EN */
       +extern int        synerr;                /* 1 if syntax error in this eqn */
       +
       +extern char        *typesetter;        /* typesetter name for -T... */
       +extern int        minsize;        /* min size it can print */
       +extern int        ttype;                /* actual type of typesetter: */
       +
       +#define        DEVCAT        1
       +#define        DEV202        2
       +#define        DEVAPS        3
       +#define        DEVPOST        4
       +
       +extern double        eht[];
       +extern double        ebase[];
       +extern int        lfont[];
       +extern int        rfont[];
       +extern int        lclass[];
       +extern int        rclass[];
       +extern int        yyval;
       +extern int        yylval;
       +extern int        eqnreg;
       +extern double        eqnht;
       +extern int        lefteq, righteq;
       +extern int        markline;        /* 1 if this EQ/EN contains mark or lineup */
       +
       +#define        TBLSIZE        100
       +
       +typedef struct s_tbl {
       +        char        *name;                /* e.g., "max" or "sum" */
       +        char        *cval;                /* e.g., "\\f1max\\fP" */
       +        int        ival;                /*    or SUM */
       +        struct s_tbl *next;
       +} tbl;
       +
       +extern        char        *spaceval;        /* use in place of normal \x (for pic) */
       +
       +#define        String        01
       +#define        Macro        02
       +#define        File        04
       +#define        Char        010
       +#define        Free        040
       +
       +typedef struct infile {
       +        FILE        *fin;
       +        char        *fname;
       +        int        lineno;
       +} Infile;
       +
       +typedef struct {        /* input source */
       +        int        type;        /* Macro, String, File */
       +        char        *sp;        /* if String or Macro */
       +} Src;
       +
       +extern        Src        src[], *srcp;        /* input source stack */
       +
       +#define        MAXARGS        20
       +typedef struct {        /* argument stack */
       +        char        *argstk[MAXARGS];        /* pointers to args */
       +        char        *argval;        /* points to space containing args */
       +} Arg;
       +
       +typedef struct {        /* font number and name */
       +        int        ft;
       +        char        name[10];
       +} Font;
       +
       +extern        Font        ftstack[];
       +extern        Font        *ftp;
       +
       +extern        int        szstack[];
       +extern        int        nszstack;
       +
       +extern        Infile        infile[10];
       +extern        Infile        *curfile;
       +
       +extern        tbl        *lookup(tbl **tblp, char *name);
       +extern        void        install(tbl **tblp, char *name, char *cval, int ival);
       +extern        tbl        *keytbl[], *deftbl[], *restbl[], *ftunetbl[];
       +
       +extern        int        salloc(void);
       +extern        void        sfree(int);
       +extern        void        nrwid(int, int, int);
       +extern        char        *ABSPS(int);
       +extern        char        *DPS(int, int);
       +extern        int        EFFPS(int);
       +extern        double        EM(double, int);
       +extern        double        REL(double, int);
       +extern        char        *pad(int);
       +extern        void        getstr(char *, int);
       +extern        char        *strsave(char *);
       +
       +extern        int        input(void);
       +extern        int        unput(int);
       +extern        void        pbstr(char *);
       +extern        void        error(int, char *);
       +extern        void        yyerror(char *);
       +
       +extern        void        diacrit(int, int);
       +extern        void        eqnbox(int, int, int);
       +extern        void        setfont(char *);
       +extern        void        font(int, int);
       +extern        void        globfont(void);
       +extern        void        fatbox(int);
       +extern        void        fromto(int, int, int);
       +extern        void        funny(int);
       +extern        void        integral(int, int, int);
       +extern        void        setintegral(void);
       +extern        void        pushsrc(int, char *);
       +extern        void        popsrc(void);
       +extern        void        putout(int);
       +extern        void        text(int, char *);
       +extern void subsup(int, int, int);
       +extern void bshiftb(int, int, int);
       +extern void shift2(int, int, int);
       +extern void setsize(char *);
       +extern void size(int, int);
       +extern void globsize(void);
       +#define sqrt esqrt
       +extern void sqrt(int);
       +extern void text(int, char *);
       +extern void boverb(int, int);
       +extern void lineup(int);
       +extern void mark(int);
       +extern void paren(int, int, int);
       +extern void move(int, int, int);
       +extern void pile(int);
       +extern int startcol(int);
       +extern void column(int, int);
       +extern void matrix(int);
 (DIR) diff --git a/src/cmd/eqn/eqn.c b/src/cmd/eqn/eqn.c
       t@@ -0,0 +1,741 @@
       +#define        CONTIG        57346
       +#define        QTEXT        57347
       +#define        SPACE        57348
       +#define        THIN        57349
       +#define        TAB        57350
       +#define        MATRIX        57351
       +#define        LCOL        57352
       +#define        CCOL        57353
       +#define        RCOL        57354
       +#define        COL        57355
       +#define        ABOVE        57356
       +#define        MARK        57357
       +#define        LINEUP        57358
       +#define        SUM        57359
       +#define        INT        57360
       +#define        PROD        57361
       +#define        UNION        57362
       +#define        INTER        57363
       +#define        DEFINE        57364
       +#define        TDEFINE        57365
       +#define        NDEFINE        57366
       +#define        DELIM        57367
       +#define        GSIZE        57368
       +#define        GFONT        57369
       +#define        INCLUDE        57370
       +#define        IFDEF        57371
       +#define        DOTEQ        57372
       +#define        DOTEN        57373
       +#define        FROM        57374
       +#define        TO        57375
       +#define        OVER        57376
       +#define        SQRT        57377
       +#define        SUP        57378
       +#define        SUB        57379
       +#define        SIZE        57380
       +#define        FONT        57381
       +#define        ROMAN        57382
       +#define        ITALIC        57383
       +#define        BOLD        57384
       +#define        FAT        57385
       +#define        UP        57386
       +#define        DOWN        57387
       +#define        BACK        57388
       +#define        FWD        57389
       +#define        LEFT        57390
       +#define        RIGHT        57391
       +#define        DOT        57392
       +#define        DOTDOT        57393
       +#define        HAT        57394
       +#define        TILDE        57395
       +#define        BAR        57396
       +#define        LOWBAR        57397
       +#define        HIGHBAR        57398
       +#define        UNDER        57399
       +#define        VEC        57400
       +#define        DYAD        57401
       +#define        UTILDE        57402
       +
       +#line        17        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +#include "e.h"
       +
       +int        yylex(void);
       +extern        int        yyerrflag;
       +#ifndef        YYMAXDEPTH
       +#define        YYMAXDEPTH        150
       +#endif
       +#ifndef        YYSTYPE
       +#define        YYSTYPE        int
       +#endif
       +YYSTYPE        yylval;
       +YYSTYPE        yyval;
       +#define YYEOFCODE 1
       +#define YYERRCODE 2
       +
       +#line        140        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +
       +short        yyexca[] =
       +{-1, 0,
       +        1, 3,
       +        -2, 0,
       +-1, 1,
       +        1, -1,
       +        -2, 0,
       +};
       +#define        YYNPROD        90
       +#define        YYPRIVATE 57344
       +#define        YYLAST        469
       +short        yyact[] =
       +{
       +   4, 103, 119,  45,  27, 118, 104,   2, 102,  41,
       +  42,  43,  44,  65,  80,  81,  79,  66,  67,  68,
       +  69,  70,  50,  49,  74,  75,  76,  77, 105,  73,
       +  40,  80,  81,  80,  81, 114,  61,  64,  54,  62,
       +  57,  58,  59,  60,  55,  56,  63,  78,  91,  92,
       +  82,  26,  83,  85,  86,  87,  88,  90,  51,  52,
       +  48, 124,  50,  49, 117,  25,  45, 117,  72,  71,
       +  80,  81, 113,  24,  45,  23,  61,  64,  54,  62,
       +  57,  58,  59,  60,  55,  56,  63,  53,  89, 100,
       +  84,  22,  96,  95, 106, 107, 108, 109,  99, 110,
       + 111,  41,  42,  43,  44,  45,  98, 115,  21,  94,
       +  93,  18, 130, 123,  17, 116, 121,  46, 112, 125,
       + 127, 128,   1, 129, 126,   0,   0,  45,   8,   7,
       +   9,  10,  11,  28,  41,  42,  43,  44,   0,  16,
       +  47,  12,  34,  13,  14,  15,  61,  64,  54,  62,
       +  57,  58,  59,  60,  55,  56,  63,   0,   0,  20,
       +   0,   0,  29,  33,  30,  31,  32,  19,  37,  39,
       +  38,  36,  35,   0,   0,   0,   0,   0,   0,   0,
       +   0,   0,   0,   0,   0,   6,  97,   8,   7,   9,
       +  10,  11,  28,  41,  42,  43,  44,   0,  16,  47,
       +  12,  34,  13,  14,  15,   0,   0,   0,   0,   0,
       +   0,   0,   0,   0,   0,   0,   0,   0,  20,   0,
       +   0,  29,  33,  30,  31,  32,  19,  37,  39,  38,
       +  36,  35, 101,   0,   0,   0,   0,   0,   0,   0,
       +   0,   0,   0,   3,   6,   8,   7,   9,  10,  11,
       +  28,  41,  42,  43,  44,   0,  16,   5,  12,  34,
       +  13,  14,  15,   0,   0,   0,   0,   0,   0,   0,
       +   0,   0,   0,   0,   0,   0,  20,   0,   0,  29,
       +  33,  30,  31,  32,  19,  37,  39,  38,  36,  35,
       +   0,   0,   8,   7,   9,  10,  11,  28,  41,  42,
       +  43,  44,   6,  16,  47,  12,  34,  13,  14,  15,
       +   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       +   0,   0,   0,  20,   0,   0,  29,  33,  30,  31,
       +  32,  19,  37,  39,  38,  36,  35,   0,   0,   8,
       +   7,   9,  10,  11,  28,  41,  42,  43,  44,   6,
       +  16,   5,  12,  34,  13,  14,  15,   0,   0,   0,
       +   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       +  20,   0,   0,  29,  33,  30,  31,  32,  19,  37,
       +  39,  38,  36,  35,   8,   7,   9,  10,  11,  28,
       +  41,  42,  43,  44,   0,  16,   6,  12,  34,  13,
       +  14,  15,   0,   0,   0,   0,   0,   0,   0,   0,
       +   0,   0,   0,   0,   0,  20,   0,   0,  29,  33,
       +  30,  31,  32,  19,  37,  39,  38,  36,  35,  51,
       + 122,  48,   0,  50,  49,   0,   0,   0,   0,   0,
       +   0,   6,   0,   0, 120,  49,   0,  61,  64,  54,
       +  62,  57,  58,  59,  60,  55,  56,  63,  61,  64,
       +  54,  62,  57,  58,  59,  60,  55,  56,  63
       +};
       +short        yypact[] =
       +{
       + 241,-1000, 288,-1000,  26,-1000, 335,-1000,-1000,-1000,
       +-1000,-1000,-1000,-1000,-1000,-1000, 380, 380, 380, 380,
       + 380,  32, 335, 380, 380, 380, 380,-1000,-1000,  66,
       +-1000,-1000,-1000,  66,-1000,  29,  66,  66,  66,  66,
       +  27,-1000,-1000,-1000,-1000,  26,-1000, 380, 380,-1000,
       +-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,
       +-1000,-1000,-1000,-1000,-1000, 124,  26,  96,  96,  96,
       + -14,-1000,-1000, 183,  96,  96,  96,  96, -53,-1000,
       +-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000, 335,
       +-1000,  26, -14, 380, 380, 380, 380,-1000, 380, 380,
       +-1000,  10,  91,  53, 288, -56, 408, -14, 397,  26,
       + 408, -14,-1000,-1000,  -1,-1000,-1000, 335, 335,-1000,
       + 380,-1000, 380,-1000,-1000,-1000, 288,  50, -14,  26,
       +-1000
       +};
       +short        yypgo[] =
       +{
       +   0, 122,   6,   0, 117,   2, 116, 114, 111, 110,
       + 109, 108, 106,  98,  93,  92,  91,  89,  87,  75,
       +  73,  65,  51,   4,  47,  35,  16,  30,   1,  28
       +};
       +short        yyr1[] =
       +{
       +   0,   1,   1,   1,   2,   2,   2,   2,   4,   5,
       +   5,   6,   6,   3,   3,   3,   3,   3,   3,   3,
       +   3,   3,   3,   3,   3,   3,   3,   3,   3,   9,
       +   3,  10,   3,  12,   3,  13,   3,   3,  14,   3,
       +  15,   3,   3,   3,   3,   3,   3,   3,   3,   3,
       +  24,   3,  11,  19,  20,  21,  22,  18,  18,  18,
       +  18,  18,  18,  18,  18,  18,  18,  18,  16,  16,
       +  17,  17,  25,  25,  23,  29,  23,  27,  27,  27,
       +  27,  28,  28,   7,   8,   8,   8,   8,  26,  26
       +};
       +short        yyr2[] =
       +{
       +   0,   1,   1,   0,   1,   2,   2,   1,   2,   2,
       +   0,   2,   0,   3,   1,   1,   1,   1,   1,   1,
       +   1,   1,   1,   3,   2,   2,   2,   2,   2,   0,
       +   5,   0,   4,   0,   5,   0,   4,   1,   0,   5,
       +   0,   4,   3,   2,   2,   2,   2,   2,   2,   1,
       +   0,   5,   1,   2,   2,   2,   2,   1,   1,   1,
       +   1,   1,   1,   1,   1,   1,   1,   1,   2,   2,
       +   2,   2,   1,   2,   4,   0,   6,   1,   1,   1,
       +   1,   1,   3,   2,   1,   1,   1,   2,   1,   1
       +};
       +short        yychk[] =
       +{
       +-1000,  -1,  -2,   2,  -3,  16,  61,   5,   4,   6,
       +   7,   8,  17,  19,  20,  21,  15,  -7,  -8,  43,
       +  35, -11, -16, -19, -20, -21, -22, -23,   9,  38,
       +  40,  41,  42,  39,  18,  48,  47,  44,  46,  45,
       + -27,  10,  11,  12,  13,  -3,  -4,  16,  34,  37,
       +  36,  32,  33, -18,  52,  58,  59,  54,  55,  56,
       +  57,  50,  53,  60,  51,  -2,  -3,  -3,  -3,  -3,
       +  -3,  37,  36,  -2,  -3,  -3,  -3,  -3, -24, -26,
       +   4,   5, -26, -26,  61, -26, -26, -26, -26,  61,
       + -26,  -3,  -3,  -9, -10, -14, -15,  62, -12, -13,
       + -17,  49,  61, -28,  -2, -29,  -3,  -3,  -3,  -3,
       +  -3,  -3, -26,  62, -25, -23,  62,  14,  61,  -5,
       +  36,  -6,  33,  -5,  62, -23,  -2, -28,  -3,  -3,
       +  62
       +};
       +short        yydef[] =
       +{
       +  -2,  -2,   1,   2,   4,   7,   0,  14,  15,  16,
       +  17,  18,  19,  20,  21,  22,   0,   0,   0,   0,
       +   0,  37,   0,   0,   0,   0,   0,  49,  50,   0,
       +  84,  85,  86,   0,  52,   0,   0,   0,   0,   0,
       +   0,  77,  78,  79,  80,   5,   6,   0,   0,  29,
       +  31,  38,  40,  44,  57,  58,  59,  60,  61,  62,
       +  63,  64,  65,  66,  67,   0,  24,  25,  26,  27,
       +  28,  33,  35,  43,  45,  46,  47,  48,   0,  83,
       +  88,  89,  87,  68,  69,  53,  54,  55,  56,   0,
       +  75,   8,  23,   0,   0,   0,   0,  13,   0,   0,
       +  42,   0,   0,   0,  81,   0,  10,  32,  12,  41,
       +  10,  36,  70,  71,   0,  72,  74,   0,   0,  30,
       +   0,  39,   0,  34,  51,  73,  82,   0,   9,  11,
       +  76
       +};
       +short        yytok1[] =
       +{
       +   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       +   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       +   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       +   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       +   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       +   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       +   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       +   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       +   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       +   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       +   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       +   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       +   0,   0,   0,  61,   0,  62
       +};
       +short        yytok2[] =
       +{
       +   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,
       +  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,
       +  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
       +  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,
       +  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,
       +  52,  53,  54,  55,  56,  57,  58,  59,  60
       +};
       +long        yytok3[] =
       +{
       +   0
       +};
       +#define YYFLAG                 -1000
       +#define YYERROR                goto yyerrlab
       +#define YYACCEPT        return(0)
       +#define YYABORT                return(1)
       +#define        yyclearin        yychar = -1
       +#define        yyerrok                yyerrflag = 0
       +
       +#ifdef        yydebug
       +#include        "y.debug"
       +#else
       +#define        yydebug                0
       +char*        yytoknames[1];                /* for debugging */
       +char*        yystates[1];                /* for debugging */
       +#endif
       +
       +/*        parser for yacc output        */
       +
       +int        yynerrs = 0;                /* number of errors */
       +int        yyerrflag = 0;                /* error recovery flag */
       +
       +char*
       +yytokname(int yyc)
       +{
       +        static char x[10];
       +
       +        if(yyc > 0 && yyc <= sizeof(yytoknames)/sizeof(yytoknames[0]))
       +        if(yytoknames[yyc-1])
       +                return yytoknames[yyc-1];
       +        sprintf(x, "<%d>", yyc);
       +        return x;
       +}
       +
       +char*
       +yystatname(int yys)
       +{
       +        static char x[10];
       +
       +        if(yys >= 0 && yys < sizeof(yystates)/sizeof(yystates[0]))
       +        if(yystates[yys])
       +                return yystates[yys];
       +        sprintf(x, "<%d>\n", yys);
       +        return x;
       +}
       +
       +long
       +yylex1(void)
       +{
       +        long yychar;
       +        long *t3p;
       +        int c;
       +
       +        yychar = yylex();
       +        if(yychar <= 0) {
       +                c = yytok1[0];
       +                goto out;
       +        }
       +        if(yychar < sizeof(yytok1)/sizeof(yytok1[0])) {
       +                c = yytok1[yychar];
       +                goto out;
       +        }
       +        if(yychar >= YYPRIVATE)
       +                if(yychar < YYPRIVATE+sizeof(yytok2)/sizeof(yytok2[0])) {
       +                        c = yytok2[yychar-YYPRIVATE];
       +                        goto out;
       +                }
       +        for(t3p=yytok3;; t3p+=2) {
       +                c = t3p[0];
       +                if(c == yychar) {
       +                        c = t3p[1];
       +                        goto out;
       +                }
       +                if(c == 0)
       +                        break;
       +        }
       +        c = 0;
       +
       +out:
       +        if(c == 0)
       +                c = yytok2[1];        /* unknown char */
       +        if(yydebug >= 3)
       +                printf("lex %.4lX %s\n", yychar, yytokname(c));
       +        return c;
       +}
       +
       +int
       +yyparse(void)
       +{
       +        struct
       +        {
       +                YYSTYPE        yyv;
       +                int        yys;
       +        } yys[YYMAXDEPTH], *yyp, *yypt;
       +        short *yyxi;
       +        int yyj, yym, yystate, yyn, yyg;
       +        YYSTYPE save1, save2;
       +        int save3, save4;
       +        long yychar;
       +
       +        save1 = yylval;
       +        save2 = yyval;
       +        save3 = yynerrs;
       +        save4 = yyerrflag;
       +
       +        yystate = 0;
       +        yychar = -1;
       +        yynerrs = 0;
       +        yyerrflag = 0;
       +        yyp = &yys[-1];
       +        goto yystack;
       +
       +ret0:
       +        yyn = 0;
       +        goto ret;
       +
       +ret1:
       +        yyn = 1;
       +        goto ret;
       +
       +ret:
       +        yylval = save1;
       +        yyval = save2;
       +        yynerrs = save3;
       +        yyerrflag = save4;
       +        return yyn;
       +
       +yystack:
       +        /* put a state and value onto the stack */
       +        if(yydebug >= 4)
       +                printf("char %s in %s", yytokname(yychar), yystatname(yystate));
       +
       +        yyp++;
       +        if(yyp >= &yys[YYMAXDEPTH]) {
       +                yyerror("yacc stack overflow");
       +                goto ret1;
       +        }
       +        yyp->yys = yystate;
       +        yyp->yyv = yyval;
       +
       +yynewstate:
       +        yyn = yypact[yystate];
       +        if(yyn <= YYFLAG)
       +                goto yydefault; /* simple state */
       +        if(yychar < 0)
       +                yychar = yylex1();
       +        yyn += yychar;
       +        if(yyn < 0 || yyn >= YYLAST)
       +                goto yydefault;
       +        yyn = yyact[yyn];
       +        if(yychk[yyn] == yychar) { /* valid shift */
       +                yychar = -1;
       +                yyval = yylval;
       +                yystate = yyn;
       +                if(yyerrflag > 0)
       +                        yyerrflag--;
       +                goto yystack;
       +        }
       +
       +yydefault:
       +        /* default state action */
       +        yyn = yydef[yystate];
       +        if(yyn == -2) {
       +                if(yychar < 0)
       +                        yychar = yylex1();
       +
       +                /* look through exception table */
       +                for(yyxi=yyexca;; yyxi+=2)
       +                        if(yyxi[0] == -1 && yyxi[1] == yystate)
       +                                break;
       +                for(yyxi += 2;; yyxi += 2) {
       +                        yyn = yyxi[0];
       +                        if(yyn < 0 || yyn == yychar)
       +                                break;
       +                }
       +                yyn = yyxi[1];
       +                if(yyn < 0)
       +                        goto ret0;
       +        }
       +        if(yyn == 0) {
       +                /* error ... attempt to resume parsing */
       +                switch(yyerrflag) {
       +                case 0:   /* brand new error */
       +                        yyerror("syntax error");
       +                        if(yydebug >= 1) {
       +                                printf("%s", yystatname(yystate));
       +                                printf("saw %s\n", yytokname(yychar));
       +                        }
       +yyerrlab:
       +                        yynerrs++;
       +
       +                case 1:
       +                case 2: /* incompletely recovered error ... try again */
       +                        yyerrflag = 3;
       +
       +                        /* find a state where "error" is a legal shift action */
       +                        while(yyp >= yys) {
       +                                yyn = yypact[yyp->yys] + YYERRCODE;
       +                                if(yyn >= 0 && yyn < YYLAST) {
       +                                        yystate = yyact[yyn];  /* simulate a shift of "error" */
       +                                        if(yychk[yystate] == YYERRCODE)
       +                                                goto yystack;
       +                                }
       +
       +                                /* the current yyp has no shift onn "error", pop stack */
       +                                if(yydebug >= 2)
       +                                        printf("error recovery pops state %d, uncovers %d\n",
       +                                                yyp->yys, (yyp-1)->yys );
       +                                yyp--;
       +                        }
       +                        /* there is no state on the stack with an error shift ... abort */
       +                        goto ret1;
       +
       +                case 3:  /* no shift yet; clobber input char */
       +                        if(yydebug >= YYEOFCODE)
       +                                printf("error recovery discards %s\n", yytokname(yychar));
       +                        if(yychar == YYEOFCODE)
       +                                goto ret1;
       +                        yychar = -1;
       +                        goto yynewstate;   /* try again in the same state */
       +                }
       +        }
       +
       +        /* reduction by production yyn */
       +        if(yydebug >= 2)
       +                printf("reduce %d in:\n\t%s", yyn, yystatname(yystate));
       +
       +        yypt = yyp;
       +        yyp -= yyr2[yyn];
       +        yyval = (yyp+1)->yyv;
       +        yym = yyn;
       +
       +        /* consult goto table to find next state */
       +        yyn = yyr1[yyn];
       +        yyg = yypgo[yyn];
       +        yyj = yyg + yyp->yys + 1;
       +
       +        if(yyj >= YYLAST || yychk[yystate=yyact[yyj]] != -yyn)
       +                yystate = yyact[yyg];
       +        switch(yym) {
       +                
       +case 1:
       +#line        24        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ putout(yypt[-0].yyv); } break;
       +case 2:
       +#line        25        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ ERROR "syntax error" WARNING; } break;
       +case 3:
       +#line        26        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ eqnreg = 0; } break;
       +case 5:
       +#line        30        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ eqnbox(yypt[-1].yyv, yypt[-0].yyv, 0); } break;
       +case 6:
       +#line        31        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ eqnbox(yypt[-1].yyv, yypt[-0].yyv, 1); } break;
       +case 7:
       +#line        32        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ lineup(0); } break;
       +case 8:
       +#line        35        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = yypt[-0].yyv; lineup(1); } break;
       +case 9:
       +#line        38        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = yypt[-0].yyv; } break;
       +case 10:
       +#line        39        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = 0; } break;
       +case 11:
       +#line        42        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = yypt[-0].yyv; } break;
       +case 12:
       +#line        43        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = 0; } break;
       +case 13:
       +#line        46        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = yypt[-1].yyv; } break;
       +case 14:
       +#line        47        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ text(QTEXT, (char *) yypt[-0].yyv); } break;
       +case 15:
       +#line        48        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ text(CONTIG, (char *) yypt[-0].yyv); } break;
       +case 16:
       +#line        49        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ text(SPACE, (char *) 0); } break;
       +case 17:
       +#line        50        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ text(THIN, (char *) 0); } break;
       +case 18:
       +#line        51        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ text(TAB, (char *) 0); } break;
       +case 19:
       +#line        52        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ funny(SUM); } break;
       +case 20:
       +#line        53        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ funny(PROD); } break;
       +case 21:
       +#line        54        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ funny(UNION); } break;
       +case 22:
       +#line        55        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ funny(INTER); } break;
       +case 23:
       +#line        56        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ boverb(yypt[-2].yyv, yypt[-0].yyv); } break;
       +case 24:
       +#line        57        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ mark(yypt[-0].yyv); } break;
       +case 25:
       +#line        58        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ size(yypt[-1].yyv, yypt[-0].yyv); } break;
       +case 26:
       +#line        59        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ font(yypt[-1].yyv, yypt[-0].yyv); } break;
       +case 27:
       +#line        60        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ fatbox(yypt[-0].yyv); } break;
       +case 28:
       +#line        61        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ sqrt(yypt[-0].yyv); } break;
       +case 29:
       +#line        62        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ps -= deltaps;} break;
       +case 30:
       +#line        62        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ subsup(yypt[-4].yyv, yypt[-1].yyv, yypt[-0].yyv); } break;
       +case 31:
       +#line        63        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ps -= deltaps;} break;
       +case 32:
       +#line        63        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ subsup(yypt[-3].yyv, 0, yypt[-0].yyv); } break;
       +case 33:
       +#line        64        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ps -= deltaps;} break;
       +case 34:
       +#line        64        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ integral(yypt[-4].yyv, yypt[-1].yyv, yypt[-0].yyv); } break;
       +case 35:
       +#line        65        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ps -= deltaps;} break;
       +case 36:
       +#line        65        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ integral(yypt[-3].yyv, 0, yypt[-0].yyv); } break;
       +case 37:
       +#line        66        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ integral(yypt[-0].yyv, 0, 0); } break;
       +case 38:
       +#line        67        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ps -= deltaps;} break;
       +case 39:
       +#line        67        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ fromto(yypt[-4].yyv, yypt[-1].yyv, yypt[-0].yyv); } break;
       +case 40:
       +#line        68        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ps -= deltaps;} break;
       +case 41:
       +#line        68        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ fromto(yypt[-3].yyv, 0, yypt[-0].yyv); } break;
       +case 42:
       +#line        69        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ paren(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv); } break;
       +case 43:
       +#line        70        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ paren(yypt[-1].yyv, yypt[-0].yyv, 0); } break;
       +case 44:
       +#line        71        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ diacrit(yypt[-1].yyv, yypt[-0].yyv); } break;
       +case 45:
       +#line        72        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ move(FWD, yypt[-1].yyv, yypt[-0].yyv); } break;
       +case 46:
       +#line        73        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ move(UP, yypt[-1].yyv, yypt[-0].yyv); } break;
       +case 47:
       +#line        74        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ move(BACK, yypt[-1].yyv, yypt[-0].yyv); } break;
       +case 48:
       +#line        75        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ move(DOWN, yypt[-1].yyv, yypt[-0].yyv); } break;
       +case 49:
       +#line        76        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ pile(yypt[-0].yyv); ct = yypt[-0].yyv; } break;
       +case 50:
       +#line        77        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{yyval=ct;} break;
       +case 51:
       +#line        77        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ matrix(yypt[-3].yyv); ct = yypt[-3].yyv; } break;
       +case 52:
       +#line        80        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ setintegral(); } break;
       +case 53:
       +#line        83        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = atoi((char *) yypt[-1].yyv); } break;
       +case 54:
       +#line        84        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = atoi((char *) yypt[-1].yyv); } break;
       +case 55:
       +#line        85        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = atoi((char *) yypt[-1].yyv); } break;
       +case 56:
       +#line        86        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = atoi((char *) yypt[-1].yyv); } break;
       +case 57:
       +#line        88        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = HAT; } break;
       +case 58:
       +#line        89        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = VEC; } break;
       +case 59:
       +#line        90        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = DYAD; } break;
       +case 60:
       +#line        91        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = BAR; } break;
       +case 61:
       +#line        92        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = LOWBAR; } break;
       +case 62:
       +#line        93        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = HIGHBAR; } break;
       +case 63:
       +#line        94        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = UNDER; } break;
       +case 64:
       +#line        95        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = DOT; } break;
       +case 65:
       +#line        96        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = TILDE; } break;
       +case 66:
       +#line        97        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = UTILDE; } break;
       +case 67:
       +#line        98        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = DOTDOT; } break;
       +case 68:
       +#line        101        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = ((char *)yypt[-0].yyv)[0]; } break;
       +case 69:
       +#line        102        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = '{'; } break;
       +case 70:
       +#line        105        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = ((char *)yypt[-0].yyv)[0]; } break;
       +case 71:
       +#line        106        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = '}'; } break;
       +case 74:
       +#line        113        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ column(yypt[-3].yyv, DEFGAP); } break;
       +case 75:
       +#line        114        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{yyval=atoi((char*)yypt[-0].yyv);} break;
       +case 76:
       +#line        114        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ column(yypt[-5].yyv, yypt[-3].yyv); } break;
       +case 77:
       +#line        117        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = startcol(LCOL); } break;
       +case 78:
       +#line        118        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = startcol(CCOL); } break;
       +case 79:
       +#line        119        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = startcol(RCOL); } break;
       +case 80:
       +#line        120        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = startcol(COL); } break;
       +case 81:
       +#line        123        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ lp[ct++] = yypt[-0].yyv; } break;
       +case 82:
       +#line        124        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ lp[ct++] = yypt[-0].yyv; } break;
       +case 83:
       +#line        127        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ yyval = ps; setsize((char *) yypt[-0].yyv); } break;
       +case 84:
       +#line        130        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ static char R[]="R"; setfont(R); } break;
       +case 85:
       +#line        131        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ static char I[]="I"; setfont(I); } break;
       +case 86:
       +#line        132        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ static char B[]="B"; setfont(B); } break;
       +case 87:
       +#line        133        "/usr/local/plan9/src/cmd/eqn/eqn.y"
       +{ setfont((char *)yypt[-0].yyv); } break;
       +        }
       +        goto yystack;  /* stack new state and value */
       +}
 (DIR) diff --git a/src/cmd/eqn/eqn.y b/src/cmd/eqn/eqn.y
       t@@ -0,0 +1,140 @@
       +%term        CONTIG QTEXT SPACE THIN TAB
       +%term        MATRIX LCOL CCOL RCOL COL ABOVE
       +%term        MARK LINEUP
       +%term        SUM INT PROD UNION INTER
       +%term        DEFINE TDEFINE NDEFINE DELIM GSIZE GFONT INCLUDE SPACE IFDEF
       +%term        DOTEQ DOTEN
       +
       +%right        FROM TO
       +%left        OVER SQRT
       +%right        SUP SUB
       +%right        SIZE FONT ROMAN ITALIC BOLD FAT
       +%right        UP DOWN BACK FWD
       +%left        LEFT RIGHT
       +%right        DOT DOTDOT HAT TILDE BAR LOWBAR HIGHBAR UNDER VEC DYAD UTILDE
       +
       +%{
       +#include "e.h"
       +
       +int        yylex(void);
       +%}
       +
       +%%
       +
       +stuff        : eqn                 { putout($1); }
       +        | error                { ERROR "syntax error" WARNING; }        /* should be SYNTAX */
       +        |                { eqnreg = 0; }
       +        ;
       +
       +eqn        : box
       +        | eqn box        { eqnbox($1, $2, 0); }
       +        | eqn lineupbox        { eqnbox($1, $2, 1); }
       +        | LINEUP        { lineup(0); }
       +        ;
       +
       +lineupbox: LINEUP box        { $$ = $2; lineup(1); }
       +        ;
       +
       +sbox        : SUP box        %prec SUP        { $$ = $2; }
       +        |                %prec SUP        { $$ = 0; }
       +        ;
       +
       +tbox        : TO box        %prec TO        { $$ = $2; }
       +        |                %prec FROM        { $$ = 0; }
       +        ;
       +
       +box        : '{' eqn '}'        { $$ = $2; }
       +        | QTEXT                { text(QTEXT, (char *) $1); }
       +        | CONTIG        { text(CONTIG, (char *) $1); }
       +        | SPACE                { text(SPACE, (char *) 0); }
       +        | THIN                { text(THIN, (char *) 0); }
       +        | TAB                { text(TAB, (char *) 0); }
       +        | SUM                { funny(SUM); }
       +        | PROD                { funny(PROD); }
       +        | UNION                { funny(UNION); }
       +        | INTER                { funny(INTER); }
       +         | box OVER box                        { boverb($1, $3); }
       +        | MARK box                        { mark($2); }
       +        | size box        %prec SIZE        { size($1, $2); }
       +        | font box        %prec FONT        { font($1, $2); }
       +        | FAT box                        { fatbox($2); }
       +        | SQRT box                        { sqrt($2); }
       +        | box SUB {ps -= deltaps;} box sbox        %prec SUB        { subsup($1, $4, $5); }
       +        | box SUP {ps -= deltaps;} box                %prec SUP        { subsup($1, 0, $4); }
       +        | int SUB {ps -= deltaps;} box sbox        %prec SUB        { integral($1, $4, $5); }
       +        | int SUP {ps -= deltaps;} box                %prec SUP        { integral($1, 0, $4); }
       +        | int                                        { integral($1, 0, 0); }
       +        | box FROM {ps -= deltaps;} box tbox        %prec FROM        { fromto($1, $4, $5); }
       +        | box TO {ps -= deltaps;} box                %prec TO        { fromto($1, 0, $4); }
       +        | left eqn right                        { paren($1, $2, $3); }
       +        | left eqn                                 { paren($1, $2, 0); }
       +        | box diacrit                        { diacrit($1, $2); }
       +        | fwd box        %prec UP        { move(FWD, $1, $2); }
       +        | up box        %prec UP        { move(UP, $1, $2); }
       +        | back box        %prec UP        { move(BACK, $1, $2); }
       +        | down box        %prec UP        { move(DOWN, $1, $2); }
       +        | column                        { pile($1); ct = $1; }
       +        | MATRIX {$$=ct;} '{' collist '}'        { matrix($2); ct = $2; }
       +        ;
       +
       +int        : INT                { setintegral(); }
       +        ;
       +
       +fwd        : FWD text        { $$ = atoi((char *) $1); } ;
       +up        : UP text        { $$ = atoi((char *) $1); } ;
       +back        : BACK text        { $$ = atoi((char *) $1); } ;
       +down        : DOWN text        { $$ = atoi((char *) $1); } ;
       +
       +diacrit        : HAT                { $$ = HAT; }
       +        | VEC                { $$ = VEC; }
       +        | DYAD                { $$ = DYAD; }
       +        | BAR                { $$ = BAR; }
       +        | LOWBAR        { $$ = LOWBAR; }
       +        | HIGHBAR        { $$ = HIGHBAR; }
       +        | UNDER                { $$ = UNDER; }        /* underbar */
       +        | DOT                { $$ = DOT; }
       +        | TILDE                { $$ = TILDE; }
       +        | UTILDE        { $$ = UTILDE; }
       +        | DOTDOT        { $$ = DOTDOT; } /* umlaut = double dot */
       +        ;
       +
       +left        : LEFT text        { $$ = ((char *)$2)[0]; }
       +        | LEFT '{'        { $$ = '{'; }
       +        ;
       +
       +right        : RIGHT text        { $$ = ((char *)$2)[0]; }
       +        | RIGHT '}'        { $$ = '}'; }
       +        ;
       +
       +collist        : column
       +        | collist column
       +        ;
       +
       +column        : col '{' list '}'                                { column($1, DEFGAP); }
       +        | col text {$$=atoi((char*)$2);} '{' list '}'        { column($1, $3); }
       +        ;
       +
       +col        : LCOL                { $$ = startcol(LCOL); }
       +        | CCOL                { $$ = startcol(CCOL); }
       +        | RCOL                { $$ = startcol(RCOL); }
       +        | COL                { $$ = startcol(COL); }
       +        ;
       +
       +list        : eqn                        { lp[ct++] = $1; }
       +        | list ABOVE eqn        { lp[ct++] = $3; }
       +        ;
       +
       +size        : SIZE text        { $$ = ps; setsize((char *) $2); }
       +        ;
       +
       +font    : ROMAN         { static char R[]="R"; setfont(R); }
       +        | ITALIC        { static char I[]="I"; setfont(I); }
       +        | BOLD          { static char B[]="B"; setfont(B); }
       +        | FONT text     { setfont((char *)$2); }
       +        ;
       +
       +text        : CONTIG
       +        | QTEXT
       +        ;
       +
       +%%
 (DIR) diff --git a/src/cmd/eqn/eqnbox.c b/src/cmd/eqn/eqnbox.c
       t@@ -0,0 +1,24 @@
       +#include "e.h"
       +
       +void eqnbox(int p1, int p2, int lu)
       +{
       +        double b, h;
       +        char *sh;
       +        extern char *IRspace;
       +
       +        yyval = p1;
       +        b = max(ebase[p1], ebase[p2]);
       +        eht[yyval] = h = b + max(eht[p1]-ebase[p1], 
       +                eht[p2]-ebase[p2]);
       +        ebase[yyval] = b;
       +        dprintf(".\tS%d <- %d %d; b=%g, h=%g\n", yyval, p1, p2, b, h);
       +        sh = pad(class[rclass[p1]][lclass[p2]]);
       +        if (lu) {
       +                printf(".nr %d \\w'\\*(%d%s'\n", p1, p1, sh);
       +                printf(".ds %d \\h'|\\n(09u-\\n(%du'\\*(%d\n", p1, p1, p1);
       +        }
       +        printf(".as %d \"%s\\*(%d\n", yyval, sh, p2);
       +        rfont[p1] = rfont[p2];
       +        rclass[p1] = rclass[p2];
       +        sfree(p2);
       +}
 (DIR) diff --git a/src/cmd/eqn/font.c b/src/cmd/eqn/font.c
       t@@ -0,0 +1,70 @@
       +# include "e.h"
       +
       +void setfont(char *ch1)
       +{
       +        yyval = ft;
       +        if (strcmp(ch1, "I") == 0) {        /* I and italic mean merely position 2 */
       +                *ch1 = '2';
       +                ft = ITAL;
       +        } else if (strcmp(ch1, "B") == 0) {        /* and similarly for B & bold */
       +                *ch1 = '3';
       +                ft = BLD;
       +        } else if (strcmp(ch1, "R") == 0) {        /* and R and roman */
       +                *ch1 = '1';
       +                ft = ROM;
       +        } else {
       +                ft = ROM;        /* assume it's a roman style */
       +        }
       +        ftp++;
       +        if (ftp >= &ftstack[10])
       +                ERROR "font stack overflow (10)" FATAL;
       +        ftp->ft = ft;
       +        if (ch1[1] == 0) {        /* 1-char name */
       +                ftp->name[0] = *ch1;
       +                ftp->name[1] = '\0';
       +        } else
       +                sprintf(ftp->name, "(%s", ch1);
       +        dprintf(".\tsetfont %s %c\n", ch1, ft);
       +}
       +
       +void font(int p1, int p2)
       +{
       +                /* old font in p1, new in ft */
       +        yyval = p2;
       +        lfont[yyval] = rfont[yyval] = ft==ITAL ? ITAL : ROM;
       +        ftp--;
       +        ft = p1;
       +}
       +
       +void globfont(void)
       +{
       +        char temp[20];
       +
       +        getstr(temp, sizeof(temp));
       +        yyval = eqnreg = 0;
       +        if (strcmp(temp, "I") == 0 || strncmp(temp, "it", 2) == 0) {
       +                ft = ITAL;
       +                strcpy(temp, "2");
       +        } else if (strcmp(temp, "B") == 0 || strncmp(temp, "bo", 2) == 0) {
       +                ft = BLD;
       +                strcpy(temp, "3");
       +        } else if (strcmp(temp, "R") == 0 || strncmp(temp, "ro", 2) == 0) {
       +                ft = ROM;
       +                strcpy(temp, "1");
       +        } else { 
       +                ft = ROM;        /* assume it's a roman style */
       +        }
       +        ftstack[0].ft = ft;
       +        if (temp[1] == 0)        /* 1-char name */
       +                strcpy(ftstack[0].name, temp);
       +        else
       +                sprintf(ftstack[0].name, "(%.2s", temp);
       +}
       +
       +void fatbox(int p)
       +{
       +        extern double Fatshift;
       +
       +        yyval = p;
       +        printf(".ds %d \\*(%d\\h'-\\w'\\*(%d'u+%gm'\\*(%d\n", p, p, p, Fatshift, p);
       +}
 (DIR) diff --git a/src/cmd/eqn/fromto.c b/src/cmd/eqn/fromto.c
       t@@ -0,0 +1,52 @@
       +# include "e.h"
       +
       +void fromto(int p1, int p2, int p3)
       +{
       +        double b, h1, b1, t;
       +        int subps;
       +
       +        yyval = salloc();
       +        lfont[yyval] = rfont[yyval] = 0;
       +        h1 = eht[yyval] = eht[p1];
       +        b1 = ebase[p1];
       +        b = 0;
       +        subps = ps;
       +        ps += deltaps;
       +        nrwid(p1, ps, p1);
       +        printf(".nr %d \\n(%d\n", yyval, p1);
       +        if (p2 > 0) {
       +                nrwid(p2, subps, p2);
       +                printf(".if \\n(%d>\\n(%d .nr %d \\n(%d\n", p2, yyval, yyval, p2);
       +                eht[yyval] += eht[p2];
       +                b = eht[p2];
       +        }
       +        if (p3 > 0) {
       +                nrwid(p3, subps, p3);
       +                printf(".if \\n(%d>\\n(%d .nr %d \\n(%d\n", p3, yyval, yyval, p3);
       +                eht[yyval] += eht[p3];
       +        }
       +        printf(".ds %d ", yyval);        /* bottom of middle box */
       +        if (p2 > 0) {
       +                t = eht[p2]-ebase[p2]+b1;
       +                printf("\\v'%gm'\\h'\\n(%du-\\n(%du/2u'%s\\*(%d%s", 
       +                        REL(t,ps), yyval, p2, DPS(ps,subps), p2, DPS(subps,ps));
       +                printf("\\h'-\\n(%du-\\n(%du/2u'\\v'%gm'\\\n", 
       +                        yyval, p2, REL(-t,ps));
       +        }
       +        printf("\\h'\\n(%du-\\n(%du/2u'\\*(%d\\h'\\n(%du-\\n(%du/2u'\\\n", 
       +                yyval, p1, p1, yyval, p1);
       +        if (p3  >0) {
       +                t = h1-b1+ebase[p3];
       +                printf("\\v'%gm'\\h'-\\n(%du-\\n(%du/2u'%s\\*(%d%s\\h'\\n(%du-\\n(%du/2u'\\v'%gm'\\\n", 
       +                        REL(-t,ps), yyval, p3, DPS(ps,subps), p3, DPS(subps,ps), yyval, p3, REL(t,ps));
       +        }
       +        printf("\n");
       +        ebase[yyval] = b + b1;
       +        dprintf(".\tS%d <- %d from %d to %d; h=%g b=%g\n", 
       +                yyval, p1, p2, p3, eht[yyval], ebase[yyval]);
       +        sfree(p1);
       +        if (p2 > 0)
       +                sfree(p2);
       +        if (p3 > 0)
       +                sfree(p3);
       +}
 (DIR) diff --git a/src/cmd/eqn/funny.c b/src/cmd/eqn/funny.c
       t@@ -0,0 +1,30 @@
       +#include "e.h"
       +#include "y.tab.h"
       +
       +extern int Funnyps;
       +extern double Funnyht, Funnybase;
       +
       +void funny(int n)
       +{
       +        char *f = 0;
       +
       +        yyval = salloc();
       +        switch (n) {
       +        case SUM:
       +                f = lookup(deftbl, "sum_def")->cval; break;
       +        case UNION:
       +                f = lookup(deftbl, "union_def")->cval; break;
       +        case INTER:        /* intersection */
       +                f = lookup(deftbl, "inter_def")->cval; break;
       +        case PROD:
       +                f = lookup(deftbl, "prod_def")->cval; break;
       +        default:
       +                ERROR "funny type %d in funny", n FATAL;
       +        }
       +        printf(".ds %d %s\n", yyval, f);
       +        eht[yyval] = EM(1.0, ps+Funnyps) - EM(Funnyht, ps);
       +        ebase[yyval] = EM(Funnybase, ps);
       +        dprintf(".\tS%d <- %s; h=%g b=%g\n", 
       +                yyval, f, eht[yyval], ebase[yyval]);
       +        lfont[yyval] = rfont[yyval] = ROM;
       +}
 (DIR) diff --git a/src/cmd/eqn/glob.c b/src/cmd/eqn/glob.c
       t@@ -0,0 +1,35 @@
       +#include "e.h"
       +
       +        /* YOU MAY WANT TO CHANGE THIS */
       +char        *typesetter = "post";        /* type of typesetter today */
       +int        ttype        = DEVPOST;
       +int        minsize        = 4;                /* min size it can handle */
       +
       +
       +int        dbg;                /* debugging print if non-zero */
       +int        lp[200];        /* stack for things like piles and matrices */
       +int        ct;                /* pointer to lp */
       +int        used[100];        /* available registers */
       +int        ps;                /* default init point size */
       +int        deltaps        = 3;        /* default change in ps */
       +int        dps_set = 0;        /* 1 => -p option used */
       +int        gsize        = 10;        /* default initial point size */
       +int        ft        = '2';
       +Font        ftstack[10] = { '2', "2" };        /* bottom is global font */
       +Font        *ftp        = ftstack;
       +int        szstack[10];        /* non-zero if absolute size set at this level */
       +int        nszstack = 0;
       +int        display        = 0;        /* 1=>display, 0=>.EQ/.EN */
       +
       +int        synerr;                /* 1 if syntax err in this eqn */
       +double        eht[100];        /* height in ems at gsize */
       +double        ebase[100];        /* base: where one enters above bottom */
       +int        lfont[100];        /* leftmost and rightmost font associated with this thing */
       +int        rfont[100];
       +int        lclass[100];        /* leftmost and rightmost class associated with this thing */
       +int        rclass[100];
       +int        eqnreg;                /* register where final string appears */
       +double        eqnht;                /* final height of equation */
       +int        lefteq        = '\0';        /* left in-line delimiter */
       +int        righteq        = '\0';        /* right in-line delimiter */
       +int        markline = 0;        /* 1 if this EQ/EN contains mark; 2 if lineup */
 (DIR) diff --git a/src/cmd/eqn/input.c b/src/cmd/eqn/input.c
       t@@ -0,0 +1,289 @@
       +#include "e.h"
       +#include "y.tab.h"
       +#include <ctype.h>
       +#include <errno.h>
       +
       +Infile        infile[10];
       +Infile        *curfile = infile;
       +
       +#define        MAXSRC        50
       +Src        src[MAXSRC];        /* input source stack */
       +Src        *srcp        = src;
       +
       +extern int getarg(char *);
       +extern        void eprint(void);
       +
       +void pushsrc(int type, char *ptr)        /* new input source */
       +{
       +        if (++srcp >= src + MAXSRC)
       +                ERROR "inputs nested too deep" FATAL;
       +        srcp->type = type;
       +        srcp->sp = ptr;
       +        if (dbg > 1) {
       +                printf("\n%3d ", srcp - src);
       +                switch (srcp->type) {
       +                case File:
       +                        printf("push file %s\n", ((Infile *)ptr)->fname);
       +                        break;
       +                case Macro:
       +                        printf("push macro <%s>\n", ptr);
       +                        break;
       +                case Char:
       +                        printf("push char <%c>\n", *ptr);
       +                        break;
       +                case String:
       +                        printf("push string <%s>\n", ptr);
       +                        break;
       +                case Free:
       +                        printf("push free <%s>\n", ptr);
       +                        break;
       +                default:
       +                        ERROR "pushed bad type %d\n", srcp->type FATAL;
       +                }
       +        }
       +}
       +
       +void popsrc(void)        /* restore an old one */
       +{
       +        if (srcp <= src)
       +                ERROR "too many inputs popped" FATAL;
       +        if (dbg > 1) {
       +                printf("%3d ", srcp - src);
       +                switch (srcp->type) {
       +                case File:
       +                        printf("pop file\n");
       +                        break;
       +                case Macro:
       +                        printf("pop macro\n");
       +                        break;
       +                case Char:
       +                        printf("pop char <%c>\n", *srcp->sp);
       +                        break;
       +                case String:
       +                        printf("pop string\n");
       +                        break;
       +                case Free:
       +                        printf("pop free\n");
       +                        break;
       +                default:
       +                        ERROR "pop weird input %d\n", srcp->type FATAL;
       +                }
       +        }
       +        srcp--;
       +}
       +
       +Arg        args[10];        /* argument frames */
       +Arg        *argfp = args;        /* frame pointer */
       +int        argcnt;                /* number of arguments seen so far */
       +
       +void dodef(tbl *stp)        /* collect args and switch input to defn */
       +{
       +        int i, len;
       +        char *p;
       +        Arg *ap;
       +
       +        ap = argfp+1;
       +        if (ap >= args+10)
       +                ERROR "more than arguments\n" FATAL;
       +        argcnt = 0;
       +        if (input() != '(')
       +                ERROR "disaster in dodef\n"FATAL;
       +        if (ap->argval == 0)
       +                ap->argval = malloc(1000);
       +        for (p = ap->argval; (len = getarg(p)) != -1; p += len) {
       +                ap->argstk[argcnt++] = p;
       +                if (input() == ')')
       +                        break;
       +        }
       +        for (i = argcnt; i < MAXARGS; i++)
       +                ap->argstk[i] = "";
       +        if (dbg)
       +                for (i = 0; i < argcnt; i++)
       +                        printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
       +        argfp = ap;
       +        pushsrc(Macro, stp->cval);
       +}
       +
       +getarg(char *p)        /* pick up single argument, store in p, return length */
       +{
       +        int n, c, npar;
       +
       +        n = npar = 0;
       +        for ( ;; ) {
       +                c = input();
       +                if (c == EOF)
       +                        ERROR "end of file in getarg!\n" FATAL;
       +                if (npar == 0 && (c == ',' || c == ')'))
       +                        break;
       +                if (c == '"')        /* copy quoted stuff intact */
       +                        do {
       +                                *p++ = c;
       +                                n++;
       +                        } while ((c = input()) != '"' && c != EOF);
       +                else if (c == '(')
       +                        npar++;
       +                else if (c == ')')
       +                        npar--;
       +                n++;
       +                *p++ = c;
       +        }
       +        *p = 0;
       +        unput(c);
       +        return(n + 1);
       +}
       +
       +#define        PBSIZE        2000
       +char        pbuf[PBSIZE];                /* pushback buffer */
       +char        *pb        = pbuf-1;        /* next pushed back character */
       +
       +char        ebuf[200];                /* collect input here for error reporting */
       +char        *ep        = ebuf;
       +
       +input(void)
       +{
       +        register int c = 0;
       +
       +  loop:
       +        switch (srcp->type) {
       +        case File:
       +                c = getc(curfile->fin);
       +                if (c == EOF) {
       +                        if (curfile == infile)
       +                                break;
       +                        if (curfile->fin != stdin) {
       +                                fclose(curfile->fin);
       +                                free(curfile->fname);        /* assumes allocated */
       +                        }
       +                        curfile--;
       +                        printf(".lf %d %s\n", curfile->lineno, curfile->fname);
       +                        popsrc();
       +                        goto loop;
       +                }
       +                if (c == '\n')
       +                        curfile->lineno++;
       +                break;
       +        case Char:
       +                if (pb >= pbuf) {
       +                        c = *pb--;
       +                        popsrc();
       +                        break;
       +                } else {        /* can't happen? */
       +                        popsrc();
       +                        goto loop;
       +                }
       +        case String:
       +                c = *srcp->sp++;
       +                if (c == '\0') {
       +                        popsrc();
       +                        goto loop;
       +                } else {
       +                        if (*srcp->sp == '\0')        /* empty, so pop */
       +                                popsrc();
       +                        break;
       +                }
       +        case Macro:
       +                c = *srcp->sp++;
       +                if (c == '\0') {
       +                        if (--argfp < args)
       +                                ERROR "argfp underflow" FATAL;
       +                        popsrc();
       +                        goto loop;
       +                } else if (c == '$' && isdigit(*srcp->sp)) {
       +                        int n = 0;
       +                        while (isdigit(*srcp->sp))
       +                                n = 10 * n + *srcp->sp++ - '0';
       +                        if (n > 0 && n <= MAXARGS)
       +                                pushsrc(String, argfp->argstk[n-1]);
       +                        goto loop;
       +                }
       +                break;
       +        case Free:        /* free string */
       +                free(srcp->sp);
       +                popsrc();
       +                goto loop;
       +        }
       +        if (ep >= ebuf + sizeof ebuf)
       +                ep = ebuf;
       +        *ep++ = c;
       +        return c;
       +}
       +
       +
       +unput(int c)
       +{
       +        if (++pb >= pbuf + sizeof pbuf)
       +                ERROR "pushback overflow\n"FATAL;
       +        if (--ep < ebuf)
       +                ep = ebuf + sizeof(ebuf) - 1;
       +        *pb = c;
       +        pushsrc(Char, pb);
       +        return c;
       +}
       +
       +void pbstr(char *s)
       +{
       +        pushsrc(String, s);
       +}
       +
       +void error(int die, char *s)
       +{
       +        extern char *cmdname;
       +
       +        if (synerr)
       +                return;
       +        fprintf(stderr, "%s: ", cmdname);
       +        fprintf(stderr, s);
       +        if (errno > 0)
       +                perror("???");
       +        if (curfile->fin)
       +                fprintf(stderr, " near %s:%d",
       +                        curfile->fname, curfile->lineno+1);
       +        fprintf(stderr, "\n");
       +        eprint();
       +        synerr = 1;
       +        errno = 0;
       +        if (die) {
       +                if (dbg)
       +                        abort();
       +                else
       +                        exit(1);
       +        }
       +}
       +
       +void yyerror(char *s)
       +{
       +        error(0, s);        /* temporary */
       +}
       +
       +char errbuf[200];
       +
       +void eprint(void)        /* try to print context around error */
       +{
       +        char *p, *q;
       +
       +        if (ep == ebuf)
       +                return;                                /* no context */
       +        p = ep - 1;
       +        if (p > ebuf && *p == '\n')
       +                p--;
       +        for ( ; p >= ebuf && *p != '\n'; p--)
       +                ;
       +        while (*p == '\n')
       +                p++;
       +        fprintf(stderr, " context is\n\t");
       +        for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
       +                ;
       +        while (p < q)
       +                putc(*p++, stderr);
       +        fprintf(stderr, " >>> ");
       +        while (p < ep)
       +                putc(*p++, stderr);
       +        fprintf(stderr, " <<< ");
       +        while (pb >= pbuf)
       +                putc(*pb--, stderr);
       +        if (curfile->fin)
       +                fgets(ebuf, sizeof ebuf, curfile->fin);
       +        fprintf(stderr, "%s", ebuf);
       +        pbstr("\n.EN\n");        /* safety first */
       +        ep = ebuf;
       +}
 (DIR) diff --git a/src/cmd/eqn/integral.c b/src/cmd/eqn/integral.c
       t@@ -0,0 +1,30 @@
       +#include "e.h"
       +#include "y.tab.h"
       +
       +extern int Intps;
       +extern double Intht, Intbase, Int1h, Int1v, Int2h, Int2v;
       +
       +void integral(int p, int p1, int p2)
       +{
       +        if (p1 != 0)
       +                printf(".ds %d \\h'%gm'\\v'%gm'\\*(%d\\v'%gm'\n", p1, -Int1h, Int1v, p1, -Int1v);
       +        if (p2 != 0)
       +                printf(".ds %d \\v'%gm'\\h'%gm'\\*(%d\\v'%gm'\n", p2, -Int2v, Int2h, p2, Int2v);
       +        if (p1 != 0 && p2 != 0)
       +                shift2(p, p1, p2);
       +        else if (p1 != 0)
       +                bshiftb(p, SUB, p1);
       +        else if (p2 != 0)
       +                bshiftb(p, SUP, p2);
       +        dprintf(".\tintegral: S%d; h=%g b=%g\n", p, eht[p], ebase[p]);
       +        lfont[p] = ROM;
       +}
       +
       +void setintegral(void)
       +{
       +        yyval = salloc();
       +        printf(".ds %d %s\n", yyval, lookup(deftbl, "int_def")->cval);
       +        eht[yyval] = EM(Intht, ps+Intps);
       +        ebase[yyval] = EM(Intbase, ps);
       +        lfont[yyval] = rfont[yyval] = ROM;
       +}
 (DIR) diff --git a/src/cmd/eqn/lex.c b/src/cmd/eqn/lex.c
       t@@ -0,0 +1,265 @@
       +#include "e.h"
       +#include "y.tab.h"
       +#include <ctype.h>
       +
       +#define        SSIZE        1000
       +char        token[SSIZE];
       +int        sp;
       +
       +void        space(void);
       +void        dodef(tbl *);
       +void        define(int);
       +void        ifdef(void);
       +void        include(void);
       +void        delim(void);
       +
       +yylex(void)
       +{
       +        register int c;
       +        tbl *tp;
       +
       +  begin:
       +        while ((c = input()) == ' ' || c == '\n' || c == '\t')
       +                ;
       +        yylval = c;
       +        switch (c) {
       +        case EOF:
       +                ERROR "unexpected end of input inside equation" WARNING;
       +                return(EOF);
       +        case '~':
       +                return(SPACE);
       +        case '^':
       +                return(THIN);
       +        /* case '\t':
       +                return(TAB);
       +        */
       +        case '{':
       +                return('{');
       +        case '}':
       +                return('}');
       +        case '"':
       +                for (sp = 0; (c=input())!='"' && c != '\n'; ) {
       +                        if (c == '\\')
       +                                if ((c = input()) != '"')
       +                                        token[sp++] = '\\';
       +                        token[sp++] = c;
       +                        if (sp >= SSIZE)
       +                                ERROR "quoted string %.20s... too long", token FATAL;
       +                }
       +                token[sp] = '\0';
       +                yylval = (int) &token[0];
       +                if (c == '\n')
       +                        ERROR "missing \" in %.20s", token WARNING;
       +                return(QTEXT);
       +        }
       +        if (!display && c == righteq)
       +                return(EOF);
       +
       +        unput(c);
       +        getstr(token, SSIZE);
       +        dprintf(".\tlex token = |%s|\n", token);
       +        if ((tp = lookup(deftbl, token)) != NULL) {        /* defined term */
       +                c = input();
       +                unput(c);
       +                if (c == '(')        /* macro with args */
       +                        dodef(tp);
       +                else {                /* no args */
       +                        unput(' ');
       +                        pbstr(tp->cval);
       +                        dprintf(".\tfound %s|=%s|\n", token, tp->cval);
       +                }
       +                goto begin;
       +        }
       +
       +        if ((tp = lookup(keytbl, token)) == NULL)        /* not a keyword */
       +                return CONTIG;
       +
       +        switch (tp->ival) {                /* some kind of keyword */
       +        case DEFINE: case TDEFINE: case NDEFINE:
       +                define(tp->ival);
       +                break;
       +        case IFDEF:
       +                ifdef();
       +                break;
       +        case DELIM:
       +                delim();
       +                break;
       +        case GSIZE:
       +                globsize();
       +                break;
       +        case GFONT:
       +                globfont();
       +                break;
       +        case INCLUDE:
       +                include();
       +                break;
       +        case SPACE:
       +                space();
       +                break;
       +        case DOTEQ:
       +                        /* .EQ inside equation -- should warn if at bottom level */
       +                break;
       +        case DOTEN:
       +                if (curfile == infile)
       +                        return EOF;
       +                /* else ignore nested .EN */
       +                break;
       +        default:
       +                return tp->ival;
       +        }
       +        goto begin;
       +}
       +
       +void getstr(char *s, int n)
       +{
       +        register int c;
       +        register char *p;
       +
       +        p = s;
       +        while ((c = input()) == ' ' || c == '\n')
       +                ;
       +        if (c == EOF) {
       +                *s = 0;
       +                return;
       +        }
       +        while (c != ' ' && c != '\t' && c != '\n' && c != '{' && c != '}'
       +            && c != '"' && c != '~' && c != '^') {
       +                if (!display && c == righteq)
       +                        break;
       +                if (c == '(' && p > s) {        /* might be defined(...) */
       +                        *p = '\0';
       +                        if (lookup(deftbl, s) != NULL)
       +                                break;
       +                }
       +                if (c == '\\')
       +                        if ((c = input()) != '"')
       +                                *p++ = '\\';
       +                *p++ = c;
       +                if (--n <= 0)
       +                        ERROR "token %.20s... too long", s FATAL;
       +                c = input();
       +        }
       +        unput(c);
       +        *p = '\0';
       +        yylval = (int) s;
       +}
       +
       +cstr(char *s, int quote, int maxs)
       +{
       +        int del, c, i;
       +
       +        s[0] = 0;
       +        while ((del=input()) == ' ' || del == '\t')
       +                ;
       +        if (quote)
       +                for (i=0; (c=input()) != del && c != EOF;) {
       +                        s[i++] = c;
       +                        if (i >= maxs)
       +                                return(1);        /* disaster */
       +                }
       +        else {
       +                if (del == '\n')
       +                        return(1);
       +                s[0] = del;
       +                for (i=1; (c=input())!=' ' && c!= '\t' && c!='\n' && c!=EOF;) {
       +                        s[i++] = c;
       +                        if (i >= maxs)
       +                                return(1);        /* disaster */
       +                }
       +        }
       +        s[i] = '\0';
       +        if (c == EOF)
       +                ERROR "Unexpected end of input at %.20s", s FATAL;
       +        return(0);
       +}
       +
       +void define(int type)
       +{
       +        char *p1, *p2;
       +        extern int ftune(char *, char *);
       +
       +        getstr(token, SSIZE);        /* get name */
       +        if (type != DEFINE) {
       +                cstr(token, 1, SSIZE);        /* skip the definition too */
       +                return;
       +        }
       +        p1 = strsave(token);
       +        if (cstr(token, 1, SSIZE))
       +                ERROR "Unterminated definition at %.20s", token FATAL;
       +        if (lookup(ftunetbl, p1) != NULL) {        /* double tuning param */
       +                dprintf(".\ttune %s %s\n", p1, token);
       +                ftune(p1, token);
       +        } else {
       +                p2 = strsave(token);
       +                install(deftbl, p1, p2, 0);
       +                dprintf(".\tname %s defined as %s\n", p1, p2);
       +        }
       +}
       +
       +void ifdef(void)                /* do body if name is defined */
       +{
       +        char name[100], *p;
       +
       +        getstr(name, sizeof(name));        /* get name */
       +        cstr(token, 1, SSIZE);                /* and body */
       +        if (lookup(deftbl, name) != NULL) {        /* found it */
       +                p = strsave(token);
       +                pushsrc(Free, p);
       +                pushsrc(String, p);
       +        }
       +}
       +
       +char        *spaceval        = NULL;
       +
       +void space(void)        /* collect line of form "space amt" to replace \x in output */
       +{
       +        getstr(token, SSIZE);
       +        spaceval = strsave(token);
       +        dprintf(".\tsetting spaceval to %s\n", token);
       +}
       +
       +char *strsave(char *s)
       +{
       +        register char *q;
       +
       +        q = malloc(strlen(s)+1);
       +        if (q == NULL)
       +                ERROR "out of space in strsave on %s", s FATAL;
       +        strcpy(q, s);
       +        return(q);
       +}
       +
       +void include(void)
       +{
       +        char name[100];
       +        FILE *fin;
       +        int c;
       +        extern int errno;
       +
       +        while ((c = input()) == ' ')
       +                ;
       +        unput(c);
       +        cstr(name, c == '"', sizeof(name));        /* gets it quoted or not */
       +        if ((fin = fopen(name, "r")) == NULL)
       +                ERROR "can't open file %s", name FATAL;
       +        errno = 0;
       +        curfile++;
       +        curfile->fin = fin;
       +        curfile->fname = strsave(name);
       +        curfile->lineno = 0;
       +        printf(".lf 1 %s\n", curfile->fname);
       +        pushsrc(File, curfile->fname);
       +}
       +
       +void delim(void)
       +{
       +        yyval = eqnreg = 0;
       +        if (cstr(token, 0, SSIZE))
       +                ERROR "Bizarre delimiters" FATAL;
       +        lefteq = token[0];
       +        righteq = token[1];
       +        if (!isprint(lefteq) || !isprint(righteq))
       +                ERROR "Bizarre delimiters" FATAL;
       +        if (lefteq == 'o' && righteq == 'f')
       +                lefteq = righteq = '\0';
       +}
 (DIR) diff --git a/src/cmd/eqn/lookup.c b/src/cmd/eqn/lookup.c
       t@@ -0,0 +1,219 @@
       +#include "e.h"
       +#include "y.tab.h"
       +
       +tbl        *keytbl[TBLSIZE];        /* key words */
       +tbl        *restbl[TBLSIZE];        /* reserved words */
       +tbl        *deftbl[TBLSIZE];        /* user-defined names */
       +
       +struct keyword {
       +        char        *key;
       +        int        keyval;
       +} keyword[]        ={
       +        "sub",                 SUB, 
       +        "sup",                 SUP, 
       +        ".EN",                 DOTEN,
       +        ".EQ",                DOTEQ, 
       +        "from",         FROM, 
       +        "to",                 TO, 
       +        "sum",                 SUM, 
       +        "hat",                 HAT, 
       +        "vec",                 VEC, 
       +        "dyad",         DYAD, 
       +        "dot",                 DOT, 
       +        "dotdot",         DOTDOT, 
       +        "bar",                 BAR,
       +        "lowbar",        LOWBAR,
       +        "highbar",        HIGHBAR, 
       +        "tilde",         TILDE, 
       +        "utilde",         UTILDE, 
       +        "under",         UNDER, 
       +        "prod",         PROD, 
       +        "int",                 INT, 
       +        "integral",         INT, 
       +        "union",         UNION, 
       +        "inter",         INTER, 
       +        "matrix",         MATRIX, 
       +        "col",                 COL, 
       +        "lcol",         LCOL, 
       +        "ccol",         CCOL, 
       +        "rcol",         RCOL, 
       +        "pile",         COL,        /* synonyms ... */ 
       +        "lpile",         LCOL, 
       +        "cpile",         CCOL, 
       +        "rpile",         RCOL, 
       +        "over",         OVER, 
       +        "sqrt",         SQRT, 
       +        "above",         ABOVE, 
       +        "size",         SIZE, 
       +        "font",         FONT, 
       +        "fat",                 FAT, 
       +        "roman",         ROMAN, 
       +        "italic",         ITALIC, 
       +        "bold",         BOLD, 
       +        "left",         LEFT, 
       +        "right",         RIGHT, 
       +        "delim",         DELIM, 
       +        "define",         DEFINE, 
       +        "tdefine",         DEFINE, 
       +        "ndefine",         NDEFINE, 
       +        "ifdef",        IFDEF,
       +        "gsize",         GSIZE, 
       +        ".gsize",         GSIZE, 
       +        "gfont",         GFONT, 
       +        "include",         INCLUDE, 
       +        "copy",         INCLUDE, 
       +        "space",        SPACE,
       +        "up",                 UP, 
       +        "down",         DOWN, 
       +        "fwd",                 FWD, 
       +        "back",         BACK, 
       +        "mark",         MARK, 
       +        "lineup",         LINEUP, 
       +        0,         0
       +};
       +
       +struct resword {
       +        char        *res;
       +        char        *resval;
       +} resword[]        ={
       +        ">=",                "\\(>=",
       +        "<=",                "\\(<=",
       +        "==",                "\\(==",
       +        "!=",                "\\(!=",
       +        "+-",                "\\(+-",
       +        "->",                "\\(->",
       +        "<-",                "\\(<-",
       +        "inf",                "\\(if",
       +        "infinity",        "\\(if",
       +        "partial",        "\\(pd",
       +        "half",                "\\f1\\(12\\fP",
       +        "prime",        "\\f1\\v'.5m'\\s+3\\(fm\\s-3\\v'-.5m'\\fP",
       +        "dollar",        "\\f1$\\fP",
       +        "nothing",        "",
       +        "times",        "\\(mu",
       +        "del",                "\\(gr",
       +        "grad",                "\\(gr",
       +        "approx",        "\\v'-.2m'\\z\\(ap\\v'.25m'\\(ap\\v'-.05m'",
       +        "cdot",                "\\v'-.3m'.\\v'.3m'",
       +        "...",                "\\v'-.25m'\\ .\\ .\\ .\\ \\v'.25m'",
       +        ",...,",        "\\f1,\\fP\\ .\\ .\\ .\\ \\f1,\\fP\\|",
       +        "alpha",        "α",
       +        "ALPHA",        "Α",
       +        "beta",                "β",
       +        "BETA",                "Β",
       +        "gamma",        "γ",
       +        "GAMMA",        "Γ",
       +        "delta",        "δ",
       +        "DELTA",        "Δ",
       +        "epsilon",        "ε",
       +        "EPSILON",        "Ε",
       +        "omega",        "ω",
       +        "OMEGA",        "Ω",
       +        "lambda",        "λ",
       +        "LAMBDA",        "Λ",
       +        "mu",                "μ",
       +        "MU",                "Μ",
       +        "nu",                "ν",
       +        "NU",                "Ν",
       +        "theta",        "θ",
       +        "THETA",        "Θ",
       +        "phi",                "φ",
       +        "PHI",                "Φ",
       +        "pi",                "π",
       +        "PI",                "Π",
       +        "sigma",        "σ",
       +        "SIGMA",        "Σ",
       +        "xi",                "ξ",
       +        "XI",                "Ξ",
       +        "zeta",                "ζ",
       +        "ZETA",                "Ζ",
       +        "iota",                "ι",
       +        "IOTA",                "Ι",
       +        "eta",                "η",
       +        "ETA",                "Η",
       +        "kappa",        "κ",
       +        "KAPPA",        "Κ",
       +        "rho",                "ρ",
       +        "RHO",                "Ρ",
       +        "tau",                "τ",
       +        "TAU",                "Τ",
       +        "omicron",        "ο",
       +        "OMICRON",        "Ο",
       +        "upsilon",        "υ",
       +        "UPSILON",        "Υ",
       +        "psi",                "ψ",
       +        "PSI",                "Ψ",
       +        "chi",                "χ",
       +        "CHI",                "Χ",
       +        "and",                "\\f1and\\fP",
       +        "for",                "\\f1for\\fP",
       +        "if",                "\\f1if\\fP",
       +        "Re",                "\\f1Re\\fP",
       +        "Im",                "\\f1Im\\fP",
       +        "sin",                "\\f1sin\\fP",
       +        "cos",                "\\f1cos\\fP",
       +        "tan",                "\\f1tan\\fP",
       +        "arc",                "\\f1arc\\fP",
       +        "sinh",                "\\f1sinh\\fP",
       +        "coth",                "\\f1coth\\fP",
       +        "tanh",                "\\f1tanh\\fP",
       +        "cosh",                "\\f1cosh\\fP",
       +        "lim",                "\\f1lim\\fP",
       +        "log",                "\\f1log\\fP",
       +        "ln",                "\\f1ln\\fP",
       +        "max",                "\\f1max\\fP",
       +        "min",                "\\f1min\\fP",
       +        "exp",                "\\f1exp\\fP",
       +        "det",                "\\f1det\\fP",
       +        0,        0
       +};
       +
       +int hash(char *s)
       +{
       +        register unsigned int h;
       +
       +        for (h = 0; *s != '\0'; )
       +                h += *s++;
       +        h %= TBLSIZE;
       +        return h;
       +}
       +
       +tbl *lookup(tbl **tblp, char *name)        /* find name in tbl */
       +{
       +        register tbl *p;
       +
       +        for (p = tblp[hash(name)]; p != NULL; p = p->next)
       +                if (strcmp(name, p->name) == 0)
       +                        return(p);
       +        return(NULL);
       +}
       +
       +void install(tbl **tblp, char *name, char *cval, int ival)        /* install name, vals in tblp */
       +{
       +        register tbl *p;
       +        int h;
       +
       +        if ((p = lookup(tblp, name)) == NULL) {
       +                p = (tbl *) malloc(sizeof(tbl));
       +                if (p == NULL)
       +                        ERROR "out of space in install" FATAL;
       +                h = hash(name);        /* bad visibility here */
       +                p->name = name;
       +                p->next = tblp[h];
       +                tblp[h] = p;
       +        }
       +        p->cval = cval;
       +        p->ival = ival;
       +}
       +
       +void init_tbl(void)        /* initialize tables */
       +{
       +        int i;
       +        extern int init_tune(void);
       +
       +        for (i = 0; keyword[i].key != NULL; i++)
       +                install(keytbl, keyword[i].key, (char *) 0, keyword[i].keyval);
       +        for (i = 0; resword[i].res != NULL; i++)
       +                install(restbl, resword[i].res, resword[i].resval, 0);
       +        init_tune();        /* tuning table done in tuning.c */
       +}
 (DIR) diff --git a/src/cmd/eqn/main.c b/src/cmd/eqn/main.c
       t@@ -0,0 +1,333 @@
       +#include "e.h"
       +
       +#define        MAXLINE        3600        /* maximum input line */
       +
       +char *version = "version Oct 24, 1991";
       +
       +char        in[MAXLINE];        /* input buffer */
       +int        noeqn;
       +char        *cmdname;
       +
       +int        yyparse(void);
       +void        settype(char *);
       +int        getdata(void);
       +int        getline(char *);
       +#define inline einline
       +void        inline(void);
       +void        init(void);
       +void        init_tbl(void);
       +
       +void
       +main(int argc, char *argv[])
       +{
       +        char *p, buf[20];
       +
       +        cmdname = argv[0];
       +        if (p = getenv("TYPESETTER"))
       +                typesetter = p;
       +        while (argc > 1 && argv[1][0] == '-') {
       +                switch (argv[1][1]) {
       +
       +                case 'd':
       +                        if (argv[1][2] == '\0') {
       +                                dbg++;
       +                                printf("...\teqn %s\n", version);
       +                        } else {
       +                                lefteq = argv[1][2];
       +                                righteq = argv[1][3];
       +                        }
       +                        break;
       +                case 's': szstack[0] = gsize = atoi(&argv[1][2]); break;
       +                case 'p': deltaps = atoi(&argv[1][2]); dps_set = 1; break;
       +                case 'm': minsize = atoi(&argv[1][2]); break;
       +                case 'f': strcpy(ftstack[0].name,&argv[1][2]); break;
       +                case 'e': noeqn++; break;
       +                case 'T': typesetter = &argv[1][2]; break;
       +                default:
       +                        fprintf(stderr, "%s: unknown option %s\n", cmdname, argv[1]);
       +                        break;
       +                }
       +                argc--;
       +                argv++;
       +        }
       +        settype(typesetter);
       +        sprintf(buf, "\"%s\"", typesetter);
       +        install(deftbl, strsave(typesetter), strsave(buf), 0);
       +        init_tbl();        /* install other keywords in tables */
       +        curfile = infile;
       +        pushsrc(File, curfile->fname);
       +        if (argc <= 1) {
       +                curfile->fin = stdin;
       +                curfile->fname = strsave("-");
       +                getdata();
       +        } else
       +                while (argc-- > 1) {
       +                        if (strcmp(*++argv, "-") == 0)
       +                                curfile->fin = stdin;
       +                        else if ((curfile->fin = fopen(*argv, "r")) == NULL)
       +                                ERROR "can't open file %s", *argv FATAL;
       +                        curfile->fname = strsave(*argv);
       +                        getdata();
       +                        if (curfile->fin != stdin)
       +                                fclose(curfile->fin);
       +                }
       +        exit(0);
       +}
       +
       +void settype(char *s)        /* initialize data for particular typesetter */
       +                        /* the minsize could profitably come from the */
       +{                        /* troff description file /usr/lib/font/dev.../DESC.out */
       +        if (strcmp(s, "202") == 0)
       +                { minsize = 5; ttype = DEV202; }
       +        else if (strcmp(s, "aps") == 0)
       +                { minsize = 5; ttype = DEVAPS; }
       +        else if (strcmp(s, "cat") == 0)
       +                { minsize = 6; ttype = DEVCAT; }
       +        else if (strcmp(s, "post") == 0)
       +                { minsize = 4; ttype = DEVPOST; }
       +        else
       +                { minsize = 5; ttype = DEV202; }
       +}
       +
       +getdata(void)
       +{
       +        int i, type, ln;
       +        char fname[100];
       +        extern int errno;
       +
       +        errno = 0;
       +        curfile->lineno = 0;
       +        printf(".lf 1 %s\n", curfile->fname);
       +        while ((type = getline(in)) != EOF) {
       +                if (in[0] == '.' && in[1] == 'E' && in[2] == 'Q') {
       +                        for (i = 11; i < 100; i++)
       +                                used[i] = 0;
       +                        printf("%s", in);
       +                        if (markline) {        /* turn off from last time */
       +                                printf(".nr MK 0\n");
       +                                markline = 0;
       +                        }
       +                        display = 1;
       +                        init();
       +                        yyparse();
       +                        if (eqnreg > 0) {
       +                                if (markline)
       +                                        printf(".nr MK %d\n", markline); /* for -ms macros */
       +                                printf(".if %gm>\\n(.v .ne %gm\n", eqnht, eqnht);
       +                                printf(".rn %d 10\n", eqnreg);
       +                                if (!noeqn)
       +                                        printf("\\&\\*(10\n");
       +                        }
       +                        printf(".EN");
       +                        while (putchar(input()) != '\n')
       +                                ;
       +                        printf(".lf %d\n", curfile->lineno+1);
       +                }
       +                else if (type == lefteq)
       +                        inline();
       +                else if (in[0] == '.' && in[1] == 'l' && in[2] == 'f') {
       +                        if (sscanf(in+3, "%d %s", &ln, fname) == 2) {
       +                                free(curfile->fname);
       +                                printf(".lf %d %s\n", curfile->lineno = ln, curfile->fname = strsave(fname));
       +                        } else
       +                                printf(".lf %d\n", curfile->lineno = ln);
       +                } else
       +                        printf("%s", in);
       +        }
       +        return(0);
       +}
       +
       +getline(char *s)
       +{
       +        register c;
       +
       +        while ((c=input()) != '\n' && c != EOF && c != lefteq) {
       +                if (s >= in+MAXLINE) {
       +                        ERROR "input line too long: %.20s\n", in WARNING;
       +                        in[MAXLINE] = '\0';
       +                        break;
       +                }
       +                *s++ = c;
       +        }
       +        if (c != lefteq)
       +                *s++ = c;
       +        *s = '\0';
       +        return(c);
       +}
       +
       +void inline(void)
       +{
       +        int ds, n, sz1 = 0;
       +
       +        n = curfile->lineno;
       +        if (szstack[0] != 0)
       +                printf(".nr %d \\n(.s\n", sz1 = salloc());
       +        ds = salloc();
       +        printf(".rm %d \n", ds);
       +        display = 0;
       +        do {
       +                if (*in)
       +                        printf(".as %d \"%s\n", ds, in);
       +                init();
       +                yyparse();
       +                if (eqnreg > 0) {
       +                        printf(".as %d \\*(%d\n", ds, eqnreg);
       +                        sfree(eqnreg);
       +                        printf(".lf %d\n", curfile->lineno+1);
       +                }
       +        } while (getline(in) == lefteq);
       +        if (*in)
       +                printf(".as %d \"%s", ds, in);
       +        if (sz1)
       +                printf("\\s\\n(%d", sz1);
       +        printf("\\*(%d\n", ds);
       +        printf(".lf %d\n", curfile->lineno+1);
       +        if (curfile->lineno > n+3)
       +                fprintf(stderr, "eqn warning: multi-line %c...%c, file %s:%d,%d\n",
       +                        lefteq, righteq, curfile->fname, n, curfile->lineno); 
       +        sfree(ds);
       +        if (sz1) sfree(sz1);
       +}
       +
       +void putout(int p1)
       +{
       +        double before, after;
       +        extern double BeforeSub, AfterSub;
       +
       +        dprintf(".\tanswer <- S%d, h=%g,b=%g\n",p1, eht[p1], ebase[p1]);
       +        eqnht = eht[p1];
       +        before = eht[p1] - ebase[p1] - BeforeSub;        /* leave room for sub or superscript */
       +        after = ebase[p1] - AfterSub;
       +        if (spaceval || before > 0.01 || after > 0.01) {
       +                printf(".ds %d ", p1);        /* used to be \\x'0' here:  why? */
       +                if (spaceval != NULL)
       +                        printf("\\x'0-%s'", spaceval);
       +                else if (before > 0.01)
       +                        printf("\\x'0-%gm'", before);
       +                printf("\\*(%d", p1);
       +                if (spaceval == NULL && after > 0.01)
       +                        printf("\\x'%gm'", after);
       +                putchar('\n');
       +        }
       +        if (szstack[0] != 0)
       +                printf(".ds %d %s\\*(%d\\s\\n(99\n", p1, DPS(gsize,gsize), p1);
       +        eqnreg = p1;
       +        if (spaceval != NULL) {
       +                free(spaceval);
       +                spaceval = NULL;
       +        }
       +}
       +
       +void init(void)
       +{
       +        synerr = 0;
       +        ct = 0;
       +        ps = gsize;
       +        ftp = ftstack;
       +        ft = ftp->ft;
       +        nszstack = 0;
       +        if (szstack[0] != 0)        /* absolute gsize in effect */
       +                printf(".nr 99 \\n(.s\n");
       +}
       +
       +salloc(void)
       +{
       +        int i;
       +
       +        for (i = 11; i < 100; i++)
       +                if (used[i] == 0) {
       +                        used[i]++;
       +                        return(i);
       +                }
       +        ERROR "no eqn strings left (%d)", i FATAL;
       +        return(0);
       +}
       +
       +void sfree(int n)
       +{
       +        used[n] = 0;
       +}
       +
       +void nrwid(int n1, int p, int n2)
       +{
       +        printf(".nr %d 0\\w'%s\\*(%d'\n", n1, DPS(gsize,p), n2);        /* 0 defends against - width */
       +}
       +
       +char *ABSPS(int dn)        /* absolute size dn in printable form \sd or \s(dd (dd >= 40) */
       +{
       +        static char buf[100], *lb = buf;
       +        char *p;
       +
       +        if (lb > buf + sizeof(buf) - 10)
       +                lb = buf;
       +        p = lb;
       +        *lb++ = '\\';
       +        *lb++ = 's';
       +        if (dn >= 10) {                /* \s(dd only works in new troff */
       +                if (dn >= 40)
       +                        *lb++ = '(';
       +                *lb++ = dn/10 + '0';
       +                *lb++ = dn%10 + '0';
       +        } else {
       +                *lb++ = dn + '0';
       +        }
       +        *lb++ = '\0';        
       +        return p;
       +}
       +
       +char *DPS(int f, int t)        /* delta ps (t-f) in printable form \s+d or \s-d or \s+-(dd */
       +{
       +        static char buf[100], *lb = buf;
       +        char *p;
       +        int dn;
       +
       +        if (lb > buf + sizeof(buf) - 10)
       +                lb = buf;
       +        p = lb;
       +        *lb++ = '\\';
       +        *lb++ = 's';
       +        dn = EFFPS(t) - EFFPS(f);
       +        if (szstack[nszstack] != 0)        /* absolute */
       +                dn = EFFPS(t);                /* should do proper \s(dd */
       +        else if (dn >= 0)
       +                *lb++ = '+';
       +        else {
       +                *lb++ = '-';
       +                dn = -dn;
       +        }
       +        if (dn >= 10) {                /* \s+(dd only works in new troff */
       +                *lb++ = '(';
       +                *lb++ = dn/10 + '0';
       +                *lb++ = dn%10 + '0';
       +        } else {
       +                *lb++ = dn + '0';
       +        }
       +        *lb++ = '\0';        
       +        return p;
       +}
       +
       +EFFPS(int n)        /* effective value of n */
       +{
       +        if (n >= minsize)
       +                return n;
       +        else
       +                return minsize;
       +}
       +
       +double EM(double m, int ps)        /* convert m to ems in gsize */
       +{
       +        m *= (double) EFFPS(ps) / gsize;
       +        if (m <= 0.001 && m >= -0.001)
       +                return 0;
       +        else
       +                return m;
       +}
       +
       +double REL(double m, int ps)        /* convert m to ems in ps */
       +{
       +        m *= (double) gsize / EFFPS(ps);
       +        if (m <= 0.001 && m >= -0.001)
       +                return 0;
       +        else
       +                return m;
       +}
 (DIR) diff --git a/src/cmd/eqn/mark.c b/src/cmd/eqn/mark.c
       t@@ -0,0 +1,19 @@
       +#include "e.h"
       +
       +void mark(int p1)
       +{
       +        markline = 1;
       +        printf(".ds %d \\k(09\\*(%d\n", p1, p1);
       +        yyval = p1;
       +        dprintf(".\tmark %d\n", p1);
       +}
       +
       +void lineup(int p1)
       +{
       +        markline = 2;
       +        if (p1 == 0) {
       +                yyval = salloc();
       +                printf(".ds %d \\h'|\\n(09u'\n", yyval);
       +        }
       +        dprintf(".\tlineup %d\n", p1);
       +}
 (DIR) diff --git a/src/cmd/eqn/matrix.c b/src/cmd/eqn/matrix.c
       t@@ -0,0 +1,78 @@
       +#include "e.h"
       +
       +startcol(int type)        /* mark start of column in lp[] array */
       +{
       +        int oct = ct;
       +
       +        lp[ct++] = type;
       +        lp[ct++] = 0;        /* count, to come */
       +        lp[ct++] = 0;        /* separation, to come */
       +        return oct;
       +}
       +
       +void column(int oct, int sep)        /* remember end of column that started at lp[oct] */
       +{
       +        int i, type;
       +
       +        lp[oct+1] = ct - oct - 3;
       +        lp[oct+2] = sep;
       +        type = lp[oct];
       +        if (dbg) {
       +                printf(".\t%d column of", type);
       +                for (i = oct+3; i < ct; i++ )
       +                        printf(" S%d", lp[i]);
       +                printf(", rows=%d, sep=%d\n", lp[oct+1], lp[oct+2]);
       +        }
       +}
       +
       +void matrix(int oct)        /* matrix is list of columns */
       +{
       +        int nrow, ncol, i, j, k, val[100];
       +        double b, hb;
       +        char *space;
       +        extern char *Matspace;
       +
       +        space = Matspace;        /* between columns of matrix */
       +        nrow = lp[oct+1];        /* disaster if rows inconsistent */
       +                                /* also assumes just columns */
       +                                /* fix when add other things */
       +        ncol = 0;
       +        for (i = oct+1; i < ct; i += lp[i]+3 ) {
       +                ncol++;
       +                dprintf(".\tcolct=%d\n", lp[i]);
       +        }
       +        for (k=1; k <= nrow; k++) {
       +                hb = b = 0;
       +                j = oct + k + 2;
       +                for (i=0; i < ncol; i++) {
       +                        hb = max(hb, eht[lp[j]]-ebase[lp[j]]);
       +                        b = max(b, ebase[lp[j]]);
       +                        j += nrow + 3;
       +                }
       +                dprintf(".\trow %d: b=%g, hb=%g\n", k, b, hb);
       +                j = oct + k + 2;
       +                for (i=0; i<ncol; i++) {
       +                        ebase[lp[j]] = b;
       +                        eht[lp[j]] = b + hb;
       +                        j += nrow + 3;
       +                }
       +        }
       +        j = oct;
       +        for (i=0; i<ncol; i++) {
       +                pile(j);
       +                val[i] = yyval;
       +                j += nrow + 3;
       +        }
       +        yyval = salloc();
       +        eht[yyval] = eht[val[0]];
       +        ebase[yyval] = ebase[val[0]];
       +        lfont[yyval] = rfont[yyval] = 0;
       +        dprintf(".\tmatrix S%d: r=%d, c=%d, h=%g, b=%g\n",
       +                yyval,nrow,ncol,eht[yyval],ebase[yyval]);
       +        printf(".ds %d \"", yyval);
       +        for( i=0; i<ncol; i++ )  {
       +                printf("\\*(%d%s", val[i], i==ncol-1 ? "" : space);
       +                sfree(val[i]);
       +        }
       +        printf("\n");
       +}
 (DIR) diff --git a/src/cmd/eqn/mkfile b/src/cmd/eqn/mkfile
       t@@ -0,0 +1,42 @@
       +<$PLAN9/src/mkhdr
       +
       +TARG=eqn
       +OFILES=main.$O\
       +        tuning.$O\
       +        diacrit.$O\
       +        eqnbox.$O\
       +        font.$O\
       +        fromto.$O\
       +        funny.$O\
       +        glob.$O\
       +        integral.$O\
       +        input.$O\
       +        lex.$O\
       +        lookup.$O\
       +        mark.$O\
       +        matrix.$O\
       +        move.$O\
       +        over.$O\
       +        paren.$O\
       +        pile.$O\
       +        shift.$O\
       +        size.$O\
       +        sqrt.$O\
       +        text.$O\
       +        eqn.$O\
       +
       +YFILES=eqn.y\
       +
       +HFILES=e.h\
       +        y.tab.h\
       +
       +SHORTLIB=bio 9
       +<$PLAN9/src/mkone
       +
       +YFLAGS=-d -S
       +
       +eqn.c:        y.tab.c prevy.tab.h
       +        mv y.tab.c $target
       +
       +prevy.tab.h:        y.tab.h
       +        sh -c 'cmp -s y.tab.h prevy.tab.h || cp y.tab.h prevy.tab.h'
 (DIR) diff --git a/src/cmd/eqn/move.c b/src/cmd/eqn/move.c
       t@@ -0,0 +1,19 @@
       +# include "e.h"
       +# include "y.tab.h"
       +
       +void move(int dir, int amt, int p)
       +{
       +        double a;
       +
       +        yyval = p;
       +        a = EM(amt/100.0, ps);
       +        printf(".ds %d ", yyval);
       +        if (dir == FWD || dir == BACK)
       +                printf("\\h'%s%gm'\\*(%d\n", (dir==BACK) ? "-" : "", a, p);
       +        else if (dir == UP)
       +                printf("\\v'-%gm'\\*(%d\\v'%gm'\n", a, p, a);
       +        else if (dir == DOWN)
       +                printf("\\v'%gm'\\*(%d\\v'-%gm'\n", a, p, a);
       +        dprintf(".\tmove %d dir %d amt %g; h=%g b=%g\n", 
       +                p, dir, a, eht[yyval], ebase[yyval]);
       +}
 (DIR) diff --git a/src/cmd/eqn/o.eqn b/src/cmd/eqn/o.eqn
       Binary files differ.
 (DIR) diff --git a/src/cmd/eqn/over.c b/src/cmd/eqn/over.c
       t@@ -0,0 +1,35 @@
       +#include "e.h"
       +
       +void boverb(int p1, int p2)
       +{
       +        int treg;
       +        double h, b, d, d1, d2;
       +        extern double Overgap, Overwid, Overline;
       +
       +        treg = salloc();
       +        yyval = p1;
       +        d = EM(Overgap, ps);
       +        h = eht[p1] + eht[p2] + d;
       +        b = eht[p2] - d;
       +        dprintf(".\tS%d <- %d over %d; b=%g, h=%g\n", 
       +                yyval, p1, p2, b, h);
       +        nrwid(p1, ps, p1);
       +        nrwid(p2, ps, p2);
       +        printf(".nr %d \\n(%d\n", treg, p1);
       +        printf(".if \\n(%d>\\n(%d .nr %d \\n(%d\n", p2, treg, treg, p2);
       +        printf(".nr %d \\n(%d+%gm\n", treg, treg, Overwid);
       +        d2 = eht[p2]-ebase[p2]-d;        /* denom */
       +        printf(".ds %d \\v'%gm'\\h'\\n(%du-\\n(%du/2u'\\*(%d\\v'%gm'\\\n", 
       +                yyval, REL(d2,ps), treg, p2, p2, REL(-d2,ps));
       +        d1 = 2 * d + ebase[p1];                /* num */
       +        printf("\\h'-\\n(%du-\\n(%du/2u'\\v'%gm'\\*(%d\\v'%gm'\\\n", 
       +                p2, p1, REL(-d1,ps), p1, REL(d1,ps));
       +        printf("\\h'-\\n(%du-\\n(%du/2u+%gm'\\v'%gm'\\l'\\n(%du-%gm'\\h'%gm'\\v'%gm'\n", 
       +                treg, p1, Overline, REL(-d,ps),
       +                treg, 2*Overline, Overline, REL(d,ps));
       +        ebase[yyval] = b;
       +        eht[yyval] = h;
       +        lfont[yyval] = rfont[yyval] = 0;
       +        sfree(p2);
       +        sfree(treg);
       +}
 (DIR) diff --git a/src/cmd/eqn/paren.c b/src/cmd/eqn/paren.c
       t@@ -0,0 +1,135 @@
       +#include "e.h"
       +
       +#define abs(x) ((x) > 0 ? (x) : (-(x)))
       +
       +extern void brack(int, char *, char *, char *);
       +
       +void paren(int leftc, int p1, int rightc)
       +{
       +        int n, m, j;
       +        double h1, b1;
       +        double v, bv;        /* v = shift of inside, bv = shift of brackets */
       +        extern double Parenbase, Parenshift, Parenheight;
       +
       +        bv = ttype == DEVPOST ? Parenshift : 0;        /* move brackets down this much */
       +        h1 = eht[p1];
       +        b1 = ebase[p1];
       +        yyval = p1;
       +        lfont[yyval] = rfont[yyval] = 0;
       +        n = REL(h1,ps) + 0.99;        /* ceiling */
       +        if (n < 2)
       +                n = 1;
       +        m = n - 2;
       +        if (leftc == '{' || rightc == '}') {
       +                n = n%2 ? n : ++n;
       +                if (n < 3)
       +                        n = 3;
       +                m = n-3;
       +        }
       +        eht[yyval] = EM((double) n + Parenheight, ps);
       +        ebase[yyval] = eht[yyval]/2 - EM(Parenbase, ps);
       +
       +        /* try to cope with things that are badly centered */
       +        /* (top heavy or bottom heavy) */
       +        if (abs(h1/2 - b1) >= EM(0.5, ps))
       +                v = REL(-ebase[yyval] + (eht[yyval]-h1)/2 + b1, ps);
       +        else
       +                v = 0;        /* don't shift it at all */
       +
       +        printf(".ds %d \\^", yyval);        /* was \| */
       +        if (bv)
       +                printf("\\v'%gm'", bv);
       +        switch (leftc) {
       +        case 'n':        /* nothing */
       +        case '\0':
       +                break;
       +        case 'f':        /* floor */
       +                if (n <= 1)
       +                        printf("\\(lf");
       +                else
       +                        brack(m, "\\(bv", "\\(bv", "\\(lf");
       +                break;
       +        case 'c':        /* ceiling */
       +                if (n <= 1)
       +                        printf("\\(lc");
       +                else
       +                        brack(m, "\\(lc", "\\(bv", "\\(bv");
       +                break;
       +        case '{':
       +                printf("\\b'\\(lt");
       +                for(j = 0; j < m; j += 2) printf("\\(bv");
       +                printf("\\(lk");
       +                for(j = 0; j < m; j += 2) printf("\\(bv");
       +                printf("\\(lb'");
       +                break;
       +        case '(':
       +                brack(m, "\\(lt", "\\(bv", "\\(lb");
       +                break;
       +        case '[':
       +                brack(m, "\\(lc", "\\(bv", "\\(lf");
       +                break;
       +        case '|':
       +                brack(m, "|", "|", "|");
       +                break;
       +        default:
       +                brack(m, (char *) &leftc, (char *) &leftc, (char *) &leftc);
       +                break;
       +        }
       +        if (bv)
       +                printf("\\v'%gm'", -bv);
       +        if (v)
       +                printf("\\v'%gm'\\*(%d\\v'%gm'", -v, p1, v);
       +        else
       +                printf("\\*(%d", p1);
       +        if (rightc) {
       +                if (bv)
       +                        printf("\\v'%gm'", bv);
       +                switch (rightc) {
       +                case 'f':        /* floor */
       +                        if (n <= 1)
       +                                printf("\\(rf");
       +                        else
       +                                brack(m, "\\(bv", "\\(bv", "\\(rf");
       +                        break;
       +                case 'c':        /* ceiling */
       +                        if (n <= 1)
       +                                printf("\\(rc");
       +                        else
       +                                brack(m, "\\(rc", "\\(bv", "\\(bv");
       +                        break;
       +                case '}':
       +                        printf("\\b'\\(rt");
       +                        for(j = 0; j < m; j += 2) printf("\\(bv");
       +                        printf("\\(rk");
       +                        for(j = 0; j < m; j += 2) printf("\\(bv");
       +                        printf("\\(rb'");
       +                        break;
       +                case ']':
       +                        brack(m, "\\(rc", "\\(bv", "\\(rf");
       +                        break;
       +                case ')':
       +                        brack(m, "\\(rt", "\\(bv", "\\(rb");
       +                        break;
       +                case '|':
       +                        brack(m, "|", "|", "|");
       +                        break;
       +                default:
       +                        brack(m, (char *) &rightc, (char *) &rightc, (char *) &rightc);
       +                        break;
       +                }
       +                if (bv)
       +                        printf("\\v'%gm'", -bv);
       +        }
       +        printf("\n");
       +        dprintf(".\tcurly: h=%g b=%g n=%d v=%g l=%c, r=%c\n", 
       +                eht[yyval], ebase[yyval], n, v, leftc, rightc);
       +}
       +
       +void brack(int m, char *t, char *c, char *b)
       +{
       +        int j;
       +        printf("\\b'%s", t);
       +        for( j=0; j < m; j++)
       +                printf("%s", c);
       +        printf("%s'", b);
       +}
 (DIR) diff --git a/src/cmd/eqn/pile.c b/src/cmd/eqn/pile.c
       t@@ -0,0 +1,76 @@
       +#include "e.h"
       +#include "y.tab.h"
       +
       +void pile(int oct)
       +{
       +        int i, nlist, nlist2, mid;
       +        double bi, h, b, gap, sb;
       +        extern double Pilegap, Pilebase;
       +        int type, p1, p2;
       +
       +        yyval = salloc();
       +        type = lp[oct];
       +        p1 = oct + 3;                /* first entry */
       +        p2 = p1 + lp[oct+1];        /* 1 after last */
       +        gap = lp[oct+2];
       +        if (gap != DEFGAP)
       +                gap = EM(gap/100.0, ps);
       +        else if (type == COL)
       +                gap = 0;
       +        else
       +                gap = EM(Pilegap, ps);        /* 0.4 m between LCOL, etc. */
       +        nlist = p2 - p1;
       +        nlist2 = (nlist+1)/2;
       +        mid = p1 + nlist2 - 1;
       +        h = 0;
       +        for (i = p1; i < p2; i++)
       +                h += eht[lp[i]];
       +        eht[yyval] = h + (nlist-1)*gap;
       +        b = 0;
       +        for (i = p2-1; i > mid; i--)
       +                b += eht[lp[i]] + gap;
       +        ebase[yyval] = (nlist%2) ? b + ebase[lp[mid]]
       +                        : b - EM(Pilebase, ps) - gap;
       +        if (dbg) {
       +                printf(".\tS%d <- %d pile of:", yyval, type);
       +                for (i = p1; i < p2; i++)
       +                        printf(" S%d", lp[i]);
       +                printf("; h=%g b=%g\n", eht[yyval], ebase[yyval]);
       +        }
       +        nrwid(lp[p1], ps, lp[p1]);
       +        printf(".nr %d \\n(%d\n", yyval, lp[p1]);
       +        for (i = p1+1; i < p2; i++) {
       +                nrwid(lp[i], ps, lp[i]);
       +                printf(".if \\n(%d>\\n(%d .nr %d \\n(%d\n", 
       +                        lp[i], yyval, yyval, lp[i]);
       +        }
       +        printf(".ds %d \\v'%gm'\\h'%du*\\n(%du'\\\n", yyval, REL(ebase[yyval],ps), 
       +                type==RCOL ? 1 : 0, yyval);
       +        sb = 0;                /* sum of box hts */
       +        for (i = p2-1; i >= p1; i--) {
       +                bi = sb + ebase[lp[i]];
       +                switch (type) {
       +                case LCOL:
       +                        printf("\\v'%gm'\\*(%d\\h'-\\n(%du'\\v'%gm'\\\n", 
       +                                REL(-bi,ps), lp[i], lp[i], REL(bi,ps));
       +                        break;
       +                case RCOL:
       +                        printf("\\v'%gm'\\h'-\\n(%du'\\*(%d\\v'%gm'\\\n", 
       +                                REL(-bi,ps), lp[i], lp[i], REL(bi,ps));
       +                        break;
       +                case CCOL:
       +                case COL:
       +                        printf("\\v'%gm'\\h'\\n(%du-\\n(%du/2u'\\*(%d", 
       +                                REL(-bi,ps), yyval, lp[i], lp[i]);
       +                        printf("\\h'-\\n(%du-\\n(%du/2u'\\v'%gm'\\\n", 
       +                                yyval, lp[i], REL(bi,ps));
       +                        break;
       +                }
       +                sb += eht[lp[i]] + gap;
       +        }
       +        printf("\\v'%gm'\\h'%du*\\n(%du'\n", REL(-ebase[yyval],ps), 
       +                type!=RCOL ? 1 : 0, yyval);
       +        for (i = p1; i < p2; i++)
       +                sfree(lp[i]);
       +        lfont[yyval] = rfont[yyval] = 0;
       +}
 (DIR) diff --git a/src/cmd/eqn/prevy.tab.h b/src/cmd/eqn/prevy.tab.h
       t@@ -0,0 +1,57 @@
       +#define        CONTIG        57346
       +#define        QTEXT        57347
       +#define        SPACE        57348
       +#define        THIN        57349
       +#define        TAB        57350
       +#define        MATRIX        57351
       +#define        LCOL        57352
       +#define        CCOL        57353
       +#define        RCOL        57354
       +#define        COL        57355
       +#define        ABOVE        57356
       +#define        MARK        57357
       +#define        LINEUP        57358
       +#define        SUM        57359
       +#define        INT        57360
       +#define        PROD        57361
       +#define        UNION        57362
       +#define        INTER        57363
       +#define        DEFINE        57364
       +#define        TDEFINE        57365
       +#define        NDEFINE        57366
       +#define        DELIM        57367
       +#define        GSIZE        57368
       +#define        GFONT        57369
       +#define        INCLUDE        57370
       +#define        IFDEF        57371
       +#define        DOTEQ        57372
       +#define        DOTEN        57373
       +#define        FROM        57374
       +#define        TO        57375
       +#define        OVER        57376
       +#define        SQRT        57377
       +#define        SUP        57378
       +#define        SUB        57379
       +#define        SIZE        57380
       +#define        FONT        57381
       +#define        ROMAN        57382
       +#define        ITALIC        57383
       +#define        BOLD        57384
       +#define        FAT        57385
       +#define        UP        57386
       +#define        DOWN        57387
       +#define        BACK        57388
       +#define        FWD        57389
       +#define        LEFT        57390
       +#define        RIGHT        57391
       +#define        DOT        57392
       +#define        DOTDOT        57393
       +#define        HAT        57394
       +#define        TILDE        57395
       +#define        BAR        57396
       +#define        LOWBAR        57397
       +#define        HIGHBAR        57398
       +#define        UNDER        57399
       +#define        VEC        57400
       +#define        DYAD        57401
       +#define        UTILDE        57402
 (DIR) diff --git a/src/cmd/eqn/shift.c b/src/cmd/eqn/shift.c
       t@@ -0,0 +1,116 @@
       +#include "e.h"
       +#include "y.tab.h"
       +
       +void subsup(int p1, int p2, int p3)
       +{
       +        if (p2 != 0 && p3 != 0)
       +                shift2(p1, p2, p3);
       +        else if (p2 != 0)
       +                bshiftb(p1, SUB, p2);
       +        else if (p3 != 0)
       +                bshiftb(p1, SUP, p3);
       +}
       +
       +extern double Subbase, Supshift;
       +extern char *Sub1space, *Sup1space, *Sub2space;
       +extern char *SS1space, *SS2space;
       +
       +void bshiftb(int p1, int dir, int p2)
       +{
       +        int subps, n;
       +        double shval, d1, h1, b1, h2, b2;
       +        char *sh1, *sh2;
       +
       +        yyval = p1;
       +        h1 = eht[p1];
       +        b1 = ebase[p1];
       +        h2 = eht[p2];
       +        b2 = ebase[p2];
       +        subps = ps;
       +        ps += deltaps;
       +        if (dir == SUB) {
       +                /* base .2m below bottom of main box */
       +                shval = b1 + EM(Subbase, ps);
       +                ebase[yyval] = shval + b2;
       +                eht[yyval] = max(h1-b1+shval+b2, h2);
       +                if (rfont[p1] == ITAL && lfont[p2] == ROM)
       +                        n = 2;                /* Sub1space */
       +                else
       +                        n = max(2, class[rclass[p1]][lclass[p2]]);
       +                sh1 = pad(n);
       +                rclass[p1] = OTHER;        /* OTHER leaves too much after sup */
       +        } else {        /* superscript */
       +                /* 4/10 up main box */
       +                d1 = EM(Subbase, subps);
       +                ebase[yyval] = b1;
       +                shval = -(Supshift * (h1-b1)) - b2;
       +                if (Supshift*(h1-b1) + h2 < h1-b1)        /* raise little super */
       +                        shval = -(h1-b1) + h2-b2 - d1;
       +                eht[yyval] = h1 + max(0, h2 - (1-Supshift)*(h1-b1));
       +                if (rclass[p1] == ILETF)
       +                        n = 4;
       +                else if (rfont[p1] == ITAL)
       +                        n = 2;                /* Sup1space */
       +                else
       +                        n = max(1, class[rclass[p1]][lclass[p2]]);
       +                sh1 = pad(n);
       +                rclass[p1] = rclass[p2];        /* OTHER leaves too much after sup */
       +        }
       +        dprintf(".\tS%d <- %d shift %g %d; b=%g, h=%g, ps=%d, subps=%d\n", 
       +                yyval, p1, shval, p2, ebase[yyval], eht[yyval], ps, subps);
       +        sh2 = Sub2space;        /* was Sub2space; */
       +        printf(".as %d \\v'%gm'%s%s\\*(%d%s%s\\v'%gm'\n", 
       +                yyval, REL(shval,ps), DPS(ps,subps), sh1, p2,
       +                DPS(subps,ps), sh2, REL(-shval,ps));
       +        rfont[p1] = 0;
       +        sfree(p2);
       +}
       +
       +void shift2(int p1, int p2, int p3)
       +{
       +        int subps;
       +        double h1, h2, h3, b1, b2, b3, subsh, d2, supsh;
       +        int treg;
       +        char *sh2;
       +
       +        treg = salloc();
       +        yyval = p1;
       +        subps = ps;        /* sub and sup at this size */
       +        ps += deltaps;        /* outer size */
       +        h1 = eht[p1]; b1 = ebase[p1];
       +        h2 = eht[p2]; b2 = ebase[p2];
       +        h3 = eht[p3]; b3 = ebase[p3];
       +        subsh = EM(Subbase, ps);
       +        if (b1 > b2 + subsh) /* move little sub down */
       +                subsh += b1;
       +        eht[yyval] = max(subsh+b2-b1+h1, h2);
       +        supsh = -Supshift*(h1-b1) - b3;
       +        d2 = EM(Subbase, subps);
       +        if (h3 < (1-Supshift)*(h1-b1))
       +                supsh = -(h1-b1) + (h3-b3) - d2;
       +        ebase[yyval] = subsh + b2 - b1;
       +        eht[yyval] = h1 + subsh+b2-b1 + max(0, h3-(1-Supshift)*(h1-b1));
       +        dprintf(".\tS%d <- %d sub %d sup %d, ps=%d, subps=%d, h=%g, b=%g\n",
       +                yyval, p1, p2, p3, ps, subps, eht[yyval], ebase[yyval]);
       +        if (rclass[p1] == ILETF)
       +                sh2 = "\\|\\|";
       +        else
       +                sh2 = SS2space;
       +        /*n = max(class[rclass[p1]][lclass[p2]], class[rclass[p1]][lclass[p3]]);
       +        /*sh2 = pad(max(2, n));
       +        */
       +        printf(".ds %d %s\\*(%d\n", p2, SS1space, p2);
       +        nrwid(p2, subps, p2);
       +        printf(".ds %d %s\\*(%d\n", p3, sh2, p3);
       +        nrwid(p3, subps, p3);
       +        printf(".nr %d \\n(%d\n", treg, p3);
       +        printf(".if \\n(%d>\\n(%d .nr %d \\n(%d\n", p2, treg, treg, p2);
       +        printf(".as %d %s\\v'%gm'\\*(%d\\v'%gm'\\h'-\\n(%du'\\\n", 
       +                p1, DPS(ps,subps), REL(subsh,subps), p2, REL(-subsh,subps), p2);
       +        printf("\\v'%gm'\\*(%d\\v'%gm'\\h'-\\n(%du+\\n(%du'%s%s\n", 
       +                REL(supsh,subps), p3, REL(-supsh,subps), p3, treg, DPS(subps,ps), Sub2space);
       +        if (rfont[p2] == ITAL)
       +                rfont[yyval] = 0;        /* lie */
       +        rclass[yyval] = rclass[p3];        /* was OTHER */
       +        sfree(p2); sfree(p3); sfree(treg);
       +}
 (DIR) diff --git a/src/cmd/eqn/size.c b/src/cmd/eqn/size.c
       t@@ -0,0 +1,70 @@
       +#include "e.h"
       +#include <ctype.h>
       +
       +void setsize(char *p)        /* set size as found in p */
       +{
       +        nszstack++;
       +        szstack[nszstack] = 0;                /* assume relative */
       +        if (*p == '+') {
       +                ps += atoi(p+1);
       +                if (szstack[nszstack-1] != 0)        /* propagate absolute size */
       +                        szstack[nszstack] = ps;
       +        } else if (*p == '-') {
       +                ps -= atoi(p+1);
       +                if (szstack[nszstack-1] != 0)
       +                        szstack[nszstack] = ps;
       +        } else if (isdigit(*p)) {
       +                if (szstack[nszstack-1] == 0)
       +                        printf(".nr %d \\n(.s\n", 99-nszstack);
       +                else
       +                        printf(".nr %d %d\n", 99-nszstack, ps);
       +                szstack[nszstack] = ps = atoi(p);
       +        } else {
       +                ERROR "illegal size %s ignored", p WARNING;
       +        }
       +        dprintf(".\tsetsize %s; ps = %d\n", p, ps);
       +}
       +
       +void size(int p1, int p2)
       +{
       +                /* old size in p1, new in ps */
       +        yyval = p2;
       +        dprintf(".\tS%d <- \\s%d %d \\s%d; b=%g, h=%g\n", 
       +                yyval, ps, p2, p1, ebase[yyval], eht[yyval]);
       +        if (szstack[nszstack] != 0) {
       +                printf(".ds %d %s\\*(%d\\s\\n(%d\n", yyval, ABSPS(ps), p2, 99-nszstack);
       +        } else
       +                printf(".ds %d %s\\*(%d%s\n", yyval, DPS(p1,ps), p2, DPS(ps,p1));
       +        nszstack--;
       +        ps = p1;
       +}
       +
       +void globsize(void)
       +{
       +        char temp[20];
       +
       +        getstr(temp, sizeof(temp));
       +        if (temp[0] == '+') {
       +                gsize += atoi(temp+1);
       +                if (szstack[0] != 0)
       +                        szstack[0] = gsize;
       +        } else if (temp[0] == '-') {
       +                gsize -= atoi(temp+1);
       +                if (szstack[0] != 0)
       +                        szstack[0] = gsize;
       +        } else  if (isdigit(temp[0])) {
       +                gsize = atoi(temp);
       +                szstack[0] = gsize;
       +                printf(".nr 99 \\n(.s\n");
       +        } else {
       +                ERROR "illegal gsize %s ignored", temp WARNING;
       +        }
       +        yyval = eqnreg = 0;
       +        ps = gsize;
       +        if (gsize < 12 && !dps_set)                /* sub and sup size change */
       +                deltaps = gsize / 3;
       +        else if (gsize < 20)
       +                deltaps = gsize / 4;
       +        else
       +                deltaps = gsize / 5;
       +}
 (DIR) diff --git a/src/cmd/eqn/sqrt.c b/src/cmd/eqn/sqrt.c
       t@@ -0,0 +1,35 @@
       +#include "e.h"
       +
       +void sqrt(int p2)
       +{
       +        static int af = 0;
       +        int nps;        /* point size for radical */
       +        double radscale = 0.95;
       +
       +        if (ttype == DEVPOST)
       +                radscale = 1.05;
       +        nps = ps * radscale * eht[p2] / EM(1.0,ps) + 0.99;        /* kludgy */
       +        nps = max(EFFPS(nps), ps);
       +        yyval = p2;
       +        if (ttype == DEVCAT || ttype == DEVAPS)
       +                eht[yyval] = EM(1.2, nps);
       +        else if (ttype == DEVPOST)
       +                eht[yyval] = EM(1.15, nps);
       +        else                /* DEV202, DEVPOST */
       +                eht[yyval] = EM(1.15, nps);
       +        dprintf(".\tS%d <- sqrt S%d;b=%g, h=%g, nps=%d\n", 
       +                yyval, p2, ebase[yyval], eht[yyval], nps);
       +        printf(".as %d \\|\n", yyval);
       +        nrwid(p2, ps, p2);
       +        if (af++ == 0)
       +                printf(".af 10 01\n");        /* make it two digits when it prints */
       +        printf(".nr 10 %.3fu*\\n(.su/10\n", 9.2*eht[p2]);        /* this nonsense */
       +                        /* guesses point size corresponding to height of stuff */
       +        printf(".ds %d \\v'%gm'\\s(\\n(10", yyval, REL(ebase[p2],ps));
       +        if (ttype == DEVCAT || ttype == DEVAPS)
       +                printf("\\v'-.2m'\\(sr\\l'\\n(%du\\(rn'\\v'.2m'", p2);
       +        else                /* DEV202, DEVPOST so far */
       +                printf("\\(sr\\l'\\n(%du\\(rn'", p2);
       +        printf("\\s0\\v'%gm'\\h'-\\n(%du'\\^\\*(%d\n", REL(-ebase[p2],ps), p2, p2);
       +        lfont[yyval] = rfont[yyval] = ROM;
       +}
 (DIR) diff --git a/src/cmd/eqn/text.c b/src/cmd/eqn/text.c
       t@@ -0,0 +1,318 @@
       +#include "e.h"
       +#include "y.tab.h"
       +#include <ctype.h>
       +
       +#define        CSSIZE        1000
       +char        cs[CSSIZE+20];        /* text string converted into this */
       +char        *csp;                /* next spot in cs[] */
       +char        *psp;                /* next character in input token */
       +
       +int        lf, rf;                /* temporary spots for left and right fonts */
       +int        lastft;                /* last \f added */
       +int        nextft;                /* next \f to be added */
       +
       +int        pclass;                /* class of previous character */
       +int        nclass;                /* class of next character */
       +
       +int class[LAST][LAST] ={        /* guesswork, tuned to times roman postscript */
       +
       +        /*OT OL IL DG LP RP SL PL IF IJ VB */
       +/*OT*/        { 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 0 },                /* OTHER */
       +/*OL*/        { 1, 0, 1, 1, 1, 1, 1, 2, 2, 2, 0 },                /* OLET */
       +/*IL*/        { 1, 1, 0, 1, 1, 1, 1, 3, 2, 1, 0 },                /* ILET */
       +/*DG*/        { 1, 1, 1, 0, 1, 1, 1, 2, 2, 2, 0 },                /* DIG */
       +/*LP*/        { 1, 1, 1, 1, 1, 2, 1, 2, 3, 3, 0 },                /* LPAR */
       +/*RP*/        { 2, 2, 2, 1, 1, 1, 1, 2, 3, 3, 0 },                /* RPAR */
       +/*SL*/        { 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 0 },                /* SLASH */
       +/*PL*/        { 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 0 },                /* PLUS */
       +/*IF*/        { 3, 3, 1, 2, 2, 3, 2, 3, 0, 1, 1 },                /* ILETF */
       +/*IJ*/        { 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0 },                /* ILETJ */
       +/*VB*/        { 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 1 },                /* VBAR */
       +
       +};
       +
       +extern void shim(int, int);
       +extern void roman(int);
       +extern void sadd(char *);
       +extern void cadd(int);
       +extern int trans(int, char *);
       +
       +int textc(void)        /* read next UTF rune from psp */
       +{
       +        wchar_t r;
       +        int w;
       +
       +        w = mbtowc(&r, psp, 3);
       +        if(w == 0){
       +                psp++;
       +                return 0;
       +        }
       +        if(w < 0){
       +                psp += 1;
       +                return 0x80;        /* Plan 9-ism */
       +        }
       +        psp += w;
       +        return r;
       +}
       +
       +void text(int t, char *p1)        /* convert text string p1 of type t */
       +{
       +        int c;
       +        char *p;
       +        tbl *tp;
       +
       +        yyval = salloc();
       +        ebase[yyval] = 0;
       +        eht[yyval] = EM(1.0, ps);        /* ht in ems of orig size */
       +        lfont[yyval] = rfont[yyval] = ROM;
       +        lclass[yyval] = rclass[yyval] = OTHER;
       +        if (t == QTEXT) {
       +                for (p = p1; *p; p++)        /* scan for embedded \f's */
       +                        if (*p == '\\' && *(p+1) == 'f')
       +                                break;
       +                if (*p)                /* if found \f, leave it alone and hope */
       +                        p = p1;
       +                else {
       +                        sprintf(cs, "\\f%s%s\\fP", ftp->name, p1);
       +                        p = cs;
       +                }
       +        } else if (t == SPACE)
       +                p = "\\ ";
       +        else if (t == THIN)
       +                p = "\\|";
       +        else if (t == TAB)
       +                p = "\\t";
       +        else if ((tp = lookup(restbl, p1)) != NULL) {
       +                p = tp->cval;
       +        } else {
       +                lf = rf = 0;
       +                lastft = 0;
       +                nclass = NONE;        /* get started with no class == no pad */
       +                csp = cs;
       +                for (psp = p1; (c = textc()) != '\0'; ) {
       +                        nextft = ft;
       +                        pclass = nclass;
       +                        rf = trans(c, p1);
       +                        if (lf == 0) {
       +                                lf = rf;        /* left stuff is first found */
       +                                lclass[yyval] = nclass;
       +                        }
       +                        if (csp-cs > CSSIZE)
       +                                ERROR "converted token %.25s... too long", p1 FATAL ;
       +                }
       +                sadd("\\fP");
       +                *csp = '\0';
       +                p = cs;
       +                lfont[yyval] = lf;
       +                rfont[yyval] = rf;
       +                rclass[yyval] = nclass;
       +        }
       +        dprintf(".\t%dtext: S%d <- %s; b=%g,h=%g,lf=%c,rf=%c,ps=%d\n",
       +                t, yyval, p, ebase[yyval], eht[yyval], lfont[yyval], rfont[yyval], ps);
       +        printf(".ds %d \"%s\n", yyval, p);
       +}
       +
       +int isalpharune(int c)
       +{
       +        return ('a'<=c && c<='z') || ('A'<=c && c<='Z');
       +}
       +
       +int isdigitrune(int c)
       +{
       +        return ('0'<=c && c<='9');
       +}
       +
       +trans(int c, char *p1)
       +{
       +        int f;
       +
       +        if (isalpharune(c) && ft == ITAL && c != 'f' && c != 'j') {        /* italic letter */
       +                shim(pclass, nclass = ILET);
       +                cadd(c);
       +                return ITAL;
       +        }
       +        if (isalpharune(c) && ft != ITAL) {                /* other letter */
       +                shim(pclass, nclass = OLET);
       +                cadd(c);
       +                return ROM;
       +        }
       +        if (isdigitrune(c)) {
       +                shim(pclass, nclass = DIG);
       +                roman(c);
       +                return ROM;        /* this is the right side font of this object */
       +        }
       +        f = ROM;
       +        nclass = OTHER;
       +        switch (c) {
       +        case ':': case ';': case '!': case '%': case '?':
       +                shim(pclass, nclass);
       +                roman(c);
       +                return f;
       +        case '(': case '[':
       +                shim(pclass, nclass = LPAR);
       +                roman(c);
       +                return f;
       +        case ')': case ']':
       +                shim(pclass, nclass = RPAR);
       +                roman(c);
       +                return f;
       +        case ',':
       +                shim(pclass, nclass = OTHER);
       +                roman(c);
       +                return f;
       +        case '.':
       +                if (rf == ROM)
       +                        roman(c);
       +                else
       +                        cadd(c);
       +                return f;
       +        case '|':                /* postscript needs help with default width! */
       +                shim(pclass, nclass = VBAR);
       +                sadd("\\v'.17m'\\z|\\v'-.17m'\\|");        /* and height */
       +                return f;
       +        case '=':
       +                shim(pclass, nclass = PLUS);
       +                sadd("\\(eq");
       +                return f;
       +        case '+':
       +                shim(pclass, nclass = PLUS);
       +                sadd("\\(pl");
       +                return f;
       +        case '>':
       +        case '<':                /* >, >=, >>, <, <-, <=, << */
       +                shim(pclass, nclass = PLUS);
       +                if (*psp == '=') {
       +                        sadd(c == '<' ? "\\(<=" : "\\(>=");
       +                        psp++;
       +                } else if (c == '<' && *psp == '-') {        /* <- only */
       +                        sadd("\\(<-");
       +                        psp++;
       +                } else if (*psp == c) {                /* << or >> */
       +                        cadd(c);
       +                        cadd(c);
       +                        psp++;
       +                } else {
       +                        cadd(c);  
       +                }
       +                return f;
       +        case '-':
       +                shim(pclass, nclass = PLUS);        /* probably too big for ->'s */
       +                if (*psp == '>') {
       +                        sadd("\\(->");
       +                        psp++;
       +                } else {
       +                        sadd("\\(mi");
       +                }
       +                return f;
       +        case '/':
       +                shim(pclass, nclass = SLASH);
       +                cadd('/');
       +                return f;
       +        case '~':
       +        case ' ':
       +                sadd("\\|\\|");
       +                return f;
       +        case '^':
       +                sadd("\\|");
       +                return f;
       +        case '\\':        /* troff - pass only \(xx without comment */
       +                shim(pclass, nclass);
       +                cadd('\\');
       +                cadd(c = *psp++);
       +                if (c == '(' && *psp && *(psp+1)) {
       +                        cadd(*psp++);
       +                        cadd(*psp++);
       +                } else
       +                        fprintf(stderr, "eqn warning: unquoted troff command \\%c, file %s:%d\n",
       +                                c, curfile->fname, curfile->lineno);
       +                return f;
       +        case '\'':
       +                shim(pclass, nclass);
       +                sadd("\\(fm");
       +                return f;
       +
       +        case 'f':
       +                if (ft == ITAL) {
       +                        shim(pclass, nclass = ILETF);
       +                        cadd('f');
       +                        f = ITAL;
       +                } else
       +                        cadd('f');
       +                return f;
       +        case 'j':
       +                if (ft == ITAL) {
       +                        shim(pclass, nclass = ILETJ);
       +                        cadd('j');
       +                        f = ITAL;
       +                } else
       +                        cadd('j');
       +                return f;
       +        default:
       +                shim(pclass, nclass);
       +                cadd(c);
       +                return ft==ITAL ? ITAL : ROM;
       +        }
       +}
       +
       +char *pad(int n)        /* return the padding as a string */
       +{
       +        static char buf[20];
       +
       +        buf[0] = 0;
       +        if (n < 0) {
       +                sprintf(buf, "\\h'-%du*\\w'\\^'u'", -n);
       +                return buf;
       +        }        
       +        for ( ; n > 1; n -= 2)
       +                strcat(buf, "\\|");
       +        if (n > 0)
       +                strcat(buf, "\\^");
       +        return buf;
       +}
       +
       +void shim(int lc, int rc)        /* add padding space suitable to left and right classes */
       +{
       +        sadd(pad(class[lc][rc]));
       +}
       +
       +void roman(int c)        /* add char c in "roman" font */
       +{
       +        nextft = ROM;
       +        cadd(c);
       +}
       +
       +void sadd(char *s)                /* add string s to cs */
       +{
       +        while (*s)
       +                cadd(*s++);
       +}
       +
       +void cadd(int c)                /* add character c to end of cs */
       +{
       +        char *p;
       +        int w;
       +
       +        if (lastft != nextft) {
       +                if (lastft != 0) {
       +                        *csp++ = '\\';
       +                        *csp++ = 'f';
       +                        *csp++ = 'P';
       +                }
       +                *csp++ = '\\';
       +                *csp++ = 'f';
       +                if (ftp == ftstack) {        /* bottom level */
       +                        if (ftp->ft == ITAL)        /* usual case */
       +                                *csp++ = nextft;
       +                        else                /* gfont set, use it */
       +                                for (p = ftp->name; *csp = *p++; )
       +                                        csp++;
       +                } else {        /* inside some kind of font ... */
       +                        for (p = ftp->name; *csp = *p++; )
       +                                csp++;
       +                }
       +                lastft = nextft;
       +        }
       +        w = wctomb(csp, c);
       +        if(w > 0)        /* ignore bad characters */
       +                csp += w;
       +}
 (DIR) diff --git a/src/cmd/eqn/tuning.c b/src/cmd/eqn/tuning.c
       t@@ -0,0 +1,153 @@
       +#include "e.h"
       +
       +/*
       +
       +This file contains parameter values for many of the
       +tuning parameters in eqn.  Names are defined words.
       +
       +Strings are plugged in verbatim.
       +Floats are usually in ems.
       +
       +*/
       +
       +/* In main.c: */
       +
       +double        BeforeSub = 1.2;        /* line space before a subscript */
       +double        AfterSub  = 0.2;        /* line space after a subscript */
       +
       +/* diacrit.c: */
       +
       +double        Dvshift        = 0.25;                /* vertical shift for diacriticals on tall letters */
       +double        Dhshift = 0.025;        /* horizontal shift for tall letters */
       +double        Dh2shift = 0.05;        /* horizontal shift for small letters */
       +double        Dheight        = 0.25;                /* increment to height for diacriticals */
       +double        Barv        = 0.68;                /* vertical shift for bar */
       +double        Barh        = 0.05;                /* 1/2 horizontal shrink for bar */
       +double        Ubarv        = 0.1;                /* shift underbar up this much ems */
       +double        Ubarh        = 0.05;                /* 1/2 horizontal shrink for underbar */
       +
       +/* Also:
       +        Vec, Dyad, Hat, Tilde, Dot, Dotdot, Utilde */
       +
       +/* eqnbox.c: */
       +
       +char        *IRspace = "\\^";        /* space between italic & roman boxes */
       +
       +/* fat.c: */
       +
       +double        Fatshift = 0.05;        /* fattening shifts by Fatshift ems */
       +
       +/* funny.c: */
       +
       +int        Funnyps        = 5;                /* point size change (== 5 above) */
       +double        Funnyht = 0.2;                /* height correction */
       +double        Funnybase = 0.3;        /* base correction */
       +
       +/* integral.c: */
       +
       +int        Intps        = 4;                /* point size change for integral (== 4 above) */
       +double        Intht        = 1.15;                /* ht of integral in ems */
       +double        Intbase        = 0.3;                /* base in ems */
       +double        Int1h        = 0.4;                /* lower limit left */
       +double        Int1v        = 0.2;                /* lower limit down */
       +double        Int2h        = 0.05;                /* upper limit right was 8 */
       +double        Int2v        = 0.1;                /* upper limit up */
       +
       +/* matrix.c: */
       +
       +char        *Matspace = "\\ \\ ";        /* space between matrix columns */
       +
       +/* over.c: */
       +
       +double        Overgap        = 0.3;                /* gap between num and denom */
       +double        Overwid        = 0.5;                /* extra width of box */
       +double        Overline = 0.1;                /* extra length of fraction bar */
       +
       +/* paren.c* */
       +
       +double        Parenbase = 0.4;        /* shift of base for even count */
       +double        Parenshift = 0.13;        /* how much to shift parens down in left ... */
       +                                /* ignored unless postscript */
       +double        Parenheight = 0.3;        /* extra height above builtups */
       +
       +/* pile.c: */
       +
       +double        Pilegap        = 0.4;                /* gap between pile elems */
       +double        Pilebase = 0.5;                /* shift base of even # of piled elems */
       +
       +/* shift.c: */
       +
       +double        Subbase        = 0.2;                /* subscript base belowe main base */
       +double        Supshift = 0.4;                /* superscript .4 up main box */
       +char        *Sub1space = "\\|";        /* italic sub roman space */
       +char        *Sup1space = "\\|";        /* italic sup roman space */
       +char        *Sub2space = "\\^";        /* space after subscripted thing */
       +char        *SS1space = "\\^";        /* space before sub in x sub i sup j */
       +char        *SS2space = "\\^";        /* space before sup */
       +
       +/* sqrt.c: */
       +        /* sqrt is hard!  punt for now. */
       +        /* part of the problem is that every typesetter does it differently */
       +        /* and we have several typesetters to run. */
       +
       +/* text.c: */
       +        /* ought to be done by a table */
       +
       +struct tune {
       +        char        *name;
       +        char        *cval;
       +} tune[]        ={
       +  /* diacrit.c */
       +        "vec_def",        "\\f1\\v'-.5m'\\s-3\\(->\\s0\\v'.5m'\\fP",        /* was \s-2 & .45m */
       +        "dyad_def",        "\\f1\\v'-.5m'\\s-3\\z\\(<-\\|\\(->\\s0\\v'.5m'\\fP",
       +        "hat_def",        "\\f1\\v'-.05m'\\s+1^\\s0\\v'.05m'\\fP",        /* was .1 */
       +        "tilde_def",        "\\f1\\v'-.05m'\\s+1~\\s0\\v'.05m'\\fP",
       +        "dot_def",        "\\f1\\v'-.67m'.\\v'.67m'\\fP",
       +        "dotdot_def",        "\\f1\\v'-.67m'..\\v'.67m'\\fP",
       +        "utilde_def",        "\\f1\\v'1.0m'\\s+2~\\s-2\\v'-1.0m'\\fP",
       +  /* funny.c */
       +        "sum_def",        "\\|\\v'.3m'\\s+5\\(*S\\s-5\\v'-.3m'\\|",
       +        "union_def",        "\\|\\v'.3m'\\s+5\\(cu\\s-5\\v'-.3m'\\|",
       +        "inter_def",        "\\|\\v'.3m'\\s+5\\(ca\\s-5\\v'-.3m'\\|",
       +        "prod_def",        "\\|\\v'.3m'\\s+5\\(*P\\s-5\\v'-.3m'\\|",
       +  /* integral.c */
       +        "int_def",        "\\v'.1m'\\s+4\\(is\\s-4\\v'-.1m'",
       +        0, 0
       +};
       +
       +tbl        *ftunetbl[TBLSIZE];        /* user-defined names */
       +
       +char *ftunes[] ={        /* this table intentionally left small */
       +        "Subbase",
       +        "Supshift",
       +        0
       +};
       +
       +void init_tune(void)
       +{
       +        int i;
       +
       +        for (i = 0; tune[i].name != NULL; i++)
       +                install(deftbl, tune[i].name, tune[i].cval, 0);
       +        for (i = 0; ftunes[i] != NULL; i++)
       +                install(ftunetbl, ftunes[i], (char *) 0, 0);
       +}
       +
       +#define eq(s, t) (strcmp(s,t) == 0)
       +
       +void ftune(char *s, char *t)        /* brute force for now */
       +{
       +        double f = atof(t);
       +        double *target;
       +
       +        while (*t == ' ' || *t == '\t')
       +                t++;
       +        if (eq(s, "Subbase"))
       +                target = &Subbase;
       +        else if (eq(s, "Supshift"))
       +                target = &Supshift;
       +        if (t[0] == '+' || t[0] == '-')
       +                *target += f;
       +        else
       +                *target = f;
       +}
 (DIR) diff --git a/src/cmd/eqn/y.tab.h b/src/cmd/eqn/y.tab.h
       t@@ -0,0 +1,57 @@
       +#define        CONTIG        57346
       +#define        QTEXT        57347
       +#define        SPACE        57348
       +#define        THIN        57349
       +#define        TAB        57350
       +#define        MATRIX        57351
       +#define        LCOL        57352
       +#define        CCOL        57353
       +#define        RCOL        57354
       +#define        COL        57355
       +#define        ABOVE        57356
       +#define        MARK        57357
       +#define        LINEUP        57358
       +#define        SUM        57359
       +#define        INT        57360
       +#define        PROD        57361
       +#define        UNION        57362
       +#define        INTER        57363
       +#define        DEFINE        57364
       +#define        TDEFINE        57365
       +#define        NDEFINE        57366
       +#define        DELIM        57367
       +#define        GSIZE        57368
       +#define        GFONT        57369
       +#define        INCLUDE        57370
       +#define        IFDEF        57371
       +#define        DOTEQ        57372
       +#define        DOTEN        57373
       +#define        FROM        57374
       +#define        TO        57375
       +#define        OVER        57376
       +#define        SQRT        57377
       +#define        SUP        57378
       +#define        SUB        57379
       +#define        SIZE        57380
       +#define        FONT        57381
       +#define        ROMAN        57382
       +#define        ITALIC        57383
       +#define        BOLD        57384
       +#define        FAT        57385
       +#define        UP        57386
       +#define        DOWN        57387
       +#define        BACK        57388
       +#define        FWD        57389
       +#define        LEFT        57390
       +#define        RIGHT        57391
       +#define        DOT        57392
       +#define        DOTDOT        57393
       +#define        HAT        57394
       +#define        TILDE        57395
       +#define        BAR        57396
       +#define        LOWBAR        57397
       +#define        HIGHBAR        57398
       +#define        UNDER        57399
       +#define        VEC        57400
       +#define        DYAD        57401
       +#define        UTILDE        57402
 (DIR) diff --git a/src/cmd/grap/coord.c b/src/cmd/grap/coord.c
       t@@ -0,0 +1,71 @@
       +#include <stdio.h>
       +#include <string.h>
       +#include <stdlib.h>
       +#include "grap.h"
       +#include "y.tab.h"
       +
       +char        *dflt_coord = "gg";
       +char        *curr_coord = "gg";
       +int        ncoord        = 0;        /* number of explicit coord's given */
       +
       +Point        xcoord;
       +Point        ycoord;
       +int        xcflag        = 0;        /* 1 if xcoord set */
       +int        ycflag        = 0;
       +int        logcoord = 0;
       +
       +void coord_x(Point pt)        /* remember x coord */
       +{
       +        xcoord = pt;
       +        xcflag = 1;
       +        margin = 0;        /* no extra space around picture if explicit coords */
       +}
       +
       +void coord_y(Point pt)
       +{
       +        ycoord = pt;
       +        ycflag = 1;
       +        margin = 0;        /* no extra space if explicit coords */
       +}
       +
       +void coordlog(int n)        /* remember log scaling */
       +{
       +        logcoord = n;
       +}
       +
       +void coord(Obj *p)        /* set coord range */
       +{
       +        static char buf[10];
       +
       +        ncoord++;
       +        if (ncoord > 1 && strcmp(p->name, dflt_coord) == 0) {
       +                /* resetting default coordinate by implication */
       +                sprintf(buf, "gg%d", ncoord);
       +                dflt_coord = buf;
       +                p = lookup(dflt_coord, 1);
       +        }
       +        if (xcflag) {
       +                p->coord |= XFLAG;
       +                p->pt.x = min(xcoord.x,xcoord.y);        /* "xcoord" is xmin, xmax */
       +                p->pt1.x = max(xcoord.x,xcoord.y);
       +                if ((logcoord&XFLAG) && p->pt.x <= 0.0)
       +                        ERROR "can't have log of x coord %g,%g", p->pt.x, p->pt1.x FATAL;
       +                xcflag = 0;
       +        }
       +        if (ycflag) {
       +                p->coord |= YFLAG;
       +                p->pt.y = min(ycoord.x,ycoord.y);        /* "ycoord" is ymin, ymax */
       +                p->pt1.y = max(ycoord.x,ycoord.y);
       +                if ((logcoord&YFLAG) && p->pt.y <= 0.0)
       +                        ERROR "can't have log of y coord %g,%g", p->pt.y, p->pt1.y FATAL;
       +                ycflag = 0;
       +        }
       +        p->log = logcoord;
       +        logcoord = 0;
       +        auto_x = 0;
       +}
       +
       +void resetcoord(Obj *p)        /* reset current coordinate */
       +{
       +        curr_coord = p->name;
       +}
 (DIR) diff --git a/src/cmd/grap/find b/src/cmd/grap/find
       t@@ -0,0 +1 @@
       +exec /usr/bin/egrep -n "$1" *.[chyl]
 (DIR) diff --git a/src/cmd/grap/for.c b/src/cmd/grap/for.c
       t@@ -0,0 +1,89 @@
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include "grap.h"
       +#include "y.tab.h"
       +
       +typedef struct {
       +        Obj        *var;        /* index variable */
       +        double        to;        /* limit */
       +        double        by;
       +        int        op;        /* operator */
       +        char        *str;        /* string to push back */
       +} For;
       +
       +#define        MAXFOR        10
       +
       +For        forstk[MAXFOR];        /* stack of for loops */
       +For        *forp = forstk;        /* pointer to current top */
       +
       +void forloop(Obj *var, double from, double to, int op, double by, char *str)        /* set up a for loop */
       +{
       +        fprintf(tfd, "# for %s from %g to %g by %c %g \n",
       +                var->name, from, to, op, by);
       +        if (++forp >= forstk+MAXFOR)
       +                ERROR "for loop nested too deep" FATAL;
       +        forp->var = var;
       +        forp->to = to;
       +        forp->op = op;
       +        forp->by = by;
       +        forp->str = str;
       +        setvar(var, from);
       +        nextfor();
       +        unput('\n');
       +}
       +
       +void nextfor(void)        /* do one iteration of a for loop */
       +{
       +        /* BUG:  this should depend on op and direction */
       +        if (forp->var->fval > SLOP * forp->to) {        /* loop is done */
       +                free(forp->str);
       +                if (--forp < forstk)
       +                        ERROR "forstk popped too far" FATAL;
       +        } else {                /* another iteration */
       +                pushsrc(String, "\nEndfor\n");
       +                pushsrc(String, forp->str);
       +        }
       +}
       +
       +void endfor(void)        /* end one iteration of for loop */
       +{
       +        switch (forp->op) {
       +        case '+':
       +        case ' ':
       +                forp->var->fval += forp->by;
       +                break;
       +        case '-':
       +                forp->var->fval -= forp->by;
       +                break;
       +        case '*':
       +                forp->var->fval *= forp->by;
       +                break;
       +        case '/':
       +                forp->var->fval /= forp->by;
       +                break;
       +        }
       +        nextfor();
       +}
       +
       +char *ifstat(double expr, char *thenpart, char *elsepart)
       +{
       +        dprintf("if %g then <%s> else <%s>\n", expr, thenpart, elsepart? elsepart : "");
       +        if (expr) {
       +                unput('\n');
       +                pushsrc(Free, thenpart);
       +                pushsrc(String, thenpart);
       +                unput('\n');
       +                  if (elsepart)
       +                        free(elsepart);
       +                return thenpart;        /* to be freed later */
       +        } else {
       +                free(thenpart);
       +                if (elsepart) {
       +                        unput('\n');
       +                        pushsrc(Free, elsepart);
       +                        pushsrc(String, elsepart);
       +                        unput('\n');
       +                }
       +                return elsepart;
       +        }
       +}
 (DIR) diff --git a/src/cmd/grap/frame.c b/src/cmd/grap/frame.c
       t@@ -0,0 +1,71 @@
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include "grap.h"
       +#include "y.tab.h"
       +
       +double        frame_ht;        /* default frame height */
       +double        frame_wid;        /* and width */
       +
       +int        nsides        = 0;                /* how many sides given on this frame */
       +char        *sides[] = {
       +                "\tline from Frame.nw to Frame.ne",
       +                "\tline from Frame.sw to Frame.se",
       +                "\tline from Frame.sw to Frame.nw",
       +                "\tline from Frame.se to Frame.ne"
       +};
       +char        *newsides[4] = { 0, 0, 0, 0 };        /* filled in later */
       +
       +void frame(void)                /* pump out frame definition, reset for next */
       +{
       +        int i;
       +
       +        fprintf(tfd, "\tframeht = %g\n", frame_ht);
       +        fprintf(tfd, "\tframewid = %g\n", frame_wid);
       +        fprintf(tfd, "Frame:\tbox ht frameht wid framewid with .sw at 0,0 ");
       +        if (nsides == 0)
       +                fprintf(tfd, "\n");
       +        else {
       +                fprintf(tfd, "invis\n");
       +                for (i = 0; i < 4; i++) {
       +                        if (newsides[i]) {
       +                                fprintf(tfd, "%s\n", newsides[i]);
       +                                free(newsides[i]);
       +                                newsides[i] = 0;
       +                        } else
       +                                fprintf(tfd, "%s\n", sides[i]);
       +                }
       +                nsides = 0;
       +        }
       +}
       +
       +void frameht(double f)        /* set height of frame */
       +{
       +        frame_ht = f;
       +}
       +
       +void framewid(double f)        /* set width of frame */
       +{
       +        frame_wid = f;
       +}
       +
       +void frameside(int type, Attr *desc)        /* create and remember sides */
       +{
       +        int n;
       +        char buf[100];
       +
       +        nsides++;
       +        switch (type) {
       +        case 0:                /* no side specified; kludge up all */
       +                frameside(TOP, desc);
       +                frameside(BOT, desc);
       +                frameside(LEFT, desc);
       +                frameside(RIGHT, desc);
       +                return;
       +        case TOP:        n = 0; break;
       +        case BOT:        n = 1; break;
       +        case LEFT:        n = 2; break;
       +        case RIGHT:        n = 3; break;
       +        }
       +        sprintf(buf, "%s %s", sides[n], desc_str(desc));
       +        newsides[n] = tostring(buf);
       +}
 (DIR) diff --git a/src/cmd/grap/grap.h b/src/cmd/grap/grap.h
       t@@ -0,0 +1,236 @@
       +extern        char        errbuf[200];
       +#define        ERROR        sprintf(errbuf,
       +#define        FATAL        ), yyerror(errbuf), exit(1)
       +#define        WARNING        ), yyerror(errbuf)
       +
       +#define        dprintf        if(dbg)printf
       +
       +#define        String        01
       +#define        Macro        02
       +#define        File        04
       +#define        Char        010
       +#define        Thru        020
       +#define        Free        040
       +
       +#define        MARGIN        0.07        /* default margin around data */
       +#define        SLOP        1.001        /* slop for limits of for loops */
       +#define        FRAMEWID 3        /* default width for boxes and ellipses */
       +#define        FRAMEHT        2        /* default height and line length */
       +#define        TICKLEN        0.1
       +
       +#define        MAXNUM        200
       +
       +#define        XFLAG        01
       +#define        YFLAG        02
       +
       +#define        INTICK        01
       +#define        OUTICK        02
       +
       +#define        BOT        01
       +#define        TOP        02
       +#define        RIGHT        04
       +#define        LEFT        010
       +
       +#define        RJUST        01
       +#define        LJUST        02
       +#define        ABOVE        04
       +#define        BELOW        010
       +
       +typedef struct infile {
       +        FILE        *fin;
       +        char        *fname;
       +        int        lineno;
       +} Infile;
       +
       +typedef struct {        /* input source */
       +        int        type;        /* Macro, String, File */
       +        char        *sp;        /* if String or Macro */
       +} Src;
       +
       +extern        Src        src[], *srcp;        /* input source stack */
       +
       +#define        MAXARGS        100
       +typedef struct {        /* argument stack */
       +        char        *argstk[MAXARGS];        /* pointers to args */
       +        char        *argval;        /* points to space containing args */
       +} Arg;
       +
       +extern        Infile        infile[10];
       +extern        Infile        *curfile;
       +
       +typedef struct {
       +        struct obj *obj;
       +        double        x, y;
       +} Point;
       +
       +typedef struct attr {        /* e.g., DASH 1.1 or "..." rjust size *.5 */
       +        int        type;
       +        double        fval;
       +        char        *sval;
       +        int        just;        /* justification, for STRING type */
       +        int        op;        /* optional operator, ditto */
       +        struct attr *next;
       +} Attr;
       +
       +typedef struct obj {        /* a name and its properties */
       +        char        *name;
       +        char        *val;        /* body of define, etc. */
       +        double        fval;        /* if a numeric variable */
       +        Point        pt;        /* usually for max and min */
       +        Point        pt1;
       +        int        type;        /* NAME, DEFNAME, ... */
       +        int        first;        /* 1 after 1st item seen */
       +        int        coord;        /* 1 if coord system specified for this name */
       +        int        log;        /* x, y, or z (= x+y) */
       +        Attr        *attr;        /* DASH, etc., for now */
       +        struct obj *next;
       +} Obj;
       +
       +typedef union {                /* the yacc stack type */
       +        int        i;
       +        char        *p;
       +        double        f;
       +        Point        pt;
       +        Obj        *op;
       +        Attr        *ap;
       +} YYSTYPE;
       +
       +extern        YYSTYPE        yylval, yyval;
       +
       +extern        int        dbg;
       +
       +extern        int        ntext;
       +extern        double        num[MAXNUM];
       +extern        int        nnum;
       +extern        int        ntick, tside;
       +
       +extern        char        *tostring(char *);
       +extern char *grow(char *, char *, int, int);
       +
       +extern        int        lineno;
       +extern        int        synerr;
       +extern        int        codegen;
       +extern        char        tempfile[];
       +extern        FILE        *tfd;
       +
       +extern        Point        ptmin, ptmax;
       +
       +extern        char        *dflt_coord;
       +extern        char        *curr_coord;
       +extern        int        ncoord;
       +extern        int        auto_x;
       +extern        double        margin;
       +extern        int        autoticks;
       +extern        int        pointsize, ps_set;
       +
       +
       +#define        logit(x) (x) = log10(x)
       +#define        Log10(x) errcheck(log10(x), "log")
       +#define        Exp(x)        errcheck(exp(x), "exp")
       +#define        Sqrt(x)        errcheck(sqrt(x), "sqrt")
       +
       +#define        min(x,y)        (((x) <= (y)) ? (x) : (y))
       +#define        max(x,y)        (((x) >= (y)) ? (x) : (y))
       +
       +extern        void        yyerror(char *);
       +extern void coord_x(Point);
       +extern void coord_y(Point);
       +extern void coordlog(int);
       +extern void coord(Obj *);
       +extern void resetcoord(Obj *);
       +extern void savenum(int, double);
       +extern void setjust(int);
       +extern void setsize(int, double);
       +extern void range(Point);
       +extern void halfrange(Obj *, int, double);
       +extern Obj *lookup(char *, int);
       +extern double getvar(Obj *);
       +extern double setvar(Obj *, double);
       +extern Point makepoint(Obj *, double, double);
       +extern Attr *makefattr(int, double);
       +extern Attr *makesattr(char *);
       +extern Attr *makeattr(int, double, char *, int, int);
       +extern Attr *addattr(Attr *, Attr *);
       +extern void freeattr(Attr *);
       +extern char *slprint(Attr *);
       +extern char *juststr(int);
       +extern char *sprntf(char *, Attr *);
       +extern void forloop(Obj *, double, double, int, double, char *);
       +extern void nextfor(void);
       +extern void endfor(void);
       +extern char *ifstat(double, char *, char *);
       +extern void frame(void);
       +extern void frameht(double);
       +extern void framewid(double);
       +extern void frameside(int, Attr *);
       +extern void pushsrc(int, char *);
       +extern void popsrc(void);
       +extern void definition(char *);
       +extern char *delimstr(char *);
       +extern int baldelim(int, char *);
       +extern void dodef(Obj *);
       +extern int getarg(char *);
       +extern int input(void);
       +extern int nextchar(void);
       +extern void do_thru(void);
       +extern int unput(int);
       +extern void pbstr(char *);
       +extern double errcheck(double, char *);
       +extern void yyerror(char *);
       +extern void eprint(void);
       +extern int yywrap(void);
       +extern void copyfile(char *);
       +extern void copydef(Obj *);
       +extern Obj *copythru(char *);
       +extern char *addnewline(char *);
       +extern void copyuntil(char *);
       +extern void copy(void);
       +extern void shell_init(void);
       +extern void shell_text(char *);
       +extern void shell_exec(void);
       +extern void labelwid(double);
       +extern void labelmove(int, double);
       +extern void label(int, Attr *);
       +extern void lab_adjust(void);
       +extern char *sizeit(Attr *);
       +extern void line(int, Point, Point, Attr *);
       +extern void circle(double, Point);
       +extern char *xyname(Point);
       +extern void pic(char *);
       +extern void numlist(void);
       +extern void plot(Attr *, Point);
       +extern void plotnum(double, char *, Point);
       +extern void drawdesc(int, Obj *, Attr *, char *);
       +extern void next(Obj *, Point, Attr *);
       +extern void print(void);
       +extern void endstat(void);
       +extern void graph(char *);
       +extern void setup(void);
       +extern void do_first(void);
       +extern void reset(void);
       +extern void opentemp(void);
       +extern void savetick(double, char *);
       +extern void dflt_tick(double);
       +extern void tickside(int);
       +extern void tickoff(int);
       +extern void gridtickoff(void);
       +extern void setlist(void);
       +extern void tickdir(int, double, int);
       +extern void ticks(void);
       +extern double modfloor(double, double);
       +extern double modceil(double, double);
       +extern void do_autoticks(Obj *);
       +extern void logtick(double, double, double);
       +extern Obj *setauto(void);
       +extern void autoside(Obj *, int);
       +extern void autolog(Obj *, int);
       +extern void iterator(double, double, int, double, char *);
       +extern void ticklist(Obj *, int);
       +extern void print_ticks(int, int, Obj *, char *, char *);
       +extern void maketick(int, char *, int, int, double, char *, char *, char *);
       +extern void griddesc(Attr *);
       +extern void gridlist(Obj *);
       +extern char *desc_str(Attr *);
       +extern int sidelog(int, int);
       +
       +extern        Obj        *objlist;
 (DIR) diff --git a/src/cmd/grap/grap.y b/src/cmd/grap/grap.y
       t@@ -0,0 +1,396 @@
       +%{
       +#include <stdio.h>
       +#include <math.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include "grap.h"
       +
       +//#define        RAND_MAX 32767        /* if your rand() returns bigger, change this too */
       +
       +extern int yylex(void);
       +extern int yyparse(void);
       +
       +%}
       +
       +%token        <i>        FRAME TICKS GRID LABEL COORD
       +%token        <i>        LINE ARROW CIRCLE DRAW NEW PLOT NEXT
       +%token        <p>        PIC
       +%token        <i>        COPY THRU UNTIL
       +%token        <i>        FOR FROM TO BY AT WITH
       +%token        <i>        IF
       +%token        <p>        GRAPH THEN ELSE DOSTR
       +%token        <i>        DOT DASH INVIS SOLID
       +%token        <i>        TEXT JUST SIZE
       +%token        <i>        LOG EXP SIN COS ATAN2 SQRT RAND MAX MIN INT PRINT SPRINTF
       +%token        <i>        X Y SIDE IN OUT OFF UP DOWN ACROSS
       +%token        <i>        HEIGHT WIDTH RADIUS
       +%token        <f>        NUMBER
       +%token        <op>        NAME VARNAME DEFNAME
       +%token        <p>        STRING
       +%token        <i>        ST '(' ')' ','
       +
       +%right        <f>        '='
       +%left        <f>        OR
       +%left        <f>        AND
       +%nonassoc <f>        GT LT LE GE EQ NE
       +%left        <f>        '+' '-'
       +%left        <f>        '*' '/' '%'
       +%right        <f>        UMINUS NOT
       +%right        <f>        '^'
       +
       +%type        <f>        expr optexpr if_expr number assign
       +%type        <i>        optop
       +%type        <p>        optstring if
       +%type        <op>        optname iterator name
       +%type        <pt>        point
       +%type        <i>        side optside numlist comma linetype drawtype
       +%type        <ap>        linedesc optdesc stringlist string stringattr sattrlist exprlist
       +%type        <i>        frameitem framelist coordlog
       +%type        <f>        string_expr
       +
       +%%
       +
       +top:
       +          graphseq                { if (codegen && !synerr) graph((char *) 0); }
       +        | /* empty */                { codegen = 0; }
       +        | error                        { codegen = 0; ERROR "syntax error" WARNING; }
       +        ;
       +
       +graphseq:
       +          statlist
       +        | graph statlist
       +        | graphseq graph statlist
       +        ;
       +graph:
       +          GRAPH                        { graph($1); endstat(); }
       +        ;
       +
       +statlist:
       +          ST
       +        | stat ST                { endstat(); }
       +        | statlist stat ST        { endstat(); }
       +        ;
       +
       +stat:
       +          FRAME framelist        { codegen = 1; }
       +        | ticks                        { codegen = 1; }
       +        | grid                        { codegen = 1; }
       +        | label                        { codegen = 1; }
       +        | coord
       +        | plot                        { codegen = 1; }
       +        | line                        { codegen = 1; }
       +        | circle                { codegen = 1; }
       +        | draw
       +        | next                        { codegen = 1; }
       +        | PIC                        { codegen = 1; pic($1); }
       +        | for
       +        | if
       +        | copy
       +        | numlist                { codegen = 1; numlist(); }
       +        | assign
       +        | PRINT expr                { fprintf(stderr, "\t%g\n", $2); }
       +        | PRINT string                { fprintf(stderr, "\t%s\n", $2->sval); freeattr($2); }
       +        | /* empty */
       +        ;
       +
       +numlist:
       +          number                { savenum(0, $1); $$ = 1; }
       +        | numlist number        { savenum($1, $2); $$ = $1+1; }
       +        | numlist comma number        { savenum($1, $3); $$ = $1+1; }
       +        ;
       +number:
       +          NUMBER
       +        | '-' NUMBER %prec UMINUS        { $$ = -$2; }
       +        | '+' NUMBER %prec UMINUS        { $$ = $2; }
       +        ;
       +
       +label:
       +          LABEL optside stringlist lablist        { label($2, $3); }
       +        ;
       +lablist:
       +          labattr
       +        | lablist labattr
       +        | /* empty */
       +        ;
       +labattr:
       +          UP expr                { labelmove($1, $2); }
       +        | DOWN expr                { labelmove($1, $2); }
       +        | SIDE expr                { labelmove($1, $2); /* LEFT or RIGHT only */ }
       +        | WIDTH expr                { labelwid($2); }
       +        ;
       +
       +framelist:
       +          framelist frameitem
       +        | /* empty */                { $$ = 0; }
       +        ;
       +frameitem:
       +          HEIGHT expr                { frameht($2); }
       +        | WIDTH expr                { framewid($2); }
       +        | side linedesc                { frameside($1, $2); }
       +        | linedesc                { frameside(0, $1); }
       +        ;
       +side:
       +          SIDE
       +        ;
       +optside:
       +          side
       +        | /* empty */                { $$ = 0; }
       +        ;
       +
       +linedesc:
       +          linetype optexpr        { $$ = makeattr($1, $2, (char *) 0, 0, 0); }
       +        ;
       +linetype:
       +          DOT | DASH | SOLID | INVIS
       +        ;
       +optdesc:
       +          linedesc
       +        | /* empty */                { $$ = makeattr(0, 0.0, (char *) 0, 0, 0); }
       +        ;
       +
       +ticks:
       +          TICKS tickdesc        { ticks(); }
       +        ;
       +tickdesc:
       +          tickattr
       +        | tickdesc tickattr
       +        ;
       +tickattr:
       +          side                        { tickside($1); }
       +        | IN expr                { tickdir(IN, $2, 1); }
       +        | OUT expr                { tickdir(OUT, $2, 1); }
       +        | IN                        { tickdir(IN, 0.0, 0); }
       +        | OUT                        { tickdir(OUT, 0.0, 0); }
       +        | AT optname ticklist        { setlist(); ticklist($2, AT); }
       +        | iterator                { setlist(); ticklist($1, AT); }
       +        | side OFF                { tickoff($1); }
       +        | OFF                        { tickoff(LEFT|RIGHT|TOP|BOT); }
       +        | labattr
       +        ;
       +ticklist:
       +          tickpoint
       +        | ticklist comma tickpoint
       +        ;
       +tickpoint:
       +          expr                        { savetick($1, (char *) 0); }
       +        | expr string                { savetick($1, $2->sval); }
       +        ;
       +iterator:
       +          FROM optname expr TO optname expr BY optop expr optstring
       +                        { iterator($3, $6, $8, $9, $10); $$ = $2; }
       +        | FROM optname expr TO optname expr optstring
       +                        { iterator($3, $6, '+', 1.0, $7); $$ = $2; }
       +        ;
       +optop:
       +          '+'                { $$ = '+'; }
       +        | '-'                { $$ = '-'; }
       +        | '*'                { $$ = '*'; }
       +        | '/'                { $$ = '/'; }
       +        | /* empty */        { $$ = ' '; }
       +        ;
       +optstring:
       +          string        { $$ = $1->sval; }
       +        | /* empty */        { $$ = (char *) 0; }
       +        ;
       +
       +grid:
       +          GRID griddesc                { ticks(); }
       +        ;
       +griddesc:
       +          gridattr
       +        | griddesc gridattr
       +        ;
       +gridattr:
       +          side                        { tickside($1); }
       +        | X                        { tickside(BOT); }
       +        | Y                        { tickside(LEFT); }
       +        | linedesc                { griddesc($1); }
       +        | AT optname ticklist        { setlist(); gridlist($2); }
       +        | iterator                { setlist(); gridlist($1); }
       +        | TICKS OFF                { gridtickoff(); }
       +        | OFF                        { gridtickoff(); }
       +        | labattr
       +        ;
       +
       +line:
       +          LINE FROM point TO point optdesc        { line($1, $3, $5, $6); }
       +        | LINE optdesc FROM point TO point        { line($1, $4, $6, $2); }
       +        ;
       +circle:
       +          CIRCLE RADIUS expr AT point                { circle($3, $5); }
       +        | CIRCLE AT point RADIUS expr                { circle($5, $3); }
       +        | CIRCLE AT point                        { circle(0.0, $3); }
       +        ;
       +
       +stringlist:
       +          string
       +        | stringlist string        { $$ = addattr($1, $2); }
       +        ;
       +string:
       +          STRING sattrlist        { $$ = makesattr($1); }
       +        | SPRINTF '(' STRING ')' sattrlist
       +                                { $$ = makesattr(sprntf($3, (Attr*) 0)); }
       +        | SPRINTF '(' STRING ',' exprlist ')' sattrlist
       +                                { $$ = makesattr(sprntf($3, $5)); }
       +        ;
       +exprlist:
       +          expr                        { $$ = makefattr(NUMBER, $1); }
       +        | exprlist ',' expr        { $$ = addattr($1, makefattr(NUMBER, $3)); }
       +        ;
       +sattrlist:
       +          stringattr
       +        | sattrlist stringattr
       +        | /* empty */                { $$ = (Attr *) 0; }
       +        ;
       +stringattr:
       +          JUST                        { setjust($1); }
       +        | SIZE optop expr        { setsize($2, $3); }
       +        ;
       +
       +coord:
       +          COORD optname coordlist        { coord($2); }
       +        | COORD optname                        { resetcoord($2); }
       +        ;
       +coordlist:
       +          coorditem
       +        | coordlist coorditem
       +        ;
       +coorditem:
       +          coordlog        { coordlog($1); }
       +        | X point        { coord_x($2); }
       +        | Y point        { coord_y($2); }
       +        | X optname expr TO expr                { coord_x(makepoint($2, $3, $5)); }
       +        | Y optname expr TO expr                { coord_y(makepoint($2, $3, $5)); }
       +        | X FROM optname expr TO expr                { coord_x(makepoint($3, $4, $6)); }
       +        | Y FROM optname expr TO expr                { coord_y(makepoint($3, $4, $6)); }
       +        ;
       +coordlog:
       +          LOG X                { $$ = XFLAG; }
       +        | LOG Y                { $$ = YFLAG; }
       +        | LOG X LOG Y        { $$ = XFLAG|YFLAG; }
       +        | LOG Y LOG X        { $$ = XFLAG|YFLAG; }
       +        | LOG LOG        { $$ = XFLAG|YFLAG; }
       +        ;
       +
       +plot:
       +          stringlist AT point                { plot($1, $3); }
       +        | PLOT stringlist AT point        { plot($2, $4); }
       +        | PLOT expr optstring AT point        { plotnum($2, $3, $5); }
       +        ;
       +
       +draw:
       +          drawtype optname linedesc                { drawdesc($1, $2, $3, (char *) 0); }
       +        | drawtype optname optdesc string        { drawdesc($1, $2, $3, $4->sval); }
       +        | drawtype optname string optdesc        { drawdesc($1, $2, $4, $3->sval); }
       +        ;
       +drawtype:
       +          DRAW
       +        | NEW
       +        ;
       +
       +next:
       +          NEXT optname AT point optdesc                { next($2, $4, $5); }
       +
       +copy:
       +          COPY copylist                { copy(); }
       +        ;
       +copylist:
       +          copyattr
       +        | copylist copyattr
       +        ;
       +copyattr:
       +          string                { copyfile($1->sval); }
       +        | THRU DEFNAME                { copydef($2); }
       +        | UNTIL string                { copyuntil($2->sval); }
       +        ;
       +
       +for:
       +          FOR name FROM expr TO expr BY optop expr DOSTR
       +                { forloop($2, $4, $6, $8, $9, $10); }
       +        | FOR name FROM expr TO expr DOSTR
       +                { forloop($2, $4, $6, '+', 1.0, $7); }
       +        | FOR name '=' expr TO expr BY optop expr DOSTR
       +                { forloop($2, $4, $6, $8, $9, $10); }
       +        | FOR name '=' expr TO expr DOSTR
       +                { forloop($2, $4, $6, '+', 1.0, $7); }
       +        ;
       +
       +if:
       +          IF if_expr THEN ELSE                { $$ = ifstat($2, $3, $4); }
       +        | IF if_expr THEN                { $$ = ifstat($2, $3, (char *) 0); }
       +        ;
       +if_expr:
       +          expr
       +        | string_expr
       +        | if_expr AND string_expr        { $$ = $1 && $3; }
       +        | if_expr OR string_expr        { $$ = $1 || $3; }
       +        ;
       +string_expr:
       +          STRING EQ STRING        { $$ = strcmp($1,$3) == 0; free($1); free($3); }
       +        | STRING NE STRING        { $$ = strcmp($1,$3) != 0; free($1); free($3); }
       +        ;
       +
       +point:
       +          optname expr comma expr                { $$ = makepoint($1, $2, $4); }
       +        | optname '(' expr comma expr ')'        { $$ = makepoint($1, $3, $5); }
       +        ;
       +comma:
       +          ','                { $$ = ','; }
       +        ;
       +
       +optname:
       +          NAME                { $$ = $1; }
       +        | /* empty */        { $$ = lookup(curr_coord, 1); }
       +        ;
       +
       +expr:
       +          NUMBER
       +        | assign
       +        | '(' string_expr ')'        { $$ = $2; }
       +        | VARNAME                { $$ = getvar($1); }
       +        | expr '+' expr                { $$ = $1 + $3; }
       +        | expr '-' expr                { $$ = $1 - $3; }
       +        | expr '*' expr                { $$ = $1 * $3; }
       +        | expr '/' expr                { if ($3 == 0.0) {
       +                                        ERROR "division by 0" WARNING; $3 = 1; }
       +                                  $$ = $1 / $3; }
       +        | expr '%' expr                { if ((long)$3 == 0) {
       +                                        ERROR "mod division by 0" WARNING; $3 = 1; }
       +                                  $$ = (long)$1 % (long)$3; }
       +        | '-' expr %prec UMINUS        { $$ = -$2; }
       +        | '+' expr %prec UMINUS        { $$ = $2; }
       +        | '(' expr ')'                { $$ = $2; }
       +        | LOG '(' expr ')'                { $$ = Log10($3); }
       +        | EXP '(' expr ')'                { $$ = Exp($3 * log(10.0)); }
       +        | expr '^' expr                        { $$ = pow($1, $3); }
       +        | SIN '(' expr ')'                { $$ = sin($3); }
       +        | COS '(' expr ')'                { $$ = cos($3); }
       +        | ATAN2 '(' expr ',' expr ')'        { $$ = atan2($3, $5); }
       +        | SQRT '(' expr ')'                { $$ = Sqrt($3); }
       +        | RAND '(' ')'                        { $$ = (double)rand() / (double)RAND_MAX; }
       +        | MAX '(' expr ',' expr ')'        { $$ = $3 >= $5 ? $3 : $5; }
       +        | MIN '(' expr ',' expr ')'        { $$ = $3 <= $5 ? $3 : $5; }
       +        | INT '(' expr ')'        { $$ = (long) $3; }
       +        | expr GT expr                { $$ = $1 > $3; }
       +        | expr LT expr                { $$ = $1 < $3; }
       +        | expr LE expr                { $$ = $1 <= $3; }
       +        | expr GE expr                { $$ = $1 >= $3; }
       +        | expr EQ expr                { $$ = $1 == $3; }
       +        | expr NE expr                { $$ = $1 != $3; }
       +        | expr AND expr                { $$ = $1 && $3; }
       +        | expr OR expr                { $$ = $1 || $3; }
       +        | NOT expr                { $$ = !($2); }
       +        ;
       +assign:
       +          name '=' expr                { $$ = setvar($1, $3); }
       +        ;
       +
       +name:
       +          NAME
       +        | VARNAME
       +        ;
       +
       +optexpr:
       +          expr
       +        | /* empty */                { $$ = 0.0; }
       +        ;
 (DIR) diff --git a/src/cmd/grap/grapl.lx b/src/cmd/grap/grapl.lx
       t@@ -0,0 +1,213 @@
       +%Start A str def thru sh
       +
       +%{
       +#undef        input
       +#undef        unput
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <ctype.h>
       +#include "grap.h"
       +#include "y.tab.h"
       +
       +extern        struct        symtab        symtab[];
       +
       +int        yyback(int *, int);
       +int        yylook(void);
       +int        yywrap(void);
       +void        shell_init(void), shell_exec(void), shell_text(char *);
       +
       +#define        CADD        cbuf[clen++] = yytext[0]; \
       +                if (clen >= CBUFLEN-1) { \
       +                        ERROR "string too long", cbuf WARNING; BEGIN A; }
       +#define        CBUFLEN        1500
       +char        cbuf[CBUFLEN];
       +int        clen, cflag;
       +int        c, delim, shcnt;
       +%}
       +
       +A        [a-zA-Z_]
       +B        [a-zA-Z0-9_]
       +D        [0-9]
       +WS        [ \t]
       +
       +%%
       +        if (yybgin-yysvec-1 == 0) {        /* witchcraft */
       +                BEGIN A;
       +        }
       +
       +<A>{WS}                ;
       +<A>"\\"\n        ;
       +<A>\n                return(ST);
       +<A>";"                return(ST);
       +
       +<A>line                return(yylval.i = LINE);
       +<A>arrow        { yylval.i = ARROW; return(LINE); }
       +<A>circle        return(yylval.i = CIRCLE);
       +<A>frame        return(FRAME);
       +<A>tick(s)?        return(TICKS);
       +<A>grid(line)?(s)?        return(GRID);
       +<A>coord(s)?        return(COORD);
       +<A>log                return(LOG);
       +<A>exp                return(EXP);
       +<A>sin                return(SIN);
       +<A>cos                return(COS);
       +<A>atan2        return(ATAN2);
       +<A>sqrt                return(SQRT);
       +<A>rand                return(RAND);
       +<A>max                return(MAX);
       +<A>min                return(MIN);
       +<A>int                return(INT);
       +<A>print        return(PRINT);
       +<A>sprintf        return(SPRINTF);
       +<A>pic{WS}.*        { yylval.p = tostring(yytext+3); return(PIC); }
       +<A>graph{WS}.*        { yylval.p = tostring(yytext+5); return(GRAPH); }
       +
       +<A>for                return(FOR);
       +<A>^Endfor\n        { endfor(); }
       +<A>do                { yylval.p = delimstr("loop body"); BEGIN A; return(DOSTR); }
       +
       +<A>copy|include        { return(COPY); }
       +<A>thru|through        { BEGIN thru; return(THRU); }
       +<thru>{WS}+        ;
       +<thru>{A}{B}*|.        { yylval.op = copythru(yytext); BEGIN A; return(DEFNAME); }
       +<A>until        return(UNTIL);
       +
       +<A>if                return(IF);
       +<A>then                { yylval.p = delimstr("then part"); BEGIN A; return(THEN); }
       +<A>else                { yylval.p = delimstr("else part"); BEGIN A; return(ELSE); }
       +
       +<A>next                return(NEXT);
       +<A>draw                return(yylval.i = DRAW);
       +<A>new                return(yylval.i = NEW);
       +<A>plot                return(yylval.i = PLOT);
       +<A>label(s)?        return(LABEL);
       +<A>x                return(X);
       +<A>y                return(Y);
       +
       +<A>top                { yylval.i = TOP; return SIDE; }
       +<A>bot(tom)?        { yylval.i = BOT; return SIDE; }
       +<A>left                { yylval.i = LEFT; return SIDE; }
       +<A>right        { yylval.i = RIGHT; return SIDE; }
       +<A>up                return(yylval.i = UP);
       +<A>down                return(yylval.i = DOWN);
       +<A>across        return(yylval.i = ACROSS);
       +<A>height|ht        return(yylval.i = HEIGHT);
       +<A>wid(th)?        return(yylval.i = WIDTH);
       +<A>rad(ius)?        return(yylval.i = RADIUS);
       +<A>invis        return(yylval.i = INVIS);
       +<A>dot(ted)        return(yylval.i = DOT);
       +<A>dash(ed)        return(yylval.i = DASH);
       +<A>solid        return(yylval.i = SOLID);
       +
       +<A>ljust        { yylval.i = LJUST; return JUST; }
       +<A>rjust        { yylval.i = RJUST; return JUST; }
       +<A>above        { yylval.i = ABOVE; return JUST; }
       +<A>below        { yylval.i = BELOW; return JUST; }
       +<A>size                return(yylval.i = SIZE);
       +
       +<A>from                return(yylval.i = FROM);
       +<A>to                return(yylval.i = TO);
       +<A>by|step        return(yylval.i = BY);
       +<A>at                return(yylval.i = AT);
       +<A>with                return(yylval.i = WITH);
       +<A>in                return(yylval.i = IN);
       +<A>out                return(yylval.i = OUT);
       +<A>off                return(yylval.i = OFF);
       +
       +<A>sh{WS}+ {        BEGIN sh;
       +                if ((delim = input()) == '{') {
       +                        shcnt = 1;
       +                        delim = '}';
       +                }
       +                shell_init();
       +        }
       +<sh>{A}{B}* {
       +                int c;
       +                Obj *p;
       +                if (yytext[0] == delim) {
       +                        shell_exec();
       +                        BEGIN A;
       +                } else {
       +                        p = lookup(yytext, 0);
       +                        if (p != NULL && p->type == DEFNAME) {
       +                                c = input();
       +                                unput(c);
       +                                if (c == '(')
       +                                        dodef(p);
       +                                else
       +                                        pbstr(p->val);
       +                        } else
       +                                shell_text(yytext);
       +                }
       +        }
       +<sh>"{"                { shcnt++; shell_text(yytext); }
       +<sh>"}"                { if (delim != '}' || --shcnt > 0)
       +                        shell_text(yytext);
       +                  else {
       +                        shell_exec();
       +                        BEGIN A;
       +                  }
       +                }
       +<sh>.|\n        { if (yytext[0] == delim) {
       +                        shell_exec();
       +                        BEGIN A;
       +                  } else
       +                        shell_text(yytext);
       +                }
       +
       +<A>define{WS}+        { BEGIN def; }
       +<def>{A}{B}*        { definition(yytext); BEGIN A; }
       +
       +<A>({D}+("."?){D}*|"."{D}+)((e|E)("+"|-)?{D}+)?i? {
       +                  yylval.f = atof(yytext); return(NUMBER); }
       +
       +<A>^"."[^0-9].*        { if (yytext[1] == 'G' && yytext[2] == '2') {
       +                        yylval.i = yytext[2];
       +                        return(EOF);
       +                  } else {
       +                        yylval.p = tostring(yytext);
       +                        return(PIC);
       +                  }
       +                }
       +
       +<A>{A}{B}* {
       +                int c;
       +                Obj *p;
       +                p = lookup(yytext, 1);
       +                if (p->type == DEFNAME) {
       +                        c = input();
       +                        unput(c);
       +                        if (c == '(')        /* it's name(...) */
       +                                dodef(p);
       +                        else        /* no argument list */
       +                                pbstr(p->val);
       +                } else {
       +                        yylval.op = p;
       +                        return p->type;        /* NAME or VARNAME */
       +                }
       +        }
       +
       +<A>"=="                return(EQ);
       +<A>">="                return(GE);
       +<A>"<="                return(LE);
       +<A>"!="                return(NE);
       +<A>">"                return(GT);
       +<A>"<"                return(LT);
       +<A>"&&"                return(AND);
       +<A>"||"                return(OR);
       +<A>"!"                return(NOT);        
       +
       +<A>\"                { BEGIN str; clen = 0; }
       +
       +<A>#.*                ;
       +
       +<A>.                { yylval.i = yytext[0]; return(yytext[0]); }
       +
       +<str>\"                { BEGIN A; cbuf[clen] = 0;
       +                  yylval.p = tostring(cbuf); return(STRING); }
       +<str>\n                { ERROR "newline in string" WARNING; BEGIN A; return(ST); }
       +<str>"\\\""        { cbuf[clen++] = '\\'; cbuf[clen++] = '"'; }
       +<str>"\\\\"        { cbuf[clen++] = '\\'; cbuf[clen++] = '\\'; }
       +<str>.                { CADD; }
       +
       +%%
 (DIR) diff --git a/src/cmd/grap/input.c b/src/cmd/grap/input.c
       t@@ -0,0 +1,580 @@
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include <ctype.h>
       +#include <errno.h>
       +#include "grap.h"
       +#include "y.tab.h"
       +
       +Infile        infile[10];
       +Infile        *curfile = infile;
       +
       +#define        MAXSRC        50
       +Src        src[MAXSRC];        /* input source stack */
       +Src        *srcp        = src;
       +
       +void pushsrc(int type, char *ptr)        /* new input source */
       +{
       +        if (++srcp >= src + MAXSRC)
       +                ERROR "inputs nested too deep" FATAL;
       +        srcp->type = type;
       +        srcp->sp = ptr;
       +        if (dbg) {
       +                printf("\n%3d ", srcp - src);
       +                switch (srcp->type) {
       +                case File:
       +                        printf("push file %s\n", ((Infile *)ptr)->fname);
       +                        break;
       +                case Macro:
       +                        printf("push macro <%s>\n", ptr);
       +                        break;
       +                case Char:
       +                        printf("push char <%c>\n", *ptr);
       +                        break;
       +                case Thru:
       +                        printf("push thru\n");
       +                        break;
       +                case String:
       +                        printf("push string <%s>\n", ptr);
       +                        break;
       +                case Free:
       +                        printf("push free <%s>\n", ptr);
       +                        break;
       +                default:
       +                        ERROR "pushed bad type %d", srcp->type FATAL;
       +                }
       +        }
       +}
       +
       +void popsrc(void)        /* restore an old one */
       +{
       +        if (srcp <= src)
       +                ERROR "too many inputs popped" FATAL;
       +        if (dbg) {
       +                printf("%3d ", srcp - src);
       +                switch (srcp->type) {
       +                case File:
       +                        printf("pop file\n");
       +                        break;
       +                case Macro:
       +                        printf("pop macro\n");
       +                        break;
       +                case Char:
       +                        printf("pop char <%c>\n", *srcp->sp);
       +                        break;
       +                case Thru:
       +                        printf("pop thru\n");
       +                        break;
       +                case String:
       +                        printf("pop string\n");
       +                        break;
       +                case Free:
       +                        printf("pop free\n");
       +                        break;
       +                default:
       +                        ERROR "pop weird input %d", srcp->type FATAL;
       +                }
       +        }
       +        srcp--;
       +}
       +
       +void definition(char *s)        /* collect definition for s and install */
       +                                /* definitions picked up lexically */
       +{
       +        char *p;
       +        Obj *stp;
       +
       +        p = delimstr("definition");
       +        stp = lookup(s, 0);
       +        if (stp != NULL) {        /* it's there before */
       +                if (stp->type != DEFNAME) {
       +                        ERROR "%s used as variable and definition", s WARNING;
       +                        return;
       +                }
       +                free(stp->val);
       +        } else {
       +                stp = lookup(s, 1);
       +                stp->type = DEFNAME;
       +        }
       +        stp->val = p;
       +        dprintf("installing %s as `%s'\n", s, p);
       +}
       +
       +char *delimstr(char *s)        /* get body of X ... X */
       +                        /* message if too big */
       +{
       +        int c, delim, rdelim, n, deep;
       +        static char *buf = NULL;
       +        static int nbuf = 0;
       +        char *p;
       +
       +        if (buf == NULL)
       +                buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
       +        while ((delim = input()) == ' ' || delim == '\t' || delim == '\n')
       +                ;
       +        rdelim = baldelim(delim, "{}");                /* could be "(){}[]`'" */
       +        deep = 1;
       +        for (p = buf; ; ) {
       +                c = input();
       +                if (c == rdelim)
       +                        if (--deep == 0)
       +                                break;
       +                if (c == delim)
       +                        deep++;
       +                if (p >= buf + nbuf) {
       +                        n = p - buf;
       +                        buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
       +                        p = buf + n;
       +                }
       +                if (c == EOF)
       +                        ERROR "end of file in %s %c %.20s... %c", s, delim, buf, delim FATAL;
       +                *p++ = c;
       +        }
       +        *p = '\0';
       +        dprintf("delimstr %s %c <%s> %c\n", s, delim, buf, delim);
       +        return tostring(buf);
       +}
       +
       +baldelim(int c, char *s)        /* replace c by balancing entry in s */
       +{
       +        for ( ; *s; s += 2)
       +                if (*s == c)
       +                        return s[1];
       +        return c;
       +}
       +
       +Arg        args[10];        /* argument frames */
       +Arg        *argfp = args;        /* frame pointer */
       +int        argcnt;                /* number of arguments seen so far */
       +
       +void dodef(Obj *stp)        /* collect args and switch input to defn */
       +{
       +        int i, len;
       +        char *p;
       +        Arg *ap;
       +
       +        ap = argfp+1;
       +        if (ap >= args+10)
       +                ERROR "arguments too deep" FATAL;
       +        argcnt = 0;
       +        if (input() != '(')
       +                ERROR "disaster in dodef" FATAL;
       +        if (ap->argval == 0)
       +                ap->argval = malloc(1000);
       +        for (p = ap->argval; (len = getarg(p)) != -1; p += len) {
       +                ap->argstk[argcnt++] = p;
       +                if (input() == ')')
       +                        break;
       +        }
       +        for (i = argcnt; i < MAXARGS; i++)
       +                ap->argstk[i] = "";
       +        if (dbg)
       +                for (i = 0; i < argcnt; i++)
       +                        printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
       +        argfp = ap;
       +        pushsrc(Macro, stp->val);
       +}
       +
       +getarg(char *p)        /* pick up single argument, store in p, return length */
       +{
       +        int n, c, npar;
       +
       +        n = npar = 0;
       +        for ( ;; ) {
       +                c = input();
       +                if (c == EOF)
       +                        ERROR "end of file in getarg!" FATAL;
       +                if (npar == 0 && (c == ',' || c == ')'))
       +                        break;
       +                if (c == '"')        /* copy quoted stuff intact */
       +                        do {
       +                                *p++ = c;
       +                                n++;
       +                        } while ((c = input()) != '"' && c != EOF);
       +                else if (c == '(')
       +                        npar++;
       +                else if (c == ')')
       +                        npar--;
       +                n++;
       +                *p++ = c;
       +        }
       +        *p = 0;
       +        unput(c);
       +        return(n + 1);
       +}
       +
       +#define        PBSIZE        2000
       +char        pbuf[PBSIZE];                /* pushback buffer */
       +char        *pb        = pbuf-1;        /* next pushed back character */
       +
       +char        ebuf[200];                /* collect input here for error reporting */
       +char        *ep        = ebuf;
       +
       +int        begin        = 0;
       +extern        int        thru;
       +extern        Obj        *thrudef;
       +extern        char        *untilstr;
       +
       +input(void)
       +{
       +        register int c;
       +
       +        if (thru && begin) {
       +                do_thru();
       +                begin = 0;
       +        }
       +        c = nextchar();
       +        dprintf(" <%c>", c);
       +        if (ep >= ebuf + sizeof ebuf)
       +                ep = ebuf;
       +        return *ep++ = c;
       +}
       +
       +nextchar(void)
       +{
       +        register int c;
       +
       +  loop:
       +        switch (srcp->type) {
       +        case Free:        /* free string */
       +                free(srcp->sp);
       +                popsrc();
       +                goto loop;
       +        case Thru:        /* end of pushed back line */
       +                begin = 1;
       +                popsrc();
       +                c = '\n';
       +                break;
       +        case Char:
       +                if (pb >= pbuf) {
       +                        c = *pb--;
       +                        popsrc();
       +                        break;
       +                } else {        /* can't happen? */
       +                        popsrc();
       +                        goto loop;
       +                }
       +        case String:
       +                c = *srcp->sp++;
       +                if (c == '\0') {
       +                        popsrc();
       +                        goto loop;
       +                } else {
       +                        if (*srcp->sp == '\0')        /* empty, so pop */
       +                                popsrc();
       +                        break;
       +                }
       +        case Macro:
       +                c = *srcp->sp++;
       +                if (c == '\0') {
       +                        if (--argfp < args)
       +                                ERROR "argfp underflow" FATAL;
       +                        popsrc();
       +                        goto loop;
       +                } else if (c == '$' && isdigit(*srcp->sp)) {        /* $3 */
       +                        int n = 0;
       +                        while (isdigit(*srcp->sp))
       +                                n = 10 * n + *srcp->sp++ - '0';
       +                        if (n > 0 && n <= MAXARGS)
       +                                pushsrc(String, argfp->argstk[n-1]);
       +                        goto loop;
       +                }
       +                break;
       +        case File:
       +                c = getc(curfile->fin);
       +                if (c == EOF) {
       +                        if (curfile == infile)
       +                                ERROR "end of file inside .G1/.G2" FATAL;
       +                        if (curfile->fin != stdin) {
       +                                fclose(curfile->fin);
       +                                free(curfile->fname);        /* assumes allocated */
       +                        }
       +                        curfile--;
       +                        printf(".lf %d %s\n", curfile->lineno, curfile->fname);
       +                        popsrc();
       +                        thru = 0;        /* chicken out */
       +                        thrudef = 0;
       +                        if (untilstr) {
       +                                free(untilstr);
       +                                untilstr = 0;
       +                        }
       +                        goto loop;
       +                }
       +                if (c == '\n')
       +                        curfile->lineno++;
       +                break;
       +        }
       +        return c;
       +}
       +
       +void do_thru(void)        /* read one line, make into a macro expansion */
       +{
       +        int c, i;
       +        char *p;
       +        Arg *ap;
       +
       +        ap = argfp+1;
       +        if (ap >= args+10)
       +                ERROR "arguments too deep" FATAL;
       +        if (ap->argval == NULL)
       +                ap->argval = malloc(1000);
       +        p = ap->argval;
       +        argcnt = 0;
       +        c = nextchar();
       +        if (thru == 0) {        /* end of file was seen, so thru is done */
       +                unput(c);
       +                return;
       +        }
       +        for ( ; c != '\n' && c != EOF; ) {
       +                if (c == ' ' || c == '\t') {
       +                        c = nextchar();
       +                        continue;
       +                }
       +                if (argcnt >= MAXARGS)
       +                        ERROR "too many fields on input line" FATAL;
       +                ap->argstk[argcnt++] = p;
       +                if (c == '"') {
       +                        do {
       +                                *p++ = c;
       +                                if ((c = nextchar()) == '\\') {
       +                                        *p++ = c;
       +                                        *p++ = nextchar();
       +                                        c = nextchar();
       +                                }
       +                        } while (c != '"' && c != '\n' && c != EOF);
       +                        *p++ = '"';
       +                        if (c == '"')
       +                                c = nextchar();
       +                } else {
       +                        do {
       +                                *p++ = c;
       +                        } while ((c = nextchar())!=' ' && c!='\t' && c!='\n' && c!=',' && c!=EOF);
       +                        if (c == ',')
       +                                c = nextchar();
       +                }
       +                *p++ = '\0';
       +        }
       +        if (c == EOF)
       +                ERROR "unexpected end of file in do_thru" FATAL;
       +        if (argcnt == 0) {        /* ignore blank line */
       +                pushsrc(Thru, (char *) 0);
       +                return;
       +        }
       +        for (i = argcnt; i < MAXARGS; i++)
       +                ap->argstk[i] = "";
       +        if (dbg)
       +                for (i = 0; i < argcnt; i++)
       +                        printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
       +        if (strcmp(ap->argstk[0], ".G2") == 0) {
       +                thru = 0;
       +                thrudef = 0;
       +                pushsrc(String, "\n.G2\n");
       +                return;
       +        }
       +        if (untilstr && strcmp(ap->argstk[0], untilstr) == 0) {
       +                thru = 0;
       +                thrudef = 0;
       +                free(untilstr);
       +                untilstr = 0;
       +                return;
       +        }
       +        pushsrc(Thru, (char *) 0);
       +        dprintf("do_thru pushing back <%s>\n", thrudef->val);
       +        argfp = ap;
       +        pushsrc(Macro, thrudef->val);
       +}
       +
       +unput(int c)
       +{
       +        if (++pb >= pbuf + sizeof pbuf)
       +                ERROR "pushback overflow" FATAL;
       +        if (--ep < ebuf)
       +                ep = ebuf + sizeof(ebuf) - 1;
       +        *pb = c;
       +        pushsrc(Char, pb);
       +        return c;
       +}
       +
       +void pbstr(char *s)
       +{
       +        pushsrc(String, s);
       +}
       +
       +double errcheck(double x, char *s)
       +{
       +        extern int errno;
       +
       +        if (errno == EDOM) {
       +                errno = 0;
       +                ERROR "%s argument out of domain", s WARNING;
       +        } else if (errno == ERANGE) {
       +                errno = 0;
       +                ERROR "%s result out of range", s WARNING;
       +        }
       +        return x;
       +}
       +
       +char        errbuf[200];
       +
       +void yyerror(char *s)
       +{
       +        extern char *cmdname;
       +        int ern = errno;        /* cause some libraries clobber it */
       +
       +        if (synerr)
       +                return;
       +        fflush(stdout);
       +        fprintf(stderr, "%s: %s", cmdname, s);
       +        if (ern > 0) {
       +                errno = ern;
       +                perror("???");
       +        }
       +        fprintf(stderr, " near %s:%d\n",
       +                curfile->fname, curfile->lineno+1);
       +        eprint();
       +        synerr = 1;
       +        errno = 0;
       +}
       +
       +void eprint(void)        /* try to print context around error */
       +{
       +        char *p, *q;
       +
       +        p = ep - 1;
       +        if (p > ebuf && *p == '\n')
       +                p--;
       +        for ( ; p >= ebuf && *p != '\n'; p--)
       +                ;
       +        while (*p == '\n')
       +                p++;
       +        fprintf(stderr, " context is\n\t");
       +        for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
       +                ;
       +        for (; p < q; p++)
       +                if (isprint(*p))
       +                        putc(*p, stderr);
       +        fprintf(stderr, " >>> ");
       +        for (; p < q; p++)
       +                if (isprint(*p))
       +                        putc(*p, stderr);
       +        fprintf(stderr, " <<< ");
       +        while (pb >= pbuf)
       +                putc(*pb--, stderr);
       +        fgets(ebuf, sizeof ebuf, curfile->fin);
       +        fprintf(stderr, "%s", ebuf);
       +        pbstr("\n.G2\n");        /* safety first */
       +        ep = ebuf;
       +}
       +
       +int yywrap(void) {return 1;}
       +
       +char        *newfile = 0;                /* filename for file copy */
       +char        *untilstr = 0;                /* string that terminates a thru */
       +int        thru        = 0;                /* 1 if copying thru macro */
       +Obj        *thrudef = 0;                /* macro being used */
       +
       +void copyfile(char *s)        /* remember file to start reading from */
       +{
       +        newfile = s;
       +}
       +
       +void copydef(Obj *p)        /* remember macro Obj */
       +{
       +        thrudef = p;
       +}
       +
       +Obj *copythru(char *s)        /* collect the macro name or body for thru */
       +{
       +        Obj *p;
       +        char *q;
       +
       +        p = lookup(s, 0);
       +        if (p != NULL) {
       +                if (p->type == DEFNAME) {
       +                        p->val = addnewline(p->val);
       +                        return p;
       +                } else
       +                        ERROR "%s used as define and name", s FATAL;
       +        }
       +        /* have to collect the definition */
       +        pbstr(s);        /* first char is the delimiter */
       +        q = delimstr("thru body");
       +        p = lookup("nameless", 1);
       +        if (p != NULL)
       +                if (p->val)
       +                        free(p->val);
       +        p->type = DEFNAME;
       +        p->val = q;
       +        p->val = addnewline(p->val);
       +        dprintf("installing nameless as `%s'\n", p->val);
       +        return p;
       +}
       +
       +char *addnewline(char *p)        /* add newline to end of p */
       +{
       +        int n;
       +
       +        n = strlen(p);
       +        if (p[n-1] != '\n') {
       +                p = realloc(p, n+2);
       +                p[n] = '\n';
       +                p[n+1] = '\0';
       +        }
       +        return p;
       +}
       +
       +void copyuntil(char *s)        /* string that terminates a thru */
       +{
       +        untilstr = s;
       +}
       +
       +void copy(void)        /* begin input from file, etc. */
       +{
       +        FILE *fin;
       +
       +        if (newfile) {
       +                if ((fin = fopen(unsharp(newfile), "r")) == NULL)
       +                        ERROR "can't open file %s", newfile FATAL;
       +                curfile++;
       +                curfile->fin = fin;
       +                curfile->fname = tostring(newfile);
       +                curfile->lineno = 0;
       +                printf(".lf 1 %s\n", curfile->fname);
       +                pushsrc(File, curfile->fname);
       +                newfile = 0;
       +        }
       +        if (thrudef) {
       +                thru = 1;
       +                begin = 1;        /* wrong place */
       +        }
       +}
       +
       +char        shellbuf[1000], *shellp;
       +
       +void shell_init(void)        /* set up to interpret a shell command */
       +{
       +        fprintf(tfd, "# shell cmd...\n");
       +        sprintf(shellbuf, "rc -c '");
       +        shellp = shellbuf + strlen(shellbuf);
       +}
       +
       +void shell_text(char *s)        /* add string to command being collected */
       +{
       +        /* fprintf(tfd, "#add <%s> to <%s>\n", s, shellbuf); */
       +        while (*s) {
       +                if (*s == '\'')        {        /* protect interior quotes */
       +                        *shellp++ = '\'';
       +                        *shellp++ = '\\';
       +                        *shellp++ = '\'';
       +                }
       +                *shellp++ = *s++;
       +        }
       +}
       +
       +void shell_exec(void)        /* do it */
       +{
       +        /* fprintf(tfd, "# run <%s>\n", shellbuf); */
       +        *shellp++ = '\'';
       +        *shellp = '\0';
       +        system(shellbuf);
       +}
 (DIR) diff --git a/src/cmd/grap/label.c b/src/cmd/grap/label.c
       t@@ -0,0 +1,123 @@
       +#include <stdio.h>
       +#include <string.h>
       +#include "grap.h"
       +#include "y.tab.h"
       +
       +int        pointsize        = 10;        /* assumed pointsize to start */
       +int        ps_set                = 0;        /* someone has set pointsize explicitly */
       +
       +double        textht        = 1.0/6.0;        /* 6 lines/inch */
       +double        textwid = 1;                /* width of text box for vertical */
       +
       +double        lab_up        = 0.0;                /* extra motion for label */
       +double        lab_rt        = 0.0;                /* extra motion for label */
       +double        lab_wid        = 0.0;                /* override default width computation */
       +
       +void labelwid(double amt)
       +{
       +        lab_wid = amt + .00001;
       +}
       +
       +void labelmove(int dir, double amt)        /* record direction & motion of position corr */
       +{
       +        switch (dir) {
       +        case UP:        lab_up += amt; break;
       +        case DOWN:        lab_up -= amt; break;
       +        case LEFT:        lab_rt -= amt; break;
       +        case RIGHT:        lab_rt += amt; break;
       +        }
       +}
       +
       +void label(int label_side, Attr *stringlist)        /* stick label on label_side */
       +{
       +        int m;
       +        Attr *ap;
       +
       +        fprintf(tfd, "\ttextht = %g\n", textht);
       +        if (lab_wid != 0.0) {
       +                fprintf(tfd, "\ttextwid = %g\n", lab_wid);
       +                lab_wid = 0;
       +        } else if (label_side == LEFT || label_side == RIGHT) {
       +                textwid = 0;
       +                for (ap = stringlist; ap != NULL; ap = ap->next)
       +                        if ((m = strlen(ap->sval)) > textwid)
       +                                textwid = m;
       +                textwid /= 15;        /* estimate width at 15 chars/inch */
       +                fprintf(tfd, "\ttextwid = %g\n", textwid);
       +        }
       +        fprintf(tfd, "Label:\t%s", slprint(stringlist));
       +        freeattr(stringlist);
       +        switch (label_side) {
       +        case BOT:
       +        case 0:
       +                fprintf(tfd, " with .n at Frame.s - (0,2 * textht)");
       +                break;
       +        case LEFT:
       +                fprintf(tfd, " wid textwid with .e at Frame.w - (0.2,0)");
       +                break;
       +        case RIGHT:
       +                fprintf(tfd, " wid textwid with .w at Frame.e + (0.2,0)");
       +                break;
       +        case TOP:
       +                fprintf(tfd, " with .s at Frame.n + (0,2 * textht)");
       +                break;
       +        }
       +        lab_adjust();
       +        fprintf(tfd, "\n");
       +        label_side = BOT;
       +}
       +
       +void lab_adjust(void)        /* add a string to adjust labels, ticks, etc. */
       +{
       +        if (lab_up != 0.0 || lab_rt != 0.0)
       +                fprintf(tfd, " + (%g,%g)", lab_rt, lab_up);
       +}
       +
       +char *sizeit(Attr *ap)                /* add \s..\s to ap->sval */
       +{
       +        int n;
       +        static char buf[1000];
       +
       +        if (!ap->op) {        /* no explicit size command */
       +                if (ps_set) {
       +                        sprintf(buf, "\\s%d%s\\s0", pointsize, ap->sval);
       +                        return buf;
       +                } else
       +                        return ap->sval;
       +        } else if (!ps_set) {        /* explicit size but no global size */
       +                n = (int) ap->fval;
       +                switch (ap->op) {
       +                case ' ':        /* absolute size */
       +                        sprintf(buf, "\\s%d%s\\s0", n, ap->sval);
       +                        break;
       +                case '+':        /* better be only one digit! */
       +                        sprintf(buf, "\\s+%d%s\\s-%d", n, ap->sval, n);
       +                        break;
       +                case '-':
       +                        sprintf(buf, "\\s-%d%s\\s+%d", n, ap->sval, n);
       +                        break;
       +                case '*':
       +                case '/':
       +                        return ap->sval;        /* ignore for now */
       +                }
       +                return buf;
       +        } else {
       +                /* explicit size and a global background size */
       +                n = (int) ap->fval;
       +                switch (ap->op) {
       +                case ' ':        /* absolute size */
       +                        sprintf(buf, "\\s%d%s\\s0", n, ap->sval);
       +                        break;
       +                case '+':
       +                        sprintf(buf, "\\s%d%s\\s0", pointsize+n, ap->sval);
       +                        break;
       +                case '-':
       +                        sprintf(buf, "\\s%d%s\\s0", pointsize-n, ap->sval);
       +                        break;
       +                case '*':
       +                case '/':
       +                        return ap->sval;        /* ignore for now */
       +                }
       +                return buf;
       +        }
       +}
 (DIR) diff --git a/src/cmd/grap/main.c b/src/cmd/grap/main.c
       t@@ -0,0 +1,164 @@
       +#include <stdio.h>
       +#include <signal.h>
       +#include <math.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include "grap.h"
       +#include "y.tab.h"
       +
       +int        dbg        = 0;
       +
       +#ifndef GRAPDEFINES
       +#define GRAPDEFINES "#9/sys/lib/grap.defines"
       +#endif
       +char        *lib_defines        = GRAPDEFINES;
       +
       +int        lib        = 1;                /* 1 to include lib_defines */
       +FILE        *tfd        = NULL;
       +char        tempfile[L_tmpnam];
       +
       +int        synerr        = 0;
       +int        codegen        = 0;                   /* 1=>output for this picture; 0=>no output */
       +char        *cmdname;
       +
       +Obj        *objlist = NULL;        /* all names stored here */
       +
       +#define        BIG        1e30
       +Point        ptmin        = { NULL, -BIG, -BIG };
       +Point        ptmax        = { NULL, BIG, BIG };
       +
       +char        *version = "version Dec 30, 1995";
       +
       +extern int yyparse(void);
       +extern void setdefaults(void);
       +extern void getdata(void);
       +extern        int        unlink(char *);
       +
       +main(int argc, char *argv[])
       +{
       +        extern void onintr(int), fpecatch(int);
       +
       +        if (signal(SIGINT, SIG_IGN) != SIG_IGN)
       +                signal(SIGINT, onintr);
       +        signal(SIGFPE, fpecatch);
       +        cmdname = argv[0];
       +        tmpnam(tempfile);
       +        while (argc > 1 && *argv[1] == '-') {
       +                switch (argv[1][1]) {
       +                case 'd':
       +                        dbg = 1;
       +                        tfd = stdout;
       +                        strcpy(tempfile, "grap.temp");
       +                        unlink(tempfile);
       +                        fprintf(stderr, "%s\n", version);
       +                        break;
       +                case 'l':        /* turn off /usr/lib inclusion */
       +                        lib = 0;
       +                        break;
       +                }
       +                argc--;
       +                argv++;
       +        }
       +        setdefaults();
       +        curfile = infile;
       +        if (argc <= 1) {
       +                curfile->fin = stdin;
       +                curfile->fname = tostring("-");
       +                pushsrc(File, curfile->fname);
       +                getdata();
       +        } else
       +                while (argc-- > 1) {
       +                        if ((curfile->fin = fopen(*++argv, "r")) == NULL) {
       +                                fprintf(stderr, "grap: can't open %s\n", *argv);
       +                                onintr(0);
       +                        }
       +                        curfile->fname = tostring(*argv);
       +                        pushsrc(File, curfile->fname);
       +                        getdata();
       +                        fclose(curfile->fin);
       +                        free(curfile->fname);
       +                }
       +        if (!dbg)
       +                unlink(tempfile);
       +        exit(0);
       +}
       +
       +void onintr(int n)
       +{
       +        n;
       +        if (!dbg)
       +                unlink(tempfile);
       +        exit(1);
       +}
       +
       +void fpecatch(int n)
       +{
       +        ERROR "floating point exception" WARNING;
       +        onintr(n);
       +}
       +
       +char *grow(char *ptr, char *name, int num, int size)        /* make array bigger */
       +{
       +        char *p;
       +
       +        if (ptr == NULL)
       +                p = malloc(num * size);
       +        else
       +                p = realloc(ptr, num * size);
       +        if (p == NULL)
       +                ERROR "can't grow %s to %d", name, num * size FATAL;
       +        return p;
       +}
       +
       +static struct {
       +        char        *name;
       +        double        val;
       +} defaults[] ={
       +        "frameht", FRAMEHT,
       +        "framewid", FRAMEWID,
       +        "ticklen", TICKLEN,
       +        "slop", SLOP,
       +        NULL, 0
       +};
       +
       +void setdefaults(void)        /* set default sizes for variables */
       +{
       +        int i;
       +        Obj *p;
       +
       +        for (i = 0; defaults[i].name != NULL; i++) {
       +                p = lookup(defaults[i].name, 1);
       +                setvar(p, defaults[i].val);
       +        }
       +}
       +
       +void getdata(void)                /* read input */
       +{
       +        register FILE *fin;
       +        char buf[1000], buf1[100];
       +        int ln;
       +
       +        fin = curfile->fin;
       +        curfile->lineno = 0;
       +        printf(".lf 1 %s\n", curfile->fname);
       +        while (fgets(buf, sizeof buf, fin) != NULL) {
       +                curfile->lineno++;
       +                if (*buf == '.' && *(buf+1) == 'G' && *(buf+2) == '1') {
       +                        setup();
       +                        fprintf(stdout, ".PS%s", &buf[3]);        /* maps .G1 [w] to .PS w */
       +                        printf("scale = 1\n");        /* defends against cip users */
       +                        printf(".lf %d\n", curfile->lineno+1);
       +                        yyparse();
       +                        fprintf(stdout, ".PE\n");
       +                        printf(".lf %d\n", curfile->lineno+1);
       +                        fflush(stdout);
       +                } else if (buf[0] == '.' && buf[1] == 'l' && buf[2] == 'f') {
       +                        if (sscanf(buf+3, "%d %s", &ln, buf1) == 2) {
       +                                free(curfile->fname);
       +                                printf(".lf %d %s\n", curfile->lineno = ln, curfile->fname = tostring(buf1));
       +                        } else
       +                                printf(".lf %d\n", curfile->lineno = ln);
       +                } else
       +                        fputs(buf, stdout);
       +        }
       +}
 (DIR) diff --git a/src/cmd/grap/misc.c b/src/cmd/grap/misc.c
       t@@ -0,0 +1,263 @@
       +#include <stdio.h>
       +#include <string.h>
       +#include <stdlib.h>
       +#include "grap.h"
       +#include "y.tab.h"
       +
       +int        nnum        = 0;        /* number of saved numbers */
       +double        num[MAXNUM];
       +
       +int        just;                /* current justification mode (RJUST, etc.) */
       +int        sizeop;                /* current optional operator for size change */
       +double        sizexpr;        /* current size change expression */
       +
       +void savenum(int n, double f)        /* save f in num[n] */
       +{
       +        num[n] = f;
       +        nnum = n+1;
       +        if (nnum >= MAXNUM)
       +                ERROR "too many numbers" WARNING;
       +}
       +
       +void setjust(int j)
       +{
       +        just |= j;
       +}
       +
       +void setsize(int op, double expr)
       +{
       +        sizeop = op;
       +        sizexpr = expr;
       +}
       +
       +char *tostring(char *s)
       +{
       +        register char *p;
       +
       +        p = malloc(strlen(s)+1);
       +        if (p == NULL)
       +                ERROR "out of space in tostring on %s", s FATAL;
       +        strcpy(p, s);
       +        return(p);
       +}
       +
       +void range(Point pt)        /* update the range for point pt */
       +{
       +        Obj *p = pt.obj;
       +
       +        if (!(p->coord & XFLAG)) {
       +                if (pt.x > p->pt1.x)
       +                        p->pt1.x = pt.x;
       +                if (pt.x < p->pt.x)
       +                        p->pt.x = pt.x;
       +        }
       +        if (!(p->coord & YFLAG)) {
       +                if (pt.y > p->pt1.y)
       +                        p->pt1.y = pt.y;
       +                if (pt.y < p->pt.y)
       +                        p->pt.y = pt.y;
       +        }
       +}
       +
       +void halfrange(Obj *p, int side, double val)        /* record max and min for one direction */
       +{
       +        if (!(p->coord&XFLAG) && (side == LEFT || side == RIGHT)) {
       +                if (val < p->pt.y)
       +                        p->pt.y = val;
       +                if (val > p->pt1.y)
       +                        p->pt1.y = val;
       +        } else if (!(p->coord&YFLAG) && (side == TOP || side == BOT)) {
       +                if (val < p->pt.x)
       +                        p->pt.x = val;
       +                if (val > p->pt1.x)
       +                        p->pt1.x = val;
       +        }
       +}
       +
       +
       +Obj *lookup(char *s, int inst)        /* find s in objlist, install if inst */
       +{
       +        Obj *p;
       +        int found = 0;
       +
       +        for (p = objlist; p; p = p->next){
       +                if (strcmp(s, p->name) == 0) {
       +                        found = 1;
       +                        break;
       +                }
       +        }
       +        if (p == NULL && inst != 0) {
       +                p = (Obj *) calloc(1, sizeof(Obj));
       +                if (p == NULL)
       +                        ERROR "out of space in lookup" FATAL;
       +                p->name = tostring(s);
       +                p->type = NAME;
       +                p->pt = ptmax;
       +                p->pt1 = ptmin;
       +                p->fval = 0.0;
       +                p->next = objlist;
       +                objlist = p;
       +        }
       +        dprintf("lookup(%s,%d) = %d\n", s, inst, found);
       +        return p;
       +}
       +
       +double getvar(Obj *p)        /* return value of variable */
       +{
       +        return p->fval;
       +}
       +
       +double setvar(Obj *p, double f)        /* set value of variable to f */
       +{
       +        if (strcmp(p->name, "pointsize") == 0) {        /* kludge */
       +                pointsize = f;
       +                ps_set = 1;
       +        }
       +        p->type = VARNAME;
       +        return p->fval = f;
       +}
       +
       +Point makepoint(Obj *s, double x, double y)        /* make a Point */
       +{
       +        Point p;
       +        
       +        dprintf("makepoint: %s, %g,%g\n", s->name, x, y);
       +        p.obj = s;
       +        p.x = x;
       +        p.y = y;
       +        return p;
       +}
       +
       +Attr *makefattr(int type, double fval)        /* set double in attribute */
       +{
       +        return makeattr(type, fval, (char *) 0, 0, 0);
       +}
       +
       +Attr *makesattr(char *s)                /* make an Attr cell containing s */
       +{
       +        Attr *ap = makeattr(STRING, sizexpr, s, just, sizeop);
       +        just = sizeop = 0;
       +        sizexpr = 0.0;
       +        return ap;
       +}
       +
       +Attr *makeattr(int type, double fval, char *sval, int just, int op)
       +{
       +        Attr *a;
       +
       +        a = (Attr *) malloc(sizeof(Attr));
       +        if (a == NULL)
       +                ERROR "out of space in makeattr" FATAL;
       +        a->type = type;
       +        a->fval = fval;
       +        a->sval = sval;
       +        a->just = just;
       +        a->op = op;
       +        a->next = NULL;
       +        return a;
       +}
       +
       +Attr *addattr(Attr *a1, Attr *ap)        /* add attr ap to end of list a1 */
       +{
       +        Attr *p;
       +
       +        if (a1 == 0)
       +                return ap;
       +        if (ap == 0)
       +                return a1;
       +        for (p = a1; p->next; p = p->next)
       +                ;
       +        p->next = ap;
       +        return a1;
       +}
       +
       +void freeattr(Attr *ap)        /* free an attribute list */
       +{
       +        Attr *p;
       +
       +        while (ap) {
       +                p = ap->next;        /* save next */
       +                if (ap->sval)
       +                        free(ap->sval);
       +                free((char *) ap);
       +                ap = p;
       +        }
       +}
       +
       +char *slprint(Attr *stringlist)        /* print strings from stringlist */
       +{
       +        int ntext, n, last_op, last_just;
       +        double last_fval;
       +        static char buf[1000];
       +        Attr *ap;
       +
       +        buf[0] = '\0';
       +        last_op = last_just = 0;
       +        last_fval = 0.0;
       +        for (ntext = 0, ap = stringlist; ap != NULL; ap = ap->next)
       +                ntext++;
       +        sprintf(buf, "box invis wid 0 ht %d*textht", ntext);
       +        n = strlen(buf);
       +        for (ap = stringlist; ap != NULL; ap = ap->next) {
       +                if (ap->op == 0) {        /* propagate last value */
       +                        ap->op = last_op;
       +                        ap->fval = last_fval;
       +                } else {
       +                        last_op = ap->op;
       +                        last_fval = ap->fval;
       +                }
       +                sprintf(buf+n, " \"%s\"", ps_set || ap->op ? sizeit(ap) : ap->sval);
       +                if (ap->just)
       +                        last_just = ap->just;
       +                if (last_just)
       +                        strcat(buf+n, juststr(last_just));
       +                n = strlen(buf);
       +        }
       +        return buf;        /* watch it:  static */
       +}
       +
       +char *juststr(int j)        /* convert RJUST, etc., into string */
       +{
       +        static char buf[50];
       +
       +        buf[0] = '\0';
       +        if (j & RJUST)
       +                strcat(buf, " rjust");
       +        if (j & LJUST)
       +                strcat(buf, " ljust");
       +        if (j & ABOVE)
       +                strcat(buf, " above");
       +        if (j & BELOW)
       +                strcat(buf, " below");
       +        return buf;        /* watch it:  static */
       +}
       +
       +char *sprntf(char *s, Attr *ap)        /* sprintf(s, attrlist ap) */
       +{
       +        char buf[500];
       +        int n;
       +        Attr *p;
       +
       +        for (n = 0, p = ap; p; p = p->next)
       +                n++;
       +        switch (n) {
       +        case 0:
       +                return s;
       +        case 1:
       +                sprintf(buf, s, ap->fval);
       +                break;
       +        case 2:
       +                sprintf(buf, s, ap->fval, ap->next->fval);
       +                break;
       +        case 3:
       +                sprintf(buf, s, ap->fval, ap->next->fval, ap->next->next->fval);
       +                break;
       +        case 5:
       +                ERROR "too many expressions in sprintf" WARNING;
       +        case 4:
       +                sprintf(buf, s, ap->fval, ap->next->fval, ap->next->next->fval, ap->next->next->next->fval);
       +                break;
       +        }
       +        free(s);
       +        return tostring(buf);
       +}
 (DIR) diff --git a/src/cmd/grap/mkfile b/src/cmd/grap/mkfile
       t@@ -0,0 +1,37 @@
       +<$PLAN9/src/mkhdr
       +
       +TARG=grap
       +OFILES=\
       +        grap.$O\
       +        grapl.$O\
       +        main.$O\
       +        input.$O\
       +        print.$O\
       +        frame.$O\
       +        for.$O\
       +        coord.$O\
       +        ticks.$O\
       +        plot.$O\
       +        label.$O\
       +        misc.$O\
       +
       +HFILES=grap.h\
       +        y.tab.h\
       +
       +YFILES=grap.y\
       +
       +LFILES=grapl.lx\
       +
       +SHORTLIB=bio 9
       +<$PLAN9/src/mkone
       +YFLAGS = -d -S
       +LEX=9lex
       +
       +grap.c:        y.tab.c
       +        mv $prereq $target
       +
       +grapl.c:        $LFILES
       +        $LEX -t $prereq > $target
       +
       +clean:V:
       +        rm -f [$OS].out *.[$OS] y.tab.? lex.yy.c grapl.c grap.c grap
 (DIR) diff --git a/src/cmd/grap/plot.c b/src/cmd/grap/plot.c
       t@@ -0,0 +1,132 @@
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <math.h>
       +#include "grap.h"
       +#include "y.tab.h"
       +
       +void line(int type, Point p1, Point p2, Attr *desc)        /* draw a line segment */
       +{
       +        fprintf(tfd, "%s %s from %s",
       +                type==LINE ? "line" : "arrow",  desc_str(desc), xyname(p1));
       +        fprintf(tfd, " to %s", xyname(p2));        /* 'cause xyname is botched */
       +        fprintf(tfd, "\n");
       +        range(p1);
       +        range(p2);
       +}
       +
       +void circle(double r, Point pt)                /* draw a circle */
       +{
       +        if (r > 0.0)
       +                fprintf(tfd, "circle rad %g at %s\n", r, xyname(pt));
       +        else
       +                fprintf(tfd, "\"\\s-3\\(ob\\s0\" at %s\n", xyname(pt));
       +        range(pt);
       +}
       +
       +char *xyname(Point pt)        /* generate xy name macro for point p */
       +{
       +        static char buf[200];
       +        Obj *p;
       +
       +        p = pt.obj;
       +        if (p->log & XFLAG) {
       +                if (pt.x <= 0.0)
       +                        ERROR "can't take log of x coord %g", pt.x FATAL;
       +                logit(pt.x);
       +        }
       +        if (p->log & YFLAG) {
       +                if (pt.y <= 0.0)
       +                        ERROR "can't take log of y coord %g", pt.y FATAL;
       +                logit(pt.y);
       +        }
       +        sprintf(buf, "xy_%s(%g,%g)", p->name, pt.x, pt.y);
       +        return buf;        /* WATCH IT:  static */
       +}
       +
       +void pic(char *s)        /* fire out pic stuff directly */
       +{
       +        while (*s == ' ')
       +                s++;
       +        fprintf(tfd, "%s\n", s);
       +}
       +
       +int        auto_x        = 0;        /* counts abscissa if none provided */
       +
       +void numlist(void)        /* print numbers in default way */
       +{
       +        Obj *p;
       +        Point pt;
       +        int i;
       +        static char *spot = "\\(bu";
       +        Attr *ap;
       +
       +        p = pt.obj = lookup(curr_coord, 1);
       +        if (nnum == 1) {
       +                nnum = 2;
       +                num[1] = num[0];
       +                num[0] = ++auto_x;
       +        }
       +        pt.x = num[0];
       +        if (p->attr && p->attr->sval)
       +                spot = p->attr->sval;
       +        for (i = 1; i < nnum; i++) {
       +                pt.y = num[i];
       +                if (p->attr == 0 || p->attr->type == 0) {
       +                        ap = makesattr(tostring(spot));
       +                        plot(ap, pt);
       +                } else
       +                        next(p, pt, p->attr);
       +        }
       +        nnum = 0;
       +}
       +
       +void plot(Attr *sl, Point pt)        /* put stringlist sl at point pt */
       +{
       +        fprintf(tfd, "%s at %s\n", slprint(sl), xyname(pt));
       +        range(pt);
       +        freeattr(sl);
       +}
       +
       +void plotnum(double f, char *fmt, Point pt)        /* plot value f at point */
       +{
       +        char buf[100];
       +
       +        if (fmt) {
       +                sprintf(buf, fmt, f);
       +                free(fmt);
       +        } else if (f >= 0.0)
       +                sprintf(buf, "%g", f);
       +        else
       +                sprintf(buf, "\\-%g", -f);
       +        fprintf(tfd, "\"%s\" at %s\n", buf, xyname(pt));
       +        range(pt);
       +}
       +
       +void drawdesc(int type, Obj *p, Attr *desc, char *s)        /* set line description for p */
       +{
       +        p->attr = desc;
       +        p->attr->sval = s;
       +        if (type == NEW) {
       +                p->first = 0;        /* so it really looks new */
       +                auto_x = 0;
       +        }
       +}
       +
       +void next(Obj *p, Point pt, Attr *desc)        /* add component to a path */
       +{
       +        char *s;
       +
       +        if (p->first == 0) {
       +                p->first++;
       +                fprintf(tfd, "L%s: %s\n", p->name, xyname(pt));
       +        } else {
       +                fprintf(tfd, "line %s from L%s to %s; L%s: Here\n",
       +                        desc_str(desc->type ? desc : p->attr),
       +                        p->name, xyname(pt), p->name);
       +        }
       +        if (p->attr && (s=p->attr->sval)) {
       +                /* BUG: should fix size here */
       +                fprintf(tfd, "\"%s\" at %s\n", s, xyname(pt));
       +        }
       +        range(pt);
       +}
 (DIR) diff --git a/src/cmd/grap/print.c b/src/cmd/grap/print.c
       t@@ -0,0 +1,236 @@
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include <math.h>
       +#include <ctype.h>
       +#include "grap.h"
       +#include "y.tab.h"
       +
       +double        margin        = MARGIN;        /* extra space around edges */
       +extern        double        frame_ht, frame_wid, ticklen;
       +extern int just, sizeop, tick_dir;
       +extern double sizexpr, lab_up, lab_rt;
       +
       +char        graphname[50] = "Graph";
       +char        graphpos[200] = "";
       +
       +void print(void)        /* arrange final output */
       +{
       +        FILE *fd;
       +        Obj *p, *dfp;
       +        int c;
       +        double dx, dy, xfac, yfac;
       +
       +        if (tfd != NULL) {
       +                fclose(tfd);        /* end the temp file */
       +                tfd = stdout;
       +        }
       +
       +        if ((p=lookup("margin",0)) != NULL)
       +                margin = p->fval;
       +        if (frame_ht < 0)        /* wasn't set explicitly, so use default */
       +                frame_ht = getvar(lookup("frameht", 0));
       +        if (frame_wid < 0)
       +                frame_wid = getvar(lookup("framewid", 0));
       +        dfp = NULL;
       +        for (p = objlist; p; p = p->next) {
       +                dprintf("print: name = <%s>, type = %d\n", p->name, p->type);
       +                if (p->type == NAME) {
       +                        Point pt, pt1;        
       +                        pt = p->pt;
       +                        pt1 = p->pt1;
       +                        fprintf(tfd, "\t# %s %g .. %g, %g .. %g\n",
       +                                p->name, pt.x, pt1.x, pt.y, pt1.y);
       +                        if (p->log & XFLAG) {
       +                                if (pt.x <= 0.0)
       +                                        ERROR "can't take log of x coord %g", pt.x FATAL;
       +                                logit(pt.x);
       +                                logit(pt1.x);
       +                        }
       +                        if (p->log & YFLAG) {
       +                                if (pt.y <= 0.0)
       +                                        ERROR "can't take log of y coord %g", pt.y FATAL;
       +                                logit(pt.y);
       +                                logit(pt1.y);
       +                        }
       +                        if (!(p->coord & XFLAG)) {
       +                                dx = pt1.x - pt.x;
       +                                pt.x -= margin * dx;
       +                                pt1.x += margin * dx;
       +                        }
       +                        if (!(p->coord & YFLAG)) {
       +                                dy = pt1.y - pt.y;
       +                                pt.y -= margin * dy;
       +                                pt1.y += margin * dy;
       +                        }
       +                        if (autoticks && strcmp(p->name, dflt_coord) == 0) {
       +                                p->pt = pt;
       +                                p->pt1 = pt1;
       +                                if (p->log & XFLAG) {
       +                                        p->pt.x = pow(10.0, pt.x);
       +                                        p->pt1.x = pow(10.0, pt1.x);
       +                                }
       +                                if (p->log & YFLAG) {
       +                                        p->pt.y = pow(10.0, pt.y);
       +                                        p->pt1.y = pow(10.0, pt1.y);
       +                                }
       +                                dfp = setauto();
       +                        }                
       +                        dx = pt1.x - pt.x;
       +                        dy = pt1.y - pt.y;
       +                        xfac = dx > 0 ? frame_wid/dx : frame_wid/2;
       +                        yfac = dy > 0 ? frame_ht/dy : frame_ht/2;
       +
       +                        fprintf(tfd, "define xy_%s @ ", p->name);
       +                        if (dx > 0)
       +                                fprintf(tfd, "\t(($1)-(%g))*%g", pt.x, xfac);
       +                        else
       +                                fprintf(tfd, "\t%g", xfac);
       +                        if (dy > 0)
       +                                fprintf(tfd, ", (($2)-(%g))*%g @\n", pt.y, yfac);
       +                        else
       +                                fprintf(tfd, ", %g @\n", yfac);
       +                        fprintf(tfd, "define x_%s @ ", p->name);
       +                        if (dx > 0)
       +                                fprintf(tfd, "\t(($1)-(%g))*%g @\n", pt.x, xfac);
       +                        else
       +                                fprintf(tfd, "\t%g @\n", xfac);
       +                        fprintf(tfd, "define y_%s @ ", p->name);
       +                        if (dy > 0)
       +                                fprintf(tfd, "\t(($1)-(%g))*%g @\n", pt.y, yfac);
       +                        else
       +                                fprintf(tfd, "\t%g @\n", yfac);
       +                }
       +        }
       +        if (codegen)
       +                frame();
       +        if (codegen && autoticks && dfp)
       +                do_autoticks(dfp);
       +
       +        if ((fd = fopen(tempfile, "r")) != NULL) {
       +                while ((c = getc(fd)) != EOF)
       +                        putc(c, tfd);
       +                fclose(fd);
       +        }
       +        tfd = NULL;
       +}
       +
       +void endstat(void)        /* clean up after each statement */
       +{
       +
       +        just = sizeop = 0;
       +        lab_up = lab_rt = 0.0;
       +        sizexpr = 0.0;
       +        nnum = 0;
       +        ntick = 0;
       +        tside = 0;
       +        tick_dir = OUT;
       +        ticklen = TICKLEN;
       +}
       +
       +void graph(char *s)        /* graph statement */
       +{
       +        char *p, *os;
       +        int c;
       +
       +        if (codegen) {
       +                fprintf(stdout, "%s: [\n", graphname);
       +                print();        /* pump out previous graph */
       +                fprintf(stdout, "\n] %s\n", graphpos);
       +                reset();
       +        }
       +        if (s) {
       +                dprintf("into graph with <%s>\n", s);
       +                opentemp();
       +                os = s;
       +                while ((c = *s) == ' ' || c == '\t')
       +                        s++;
       +                if (c == '\0')
       +                        ERROR "no name on graph statement" WARNING;
       +                if (!isupper(s[0]))
       +                        ERROR "graph name %s must be capitalized", s WARNING;
       +                for (p=graphname; (c = *s) != ' ' && c != '\t' && c != '\0'; )
       +                        *p++ = *s++;
       +                *p = '\0';
       +                strcpy(graphpos, s);
       +                dprintf("graphname = <%s>, graphpos = <%s>\n", graphname, graphpos);
       +                free(os);
       +        }
       +}
       +
       +void setup(void)                /* done at each .G1 */
       +{
       +        static int firstG1 = 0;
       +
       +        reset();
       +        opentemp();
       +        frame_ht = frame_wid = -1;        /* reset in frame() */
       +        ticklen = getvar(lookup("ticklen", 0));
       +        if (firstG1++ == 0)
       +                do_first();
       +        codegen = synerr = 0;
       +        strcpy(graphname, "Graph");
       +        strcpy(graphpos, "");
       +}
       +
       +void do_first(void)        /* done at first .G1:  definitions, etc. */
       +{
       +        extern int lib;
       +        extern char *lib_defines;
       +        static char buf[50], buf1[50];        /* static because pbstr uses them */
       +        FILE *fp;
       +        extern int getpid(void);
       +
       +        sprintf(buf, "define pid /%d/\n", getpid());
       +        pbstr(buf);        
       +        if (lib != 0) {
       +                if ((fp = fopen(unsharp(lib_defines), "r")) != NULL) {
       +                        sprintf(buf1, "copy \"%s\"\n", lib_defines);
       +                        pbstr(buf1);
       +                        fclose(fp);
       +                } else {
       +                        fprintf(stderr, "grap warning: can't open %s\n", lib_defines);
       +                }
       +        }
       +}
       +
       +void reset(void)                /* done at each "graph ..." statement */
       +{
       +        Obj *p, *np, *deflist;
       +        extern int tlist, toffside, autodir;
       +
       +        curr_coord = dflt_coord;
       +        ncoord = auto_x = 0;
       +        autoticks = LEFT|BOT;
       +        autodir = 0;
       +        tside = tlist = toffside = 0;
       +        tick_dir = OUT;
       +        margin = MARGIN;
       +        deflist = NULL;
       +        for (p = objlist; p; p = np) {
       +                np = p->next;
       +                if (p->type == DEFNAME || p->type == VARNAME) {
       +                        p->next = deflist;
       +                        deflist = p;
       +                } else {
       +                        free(p->name);
       +                        freeattr(p->attr);
       +                        free((char *) p);
       +                }
       +        }
       +        objlist = deflist;
       +}
       +
       +void opentemp(void)
       +{
       +        if (tfd != NULL)
       +                fclose(tfd);
       +        if (tfd != stdout) {
       +//                if (tfd != NULL)
       +//                        fclose(tfd);
       +                if ((tfd = fopen(tempfile, "w")) == NULL) {
       +                        fprintf(stderr, "grap: can't open %s\n", tempfile);
       +                        exit(1);
       +                }
       +          }
       +}
 (DIR) diff --git a/src/cmd/grap/ticks.c b/src/cmd/grap/ticks.c
       t@@ -0,0 +1,492 @@
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include <math.h>
       +#include "grap.h"
       +#include "y.tab.h"
       +
       +#define        MAXTICK        200
       +int        ntick        = 0;
       +double        tickval[MAXTICK];        /* tick values (one axis at a time */
       +char        *tickstr[MAXTICK];        /* and labels */
       +
       +int        tside        = 0;
       +int        tlist        = 0;                /* 1 => explicit values given */
       +int        toffside = 0;                /* no ticks on these sides */
       +int        goffside = 0;                /* no ticks on grid on these sides */
       +int        tick_dir = OUT;
       +double        ticklen        = TICKLEN;        /* default tick length */
       +int        autoticks = LEFT|BOT;
       +int        autodir = 0;                /* set LEFT, etc. if automatic ticks go in */
       +
       +void savetick(double f, char *s)        /* remember tick location and label */
       +{
       +        if (ntick >= MAXTICK)
       +                ERROR "too many ticks (%d)", MAXTICK FATAL;
       +        tickval[ntick] = f;
       +        tickstr[ntick] = s;
       +        ntick++;
       +}
       +
       +void dflt_tick(double f)
       +{
       +        if (f >= 0.0)
       +                savetick(f, tostring("%g"));
       +        else
       +                savetick(f, tostring("\\%g"));
       +}
       +
       +void tickside(int n)        /* remember which side these ticks/gridlines go on */
       +{
       +        tside |= n;
       +}
       +
       +void tickoff(int side)        /* remember explicit sides */
       +{
       +        toffside |= side;
       +}
       +
       +void gridtickoff(void)        /* turn grid ticks off on the side previously specified (ugh) */
       +{
       +        goffside = tside;
       +}
       +
       +void setlist(void)        /* remember that there was an explicit list */
       +{
       +        tlist = 1;
       +}
       +
       +void tickdir(int dir, double val, int explicit)        /* remember in/out [expr] */
       +{
       +        tick_dir = dir;
       +        if (explicit)
       +                ticklen = val;
       +}
       +
       +void ticks(void)                /* set autoticks after ticks statement */
       +{
       +        /* was there an explicit "ticks [side] off"? */
       +        if (toffside)
       +                autoticks &= ~toffside;
       +        /* was there an explicit list? (eg "ticks at ..." or "ticks from ...") */
       +        if (tlist) {
       +                if (tside & (BOT|TOP))
       +                        autoticks &= ~(BOT|TOP);
       +                if (tside & (LEFT|RIGHT))
       +                        autoticks &= ~(LEFT|RIGHT);
       +        }
       +        /* was there a side without a list? (eg "ticks left in") */
       +        if (tside && !tlist) {
       +                if (tick_dir == IN)
       +                        autodir |= tside;
       +                if (tside & (BOT|TOP))
       +                        autoticks = (autoticks & ~(BOT|TOP)) | (tside & (BOT|TOP));
       +                if (tside & (LEFT|RIGHT))
       +                        autoticks = (autoticks & ~(LEFT|RIGHT)) | (tside & (LEFT|RIGHT));
       +        }
       +        tlist = tside = toffside = goffside = 0;
       +        tick_dir = OUT;
       +}
       +
       +double modfloor(double f, double t)
       +{
       +        t = fabs(t);
       +        return floor(f/t) * t;
       +}
       +
       +double modceil(double f, double t)
       +{
       +        t = fabs(t);
       +        return ceil(f/t) * t;
       +}
       +
       +double        xtmin, xtmax;        /* range of ticks */
       +double        ytmin, ytmax;
       +double        xquant, xmult;        /* quantization & scale for auto x ticks */
       +double        yquant, ymult;
       +double        lograt = 5;
       +
       +void do_autoticks(Obj *p)        /* make set of ticks for default coord only */
       +{
       +        double x, xl, xu, q;
       +
       +        if (p == NULL)
       +                return;
       +        fprintf(tfd, "Autoticks:\t# x %g..%g, y %g..%g",
       +                p->pt.x, p->pt1.x, p->pt.y, p->pt1.y);
       +        fprintf(tfd, ";   xt %g,%g, yt %g,%g, xq,xm = %g,%g, yq,ym = %g,%g\n",
       +                xtmin, xtmax, ytmin, ytmax, xquant, xmult, yquant, ymult);
       +        if ((autoticks & (BOT|TOP)) && p->pt1.x >= p->pt.x) {        /* make x ticks */
       +                q = xquant;
       +                xl = p->pt.x;
       +                xu = p->pt1.x;
       +                if (xl >= xu)
       +                        dflt_tick(xl);
       +                else if ((p->log & XFLAG) && xu/xl >= lograt) {
       +                        for (x = q; x < xu; x *= 10) {
       +                                logtick(x, xl, xu);
       +                                if (xu/xl <= 100) {
       +                                        logtick(2*x, xl, xu);
       +                                        logtick(5*x, xl, xu);
       +                                }
       +                        }
       +                } else {
       +                        xl = modceil(xtmin - q/100, q);
       +                        xu = modfloor(xtmax + q/100, q) + q/2;
       +                        for (x = xl; x <= xu; x += q)
       +                                dflt_tick(x);
       +                }
       +                tside = autoticks & (BOT|TOP);
       +                ticklist(p, 0);
       +        }
       +        if ((autoticks & (LEFT|RIGHT)) && p->pt1.y >= p->pt.y) {        /* make y ticks */
       +                q = yquant;
       +                xl = p->pt.y;
       +                xu = p->pt1.y;
       +                if (xl >= xu)
       +                        dflt_tick(xl);
       +                else if ((p->log & YFLAG) && xu/xl >= lograt) {
       +                        for (x = q; x < xu; x *= 10) {
       +                                logtick(x, xl, xu);
       +                                if (xu/xl <= 100) {
       +                                        logtick(2*x, xl, xu);
       +                                        logtick(5*x, xl, xu);
       +                                }
       +                        }
       +                } else {
       +                        xl = modceil(ytmin - q/100, q);
       +                        xu = modfloor(ytmax + q/100, q) + q/2;
       +                        for (x = xl; x <= xu; x += q)
       +                                dflt_tick(x);
       +                }
       +                tside = autoticks & (LEFT|RIGHT);
       +                ticklist(p, 0);
       +        }
       +}
       +
       +void logtick(double v, double lb, double ub)
       +{
       +        float slop = 1.0;        /* was 1.001 */
       +
       +        if (slop * lb <= v && ub >= slop * v)
       +                dflt_tick(v);
       +}
       +
       +Obj *setauto(void)        /* compute new min,max, and quant & mult */
       +{
       +        Obj *p, *q;
       +
       +        if ((q = lookup("lograt",0)) != NULL)
       +                lograt = q->fval;
       +        for (p = objlist; p; p = p->next)
       +                if (p->type == NAME && strcmp(p->name,dflt_coord) == 0)
       +                        break;
       +        if (p) {
       +                if ((p->log & XFLAG) && p->pt1.x/p->pt.x >= lograt)
       +                        autolog(p, 'x');
       +                else
       +                        autoside(p, 'x');
       +                if ((p->log & YFLAG) && p->pt1.y/p->pt.y >= lograt)
       +                        autolog(p, 'y');
       +                else
       +                        autoside(p, 'y');
       +        }
       +        return p;
       +}
       +
       +void autoside(Obj *p, int side)
       +{
       +        double r, s, d, ub, lb;
       +
       +        if (side == 'x') {
       +                xtmin = lb = p->pt.x;
       +                xtmax = ub = p->pt1.x;
       +        } else {
       +                ytmin = lb = p->pt.y;
       +                ytmax = ub = p->pt1.y;
       +        }
       +        if (ub <= lb)
       +                return;        /* cop out on little ranges */
       +        d = ub - lb;
       +        r = s = 1;
       +        while (d * s < 10)
       +                s *= 10;
       +        d *= s;
       +        while (10 * r < d)
       +                r *= 10;
       +        if (r > d/3)
       +                r /= 2;
       +        else if (r <= d/6)
       +                r *= 2;
       +        if (side == 'x') {
       +                xquant = r / s;
       +        } else {
       +                yquant = r / s;
       +        }
       +}
       +
       +void autolog(Obj *p, int side)
       +{
       +        double r, s, t, ub, lb;
       +        int flg;
       +
       +        if (side == 'x') {
       +                xtmin = lb = p->pt.x;
       +                xtmax = ub = p->pt1.x;
       +                flg = p->coord & XFLAG;
       +        } else {
       +                ytmin = lb = p->pt.y;
       +                ytmax = ub = p->pt1.y;
       +                flg = p->coord & YFLAG;
       +        }
       +        for (s = 1; lb * s < 1; s *= 10)
       +                ;
       +        lb *= s;
       +        ub *= s;
       +        for (r = 1; 10 * r < lb; r *= 10)
       +                ;
       +        for (t = 1; t < ub; t *= 10)
       +                ;
       +        if (side == 'x')
       +                xquant = r / s;
       +        else
       +                yquant = r / s;
       +        if (flg)
       +                return;
       +        if (ub / lb < 100) {
       +                if (lb >= 5 * r)
       +                        r *= 5;
       +                else if (lb >= 2 * r)
       +                        r *= 2;
       +                if (ub * 5 <= t)
       +                        t /= 5;
       +                else if (ub * 2 <= t)
       +                        t /= 2;
       +                if (side == 'x') {
       +                        xtmin = r / s;
       +                        xtmax = t / s;
       +                } else {
       +                        ytmin = r / s;
       +                        ytmax = t / s;
       +                }
       +        }
       +}
       +
       +void iterator(double from, double to, int op, double by, char *fmt)        /* create an iterator */
       +{
       +        double x;
       +
       +        /* should validate limits, etc. */
       +        /* punt for now */
       +
       +        dprintf("iterate from %g to %g by %g, op = %c, fmt=%s\n",
       +                from, to, by, op, fmt ? fmt : "");
       +        switch (op) {
       +        case '+':
       +        case ' ':
       +                for (x = from; x <= to + (SLOP-1) * by; x += by)
       +                        if (fmt)
       +                                savetick(x, tostring(fmt));
       +                        else
       +                                dflt_tick(x);
       +                break;
       +        case '-':
       +                for (x = from; x >= to; x -= by)
       +                        if (fmt)
       +                                savetick(x, tostring(fmt));
       +                        else
       +                                dflt_tick(x);
       +                break;
       +        case '*':
       +                for (x = from; x <= SLOP * to; x *= by)
       +                        if (fmt)
       +                                savetick(x, tostring(fmt));
       +                        else
       +                                dflt_tick(x);
       +                break;
       +        case '/':
       +                for (x = from; x >= to; x /= by)
       +                        if (fmt)
       +                                savetick(x, tostring(fmt));
       +                        else
       +                                dflt_tick(x);
       +                break;
       +        }
       +        if (fmt)
       +                free(fmt);
       +}
       +
       +void ticklist(Obj *p, int explicit)        /* fire out the accumulated ticks */
       +                                        /* 1 => list, 0 => auto */
       +{
       +        if (p == NULL)
       +                return;
       +        fprintf(tfd, "Ticks_%s:\n\tticklen = %g\n", p->name, ticklen);
       +        print_ticks(TICKS, explicit, p, "ticklen", "");
       +}
       +
       +void print_ticks(int type, int explicit, Obj *p, char *lenstr, char *descstr)
       +{
       +        int i, logflag, inside;
       +        char buf[100];
       +        double tv;
       +
       +        for (i = 0; i < ntick; i++)        /* any ticks given explicitly? */
       +                if (tickstr[i] != NULL)
       +                        break;
       +        if (i >= ntick && type == TICKS)        /* no, so use values */
       +                for (i = 0; i < ntick; i++) {
       +                        if (tickval[i] >= 0.0)
       +                                sprintf(buf, "%g", tickval[i]);
       +                        else
       +                                sprintf(buf, "\\-%g", -tickval[i]);
       +                        tickstr[i] = tostring(buf);
       +                }
       +        else
       +                for (i = 0; i < ntick; i++) {
       +                        if (tickstr[i] != NULL) {
       +                                sprintf(buf, tickstr[i], tickval[i]);
       +                                free(tickstr[i]);
       +                                tickstr[i] = tostring(buf);
       +                        }
       +                }
       +        logflag = sidelog(p->log, tside);
       +        for (i = 0; i < ntick; i++) {
       +                tv = tickval[i];
       +                halfrange(p, tside, tv);
       +                if (logflag) {
       +                        if (tv <= 0.0)
       +                                ERROR "can't take log of tick value %g", tv FATAL;
       +                        logit(tv);
       +                }
       +                if (type == GRID)
       +                        inside = LEFT|RIGHT|TOP|BOT;
       +                else if (explicit)
       +                        inside = (tick_dir == IN) ? tside : 0;
       +                else
       +                        inside = autodir;
       +                if (tside & BOT)
       +                        maketick(type, p->name, BOT, inside, tv, tickstr[i], lenstr, descstr);
       +                if (tside & TOP)
       +                        maketick(type, p->name, TOP, inside, tv, tickstr[i], lenstr, descstr);
       +                if (tside & LEFT)
       +                        maketick(type, p->name, LEFT, inside, tv, tickstr[i], lenstr, descstr);
       +                if (tside & RIGHT)
       +                        maketick(type, p->name, RIGHT, inside, tv, tickstr[i], lenstr, descstr);
       +                if (tickstr[i]) {
       +                        free(tickstr[i]);
       +                        tickstr[i] = NULL;
       +                }
       +        }
       +        ntick = 0;
       +}
       +
       +void maketick(int type, char *name, int side, int inflag, double val, char *lab, char *lenstr, char *descstr)
       +{
       +        char *sidestr, *td;
       +
       +        fprintf(tfd, "\tline %s ", descstr);
       +        inflag &= side;
       +        switch (side) {
       +        case BOT:
       +        case 0:
       +                td = inflag ? "up" : "down";
       +                fprintf(tfd, "%s %s from (x_%s(%g),0)", td, lenstr, name, val);
       +                break;
       +        case TOP:
       +                td = inflag ? "down" : "up";
       +                fprintf(tfd, "%s %s from (x_%s(%g),frameht)", td, lenstr, name, val);
       +                break;
       +        case LEFT:
       +                td = inflag ? "right" : "left";
       +                fprintf(tfd, "%s %s from (0,y_%s(%g))", td, lenstr, name, val);
       +                break;
       +        case RIGHT:
       +                td = inflag ? "left" : "right";
       +                fprintf(tfd, "%s %s from (framewid,y_%s(%g))", td, lenstr, name, val);
       +                break;
       +        }
       +        fprintf(tfd, "\n");
       +        if (type == GRID && (side & goffside))        /* wanted no ticks on grid */
       +                return;
       +        sidestr = tick_dir == IN ? "start" : "end";
       +        if (lab != NULL) {
       +                /* BUG: should fix size of lab here */
       +                double wid = strlen(lab)/7.5 + (tick_dir == IN ? 0 : 0.1);        /* estimate width at 15 chars/inch */
       +                switch (side) {
       +                case BOT: case 0:
       +                        /* can drop "box invis" with new pic */
       +                        fprintf(tfd, "\tbox invis \"%s\" ht .25 wid 0 with .n at last line.%s",
       +                                lab, sidestr);
       +                        break;
       +                case TOP:
       +                        fprintf(tfd, "\tbox invis \"%s\" ht .2 wid 0 with .s at last line.%s",
       +                                lab, sidestr);
       +                        break;
       +                case LEFT:
       +                        fprintf(tfd, "\t\"%s \" wid %.2f rjust at last line.%s",
       +                                lab, wid, sidestr);
       +                        break;
       +                case RIGHT:
       +                        fprintf(tfd, "\t\" %s\" wid %.2f ljust at last line.%s",
       +                                lab, wid, sidestr);
       +                        break;
       +                }
       +                /* BUG: works only if "down x" comes before "at wherever" */
       +                lab_adjust();
       +                fprintf(tfd, "\n");
       +        }
       +}
       +
       +Attr        *grid_desc        = 0;
       +
       +void griddesc(Attr *a)
       +{
       +        grid_desc = a;
       +}
       +
       +void gridlist(Obj *p)
       +{
       +        char *framestr;
       +
       +        if ((tside & (BOT|TOP)) || tside == 0)
       +                framestr = "frameht";
       +        else
       +                framestr = "framewid";
       +        fprintf(tfd, "Grid_%s:\n", p->name);
       +        tick_dir = IN;
       +        print_ticks(GRID, 0, p, framestr, desc_str(grid_desc));
       +        if (grid_desc) {
       +                freeattr(grid_desc);
       +                grid_desc = 0;
       +        }
       +}
       +
       +char *desc_str(Attr *a)        /* convert DOT to "dotted", etc. */
       +{
       +        static char buf[50], *p;
       +
       +        if (a == NULL)
       +                return p = "";
       +        switch (a->type) {
       +        case DOT:        p = "dotted"; break;
       +        case DASH:        p = "dashed"; break;
       +        case INVIS:        p = "invis"; break;
       +        default:        p = "";
       +        }
       +        if (a->fval != 0.0) {
       +                sprintf(buf, "%s %g", p, a->fval);
       +                return buf;
       +        } else
       +                return p;
       +}
       +
       +sidelog(int logflag, int side)        /* figure out whether to scale a side */
       +{
       +        if ((logflag & XFLAG) && ((side & (BOT|TOP)) || side == 0))
       +                return 1;
       +        else if ((logflag & YFLAG) && (side & (LEFT|RIGHT)))
       +                return 1;
       +        else
       +                return 0;
       +}
 (DIR) diff --git a/src/cmd/mkfile b/src/cmd/mkfile
       t@@ -5,7 +5,7 @@ SHORTLIB=sec fs mux regexp9 thread bio 9
        
        <$PLAN9/src/mkmany
        
       -BUGGERED='CVS|faces|factotum|mailfs|scat|upas|vac|venti|lex|vncv'
       +BUGGERED='CVS|faces|factotum|mailfs|scat|upas|vac|venti|lex|vncv|grap|eqn|troff|pic|tbl'
        DIRS=`ls -l |sed -n 's/^d.* //p' |egrep -v "^($BUGGERED)$"`
        
        <$PLAN9/src/mkdirs
 (DIR) diff --git a/src/cmd/pic/arcgen.c b/src/cmd/pic/arcgen.c
       t@@ -0,0 +1,221 @@
       +#include        <stdio.h>
       +#include        <math.h>
       +#include        "pic.h"
       +#include        "y.tab.h"
       +
       +void arc_extreme(double, double, double, double, double, double);
       +int quadrant(double x, double y);
       +
       +obj *arcgen(int type)        /* handles circular and (eventually) elliptical arcs */
       +{
       +        static double prevw = HT10;
       +        static double prevh = HT5;
       +        static double prevrad = HT2;
       +        static int dtox[2][4] ={ 1, -1, -1, 1, 1, 1, -1, -1 };
       +        static int dtoy[2][4] ={ 1, 1, -1, -1, -1, 1, 1, -1 };
       +        static int dctrx[2][4] ={ 0, -1, 0, 1, 0, 1, 0, -1 };
       +        static int dctry[2][4] ={ 1, 0, -1, 0, -1, 0, 1, 0 };
       +        static int nexthv[2][4] ={ U_DIR, L_DIR, D_DIR, R_DIR, D_DIR, R_DIR, U_DIR, L_DIR };
       +        double dx2, dy2, ht, phi, r, d;
       +        int i, head, to, at, cw, invis, ddtype, battr;
       +        obj *p, *ppos;
       +        double fromx, fromy, tox, toy, fillval = 0;
       +        Attr *ap;
       +
       +        prevrad = getfval("arcrad");
       +        prevh = getfval("arrowht");
       +        prevw = getfval("arrowwid");
       +        fromx = curx;
       +        fromy = cury;
       +        head = to = at = cw = invis = ddtype = battr = 0;
       +        for (i = 0; i < nattr; i++) {
       +                ap = &attr[i];
       +                switch (ap->a_type) {
       +                case TEXTATTR:
       +                        savetext(ap->a_sub, ap->a_val.p);
       +                        break;
       +                case HEAD:
       +                        head += ap->a_val.i;
       +                        break;
       +                case INVIS:
       +                        invis = INVIS;
       +                        break;
       +                case HEIGHT:        /* length of arrowhead */
       +                        prevh = ap->a_val.f;
       +                        break;
       +                case WIDTH:        /* width of arrowhead */
       +                        prevw = ap->a_val.f;
       +                        break;
       +                case RADIUS:
       +                        prevrad = ap->a_val.f;
       +                        break;
       +                case DIAMETER:
       +                        prevrad = ap->a_val.f / 2;
       +                        break;
       +                case CW:
       +                        cw = 1;
       +                        break;
       +                case FROM:        /* start point of arc */
       +                        ppos = ap->a_val.o;
       +                        fromx = ppos->o_x;
       +                        fromy = ppos->o_y;
       +                        break;
       +                case TO:        /* end point of arc */
       +                        ppos = ap->a_val.o;
       +                        tox = ppos->o_x;
       +                        toy = ppos->o_y;
       +                        to++;
       +                        break;
       +                case AT:        /* center of arc */
       +                        ppos = ap->a_val.o;
       +                        curx = ppos->o_x;
       +                        cury = ppos->o_y;
       +                        at = 1;
       +                        break;
       +                case UP:
       +                        hvmode = U_DIR;
       +                        break;
       +                case DOWN:
       +                        hvmode = D_DIR;
       +                        break;
       +                case RIGHT:
       +                        hvmode = R_DIR;
       +                        break;
       +                case LEFT:
       +                        hvmode = L_DIR;
       +                        break;
       +                case FILL:
       +                        battr |= FILLBIT;
       +                        if (ap->a_sub == DEFAULT)
       +                                fillval = getfval("fillval");
       +                        else
       +                                fillval = ap->a_val.f;
       +                        break;
       +                }
       +        }
       +        if (!at && !to) {        /* the defaults are mostly OK */
       +                curx = fromx + prevrad * dctrx[cw][hvmode];
       +                cury = fromy + prevrad * dctry[cw][hvmode];
       +                tox = fromx + prevrad * dtox[cw][hvmode];
       +                toy = fromy + prevrad * dtoy[cw][hvmode];
       +                hvmode = nexthv[cw][hvmode];
       +        }
       +        else if (!at) {
       +                dx2 = (tox - fromx) / 2;
       +                dy2 = (toy - fromy) / 2;
       +                phi = atan2(dy2, dx2) + (cw ? -PI/2 : PI/2);
       +                if (prevrad <= 0.0)
       +                        prevrad = dx2*dx2+dy2*dy2;
       +                for (r=prevrad; (d = r*r - (dx2*dx2+dy2*dy2)) <= 0.0; r *= 2)
       +                        ;        /* this kludge gets around too-small radii */
       +                prevrad = r;
       +                ht = sqrt(d);
       +                curx = fromx + dx2 + ht * cos(phi);
       +                cury = fromy + dy2 + ht * sin(phi);
       +                dprintf("dx2,dy2=%g,%g, phi=%g, r,ht=%g,%g\n",
       +                        dx2, dy2, phi, r, ht);
       +        }
       +        else if (at && !to) {        /* do we have all the cases??? */
       +                tox = fromx + prevrad * dtox[cw][hvmode];
       +                toy = fromy + prevrad * dtoy[cw][hvmode];
       +                hvmode = nexthv[cw][hvmode];
       +        }
       +        if (cw) {        /* interchange roles of from-to and heads */
       +                double temp;
       +                temp = fromx; fromx = tox; tox = temp;
       +                temp = fromy; fromy = toy; toy = temp;
       +                if (head == HEAD1)
       +                        head = HEAD2;
       +                else if (head == HEAD2)
       +                        head = HEAD1;
       +        }
       +        p = makenode(type, 7);
       +        arc_extreme(fromx, fromy, tox, toy, curx, cury);
       +        p->o_val[0] = fromx;
       +        p->o_val[1] = fromy;
       +        p->o_val[2] = tox;
       +        p->o_val[3] = toy;
       +        if (cw) {
       +                curx = fromx;
       +                cury = fromy;
       +        } else {
       +                curx = tox;
       +                cury = toy;
       +        }
       +        p->o_val[4] = prevw;
       +        p->o_val[5] = prevh;
       +        p->o_val[6] = prevrad;
       +        p->o_attr = head | (cw ? CW_ARC : 0) | invis | ddtype | battr;
       +        p->o_fillval = fillval;
       +        if (head)
       +                p->o_nhead = getfval("arrowhead");
       +        dprintf("arc rad %g at %g %g from %g %g to %g %g head %g %g\n",
       +                prevrad, p->o_x, p->o_y,
       +                p->o_val[0], p->o_val[1], p->o_val[2], p->o_val[3], p->o_val[4], p->o_val[5]);
       +        return(p);
       +}
       +
       +/***************************************************************************
       +   bounding box of a circular arc             Eric Grosse  24 May 84
       +
       +Conceptually, this routine generates a list consisting of the start,
       +end, and whichever north, east, south, and west points lie on the arc.
       +The bounding box is then the range of this list.
       +    list = {start,end}
       +    j = quadrant(start)
       +    k = quadrant(end)
       +    if( j==k && long way 'round )  append north,west,south,east
       +    else
       +      while( j != k )
       +         append center+radius*[j-th of north,west,south,east unit vectors]
       +         j += 1  (mod 4)
       +    return( bounding box of list )
       +The following code implements this, with simple optimizations.
       +***********************************************************************/
       +
       +
       +void arc_extreme(double x0, double y0, double x1, double y1, double xc, double yc)
       +                          /* start, end, center */
       +{
       +        /* assumes center isn't too far out */
       +        double r, xmin, ymin, xmax, ymax;
       +        int j, k;
       +        x0 -= xc; y0 -= yc;        /* move to center */
       +        x1 -= xc; y1 -= yc;
       +        xmin = (x0<x1)?x0:x1; ymin = (y0<y1)?y0:y1;
       +        xmax = (x0>x1)?x0:x1; ymax = (y0>y1)?y0:y1;
       +        r = sqrt(x0*x0 + y0*y0);
       +        if (r > 0.0) {
       +                j = quadrant(x0,y0);
       +                k = quadrant(x1,y1);
       +                if (j == k && y1*x0 < x1*y0) {
       +                        /* viewed as complex numbers, if Im(z1/z0)<0, arc is big */
       +                        if( xmin > -r) xmin = -r; if( ymin > -r) ymin = -r;
       +                        if( xmax <  r) xmax =  r; if( ymax <  r) ymax =  r;
       +                } else {
       +                        while (j != k) {
       +                                switch (j) {
       +                                        case 1: if( ymax <  r) ymax =  r; break; /* north */
       +                                        case 2: if( xmin > -r) xmin = -r; break; /* west */
       +                                        case 3: if( ymin > -r) ymin = -r; break; /* south */
       +                                        case 4: if( xmax <  r) xmax =  r; break; /* east */
       +                                }
       +                                j = j%4 + 1;
       +                        }
       +                }
       +        }
       +        xmin += xc; ymin += yc;
       +        xmax += xc; ymax += yc;
       +        extreme(xmin, ymin);
       +        extreme(xmax, ymax);
       +}
       +
       +quadrant(double x, double y)
       +{
       +        if (     x>=0.0 && y> 0.0) return(1);
       +        else if( x< 0.0 && y>=0.0) return(2);
       +        else if( x<=0.0 && y< 0.0) return(3);
       +        else if( x> 0.0 && y<=0.0) return(4);
       +        else                           return 0;        /* shut up lint */
       +}
       +
 (DIR) diff --git a/src/cmd/pic/blockgen.c b/src/cmd/pic/blockgen.c
       t@@ -0,0 +1,226 @@
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include "pic.h"
       +#include "y.tab.h"
       +
       +#define        NBRACK        20        /* depth of [...] */
       +#define        NBRACE        20        /* depth of {...} */
       +
       +struct pushstack stack[NBRACK];
       +int        nstack        = 0;
       +struct pushstack bracestack[NBRACE];
       +int        nbstack        = 0;
       +
       +void blockadj(obj *);
       +
       +obj *leftthing(int c)        /* called for {... or [... */
       +                        /* really ought to be separate functions */
       +{
       +        obj *p;
       +
       +        if (c == '[') {
       +                if (nstack >= NBRACK)
       +                        ERROR "[...] nested too deep" FATAL;
       +                stack[nstack].p_x = curx;
       +                stack[nstack].p_y = cury;
       +                stack[nstack].p_hvmode = hvmode;
       +                curx = cury = 0;
       +                stack[nstack].p_xmin = xmin;
       +                stack[nstack].p_xmax = xmax;
       +                stack[nstack].p_ymin = ymin;
       +                stack[nstack].p_ymax = ymax;
       +                nstack++;
       +                xmin = ymin = 30000;
       +                xmax = ymax = -30000;
       +                p = makenode(BLOCK, 7);
       +                p->o_val[4] = nobj;        /* 1st item within [...] */
       +                if (p->o_nobj != nobj-1)
       +                        fprintf(stderr, "nobjs wrong%d %d\n", p->o_nobj, nobj);
       +        } else {
       +                if (nbstack >= NBRACK)
       +                        ERROR "{...} nested too deep" FATAL;
       +                bracestack[nbstack].p_x = curx;
       +                bracestack[nbstack].p_y = cury;
       +                bracestack[nbstack].p_hvmode = hvmode;
       +                nbstack++;
       +                p = NULL;
       +        }
       +        return(p);
       +}
       +
       +obj *rightthing(obj *p, int c)        /* called for ... ] or ... } */
       +{
       +        obj *q;
       +
       +        if (c == '}') {
       +                nbstack--;
       +                curx = bracestack[nbstack].p_x;
       +                cury = bracestack[nbstack].p_y;
       +                hvmode = bracestack[nbstack].p_hvmode;
       +                q = makenode(MOVE, 0);
       +                dprintf("M %g %g\n", curx, cury);
       +        } else {
       +                nstack--;
       +                curx = stack[nstack].p_x;
       +                cury = stack[nstack].p_y;
       +                hvmode = stack[nstack].p_hvmode;
       +                q = makenode(BLOCKEND, 7);
       +                q->o_val[4] = p->o_nobj + 1;        /* back pointer */
       +                p->o_val[5] = q->o_nobj - 1;        /* forward pointer */
       +                if (xmin > xmax)        /* nothing happened */
       +                        xmin = xmax;
       +                if (ymin > ymax)
       +                        ymin = ymax;
       +                p->o_val[0] = xmin; p->o_val[1] = ymin;
       +                p->o_val[2] = xmax; p->o_val[3] = ymax;
       +                p->o_symtab = q->o_symtab = stack[nstack+1].p_symtab;
       +                xmin = stack[nstack].p_xmin;
       +                ymin = stack[nstack].p_ymin;
       +                xmax = stack[nstack].p_xmax;
       +                ymax = stack[nstack].p_ymax;
       +        }
       +        return(q);
       +}
       +
       +obj *blockgen(obj *p, obj *q)        /* handles [...] */
       +{
       +        int i, invis, at, with;
       +        double ddval, h, w, xwith, ywith;
       +        double x0, y0, x1, y1, cx, cy;
       +        obj *ppos;
       +        Attr *ap;
       +
       +        invis = at = 0;
       +        with = xwith = ywith = 0;
       +        ddval = 0;
       +        w = p->o_val[2] - p->o_val[0];
       +        h = p->o_val[3] - p->o_val[1];
       +        cx = (p->o_val[2] + p->o_val[0]) / 2;        /* geom ctr of [] wrt local orogin */
       +        cy = (p->o_val[3] + p->o_val[1]) / 2;
       +        dprintf("cx,cy=%g,%g\n", cx, cy);
       +        for (i = 0; i < nattr; i++) {
       +                ap = &attr[i];
       +                switch (ap->a_type) {
       +                case HEIGHT:
       +                        h = ap->a_val.f;
       +                        break;
       +                case WIDTH:
       +                        w = ap->a_val.f;
       +                        break;
       +                case WITH:
       +                        with = ap->a_val.i;        /* corner */
       +                        break;
       +                case PLACE:        /* actually with position ... */
       +                        ppos = ap->a_val.o;
       +                        xwith = cx - ppos->o_x;
       +                        ywith = cy - ppos->o_y;
       +                        with = PLACE;
       +                        break;
       +                case AT:
       +                case FROM:
       +                        ppos = ap->a_val.o;
       +                        curx = ppos->o_x;
       +                        cury = ppos->o_y;
       +                        at++;
       +                        break;
       +                case INVIS:
       +                        invis = INVIS;
       +                        break;
       +                case TEXTATTR:
       +                        savetext(ap->a_sub, ap->a_val.p);
       +                        break;
       +                }
       +        }
       +        if (with) {
       +                switch (with) {
       +                case NORTH:        ywith = -h / 2; break;
       +                case SOUTH:        ywith = h / 2; break;
       +                case EAST:        xwith = -w / 2; break;
       +                case WEST:        xwith = w / 2; break;
       +                case NE:        xwith = -w / 2; ywith = -h / 2; break;
       +                case SE:        xwith = -w / 2; ywith = h / 2; break;
       +                case NW:        xwith = w / 2; ywith = -h / 2; break;
       +                case SW:        xwith = w / 2; ywith = h / 2; break;
       +                }
       +                curx += xwith;
       +                cury += ywith;
       +        }
       +        if (!at) {
       +                if (isright(hvmode))
       +                        curx += w / 2;
       +                else if (isleft(hvmode))
       +                        curx -= w / 2;
       +                else if (isup(hvmode))
       +                        cury += h / 2;
       +                else
       +                        cury -= h / 2;
       +        }
       +        x0 = curx - w / 2;
       +        y0 = cury - h / 2;
       +        x1 = curx + w / 2;
       +        y1 = cury + h / 2;
       +        extreme(x0, y0);
       +        extreme(x1, y1);
       +        p->o_x = curx;
       +        p->o_y = cury;
       +        p->o_nt1 = ntext1;
       +        p->o_nt2 = ntext;
       +        ntext1 = ntext;
       +        p->o_val[0] = w;
       +        p->o_val[1] = h;
       +        p->o_val[2] = cx;
       +        p->o_val[3] = cy;
       +        p->o_val[5] = q->o_nobj - 1;                /* last item in [...] */
       +        p->o_ddval = ddval;
       +        p->o_attr = invis;
       +        dprintf("[] %g %g %g %g at %g %g, h=%g, w=%g\n", x0, y0, x1, y1, curx, cury, h, w);
       +        if (isright(hvmode))
       +                curx = x1;
       +        else if (isleft(hvmode))
       +                curx = x0;
       +        else if (isup(hvmode))
       +                cury = y1;
       +        else
       +                cury = y0;
       +        for (i = 0; i <= 5; i++)
       +                q->o_val[i] = p->o_val[i];
       +        stack[nstack+1].p_symtab = NULL;        /* so won't be found again */
       +        blockadj(p);        /* fix up coords for enclosed blocks */
       +        return(p);
       +}
       +
       +void blockadj(obj *p)        /* adjust coords in block starting at p */
       +{
       +        double dx, dy;
       +        int n, lev;
       +
       +        dx = p->o_x - p->o_val[2];
       +        dy = p->o_y - p->o_val[3];
       +        n = p->o_nobj + 1;
       +        dprintf("into blockadj: dx,dy=%g,%g\n", dx, dy);
       +        for (lev = 1; lev > 0; n++) {
       +                p = objlist[n];
       +                if (p->o_type == BLOCK)
       +                        lev++;
       +                else if (p->o_type == BLOCKEND)
       +                        lev--;
       +                dprintf("blockadj: type=%d o_x,y=%g,%g;", p->o_type, p->o_x, p->o_y);
       +                p->o_x += dx;
       +                p->o_y += dy;
       +                dprintf(" becomes %g,%g\n", p->o_x, p->o_y);
       +                switch (p->o_type) {        /* other absolute coords */
       +                case LINE:
       +                case ARROW:
       +                case SPLINE:
       +                        p->o_val[0] += dx;
       +                        p->o_val[1] += dy;
       +                        break;
       +                case ARC:
       +                        p->o_val[0] += dx;
       +                        p->o_val[1] += dy;
       +                        p->o_val[2] += dx;
       +                        p->o_val[3] += dy;
       +                        break;
       +                }
       +        }
       +}
 (DIR) diff --git a/src/cmd/pic/boxgen.c b/src/cmd/pic/boxgen.c
       t@@ -0,0 +1,115 @@
       +#include        <stdio.h>
       +#include        "pic.h"
       +#include        "y.tab.h"
       +
       +obj *boxgen(void)
       +{
       +        static double prevh = HT;
       +        static double prevw = WID;        /* golden mean, sort of */
       +        int i, at, battr, with;
       +        double ddval, fillval, xwith, ywith;
       +        double h, w, x0, y0, x1, y1;
       +        obj *p, *ppos;
       +        Attr *ap;
       +
       +        h = getfval("boxht");
       +        w = getfval("boxwid");
       +        at = battr = with = 0;
       +        ddval = fillval = xwith = ywith = 0;
       +        for (i = 0; i < nattr; i++) {
       +                ap = &attr[i];
       +                switch (ap->a_type) {
       +                case HEIGHT:
       +                        h = ap->a_val.f;
       +                        break;
       +                case WIDTH:
       +                        w = ap->a_val.f;
       +                        break;
       +                case SAME:
       +                        h = prevh;
       +                        w = prevw;
       +                        break;
       +                case WITH:
       +                        with = ap->a_val.i;        /* corner */
       +                        break;
       +                case AT:
       +                        ppos = ap->a_val.o;
       +                        curx = ppos->o_x;
       +                        cury = ppos->o_y;
       +                        at++;
       +                        break;
       +                case INVIS:
       +                        battr |= INVIS;
       +                        break;
       +                case NOEDGE:
       +                        battr |= NOEDGEBIT;
       +                        break;
       +                case DOT:
       +                case DASH:
       +                        battr |= ap->a_type==DOT ? DOTBIT : DASHBIT;
       +                        if (ap->a_sub == DEFAULT)
       +                                ddval = getfval("dashwid");
       +                        else
       +                                ddval = ap->a_val.f;
       +                        break;
       +                case FILL:
       +                        battr |= FILLBIT;
       +                        if (ap->a_sub == DEFAULT)
       +                                fillval = getfval("fillval");
       +                        else
       +                                fillval = ap->a_val.f;
       +                        break;
       +                case TEXTATTR:
       +                        savetext(ap->a_sub, ap->a_val.p);
       +                        break;
       +                }
       +        }
       +        if (with) {
       +                switch (with) {
       +                case NORTH:        ywith = -h / 2; break;
       +                case SOUTH:        ywith = h / 2; break;
       +                case EAST:        xwith = -w / 2; break;
       +                case WEST:        xwith = w / 2; break;
       +                case NE:        xwith = -w / 2; ywith = -h / 2; break;
       +                case SE:        xwith = -w / 2; ywith = h / 2; break;
       +                case NW:        xwith = w / 2; ywith = -h / 2; break;
       +                case SW:        xwith = w / 2; ywith = h / 2; break;
       +                }
       +                curx += xwith;
       +                cury += ywith;
       +        }
       +        if (!at) {
       +                if (isright(hvmode))
       +                        curx += w / 2;
       +                else if (isleft(hvmode))
       +                        curx -= w / 2;
       +                else if (isup(hvmode))
       +                        cury += h / 2;
       +                else
       +                        cury -= h / 2;
       +        }
       +        x0 = curx - w / 2;
       +        y0 = cury - h / 2;
       +        x1 = curx + w / 2;
       +        y1 = cury + h / 2;
       +        extreme(x0, y0);
       +        extreme(x1, y1);
       +        p = makenode(BOX, 2);
       +        p->o_val[0] = w;
       +        p->o_val[1] = h;
       +        p->o_attr = battr;
       +        p->o_ddval = ddval;
       +        p->o_fillval = fillval;
       +        dprintf("B %g %g %g %g at %g %g, h=%g, w=%g\n", x0, y0, x1, y1, curx, cury, h, w);
       +        if (isright(hvmode))
       +                curx = x1;
       +        else if (isleft(hvmode))
       +                curx = x0;
       +        else if (isup(hvmode))
       +                cury = y1;
       +        else
       +                cury = y0;
       +        prevh = h;
       +        prevw = w;
       +        return(p);
       +}
 (DIR) diff --git a/src/cmd/pic/circgen.c b/src/cmd/pic/circgen.c
       t@@ -0,0 +1,126 @@
       +#include        <stdio.h>
       +#include        "pic.h"
       +#include        "y.tab.h"
       +
       +obj *circgen(int type)
       +{
       +        static double rad[2] = { HT2, WID2 };
       +        static double rad2[2] = { HT2, HT2 };
       +        int i, at, t, with, battr;
       +        double xwith, ywith;
       +        double r, r2, ddval, fillval;
       +        obj *p, *ppos;
       +        Attr *ap;
       +
       +        battr = at = 0;
       +        with = xwith = ywith = fillval = ddval = 0;
       +        t = (type == CIRCLE) ? 0 : 1;
       +        if (type == CIRCLE)
       +                r = r2 = getfval("circlerad");
       +        else if (type == ELLIPSE) {
       +                r = getfval("ellipsewid") / 2;
       +                r2 = getfval("ellipseht") / 2;
       +        }
       +        for (i = 0; i < nattr; i++) {
       +                ap = &attr[i];
       +                switch (ap->a_type) {
       +                case TEXTATTR:
       +                        savetext(ap->a_sub, ap->a_val.p);
       +                        break;
       +                case RADIUS:
       +                        r = ap->a_val.f;
       +                        break;
       +                case DIAMETER:
       +                case WIDTH:
       +                        r = ap->a_val.f / 2;
       +                        break;
       +                case HEIGHT:
       +                        r2 = ap->a_val.f / 2;
       +                        break;
       +                case SAME:
       +                        r = rad[t];
       +                        r2 = rad2[t];
       +                        break;
       +                case WITH:
       +                        with = ap->a_val.i;
       +                        break;
       +                case AT:
       +                        ppos = ap->a_val.o;
       +                        curx = ppos->o_x;
       +                        cury = ppos->o_y;
       +                        at++;
       +                        break;
       +                case INVIS:
       +                        battr |= INVIS;
       +                        break;
       +                case NOEDGE:
       +                        battr |= NOEDGEBIT;
       +                        break;
       +                case DOT:
       +                case DASH:
       +                        battr |= ap->a_type==DOT ? DOTBIT : DASHBIT;
       +                        if (ap->a_sub == DEFAULT)
       +                                ddval = getfval("dashwid");
       +                        else
       +                                ddval = ap->a_val.f;
       +                        break;
       +                case FILL:
       +                        battr |= FILLBIT;
       +                        if (ap->a_sub == DEFAULT)
       +                                fillval = getfval("fillval");
       +                        else
       +                                fillval = ap->a_val.f;
       +                        break;
       +                }
       +        }
       +        if (type == CIRCLE)
       +                r2 = r;        /* probably superfluous */
       +        if (with) {
       +                switch (with) {
       +                case NORTH:        ywith = -r2; break;
       +                case SOUTH:        ywith = r2; break;
       +                case EAST:        xwith = -r; break;
       +                case WEST:        xwith = r; break;
       +                case NE:        xwith = -r * 0.707; ywith = -r2 * 0.707; break;
       +                case SE:        xwith = -r * 0.707; ywith = r2 * 0.707; break;
       +                case NW:        xwith = r * 0.707; ywith = -r2 * 0.707; break;
       +                case SW:        xwith = r * 0.707; ywith = r2 * 0.707; break;
       +                }
       +                curx += xwith;
       +                cury += ywith;
       +        }
       +        if (!at) {
       +                if (isright(hvmode))
       +                        curx += r;
       +                else if (isleft(hvmode))
       +                        curx -= r;
       +                else if (isup(hvmode))
       +                        cury += r2;
       +                else
       +                        cury -= r2;
       +        }
       +        p = makenode(type, 2);
       +        p->o_val[0] = rad[t] = r;
       +        p->o_val[1] = rad2[t] = r2;
       +        if (r <= 0 || r2 <= 0) {
       +                ERROR "%s has invalid radius %g\n", (type==CIRCLE) ? "circle" : "ellipse", r<r2 ? r : r2 WARNING;
       +        }
       +        p->o_attr = battr;
       +        p->o_ddval = ddval;
       +        p->o_fillval = fillval;
       +        extreme(curx+r, cury+r2);
       +        extreme(curx-r, cury-r2);
       +        if (type == CIRCLE)
       +                dprintf("C %g %g %g\n", curx, cury, r);
       +        if (type == ELLIPSE)
       +                dprintf("E %g %g %g %g\n", curx, cury, r, r2);
       +        if (isright(hvmode))
       +                curx += r;
       +        else if (isleft(hvmode))
       +                curx -= r;
       +        else if (isup(hvmode))
       +                cury += r2;
       +        else
       +                cury -= r2;
       +        return(p);
       +}
 (DIR) diff --git a/src/cmd/pic/for.c b/src/cmd/pic/for.c
       t@@ -0,0 +1,95 @@
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include "pic.h"
       +#include "y.tab.h"
       +
       +#define        SLOP        1.001
       +
       +typedef struct {
       +        char        *var;        /* index variable */
       +        double        to;        /* limit */
       +        double        by;
       +        int        op;        /* operator */
       +        char        *str;        /* string to push back */
       +} For;
       +
       +For        forstk[10];        /* stack of for loops */
       +For        *forp = forstk;        /* pointer to current top */
       +
       +void        setfval(char *, double);
       +void        nextfor(void);
       +
       +void forloop(char *var, double from, double to, int op,
       +        double by, char *str)        /* set up a for loop */
       +{
       +        dprintf("# for %s from %g to %g by %c %g \n",
       +                var, from, to, op, by);
       +        if (++forp >= forstk+10)
       +                ERROR "for loop nested too deep" FATAL;
       +        forp->var = var;
       +        forp->to = to;
       +        forp->op = op;
       +        forp->by = by;
       +        forp->str = str;
       +        setfval(var, from);
       +        nextfor();
       +        unput('\n');
       +}
       +
       +void nextfor(void)        /* do one iteration of a for loop */
       +{
       +        /* BUG:  this should depend on op and direction */
       +        if (getfval(forp->var) > SLOP * forp->to) {        /* loop is done */
       +                free(forp->str);
       +                if (--forp < forstk)
       +                        ERROR "forstk popped too far" FATAL;
       +        } else {                /* another iteration */
       +                pushsrc(String, "\nEndfor\n");
       +                pushsrc(String, forp->str);
       +        }
       +}
       +
       +void endfor(void)        /* end one iteration of for loop */
       +{
       +        struct symtab *p = lookup(forp->var);
       +
       +        switch (forp->op) {
       +        case '+':
       +        case ' ':
       +                p->s_val.f += forp->by;
       +                break;
       +        case '-':
       +                p->s_val.f -= forp->by;
       +                break;
       +        case '*':
       +                p->s_val.f *= forp->by;
       +                break;
       +        case '/':
       +                p->s_val.f /= forp->by;
       +                break;
       +        }
       +        nextfor();
       +}
       +
       +char *ifstat(double expr, char *thenpart, char *elsepart)
       +{
       +        dprintf("if %g then <%s> else <%s>\n", expr, thenpart, elsepart? elsepart : "");
       +        if (expr) {
       +                unput('\n');
       +                pushsrc(Free, thenpart);
       +                pushsrc(String, thenpart);
       +                unput('\n');
       +                  if (elsepart)
       +                        free(elsepart);
       +                return thenpart;        /* to be freed later */
       +        } else {
       +                free(thenpart);
       +                if (elsepart) {
       +                        unput('\n');
       +                        pushsrc(Free, elsepart);
       +                        pushsrc(String, elsepart);
       +                        unput('\n');
       +                }
       +                return elsepart;
       +        }
       +}
 (DIR) diff --git a/src/cmd/pic/input.c b/src/cmd/pic/input.c
       t@@ -0,0 +1,593 @@
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include <ctype.h>
       +#include <errno.h>
       +#include "pic.h"
       +#include "y.tab.h"
       +
       +Infile        infile[10];
       +Infile        *curfile = infile;
       +
       +#define        MAXSRC        50
       +Src        src[MAXSRC];        /* input source stack */
       +Src        *srcp        = src;
       +
       +void        do_thru(void);
       +int        nextchar(void);
       +int        getarg(char *);
       +void        freedef(char *);
       +int        baldelim(int, char *);
       +
       +void pushsrc(int type, char *ptr)        /* new input source */
       +{
       +        if (++srcp >= src + MAXSRC)
       +                ERROR "inputs nested too deep" FATAL;
       +        srcp->type = type;
       +        srcp->sp = ptr;
       +        if (dbg > 1) {
       +                printf("\n%3d ", srcp - src);
       +                switch (srcp->type) {
       +                case File:
       +                        printf("push file %s\n", ((Infile *)ptr)->fname);
       +                        break;
       +                case Macro:
       +                        printf("push macro <%s>\n", ptr);
       +                        break;
       +                case Char:
       +                        printf("push char <%c>\n", *ptr);
       +                        break;
       +                case Thru:
       +                        printf("push thru\n");
       +                        break;
       +                case String:
       +                        printf("push string <%s>\n", ptr);
       +                        break;
       +                case Free:
       +                        printf("push free <%s>\n", ptr);
       +                        break;
       +                default:
       +                        ERROR "pushed bad type %d", srcp->type FATAL;
       +                }
       +        }
       +}
       +
       +void popsrc(void)        /* restore an old one */
       +{
       +        if (srcp <= src)
       +                ERROR "too many inputs popped" FATAL;
       +        if (dbg > 1) {
       +                printf("%3d ", srcp - src);
       +                switch (srcp->type) {
       +                case File:
       +                        printf("pop file\n");
       +                        break;
       +                case Macro:
       +                        printf("pop macro\n");
       +                        break;
       +                case Char:
       +                        printf("pop char <%c>\n", *srcp->sp);
       +                        break;
       +                case Thru:
       +                        printf("pop thru\n");
       +                        break;
       +                case String:
       +                        printf("pop string\n");
       +                        break;
       +                case Free:
       +                        printf("pop free\n");
       +                        break;
       +                default:
       +                        ERROR "pop weird input %d", srcp->type FATAL;
       +                }
       +        }
       +        srcp--;
       +}
       +
       +void definition(char *s)        /* collect definition for s and install */
       +                                /* definitions picked up lexically */
       +{
       +        char *p;
       +        struct symtab *stp;
       +
       +        p = delimstr("definition");
       +        stp = lookup(s);
       +        if (stp != NULL) {        /* it's there before */
       +                if (stp->s_type != DEFNAME) {
       +                        ERROR "%s used as variable and definition", s WARNING;
       +                        return;
       +                }
       +                free(stp->s_val.p);
       +                stp->s_val.p = p;
       +        } else {
       +                YYSTYPE u;
       +                u.p = p;
       +                makevar(tostring(s), DEFNAME, u);
       +        }
       +        dprintf("installing %s as `%s'\n", s, p);
       +}
       +
       +char *delimstr(char *s)        /* get body of X ... X */
       +                                /* message if too big */
       +{
       +        int c, delim, rdelim, n, deep;
       +        static char *buf = NULL;
       +        static int nbuf = 0;
       +        char *p;
       +
       +        if (buf == NULL)
       +                buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
       +        while ((delim = input()) == ' ' || delim == '\t' || delim == '\n')
       +                ;
       +        rdelim = baldelim(delim, "{}");                /* could be "(){}[]`'" */
       +        deep = 1;
       +        for (p = buf; ; ) {
       +                c = input();
       +                if (c == rdelim)
       +                        if (--deep == 0)
       +                                break;
       +                if (c == delim)
       +                        deep++;
       +                if (p >= buf + nbuf) {
       +                        n = p - buf;
       +                        buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
       +                        p = buf + n;
       +                }
       +                if (c == EOF)
       +                        ERROR "end of file in %s %c %.20s... %c", s, delim, buf, delim FATAL;
       +                *p++ = c;
       +        }
       +        *p = '\0';
       +        dprintf("delimstr %s %c <%s> %c\n", s, delim, buf, delim);
       +        return tostring(buf);
       +}
       +
       +baldelim(int c, char *s)        /* replace c by balancing entry in s */
       +{
       +        for ( ; *s; s += 2)
       +                if (*s == c)
       +                        return s[1];
       +        return c;
       +}
       +
       +void undefine(char *s)        /* undefine macro */
       +{
       +        while (*s != ' ' && *s != '\t')                /* skip "undef..." */
       +                s++;
       +        while (*s == ' ' || *s == '\t')
       +                s++;
       +        freedef(s);
       +}
       +
       +
       +Arg        args[10];        /* argument frames */
       +Arg        *argfp = args;        /* frame pointer */
       +int        argcnt;                /* number of arguments seen so far */
       +
       +void dodef(struct symtab *stp)        /* collect args and switch input to defn */
       +{
       +        int i, len;
       +        char *p;
       +        Arg *ap;
       +
       +        ap = argfp+1;
       +        if (ap >= args+10)
       +                ERROR "arguments too deep" FATAL;
       +        argcnt = 0;
       +        if (input() != '(')
       +                ERROR "disaster in dodef" FATAL;
       +        if (ap->argval == 0)
       +                ap->argval = malloc(1000);
       +        for (p = ap->argval; (len = getarg(p)) != -1; p += len) {
       +                ap->argstk[argcnt++] = p;
       +                if (input() == ')')
       +                        break;
       +        }
       +        for (i = argcnt; i < MAXARGS; i++)
       +                ap->argstk[i] = "";
       +        if (dbg)
       +                for (i = 0; i < argcnt; i++)
       +                        printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
       +        argfp = ap;
       +        pushsrc(Macro, stp->s_val.p);
       +}
       +
       +getarg(char *p)        /* pick up single argument, store in p, return length */
       +{
       +        int n, c, npar;
       +
       +        n = npar = 0;
       +        for ( ;; ) {
       +                c = input();
       +                if (c == EOF)
       +                        ERROR "end of file in getarg" FATAL;
       +                if (npar == 0 && (c == ',' || c == ')'))
       +                        break;
       +                if (c == '"')        /* copy quoted stuff intact */
       +                        do {
       +                                *p++ = c;
       +                                n++;
       +                        } while ((c = input()) != '"' && c != EOF);
       +                else if (c == '(')
       +                        npar++;
       +                else if (c == ')')
       +                        npar--;
       +                n++;
       +                *p++ = c;
       +        }
       +        *p = 0;
       +        unput(c);
       +        return(n + 1);
       +}
       +
       +#define        PBSIZE        2000
       +char        pbuf[PBSIZE];                /* pushback buffer */
       +char        *pb        = pbuf-1;        /* next pushed back character */
       +
       +char        ebuf[200];                /* collect input here for error reporting */
       +char        *ep        = ebuf;
       +
       +int        begin        = 0;
       +extern        int        thru;
       +extern        struct symtab        *thrudef;
       +extern        char        *untilstr;
       +
       +input(void)
       +{
       +        register int c;
       +
       +        if (thru && begin) {
       +                do_thru();
       +                begin = 0;
       +        }
       +        c = nextchar();
       +        if (dbg > 1)
       +                printf(" <%c>", c);
       +        if (ep >= ebuf + sizeof ebuf)
       +                ep = ebuf;
       +        return *ep++ = c;
       +}
       +
       +nextchar(void)
       +{
       +        register int c;
       +
       +  loop:
       +        switch (srcp->type) {
       +        case Free:        /* free string */
       +                free(srcp->sp);
       +                popsrc();
       +                goto loop;
       +        case Thru:        /* end of pushed back line */
       +                begin = 1;
       +                popsrc();
       +                c = '\n';
       +                break;
       +        case Char:
       +                if (pb >= pbuf) {
       +                        c = *pb--;
       +                        popsrc();
       +                        break;
       +                } else {        /* can't happen? */
       +                        popsrc();
       +                        goto loop;
       +                }
       +        case String:
       +                c = *srcp->sp++;
       +                if (c == '\0') {
       +                        popsrc();
       +                        goto loop;
       +                } else {
       +                        if (*srcp->sp == '\0')        /* empty, so pop */
       +                                popsrc();
       +                        break;
       +                }
       +        case Macro:
       +                c = *srcp->sp++;
       +                if (c == '\0') {
       +                        if (--argfp < args)
       +                                ERROR "argfp underflow" FATAL;
       +                        popsrc();
       +                        goto loop;
       +                } else if (c == '$' && isdigit(*srcp->sp)) {
       +                        int n = 0;
       +                        while (isdigit(*srcp->sp))
       +                                n = 10 * n + *srcp->sp++ - '0';
       +                        if (n > 0 && n <= MAXARGS)
       +                                pushsrc(String, argfp->argstk[n-1]);
       +                        goto loop;
       +                }
       +                break;
       +        case File:
       +                c = getc(curfile->fin);
       +                if (c == EOF) {
       +                        if (curfile == infile)
       +                                ERROR "end of file inside .PS/.PE" FATAL;
       +                        if (curfile->fin != stdin) {
       +                                fclose(curfile->fin);
       +                                free(curfile->fname);        /* assumes allocated */
       +                        }
       +                        curfile--;
       +                        printlf(curfile->lineno, curfile->fname);
       +                        popsrc();
       +                        thru = 0;        /* chicken out */
       +                        thrudef = 0;
       +                        if (untilstr) {
       +                                free(untilstr);
       +                                untilstr = 0;
       +                        }
       +                        goto loop;
       +                }
       +                if (c == '\n')
       +                        curfile->lineno++;
       +                break;
       +        }
       +        return c;
       +}
       +
       +void do_thru(void)        /* read one line, make into a macro expansion */
       +{
       +        int c, i;
       +        char *p;
       +        Arg *ap;
       +
       +        ap = argfp+1;
       +        if (ap >= args+10)
       +                ERROR "arguments too deep" FATAL;
       +        if (ap->argval == NULL)
       +                ap->argval = malloc(1000);
       +        p = ap->argval;
       +        argcnt = 0;
       +        c = nextchar();
       +        if (thru == 0) {        /* end of file was seen, so thru is done */
       +                unput(c);
       +                return;
       +        }
       +        for ( ; c != '\n' && c != EOF; ) {
       +                if (c == ' ' || c == '\t') {
       +                        c = nextchar();
       +                        continue;
       +                }
       +                ap->argstk[argcnt++] = p;
       +                if (c == '"') {
       +                        do {
       +                                *p++ = c;
       +                                if ((c = nextchar()) == '\\') {
       +                                        *p++ = c;
       +                                        *p++ = nextchar();
       +                                        c = nextchar();
       +                                }
       +                        } while (c != '"' && c != '\n' && c != EOF);
       +                        *p++ = '"';
       +                        if (c == '"')
       +                                c = nextchar();
       +                } else {
       +                        do {
       +                                *p++ = c;
       +                        } while ((c = nextchar())!=' ' && c!='\t' && c!='\n' && c!=',' && c!=EOF);
       +                        if (c == ',')
       +                                c = nextchar();
       +                }
       +                *p++ = '\0';
       +        }
       +        if (c == EOF)
       +                ERROR "unexpected end of file in do_thru" FATAL;
       +        if (argcnt == 0) {        /* ignore blank line */
       +                pushsrc(Thru, (char *) 0);
       +                return;
       +        }
       +        for (i = argcnt; i < MAXARGS; i++)
       +                ap->argstk[i] = "";
       +        if (dbg)
       +                for (i = 0; i < argcnt; i++)
       +                        printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
       +        if (strcmp(ap->argstk[0], ".PE") == 0) {
       +                thru = 0;
       +                thrudef = 0;
       +                pushsrc(String, "\n.PE\n");
       +                return;
       +        }
       +        if (untilstr && strcmp(ap->argstk[0], untilstr) == 0) {
       +                thru = 0;
       +                thrudef = 0;
       +                free(untilstr);
       +                untilstr = 0;
       +                return;
       +        }
       +        pushsrc(Thru, (char *) 0);
       +        dprintf("do_thru pushing back <%s>\n", thrudef->s_val.p);
       +        argfp = ap;
       +        pushsrc(Macro, thrudef->s_val.p);
       +}
       +
       +unput(int c)
       +{
       +        if (++pb >= pbuf + sizeof pbuf)
       +                ERROR "pushback overflow" FATAL;
       +        if (--ep < ebuf)
       +                ep = ebuf + sizeof(ebuf) - 1;
       +        *pb = c;
       +        pushsrc(Char, pb);
       +        return c;
       +}
       +
       +void pbstr(char *s)
       +{
       +        pushsrc(String, s);
       +}
       +
       +double errcheck(double x, char  *s)
       +{
       +        extern int errno;
       +
       +        if (errno == EDOM) {
       +                errno = 0;
       +                ERROR "%s argument out of domain", s WARNING;
       +        } else if (errno == ERANGE) {
       +                errno = 0;
       +                ERROR "%s result out of range", s WARNING;
       +        }
       +        return x;
       +}
       +
       +char        errbuf[200];
       +
       +void        eprint(void);
       +
       +void yyerror(char *s)
       +{
       +        extern char *cmdname;
       +        int ern = errno;        /* cause some libraries clobber it */
       +
       +        if (synerr)
       +                return;
       +        fflush(stdout);
       +        fprintf(stderr, "%s: %s", cmdname, s);
       +        if (ern > 0) {
       +                errno = ern;
       +                perror("???");
       +        }
       +        fprintf(stderr, " near %s:%d\n",
       +                curfile->fname, curfile->lineno+1);
       +        eprint();
       +        synerr = 1;
       +        errno = 0;
       +}
       +
       +void eprint(void)        /* try to print context around error */
       +{
       +        char *p, *q;
       +
       +        p = ep - 1;
       +        if (p > ebuf && *p == '\n')
       +                p--;
       +        for ( ; p >= ebuf && *p != '\n'; p--)
       +                ;
       +        while (*p == '\n')
       +                p++;
       +        fprintf(stderr, " context is\n\t");
       +        for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
       +                ;
       +        while (p < q)
       +                putc(*p++, stderr);
       +        fprintf(stderr, " >>> ");
       +        while (p < ep)
       +                putc(*p++, stderr);
       +        fprintf(stderr, " <<< ");
       +        while (pb >= pbuf)
       +                putc(*pb--, stderr);
       +        fgets(ebuf, sizeof ebuf, curfile->fin);
       +        fprintf(stderr, "%s", ebuf);
       +        pbstr("\n.PE\n");        /* safety first */
       +        ep = ebuf;
       +}
       +
       +void yywrap(void) {}
       +
       +char        *newfile = 0;                /* filename for file copy */
       +char        *untilstr = 0;                /* string that terminates a thru */
       +int        thru        = 0;                /* 1 if copying thru macro */
       +struct symtab        *thrudef = 0;                /* macro being used */
       +
       +void copyfile(char *s)        /* remember file to start reading from */
       +{
       +        newfile = s;
       +}
       +
       +void copydef(struct symtab *p)        /* remember macro symtab ptr */
       +{
       +        thrudef = p;
       +}
       +
       +struct symtab *copythru(char *s)        /* collect the macro name or body for thru */
       +{
       +        struct symtab *p;
       +        char *q, *addnewline(char *);
       +
       +        p = lookup(s);
       +        if (p != NULL) {
       +                if (p->s_type == DEFNAME) {
       +                        p->s_val.p = addnewline(p->s_val.p);
       +                        return p;
       +                } else
       +                        ERROR "%s used as define and name", s FATAL;
       +        }
       +        /* have to collect the definition */
       +        pbstr(s);        /* first char is the delimiter */
       +        q = delimstr("thru body");
       +        s = "nameless";
       +        p = lookup(s);
       +        if (p != NULL) {
       +                if (p->s_val.p)
       +                        free(p->s_val.p);
       +                p->s_val.p = q;
       +        } else {
       +                YYSTYPE u;
       +                u.p = q;
       +                p = makevar(tostring(s), DEFNAME, u);
       +        }
       +        p->s_val.p = addnewline(p->s_val.p);
       +        dprintf("installing %s as `%s'\n", s, p->s_val.p);
       +        return p;
       +}
       +
       +char *addnewline(char *p)        /* add newline to end of p */
       +{
       +        int n;
       +
       +        n = strlen(p);
       +        if (p[n-1] != '\n') {
       +                p = realloc(p, n+2);
       +                p[n] = '\n';
       +                p[n+1] = '\0';
       +        }
       +        return p;
       +}
       +
       +void copyuntil(char *s)        /* string that terminates a thru */
       +{
       +        untilstr = s;
       +}
       +
       +void copy(void)        /* begin input from file, etc. */
       +{
       +        FILE *fin;
       +
       +        if (newfile) {
       +                if ((fin = fopen(newfile, "r")) == NULL)
       +                        ERROR "can't open file %s", newfile FATAL;
       +                curfile++;
       +                curfile->fin = fin;
       +                curfile->fname = newfile;
       +                curfile->lineno = 0;
       +                printlf(1, curfile->fname);
       +                pushsrc(File, curfile->fname);
       +                newfile = 0;
       +        }
       +        if (thrudef) {
       +                thru = 1;
       +                begin = 1;        /* wrong place */
       +        }
       +}
       +
       +char        shellbuf[1000], *shellp;
       +
       +void shell_init(void)        /* set up to interpret a shell command */
       +{
       +        sprintf(shellbuf, "rc -c '");
       +        shellp = shellbuf + strlen(shellbuf);
       +}
       +
       +void shell_text(char *s)        /* add string to command being collected */
       +{
       +        while (*shellp++ = *s++)
       +                ;
       +        shellp--;
       +}
       +
       +void shell_exec(void)        /* do it */
       +{
       +        *shellp++ = '\'';
       +        *shellp = '\0';
       +        system(shellbuf);
       +}
 (DIR) diff --git a/src/cmd/pic/linegen.c b/src/cmd/pic/linegen.c
       t@@ -0,0 +1,240 @@
       +#include <stdio.h>
       +#include <math.h>
       +#include "pic.h"
       +#include "y.tab.h"
       +
       +obj *linegen(int type)
       +{
       +        static double prevdx = HT;
       +        static double prevdy = 0;
       +        static double prevw = HT10;
       +        static double prevh = HT5;
       +        int i, j, some, head, ddtype, invis, chop, battr, with;
       +        double ddval, chop1, chop2, x0, y0, x1, y1;
       +        double fillval = 0;
       +        double theta;
       +        double defx, defy, xwith, ywith;
       +        obj *p, *ppos;
       +        static int xtab[] = { 1, 0, -1, 0 };        /* R=0, U=1, L=2, D=3 */
       +        static int ytab[] = { 0, 1, 0, -1 };
       +        double dx[500], dy[500];
       +        int ndxy;
       +        double nx, ny;
       +        Attr *ap, *chop_ap[4];
       +
       +        nx = curx;
       +        ny = cury;
       +        defx = getfval("linewid");
       +        defy = getfval("lineht");
       +        prevh = getfval("arrowht");
       +        prevw = getfval("arrowwid");
       +        dx[0] = dy[0] = ndxy = some = head = invis = battr = with = 0;
       +        chop = chop1 = chop2 = 0;
       +        ddtype = ddval = xwith = ywith = 0;
       +        for (i = 0; i < nattr; i++) {
       +                ap = &attr[i];
       +                switch (ap->a_type) {
       +                case TEXTATTR:
       +                        savetext(ap->a_sub, ap->a_val.p);
       +                        break;
       +                case HEAD:
       +                        head += ap->a_val.i;
       +                        break;
       +                case INVIS:
       +                        invis = INVIS;
       +                        break;
       +                case NOEDGE:
       +                        battr |= NOEDGEBIT;
       +                        break;
       +                case DOT:
       +                case DASH:
       +                        ddtype = ap->a_type==DOT ? DOTBIT : DASHBIT;
       +                        if (ap->a_sub == DEFAULT)
       +                                ddval = getfval("dashwid");
       +                        else
       +                                ddval = ap->a_val.f;
       +                        break;
       +                case SAME:
       +                        dx[ndxy] = prevdx;
       +                        dy[ndxy] = prevdy;
       +                        some++;
       +                        break;
       +                case LEFT:
       +                        dx[ndxy] -= (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
       +                        some++;
       +                        hvmode = L_DIR;
       +                        break;
       +                case RIGHT:
       +                        dx[ndxy] += (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
       +                        some++;
       +                        hvmode = R_DIR;
       +                        break;
       +                case UP:
       +                        dy[ndxy] += (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
       +                        some++;
       +                        hvmode = U_DIR;
       +                        break;
       +                case DOWN:
       +                        dy[ndxy] -= (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
       +                        some++;
       +                        hvmode = D_DIR;
       +                        break;
       +                case HEIGHT:        /* length of arrowhead */
       +                        prevh = ap->a_val.f;
       +                        break;
       +                case WIDTH:        /* width of arrowhead */
       +                        prevw = ap->a_val.f;
       +                        break;
       +                case TO:
       +                        if (some) {
       +                                nx += dx[ndxy];
       +                                ny += dy[ndxy];
       +                                ndxy++;
       +                                dx[ndxy] = dy[ndxy] = some = 0;
       +                        }
       +                        ppos = attr[i].a_val.o;
       +                        dx[ndxy] = ppos->o_x - nx;
       +                        dy[ndxy] = ppos->o_y - ny;
       +                        some++;
       +                        break;
       +                case BY:
       +                        if (some) {
       +                                nx += dx[ndxy];
       +                                ny += dy[ndxy];
       +                                ndxy++;
       +                                dx[ndxy] = dy[ndxy] = some = 0;
       +                        }
       +                        ppos = ap->a_val.o;
       +                        dx[ndxy] = ppos->o_x;
       +                        dy[ndxy] = ppos->o_y;
       +                        some++;
       +                        break;
       +                case THEN:        /* turn off any previous accumulation */
       +                        if (some) {
       +                                nx += dx[ndxy];
       +                                ny += dy[ndxy];
       +                                ndxy++;
       +                                dx[ndxy] = dy[ndxy] = some = 0;
       +                        }
       +                        break;
       +                case FROM:
       +                case AT:
       +                        ppos = ap->a_val.o;
       +                        nx = curx = ppos->o_x;
       +                        ny = cury = ppos->o_y;
       +                        break;
       +                case WITH:
       +                        with = ap->a_val.i;
       +                        break;
       +                case CHOP:
       +                        if (ap->a_sub != PLACENAME) {
       +                                if( chop == 0)
       +                                        chop1 = chop2 = ap->a_val.f;
       +                                else
       +                                        chop2 = ap->a_val.f;
       +                        }
       +                        chop_ap[chop++] = ap;
       +                        break;
       +                case FILL:
       +                        battr |= FILLBIT;
       +                        if (ap->a_sub == DEFAULT)
       +                                fillval = getfval("fillval");
       +                        else
       +                                fillval = ap->a_val.f;
       +                        break;
       +                }
       +        }
       +        if (with) {        /* this doesn't work at all */
       +                switch (with) {
       +                case CENTER:
       +                        xwith = (dx[1] - dx[0]) / 2; ywith = (dy[1] - dy[0]) / 2; break;
       +                }
       +                for (i = 0; i < ndxy; i++) {
       +                        dx[i] -= xwith;
       +                        dy[i] -= ywith;
       +                }
       +                curx += xwith;
       +                cury += ywith;
       +        }
       +        if (some) {
       +                nx += dx[ndxy];
       +                ny += dy[ndxy];
       +                ndxy++;
       +                defx = dx[ndxy-1];
       +                defy = dy[ndxy-1];
       +        } else {
       +                defx *= xtab[hvmode];
       +                defy *= ytab[hvmode];
       +                dx[ndxy] = defx;
       +                dy[ndxy] = defy;
       +                ndxy++;
       +                nx += defx;
       +                ny += defy;
       +        }
       +        prevdx = defx;
       +        prevdy = defy;
       +        if (chop) {
       +                if (chop == 1 && chop1 == 0)        /* just said "chop", so use default */
       +                        chop1 = chop2 = getfval("circlerad");
       +                theta = atan2(dy[0], dx[0]);
       +                x0 = chop1 * cos(theta);
       +                y0 = chop1 * sin(theta);
       +                curx += x0;
       +                cury += y0;
       +                dx[0] -= x0;
       +                dy[0] -= y0;
       +
       +                theta = atan2(dy[ndxy-1], dx[ndxy-1]);
       +                x1 = chop2 * cos(theta);
       +                y1 = chop2 * sin(theta);
       +                nx -= x1;
       +                ny -= y1;
       +                dx[ndxy-1] -= x1;
       +                dy[ndxy-1] -= y1;
       +                dprintf("chopping %g %g %g %g; cur=%g,%g end=%g,%g\n",
       +                        x0, y0, x1, y1, curx, cury, nx, ny);
       +        }
       +        p = makenode(type, 5 + 2 * ndxy);
       +        curx = p->o_val[0] = nx;
       +        cury = p->o_val[1] = ny;
       +        if (head || type == ARROW) {
       +                p->o_nhead = getfval("arrowhead");
       +                p->o_val[2] = prevw;
       +                p->o_val[3] = prevh;
       +                if (head == 0)
       +                        head = HEAD2;        /* default arrow head */
       +        }
       +        p->o_attr = head | invis | ddtype | battr;
       +        p->o_fillval = fillval;
       +        p->o_val[4] = ndxy;
       +        nx = p->o_x;
       +        ny = p->o_y;
       +        for (i = 0, j = 5; i < ndxy; i++, j += 2) {
       +                p->o_val[j] = dx[i];
       +                p->o_val[j+1] = dy[i];
       +                if (type == LINE || type == ARROW)
       +                        extreme(nx += dx[i], ny += dy[i]);
       +                else if (type == SPLINE && i < ndxy-1) {
       +                        /* to compute approx extreme of spline at p,
       +                        /* compute midway between p-1 and p+1,
       +                        /* then go 3/4 from there to p */
       +                        double ex, ey, xi, yi, xi1, yi1;
       +                        xi = nx + dx[i]; yi = ny + dy[i];        /* p */
       +                        xi1 = xi + dx[i+1]; yi1 = yi + dy[i+1];        /* p+1 */
       +                        ex = (nx+xi1)/2; ey = (ny+yi1)/2;        /* midway */
       +                        ex += 0.75*(xi-ex); ey += 0.75*(yi-ey);
       +                        extreme(ex, ey);
       +                        nx = xi; ny = yi;
       +                }
       +                        
       +        }
       +        p->o_ddval = ddval;
       +        if (dbg) {
       +                printf("S or L from %g %g to %g %g with %d elements:\n", p->o_x, p->o_y, curx, cury, ndxy);
       +                for (i = 0, j = 5; i < ndxy; i++, j += 2)
       +                        printf("%g %g\n", p->o_val[j], p->o_val[j+1]);
       +        }
       +        extreme(p->o_x, p->o_y);
       +        extreme(curx, cury);
       +        return(p);
       +}
 (DIR) diff --git a/src/cmd/pic/main.c b/src/cmd/pic/main.c
       t@@ -0,0 +1,282 @@
       +#include        <stdio.h>
       +#include        <signal.h>
       +#include        <stdlib.h>
       +#include        <string.h>
       +#include        "pic.h"
       +#include        "y.tab.h"
       +
       +char        *version = "version July 5, 1993";
       +
       +obj        **objlist = 0;                /* store the elements here */
       +int        nobjlist = 0;                /* size of objlist array */
       +int        nobj        = 0;
       +
       +Attr        *attr;        /* attributes stored here as collected */
       +int        nattrlist = 0;
       +int        nattr        = 0;        /* number of entries in attr_list */
       +
       +Text        *text        = 0;        /* text strings stored here as collected */
       +int        ntextlist = 0;                /* size of text[] array */
       +int        ntext        = 0;
       +int        ntext1        = 0;        /* record ntext here on entry to each figure */
       +
       +double        curx        = 0;
       +double        cury        = 0;
       +
       +int        hvmode        = R_DIR;        /* R => join left to right, D => top to bottom, etc. */
       +
       +int        codegen        = 0;        /* 1=>output for this picture; 0=>no output */
       +char        *PEstring;        /* "PS" or "PE" picked up by lexer */
       +
       +double        deltx        = 6;        /* max x value in output, for scaling */
       +double        delty        = 6;        /* max y value in output, for scaling */
       +int        dbg        = 0;
       +int        lineno        = 0;
       +char        *filename        = "-";
       +int        synerr        = 0;
       +int        anyerr        = 0;        /* becomes 1 if synerr ever 1 */
       +char        *cmdname;
       +
       +double        xmin        = 30000;        /* min values found in actual data */
       +double        ymin        = 30000;
       +double        xmax        = -30000;        /* max */
       +double        ymax        = -30000;
       +
       +void        fpecatch(int);
       +void        getdata(void), setdefaults(void);
       +void        setfval(char *, double);
       +int        getpid(void);
       +
       +main(int argc, char *argv[])
       +{
       +        char buf[20];
       +
       +        signal(SIGFPE, fpecatch);
       +        cmdname = argv[0];
       +        while (argc > 1 && *argv[1] == '-') {
       +                switch (argv[1][1]) {
       +                case 'd':
       +                        dbg = atoi(&argv[1][2]);
       +                        if (dbg == 0)
       +                                dbg = 1;
       +                        fprintf(stderr, "%s\n", version);
       +                        break;
       +                case 'V':
       +                        fprintf(stderr, "%s\n", version);
       +                        return 0;
       +                }
       +                argc--;
       +                argv++;
       +        }
       +        setdefaults();
       +        objlist = (obj **) grow((char *)objlist, "objlist", nobjlist += 1000, sizeof(obj *));
       +        text = (Text *) grow((char *)text, "text", ntextlist += 1000, sizeof(Text));
       +        attr = (Attr *) grow((char *)attr, "attr", nattrlist += 100, sizeof(Attr));
       +
       +        sprintf(buf, "/%d/", getpid());
       +        pushsrc(String, buf);
       +        definition("pid");
       +
       +        curfile = infile;
       +        pushsrc(File, curfile->fname);
       +        if (argc <= 1) {
       +                curfile->fin = stdin;
       +                curfile->fname = tostring("-");
       +                getdata();
       +        } else
       +                while (argc-- > 1) {
       +                        if ((curfile->fin = fopen(*++argv, "r")) == NULL) {
       +                                fprintf(stderr, "%s: can't open %s\n", cmdname, *argv);
       +                                exit(1);
       +                        }
       +                        curfile->fname = tostring(*argv);
       +                        getdata();
       +                        fclose(curfile->fin);
       +                        free(curfile->fname);
       +                }
       +        return anyerr;
       +}
       +
       +void fpecatch(int n)
       +{
       +        ERROR "floating point exception %d", n FATAL;
       +}
       +
       +char *grow(char *ptr, char *name, int num, int size)        /* make array bigger */
       +{
       +        char *p;
       +
       +        if (ptr == NULL)
       +                p = malloc(num * size);
       +        else
       +                p = realloc(ptr, num * size);
       +        if (p == NULL)
       +                ERROR "can't grow %s to %d", name, num * size FATAL;
       +        return p;
       +}
       +
       +static struct {
       +        char *name;
       +        double val;
       +        short scalable;                /* 1 => adjust when "scale" changes */
       +} defaults[] ={
       +        "scale", SCALE, 1,
       +        "lineht", HT, 1,
       +        "linewid", HT, 1,
       +        "moveht", HT, 1,
       +        "movewid", HT, 1,
       +        "dashwid", HT10, 1,
       +        "boxht", HT, 1,
       +        "boxwid", WID, 1,
       +        "circlerad", HT2, 1,
       +        "arcrad", HT2, 1,
       +        "ellipseht", HT, 1,
       +        "ellipsewid", WID, 1,
       +        "arrowht", HT5, 1,
       +        "arrowwid", HT10, 1,
       +        "arrowhead", 2, 0,                /* arrowhead style */
       +        "textht", 0.0, 1,                /* 6 lines/inch is also a useful value */
       +        "textwid", 0.0, 1,
       +        "maxpsht", MAXHT, 0,
       +        "maxpswid", MAXWID, 0,
       +        "fillval", 0.7, 0,                /* gray value for filling boxes */
       +        NULL, 0, 0
       +};
       +
       +void setdefaults(void)        /* set default sizes for variables like boxht */
       +{
       +        int i;
       +        YYSTYPE v;
       +
       +        for (i = 0; defaults[i].name != NULL; i++) {
       +                v.f = defaults[i].val;
       +                makevar(tostring(defaults[i].name), VARNAME, v);
       +        }
       +}
       +
       +void resetvar(void)        /* reset variables listed */
       +{
       +        int i, j;
       +
       +        if (nattr == 0) {        /* none listed, so do all */
       +                setdefaults();
       +                return;
       +        }
       +        for (i = 0; i < nattr; i++) {
       +                for (j = 0; defaults[j].name != NULL; j++)
       +                        if (strcmp(defaults[j].name, attr[i].a_val.p) == 0) {
       +                                setfval(defaults[j].name, defaults[j].val);
       +                                free(attr[i].a_val.p);
       +                                break;
       +                        }
       +        }
       +}
       +
       +void checkscale(char *s)        /* if s is "scale", adjust default variables */
       +{
       +        int i;
       +        double scale;
       +
       +        if (strcmp(s, "scale") == 0) {
       +                scale = getfval("scale");
       +                for (i = 1; defaults[i].name != NULL; i++)
       +                        if (defaults[i].scalable)
       +                                setfval(defaults[i].name, defaults[i].val * scale);
       +        }
       +}
       +
       +void getdata(void)
       +{
       +        char *p, buf[1000], buf1[100];
       +        int ln;
       +        void reset(void), openpl(char *), closepl(char *), print(void);
       +        int yyparse(void);
       +
       +        curfile->lineno = 0;
       +        printlf(1, curfile->fname);
       +        while (fgets(buf, sizeof buf, curfile->fin) != NULL) {
       +                curfile->lineno++;
       +                if (*buf == '.' && *(buf+1) == 'P' && *(buf+2) == 'S') {
       +                        for (p = &buf[3]; *p == ' '; p++)
       +                                ;
       +                        if (*p++ == '<') {
       +                                Infile svfile;
       +                                svfile = *curfile;
       +                                sscanf(p, "%s", buf1);
       +                                if ((curfile->fin=fopen(buf1, "r")) == NULL)
       +                                        ERROR "can't open %s", buf1 FATAL;
       +                                curfile->fname = tostring(buf1);
       +                                getdata();
       +                                fclose(curfile->fin);
       +                                free(curfile->fname);
       +                                *curfile = svfile;
       +                                printlf(curfile->lineno, curfile->fname);
       +                                continue;
       +                        }
       +                        reset();
       +                        yyparse();
       +                        anyerr += synerr;
       +                        deltx = (xmax - xmin) / getfval("scale");
       +                        delty = (ymax - ymin) / getfval("scale");
       +                        if (buf[3] == ' ') {        /* next things are wid & ht */
       +                                if (sscanf(&buf[4],"%lf %lf", &deltx, &delty) < 2)
       +                                        delty = deltx * (ymax-ymin) / (xmax-xmin);
       +                                /* else {
       +                                /*        double xfac, yfac; */
       +                                /*        xfac = deltx / (xmax-xmin);
       +                                /*        yfac = delty / (ymax-ymin);
       +                                /*        if (xfac <= yfac)
       +                                /*                delty = xfac * (ymax-ymin);
       +                                /*        else
       +                                /*                deltx = yfac * (xmax-xmin);
       +                                /*}
       +                                */
       +                        }
       +                        dprintf("deltx = %g, delty = %g\n", deltx, delty);
       +                        if (codegen && !synerr) {
       +                                openpl(&buf[3]);        /* puts out .PS, with ht & wid stuck in */
       +                                printlf(curfile->lineno+1, NULL);
       +                                print();        /* assumes \n at end */
       +                                closepl(PEstring);        /* does the .PE/F */
       +                                free(PEstring);
       +                        }
       +                        printlf(curfile->lineno+1, NULL);
       +                        fflush(stdout);
       +                } else if (buf[0] == '.' && buf[1] == 'l' && buf[2] == 'f') {
       +                        if (sscanf(buf+3, "%d %s", &ln, buf1) == 2) {
       +                                free(curfile->fname);
       +                                printlf(curfile->lineno = ln, curfile->fname = tostring(buf1));
       +                        } else
       +                                printlf(curfile->lineno = ln, NULL);
       +                } else
       +                        fputs(buf, stdout);
       +        }
       +}
       +
       +void reset(void)
       +{
       +        obj *op;
       +        int i;
       +        extern int nstack;
       +        extern        void freesymtab(struct symtab *);
       +
       +        for (i = 0; i < nobj; i++) {
       +                op = objlist[i];
       +                if (op->o_type == BLOCK)
       +                        freesymtab(op->o_symtab);
       +                free((char *)objlist[i]);
       +        }
       +        nobj = 0;
       +        nattr = 0;
       +        for (i = 0; i < ntext; i++)
       +                if (text[i].t_val)
       +                        free(text[i].t_val);
       +        ntext = ntext1 = 0;
       +        codegen = synerr = 0;
       +        nstack = 0;
       +        curx = cury = 0;
       +        PEstring = 0;
       +        hvmode = R_DIR;
       +        xmin = ymin = 30000;
       +        xmax = ymax = -30000;
       +}
 (DIR) diff --git a/src/cmd/pic/makefile b/src/cmd/pic/makefile
       t@@ -0,0 +1,39 @@
       +CC = cc     # the usual situation
       +CFLAGS =    # the usual situation
       +
       +CC = lcc        # you will probably want to remove this 
       +CFLAGS = -g -N -I/usr/include/lcc -I/usr/include       # and this
       +
       +YFLAGS = -d
       +
       +OFILES = picl.o main.o print.o misc.o symtab.o blockgen.o boxgen.o \
       +         circgen.o arcgen.o linegen.o movegen.o textgen.o \
       +         input.o for.o pltroff.o $(ALLOC)
       +CFILES = main.c print.c misc.c symtab.c blockgen.c boxgen.c circgen.c \
       +         arcgen.c linegen.c movegen.c textgen.c \
       +         input.c for.c pltroff.c
       +SRCFILES = picy.y picl.l pic.h $(CFILES) makefile FIXES README PS-PEmacros
       +
       +pic:        picy.o $(OFILES) pic.h
       +        $(CC) $(CFLAGS) picy.o $(OFILES) -lm
       +
       +$(OFILES):        pic.h prevy.tab.h
       +
       +picy.o:        pic.h
       +
       +prevy.tab.h:        y.tab.h
       +        -cmp -s y.tab.h prevy.tab.h || cp y.tab.h prevy.tab.h
       +
       +bundle:
       +        @bundle $(SRCFILES) 
       +
       +bowell:         $(SRCFILES)  pictest.a 
       +        push bowell $? /usr/src/cmd/pic
       +        touch bowell
       +
       +clean:
       +        rm *.o a.out *y.tab.h
       +
       +install:
       +        cp a.out /usr/bin/pic
       +        strip /usr/bin/pic
 (DIR) diff --git a/src/cmd/pic/misc.c b/src/cmd/pic/misc.c
       t@@ -0,0 +1,436 @@
       +#include <stdio.h>
       +#include <string.h>
       +#include <stdlib.h>
       +#include <math.h>
       +#include "pic.h"
       +#include "y.tab.h"
       +
       +int whatpos(obj *p, int corner, double *px, double *py);
       +void makeattr(int type, int sub, YYSTYPE val);
       +YYSTYPE getblk(obj *, char *);
       +
       +setdir(int n)        /* set direction (hvmode) from LEFT, RIGHT, etc. */
       +{
       +        switch (n) {
       +        case UP:        hvmode = U_DIR; break;
       +        case DOWN:        hvmode = D_DIR; break;
       +        case LEFT:        hvmode = L_DIR; break;
       +        case RIGHT:        hvmode = R_DIR; break;
       +        }
       +         return(hvmode);
       +}
       +
       +curdir(void)        /* convert current dir (hvmode) to RIGHT, LEFT, etc. */
       +{
       +        switch (hvmode) {
       +        case R_DIR:        return RIGHT;
       +        case L_DIR:        return LEFT;
       +        case U_DIR:        return UP;
       +        case D_DIR:        return DOWN;
       +        }
       +        ERROR "can't happen curdir" FATAL;
       +        return 0;
       +}
       +
       +double getcomp(obj *p, int t)        /* return component of a position */
       +{
       +        switch (t) {
       +        case DOTX:
       +                return p->o_x;
       +        case DOTY:
       +                return p->o_y;
       +        case DOTWID:
       +                switch (p->o_type) {
       +                case BOX:
       +                case BLOCK:
       +                case TEXT:
       +                        return p->o_val[0];
       +                case CIRCLE:
       +                case ELLIPSE:
       +                        return 2 * p->o_val[0];
       +                case LINE:
       +                case ARROW:
       +                        return p->o_val[0] - p->o_x;
       +                case PLACE:
       +                        return 0;
       +                }
       +        case DOTHT:
       +                switch (p->o_type) {
       +                case BOX:
       +                case BLOCK:
       +                case TEXT:
       +                        return p->o_val[1];
       +                case CIRCLE:
       +                case ELLIPSE:
       +                        return 2 * p->o_val[1];
       +                case LINE:
       +                case ARROW:
       +                        return p->o_val[1] - p->o_y;
       +                case PLACE:
       +                        return 0;
       +                }
       +        case DOTRAD:
       +                switch (p->o_type) {
       +                case CIRCLE:
       +                case ELLIPSE:
       +                        return p->o_val[0];
       +                }
       +        }
       +        ERROR "you asked for a weird dimension or position" WARNING;
       +        return 0;
       +}
       +
       +double        exprlist[100];
       +int        nexpr        = 0;
       +
       +void exprsave(double f)
       +{
       +        exprlist[nexpr++] = f;
       +}
       +
       +char *sprintgen(char *fmt)
       +{
       +        char buf[1000];
       +
       +        sprintf(buf, fmt, exprlist[0], exprlist[1], exprlist[2], exprlist[3], exprlist[4]);
       +        nexpr = 0;
       +        free(fmt);
       +        return tostring(buf);
       +}
       +
       +void makefattr(int type, int sub, double f)        /* double attr */
       +{
       +        YYSTYPE val;
       +        val.f = f;
       +        makeattr(type, sub, val);
       +}
       +
       +void makeoattr(int type, obj *o)        /* obj* attr */
       +{
       +        YYSTYPE val;
       +        val.o = o;
       +        makeattr(type, 0, val);
       +}
       +
       +void makeiattr(int type, int i)        /* int attr */
       +{
       +        YYSTYPE val;
       +        val.i = i;
       +        makeattr(type, 0, val);
       +}
       +
       +void maketattr(int sub, char *p)        /* text attribute: takes two */
       +{
       +        YYSTYPE val;
       +        val.p = p;
       +        makeattr(TEXTATTR, sub, val);
       +}
       +
       +void addtattr(int sub)                /* add text attrib to existing item */
       +{
       +        attr[nattr-1].a_sub |= sub;
       +}
       +
       +void makevattr(char *p)        /* varname attribute */
       +{
       +        YYSTYPE val;
       +        val.p = p;
       +        makeattr(VARNAME, 0, val);
       +}
       +
       +void makeattr(int type, int sub, YYSTYPE val)        /* add attribute type and val */
       +{
       +        if (type == 0 && val.i == 0) {        /* clear table for next stat */
       +                nattr = 0;
       +                return;
       +        }
       +        if (nattr >= nattrlist)
       +                attr = (Attr *) grow((char *)attr, "attr", nattrlist += 100, sizeof(Attr));
       +        dprintf("attr %d:  %d %d %d\n", nattr, type, sub, val.i);
       +        attr[nattr].a_type = type;
       +        attr[nattr].a_sub = sub;
       +        attr[nattr].a_val = val;
       +        nattr++;
       +}
       +
       +void printexpr(double f)        /* print expression for debugging */
       +{
       +        printf("%g\n", f);
       +}
       +
       +void printpos(obj *p)        /* print position for debugging */
       +{
       +        printf("%g, %g\n", p->o_x, p->o_y);
       +}
       +
       +char *tostring(char *s)
       +{
       +        register char *p;
       +
       +        p = malloc(strlen(s)+1);
       +        if (p == NULL)
       +                ERROR "out of space in tostring on %s", s FATAL;
       +        strcpy(p, s);
       +        return(p);
       +}
       +
       +obj *makepos(double x, double y)        /* make a position cell */
       +{
       +        obj *p;
       +
       +        p = makenode(PLACE, 0);
       +        p->o_x = x;
       +        p->o_y = y;
       +        return(p);
       +}
       +
       +obj *makebetween(double f, obj *p1, obj *p2)        /* make position between p1 and p2 */
       +{
       +        obj *p;
       +
       +        dprintf("fraction = %.2f\n", f);
       +        p = makenode(PLACE, 0);
       +        p->o_x = p1->o_x + f * (p2->o_x - p1->o_x);
       +        p->o_y = p1->o_y + f * (p2->o_y - p1->o_y);
       +        return(p);
       +}
       +
       +obj *getpos(obj *p, int corner)        /* find position of point */
       +{
       +        double x, y;
       +
       +        whatpos(p, corner, &x, &y);
       +        return makepos(x, y);
       +}
       +
       +int whatpos(obj *p, int corner, double *px, double *py)        /* what is the position (no side effect) */
       +{
       +        double x, y, x1, y1;
       +
       +        dprintf("whatpos %o %d %d\n", p, p->o_type, corner);
       +        x = p->o_x;
       +        y = p->o_y;
       +        if (p->o_type != PLACE && p->o_type != MOVE) {
       +                x1 = p->o_val[0];
       +                y1 = p->o_val[1];
       +        }
       +        switch (p->o_type) {
       +        case PLACE:
       +                break;
       +        case BOX:
       +        case BLOCK:
       +        case TEXT:
       +                switch (corner) {
       +                case NORTH:        y += y1 / 2; break;
       +                case SOUTH:        y -= y1 / 2; break;
       +                case EAST:        x += x1 / 2; break;
       +                case WEST:        x -= x1 / 2; break;
       +                case NE:        x += x1 / 2; y += y1 / 2; break;
       +                case SW:        x -= x1 / 2; y -= y1 / 2; break;
       +                case SE:        x += x1 / 2; y -= y1 / 2; break;
       +                case NW:        x -= x1 / 2; y += y1 / 2; break;
       +                case START:
       +                        if (p->o_type == BLOCK)
       +                                return whatpos(objlist[(int)p->o_val[2]], START, px, py);
       +                case END:
       +                        if (p->o_type == BLOCK)
       +                                return whatpos(objlist[(int)p->o_val[3]], END, px, py);
       +                }
       +                break;
       +        case ARC:
       +                switch (corner) {
       +                case START:
       +                        if (p->o_attr & CW_ARC) {
       +                                x = p->o_val[2]; y = p->o_val[3];
       +                        } else {
       +                                x = x1; y = y1;
       +                        }
       +                        break;
       +                case END:
       +                        if (p->o_attr & CW_ARC) {
       +                                x = x1; y = y1;
       +                        } else {
       +                                x = p->o_val[2]; y = p->o_val[3];
       +                        }
       +                        break;
       +                }
       +                if (corner == START || corner == END)
       +                        break;
       +                x1 = y1 = sqrt((x1-x)*(x1-x) + (y1-y)*(y1-y));
       +                /* Fall Through! */
       +        case CIRCLE:
       +        case ELLIPSE:
       +                switch (corner) {
       +                case NORTH:        y += y1; break;
       +                case SOUTH:        y -= y1; break;
       +                case EAST:        x += x1; break;
       +                case WEST:        x -= x1; break;
       +                case NE:        x += 0.707 * x1; y += 0.707 * y1; break;
       +                case SE:        x += 0.707 * x1; y -= 0.707 * y1; break;
       +                case NW:        x -= 0.707 * x1; y += 0.707 * y1; break;
       +                case SW:        x -= 0.707 * x1; y -= 0.707 * y1; break;
       +                }
       +                break;
       +        case LINE:
       +        case SPLINE:
       +        case ARROW:
       +                switch (corner) {
       +                case START:        break;        /* already in place */
       +                case END:        x = x1; y = y1; break;
       +                default: /* change! */
       +                case CENTER:        x = (x+x1)/2; y = (y+y1)/2; break;
       +                case NORTH:        if (y1 > y) { x = x1; y = y1; } break;
       +                case SOUTH:        if (y1 < y) { x = x1; y = y1; } break;
       +                case EAST:        if (x1 > x) { x = x1; y = y1; } break;
       +                case WEST:        if (x1 < x) { x = x1; y = y1; } break;
       +                }
       +                break;
       +        case MOVE:
       +                /* really ought to be same as line... */
       +                break;
       +        }
       +        dprintf("whatpos returns %g %g\n", x, y);
       +        *px = x;
       +        *py = y;
       +        return 1;
       +}
       +
       +obj *gethere(void)        /* make a place for curx,cury */
       +{
       +        dprintf("gethere %g %g\n", curx, cury);
       +        return(makepos(curx, cury));
       +}
       +
       +obj *getlast(int n, int t)        /* find n-th previous occurrence of type t */
       +{
       +        int i, k;
       +        obj *p;
       +
       +        k = n;
       +        for (i = nobj-1; i >= 0; i--) {
       +                p = objlist[i];
       +                if (p->o_type == BLOCKEND) {
       +                        i = p->o_val[4];
       +                        continue;
       +                }
       +                if (p->o_type != t)
       +                        continue;
       +                if (--k > 0)
       +                        continue;        /* not there yet */
       +                dprintf("got a last of x,y= %g,%g\n", p->o_x, p->o_y);
       +                return(p);
       +        }
       +        ERROR "there is no %dth last", n FATAL;
       +        return(NULL);
       +}
       +
       +obj *getfirst(int n, int t)        /* find n-th occurrence of type t */
       +{
       +        int i, k;
       +        obj *p;
       +
       +        k = n;
       +        for (i = 0; i < nobj; i++) {
       +                p = objlist[i];
       +                if (p->o_type == BLOCK && t != BLOCK) {        /* skip whole block */
       +                        i = p->o_val[5] + 1;
       +                        continue;
       +                }
       +                if (p->o_type != t)
       +                        continue;
       +                if (--k > 0)
       +                        continue;        /* not there yet */
       +                dprintf("got a first of x,y= %g,%g\n", p->o_x, p->o_y);
       +                return(p);
       +        }
       +        ERROR "there is no %dth ", n FATAL;
       +        return(NULL);
       +}
       +
       +double getblkvar(obj *p, char *s)        /* find variable s2 in block p */
       +{
       +        YYSTYPE y;
       +
       +        y = getblk(p, s);
       +        return y.f;
       +}
       +
       +obj *getblock(obj *p, char *s)        /* find variable s in block p */
       +{
       +        YYSTYPE y;
       +
       +        y = getblk(p, s);
       +        return y.o;
       +}
       +
       +YYSTYPE getblk(obj *p, char *s)        /* find union type for s in p */
       +{
       +        static YYSTYPE bug;
       +        struct symtab *stp;
       +
       +        if (p->o_type != BLOCK) {
       +                ERROR ".%s is not in that block", s WARNING;
       +                return(bug);
       +        }
       +        for (stp = p->o_symtab; stp != NULL; stp = stp->s_next)
       +                if (strcmp(s, stp->s_name) == 0) {
       +                        dprintf("getblk %s found x,y= %g,%g\n",
       +                                s, (stp->s_val.o)->o_x, (stp->s_val.o)->o_y);
       +                        return(stp->s_val);
       +                }
       +        ERROR "there is no .%s in that []", s WARNING;
       +        return(bug);
       +}
       +
       +obj *fixpos(obj *p, double x, double y)
       +{
       +        dprintf("fixpos returns %g %g\n", p->o_x + x, p->o_y + y);
       +        return makepos(p->o_x + x, p->o_y + y);
       +}
       +
       +obj *addpos(obj *p, obj *q)
       +{
       +        dprintf("addpos returns %g %g\n", p->o_x+q->o_x, p->o_y+q->o_y);
       +        return makepos(p->o_x+q->o_x, p->o_y+q->o_y);
       +}
       +
       +obj *subpos(obj *p, obj *q)
       +{
       +        dprintf("subpos returns %g %g\n", p->o_x-q->o_x, p->o_y-q->o_y);
       +        return makepos(p->o_x-q->o_x, p->o_y-q->o_y);
       +}
       +
       +obj *makenode(int type, int n)
       +{
       +        obj *p;
       +
       +        p = (obj *) calloc(1, sizeof(obj) + (n-1)*sizeof(ofloat));
       +        if (p == NULL)
       +                ERROR "out of space in makenode" FATAL;
       +        p->o_type = type;
       +        p->o_count = n;
       +        p->o_nobj = nobj;
       +        p->o_mode = hvmode;
       +        p->o_x = curx;
       +        p->o_y = cury;
       +        p->o_nt1 = ntext1;
       +        p->o_nt2 = ntext;
       +        ntext1 = ntext;        /* ready for next caller */
       +        if (nobj >= nobjlist)
       +                objlist = (obj **) grow((char *) objlist, "objlist",
       +                        nobjlist *= 2, sizeof(obj *));
       +        objlist[nobj++] = p;
       +        return(p);
       +}
       +
       +void extreme(double x, double y)        /* record max and min x and y values */
       +{
       +        if (x > xmax)
       +                xmax = x;
       +        if (y > ymax)
       +                ymax = y;
       +        if (x < xmin)
       +                xmin = x;
       +        if (y < ymin)
       +                ymin = y;
       +}
 (DIR) diff --git a/src/cmd/pic/mkfile b/src/cmd/pic/mkfile
       t@@ -0,0 +1,38 @@
       +<$PLAN9/src/mkhdr
       +
       +TARG=pic
       +OFILES=picy.$O\
       +        picl.$O\
       +        main.$O\
       +        print.$O\
       +        misc.$O\
       +        symtab.$O\
       +        blockgen.$O\
       +        boxgen.$O\
       +        circgen.$O\
       +        arcgen.$O\
       +        linegen.$O\
       +        movegen.$O\
       +        textgen.$O\
       +        input.$O\
       +        for.$O\
       +        pltroff.$O\
       +
       +HFILES=pic.h\
       +        y.tab.h\
       +
       +YFILES=picy.y\
       +
       +SHORTLIB=bio 9
       +<$PLAN9/src/mkone
       +YFLAGS=-S -d
       +LEX=9lex
       +
       +picy.c:        y.tab.c
       +        mv $prereq $target
       +
       +picl.c:        picl.lx
       +        $LEX -t $prereq > $target
       +
       +clean:V:
       +        rm -f *.[$OS] [$OS].out y.tab.? y.debug $TARG picy.c picl.c
 (DIR) diff --git a/src/cmd/pic/movegen.c b/src/cmd/pic/movegen.c
       t@@ -0,0 +1,86 @@
       +#include        <stdio.h>
       +#include        "pic.h"
       +#include        "y.tab.h"
       +
       +obj *movegen(void)
       +{
       +        static double prevdx, prevdy;
       +        int i, some;
       +        double defx, defy, dx, dy;
       +        obj *p;
       +        obj *ppos;
       +        static int xtab[] = { 1, 0, -1, 0 };        /* R=0, U=1, L=2, D=3 */
       +        static int ytab[] = { 0, 1, 0, -1 };
       +        Attr *ap;
       +
       +        defx = getfval("movewid");
       +        defy = getfval("moveht");
       +        dx = dy = some = 0;
       +        for (i = 0; i < nattr; i++) {
       +                ap = &attr[i];
       +                switch (ap->a_type) {
       +                case TEXTATTR:
       +                        savetext(ap->a_sub, ap->a_val.p);
       +                        break;
       +                case SAME:
       +                        dx = prevdx;
       +                        dy = prevdy;
       +                        some++;
       +                        break;
       +                case LEFT:
       +                        dx -= (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
       +                        some++;
       +                        hvmode = L_DIR;
       +                        break;
       +                case RIGHT:
       +                        dx += (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
       +                        some++;
       +                        hvmode = R_DIR;
       +                        break;
       +                case UP:
       +                        dy += (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
       +                        some++;
       +                        hvmode = U_DIR;
       +                        break;
       +                case DOWN:
       +                        dy -= (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
       +                        some++;
       +                        hvmode = D_DIR;
       +                        break;
       +                case TO:
       +                        ppos = ap->a_val.o;
       +                        dx = ppos->o_x - curx;
       +                        dy = ppos->o_y - cury;
       +                        some++;
       +                        break;
       +                case BY:
       +                        ppos = ap->a_val.o;
       +                        dx = ppos->o_x;
       +                        dy = ppos->o_y;
       +                        some++;
       +                        break;
       +                case FROM:
       +                case AT:
       +                        ppos = ap->a_val.o;
       +                        curx = ppos->o_x;
       +                        cury = ppos->o_y;
       +                        break;
       +                }
       +        }
       +        if (some) {
       +                defx = dx;
       +                defy = dy;
       +        } else {
       +                defx *= xtab[hvmode];
       +                defy *= ytab[hvmode];
       +        }
       +        prevdx = defx;
       +        prevdy = defy;
       +        extreme(curx, cury);
       +        curx += defx;
       +        cury += defy;
       +        extreme(curx, cury);
       +        p = makenode(MOVE, 0);
       +        dprintf("M %g %g\n", curx, cury);
       +        return(p);
       +}
 (DIR) diff --git a/src/cmd/pic/pic.h b/src/cmd/pic/pic.h
       t@@ -0,0 +1,219 @@
       +#ifndef PI
       +#define PI 3.1415926535897932384626433832795028841971693993751
       +#endif
       +
       +#define        MAXWID        8.5        /* default limits max picture to 8.5 x 11; */
       +#define        MAXHT        11        /* change to taste without peril */
       +
       +#define        dprintf        if(dbg)printf
       +
       +extern        void        yyerror(char *);
       +
       +extern        char        errbuf[200];
       +#define        ERROR        sprintf(errbuf,
       +#define        FATAL        ), yyerror(errbuf), exit(1)
       +#define        WARNING        ), yyerror(errbuf)
       +
       +#define        DEFAULT        0
       +
       +#define        HEAD1        1
       +#define        HEAD2        2
       +#define        HEAD12        (HEAD1+HEAD2)
       +#define        INVIS        4
       +#define        CW_ARC        8        /* clockwise arc */
       +#define        DOTBIT        16        /* line styles */
       +#define        DASHBIT        32
       +#define        FILLBIT        64        /* gray-fill on boxes, etc. */
       +#define NOEDGEBIT 128        /* no edge on filled object */
       +
       +#define        CENTER        01        /* text attributes */
       +#define        LJUST        02
       +#define        RJUST        04
       +#define        ABOVE        010
       +#define        BELOW        020
       +#define        SPREAD        040
       +
       +#define        SCALE        1.0        /* default scale: units/inch */
       +#define        WID        0.75        /* default width for boxes and ellipses */
       +#define        WID2        0.375
       +#define        HT        0.5        /* default height and line length */
       +#define        HT2        (HT/2)
       +#define        HT5        (HT/5)
       +#define        HT10        (HT/10)
       +
       +/* these have to be like so, so that we can write */
       +/* things like R & V, etc. */
       +#define        H        0
       +#define        V        1
       +#define        R_DIR        0
       +#define        U_DIR        1
       +#define        L_DIR        2
       +#define        D_DIR        3
       +#define        ishor(n)        (((n) & V) == 0)
       +#define        isvert(n)        (((n) & V) != 0)
       +#define        isright(n)        ((n) == R_DIR)
       +#define        isleft(n)        ((n) == L_DIR)
       +#define        isdown(n)        ((n) == D_DIR)
       +#define        isup(n)                ((n) == U_DIR)
       +
       +typedef        float        ofloat;        /* for o_val[] in obj;  could be double */
       +
       +typedef struct obj {        /* stores various things in variable length */
       +        int        o_type;
       +        int        o_count;        /* number of things */
       +        int        o_nobj;                /* index in objlist */
       +        int        o_mode;                /* hor or vert */
       +        float        o_x;                /* coord of "center" */
       +        float        o_y;
       +        int        o_nt1;                /* 1st index in text[] for this object */
       +        int        o_nt2;                /* 2nd; difference is #text strings */
       +        int        o_attr;                /* HEAD, CW, INVIS, etc., go here */
       +        int        o_size;                /* linesize */
       +        int        o_nhead;        /* arrowhead style */
       +        struct symtab *o_symtab; /* symtab for [...] */
       +        float        o_ddval;        /* value of dot/dash expression */
       +        float        o_fillval;        /* gray scale value */
       +        ofloat        o_val[1];        /* actually this will be > 1 in general */
       +                                /* type is not always FLOAT!!!! */
       +} obj;
       +
       +typedef union {                /* the yacc stack type */
       +        int        i;
       +        char        *p;
       +        obj        *o;
       +        double        f;
       +        struct symtab *st;
       +} YYSTYPE;
       +
       +extern        YYSTYPE        yylval, yyval;
       +
       +struct symtab {
       +        char        *s_name;
       +        int        s_type;
       +        YYSTYPE        s_val;
       +        struct symtab *s_next;
       +};
       +
       +typedef struct {        /* attribute of an object */
       +        int        a_type;
       +        int        a_sub;
       +        YYSTYPE        a_val;
       +} Attr;
       +
       +typedef struct {
       +        int        t_type;                /* CENTER, LJUST, etc. */
       +        char        t_op;                /* optional sign for size changes */
       +        char        t_size;                /* size, abs or rel */
       +        char        *t_val;
       +} Text;
       +
       +#define        String        01
       +#define        Macro        02
       +#define        File        04
       +#define        Char        010
       +#define        Thru        020
       +#define        Free        040
       +
       +typedef struct {        /* input source */
       +        int        type;        /* Macro, String, File */
       +        char        *sp;        /* if String or Macro */
       +} Src;
       +
       +extern        Src        src[], *srcp;        /* input source stack */
       +
       +typedef struct {
       +        FILE        *fin;
       +        char        *fname;
       +        int        lineno;
       +} Infile;
       +
       +extern        Infile        infile[], *curfile;
       +
       +#define        MAXARGS        20
       +typedef struct {        /* argument stack */
       +        char        *argstk[MAXARGS];        /* pointers to args */
       +        char        *argval;        /* points to space containing args */
       +} Arg;
       +
       +extern        int        dbg;
       +extern        obj        **objlist;
       +extern        int        nobj, nobjlist;
       +extern        Attr        *attr;
       +extern        int        nattr, nattrlist;
       +extern        Text        *text;
       +extern        int        ntextlist;
       +extern        int        ntext;
       +extern        int        ntext1;
       +extern        double        curx, cury;
       +extern        int        hvmode;
       +extern        int        codegen;
       +extern        char        *PEstring;
       +
       +char        *tostring(char *);
       +char        *grow(char *, char *, int, int);
       +double        getfval(char *), getcomp(obj *, int), getblkvar(obj *, char *);
       +YYSTYPE        getvar(char *);
       +struct        symtab *lookup(char *), *makevar(char *, int, YYSTYPE);
       +char        *ifstat(double, char *, char *), *delimstr(char *), *sprintgen(char *);
       +void        forloop(char *var, double from, double to, int op, double by, char *_str);
       +int        setdir(int), curdir(void);
       +void        resetvar(void);
       +void        checkscale(char *);
       +void        pushsrc(int, char *);
       +void        copy(void);
       +void        copyuntil(char *);
       +void        copyfile(char *);
       +void        copydef(struct symtab *);
       +void        definition(char *);
       +struct symtab *copythru(char *);
       +int        input(void);
       +int        unput(int);
       +void        extreme(double, double);
       +
       +extern        double        deltx, delty;
       +extern        int        lineno;
       +extern        int        synerr;
       +
       +extern        double        xmin, ymin, xmax, ymax;
       +
       +obj        *leftthing(int), *boxgen(void), *circgen(int), *arcgen(int);
       +obj        *linegen(int), *splinegen(void), *movegen(void);
       +obj        *textgen(void), *plotgen(void);
       +obj        *troffgen(char *), *rightthing(obj *, int), *blockgen(obj *, obj *);
       +obj        *makenode(int, int), *makepos(double, double);
       +obj        *fixpos(obj *, double, double);
       +obj        *addpos(obj *, obj *), *subpos(obj *, obj *);
       +obj        *makebetween(double, obj *, obj *);
       +obj        *getpos(obj *, int), *gethere(void), *getfirst(int, int);
       +obj        *getlast(int, int), *getblock(obj *, char *);
       +void        savetext(int, char *);
       +void        makeiattr(int, int);
       +void        makevattr(char *);
       +void        makefattr(int type, int sub, double f);
       +void        maketattr(int, char *);
       +void        makeoattr(int, obj *);
       +void        makeattr(int type, int sub, YYSTYPE val);
       +void        printexpr(double);
       +void        printpos(obj *);
       +void        exprsave(double);
       +void        addtattr(int);
       +void        printlf(int, char *);
       +
       +struct pushstack {
       +        double        p_x;
       +        double        p_y;
       +        int        p_hvmode;
       +        double        p_xmin;
       +        double        p_ymin;
       +        double        p_xmax;
       +        double        p_ymax;
       +        struct symtab *p_symtab;
       +};
       +extern        struct pushstack stack[];
       +extern        int        nstack;
       +extern        int        cw;
       +
       +extern        double        errcheck(double, char *);
       +#define        Log10(x) errcheck(log10(x), "log")
       +#define        Exp(x)        errcheck(exp(x), "exp")
       +#define        Sqrt(x)        errcheck(sqrt(x), "sqrt")
 (DIR) diff --git a/src/cmd/pic/picl.lx b/src/cmd/pic/picl.lx
       t@@ -0,0 +1,273 @@
       +%Start A str def sc br thru sh
       +%e 1700
       +%k 120
       +%a 1800
       +%o 1500
       +%p 5000
       +%n 700
       +
       +%{
       +#undef        input
       +#undef        unput
       +/* #include <stdio.h> lex puts one out for us */
       +#include <ctype.h>
       +#include <stdlib.h>
       +#include "pic.h"
       +#include "y.tab.h"
       +
       +extern        char        *filename;
       +extern        struct        symtab        symtab[];
       +
       +void        pbstr(char *);
       +void        dodef(struct symtab *stp);
       +void        undefine(char *s);
       +void        shell_init(void), shell_exec(void), shell_text(char *);
       +void        endfor(void);
       +
       +int        yyback(int *, int);
       +int        yylook(void);
       +int        yywrap(void);
       +
       +#define        CADD        cbuf[clen++]=yytext[0]; \
       +                if (clen>=CBUFLEN-1) { ERROR "string too long", cbuf WARNING; BEGIN A; }
       +#define        CBUFLEN        500
       +char        cbuf[CBUFLEN];
       +int        c, clen, cflag, delim;
       +int        ifsw        = 0;        /* 1 if if statement in progress */
       +%}
       +
       +A        [a-zA-Z_]
       +B        [a-zA-Z0-9_]
       +D        [0-9]
       +WS        [ \t]
       +
       +%%
       +        switch (yybgin-yysvec-1) {        /* witchcraft */
       +        case 0:
       +                BEGIN A;
       +                break;
       +        case sc:
       +                BEGIN A;
       +                return('}');
       +        case br:
       +                BEGIN A;
       +                return(']');
       +        }
       +
       +<A>{WS}                ;
       +<A>"\\"\n        ;
       +<A>\n                { return(ST); }
       +<A>";"                { return(ST); }
       +<A>"}"                { BEGIN sc; return(ST); }
       +<A>"]"                { BEGIN br; return(ST); }
       +<A>"{"{WS}*(#.*)?\n+        { return(yylval.i = yytext[0]); }
       +
       +<A>^".PS".*        { if (curfile == infile) ERROR ".PS found inside .PS/.PE" WARNING; }
       +<A>^".PE".*        { if (curfile == infile) {
       +                        yylval.p = PEstring = tostring(yytext);
       +                        return(EOF);
       +                  }
       +                }
       +<A>^".".*        { yylval.p = tostring(yytext); return(TROFF); }
       +
       +<A>print        return(yylval.i = PRINT);
       +<A>box                return(yylval.i = BOX);
       +<A>circle        return(yylval.i = CIRCLE);
       +<A>arc                return(yylval.i = ARC);
       +<A>ellipse        return(yylval.i = ELLIPSE);
       +<A>arrow        return(yylval.i = ARROW);
       +<A>spline        return(yylval.i = SPLINE);
       +<A>line                return(yylval.i = LINE);
       +<A>move                return(yylval.i = MOVE);
       +<A>"[]"                return(yylval.i = BLOCK);
       +<A>reset        return(RESET);
       +<A>sprintf        return(SPRINTF);
       +
       +<A>same                return(SAME);
       +<A>between        return(BETWEEN);
       +<A>and                return(AND);
       +
       +<A>of                ;
       +<A>the                ;
       +<A>way                ;
       +
       +<A>"."(e|east)                { yylval.i = EAST; return(CORNER); }
       +<A>"."(r|right)                { yylval.i = EAST; return(CORNER); }
       +<A>"."(w|west)                { yylval.i = WEST; return(CORNER); }
       +<A>"."(l|left)                { yylval.i = WEST; return(CORNER); }
       +<A>"."(n|north)                { yylval.i = NORTH; return(CORNER); }
       +<A>"."(t|top)                { yylval.i = NORTH; return(CORNER); }
       +<A>"."(s|south)                { yylval.i = SOUTH; return(CORNER); }
       +<A>"."(b|bot|bottom)        { yylval.i = SOUTH; return(CORNER); }
       +<A>"."(c|center)        { yylval.i = CENTER; return(CORNER); }
       +<A>".start"                { yylval.i = START; return(CORNER); }
       +<A>".end"                { yylval.i = END; return(CORNER); }
       +<A>".ne"                { yylval.i = NE; return(CORNER); }
       +<A>".se"                { yylval.i = SE; return(CORNER); }
       +<A>".nw"                { yylval.i = NW; return(CORNER); }
       +<A>".sw"                { yylval.i = SW; return(CORNER); }
       +
       +<A>top" "+of                { yylval.i = NORTH; return(CORNER); }
       +<A>north" "+of                { yylval.i = NORTH; return(CORNER); }
       +<A>bottom" "+of                { yylval.i = SOUTH; return(CORNER); }
       +<A>south" "+of                { yylval.i = SOUTH; return(CORNER); }
       +<A>left" "+of                { yylval.i = WEST; return(CORNER); }
       +<A>west" "+of                { yylval.i = WEST; return(CORNER); }
       +<A>right" "+of                { yylval.i = EAST; return(CORNER); }
       +<A>east" "+of                { yylval.i = EAST; return(CORNER); }
       +<A>center" "+of                { yylval.i = CENTER; return(CORNER); }
       +<A>start" "+of                { yylval.i = START; return(CORNER); }
       +<A>end" "+of                { yylval.i = END; return(CORNER); }
       +
       +<A>height|ht        { yylval.i = HEIGHT; return(ATTR); }
       +<A>width|wid        { yylval.i = WIDTH; return(ATTR); }
       +<A>radius|rad        { yylval.i = RADIUS; return(ATTR); }
       +<A>diameter|diam { yylval.i = DIAMETER; return(ATTR); }
       +<A>size                { yylval.i = SIZE; return(ATTR); }
       +<A>left                { yylval.i = LEFT; return(DIR); }
       +<A>right        { yylval.i = RIGHT; return(DIR); }
       +<A>up                { yylval.i = UP; return(DIR); }
       +<A>down                { yylval.i = DOWN; return(DIR); }
       +<A>cw                { yylval.i = CW; return(ATTR); }
       +<A>clockwise        { yylval.i = CW; return(ATTR); }
       +<A>ccw                { yylval.i = CCW; return(ATTR); }
       +<A>invis(ible)?        { yylval.i = INVIS; return(ATTR); }
       +<A>noedge        { yylval.i = INVIS; return ATTR; }
       +<A>fill                return(yylval.i = FILL);
       +<A>solid        ;
       +<A>dot(ted)?        return(yylval.i = DOT);
       +<A>dash(ed)?        return(yylval.i = DASH);
       +<A>chop                return(yylval.i = CHOP);
       +
       +<A>spread        { yylval.i = SPREAD; return TEXTATTR; }
       +<A>ljust        { yylval.i = LJUST; return TEXTATTR; }
       +<A>rjust        { yylval.i = RJUST; return TEXTATTR; }
       +<A>above        { yylval.i = ABOVE; return TEXTATTR; }
       +<A>below        { yylval.i = BELOW; return TEXTATTR; }
       +<A>center        { yylval.i = CENTER; return TEXTATTR; }
       +
       +<A>"<-"                { yylval.i = HEAD1; return(HEAD); }
       +<A>"->"                { yylval.i = HEAD2; return(HEAD); }
       +<A>"<->"        { yylval.i = HEAD12; return(HEAD); }
       +
       +<A>".x"                        return(yylval.i = DOTX);
       +<A>".y"                        return(yylval.i = DOTY);
       +<A>"."(ht|height)        return(yylval.i = DOTHT);
       +<A>"."(wid|width)        return(yylval.i = DOTWID);
       +<A>"."(rad|radius)        return(yylval.i = DOTRAD);
       +
       +<A>from                return(yylval.i = FROM);
       +<A>to                return(yylval.i = TO);
       +<A>at                return(yylval.i = AT);
       +<A>by                return(yylval.i = BY);
       +<A>with                return(yylval.i = WITH);
       +<A>last                return(yylval.i = LAST);
       +
       +<A>log                return(LOG);
       +<A>exp                return(EXP);
       +<A>sin                return(SIN);
       +<A>cos                return(COS);
       +<A>atan2        return(ATAN2);
       +<A>sqrt                return(SQRT);
       +<A>rand                return(RAND);
       +<A>max                return(MAX);
       +<A>min                return(MIN);
       +<A>int                return(INT);
       +
       +<A>"=="                return(EQ);
       +<A>">="                return(GE);
       +<A>"<="                return(LE);
       +<A>"!="                return(NEQ);
       +<A>">"                return(GT);
       +<A>"<"                return(LT);
       +<A>"&&"                return(ANDAND);
       +<A>"||"                return(OROR);
       +<A>"!"                return(NOT);        
       +
       +<A>Here                return(yylval.i = HERE);
       +
       +<A>for                return(FOR);
       +<A>^Endfor\n        { endfor(); }
       +<A>do                { yylval.p = delimstr("loop body"); return(DOSTR); }
       +
       +<A>copy|include                return(COPY);
       +<A>(thru|through){WS}+        { BEGIN thru; return(THRU); }
       +<thru>{A}{B}*|.                { yylval.st = copythru(yytext); BEGIN A; return(DEFNAME); }
       +<A>until                return(UNTIL);
       +
       +<A>if                { ifsw = 1; return(IF); }
       +<A>then                { if (!ifsw) { yylval.i = THEN; return(ATTR); }
       +                  yylval.p = delimstr("then part"); ifsw = 0;
       +                  return(THENSTR); }
       +<A>else                { yylval.p = delimstr("else part"); return(ELSESTR); }
       +
       +<A>sh{WS}+        { BEGIN sh;
       +                  if ((delim = input()) == '{') delim = '}';        /* no nested {} */
       +                  shell_init(); }
       +<sh>{A}{B}*        { struct symtab *p;
       +                  if (yytext[0] == delim) {
       +                        shell_exec();
       +                        BEGIN A;
       +                  } else {
       +                        p = lookup(yytext);
       +                        if (p != NULL && p->s_type == DEFNAME) {
       +                                c = input();
       +                                unput(c);
       +                                if (c == '(')
       +                                        dodef(p);
       +                                else
       +                                        pbstr(p->s_val.p);
       +                        } else
       +                                shell_text(yytext);
       +                  }
       +                }
       +<sh>.|\n        { if (yytext[0] == delim) {
       +                        shell_exec();
       +                        BEGIN A;
       +                  } else
       +                        shell_text(yytext);
       +                }
       +
       +<A>define{WS}+                { BEGIN def; }
       +<def>{A}{B}*                { definition(yytext); BEGIN A; }
       +<A>undef(ine)?{WS}+{A}{B}*        { undefine(yytext); }
       +
       +<A>first                { yylval.i = 1; return(NTH); }
       +<A>{D}+(th|nd|rd|st)        { yylval.i = atoi(yytext); return(NTH); }
       +<A>({D}+("."?){D}*|"."{D}+)((e|E)("+"|-)?{D}+)?i? {
       +                          yylval.f = atof(yytext); return(NUMBER); }
       +
       +<A>{A}{B}* {        struct symtab *p;
       +                p = lookup(yytext);
       +                if (p != NULL && p->s_type == DEFNAME) {
       +                        c = input();
       +                        unput(c);
       +                        if (c == '(')        /* it's name(...) */
       +                                dodef(p);
       +                        else {        /* no argument list */
       +                                pbstr(p->s_val.p);
       +                                dprintf("pushing back `%s'\n", p->s_val.p);
       +                        }
       +                } else if (islower(yytext[0])) {
       +                        yylval.p = tostring(yytext);
       +                        return(VARNAME);
       +                } else {
       +                        yylval.p = tostring(yytext);
       +                        return(PLACENAME);
       +                }
       +        }
       +
       +<A>\"                { BEGIN str; clen=0; }
       +<str>\"                { cbuf[clen]=0; yylval.p = tostring(cbuf); BEGIN A; return(TEXT); }
       +<str>\n                { cbuf[clen]=0; ERROR "missing quote in string \"%s\"", cbuf WARNING;
       +                                BEGIN A; return(ST); }
       +<str>"\\\""        { cbuf[clen++]='"'; }
       +<str>"\\"t        { cbuf[clen++]='\t'; }
       +<str>"\\\\"        { cbuf[clen++]='\\'; }
       +<str>.                { CADD; }
       +
       +<A>#.*                ;
       +
       +<A>.                return(yylval.i = yytext[0]);
       +
       +%%
 (DIR) diff --git a/src/cmd/pic/picy.y b/src/cmd/pic/picy.y
       t@@ -0,0 +1,328 @@
       +%{
       +#include <stdio.h>
       +#include "pic.h"
       +#include <math.h>
       +#include <stdlib.h>
       +#include <string.h>
       +
       +YYSTYPE        y;
       +
       +extern        void        yyerror(char *);
       +extern        int        yylex(void);
       +%}
       +
       +%token        <i>        BOX        1        /* DON'T CHANGE THESE! */
       +%token        <i>        LINE        2
       +%token        <i>        ARROW        3
       +%token        <i>        CIRCLE        4
       +%token        <i>        ELLIPSE        5
       +%token        <i>        ARC        6
       +%token        <i>        SPLINE        7
       +%token        <i>        BLOCK        8
       +%token        <p>        TEXT        9
       +%token        <p>        TROFF        10
       +%token        <i>        MOVE        11
       +%token        <i>        BLOCKEND 12
       +%token        <i>        PLACE        13
       +%token        <i>        PRINT RESET THRU UNTIL
       +%token        <o>        FOR IF COPY
       +%token        <p>        THENSTR ELSESTR DOSTR PLACENAME VARNAME SPRINTF
       +%token        <st>        DEFNAME
       +%token        <i>        ATTR TEXTATTR
       +%token        <i>        LEFT RIGHT UP DOWN FROM TO AT BY WITH HEAD CW CCW THEN
       +%token        <i>        HEIGHT WIDTH RADIUS DIAMETER LENGTH SIZE
       +%token        <i>        CORNER HERE LAST NTH SAME BETWEEN AND
       +%token        <i>        EAST WEST NORTH SOUTH NE NW SE SW START END
       +%token        <i>        DOTX DOTY DOTHT DOTWID DOTRAD
       +%token        <f>        NUMBER
       +%token        <f>        LOG EXP SIN COS ATAN2 SQRT RAND MIN MAX INT
       +%token        <i>        DIR
       +%token        <i>        DOT DASH CHOP FILL NOEDGE
       +%token        <o>        ST        /* statement terminator */
       +
       +%right        <f>        '='
       +%left        <f>        OROR
       +%left        <f>        ANDAND
       +%nonassoc <f>        GT LT LE GE EQ NEQ
       +%left        <f>        '+' '-'
       +%left        <f>        '*' '/' '%'
       +%right        <f>        UMINUS NOT
       +%right        <f>        '^'
       +
       +%type        <f>        expr if_expr asgn
       +%type        <p>        name text
       +%type        <i>        optop exprlist
       +%type        <o>        if for copy
       +
       +/* this is a lie:  picture and position are really the whole union */
       +%type        <o>        leftbrace picture piclist position lbracket
       +%type        <o>        prim place blockname
       +%type        <i>        textlist textattr        /* not a sensible value */
       +%type        <i>        last type
       +
       +%%
       +
       +top:
       +          piclist
       +        | /* empty */
       +        | error                { ERROR "syntax error" WARNING; }
       +        ;
       +
       +piclist:
       +          picture
       +        | piclist picture
       +        ;
       +
       +picture:
       +          prim ST                        { codegen = 1; makeiattr(0, 0); }
       +        | leftbrace piclist '}'                { rightthing($1, '}'); $$ = $2; }
       +        | PLACENAME ':' picture                { y.o=$3; makevar($1,PLACENAME,y); $$ = $3; }
       +        | PLACENAME ':' ST picture        { y.o=$4; makevar($1,PLACENAME,y); $$ = $4; }
       +        | PLACENAME ':' position ST        { y.o=$3; makevar($1,PLACENAME,y); $$ = $3; }
       +        | asgn ST                        { y.f = $1; $$ = y.o; $$ = makenode(PLACE, 0); }
       +        | DIR                                { setdir($1); $$ = makenode(PLACE, 0); }
       +        | PRINT expr ST                        { printexpr($2); $$ = makenode(PLACE, 0); }
       +        | PRINT position ST                { printpos($2); $$ = makenode(PLACE, 0); }
       +        | PRINT text ST                        { printf("%s\n", $2); free($2); $$ = makenode(PLACE, 0); }
       +        | RESET varlist ST                { resetvar(); makeiattr(0, 0); $$ = makenode(PLACE, 0); }
       +        | copy
       +        | for
       +        | if
       +        | ST
       +        ;
       +
       +varlist:
       +          /* empty */
       +        | VARNAME                { makevattr($1); }
       +        | varlist VARNAME        { makevattr($2); }
       +        | varlist ',' VARNAME        { makevattr($3); }
       +        ;
       +
       +asgn:
       +          VARNAME '=' expr        { $$=y.f=$3; makevar($1,VARNAME,y); checkscale($1); }
       +        ;
       +
       +copy:
       +          COPY copylist                { copy(); }
       +        ;
       +copylist:
       +          copyattr
       +        | copylist copyattr
       +        ;
       +copyattr:
       +          text                        { copyfile($1); }
       +        | THRU DEFNAME                { copydef($2); }
       +        | UNTIL text                { copyuntil($2); }
       +        ;
       +
       +for:
       +          FOR name FROM expr TO expr BY optop expr DOSTR
       +                { forloop($2, $4, $6, $8, $9, $10); }
       +        | FOR name FROM expr TO expr DOSTR
       +                { forloop($2, $4, $6, '+', 1.0, $7); }
       +        | FOR name '=' expr TO expr BY optop expr DOSTR
       +                { forloop($2, $4, $6, $8, $9, $10); }
       +        | FOR name '=' expr TO expr DOSTR
       +                { forloop($2, $4, $6, '+', 1.0, $7); }
       +        ;
       +
       +if:
       +          IF if_expr THENSTR ELSESTR        { ifstat($2, $3, $4); }
       +        | IF if_expr THENSTR                { ifstat($2, $3, (char *) 0); }
       +        ;
       +if_expr:
       +          expr
       +        | text EQ text                { $$ = strcmp($1,$3) == 0; free($1); free($3); }
       +        | text NEQ text                { $$ = strcmp($1,$3) != 0; free($1); free($3); }
       +        ;
       +
       +name:
       +          VARNAME        { y.f = 0; makevar($1, VARNAME, y); }
       +        ;
       +optop:
       +          '+'                { $$ = '+'; }
       +        | '-'                { $$ = '-'; }
       +        | '*'                { $$ = '*'; }
       +        | '/'                { $$ = '/'; }
       +        | /* empty */        { $$ = ' '; }
       +        ;
       +
       +
       +leftbrace:
       +          '{'                        { $$ = leftthing('{'); }
       +        ;
       +
       +prim:
       +          BOX attrlist                { $$ = boxgen(); }
       +        | CIRCLE attrlist        { $$ = circgen($1); }
       +        | ELLIPSE attrlist        { $$ = circgen($1); }
       +        | ARC attrlist                { $$ = arcgen($1); }
       +        | LINE attrlist                { $$ = linegen($1); }
       +        | ARROW attrlist        { $$ = linegen($1); }
       +        | SPLINE attrlist        { $$ = linegen($1); }
       +        | MOVE attrlist                { $$ = movegen(); }
       +        | textlist attrlist        { $$ = textgen(); }
       +        | TROFF                        { $$ = troffgen($1); }
       +        | lbracket piclist ']' { $<o>$=rightthing($1,']'); } attrlist
       +                                { $$ = blockgen($1, $<o>4); }
       +        ;
       +
       +lbracket:
       +          '['                        { $$ = leftthing('['); }
       +        ;
       +
       +attrlist:
       +          attrlist attr
       +        | /* empty */
       +        ;
       +
       +attr:
       +          ATTR expr                { makefattr($1, !DEFAULT, $2); }
       +        | ATTR                        { makefattr($1, DEFAULT, 0.0); }
       +        | expr                        { makefattr(curdir(), !DEFAULT, $1); }
       +        | DIR expr                { makefattr($1, !DEFAULT, $2); }
       +        | DIR                        { makefattr($1, DEFAULT, 0.0); }
       +        | FROM position                { makeoattr($1, $2); }
       +        | TO position                { makeoattr($1, $2); }
       +        | AT position                { makeoattr($1, $2); }
       +        | BY position                { makeoattr($1, $2); }
       +        | WITH CORNER                { makeiattr(WITH, $2); }
       +        | WITH '.' PLACENAME        { makeoattr(PLACE, getblock(getlast(1,BLOCK), $3)); }
       +        | WITH '.' PLACENAME CORNER
       +                { makeoattr(PLACE, getpos(getblock(getlast(1,BLOCK), $3), $4)); }
       +        | WITH position                { makeoattr(PLACE, $2); }
       +        | SAME                        { makeiattr(SAME, $1); }
       +        | TEXTATTR                { maketattr($1, (char *) 0); }
       +        | HEAD                        { makeiattr(HEAD, $1); }
       +        | DOT expr                { makefattr(DOT, !DEFAULT, $2); }
       +        | DOT                        { makefattr(DOT, DEFAULT, 0.0); }
       +        | DASH expr                { makefattr(DASH, !DEFAULT, $2); }
       +        | DASH                        { makefattr(DASH, DEFAULT, 0.0); }
       +        | CHOP expr                { makefattr(CHOP, !DEFAULT, $2); }
       +        | CHOP                        { makefattr(CHOP, DEFAULT, 0.0); }
       +        | CHOP PLACENAME        { makeattr(CHOP, PLACENAME, getvar($2)); }
       +        | FILL expr                { makefattr(FILL, !DEFAULT, $2); }
       +        | FILL                        { makefattr(FILL, DEFAULT, 0.0); }
       +        | NOEDGE                { makeiattr(NOEDGE, 0); }
       +        | textlist
       +        ;
       +
       +textlist:
       +          textattr
       +        | textlist textattr
       +        ;
       +textattr:
       +          text                        { maketattr(CENTER, $1); }
       +        | text TEXTATTR                { maketattr($2, $1); }
       +        | textattr TEXTATTR        { addtattr($2); }
       +        ;
       +text:
       +          TEXT
       +        | SPRINTF '(' text ')'                        { $$ = sprintgen($3); }
       +        | SPRINTF '(' text ',' exprlist ')'        { $$ = sprintgen($3); }
       +        ;
       +
       +exprlist:
       +          expr                        { exprsave($1); $$ = 0; }
       +        | exprlist ',' expr        { exprsave($3); }
       +        ;
       +
       +position:                /* absolute, not relative */
       +          place
       +        | '(' position ')'                        { $$ = $2; }
       +        | expr ',' expr                                { $$ = makepos($1, $3); }
       +        | position '+' expr ',' expr                { $$ = fixpos($1, $3, $5); }
       +        | position '-' expr ',' expr                { $$ = fixpos($1, -$3, -$5); }
       +        | position '+' '(' expr ',' expr ')'        { $$ = fixpos($1, $4, $6); }
       +        | position '-' '(' expr ',' expr ')'        { $$ = fixpos($1, -$4, -$6); }
       +        | position '+' place                        { $$ = addpos($1, $3); }
       +        | position '-' place                        { $$ = subpos($1, $3); }
       +        | '(' place ',' place ')'        { $$ = makepos(getcomp($2,DOTX), getcomp($4,DOTY)); }
       +        | expr LT position ',' position GT        { $$ = makebetween($1, $3, $5); }
       +        | expr BETWEEN position AND position        { $$ = makebetween($1, $3, $5); }
       +        ;
       +
       +place:
       +          PLACENAME                { y = getvar($1); $$ = y.o; }
       +        | PLACENAME CORNER        { y = getvar($1); $$ = getpos(y.o, $2); }
       +        | CORNER PLACENAME        { y = getvar($2); $$ = getpos(y.o, $1); }
       +        | HERE                        { $$ = gethere(); }
       +        | last type                { $$ = getlast($1, $2); }
       +        | last type CORNER        { $$ = getpos(getlast($1, $2), $3); }
       +        | CORNER last type        { $$ = getpos(getlast($2, $3), $1); }
       +        | NTH type                { $$ = getfirst($1, $2); }
       +        | NTH type CORNER        { $$ = getpos(getfirst($1, $2), $3); }
       +        | CORNER NTH type        { $$ = getpos(getfirst($2, $3), $1); }
       +        | blockname
       +        | blockname CORNER        { $$ = getpos($1, $2); }
       +        | CORNER blockname        { $$ = getpos($2, $1); }
       +        ;
       +
       +blockname:
       +          last BLOCK '.' PLACENAME        { $$ = getblock(getlast($1,$2), $4); }
       +        | NTH BLOCK '.' PLACENAME        { $$ = getblock(getfirst($1,$2), $4); }
       +        | PLACENAME '.' PLACENAME        { y = getvar($1); $$ = getblock(y.o, $3); }
       +        ;
       +
       +last:
       +          last LAST                { $$ = $1 + 1; }
       +        | NTH LAST                { $$ = $1; }
       +        | LAST                        { $$ = 1; }
       +        ;
       +
       +type:
       +          BOX
       +        | CIRCLE
       +        | ELLIPSE
       +        | ARC
       +        | LINE
       +        | ARROW
       +        | SPLINE
       +        | BLOCK
       +        ;
       +
       +expr:
       +          NUMBER
       +        | VARNAME                { $$ = getfval($1); }
       +        | asgn
       +        | expr '+' expr                { $$ = $1 + $3; }
       +        | expr '-' expr                { $$ = $1 - $3; }
       +        | expr '*' expr                { $$ = $1 * $3; }
       +        | expr '/' expr                { if ($3 == 0.0) {
       +                                        ERROR "division by 0" WARNING; $3 = 1; }
       +                                  $$ = $1 / $3; }
       +        | expr '%' expr                { if ((long)$3 == 0) {
       +                                        ERROR "mod division by 0" WARNING; $3 = 1; }
       +                                  $$ = (long)$1 % (long)$3; }
       +        | '-' expr %prec UMINUS        { $$ = -$2; }
       +        | '+' expr %prec UMINUS        { $$ = $2; }
       +        | '(' expr ')'                { $$ = $2; }
       +        | place DOTX                { $$ = getcomp($1, $2); }
       +        | place DOTY                { $$ = getcomp($1, $2); }
       +        | place DOTHT                { $$ = getcomp($1, $2); }
       +        | place DOTWID                { $$ = getcomp($1, $2); }
       +        | place DOTRAD                { $$ = getcomp($1, $2); }
       +        | PLACENAME '.' VARNAME        { y = getvar($1); $$ = getblkvar(y.o, $3); }
       +        | last BLOCK '.' VARNAME { $$ = getblkvar(getlast($1,$2), $4); }
       +        | NTH BLOCK '.' VARNAME        { $$ = getblkvar(getfirst($1,$2), $4); }
       +        | expr GT expr                { $$ = $1 > $3; }
       +        | expr LT expr                { $$ = $1 < $3; }
       +        | expr LE expr                { $$ = $1 <= $3; }
       +        | expr GE expr                { $$ = $1 >= $3; }
       +        | expr EQ expr                { $$ = $1 == $3; }
       +        | expr NEQ expr                { $$ = $1 != $3; }
       +        | expr ANDAND expr        { $$ = $1 && $3; }
       +        | expr OROR expr        { $$ = $1 || $3; }
       +        | NOT expr                { $$ = !($2); }
       +        | LOG '(' expr ')'                { $$ = Log10($3); }
       +        | EXP '(' expr ')'                { $$ = Exp($3 * log(10.0)); }
       +        | expr '^' expr                        { $$ = pow($1, $3); }
       +        | SIN '(' expr ')'                { $$ = sin($3); }
       +        | COS '(' expr ')'                { $$ = cos($3); }
       +        | ATAN2 '(' expr ',' expr ')'        { $$ = atan2($3, $5); }
       +        | SQRT '(' expr ')'                { $$ = Sqrt($3); }
       +        | RAND '(' ')'                        { $$ = (float)rand() / 32767.0; /* might be 2^31-1 */ }
       +        | MAX '(' expr ',' expr ')'        { $$ = $3 >= $5 ? $3 : $5; }
       +        | MIN '(' expr ',' expr ')'        { $$ = $3 <= $5 ? $3 : $5; }
       +        | INT '(' expr ')'                { $$ = (long) $3; }
       +        ;
 (DIR) diff --git a/src/cmd/pic/pltroff.c b/src/cmd/pic/pltroff.c
       t@@ -0,0 +1,357 @@
       +#include <stdio.h>
       +#include <math.h>
       +#include <string.h>
       +#include "pic.h"
       +extern int dbg;
       +
       +#define        abs(n)        (n >= 0 ? n : -(n))
       +#define        max(x,y)        ((x)>(y) ? (x) : (y))
       +
       +char        *textshift = "\\v'.2m'";        /* move text this far down */
       +
       +/* scaling stuff defined by s command as X0,Y0 to X1,Y1 */
       +/* output dimensions set by -l,-w options to 0,0 to hmax, vmax */
       +/* default output is 6x6 inches */
       +
       +
       +double        xscale;
       +double        yscale;
       +
       +double        hpos        = 0;        /* current horizontal position in output coordinate system */
       +double        vpos        = 0;        /* current vertical position; 0 is top of page */
       +
       +double        htrue        = 0;        /* where we really are */
       +double        vtrue        = 0;
       +
       +double        X0, Y0;                /* left bottom of input */
       +double        X1, Y1;                /* right top of input */
       +
       +double        hmax;                /* right end of output */
       +double        vmax;                /* top of output (down is positive) */
       +
       +extern        double        deltx;
       +extern        double        delty;
       +extern        double        xmin, ymin, xmax, ymax;
       +
       +double        xconv(double), yconv(double), xsc(double), ysc(double);
       +void        space(double, double, double, double);
       +void        hgoto(double), vgoto(double), hmot(double), vmot(double);
       +void        move(double, double), movehv(double, double);
       +void        cont(double, double);
       +
       +void openpl(char *s)        /* initialize device; s is residue of .PS invocation line */
       +{
       +        double maxw, maxh, ratio = 1;
       +        double odeltx = deltx, odelty = delty;
       +
       +        hpos = vpos = 0;
       +        maxw = getfval("maxpswid");
       +        maxh = getfval("maxpsht");
       +        if (deltx > maxw) {        /* shrink horizontal */
       +                ratio = maxw / deltx;
       +                deltx *= ratio;
       +                delty *= ratio;
       +        }
       +        if (delty > maxh) {        /* shrink vertical */
       +                ratio = maxh / delty;
       +                deltx *= ratio;
       +                delty *= ratio;
       +        }
       +        if (ratio != 1) {
       +                fprintf(stderr, "pic: %g X %g picture shrunk to", odeltx, odelty);
       +                fprintf(stderr, " %g X %g\n", deltx, delty);
       +        }
       +        space(xmin, ymin, xmax, ymax);
       +        printf("... %g %g %g %g\n", xmin, ymin, xmax, ymax);
       +        printf("... %.3fi %.3fi %.3fi %.3fi\n",
       +                xconv(xmin), yconv(ymin), xconv(xmax), yconv(ymax));
       +        printf(".nr 00 \\n(.u\n");
       +        printf(".nf\n");
       +        printf(".PS %.3fi %.3fi %s", yconv(ymin), xconv(xmax), s);
       +                /* assumes \n comes as part of s */
       +}
       +
       +void space(double x0, double y0, double x1, double y1)        /* set limits of page */
       +{
       +        X0 = x0;
       +        Y0 = y0;
       +        X1 = x1;
       +        Y1 = y1;
       +        xscale = deltx == 0.0 ? 1.0 : deltx / (X1-X0);
       +        yscale = delty == 0.0 ? 1.0 : delty / (Y1-Y0);
       +}
       +
       +double xconv(double x)        /* convert x from external to internal form */
       +{
       +        return (x-X0) * xscale;
       +}
       +
       +double xsc(double x)        /* convert x from external to internal form, scaling only */
       +{
       +
       +        return (x) * xscale;
       +}
       +
       +double yconv(double y)        /* convert y from external to internal form */
       +{
       +        return (Y1-y) * yscale;
       +}
       +
       +double ysc(double y)        /* convert y from external to internal form, scaling only */
       +{
       +        return (y) * yscale;
       +}
       +
       +void closepl(char *PEline)        /* clean up after finished */
       +{
       +        movehv(0.0, 0.0);        /* get back to where we started */
       +        if (strchr(PEline, 'F') == NULL) {
       +                printf(".sp 1+%.3fi\n", yconv(ymin));
       +        }
       +        printf("%s\n", PEline);
       +        printf(".if \\n(00 .fi\n");
       +}
       +
       +void move(double x, double y)        /* go to position x, y in external coords */
       +{
       +        hgoto(xconv(x));
       +        vgoto(yconv(y));
       +}
       +
       +void movehv(double h, double v)        /* go to internal position h, v */
       +{
       +        hgoto(h);
       +        vgoto(v);
       +}
       +
       +void hmot(double n)        /* generate n units of horizontal motion */
       +{
       +        hpos += n;
       +}
       +
       +void vmot(double n)        /* generate n units of vertical motion */
       +{
       +        vpos += n;
       +}
       +
       +void hgoto(double n)
       +{
       +        hpos = n;
       +}
       +
       +void vgoto(double n)
       +{
       +        vpos = n;
       +}
       +
       +double fabs(double x)
       +{
       +        return x < 0 ? -x : x;
       +}
       +
       +void hvflush(void)        /* get to proper point for output */
       +{
       +        if (fabs(hpos-htrue) >= 0.0005) {
       +                printf("\\h'%.3fi'", hpos - htrue);
       +                htrue = hpos;
       +        }
       +        if (fabs(vpos-vtrue) >= 0.0005) {
       +                printf("\\v'%.3fi'", vpos - vtrue);
       +                vtrue = vpos;
       +        }
       +}
       +
       +void flyback(void)        /* return to upper left corner (entry point) */
       +{
       +        printf(".sp -1\n");
       +        htrue = vtrue = 0;
       +}
       +
       +void printlf(int n, char *f)
       +{
       +        if (f)
       +                printf(".lf %d %s\n", n, f);
       +        else
       +                printf(".lf %d\n", n);
       +}
       +
       +void troff(char *s)        /* output troff right here */
       +{
       +        printf("%s\n", s);
       +}
       +
       +void label(char *s, int t, int nh)        /* text s of type t nh half-lines up */
       +{
       +        int q;
       +        char *p;
       +
       +        if (!s)
       +                return;
       +        hvflush();
       +        dprintf("label: %s %o %d\n", s, t, nh);
       +        printf("%s", textshift);        /* shift down and left */
       +        if (t & ABOVE)
       +                nh++;
       +        else if (t & BELOW)
       +                nh--;
       +        if (nh)
       +                printf("\\v'%du*\\n(.vu/2u'", -nh);
       +        /* just in case the text contains a quote: */
       +        q = 0;
       +        for (p = s; *p; p++)
       +                if (*p == '\'') {
       +                        q = 1;
       +                        break;
       +                }
       +        t &= ~(ABOVE|BELOW);
       +        if (t & LJUST) {
       +                printf("%s", s);
       +        } else if (t & RJUST) {
       +                if (q)
       +                        printf("\\h\\(ts-\\w\\(ts%s\\(tsu\\(ts%s", s, s);
       +                else
       +                        printf("\\h'-\\w'%s'u'%s", s, s);
       +        } else {        /* CENTER */
       +                if (q)
       +                        printf("\\h\\(ts-\\w\\(ts%s\\(tsu/2u\\(ts%s", s, s);
       +                else
       +                        printf("\\h'-\\w'%s'u/2u'%s", s, s);
       +        }
       +        printf("\n");
       +        flyback();
       +}
       +
       +void line(double x0, double y0, double x1, double y1)        /* draw line from x0,y0 to x1,y1 */
       +{
       +        move(x0, y0);
       +        cont(x1, y1);
       +}
       +
       +void arrow(double x0, double y0, double x1, double y1, double w, double h,
       +         double ang, int nhead)         /* draw arrow (without shaft) */
       +{
       +        double alpha, rot, drot, hyp;
       +        double dx, dy;
       +        int i;
       +
       +        rot = atan2(w / 2, h);
       +        hyp = sqrt(w/2 * w/2 + h * h);
       +        alpha = atan2(y1-y0, x1-x0) + ang;
       +        if (nhead < 2)
       +                nhead = 2;
       +        dprintf("rot=%g, hyp=%g, alpha=%g\n", rot, hyp, alpha);
       +        for (i = nhead-1; i >= 0; i--) {
       +                drot = 2 * rot / (double) (nhead-1) * (double) i;
       +                dx = hyp * cos(alpha + PI - rot + drot);
       +                dy = hyp * sin(alpha + PI - rot + drot);
       +                dprintf("dx,dy = %g,%g\n", dx, dy);
       +                line(x1+dx, y1+dy, x1, y1);
       +        }
       +}
       +
       +double lastgray = 0;
       +
       +void fillstart(double v)        /* this works only for postscript, obviously. */
       +{                                /* uses drechsler's dpost conventions... */
       +        hvflush();
       +        printf("\\X'BeginObject %g setgray'\n", v);
       +        lastgray = v;
       +        flyback();
       +}
       +
       +void fillend(int vis, int fill)
       +{
       +        hvflush();
       +        printf("\\X'EndObject gsave eofill grestore %g setgray %s'\n",
       +                !vis ? lastgray : 0.0,
       +                vis ? "stroke" : "");
       +        /* for dashed: [50] 0 setdash just before stroke. */
       +        lastgray = 0;
       +        flyback();
       +}
       +
       +void box(double x0, double y0, double x1, double y1)
       +{
       +        move(x0, y0);
       +        cont(x0, y1);
       +        cont(x1, y1);
       +        cont(x1, y0);
       +        cont(x0, y0);
       +}
       +
       +void cont(double x, double y)        /* continue line from here to x,y */
       +{
       +        double h1, v1;
       +        double dh, dv;
       +
       +        h1 = xconv(x);
       +        v1 = yconv(y);
       +        dh = h1 - hpos;
       +        dv = v1 - vpos;
       +        hvflush();
       +        printf("\\D'l%.3fi %.3fi'\n", dh, dv);
       +        flyback();        /* expensive */
       +        hpos = h1;
       +        vpos = v1;
       +}
       +
       +void circle(double x, double y, double r)
       +{
       +        move(x-r, y);
       +        hvflush();
       +        printf("\\D'c%.3fi'\n", xsc(2 * r));
       +        flyback();
       +}
       +
       +void spline(double x, double y, double n, ofloat *p, int dashed, double ddval)
       +{
       +        int i;
       +        double dx, dy;
       +        double xerr, yerr;
       +
       +        move(x, y);
       +        hvflush();
       +        xerr = yerr = 0.0;
       +        printf("\\D'~");
       +        for (i = 0; i < 2 * n; i += 2) {
       +                dx = xsc(xerr += p[i]);
       +                xerr -= dx/xscale;
       +                dy = ysc(yerr += p[i+1]);
       +                yerr -= dy/yscale;
       +                printf(" %.3fi %.3fi", dx, -dy);        /* WATCH SIGN */
       +        }
       +        printf("'\n");
       +        flyback();
       +}
       +
       +void ellipse(double x, double y, double r1, double r2)
       +{
       +        double ir1, ir2;
       +
       +        move(x-r1, y);
       +        hvflush();
       +        ir1 = xsc(r1);
       +        ir2 = ysc(r2);
       +        printf("\\D'e%.3fi %.3fi'\n", 2 * ir1, 2 * abs(ir2));
       +        flyback();
       +}
       +
       +void arc(double x, double y, double x0, double y0, double x1, double y1)        /* draw arc with center x,y */
       +{
       +
       +        move(x0, y0);
       +        hvflush();
       +        printf("\\D'a%.3fi %.3fi %.3fi %.3fi'\n",
       +                xsc(x-x0), -ysc(y-y0), xsc(x1-x), -ysc(y1-y));        /* WATCH SIGNS */
       +        flyback();
       +}
       +
       +void dot(void) {
       +        hvflush();
       +        /* what character to draw here depends on what's available. */
       +        /* on the 202, l. is good but small. */
       +        /* in general, use a smaller, shifted period and hope */
       +
       +        printf("\\&\\f1\\h'-.1m'\\v'.03m'\\s-3.\\s+3\\fP\n");
       +        flyback();
       +}
 (DIR) diff --git a/src/cmd/pic/prevy.tab.h b/src/cmd/pic/prevy.tab.h
       t@@ -0,0 +1,97 @@
       +# define BOX 1
       +# define LINE 2
       +# define ARROW 3
       +# define CIRCLE 4
       +# define ELLIPSE 5
       +# define ARC 6
       +# define SPLINE 7
       +# define BLOCK 8
       +# define TEXT 9
       +# define TROFF 10
       +# define MOVE 11
       +# define BLOCKEND 12
       +# define PLACE 13
       +# define PRINT 270
       +# define RESET 271
       +# define THRU 272
       +# define UNTIL 273
       +# define FOR 274
       +# define IF 275
       +# define COPY 276
       +# define THENSTR 277
       +# define ELSESTR 278
       +# define DOSTR 279
       +# define PLACENAME 280
       +# define VARNAME 281
       +# define SPRINTF 282
       +# define DEFNAME 283
       +# define ATTR 284
       +# define TEXTATTR 285
       +# define LEFT 286
       +# define RIGHT 287
       +# define UP 288
       +# define DOWN 289
       +# define FROM 290
       +# define TO 291
       +# define AT 292
       +# define BY 293
       +# define WITH 294
       +# define HEAD 295
       +# define CW 296
       +# define CCW 297
       +# define THEN 298
       +# define HEIGHT 299
       +# define WIDTH 300
       +# define RADIUS 301
       +# define DIAMETER 302
       +# define LENGTH 303
       +# define SIZE 304
       +# define CORNER 305
       +# define HERE 306
       +# define LAST 307
       +# define NTH 308
       +# define SAME 309
       +# define BETWEEN 310
       +# define AND 311
       +# define EAST 312
       +# define WEST 313
       +# define NORTH 314
       +# define SOUTH 315
       +# define NE 316
       +# define NW 317
       +# define SE 318
       +# define SW 319
       +# define START 320
       +# define END 321
       +# define DOTX 322
       +# define DOTY 323
       +# define DOTHT 324
       +# define DOTWID 325
       +# define DOTRAD 326
       +# define NUMBER 327
       +# define LOG 328
       +# define EXP 329
       +# define SIN 330
       +# define COS 331
       +# define ATAN2 332
       +# define SQRT 333
       +# define RAND 334
       +# define MIN 335
       +# define MAX 336
       +# define INT 337
       +# define DIR 338
       +# define DOT 339
       +# define DASH 340
       +# define CHOP 341
       +# define FILL 342
       +# define ST 343
       +# define OROR 344
       +# define ANDAND 345
       +# define GT 346
       +# define LT 347
       +# define LE 348
       +# define GE 349
       +# define EQ 350
       +# define NEQ 351
       +# define UMINUS 352
       +# define NOT 353
 (DIR) diff --git a/src/cmd/pic/print.c b/src/cmd/pic/print.c
       t@@ -0,0 +1,238 @@
       +#include <stdio.h>
       +#include <math.h>
       +#include "pic.h"
       +#include "y.tab.h"
       +
       +void dotext(obj *);
       +void dotline(double, double, double, double, int, double);
       +void dotbox(double, double, double, double, int, double);
       +void ellipse(double, double, double, double);
       +void circle(double, double, double);
       +void arc(double, double, double, double, double, double);
       +void arrow(double, double, double, double, double, double, double, int);
       +void line(double, double, double, double);
       +void box(double, double, double, double);
       +void spline(double x, double y, double n, ofloat *p, int dashed, double ddval);
       +void move(double, double);
       +void troff(char *);
       +void dot(void);
       +void fillstart(double), fillend(int vis, int noedge);
       +
       +void print(void)
       +{
       +        obj *p;
       +        int i, j, k, m;
       +        int fill, vis, invis;
       +        double x0, y0, x1, y1, ox, oy, dx, dy, ndx, ndy;
       +
       +        for (i = 0; i < nobj; i++) {
       +                p = objlist[i];
       +                ox = p->o_x;
       +                oy = p->o_y;
       +                if (p->o_count >= 1)
       +                        x1 = p->o_val[0];
       +                if (p->o_count >= 2)
       +                        y1 = p->o_val[1];
       +                m = p->o_mode;
       +                fill = p->o_attr & FILLBIT;
       +                invis = p->o_attr & INVIS;
       +                vis = !invis;
       +                switch (p->o_type) {
       +                case TROFF:
       +                        troff(text[p->o_nt1].t_val);
       +                        break;
       +                case BOX:
       +                case BLOCK:
       +                        x0 = ox - x1 / 2;
       +                        y0 = oy - y1 / 2;
       +                        x1 = ox + x1 / 2;
       +                        y1 = oy + y1 / 2;
       +                        if (fill) {
       +                                move(x0, y0);
       +                                fillstart(p->o_fillval);
       +                        }
       +                        if (p->o_type == BLOCK)
       +                                ;        /* nothing at all */
       +                        else if (invis && !fill)
       +                                ;        /* nothing at all */
       +                        else if (p->o_attr & (DOTBIT|DASHBIT))
       +                                dotbox(x0, y0, x1, y1, p->o_attr, p->o_ddval);
       +                        else
       +                                box(x0, y0, x1, y1);
       +                        if (fill)
       +                                fillend(vis, fill);
       +                        move(ox, oy);
       +                        dotext(p);        /* if there are any text strings */
       +                        if (ishor(m))
       +                                move(isright(m) ? x1 : x0, oy);        /* right side */
       +                        else
       +                                move(ox, isdown(m) ? y0 : y1);        /* bottom */
       +                        break;
       +                case BLOCKEND:
       +                        break;
       +                case CIRCLE:
       +                        if (fill)
       +                                fillstart(p->o_fillval);
       +                        if (vis || fill)
       +                                circle(ox, oy, x1);
       +                        if (fill)
       +                                fillend(vis, fill);
       +                        move(ox, oy);
       +                        dotext(p);
       +                        if (ishor(m))
       +                                move(ox + isright(m) ? x1 : -x1, oy);
       +                        else
       +                                move(ox, oy + isup(m) ? x1 : -x1);
       +                        break;
       +                case ELLIPSE:
       +                        if (fill)
       +                                fillstart(p->o_fillval);
       +                        if (vis || fill)
       +                                ellipse(ox, oy, x1, y1);
       +                        if (fill)
       +                                fillend(vis, fill);
       +                        move(ox, oy);
       +                        dotext(p);
       +                        if (ishor(m))
       +                                move(ox + isright(m) ? x1 : -x1, oy);
       +                        else
       +                                move(ox, oy - isdown(m) ? y1 : -y1);
       +                        break;
       +                case ARC:
       +                        if (fill) {
       +                                move(ox, oy);
       +                                fillstart(p->o_fillval);
       +                        }
       +                        if (p->o_attr & HEAD1)
       +                                arrow(x1 - (y1 - oy), y1 + (x1 - ox),
       +                                      x1, y1, p->o_val[4], p->o_val[5], p->o_val[5]/p->o_val[6]/2, p->o_nhead);
       +                        if (invis && !fill)
       +                                /* probably wrong when it's cw */
       +                                move(x1, y1);
       +                        else
       +                                arc(ox, oy, x1, y1, p->o_val[2], p->o_val[3]);
       +                        if (p->o_attr & HEAD2)
       +                                arrow(p->o_val[2] + p->o_val[3] - oy, p->o_val[3] - (p->o_val[2] - ox),
       +                                      p->o_val[2], p->o_val[3], p->o_val[4], p->o_val[5], -p->o_val[5]/p->o_val[6]/2, p->o_nhead);
       +                        if (fill)
       +                                fillend(vis, fill);
       +                        if (p->o_attr & CW_ARC)
       +                                move(x1, y1);        /* because drawn backwards */
       +                        move(ox, oy);
       +                        dotext(p);
       +                        break;
       +                case LINE:
       +                case ARROW:
       +                case SPLINE:
       +                        if (fill) {
       +                                move(ox, oy);
       +                                fillstart(p->o_fillval);
       +                        }
       +                        if (vis && p->o_attr & HEAD1)
       +                                arrow(ox + p->o_val[5], oy + p->o_val[6], ox, oy, p->o_val[2], p->o_val[3], 0.0, p->o_nhead);
       +                        if (invis && !fill)
       +                                move(x1, y1);
       +                        else if (p->o_type == SPLINE)
       +                                spline(ox, oy, p->o_val[4], &p->o_val[5], p->o_attr & (DOTBIT|DASHBIT), p->o_ddval);
       +                        else {
       +                                dx = ox;
       +                                dy = oy;
       +                                for (k=0, j=5; k < p->o_val[4]; k++, j += 2) {
       +                                        ndx = dx + p->o_val[j];
       +                                        ndy = dy + p->o_val[j+1];
       +                                        if (p->o_attr & (DOTBIT|DASHBIT))
       +                                                dotline(dx, dy, ndx, ndy, p->o_attr, p->o_ddval);
       +                                        else
       +                                                line(dx, dy, ndx, ndy);
       +                                        dx = ndx;
       +                                        dy = ndy;
       +                                }
       +                        }
       +                        if (vis && p->o_attr & HEAD2) {
       +                                dx = ox;
       +                                dy = oy;
       +                                for (k = 0, j = 5; k < p->o_val[4] - 1; k++, j += 2) {
       +                                        dx += p->o_val[j];
       +                                        dy += p->o_val[j+1];
       +                                }
       +                                arrow(dx, dy, x1, y1, p->o_val[2], p->o_val[3], 0.0, p->o_nhead);
       +                        }
       +                        if (fill)
       +                                fillend(vis, fill);
       +                        move((ox + x1)/2, (oy + y1)/2);        /* center */
       +                        dotext(p);
       +                        break;
       +                case MOVE:
       +                        move(ox, oy);
       +                        break;
       +                case TEXT:
       +                        move(ox, oy);
       +                        if (vis)
       +                                dotext(p);
       +                        break;
       +                }
       +        }
       +}
       +
       +void dotline(double x0, double y0, double x1, double y1, int ddtype, double ddval) /* dotted line */
       +{
       +        static double prevval = 0.05;        /* 20 per inch by default */
       +        int i, numdots;
       +        double a, b, dx, dy;
       +
       +        if (ddval == 0)
       +                ddval = prevval;
       +        prevval = ddval;
       +        /* don't save dot/dash value */
       +        dx = x1 - x0;
       +        dy = y1 - y0;
       +        if (ddtype & DOTBIT) {
       +                numdots = sqrt(dx*dx + dy*dy) / prevval + 0.5;
       +                if (numdots > 0)
       +                        for (i = 0; i <= numdots; i++) {
       +                                a = (double) i / (double) numdots;
       +                                move(x0 + (a * dx), y0 + (a * dy));
       +                                dot();
       +                        }
       +        } else if (ddtype & DASHBIT) {
       +                double d, dashsize, spacesize;
       +                d = sqrt(dx*dx + dy*dy);
       +                if (d <= 2 * prevval) {
       +                        line(x0, y0, x1, y1);
       +                        return;
       +                }
       +                numdots = d / (2 * prevval) + 1;        /* ceiling */
       +                dashsize = prevval;
       +                spacesize = (d - numdots * dashsize) / (numdots - 1);
       +                for (i = 0; i < numdots-1; i++) {
       +                        a = i * (dashsize + spacesize) / d;
       +                        b = a + dashsize / d;
       +                        line(x0 + (a*dx), y0 + (a*dy), x0 + (b*dx), y0 + (b*dy));
       +                        a = b;
       +                        b = a + spacesize / d;
       +                        move(x0 + (a*dx), y0 + (a*dy));
       +                }
       +                line(x0 + (b * dx), y0 + (b * dy), x1, y1);
       +        }
       +        prevval = 0.05;
       +}
       +
       +void dotbox(double x0, double y0, double x1, double y1, int ddtype, double ddval)        /* dotted or dashed box */
       +{
       +        dotline(x0, y0, x1, y0, ddtype, ddval);
       +        dotline(x1, y0, x1, y1, ddtype, ddval);
       +        dotline(x1, y1, x0, y1, ddtype, ddval);
       +        dotline(x0, y1, x0, y0, ddtype, ddval);
       +}
       +
       +void dotext(obj *p)        /* print text strings of p in proper vertical spacing */
       +{
       +        int i, nhalf;
       +        void label(char *, int, int);
       +
       +        nhalf = p->o_nt2 - p->o_nt1 - 1;
       +        for (i = p->o_nt1; i < p->o_nt2; i++) {
       +                label(text[i].t_val, text[i].t_type, nhalf);
       +                nhalf -= 2;
       +        }
       +}
 (DIR) diff --git a/src/cmd/pic/symtab.c b/src/cmd/pic/symtab.c
       t@@ -0,0 +1,104 @@
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <ctype.h>
       +#include <string.h>
       +#include "pic.h"
       +#include "y.tab.h"
       +
       +YYSTYPE getvar(char *s)        /* return value of variable s (usually pointer) */
       +{
       +        struct symtab *p;
       +        static YYSTYPE bug;
       +
       +        p = lookup(s);
       +        if (p == NULL) {
       +                if (islower(s[0]))
       +                        ERROR "no such variable as %s", s WARNING;
       +                else
       +                        ERROR "no such place as %s", s WARNING;
       +                return(bug);
       +        }
       +        return(p->s_val);
       +}
       +
       +double getfval(char *s)        /* return float value of variable s */
       +{
       +        YYSTYPE y;
       +
       +        y = getvar(s);
       +        return y.f;
       +}
       +
       +void setfval(char *s, double f)        /* set variable s to f */
       +{
       +        struct symtab *p;
       +
       +        if ((p = lookup(s)) != NULL)
       +                p->s_val.f = f;
       +}
       +
       +struct symtab *makevar(char *s, int t, YYSTYPE v)        /* make variable named s in table */
       +                /* assumes s is static or from tostring */
       +{
       +        struct symtab *p;
       +
       +        for (p = stack[nstack].p_symtab; p != NULL; p = p->s_next)
       +                if (strcmp(s, p->s_name) == 0)
       +                        break;
       +        if (p == NULL) {        /* it's a new one */
       +                p = (struct symtab *) malloc(sizeof(struct symtab));
       +                if (p == NULL)
       +                        ERROR "out of symtab space with %s", s FATAL;
       +                p->s_next = stack[nstack].p_symtab;
       +                stack[nstack].p_symtab = p;        /* stick it at front */
       +        }
       +        p->s_name = s;
       +        p->s_type = t;
       +        p->s_val = v;
       +        return(p);
       +}
       +
       +struct symtab *lookup(char *s)        /* find s in symtab */
       +{
       +        int i;
       +        struct symtab *p;
       +
       +        for (i = nstack; i >= 0; i--)        /* look in each active symtab */
       +                for (p = stack[i].p_symtab; p != NULL; p = p->s_next)
       +                        if (strcmp(s, p->s_name) == 0)
       +                                return(p);
       +        return(NULL);
       +}
       +
       +void freesymtab(struct symtab *p)        /* free space used by symtab at p */
       +{
       +        struct symtab *q;
       +
       +        for ( ; p != NULL; p = q) {
       +                q = p->s_next;
       +                free(p->s_name);        /* assumes done with tostring */
       +                free((char *)p);
       +        }
       +}
       +
       +void freedef(char *s)        /* free definition for string s */
       +{
       +        struct symtab *p, *q, *op;
       +
       +        for (p = op = q = stack[nstack].p_symtab; p != NULL; p = p->s_next) {
       +                if (strcmp(s, p->s_name) == 0) {         /* got it */
       +                        if (p->s_type != DEFNAME)
       +                                break;
       +                        if (p == op)        /* 1st elem */
       +                                stack[nstack].p_symtab = p->s_next;
       +                        else
       +                                q->s_next = p->s_next;
       +                        free(p->s_name);
       +                        free(p->s_val.p);
       +                        free((char *)p);
       +                        return;
       +                }
       +                q = p;
       +        }
       +        /* ERROR "%s is not defined at this point", s WARNING; */
       +}
 (DIR) diff --git a/src/cmd/pic/textgen.c b/src/cmd/pic/textgen.c
       t@@ -0,0 +1,115 @@
       +#include        <stdio.h>
       +#include        "pic.h"
       +#include        "y.tab.h"
       +
       +obj *textgen(void)
       +{
       +        int i, sub, nstr, at, with, hset, invis;
       +        double xwith, ywith, h, w, x0, y0, x1, y1;
       +        obj *p, *ppos;
       +        static double prevh = 0;
       +        static double prevw = 0;
       +        Attr *ap;
       +
       +        at = with = nstr = hset = invis = 0;
       +        h = getfval("textht");
       +        w = getfval("textwid");
       +        for (i = 0; i < nattr; i++) {
       +                ap = &attr[i];
       +                switch (ap->a_type) {
       +                case HEIGHT:
       +                        h = ap->a_val.f;
       +                        hset++;
       +                        break;
       +                case WIDTH:
       +                        w = ap->a_val.f;
       +                        break;
       +                case WITH:
       +                        with = ap->a_val.i;
       +                        break;
       +                case INVIS:
       +                        invis = INVIS;
       +                        break;
       +                case AT:
       +                        ppos = ap->a_val.o;
       +                        curx = ppos->o_x;
       +                        cury = ppos->o_y;
       +                        at++;
       +                        break;
       +                case TEXTATTR:
       +                        sub = ap->a_sub;
       +                        if (ap->a_val.p == NULL)        /* an isolated modifier */
       +                                text[ntext-1].t_type = sub;
       +                        else {
       +                                savetext(sub, ap->a_val.p);
       +                                nstr++;
       +                        }
       +                        break;
       +                }
       +        }
       +        if (hset == 0)                /* no explicit ht cmd */
       +                h *= nstr;
       +        if (with) {
       +                xwith = ywith = 0.0;
       +                switch (with) {
       +                case NORTH:        ywith = -h / 2; break;
       +                case SOUTH:        ywith = h / 2; break;
       +                case EAST:        xwith = -w / 2; break;
       +                case WEST:        xwith = w / 2; break;
       +                case NE:        xwith = -w / 2; ywith = -h / 2; break;
       +                case SE:        xwith = -w / 2; ywith = h / 2; break;
       +                case NW:        xwith = w / 2; ywith = -h / 2; break;
       +                case SW:        xwith = w / 2; ywith = h / 2; break;
       +                }
       +                curx += xwith;
       +                cury += ywith;
       +        }
       +        if (!at) {
       +                if (isright(hvmode))
       +                        curx += w / 2;
       +                else if (isleft(hvmode))
       +                        curx -= w / 2;
       +                else if (isup(hvmode))
       +                        cury += h / 2;
       +                else
       +                        cury -= h / 2;
       +        }
       +        x0 = curx - w / 2;
       +        y0 = cury - h / 2;
       +        x1 = curx + w / 2;
       +        y1 = cury + h / 2;
       +        extreme(x0, y0);
       +        extreme(x1, y1);
       +        dprintf("Text h %g w %g at %g,%g\n", h, w, curx, cury);
       +        p = makenode(TEXT, 2);
       +        p->o_attr = invis;
       +        p->o_val[0] = w;
       +        p->o_val[1] = h;
       +        if (isright(hvmode))
       +                curx = x1;
       +        else if (isleft(hvmode))
       +                curx = x0;
       +        else if (isup(hvmode))
       +                cury = y1;
       +        else
       +                cury = y0;
       +        prevh = h;
       +        prevw = w;
       +        return(p);
       +}
       +
       +obj *troffgen(char *s)        /* save away a string of troff commands */
       +{
       +        savetext(CENTER, s);        /* use the existing text mechanism */
       +        return makenode(TROFF, 0);
       +}
       +
       +void savetext(int t, char *s)        /* record text elements for current object */
       +{
       +        if (ntext >= ntextlist)
       +                text = (Text *) grow((char *) text, "text", ntextlist += 200, sizeof(Text));
       +        text[ntext].t_type = t;
       +        text[ntext].t_val = s;
       +        dprintf("saving %d text %s at %d\n", t, s, ntext);
       +        ntext++;
       +}
 (DIR) diff --git a/src/cmd/tbl/mkfile b/src/cmd/tbl/mkfile
       t@@ -0,0 +1,32 @@
       +<$PLAN9/src/mkhdr
       +
       +TARG=tbl
       +OFILES=\
       +        t8.$O\
       +        t4.$O\
       +        t6.$O\
       +        tu.$O\
       +        t5.$O\
       +        t7.$O\
       +        tv.$O\
       +        tg.$O\
       +        t3.$O\
       +        tb.$O\
       +        tt.$O\
       +        t9.$O\
       +        t1.$O\
       +        tf.$O\
       +        tc.$O\
       +        ti.$O\
       +        tm.$O\
       +        t0.$O\
       +        tr.$O\
       +        te.$O\
       +        ts.$O\
       +        t2.$O\
       +
       +HFILES=\
       +        t.h\
       +
       +SHORTLIB=bio 9
       +<$PLAN9/src/mkone
 (DIR) diff --git a/src/cmd/tbl/t.h b/src/cmd/tbl/t.h
       t@@ -0,0 +1,192 @@
       +/* t..c : external declarations */
       +
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +# include <ctype.h>
       +
       +# define MAXLIN 250
       +# define MAXHEAD 44
       +# define MAXCOL 30
       + /* Do NOT make MAXCOL bigger with adjusting nregs[] in tr.c */
       +# define MAXCHS 2000
       +#define MAXLINLEN 300
       +# define MAXRPT 100
       +# define CLLEN 10
       +# define SHORTLINE 4
       +extern int nlin, ncol, iline, nclin, nslin;
       +
       +extern int (*style)[MAXHEAD];
       +extern char (*font)[MAXHEAD][2];
       +extern char (*csize)[MAXHEAD][4];
       +extern char (*vsize)[MAXHEAD][4];
       +extern char (*cll)[CLLEN];
       +extern int (*flags)[MAXHEAD];
       +# define ZEROW 001
       +# define HALFUP 002
       +# define CTOP 004
       +# define CDOWN 010
       +extern int stynum[];
       +extern int qcol;
       +extern int *doubled, *acase, *topat;
       +extern int F1, F2;
       +extern int (*lefline)[MAXHEAD];
       +extern int fullbot[];
       +extern char *instead[];
       +extern int expflg;
       +extern int ctrflg;
       +extern int evenflg;
       +extern int *evenup;
       +extern int boxflg;
       +extern int dboxflg;
       +extern int linsize;
       +extern int tab;
       +extern int pr1403;
       +extern int linsize, delim1, delim2;
       +extern int allflg;
       +extern int textflg;
       +extern int left1flg;
       +extern int rightl;
       +struct colstr {char *col, *rcol;};
       +extern struct colstr *table[];
       +extern char *cspace, *cstore;
       +extern char *exstore, *exlim, *exspace;
       +extern int *sep;
       +extern int *used, *lused, *rused;
       +extern int linestop[];
       +extern char *leftover;
       +extern char *last, *ifile;
       +extern int texname;
       +extern int texct, texmax;
       +extern char texstr[];
       +extern int linstart;
       +
       +
       +extern Biobuf *tabin, tabout;
       +# define CRIGHT 2
       +# define CLEFT 0
       +# define CMID 1
       +# define S1 31
       +# define S2 32
       +# define S3 33
       +# define TMP 38
       +#define S9 39
       +# define SF 35
       +# define SL 34
       +# define LSIZE 33
       +# define SIND 37
       +# define SVS 36
       +/* this refers to the relative position of lines */
       +# define LEFT 1
       +# define RIGHT 2
       +# define THRU 3
       +# define TOP 1
       +# define BOT 2
       +
       +int tbl(int argc,char *argv[]);                /*t1.c*/
       +void setinp(int, char **);
       +int swapin(void);
       +
       +void tableput(void);                        /*t2.c*/
       +
       +void getcomm(void);                        /*t3.c*/
       +void backrest(char *);
       +
       +void getspec(void);                        /*t4.c*/
       +void readspec(void);
       +int findcol(void);
       +void garray(int);
       +char *getcore(int, int);
       +void freearr(void);
       +
       +void gettbl(void);                        /*t5.c*/
       +int nodata(int);
       +int oneh(int);
       +int vspand(int, int, int);
       +int vspen(char *);
       +void permute(void);
       +
       +void maktab(void);                        /*t6.c*/
       +void wide(char *, char *, char *);
       +int filler(char *);
       +
       +void runout(void);                        /*t7.c*/
       +void runtabs(int, int);
       +int ifline(char *);
       +void need(void);
       +void deftail(void);
       +
       +void putline(int, int);                        /*t8.c*/
       +void puttext(char *, char *, char *);
       +void funnies(int, int);
       +void putfont(char *);
       +void putsize(char *);
       +
       +void yetmore(void);                        /*t9.c*/
       +int domore(char *);
       +
       +void checkuse(void);                        /*tb.c*/
       +int real(char *);
       +char *chspace(void);
       +int *alocv(int);
       +void release(void);
       +
       +void choochar(void);                        /*tc.c*/
       +int point(char *);
       +
       +void error(char *);                        /*te.c*/
       +char *gets1(char *, int);
       +void un1getc(int);
       +int get1char(void);
       +
       +void savefill(void);                        /*tf.c*/
       +void rstofill(void);
       +void endoff(void);
       +void freearr(void);
       +void saveline(void);
       +void ifdivert(void);
       +void restline(void);
       +void cleanfc(void);
       +
       +int gettext(char *, int, int, char *, char *);                /*tg.c*/
       +void untext(void);
       +
       +int interv(int, int);                        /*ti.c*/
       +int interh(int, int);
       +int up1(int);
       +
       +char *maknew(char *);                        /*tm.c*/
       +int ineqn (char *, char *);
       +
       +char *reg(int, int);                        /*tr.c*/
       +
       +int match (char *, char *);                /*ts.c*/
       +int prefix(char *, char *);
       +int letter (int);
       +int numb(char *);
       +int digit(int);
       +int max(int, int);
       +void tcopy (char *, char *);
       +
       +int ctype(int, int);                        /*tt.c*/
       +int min(int, int);
       +int fspan(int, int);
       +int lspan(int, int);
       +int ctspan(int, int);
       +void tohcol(int);
       +int allh(int);
       +int thish(int, int);
       +
       +void makeline(int, int, int);                /*tu.c*/
       +void fullwide(int, int);
       +void drawline(int, int, int, int, int, int);
       +void getstop(void);
       +int left(int, int, int *);
       +int lefdata(int, int);
       +int next(int);
       +int prev(int);
       +
       +void drawvert(int, int, int, int);                        /*tv.c*/
       +int midbar(int, int);
       +int midbcol(int, int);
       +int barent(char *);
 (DIR) diff --git a/src/cmd/tbl/t0.c b/src/cmd/tbl/t0.c
       t@@ -0,0 +1,49 @@
       + /* t0.c: storage allocation */
       +#
       +# include "t.h"
       +int expflg = 0;
       +int ctrflg = 0;
       +int boxflg = 0;
       +int dboxflg = 0;
       +int tab = '\t';
       +int linsize;
       +int pr1403;
       +int delim1, delim2;
       +int evenflg;
       +int *evenup;
       +int F1 = 0;
       +int F2 = 0;
       +int allflg = 0;
       +char *leftover = 0;
       +int textflg = 0;
       +int left1flg = 0;
       +int rightl = 0;
       +char *cstore, *cspace;
       +char *last;
       +struct colstr *table[MAXLIN];
       +int stynum[MAXLIN+1];
       +int fullbot[MAXLIN];
       +char *instead[MAXLIN];
       +int linestop[MAXLIN];
       +int (*style)[MAXHEAD];
       +char (*font)[MAXHEAD][2];
       +char (*csize)[MAXHEAD][4];
       +char (*vsize)[MAXHEAD][4];
       +int (*lefline)[MAXHEAD];
       +char (*cll)[CLLEN];
       +int (*flags)[MAXHEAD];
       +int qcol;
       +int *doubled, *acase, *topat;
       +int nslin, nclin;
       +int *sep;
       +int *used, *lused, *rused;
       +int nlin, ncol;
       +int iline = 1;
       +char *ifile = "Input";
       +int texname = 'a';
       +int texct = 0;
       +char texstr[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWYXZ0123456789";
       +int linstart;
       +char *exstore, *exlim, *exspace;
       +Biobuf *tabin  /*= stdin */;
       +Biobuf tabout  /* = stdout */;
 (DIR) diff --git a/src/cmd/tbl/t1.c b/src/cmd/tbl/t1.c
       t@@ -0,0 +1,95 @@
       +/* t1.c: main control and input switching */
       +#
       +# include "t.h"
       +
       +# define MACROS "/usr/lib/tmac.s"
       +# define PYMACS "/usr/lib/tmac.m"
       +
       +
       +# define ever (;;)
       +
       +void
       +main(int argc, char *argv[])
       +{
       +        exits(tbl(argc, argv)? "error" : 0);
       +}
       +
       +
       +int
       +tbl(int argc, char *argv[])
       +{
       +        char        line[5120];
       +        /*int x;*/
       +        /*x=malloc((char *)0);        uncomment when allocation breaks*/
       +        Binit(&tabout, 1, OWRITE);
       +        setinp(argc, argv);
       +        while (gets1(line, sizeof(line))) {
       +                Bprint(&tabout, "%s\n", line);
       +                if (prefix(".TS", line))
       +                        tableput();
       +        }
       +        Bterm(tabin);
       +        return(0);
       +}
       +
       +
       +int        sargc;
       +char        **sargv;
       +
       +void
       +setinp(int argc, char **argv)
       +{
       +        sargc = argc;
       +        sargv = argv;
       +        sargc--; 
       +        sargv++;
       +        if (sargc > 0)
       +                swapin();
       +        else {
       +                tabin = (Biobuf*)getcore(sizeof(Biobuf), 1);
       +                Binit(tabin, 0, OREAD);
       +        }
       +}
       +
       +
       +int
       +swapin(void)
       +{
       +        char        *name;
       +        while (sargc > 0 && **sargv == '-') {
       +                if (match("-ms", *sargv)) {
       +                        *sargv = MACROS;
       +                        break;
       +                }
       +                if (match("-mm", *sargv)) {
       +                        *sargv = PYMACS;
       +                        break;
       +                }
       +                if (match("-TX", *sargv))
       +                        pr1403 = 1;
       +                if (match("-", *sargv))
       +                        break;
       +                sargc--; 
       +                sargv++;
       +        }
       +        if (sargc <= 0) 
       +                return(0);
       +        /* file closing is done by GCOS troff preprocessor */
       +        if(tabin)
       +                Bterm(tabin);
       +        ifile = *sargv;
       +        name = ifile;
       +        if (match(ifile, "-")) {
       +                tabin = (Biobuf*)getcore(sizeof(Biobuf), 1);
       +                Binit(tabin, 0, OREAD);
       +        } else
       +                tabin = Bopen(ifile, OREAD);
       +        iline = 1;
       +        Bprint(&tabout, ".ds f. %s\n", ifile);
       +        Bprint(&tabout, ".lf %d %s\n", iline, name);
       +        if (tabin == 0)
       +                error("Can't open file");
       +        sargc--;
       +        sargv++;
       +        return(1);
       +}
 (DIR) diff --git a/src/cmd/tbl/t2.c b/src/cmd/tbl/t2.c
       t@@ -0,0 +1,25 @@
       +/* t2.c:  subroutine sequencing for one table */
       +# include "t.h"
       +void
       +tableput(void)
       +{
       +        saveline();
       +        savefill();
       +        ifdivert();
       +        cleanfc();
       +        getcomm();
       +        getspec();
       +        gettbl();
       +        getstop();
       +        checkuse();
       +        choochar();
       +        maktab();
       +        runout();
       +        release();
       +        rstofill();
       +        endoff();
       +        freearr();
       +        restline();
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/t3.c b/src/cmd/tbl/t3.c
       t@@ -0,0 +1,104 @@
       +/* t3.c: interpret commands affecting whole table */
       +# include "t.h"
       +struct optstr {
       +        char        *optnam; 
       +        int        *optadd;
       +} options [] = {
       +        "expand", &expflg,
       +        "EXPAND", &expflg,
       +        "center", &ctrflg,
       +        "CENTER", &ctrflg,
       +        "box", &boxflg,
       +        "BOX", &boxflg,
       +        "allbox", &allflg,
       +        "ALLBOX", &allflg,
       +        "doublebox", &dboxflg,
       +        "DOUBLEBOX", &dboxflg,
       +        "frame", &boxflg,
       +        "FRAME", &boxflg,
       +        "doubleframe", &dboxflg,
       +        "DOUBLEFRAME", &dboxflg,
       +        "tab", &tab,
       +        "TAB", &tab,
       +        "linesize", &linsize,
       +        "LINESIZE", &linsize,
       +        "delim", &delim1,
       +        "DELIM", &delim1,
       +        0, 0};
       +
       +
       +void
       +getcomm(void)
       +{
       +        char        line[200], *cp, nb[25], *t;
       +        struct optstr *lp;
       +        int        c, ci, found;
       +
       +        for (lp = options; lp->optnam; lp++)
       +                *(lp->optadd) = 0;
       +        texname = texstr[texct=0];
       +        tab = '\t';
       +        Bprint(&tabout, ".nr %d \\n(.s\n", LSIZE);
       +        gets1(line, sizeof(line));
       +        /* see if this is a command line */
       +        if (strchr(line, ';') == 0) {
       +                backrest(line);
       +                return;
       +        }
       +        for (cp = line; (c = *cp) != ';'; cp++) {
       +                if (!letter(c)) 
       +                        continue;
       +                found = 0;
       +                for (lp = options; lp->optadd; lp++) {
       +                        if (prefix(lp->optnam, cp)) {
       +                                *(lp->optadd) = 1;
       +                                cp += strlen(lp->optnam);
       +                                if (letter(*cp))
       +                                        error("Misspelled global option");
       +                                while (*cp == ' ')
       +                                        cp++;
       +                                t = nb;
       +                                if ( *cp == '(')
       +                                        while ((ci = *++cp) != ')')
       +                                                *t++ = ci;
       +                                else 
       +                                        cp--;
       +                                *t++ = 0; 
       +                                *t = 0;
       +                                if (lp->optadd == &tab) {
       +                                        if (nb[0])
       +                                                *(lp->optadd) = nb[0];
       +                                }
       +                                if (lp->optadd == &linsize)
       +                                        Bprint(&tabout, ".nr %d %s\n", LSIZE, nb);
       +                                if (lp->optadd == &delim1) {
       +                                        delim1 = nb[0];
       +                                        delim2 = nb[1];
       +                                }
       +                                found = 1;
       +                                break;
       +                        }
       +                }
       +                if (!found)
       +                        error("Illegal option");
       +        }
       +        cp++;
       +        backrest(cp);
       +        return;
       +}
       +
       +
       +void
       +backrest(char *cp)
       +{
       +        char        *s;
       +
       +        for (s = cp; *s; s++)
       +                ;
       +        un1getc('\n');
       +        while (s > cp)
       +                un1getc(*--s);
       +        return;
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/t4.c b/src/cmd/tbl/t4.c
       t@@ -0,0 +1,405 @@
       +/* t4.c: read table specification */
       +# include "t.h"
       +int        oncol;
       +
       +void
       +getspec(void)
       +{
       +        int        icol, i;
       +
       +        qcol = findcol() + 1;/* must allow one extra for line at right */
       +        garray(qcol);
       +        sep[-1] = -1;
       +        for (icol = 0; icol < qcol; icol++) {
       +                sep[icol] = -1;
       +                evenup[icol] = 0;
       +                cll[icol][0] = 0;
       +                for (i = 0; i < MAXHEAD; i++) {
       +                        csize[icol][i][0] = 0;
       +                        vsize[icol][i][0] = 0;
       +                        font[icol][i][0] = lefline[icol][i] = 0;
       +                        flags[icol][i] = 0;
       +                        style[icol][i] = 'l';
       +                }
       +        }
       +        for (i = 0; i < MAXHEAD; i++)
       +                lefline[qcol][i] = 0;        /* fixes sample55 looping */
       +        nclin = ncol = 0;
       +        oncol = 0;
       +        left1flg = rightl = 0;
       +        readspec();
       +        Bprint(&tabout, ".rm");
       +        for (i = 0; i < ncol; i++)
       +                Bprint(&tabout, " %2s", reg(i, CRIGHT));
       +        Bprint(&tabout, "\n");
       +}
       +
       +
       +void
       +readspec(void)
       +{
       +        int        icol, c, sawchar, stopc, i;
       +        char        sn[10], *snp, *temp;
       +
       +        sawchar = icol = 0;
       +        while (c = get1char()) {
       +                switch (c) {
       +                default:
       +                        if (c != tab) {
       +                                char buf[64];
       +                                sprint(buf, "bad table specification character %c", c);
       +                                error(buf);
       +                        }
       +                case ' ': /* note this is also case tab */
       +                        continue;
       +                case '\n':
       +                        if (sawchar == 0) 
       +                                continue;
       +                case ',':
       +                case '.': /* end of table specification */
       +                        ncol = max(ncol, icol);
       +                        if (lefline[ncol][nclin] > 0) {
       +                                ncol++; 
       +                                rightl++;
       +                        };
       +                        if (sawchar)
       +                                nclin++;
       +                        if (nclin >= MAXHEAD)
       +                                error("too many lines in specification");
       +                        icol = 0;
       +                        if (ncol == 0 || nclin == 0)
       +                                error("no specification");
       +                        if (c == '.') {
       +                                while ((c = get1char()) && c != '\n')
       +                                        if (c != ' ' && c != '\t')
       +                                                error("dot not last character on format line");
       +                                /* fix up sep - default is 3 except at edge */
       +                                for (icol = 0; icol < ncol; icol++)
       +                                        if (sep[icol] < 0)
       +                                                sep[icol] =  icol + 1 < ncol ? 3 : 2;
       +                                if (oncol == 0)
       +                                        oncol = ncol;
       +                                else if (oncol + 2 < ncol)
       +                                        error("tried to widen table in T&, not allowed");
       +                                return;
       +                        }
       +                        sawchar = 0;
       +                        continue;
       +                case 'C': 
       +                case 'S': 
       +                case 'R': 
       +                case 'N': 
       +                case 'L':  
       +                case 'A':
       +                        c += ('a' - 'A');
       +                case '_': 
       +                        if (c == '_') 
       +                                c = '-';
       +                case '=': 
       +                case '-':
       +                case '^':
       +                case 'c': 
       +                case 's': 
       +                case 'n': 
       +                case 'r': 
       +                case 'l':  
       +                case 'a':
       +                        style[icol][nclin] = c;
       +                        if (c == 's' && icol <= 0)
       +                                error("first column can not be S-type");
       +                        if (c == 's' && style[icol-1][nclin] == 'a') {
       +                                Bprint(&tabout, ".tm warning: can't span a-type cols, changed to l\n");
       +                                style[icol-1][nclin] = 'l';
       +                        }
       +                        if (c == 's' && style[icol-1][nclin] == 'n') {
       +                                Bprint(&tabout, ".tm warning: can't span n-type cols, changed to c\n");
       +                                style[icol-1][nclin] = 'c';
       +                        }
       +                        icol++;
       +                        if (c == '^' && nclin <= 0)
       +                                error("first row can not contain vertical span");
       +                        if (icol > qcol)
       +                                error("too many columns in table");
       +                        sawchar = 1;
       +                        continue;
       +                case 'b': 
       +                case 'i':
       +                        c += 'A' - 'a';
       +                case 'B': 
       +                case 'I':
       +                        if (icol == 0) 
       +                                continue;
       +                        snp = font[icol-1][nclin];
       +                        snp[0] = (c == 'I' ? '2' : '3');
       +                        snp[1] = 0;
       +                        continue;
       +                case 't': 
       +                case 'T':
       +                        if (icol > 0)
       +                                flags[icol-1][nclin] |= CTOP;
       +                        continue;
       +                case 'd': 
       +                case 'D':
       +                        if (icol > 0)
       +                                flags[icol-1][nclin] |= CDOWN;
       +                        continue;
       +                case 'f': 
       +                case 'F':
       +                        if (icol == 0) 
       +                                continue;
       +                        snp = font[icol-1][nclin];
       +                        snp[0] = snp[1] = stopc = 0;
       +                        for (i = 0; i < 2; i++) {
       +                                c = get1char();
       +                                if (i == 0 && c == '(') {
       +                                        stopc = ')';
       +                                        c = get1char();
       +                                }
       +                                if (c == 0) 
       +                                        break;
       +                                if (c == stopc) {
       +                                        stopc = 0; 
       +                                        break;
       +                                }
       +                                if (stopc == 0)  
       +                                        if (c == ' ' || c == tab ) 
       +                                                break;
       +                                if (c == '\n' || c == '|') {
       +                                        un1getc(c); 
       +                                        break;
       +                                }
       +                                snp[i] = c;
       +                                if (c >= '0' && c <= '9') 
       +                                        break;
       +                        }
       +                        if (stopc) 
       +                                if (get1char() != stopc)
       +                                        error("Nonterminated font name");
       +                        continue;
       +                case 'P': 
       +                case 'p':
       +                        if (icol <= 0) 
       +                                continue;
       +                        temp = snp = csize[icol-1][nclin];
       +                        while (c = get1char()) {
       +                                if (c == ' ' || c == tab || c == '\n') 
       +                                        break;
       +                                if (c == '-' || c == '+')
       +                                        if (snp > temp)
       +                                                break;
       +                                        else
       +                                                *snp++ = c;
       +                                else if (digit(c))
       +                                        *snp++ = c;
       +                                else 
       +                                        break;
       +                                if (snp - temp > 4)
       +                                        error("point size too large");
       +                        }
       +                        *snp = 0;
       +                        if (atoi(temp) > 36)
       +                                error("point size unreasonable");
       +                        un1getc (c);
       +                        continue;
       +                case 'V': 
       +                case 'v':
       +                        if (icol <= 0) 
       +                                continue;
       +                        temp = snp = vsize[icol-1][nclin];
       +                        while (c = get1char()) {
       +                                if (c == ' ' || c == tab || c == '\n') 
       +                                        break;
       +                                if (c == '-' || c == '+')
       +                                        if (snp > temp)
       +                                                break;
       +                                        else
       +                                                *snp++ = c;
       +                                else if (digit(c))
       +                                        *snp++ = c;
       +                                else 
       +                                        break;
       +                                if (snp - temp > 4)
       +                                        error("vertical spacing value too large");
       +                        }
       +                        *snp = 0;
       +                        un1getc(c);
       +                        continue;
       +                case 'w': 
       +                case 'W':
       +                        snp = cll [icol-1];
       +                        /* Dale Smith didn't like this check - possible to have two text blocks
       +                   of different widths now ....
       +                        if (*snp)
       +                                {
       +                                Bprint(&tabout, "Ignored second width specification");
       +                                continue;
       +                                }
       +                /* end commented out code ... */
       +                        stopc = 0;
       +                        while (c = get1char()) {
       +                                if (snp == cll[icol-1] && c == '(') {
       +                                        stopc = ')';
       +                                        continue;
       +                                }
       +                                if ( !stopc && (c > '9' || c < '0'))
       +                                        break;
       +                                if (stopc && c == stopc)
       +                                        break;
       +                                *snp++ = c;
       +                        }
       +                        *snp = 0;
       +                        if (snp - cll[icol-1] > CLLEN)
       +                                error ("column width too long");
       +                        if (!stopc)
       +                                un1getc(c);
       +                        continue;
       +                case 'e': 
       +                case 'E':
       +                        if (icol < 1) 
       +                                continue;
       +                        evenup[icol-1] = 1;
       +                        evenflg = 1;
       +                        continue;
       +                case 'z': 
       +                case 'Z': /* zero width-ignre width this item */
       +                        if (icol < 1) 
       +                                continue;
       +                        flags[icol-1][nclin] |= ZEROW;
       +                        continue;
       +                case 'u': 
       +                case 'U': /* half line up */
       +                        if (icol < 1) 
       +                                continue;
       +                        flags[icol-1][nclin] |= HALFUP;
       +                        continue;
       +                case '0': 
       +                case '1': 
       +                case '2': 
       +                case '3': 
       +                case '4':
       +                case '5': 
       +                case '6': 
       +                case '7': 
       +                case '8': 
       +                case '9':
       +                        sn[0] = c;
       +                        snp = sn + 1;
       +                        while (digit(*snp++ = c = get1char()))
       +                                ;
       +                        un1getc(c);
       +                        sep[icol-1] = max(sep[icol-1], numb(sn));
       +                        continue;
       +                case '|':
       +                        lefline[icol][nclin]++;
       +                        if (icol == 0) 
       +                                left1flg = 1;
       +                        continue;
       +                }
       +        }
       +        error("EOF reading table specification");
       +}
       +
       +
       +int
       +findcol(void)
       +{
       +# define FLNLIM 200
       +        /* this counts the number of columns and then puts the line back*/
       +        char        *s, line[FLNLIM+2], *p;
       +        int        c, n = 0, inpar = 0;
       +
       +        while ((c = get1char()) != 0 && c == ' ')
       +                ;
       +        if (c != '\n')
       +                un1getc(c);
       +        for (s = line; *s = c = get1char(); s++) {
       +                if (c == ')') 
       +                        inpar = 0;
       +                if (inpar) 
       +                        continue;
       +                if (c == '\n' || c == 0 || c == '.' || c == ',')
       +                        break;
       +                else if (c == '(')
       +                        inpar = 1;
       +                else if (s >= line + FLNLIM)
       +                        error("too long spec line");
       +        }
       +        for (p = line; p < s; p++)
       +                switch (*p) {
       +                case 'l': 
       +                case 'r': 
       +                case 'c': 
       +                case 'n': 
       +                case 'a': 
       +                case 's':
       +                case 'L': 
       +                case 'R': 
       +                case 'C': 
       +                case 'N': 
       +                case 'A': 
       +                case 'S':
       +                case '-': 
       +                case '=': 
       +                case '_':
       +                        n++;
       +                }
       +        while (p >= line)
       +                un1getc(*p--);
       +        return(n);
       +}
       +
       +
       +void
       +garray(int qcol)
       +{
       +        style =  (int (*)[]) getcore(MAXHEAD * qcol, sizeof(int));
       +        evenup = (int *) getcore(qcol, sizeof(int));
       +        lefline = (int (*)[]) getcore(MAXHEAD * (qcol + 1), sizeof (int)); /*+1 for sample55 loop - others may need it too*/
       +        font = (char (*)[][2]) getcore(MAXHEAD * qcol, 2);
       +        csize = (char (*)[MAXHEAD][4]) getcore(MAXHEAD * qcol, 4);
       +        vsize = (char (*)[MAXHEAD][4]) getcore(MAXHEAD * qcol, 4);
       +        flags =  (int (*)[]) getcore(MAXHEAD * qcol, sizeof(int));
       +        cll = (char (*)[])getcore(qcol, CLLEN);
       +        sep = (int *) getcore(qcol + 1, sizeof(int));
       +        sep++; /* sep[-1] must be legal */
       +        used = (int *) getcore(qcol + 1, sizeof(int));
       +        lused = (int *) getcore(qcol + 1, sizeof(int));
       +        rused = (int *) getcore(qcol + 1, sizeof(int));
       +        doubled = (int *) getcore(qcol + 1, sizeof(int));
       +        acase = (int *) getcore(qcol + 1, sizeof(int));
       +        topat = (int *) getcore(qcol + 1, sizeof(int));
       +}
       +
       +
       +char        *
       +getcore(int a, int b)
       +{
       +        char        *x;
       +        x = calloc(a, b);
       +        if (x == 0)
       +                error("Couldn't get memory");
       +        return(x);
       +}
       +
       +
       +void
       +freearr(void)
       +{
       +        free(style);
       +        free(evenup);
       +        free(lefline);
       +        free(flags);
       +        free(font);
       +        free(csize);
       +        free(vsize);
       +        free(cll);
       +        free(--sep);        /* netnews says this should be --sep because incremented earlier! */
       +        free(used);
       +        free(lused);
       +        free(rused);
       +        free(doubled);
       +        free(acase);
       +        free(topat);
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/t5.c b/src/cmd/tbl/t5.c
       t@@ -0,0 +1,198 @@
       +/* t5.c: read data for table */
       +# include "t.h"
       +
       +void
       +gettbl(void)
       +{
       +        int        icol, ch;
       +
       +        cstore = cspace = chspace();
       +        textflg = 0;
       +        for (nlin = nslin = 0; gets1(cstore, MAXCHS - (cstore - cspace)); nlin++) {
       +                stynum[nlin] = nslin;
       +                if (prefix(".TE", cstore)) {
       +                        leftover = 0;
       +                        break;
       +                }
       +                if (prefix(".TC", cstore) || prefix(".T&", cstore)) {
       +                        readspec();
       +                        nslin++;
       +                }
       +                if (nlin >= MAXLIN) {
       +                        leftover = cstore;
       +                        break;
       +                }
       +                fullbot[nlin] = 0;
       +                if (cstore[0] == '.' && !isdigit(cstore[1])) {
       +                        instead[nlin] = cstore;
       +                        while (*cstore++)
       +                                ;
       +                        continue;
       +                } else 
       +                        instead[nlin] = 0;
       +                if (nodata(nlin)) {
       +                        if (ch = oneh(nlin))
       +                                fullbot[nlin] = ch;
       +                        table[nlin] = (struct colstr *) alocv((ncol + 2) * sizeof(table[0][0]));
       +                        for (icol = 0; icol < ncol; icol++) {
       +                                table[nlin][icol].rcol = "";
       +                                table[nlin][icol].col = "";
       +                        }
       +                        nlin++;
       +                        nslin++;
       +                        fullbot[nlin] = 0;
       +                        instead[nlin] = (char *) 0;
       +                }
       +                table[nlin] = (struct colstr *) alocv((ncol + 2) * sizeof(table[0][0]));
       +                if (cstore[1] == 0)
       +                        switch (cstore[0]) {
       +                        case '_': 
       +                                fullbot[nlin] = '-'; 
       +                                continue;
       +                        case '=': 
       +                                fullbot[nlin] = '='; 
       +                                continue;
       +                        }
       +                stynum[nlin] = nslin;
       +                nslin = min(nslin + 1, nclin - 1);
       +                for (icol = 0; icol < ncol; icol++) {
       +                        table[nlin][icol].col = cstore;
       +                        table[nlin][icol].rcol = 0;
       +                        ch = 1;
       +                        if (match(cstore, "T{")) { /* text follows */
       +                                table[nlin][icol].col = 
       +                                    (char *)gettext(cstore, nlin, icol,
       +                                    font[icol][stynum[nlin]],
       +                                    csize[icol][stynum[nlin]]);
       +                        } else
       +                         {
       +                                for (; (ch = *cstore) != '\0' && ch != tab; cstore++)
       +                                        ;
       +                                *cstore++ = '\0';
       +                                switch (ctype(nlin, icol)) /* numerical or alpha, subcol */ {
       +                                case 'n':
       +                                        table[nlin][icol].rcol = maknew(table[nlin][icol].col);
       +                                        break;
       +                                case 'a':
       +                                        table[nlin][icol].rcol = table[nlin][icol].col;
       +                                        table[nlin][icol].col = "";
       +                                        break;
       +                                }
       +                        }
       +                        while (ctype(nlin, icol + 1) == 's') /* spanning */
       +                                table[nlin][++icol].col = "";
       +                        if (ch == '\0') 
       +                                break;
       +                }
       +                while (++icol < ncol + 2) {
       +                        table[nlin][icol].col = "";
       +                        table [nlin][icol].rcol = 0;
       +                }
       +                while (*cstore != '\0')
       +                        cstore++;
       +                if (cstore - cspace + MAXLINLEN > MAXCHS)
       +                        cstore = cspace = chspace();
       +        }
       +        last = cstore;
       +        permute();
       +        if (textflg) 
       +                untext();
       +        return;
       +}
       +
       +
       +int
       +nodata(int il)
       +{
       +        int        c;
       +
       +        for (c = 0; c < ncol; c++) {
       +                switch (ctype(il, c)) {
       +                case 'c': 
       +                case 'n': 
       +                case 'r': 
       +                case 'l': 
       +                case 's': 
       +                case 'a':
       +                        return(0);
       +                }
       +        }
       +        return(1);
       +}
       +
       +
       +int
       +oneh(int lin)
       +{
       +        int        k, icol;
       +
       +        k = ctype(lin, 0);
       +        for (icol = 1; icol < ncol; icol++) {
       +                if (k != ctype(lin, icol))
       +                        return(0);
       +        }
       +        return(k);
       +}
       +
       +
       +# define SPAN "\\^"
       +
       +void
       +permute(void)
       +{
       +        int        irow, jcol, is;
       +        char        *start, *strig;
       +
       +        for (jcol = 0; jcol < ncol; jcol++) {
       +                for (irow = 1; irow < nlin; irow++) {
       +                        if (vspand(irow, jcol, 0)) {
       +                                is = prev(irow);
       +                                if (is < 0)
       +                                        error("Vertical spanning in first row not allowed");
       +                                start = table[is][jcol].col;
       +                                strig = table[is][jcol].rcol;
       +                                while (irow < nlin && vspand(irow, jcol, 0))
       +                                        irow++;
       +                                table[--irow][jcol].col = start;
       +                                table[irow][jcol].rcol = strig;
       +                                while (is < irow) {
       +                                        table[is][jcol].rcol = 0;
       +                                        table[is][jcol].col = SPAN;
       +                                        is = next(is);
       +                                }
       +                        }
       +                }
       +        }
       +}
       +
       +
       +int
       +vspand(int ir, int ij, int ifform)
       +{
       +        if (ir < 0) 
       +                return(0);
       +        if (ir >= nlin)
       +                return(0);
       +        if (instead[ir]) 
       +                return(0);
       +        if (ifform == 0 && ctype(ir, ij) == '^') 
       +                return(1);
       +        if (table[ir][ij].rcol != 0) 
       +                return(0);
       +        if (fullbot[ir]) 
       +                return(0);
       +        return(vspen(table[ir][ij].col));
       +}
       +
       +
       +int
       +vspen(char *s)
       +{
       +        if (s == 0) 
       +                return(0);
       +        if (!point(s)) 
       +                return(0);
       +        return(match(s, SPAN));
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/t6.c b/src/cmd/tbl/t6.c
       t@@ -0,0 +1,223 @@
       +/* t6.c: compute tab stops */
       +# define tx(a) (a>0 && a<128)
       +# include "t.h"
       +# define FN(i,c) font[c][stynum[i]]
       +# define SZ(i,c) csize[c][stynum[i]]
       +# define TMP1 S1
       +# define TMP2 S2
       +
       +void
       +maktab(void)                        /* define the tab stops of the table */
       +{
       +        int        icol, ilin, tsep, k, ik, vforml, il, text;
       +        char        *s;
       +
       +        for (icol = 0; icol < ncol; icol++) {
       +                doubled[icol] = acase[icol] = 0;
       +                Bprint(&tabout, ".nr %2s 0\n", reg(icol, CRIGHT));
       +                for (text = 0; text < 2; text++) {
       +                        if (text)
       +                                Bprint(&tabout, ".%2s\n.rm %2s\n", reg(icol, CRIGHT),
       +                                    reg(icol, CRIGHT));
       +                        for (ilin = 0; ilin < nlin; ilin++) {
       +                                if (instead[ilin] || fullbot[ilin]) 
       +                                        continue;
       +                                vforml = ilin;
       +                                for (il = prev(ilin); il >= 0 && vspen(table[il][icol].col); il = prev(il))
       +                                        vforml = il;
       +                                if (fspan(vforml, icol)) 
       +                                        continue;
       +                                if (filler(table[ilin][icol].col)) 
       +                                        continue;
       +                                if ((flags[icol][stynum[ilin]] & ZEROW) != 0) 
       +                                        continue;
       +                                switch (ctype(vforml, icol)) {
       +                                case 'a':
       +                                        acase[icol] = 1;
       +                                        s = table[ilin][icol].col;
       +                                        if ((int)s > 0 && (int)s < 128 && text) {
       +                                                if (doubled[icol] == 0)
       +                                                        Bprint(&tabout, ".nr %d 0\n.nr %d 0\n",
       +                                                            S1, S2);
       +                                                doubled[icol] = 1;
       +                                                Bprint(&tabout, ".if \\n(%c->\\n(%d .nr %d \\n(%c-\n",
       +                                                    (int)s, S2, S2, (int)s);
       +                                        }
       +                                case 'n':
       +                                        if (table[ilin][icol].rcol != 0) {
       +                                                if (doubled[icol] == 0 && text == 0)
       +                                                        Bprint(&tabout, ".nr %d 0\n.nr %d 0\n",
       +                                                            S1, S2);
       +                                                doubled[icol] = 1;
       +                                                if (real(s = table[ilin][icol].col) && !vspen(s)) {
       +                                                        if (tx((int)s) != text) 
       +                                                                continue;
       +                                                        Bprint(&tabout, ".nr %d ", TMP);
       +                                                        wide(s, FN(vforml, icol), SZ(vforml, icol)); 
       +                                                        Bprint(&tabout, "\n");
       +                                                        Bprint(&tabout, ".if \\n(%d<\\n(%d .nr %d \\n(%d\n",
       +                                                            S1, TMP, S1, TMP);
       +                                                }
       +                                                if (text == 0 && real(s = table[ilin][icol].rcol) && !vspen(s) && !barent(s)) {
       +                                                        Bprint(&tabout, ".nr %d \\w%c%s%c\n",
       +                                                            TMP, F1, s, F1);
       +                                                        Bprint(&tabout, ".if \\n(%d<\\n(%d .nr %d \\n(%d\n", S2, TMP, S2,
       +                                                             TMP);
       +                                                }
       +                                                continue;
       +                                        }
       +                                case 'r':
       +                                case 'c':
       +                                case 'l':
       +                                        if (real(s = table[ilin][icol].col) && !vspen(s)) {
       +                                                if (tx((int)s) != text) 
       +                                                        continue;
       +                                                Bprint(&tabout, ".nr %d ", TMP);
       +                                                wide(s, FN(vforml, icol), SZ(vforml, icol)); 
       +                                                Bprint(&tabout, "\n");
       +                                                Bprint(&tabout, ".if \\n(%2s<\\n(%d .nr %2s \\n(%d\n",
       +                                                     reg(icol, CRIGHT), TMP, reg(icol, CRIGHT), TMP);
       +                                        }
       +                                }
       +                        }
       +                }
       +                if (acase[icol]) {
       +                        Bprint(&tabout, ".if \\n(%d>=\\n(%2s .nr %2s \\n(%du+2n\n", 
       +                             S2, reg(icol, CRIGHT), reg(icol, CRIGHT), S2);
       +                }
       +                if (doubled[icol]) {
       +                        Bprint(&tabout, ".nr %2s \\n(%d\n", reg(icol, CMID), S1);
       +                        Bprint(&tabout, ".nr %d \\n(%2s+\\n(%d\n", TMP, reg(icol, CMID), S2);
       +                        Bprint(&tabout, ".if \\n(%d>\\n(%2s .nr %2s \\n(%d\n", TMP,
       +                            reg(icol, CRIGHT), reg(icol, CRIGHT), TMP);
       +                        Bprint(&tabout, ".if \\n(%d<\\n(%2s .nr %2s +(\\n(%2s-\\n(%d)/2\n",
       +                             TMP, reg(icol, CRIGHT), reg(icol, CMID), reg(icol, CRIGHT), TMP);
       +                }
       +                if (cll[icol][0]) {
       +                        Bprint(&tabout, ".nr %d %sn\n", TMP, cll[icol]);
       +                        Bprint(&tabout, ".if \\n(%2s<\\n(%d .nr %2s \\n(%d\n",
       +                            reg(icol, CRIGHT), TMP, reg(icol, CRIGHT), TMP);
       +                }
       +                for (ilin = 0; ilin < nlin; ilin++)
       +                        if (k = lspan(ilin, icol)) {
       +                                s = table[ilin][icol-k].col;
       +                                if (!real(s) || barent(s) || vspen(s) ) 
       +                                        continue;
       +                                Bprint(&tabout, ".nr %d ", TMP);
       +                                wide(table[ilin][icol-k].col, FN(ilin, icol - k), SZ(ilin, icol - k));
       +                                for (ik = k; ik >= 0; ik--) {
       +                                        Bprint(&tabout, "-\\n(%2s", reg(icol - ik, CRIGHT));
       +                                        if (!expflg && ik > 0) 
       +                                                Bprint(&tabout, "-%dn", sep[icol-ik]);
       +                                }
       +                                Bprint(&tabout, "\n");
       +                                Bprint(&tabout, ".if \\n(%d>0 .nr %d \\n(%d/%d\n", TMP,
       +                                      TMP, TMP, k);
       +                                Bprint(&tabout, ".if \\n(%d<0 .nr %d 0\n", TMP, TMP);
       +                                for (ik = 1; ik <= k; ik++) {
       +                                        if (doubled[icol-k+ik])
       +                                                Bprint(&tabout, ".nr %2s +\\n(%d/2\n",
       +                                                     reg(icol - k + ik, CMID), TMP);
       +                                        Bprint(&tabout, ".nr %2s +\\n(%d\n",
       +                                             reg(icol - k + ik, CRIGHT), TMP);
       +                                }
       +                        }
       +        }
       +        if (textflg) 
       +                untext();
       +                                /* if even requested, make all columns widest width */
       +        if (evenflg) {
       +                Bprint(&tabout, ".nr %d 0\n", TMP);
       +                for (icol = 0; icol < ncol; icol++) {
       +                        if (evenup[icol] == 0) 
       +                                continue;
       +                        Bprint(&tabout, ".if \\n(%2s>\\n(%d .nr %d \\n(%2s\n",
       +                            reg(icol, CRIGHT), TMP, TMP, reg(icol, CRIGHT));
       +                }
       +                for (icol = 0; icol < ncol; icol++) {
       +                        if (evenup[icol] == 0)
       +                                /* if column not evened just retain old interval */
       +                                continue;
       +                        if (doubled[icol])
       +                                Bprint(&tabout, ".nr %2s (100*\\n(%2s/\\n(%2s)*\\n(%d/100\n",
       +                                    reg(icol, CMID), reg(icol, CMID), reg(icol, CRIGHT), TMP);
       +                        /* that nonsense with the 100's and parens tries
       +                                   to avoid overflow while proportionally shifting
       +                                   the middle of the number */
       +                        Bprint(&tabout, ".nr %2s \\n(%d\n", reg(icol, CRIGHT), TMP);
       +                }
       +        }
       +                                /* now adjust for total table width */
       +        for (tsep = icol = 0; icol < ncol; icol++)
       +                tsep += sep[icol];
       +        if (expflg) {
       +                Bprint(&tabout, ".nr %d 0", TMP);
       +                for (icol = 0; icol < ncol; icol++)
       +                        Bprint(&tabout, "+\\n(%2s", reg(icol, CRIGHT));
       +                Bprint(&tabout, "\n");
       +                Bprint(&tabout, ".nr %d \\n(.l-\\n(%d\n", TMP, TMP);
       +                if (boxflg || dboxflg || allflg)
       +                        /* tsep += 1; */ {}
       +                else
       +                        tsep -= sep[ncol-1];
       +                Bprint(&tabout, ".nr %d \\n(%d/%d\n", TMP, TMP,  tsep);
       +                Bprint(&tabout, ".if \\n(%d<0 .nr %d 0\n", TMP, TMP);
       +        } else
       +                Bprint(&tabout, ".nr %d 1n\n", TMP);
       +        Bprint(&tabout, ".nr %2s 0\n", reg(-1, CRIGHT));
       +        tsep = (boxflg || allflg || dboxflg || left1flg) ? 2 : 0;
       +        if (sep[-1] >= 0) 
       +                tsep = sep[-1];
       +        for (icol = 0; icol < ncol; icol++) {
       +                Bprint(&tabout, ".nr %2s \\n(%2s+((%d*\\n(%d)/2)\n", reg(icol, CLEFT),
       +                    reg(icol - 1, CRIGHT), tsep, TMP);
       +                Bprint(&tabout, ".nr %2s +\\n(%2s\n", reg(icol, CRIGHT), reg(icol, CLEFT));
       +                if (doubled[icol]) {
       +                        /* the next line is last-ditch effort to avoid zero field width */
       +                        /*Bprint(&tabout, ".if \\n(%2s=0 .nr %2s 1\n",reg(icol,CMID), reg(icol,CMID));*/
       +                        Bprint(&tabout, ".nr %2s +\\n(%2s\n", reg(icol, CMID),
       +                            reg(icol, CLEFT));
       +                        /*  Bprint(&tabout, ".if n .if \\n(%s%%24>0 .nr %s +12u\n",reg(icol,CMID), reg(icol,CMID)); */
       +                }
       +                tsep = sep[icol] * 2;
       +        }
       +        if (rightl)
       +                Bprint(&tabout, ".nr %s (\\n(%s+\\n(%s)/2\n", reg(ncol - 1, CRIGHT),
       +                      reg(ncol - 1, CLEFT), reg(ncol - 2, CRIGHT));
       +        Bprint(&tabout, ".nr TW \\n(%2s\n", reg(ncol - 1, CRIGHT));
       +        tsep = sep[ncol-1];
       +        if (boxflg || allflg || dboxflg)
       +                Bprint(&tabout, ".nr TW +((%d*\\n(%d)/2)\n", tsep, TMP);
       +        Bprint(&tabout,
       +            ".if t .if (\\n(TW+\\n(.o)>7.65i .tm Table at line %d file %s is too wide - \\n(TW units\n", iline - 1, ifile);
       +        return;
       +}
       +
       +
       +void
       +wide(char *s, char *fn, char *size)
       +{
       +        if (point(s)) {
       +                Bprint(&tabout, "\\w%c", F1);
       +                if (*fn > 0) 
       +                        putfont(fn);
       +                if (*size) 
       +                        putsize(size);
       +                Bprint(&tabout, "%s", s);
       +                if (*fn > 0) 
       +                        putfont("P");
       +                if (*size) 
       +                        putsize("0");
       +                Bprint(&tabout, "%c", F1);
       +        } else
       +                Bprint(&tabout, "\\n(%c-", (int)s);
       +}
       +
       +
       +int
       +filler(char *s)
       +{
       +        return (point(s) && s[0] == '\\' && s[1] == 'R');
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/t7.c b/src/cmd/tbl/t7.c
       t@@ -0,0 +1,150 @@
       +/* t7.c: control to write table entries */
       +# include "t.h"
       +# define realsplit ((ct=='a'||ct=='n') && table[ldata][c].rcol)
       +
       +void
       +runout(void)
       +{
       +        int        i;
       +
       +        if (boxflg || allflg || dboxflg) 
       +                need();
       +        if (ctrflg) {
       +                Bprint(&tabout, ".nr #I \\n(.i\n");
       +                Bprint(&tabout, ".in +(\\n(.lu-\\n(TWu-\\n(.iu)/2u\n");
       +        }
       +        Bprint(&tabout, ".fc %c %c\n", F1, F2);
       +        Bprint(&tabout, ".nr #T 0-1\n");
       +        deftail();
       +        for (i = 0; i < nlin; i++)
       +                putline(i, i);
       +        if (leftover)
       +                yetmore();
       +        Bprint(&tabout, ".fc\n");
       +        Bprint(&tabout, ".nr T. 1\n");
       +        Bprint(&tabout, ".T# 1\n");
       +        if (ctrflg)
       +                Bprint(&tabout, ".in \\n(#Iu\n");
       +}
       +
       +
       +void
       +runtabs(int lform, int ldata)
       +{
       +        int        c, ct, vforml, lf;
       +
       +        Bprint(&tabout, ".ta ");
       +        for (c = 0; c < ncol; c++) {
       +                vforml = lform;
       +                for (lf = prev(lform); lf >= 0 && vspen(table[lf][c].col); lf = prev(lf))
       +                        vforml = lf;
       +                if (fspan(vforml, c))
       +                        continue;
       +                switch (ct = ctype(vforml, c)) {
       +                case 'n':
       +                case 'a':
       +                        if (table[ldata][c].rcol)
       +                                if (lused[c]) /*Zero field width*/
       +                                        Bprint(&tabout, "\\n(%2su ", reg(c, CMID));
       +                case 'c':
       +                case 'l':
       +                case 'r':
       +                        if (realsplit ? rused[c] : (used[c] + lused[c]))
       +                                Bprint(&tabout, "\\n(%2su ", reg(c, CRIGHT));
       +                        continue;
       +                case 's':
       +                        if (lspan(lform, c))
       +                                Bprint(&tabout, "\\n(%2su ", reg(c, CRIGHT));
       +                        continue;
       +                }
       +        }
       +        Bprint(&tabout, "\n");
       +}
       +
       +
       +int
       +ifline(char *s)
       +{
       +        if (!point(s)) 
       +                return(0);
       +        if (s[0] == '\\') 
       +                s++;
       +        if (s[1] ) 
       +                return(0);
       +        if (s[0] == '_') 
       +                return('-');
       +        if (s[0] == '=') 
       +                return('=');
       +        return(0);
       +}
       +
       +
       +void
       +need(void)
       +{
       +        int        texlin, horlin, i;
       +
       +        for (texlin = horlin = i = 0; i < nlin; i++) {
       +                if (fullbot[i] != 0)
       +                        horlin++;
       +                else if (instead[i] != 0)
       +                        continue;
       +                else
       +                        texlin++;
       +        }
       +        Bprint(&tabout, ".ne %dv+%dp\n", texlin, 2 * horlin);
       +}
       +
       +
       +void
       +deftail(void)
       +{
       +        int        i, c, lf, lwid;
       +
       +        for (i = 0; i < MAXHEAD; i++)
       +                if (linestop[i])
       +                        Bprint(&tabout, ".nr #%c 0-1\n", linestop[i] + 'a' - 1);
       +        Bprint(&tabout, ".nr #a 0-1\n");
       +        Bprint(&tabout, ".eo\n");
       +        Bprint(&tabout, ".de T#\n");
       +        Bprint(&tabout, ".nr 35 1m\n");
       +        Bprint(&tabout, ".ds #d .d\n");
       +        Bprint(&tabout, ".if \\(ts\\n(.z\\(ts\\(ts .ds #d nl\n");
       +        Bprint(&tabout, ".mk ##\n");
       +        Bprint(&tabout, ".nr ## -1v\n");
       +        Bprint(&tabout, ".ls 1\n");
       +        for (i = 0; i < MAXHEAD; i++)
       +                if (linestop[i])
       +                        Bprint(&tabout, ".if \\n(#T>=0 .nr #%c \\n(#T\n",
       +                             linestop[i] + 'a' - 1);
       +        if (boxflg || allflg || dboxflg) /* bottom of table line */
       +                if (fullbot[nlin-1] == 0) {
       +                        if (!pr1403)
       +                                Bprint(&tabout, ".if \\n(T. .vs \\n(.vu-\\n(.sp\n");
       +                        Bprint(&tabout, ".if \\n(T. ");
       +                        drawline(nlin, 0, ncol, dboxflg ? '=' : '-', 1, 0);
       +                        Bprint(&tabout, "\n.if \\n(T. .vs\n");
       +                        /* T. is really an argument to a macro but because of 
       +                   eqn we don't dare pass it as an argument and reference by $1 */
       +                }
       +        for (c = 0; c < ncol; c++) {
       +                if ((lf = left(nlin - 1, c, &lwid)) >= 0) {
       +                        Bprint(&tabout, ".if \\n(#%c>=0 .sp -1\n", linestop[lf] + 'a' - 1);
       +                        Bprint(&tabout, ".if \\n(#%c>=0 ", linestop[lf] + 'a' - 1);
       +                        tohcol(c);
       +                        drawvert(lf, nlin - 1, c, lwid);
       +                        Bprint(&tabout, "\\h'|\\n(TWu'\n");
       +                }
       +        }
       +        if (boxflg || allflg || dboxflg) /* right hand line */ {
       +                Bprint(&tabout, ".if \\n(#a>=0 .sp -1\n");
       +                Bprint(&tabout, ".if \\n(#a>=0 \\h'|\\n(TWu'");
       +                drawvert (0, nlin - 1, ncol, dboxflg ? 2 : 1);
       +                Bprint(&tabout, "\n");
       +        }
       +        Bprint(&tabout, ".ls\n");
       +        Bprint(&tabout, "..\n");
       +        Bprint(&tabout, ".ec\n");
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/t8.c b/src/cmd/tbl/t8.c
       t@@ -0,0 +1,367 @@
       +/* t8.c: write out one line of output table */
       +# include "t.h"
       +# define realsplit ((ct=='a'||ct=='n') && table[nl][c].rcol)
       +int        watchout;
       +int        once;
       +
       +void
       +putline(int i, int nl)
       +                                /* i is line number for deciding format */
       +                                /* nl is line number for finding data   usually identical */
       +{
       +        int        c, lf, ct, form, lwid, vspf, ip, cmidx, exvspen, vforml;
       +        int        vct, chfont, uphalf;
       +        char        *s, *size, *fn, *rct;
       +
       +        cmidx = watchout = vspf = exvspen = 0;
       +        if (i == 0) 
       +                once = 0;
       +        if (i == 0 && ( allflg || boxflg || dboxflg))
       +                fullwide(0,   dboxflg ? '=' : '-');
       +        if (instead[nl] == 0 && fullbot[nl] == 0)
       +                for (c = 0; c < ncol; c++) {
       +                        s = table[nl][c].col;
       +                        if (s == 0) 
       +                                continue;
       +                        if (vspen(s)) {
       +                                for (ip = nl; ip < nlin; ip = next(ip))
       +                                        if (!vspen(s = table[ip][c].col)) 
       +                                                break;
       +                                if ((int)s > 0 && (int)s < 128)
       +                                        Bprint(&tabout, ".ne \\n(%c|u+\\n(.Vu\n", (int)s);
       +                                continue;
       +                        }
       +                        if (point(s)) 
       +                                continue;
       +                        Bprint(&tabout, ".ne \\n(%c|u+\\n(.Vu\n", (int)s);
       +                        watchout = 1;
       +                }
       +        if (linestop[nl])
       +                Bprint(&tabout, ".mk #%c\n", linestop[nl] + 'a' - 1);
       +        lf = prev(nl);
       +        if (instead[nl]) {
       +                Bprint(&tabout, "%s\n", instead[nl]);
       +                return;
       +        }
       +        if (fullbot[nl]) {
       +                switch (ct = fullbot[nl]) {
       +                case '=':
       +                case '-':
       +                        fullwide(nl, ct);
       +                }
       +                return;
       +        }
       +        for (c = 0; c < ncol; c++) {
       +                if (instead[nl] == 0 && fullbot[nl] == 0)
       +                        if (vspen(table[nl][c].col)) 
       +                                vspf = 1;
       +                if (lf >= 0)
       +                        if (vspen(table[lf][c].col)) 
       +                                vspf = 1;
       +        }
       +        if (vspf) {
       +                Bprint(&tabout, ".nr #^ \\n(\\*(#du\n");
       +                Bprint(&tabout, ".nr #- \\n(#^\n"); /* current line position relative to bottom */
       +        }
       +        vspf = 0;
       +        chfont = 0;
       +        for (c = 0; c < ncol; c++) {
       +                s = table[nl][c].col;
       +                if (s == 0) 
       +                        continue;
       +                chfont |= (int)(font[c][stynum[nl]]);
       +                if (point(s) ) 
       +                        continue;
       +                lf = prev(nl);
       +                if (lf >= 0 && vspen(table[lf][c].col))
       +                        Bprint(&tabout,
       +                           ".if (\\n(%c|+\\n(^%c-1v)>\\n(#- .nr #- +(\\n(%c|+\\n(^%c-\\n(#--1v)\n",
       +                            (int)s, 'a' + c, (int)s, 'a' + c);
       +                else
       +                        Bprint(&tabout,
       +                            ".if (\\n(%c|+\\n(#^-1v)>\\n(#- .nr #- +(\\n(%c|+\\n(#^-\\n(#--1v)\n",
       +                            (int)s, (int)s);
       +        }
       +        if (allflg && once > 0 )
       +                fullwide(i, '-');
       +        once = 1;
       +        runtabs(i, nl);
       +        if (allh(i) && !pr1403) {
       +                Bprint(&tabout, ".nr %d \\n(.v\n", SVS);
       +                Bprint(&tabout, ".vs \\n(.vu-\\n(.sp\n");
       +                Bprint(&tabout, ".nr 35 \\n(.vu\n");
       +        } else
       +                Bprint(&tabout, ".nr 35 1m\n");
       +        if (chfont)
       +                Bprint(&tabout, ".nr %2d \\n(.f\n", S1);
       +        Bprint(&tabout, "\\&");
       +        vct = 0;
       +        for (c = 0; c < ncol; c++) {
       +                uphalf = 0;
       +                if (watchout == 0 && i + 1 < nlin && (lf = left(i, c, &lwid)) >= 0) {
       +                        tohcol(c);
       +                        drawvert(lf, i, c, lwid);
       +                        vct += 2;
       +                }
       +                if (rightl && c + 1 == ncol) 
       +                        continue;
       +                vforml = i;
       +                for (lf = prev(nl); lf >= 0 && vspen(table[lf][c].col); lf = prev(lf))
       +                        vforml = lf;
       +                form = ctype(vforml, c);
       +                if (form != 's') {
       +                        rct = reg(c, CLEFT);
       +                        if (form == 'a') 
       +                                rct = reg(c, CMID);
       +                        if (form == 'n' && table[nl][c].rcol && lused[c] == 0) 
       +                                rct = reg(c, CMID);
       +                        Bprint(&tabout, "\\h'|\\n(%2su'", rct);
       +                }
       +                s = table[nl][c].col;
       +                fn = font[c][stynum[vforml]];
       +                size = csize[c][stynum[vforml]];
       +                if (*size == 0)
       +                        size = 0;
       +                if ((flags[c][stynum[nl]] & HALFUP) != 0 && pr1403 == 0)
       +                        uphalf = 1;
       +                switch (ct = ctype(vforml, c)) {
       +                case 'n':
       +                case 'a':
       +                        if (table[nl][c].rcol) {
       +                                if (lused[c]) /*Zero field width*/ {
       +                                        ip = prev(nl);
       +                                        if (ip >= 0)
       +                                                if (vspen(table[ip][c].col)) {
       +                                                        if (exvspen == 0) {
       +                                                                Bprint(&tabout, "\\v'-(\\n(\\*(#du-\\n(^%cu", c + 'a');
       +                                                                if (cmidx)
       +/* code folded from here */
       +        Bprint(&tabout, "-((\\n(#-u-\\n(^%cu)/2u)", c + 'a');
       +/* unfolding */
       +                                                                vct++;
       +                                                                if (pr1403) /* must round to whole lines */
       +/* code folded from here */
       +        Bprint(&tabout, "/1v*1v");
       +/* unfolding */
       +                                                                Bprint(&tabout, "'");
       +                                                                exvspen = 1;
       +                                                        }
       +                                                }
       +                                        Bprint(&tabout, "%c%c", F1, F2);
       +                                        if (uphalf) 
       +                                                Bprint(&tabout, "\\u");
       +                                        puttext(s, fn, size);
       +                                        if (uphalf) 
       +                                                Bprint(&tabout, "\\d");
       +                                        Bprint(&tabout, "%c", F1);
       +                                }
       +                                s = table[nl][c].rcol;
       +                                form = 1;
       +                                break;
       +                        }
       +                case 'c':
       +                        form = 3; 
       +                        break;
       +                case 'r':
       +                        form = 2; 
       +                        break;
       +                case 'l':
       +                        form = 1; 
       +                        break;
       +                case '-':
       +                case '=':
       +                        if (real(table[nl][c].col))
       +                                fprint(2, "%s: line %d: Data ignored on table line %d\n", ifile, iline - 1, i + 1);
       +                        makeline(i, c, ct);
       +                        continue;
       +                default:
       +                        continue;
       +                }
       +                if (realsplit ? rused[c] : used[c]) /*Zero field width*/ {
       +                        /* form: 1 left, 2 right, 3 center adjust */
       +                        if (ifline(s)) {
       +                                makeline(i, c, ifline(s));
       +                                continue;
       +                        }
       +                        if (filler(s)) {
       +                                Bprint(&tabout, "\\l'|\\n(%2su\\&%s'", reg(c, CRIGHT), s + 2);
       +                                continue;
       +                        }
       +                        ip = prev(nl);
       +                        cmidx = (flags[c][stynum[nl]] & (CTOP | CDOWN)) == 0;
       +                        if (ip >= 0)
       +                                if (vspen(table[ip][c].col)) {
       +                                        if (exvspen == 0) {
       +                                                Bprint(&tabout, "\\v'-(\\n(\\*(#du-\\n(^%cu", c + 'a');
       +                                                if (cmidx)
       +                                                        Bprint(&tabout, "-((\\n(#-u-\\n(^%cu)/2u)", c + 'a');
       +                                                vct++;
       +                                                if (pr1403) /* round to whole lines */
       +                                                        Bprint(&tabout, "/1v*1v");
       +                                                Bprint(&tabout, "'");
       +                                        }
       +                                }
       +                        Bprint(&tabout, "%c", F1);
       +                        if (form != 1)
       +                                Bprint(&tabout, "%c", F2);
       +                        if (vspen(s))
       +                                vspf = 1;
       +                        else
       +                         {
       +                                if (uphalf) 
       +                                        Bprint(&tabout, "\\u");
       +                                puttext(s, fn, size);
       +                                if (uphalf) 
       +                                        Bprint(&tabout, "\\d");
       +                        }
       +                        if (form != 2)
       +                                Bprint(&tabout, "%c", F2);
       +                        Bprint(&tabout, "%c", F1);
       +                }
       +                ip = prev(nl);
       +                if (ip >= 0)
       +                        if (vspen(table[ip][c].col)) {
       +                                exvspen = (c + 1 < ncol) && vspen(table[ip][c+1].col) && 
       +                                    (topat[c] == topat[c+1]) && 
       +                                    (cmidx == (flags[c+1] [stynum[nl]] & (CTOP | CDOWN) == 0))
       +                                     && (left(i, c + 1, &lwid) < 0);
       +                                if (exvspen == 0) {
       +                                        Bprint(&tabout, "\\v'(\\n(\\*(#du-\\n(^%cu", c + 'a');
       +                                        if (cmidx)
       +                                                Bprint(&tabout, "-((\\n(#-u-\\n(^%cu)/2u)", c + 'a');
       +                                        vct++;
       +                                        if (pr1403) /* round to whole lines */
       +                                                Bprint(&tabout, "/1v*1v");
       +                                        Bprint(&tabout, "'");
       +                                }
       +                        }
       +                        else
       +                                exvspen = 0;
       +                /* if lines need to be split for gcos here is the place for a backslash */
       +                if (vct > 7 && c < ncol) {
       +                        Bprint(&tabout, "\n.sp-1\n\\&");
       +                        vct = 0;
       +                }
       +        }
       +        Bprint(&tabout, "\n");
       +        if (allh(i) && !pr1403) 
       +                Bprint(&tabout, ".vs \\n(%du\n", SVS);
       +        if (watchout)
       +                funnies(i, nl);
       +        if (vspf) {
       +                for (c = 0; c < ncol; c++)
       +                        if (vspen(table[nl][c].col) && (nl == 0 || (lf = prev(nl)) < 0 ||
       +                            !vspen(table[lf][c].col))) {
       +                                Bprint(&tabout, ".nr ^%c \\n(#^u\n", 'a' + c);
       +                                topat[c] = nl;
       +                        }
       +        }
       +}
       +
       +
       +void
       +puttext(char *s, char *fn, char *size)
       +{
       +        if (point(s)) {
       +                putfont(fn);
       +                putsize(size);
       +                Bprint(&tabout, "%s", s);
       +                if (*fn > 0) 
       +                        Bprint(&tabout, "\\f\\n(%2d", S1);
       +                if (size != 0) 
       +                        putsize("0");
       +        }
       +}
       +
       +
       +void
       +funnies(int stl, int lin)
       +{
       +                                        /* write out funny diverted things */
       +        int        c, s, pl, lwid, dv, lf, ct;
       +        char        *fn, *ss;
       +
       +        Bprint(&tabout, ".mk ##\n");         /* rmember current vertical position */
       +        Bprint(&tabout, ".nr %d \\n(##\n", S1);                 /* bottom position */
       +        for (c = 0; c < ncol; c++) {
       +                ss = table[lin][c].col;
       +                if (point(ss)) 
       +                        continue;
       +                if (ss == 0) 
       +                        continue;
       +                s = (int)ss;
       +                Bprint(&tabout, ".sp |\\n(##u-1v\n");
       +                Bprint(&tabout, ".nr %d ", SIND);
       +                ct = 0;
       +                for (pl = stl; pl >= 0 && !isalpha(ct = ctype(pl, c)); pl = prev(pl))
       +                        ;
       +                switch (ct) {
       +                case 'n':
       +                case 'c':
       +                        Bprint(&tabout, "(\\n(%2su+\\n(%2su-\\n(%c-u)/2u\n", reg(c, CLEFT),
       +                             reg(c - 1 + ctspan(lin, c), CRIGHT),
       +                             s);
       +                        break;
       +                case 'l':
       +                        Bprint(&tabout, "\\n(%2su\n", reg(c, CLEFT));
       +                        break;
       +                case 'a':
       +                        Bprint(&tabout, "\\n(%2su\n", reg(c, CMID));
       +                        break;
       +                case 'r':
       +                        Bprint(&tabout, "\\n(%2su-\\n(%c-u\n", reg(c, CRIGHT), s);
       +                        break;
       +                }
       +                Bprint(&tabout, ".in +\\n(%du\n", SIND);
       +                fn = font[c][stynum[stl]];
       +                putfont(fn);
       +                pl = prev(stl);
       +                if (stl > 0 && pl >= 0 && vspen(table[pl][c].col)) {
       +                        Bprint(&tabout, ".sp |\\n(^%cu\n", 'a' + c);
       +                        if ((flags[c][stynum[stl]] & (CTOP | CDOWN)) == 0) {
       +                                Bprint(&tabout, ".nr %d \\n(#-u-\\n(^%c-\\n(%c|+1v\n",
       +                                     TMP, 'a' + c, s);
       +                                Bprint(&tabout, ".if \\n(%d>0 .sp \\n(%du/2u", TMP, TMP);
       +                                if (pr1403)                 /* round */
       +                                        Bprint(&tabout, "/1v*1v");
       +                                Bprint(&tabout, "\n");
       +                        }
       +                }
       +                Bprint(&tabout, ".%c+\n", s);
       +                Bprint(&tabout, ".in -\\n(%du\n", SIND);
       +                if (*fn > 0) 
       +                        putfont("P");
       +                Bprint(&tabout, ".mk %d\n", S2);
       +                Bprint(&tabout, ".if \\n(%d>\\n(%d .nr %d \\n(%d\n", S2, S1, S1, S2);
       +        }
       +        Bprint(&tabout, ".sp |\\n(%du\n", S1);
       +        for (c = dv = 0; c < ncol; c++) {
       +                if (stl + 1 < nlin && (lf = left(stl, c, &lwid)) >= 0) {
       +                        if (dv++ == 0)
       +                                Bprint(&tabout, ".sp -1\n");
       +                        tohcol(c);
       +                        dv++;
       +                        drawvert(lf, stl, c, lwid);
       +                }
       +        }
       +        if (dv)
       +                Bprint(&tabout, "\n");
       +}
       +
       +
       +void
       +putfont(char *fn)
       +{
       +        if (fn && *fn)
       +                Bprint(&tabout,  fn[1] ? "\\f(%.2s" : "\\f%.2s",  fn);
       +}
       +
       +
       +void
       +putsize(char *s)
       +{
       +        if (s && *s)
       +                Bprint(&tabout, "\\s%s", s);
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/t9.c b/src/cmd/tbl/t9.c
       t@@ -0,0 +1,76 @@
       +/* t9.c: write lines for tables over 200 lines */
       +# include "t.h"
       +static useln;
       +
       +void
       +yetmore(void)
       +{
       +        for (useln = 0; useln < MAXLIN && table[useln] == 0; useln++)
       +                ;
       +        if (useln >= MAXLIN)
       +                error("Wierd.  No data in table.");
       +        table[0] = table[useln];
       +        for (useln = nlin - 1; useln >= 0 && (fullbot[useln] || instead[useln]); useln--)
       +                ;
       +        if (useln < 0)
       +                error("Wierd.  No real lines in table.");
       +        domore(leftover);
       +        while (gets1(cstore = cspace, MAXCHS) && domore(cstore))
       +                ;
       +        last = cstore;
       +        return;
       +}
       +
       +
       +int
       +domore(char *dataln)
       +{
       +        int        icol, ch;
       +
       +        if (prefix(".TE", dataln))
       +                return(0);
       +        if (dataln[0] == '.' && !isdigit(dataln[1])) {
       +                Bprint(&tabout, "%s\n", dataln);
       +                return(1);
       +        }
       +        fullbot[0] = 0;
       +        instead[0] = (char *)0;
       +        if (dataln[1] == 0)
       +                switch (dataln[0]) {
       +                case '_': 
       +                        fullbot[0] = '-'; 
       +                        putline(useln, 0);  
       +                        return(1);
       +                case '=': 
       +                        fullbot[0] = '='; 
       +                        putline(useln, 0); 
       +                        return(1);
       +                }
       +        for (icol = 0; icol < ncol; icol++) {
       +                table[0][icol].col = dataln;
       +                table[0][icol].rcol = 0;
       +                for (; (ch = *dataln) != '\0' && ch != tab; dataln++)
       +                        ;
       +                *dataln++ = '\0';
       +                switch (ctype(useln, icol)) {
       +                case 'n':
       +                        table[0][icol].rcol = maknew(table[0][icol].col);
       +                        break;
       +                case 'a':
       +                        table[0][icol].rcol = table[0][icol].col;
       +                        table[0][icol].col = "";
       +                        break;
       +                }
       +                while (ctype(useln, icol + 1) == 's') /* spanning */
       +                        table[0][++icol].col = "";
       +                if (ch == '\0') 
       +                        break;
       +        }
       +        while (++icol < ncol)
       +                table[0][icol].col = "";
       +        putline(useln, 0);
       +        exstore = exspace;                 /* reuse space for numerical items */
       +        return(1);
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/tb.c b/src/cmd/tbl/tb.c
       t@@ -0,0 +1,101 @@
       +/* tb.c: check which entries exist, also storage allocation */
       +# include "t.h"
       +
       +void
       +checkuse(void)
       +{
       +        int        i, c, k;
       +
       +        for (c = 0; c < ncol; c++) {
       +                used[c] = lused[c] = rused[c] = 0;
       +                for (i = 0; i < nlin; i++) {
       +                        if (instead[i] || fullbot[i]) 
       +                                continue;
       +                        k = ctype(i, c);
       +                        if (k == '-' || k == '=') 
       +                                continue;
       +                        if ((k == 'n' || k == 'a')) {
       +                                rused[c] |= real(table[i][c].rcol);
       +                                if ( !real(table[i][c].rcol))
       +                                        used[c] |= real(table[i][c].col);
       +                                if (table[i][c].rcol)
       +                                        lused[c] |= real(table[i][c].col);
       +                        } else
       +                                used[c] |= real(table[i][c].col);
       +                }
       +        }
       +}
       +
       +
       +int
       +real(char *s)
       +{
       +        if (s == 0) 
       +                return(0);
       +        if (!point(s)) 
       +                return(1);
       +        if (*s == 0) 
       +                return(0);
       +        return(1);
       +}
       +
       +
       +int        spcount = 0;
       +# define MAXVEC 20
       +char        *spvecs[MAXVEC];
       +
       +char        *
       +chspace(void)
       +{
       +        char        *pp;
       +
       +        if (spvecs[spcount])
       +                return(spvecs[spcount++]);
       +        if (spcount >= MAXVEC)
       +                error("Too many characters in table");
       +        spvecs[spcount++] = pp = calloc(MAXCHS + MAXLINLEN, 1);
       +        if (pp == (char *) - 1 || pp == (char *)0)
       +                error("no space for characters");
       +        return(pp);
       +}
       +
       +
       +# define MAXPC 50
       +char        *thisvec;
       +int        tpcount = -1;
       +char        *tpvecs[MAXPC];
       +
       +int        *
       +alocv(int n)
       +{
       +        int        *tp, *q;
       +
       +        if (tpcount < 0 || thisvec + n > tpvecs[tpcount] + MAXCHS) {
       +                tpcount++;
       +                if (tpvecs[tpcount] == 0) {
       +                        tpvecs[tpcount] = calloc(MAXCHS, 1);
       +                }
       +                thisvec = tpvecs[tpcount];
       +                if (thisvec == (char *)0)
       +                        error("no space for vectors");
       +        }
       +        tp = (int *)thisvec;
       +        thisvec += n;
       +        for (q = tp; q < (int *)thisvec; q++)
       +                *q = 0;
       +        return(tp);
       +}
       +
       +
       +void
       +release(void)
       +{
       +                        /* give back unwanted space in some vectors */
       +                        /* this should call free; it does not because
       +                                alloc() is so buggy */
       +        spcount = 0;
       +        tpcount = -1;
       +        exstore = 0;
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/tc.c b/src/cmd/tbl/tc.c
       t@@ -0,0 +1,65 @@
       +/* tc.c: find character not in table to delimit fields */
       +# include "t.h"
       +
       +void
       +choochar(void)
       +{
       +                                /* choose funny characters to delimit fields */
       +        int        had[128], ilin, icol, k;
       +        char        *s;
       +
       +        for (icol = 0; icol < 128; icol++)
       +                had[icol] = 0;
       +        F1 = F2 = 0;
       +        for (ilin = 0; ilin < nlin; ilin++) {
       +                if (instead[ilin]) 
       +                        continue;
       +                if (fullbot[ilin]) 
       +                        continue;
       +                for (icol = 0; icol < ncol; icol++) {
       +                        k = ctype(ilin, icol);
       +                        if (k == 0 || k == '-' || k == '=')
       +                                continue;
       +                        s = table[ilin][icol].col;
       +                        if (point(s))
       +                                while (*s)
       +                                        had[*s++] = 1;
       +                        s = table[ilin][icol].rcol;
       +                        if (point(s))
       +                                while (*s)
       +                                        had[*s++] = 1;
       +                }
       +        }
       +                                /* choose first funny character */
       +        for (
       +            s = "\002\003\005\006\007!%&#/?,:;<=>@`^~_{}+-*ABCDEFGHIJKMNOPQRSTUVWXYZabcdefgjkoqrstwxyz"; 
       +            *s; s++) {
       +                if (had[*s] == 0) {
       +                        F1 = *s;
       +                        had[F1] = 1;
       +                        break;
       +                }
       +        }
       +                                /* choose second funny character */
       +        for (
       +            s = "\002\003\005\006\007:_~^`@;,<=>#%&!/?{}+-*ABCDEFGHIJKMNOPQRSTUVWXZabcdefgjkoqrstuwxyz"; 
       +            *s; s++) {
       +                if (had[*s] == 0) {
       +                        F2 = *s;
       +                        break;
       +                }
       +        }
       +        if (F1 == 0 || F2 == 0)
       +                error("couldn't find characters to use for delimiters");
       +        return;
       +}
       +
       +
       +int
       +point(char *s)
       +{
       +        int        ss = (int)s;
       +        return(ss >= 128 || ss < 0);
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/te.c b/src/cmd/tbl/te.c
       t@@ -0,0 +1,75 @@
       +/* te.c: error message control, input line count */
       +# include "t.h"
       +
       +void
       +error(char *s)
       +{
       +        fprint(2, "\n%s:%d: %s\n", ifile, iline, s);
       +        fprint(2, "tbl quits\n");
       +        exits(s);
       +}
       +
       +
       +char        *
       +gets1(char *s, int size)
       +{
       +        char        *p, *ns;
       +        int        nbl;
       +
       +        iline++;
       +        ns = s;
       +        p = Brdline(tabin, '\n');
       +        while (p == 0) {
       +                if (swapin() == 0)
       +                        return(0);
       +                p = Brdline(tabin, '\n');
       +        }
       +        nbl = Blinelen(tabin)-1;
       +        if(nbl >= size)
       +                error("input buffer too small");
       +        p[nbl] = 0;
       +        strcpy(s, p);
       +        s += nbl;
       +        for (nbl = 0; *s == '\\' && s > ns; s--)
       +                nbl++;
       +        if (linstart && nbl % 2) /* fold escaped nl if in table */
       +                gets1(s + 1, size - (s-ns));
       +
       +        return(p);
       +}
       +
       +
       +# define BACKMAX 500
       +char        backup[BACKMAX];
       +char        *backp = backup;
       +
       +void
       +un1getc(int c)
       +{
       +        if (c == '\n')
       +                iline--;
       +        *backp++ = c;
       +        if (backp >= backup + BACKMAX)
       +                error("too much backup");
       +}
       +
       +
       +int
       +get1char(void)
       +{
       +        int        c;
       +        if (backp > backup)
       +                c = *--backp;
       +        else
       +                c = Bgetc(tabin);
       +        if (c == 0) /* EOF */ {
       +                if (swapin() == 0)
       +                        error("unexpected EOF");
       +                c = Bgetc(tabin);
       +        }
       +        if (c == '\n')
       +                iline++;
       +        return(c);
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/tf.c b/src/cmd/tbl/tf.c
       t@@ -0,0 +1,74 @@
       +/* tf.c: save and restore fill mode around table */
       +# include "t.h"
       +
       +void
       +savefill(void)
       +{
       +                        /* remembers various things: fill mode, vs, ps in mac 35 (SF) */
       +        Bprint(&tabout, ".de %d\n", SF);
       +        Bprint(&tabout, ".ps \\n(.s\n");
       +        Bprint(&tabout, ".vs \\n(.vu\n");
       +        Bprint(&tabout, ".in \\n(.iu\n");
       +        Bprint(&tabout, ".if \\n(.u .fi\n");
       +        Bprint(&tabout, ".if \\n(.j .ad\n");
       +        Bprint(&tabout, ".if \\n(.j=0 .na\n");
       +        Bprint(&tabout, "..\n");
       +        Bprint(&tabout, ".nf\n");
       +        /* set obx offset if useful */
       +        Bprint(&tabout, ".nr #~ 0\n");
       +        Bprint(&tabout, ".if \\n(.T .if n .nr #~ 0.6n\n");
       +}
       +
       +
       +void
       +rstofill(void)
       +{
       +        Bprint(&tabout, ".%d\n", SF);
       +}
       +
       +
       +void
       +endoff(void)
       +{
       +        int        i;
       +
       +        for (i = 0; i < MAXHEAD; i++)
       +                if (linestop[i])
       +                        Bprint(&tabout, ".nr #%c 0\n", linestop[i] + 'a' - 1);
       +        for (i = 0; i < texct; i++)
       +                Bprint(&tabout, ".rm %c+\n", texstr[i]);
       +        Bprint(&tabout, "%s\n", last);
       +}
       +
       +
       +void
       +ifdivert(void)
       +{
       +        Bprint(&tabout, ".ds #d .d\n");
       +        Bprint(&tabout, ".if \\(ts\\n(.z\\(ts\\(ts .ds #d nl\n");
       +}
       +
       +
       +void
       +saveline(void)
       +{
       +        Bprint(&tabout, ".if \\n+(b.=1 .nr d. \\n(.c-\\n(c.-1\n");
       +        linstart = iline;
       +}
       +
       +
       +void
       +restline(void)
       +{
       +        Bprint(&tabout, ".if \\n-(b.=0 .nr c. \\n(.c-\\n(d.-%d\n", iline - linstart);
       +        linstart = 0;
       +}
       +
       +
       +void
       +cleanfc(void)
       +{
       +        Bprint(&tabout, ".fc\n");
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/tg.c b/src/cmd/tbl/tg.c
       t@@ -0,0 +1,81 @@
       +/* tg.c: process included text blocks */
       +# include "t.h"
       +
       +int
       +gettext(char *sp, int ilin, int icol, char *fn, char *sz)
       +{
       +                                        /* get a section of text */
       +        char        line[4096];
       +        int        oname;
       +        char        *vs;
       +
       +        if (texname == 0) 
       +                error("Too many text block diversions");
       +        if (textflg == 0) {
       +                Bprint(&tabout, ".nr %d \\n(.lu\n", SL); /* remember old line length */
       +                textflg = 1;
       +        }
       +        Bprint(&tabout, ".eo\n");
       +        Bprint(&tabout, ".am %s\n", reg(icol, CRIGHT));
       +        Bprint(&tabout, ".br\n");
       +        Bprint(&tabout, ".di %c+\n", texname);
       +        rstofill();
       +        if (fn && *fn) 
       +                Bprint(&tabout, ".nr %d \\n(.f\n.ft %s\n", S1, fn);
       +        Bprint(&tabout, ".ft \\n(.f\n"); /* protect font */
       +        vs = vsize[icol][stynum[ilin]];
       +        if ((sz && *sz) || (vs && *vs)) {
       +                Bprint(&tabout, ".nr %d \\n(.v\n", S9);
       +                if (vs == 0 || *vs == 0) 
       +                        vs = "\\n(.s+2";
       +                if (sz && *sz)
       +                        Bprint(&tabout, ".ps %s\n", sz);
       +                Bprint(&tabout, ".vs %s\n", vs);
       +                Bprint(&tabout, ".if \\n(%du>\\n(.vu .sp \\n(%du-\\n(.vu\n", S9, S9);
       +        }
       +        if (cll[icol][0])
       +                Bprint(&tabout, ".ll %sn\n", cll[icol]);
       +        else
       +                Bprint(&tabout, ".ll \\n(%du*%du/%du\n", SL, ctspan(ilin, icol), ncol + 1);
       +        Bprint(&tabout, ".if \\n(.l<\\n(%2s .ll \\n(%2su\n", reg(icol, CRIGHT),
       +             reg(icol, CRIGHT));
       +        if (ctype(ilin, icol) == 'a')
       +                Bprint(&tabout, ".ll -2n\n");
       +        Bprint(&tabout, ".in 0\n");
       +        while (gets1(line, sizeof(line))) {
       +                if (line[0] == 'T' && line[1] == '}' && line[2] == tab) 
       +                        break;
       +                if (match("T}", line)) 
       +                        break;
       +                Bprint(&tabout, "%s\n", line);
       +        }
       +        if (fn && *fn) 
       +                Bprint(&tabout, ".ft \\n(%d\n", S1);
       +        if (sz && *sz) 
       +                Bprint(&tabout, ".br\n.ps\n.vs\n");
       +        Bprint(&tabout, ".br\n");
       +        Bprint(&tabout, ".di\n");
       +        Bprint(&tabout, ".nr %c| \\n(dn\n", texname);
       +        Bprint(&tabout, ".nr %c- \\n(dl\n", texname);
       +        Bprint(&tabout, "..\n");
       +        Bprint(&tabout, ".ec \\\n");
       +        /* copy remainder of line */
       +        if (line[2])
       +                tcopy (sp, line + 3);
       +        else
       +                *sp = 0;
       +        oname = texname;
       +        texname = texstr[++texct];
       +        return(oname);
       +}
       +
       +
       +void
       +untext(void)
       +{
       +        rstofill();
       +        Bprint(&tabout, ".nf\n");
       +        Bprint(&tabout, ".ll \\n(%du\n", SL);
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/ti.c b/src/cmd/tbl/ti.c
       t@@ -0,0 +1,75 @@
       +/* ti.c: classify line intersections */
       +# include "t.h"
       +/* determine local environment for intersections */
       +
       +int
       +interv(int i, int c)
       +{
       +        int        ku, kl;
       +
       +        if (c >= ncol || c == 0) {
       +                if (dboxflg) {
       +                        if (i == 0) 
       +                                return(BOT);
       +                        if (i >= nlin) 
       +                                return(TOP);
       +                        return(THRU);
       +                }
       +                if (c >= ncol)
       +                        return(0);
       +        }
       +        ku = i > 0 ? lefdata(i - 1, c) : 0;
       +        if (i + 1 >= nlin && allh(i))
       +                kl = 0;
       +        else
       +                kl = lefdata(allh(i) ? i + 1 : i, c);
       +        if (ku == 2 && kl == 2) 
       +                return(THRU);
       +        if (ku == 2) 
       +                return(TOP);
       +        if (kl == BOT) 
       +                return(2);
       +        return(0);
       +}
       +
       +
       +int
       +interh(int i, int c)
       +{
       +        int        kl, kr;
       +
       +        if (fullbot[i] == '=' || (dboxflg && (i == 0 || i >= nlin - 1))) {
       +                if (c == ncol)
       +                        return(LEFT);
       +                if (c == 0)
       +                        return(RIGHT);
       +                return(THRU);
       +        }
       +        if (i >= nlin) 
       +                return(0);
       +        kl = c > 0 ? thish (i, c - 1) : 0;
       +        if (kl <= 1 && i > 0 && allh(up1(i)))
       +                kl = c > 0 ? thish(up1(i), c - 1) : 0;
       +        kr = thish(i, c);
       +        if (kr <= 1 && i > 0 && allh(up1(i)))
       +                kr = c > 0 ? thish(up1(i), c) : 0;
       +        if (kl == '=' && kr ==  '=') 
       +                return(THRU);
       +        if (kl == '=') 
       +                return(LEFT);
       +        if (kr == '=') 
       +                return(RIGHT);
       +        return(0);
       +}
       +
       +
       +int
       +up1(int i)
       +{
       +        i--;
       +        while (instead[i] && i > 0) 
       +                i--;
       +        return(i);
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/tm.c b/src/cmd/tbl/tm.c
       t@@ -0,0 +1,65 @@
       +/* tm.c: split numerical fields */
       +# include "t.h"
       +
       +char        *
       +maknew(char *str)
       +{
       +                                /* make two numerical fields */
       +        int        dpoint, c;
       +        char        *p, *q, *ba;
       +
       +        p = str;
       +        for (ba = 0; c = *str; str++)
       +                if (c == '\\' && *(str + 1) == '&')
       +                        ba = str;
       +        str = p;
       +        if (ba == 0) {
       +                for (dpoint = 0; *str; str++) {
       +                        if (*str == '.' && !ineqn(str, p) && 
       +                            (str > p && digit(*(str - 1)) || 
       +                            digit(*(str + 1))))
       +                                dpoint = (int)str;
       +                }
       +                if (dpoint == 0)
       +                        for (; str > p; str--) {
       +                                if (digit( *(str - 1) ) && !ineqn(str, p))
       +                                        break;
       +                        }
       +                if (!dpoint && p == str) /* not numerical, don't split */
       +                        return(0);
       +                if (dpoint) 
       +                        str = (char *)dpoint;
       +        } else
       +                str = ba;
       +        p = str;
       +        if (exstore == 0 || exstore > exlim) {
       +                exstore = exspace = chspace();
       +                exlim = exstore + MAXCHS;
       +        }
       +        q = exstore;
       +        while (*exstore++ = *str++)
       +                ;
       +        *p = 0;
       +        return(q);
       +}
       +
       +
       +int
       +ineqn (char *s, char *p)
       +{
       +                                /* true if s is in a eqn within p */
       +        int        ineq = 0, c;
       +
       +        while (c = *p) {
       +                if (s == p)
       +                        return(ineq);
       +                p++;
       +                if ((ineq == 0) && (c == delim1))
       +                        ineq = 1;
       +                else if ((ineq == 1) && (c == delim2))
       +                        ineq = 0;
       +        }
       +        return(0);
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/tr.c b/src/cmd/tbl/tr.c
       t@@ -0,0 +1,28 @@
       +# include "t.h"
       +/* tr.c: number register allocation */
       +char        *nregs[] = {
       +        /* this array must have at least 3*qcol entries
       +           or illegal register names will result */
       +        "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
       +        "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
       +        "60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
       +        "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
       +        "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
       +        "90", "91", "92", "93", "94", "95", "96", "97", "4q", "4r",
       +        "4s", "4t", "4u", "4v", "4w", "4x", "4y", "4z", "4;", "4.",
       +        "4a", "4b", "4c", "4d", "4e", "4f", "4g", "4h", "4i", "4j",
       +        "4k", "4l", "4m", "4n", "4o", "4p", "5a", "5b", "5c", "5d",
       +        "5e", "5f", "5g", "5h", "5i", "5j", "5k", "5l", "5m", "5n",
       +        "5o", "5p", "5q", "5r", "5s", "5t", "5u", "5v", "5w", "5x",
       +        0};
       +
       +
       +char        *
       +reg(int col, int place)
       +{
       +        if (sizeof(nregs) < 2 * 3 * qcol)
       +                error("Too many columns for registers");
       +        return (nregs[qcol*place+col]);
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/ts.c b/src/cmd/tbl/ts.c
       t@@ -0,0 +1,71 @@
       +/* ts.c: minor string processing subroutines */
       +#include "t.h"
       +
       +int
       +match (char *s1, char *s2)
       +{
       +        while (*s1 == *s2)
       +                if (*s1++ == '\0')
       +                        return(1);
       +                else
       +                        s2++;
       +        return(0);
       +}
       +
       +
       +int
       +prefix(char *small, char *big)
       +{
       +        int        c;
       +
       +        while ((c = *small++) == *big++)
       +                if (c == 0) 
       +                        return(1);
       +        return(c == 0);
       +}
       +
       +
       +int
       +letter (int ch)
       +{
       +        if (ch >= 'a' && ch <= 'z')
       +                return(1);
       +        if (ch >= 'A' && ch <= 'Z')
       +                return(1);
       +        return(0);
       +}
       +
       +
       +int
       +numb(char *str)
       +{
       +                                /* convert to integer */
       +        int        k;
       +        for (k = 0; *str >= '0' && *str <= '9'; str++)
       +                k = k * 10 + *str - '0';
       +        return(k);
       +}
       +
       +
       +int
       +digit(int x)
       +{
       +        return(x >= '0' && x <= '9');
       +}
       +
       +
       +int
       +max(int a, int b)
       +{
       +        return( a > b ? a : b);
       +}
       +
       +
       +void
       +tcopy (char *s, char *t)
       +{
       +        while (*s++ = *t++)
       +                ;
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/tt.c b/src/cmd/tbl/tt.c
       t@@ -0,0 +1,127 @@
       +/* tt.c: subroutines for drawing horizontal lines */
       +# include "t.h"
       +
       +int
       +ctype(int il, int ic)
       +{
       +        if (instead[il])
       +                return(0);
       +        if (fullbot[il])
       +                return(0);
       +        il = stynum[il];
       +        return(style[ic][il]);
       +}
       +
       +
       +int
       +min(int a, int b)
       +{
       +        return(a < b ? a : b);
       +}
       +
       +
       +int
       +fspan(int i, int c)
       +{
       +        c++;
       +        return(c < ncol && ctype(i, c) == 's');
       +}
       +
       +
       +int
       +lspan(int i, int c)
       +{
       +        int        k;
       +
       +        if (ctype(i, c) != 's') 
       +                return(0);
       +        c++;
       +        if (c < ncol && ctype(i, c) == 's')
       +                return(0);
       +        for (k = 0; ctype(i, --c) == 's'; k++)
       +                ;
       +        return(k);
       +}
       +
       +
       +int
       +ctspan(int i, int c)
       +{
       +        int        k;
       +        c++;
       +        for (k = 1; c < ncol && ctype(i, c) == 's'; k++)
       +                c++;
       +        return(k);
       +}
       +
       +
       +void
       +tohcol(int ic)
       +{
       +        if (ic == 0)
       +                Bprint(&tabout, "\\h'|0'");
       +        else
       +                Bprint(&tabout, "\\h'(|\\n(%2su+|\\n(%2su)/2u'", reg(ic, CLEFT),
       +                     reg(ic - 1, CRIGHT));
       +}
       +
       +
       +int
       +allh(int i)
       +{
       +                        /* return true if every element in line i is horizontal */
       +                                /* also at least one must be horizontl */
       +        int        c, one, k;
       +
       +        if (fullbot[i]) 
       +                return(1);
       +        if (i >= nlin) 
       +                return(dboxflg || boxflg);
       +        for (one = c = 0; c < ncol; c++) {
       +                k = thish(i, c);
       +                if (k == 0) 
       +                        return(0);
       +                if (k == 1) 
       +                        continue;
       +                one = 1;
       +        }
       +        return(one);
       +}
       +
       +
       +int
       +thish(int i, int c)
       +{
       +        int        t;
       +        char        *s;
       +        struct colstr *pc;
       +
       +        if (c < 0)
       +                return(0);
       +        if (i < 0) 
       +                return(0);
       +        t = ctype(i, c);
       +        if (t == '_' || t == '-')
       +                return('-');
       +        if (t == '=')
       +                return('=');
       +        if (t == '^') 
       +                return(1);
       +        if (fullbot[i] )
       +                return(fullbot[i]);
       +        if (t == 's') 
       +                return(thish(i, c - 1));
       +        if (t == 0) 
       +                return(1);
       +        pc = &table[i][c];
       +        s = (t == 'a' ? pc->rcol : pc->col);
       +        if (s == 0 || (point(s) && *s == 0))
       +                return(1);
       +        if (vspen(s)) 
       +                return(1);
       +        if (t = barent( s))
       +                return(t);
       +        return(0);
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/tu.c b/src/cmd/tbl/tu.c
       t@@ -0,0 +1,257 @@
       +/* tu.c: draws horizontal lines */
       +# include "t.h"
       +
       +void
       +makeline(int i, int c, int lintype)
       +{
       +        int        cr, type, shortl;
       +
       +        type = thish(i, c);
       +        if (type == 0) 
       +                return;
       +        shortl = (table[i][c].col[0] == '\\');
       +        if (c > 0 && !shortl && thish(i, c - 1) == type)
       +                return;
       +        if (shortl == 0)
       +                for (cr = c; cr < ncol && (ctype(i, cr) == 's' || type == thish(i, cr)); cr++)
       +                        ;
       +        else
       +                for (cr = c + 1; cr < ncol && ctype(i, cr) == 's'; cr++)
       +                        ;
       +        drawline(i, c, cr - 1, lintype, 0, shortl);
       +}
       +
       +
       +void
       +fullwide(int i, int lintype)
       +{
       +        int        cr, cl;
       +
       +        if (!pr1403)
       +                Bprint(&tabout, ".nr %d \\n(.v\n.vs \\n(.vu-\\n(.sp\n", SVS);
       +        cr = 0;
       +        while (cr < ncol) {
       +                cl = cr;
       +                while (i > 0 && vspand(prev(i), cl, 1))
       +                        cl++;
       +                for (cr = cl; cr < ncol; cr++)
       +                        if (i > 0 && vspand(prev(i), cr, 1))
       +                                break;
       +                if (cl < ncol)
       +                        drawline(i, cl, (cr < ncol ? cr - 1 : cr), lintype, 1, 0);
       +        }
       +        Bprint(&tabout, "\n");
       +        if (!pr1403)
       +                Bprint(&tabout, ".vs \\n(%du\n", SVS);
       +}
       +
       +
       +void
       +drawline(int i, int cl, int cr, int lintype, int noheight, int shortl)
       +{
       +        char        *exhr, *exhl, *lnch;
       +        int        lcount, ln, linpos, oldpos, nodata;
       +
       +        lcount = 0;
       +        exhr = exhl = "";
       +        switch (lintype) {
       +        case '-': 
       +                lcount = 1;
       +                break;
       +        case '=': 
       +                lcount = pr1403 ? 1 : 2; 
       +                break;
       +        case SHORTLINE: 
       +                lcount = 1; 
       +                break;
       +        }
       +        if (lcount <= 0) 
       +                return;
       +        nodata = cr - cl >= ncol || noheight || allh(i);
       +        if (!nodata)
       +                Bprint(&tabout, "\\v'-.5m'");
       +        for (ln = oldpos = 0; ln < lcount; ln++) {
       +                linpos = 2 * ln - lcount + 1;
       +                if (linpos != oldpos)
       +                        Bprint(&tabout, "\\v'%dp'", linpos - oldpos);
       +                oldpos = linpos;
       +                if (shortl == 0) {
       +                        tohcol(cl);
       +                        if (lcount > 1) {
       +                                switch (interv(i, cl)) {
       +                                case TOP: 
       +                                        exhl = ln == 0 ? "1p" : "-1p"; 
       +                                        break;
       +                                case BOT: 
       +                                        exhl = ln == 1 ? "1p" : "-1p"; 
       +                                        break;
       +                                case THRU: 
       +                                        exhl = "1p"; 
       +                                        break;
       +                                }
       +                                if (exhl[0])
       +                                        Bprint(&tabout, "\\h'%s'", exhl);
       +                        } else if (lcount == 1) {
       +                                switch (interv(i, cl)) {
       +                                case TOP: 
       +                                case BOT: 
       +                                        exhl = "-1p"; 
       +                                        break;
       +                                case THRU: 
       +                                        exhl = "1p"; 
       +                                        break;
       +                                }
       +                                if (exhl[0])
       +                                        Bprint(&tabout, "\\h'%s'", exhl);
       +                        }
       +                        if (lcount > 1) {
       +                                switch (interv(i, cr + 1)) {
       +                                case TOP: 
       +                                        exhr = ln == 0 ? "-1p" : "+1p"; 
       +                                        break;
       +                                case BOT: 
       +                                        exhr = ln == 1 ? "-1p" : "+1p"; 
       +                                        break;
       +                                case THRU: 
       +                                        exhr = "-1p"; 
       +                                        break;
       +                                }
       +                        } else if (lcount == 1) {
       +                                switch (interv(i, cr + 1)) {
       +                                case TOP: 
       +                                case BOT: 
       +                                        exhr = "+1p"; 
       +                                        break;
       +                                case THRU: 
       +                                        exhr = "-1p"; 
       +                                        break;
       +                                }
       +                        }
       +                } else
       +                        Bprint(&tabout, "\\h'|\\n(%2su'", reg(cl, CLEFT));
       +                Bprint(&tabout, "\\s\\n(%d", LSIZE);
       +                if (linsize)
       +                        Bprint(&tabout, "\\v'-\\n(%dp/6u'", LSIZE);
       +                if (shortl)
       +                        Bprint(&tabout, "\\l'|\\n(%2su'", reg(cr, CRIGHT));
       +                else
       +                 {
       +                        lnch = "\\(ul";
       +                        if (pr1403)
       +                                lnch = lintype == 2 ? "=" : "\\(ru";
       +                        if (cr + 1 >= ncol)
       +                                Bprint(&tabout, "\\l'|\\n(TWu%s%s'", exhr, lnch);
       +                        else
       +                                Bprint(&tabout, "\\l'(|\\n(%2su+|\\n(%2su)/2u%s%s'", reg(cr, CRIGHT),
       +                                    reg(cr + 1, CLEFT), exhr, lnch);
       +                }
       +                if (linsize)
       +                        Bprint(&tabout, "\\v'\\n(%dp/6u'", LSIZE);
       +                Bprint(&tabout, "\\s0");
       +        }
       +        if (oldpos != 0)
       +                Bprint(&tabout, "\\v'%dp'", -oldpos);
       +        if (!nodata)
       +                Bprint(&tabout, "\\v'+.5m'");
       +}
       +
       +
       +void
       +getstop(void)
       +{
       +        int        i, c, k, junk, stopp;
       +
       +        stopp = 1;
       +        for (i = 0; i < MAXLIN; i++)
       +                linestop[i] = 0;
       +        for (i = 0; i < nlin; i++)
       +                for (c = 0; c < ncol; c++) {
       +                        k = left(i, c, &junk);
       +                        if (k >= 0 && linestop[k] == 0)
       +                                linestop[k] = ++stopp;
       +                }
       +        if (boxflg || allflg || dboxflg)
       +                linestop[0] = 1;
       +}
       +
       +
       +int
       +left(int i, int c, int *lwidp)
       +{
       +        int        kind, li, lj;
       +                                        /* returns -1 if no line to left */
       +                                        /* returns number of line where it starts */
       +                                        /* stores into lwid the kind of line */
       +        *lwidp = 0;
       +        if (i < 0) 
       +                return(-1);
       +        kind = lefdata(i, c);
       +        if (kind == 0) 
       +                return(-1);
       +        if (i + 1 < nlin)
       +                if (lefdata(next(i), c) == kind) 
       +                        return(-1);
       +        li = i;
       +        while (i >= 0 && lefdata(i, c) == kind)
       +                i = prev(li = i);
       +        if (prev(li) == -1) 
       +                li = 0;
       +        *lwidp = kind;
       +        for (lj = i + 1; lj < li; lj++)
       +                if (instead[lj] && strcmp(instead[lj], ".TH") == 0)
       +                        return(li);
       +        for (i = i + 1; i < li; i++)
       +                if (fullbot[i])
       +                        li = i;
       +        return(li);
       +}
       +
       +
       +int
       +lefdata(int i, int c)
       +{
       +        int        ck;
       +
       +        if (i >= nlin) 
       +                i = nlin - 1;
       +        if (ctype(i, c) == 's') {
       +                for (ck = c; ctype(i, ck) == 's'; ck--)
       +                        ;
       +                if (thish(i, ck) == 0)
       +                        return(0);
       +        }
       +        i = stynum[i];
       +        i = lefline[c][i];
       +        if (i > 0) 
       +                return(i);
       +        if (dboxflg && c == 0) 
       +                return(2);
       +        if (allflg)
       +                return(1);
       +        if (boxflg && c == 0) 
       +                return(1);
       +        return(0);
       +}
       +
       +
       +int
       +next(int i)
       +{
       +        while (i + 1 < nlin) {
       +                i++;
       +                if (!fullbot[i] && !instead[i]) 
       +                        break;
       +        }
       +        return(i);
       +}
       +
       +
       +int
       +prev(int i)
       +{
       +        while (--i >= 0  && (fullbot[i] || instead[i]))
       +                ;
       +        return(i);
       +}
       +
       +
 (DIR) diff --git a/src/cmd/tbl/tv.c b/src/cmd/tbl/tv.c
       t@@ -0,0 +1,183 @@
       +/* tv.c: draw vertical lines */
       +# include "t.h"
       +
       +void
       +drawvert(int start, int end, int c, int lwid)
       +{
       +        char        *exb = 0, *ext = 0;
       +        int        tp = 0, sl, ln, pos, epb, ept, vm;
       +
       +        end++;
       +        vm = 'v';
       +                                /* note: nr 35 has value of 1m outside of linesize */
       +        while (instead[end]) 
       +                end++;
       +        for (ln = 0; ln < lwid; ln++) {
       +                epb = ept = 0;
       +                pos = 2 * ln - lwid + 1;
       +                if (pos != tp) 
       +                        Bprint(&tabout, "\\h'%dp'", pos - tp);
       +                tp = pos;
       +                if (end < nlin) {
       +                        if (fullbot[end] || (!instead[end] && allh(end)))
       +                                epb = 2;
       +                        else
       +                                switch (midbar(end, c)) {
       +                                case '-':
       +                                        exb = "1v-.5m"; 
       +                                        break;
       +                                case '=':
       +                                        exb = "1v-.5m";
       +                                        epb = 1; 
       +                                        break;
       +                                }
       +                }
       +                if (lwid > 1)
       +                        switch (interh(end, c)) {
       +                        case THRU: 
       +                                epb -= 1; 
       +                                break;
       +                        case RIGHT: 
       +                                epb += (ln == 0 ? 1 : -1); 
       +                                break;
       +                        case LEFT: 
       +                                epb += (ln == 1 ? 1 : -1); 
       +                                break;
       +                        }
       +                if (lwid == 1)
       +                        switch (interh(end, c)) {
       +                        case THRU: 
       +                                epb -= 1; 
       +                                break;
       +                        case RIGHT: 
       +                        case LEFT: 
       +                                epb += 1; 
       +                                break;
       +                        }
       +                if (start > 0) {
       +                        sl = start - 1;
       +                        while (sl >= 0 && instead[sl]) 
       +                                sl--;
       +                        if (sl >= 0 && (fullbot[sl] || allh(sl)))
       +                                ept = 0;
       +                        else if (sl >= 0)
       +                                switch (midbar(sl, c)) {
       +                                case '-':
       +                                        ext = ".5m"; 
       +                                        break;
       +                                case '=':
       +                                        ext = ".5m"; 
       +                                        ept = -1; 
       +                                        break;
       +                                default:
       +                                        vm = 'm'; 
       +                                        break;
       +                                }
       +                        else
       +                                ept = -4;
       +                } else if (start == 0 && allh(0)) {
       +                        ept = 0;
       +                        vm = 'm';
       +                }
       +                if (lwid > 1)
       +                        switch (interh(start, c)) {
       +                        case THRU: 
       +                                ept += 1; 
       +                                break;
       +                        case LEFT: 
       +                                ept += (ln == 0 ? 1 : -1); 
       +                                break;
       +                        case RIGHT: 
       +                                ept += (ln == 1 ? 1 : -1); 
       +                                break;
       +                        }
       +                else if (lwid == 1)
       +                        switch (interh(start, c)) {
       +                        case THRU: 
       +                                ept += 1; 
       +                                break;
       +                        case LEFT: 
       +                        case RIGHT: 
       +                                ept -= 1; 
       +                                break;
       +                        }
       +                if (exb)
       +                        Bprint(&tabout, "\\v'%s'", exb);
       +                if (epb)
       +                        Bprint(&tabout, "\\v'%dp'", epb);
       +                Bprint(&tabout, "\\s\\n(%d", LSIZE);
       +                if (linsize)
       +                        Bprint(&tabout, "\\v'-\\n(%dp/6u'", LSIZE);
       +                Bprint(&tabout, "\\h'-\\n(#~u'");         /* adjustment for T450 nroff boxes */
       +                Bprint(&tabout, "\\L'|\\n(#%cu-%s", linestop[start] + 'a' - 1,
       +                      vm == 'v' ? "1v" : "\\n(35u");
       +                if (ext)
       +                        Bprint(&tabout, "-(%s)", ext);
       +                if (exb)
       +                        Bprint(&tabout, "-(%s)", exb);
       +                pos = ept - epb;
       +                if (pos)
       +                        Bprint(&tabout, "%s%dp", pos >= 0 ? "+" : "", pos);
       +                /* the string #d is either "nl" or ".d" depending
       +           on diversions; on GCOS not the same */
       +                Bprint(&tabout, "'\\s0\\v'\\n(\\*(#du-\\n(#%cu+%s",
       +                     linestop[start] + 'a' - 1, vm == 'v' ? "1v" : "\\n(35u");
       +                if (ext)
       +                        Bprint(&tabout, "+%s", ext);
       +                if (ept)
       +                        Bprint(&tabout, "%s%dp", (-ept) > 0 ? "+" : "", (-ept));
       +                Bprint(&tabout, "'");
       +                if (linsize)
       +                        Bprint(&tabout, "\\v'\\n(%dp/6u'", LSIZE);
       +        }
       +}
       +
       +
       +int
       +midbar(int i, int c)
       +{
       +        int        k;
       +
       +        k = midbcol(i, c);
       +        if (k == 0 && c > 0)
       +                k = midbcol(i, c - 1);
       +        return(k);
       +}
       +
       +
       +int
       +midbcol(int i, int c)
       +{
       +        int        ct;
       +
       +        while ( (ct = ctype(i, c)) == 's')
       +                c--;
       +        if (ct == '-' || ct == '=')
       +                return(ct);
       +        if (ct = barent(table[i][c].col))
       +                return(ct);
       +        return(0);
       +}
       +
       +
       +int
       +barent(char *s)
       +{
       +        if (s == 0) 
       +                return (1);
       +        if (!point(s)) 
       +                return(0);
       +        if (s[0] == '\\') 
       +                s++;
       +        if (s[1] != 0)
       +                return(0);
       +        switch (s[0]) {
       +        case '_':
       +                return('-');
       +        case '=':
       +                return('=');
       +        }
       +        return(0);
       +}
       +
       +
 (DIR) diff --git a/src/cmd/troff/FIXES b/src/cmd/troff/FIXES
       t@@ -0,0 +1,821 @@
       +March 11, 1994
       +
       +        If we are just plain old nroff (and not doing UNICODE) we should
       +        only Lookup characters, not Install when we don't know them.
       +        If we are troff, we Install them anyway
       +
       +March 8, 1994
       +
       +        Nroff had problems with parsing quoted white space as options or
       +        character code in some terminals tables. Changed by having scanf
       +        include white space when necessary as suggested by Rich.
       +
       +March 1, 1994
       +
       +        Made sanity check for terminal type depending on the trace level;
       +        trace level set with -tn flag at start up
       +
       +22 Feb, 1994
       +
       +        More pointer shuffling fixes.
       +
       +18 Feb, 1994
       +
       +        More disabling of multibyte stuff. Fixed bug in n5.c: casetm didn'
       +        know about the new format in the fontables.
       +
       +Feb 17, 1994
       +
       +        Removed extra include <setlocale> from n1.c
       +
       +        Fixed dubious pointer shuffling in n7.c, t10.c & n8.c. Thanks Rich!
       +
       +Feb 10, 1994
       +
       +        Disabled the multybyte stuff; only plan 9 will get it.
       +
       +Jan 24, 1994
       +
       +        Fixed nasty bug discovered by td, which caused core dumps on
       +        \D'l-0.002775i 0i' and apparently all numbers closer to 0
       +        than -.002775. Fixed in storeline() and storeword() (n7.c).
       +
       +Dec 16, 1993
       +
       +        nroff & troff -N were looking for the TYPESETTER variable, causing
       +
       +        troff: cannot open /sys/lib/troff/term/tab.202; line 1, file stdin
       +
       +        fixed my moving getenv("TYPESETTER") to t10.c in t_ptinit(void).
       +
       +Dec 3, 1993:
       +
       +        The sequence \s+2\H'+10' came sometimes out in the wrong order
       +        (x H before s), so there wasn't a difference bewteen \s+2\H'+10'
       +        and \H'+10'\s+2. Now the fonts bits of the CHARHT are used to
       +        register the current pontsize, so we can issue a s10 in t10.c
       +        if needed. A bit sneaky.
       +
       +        Try to prevent double slashes in path names. Especially under
       +        plan9 things started to look ugly.
       +
       +        Exception word list now grows dynamic.
       +
       +Nov 30, 1993:
       +
       +        Allow multiple calls to .pi, requested by Rob.
       +                .pi cat
       +                .pi dogs
       +        is now equivalent with
       +                .pi cat | dogs
       +
       +
       +        .ab now takes also optional error code:
       +                .ab [n] [string]
       +        If n and string, n is exit code, string is message
       +        If n, n is exit code, ``User Abort, exit code n" is message
       +        If !n and string, standard exit code, string is message
       +        If !n and ! string, standard exit code, "User Abort" is message
       +
       +Nov 24, 1993:
       +
       +        Reordered code to keep the UNASNI scripts happy.
       +
       +        Nroff dumped core reading terminal tables: apparenty under plan 9,
       +        scanf includes the '\n'; added test for '\0' in parse in n10.c.
       +
       +        Relative tab settings (.ta +1C +2C) didn't work; anding the
       +        previous value with TABMASK fixes this (caseta).
       +
       +Nov 23, 1993:
       +
       +        Included code, originally done by bwk for plan 9, to handle
       +        multi-byte characters.
       +
       +Nov 3, 1993:
       +
       +        ``pair internal'' two char names by shifting 16 bits. Will allow
       +        the use of 16 bit characters sets (Unicode in plan9 etc.) for
       +        macro's etc.
       +
       +Oct 20, 1993:
       +
       +        Word & line buffers are now dynamic: No more word or line overflow
       +        unless when we run out of memory.
       +
       +Oct 11, 1993:
       +
       +        lost diversion warning pops up regularly with man macro's. Due
       +        to a possible macro coding problem. Triggered by something like
       +        troff -man:
       +                .TP
       +                .TP
       +                foo
       +                .ex
       +            Minimal code:
       +                .di aa
       +                throw away this diversion (aa) while being defined.
       +                .rm aa
       +                .br
       +                .di
       +
       +        Fixed by disallowing .rm to throw away current diversion. The
       +        rn request will complain with:
       +
       +                cannot remove diversion aa during definition; etc.
       +
       +Sep 29, 1993:
       +
       +        Some long standing fixes which never went back in the source.
       +        Thanks to Janet & Rich.
       +
       +Sep 28, 1993:
       +
       +        Changed getach() (n1.c), so it does't consider truncated
       +        special characters as (8-bit) ascii.  STX ETX ENQ ACK and BELL
       +        are still allowed for the ultimate backwards compatibility.
       +
       +        Some code changes, so real ANSI compilers like the SGI version
       +        (acc from Sun is a poor excuse for an ANSI compiler) don't
       +        barf.  Some compromises (static Tchar wbuf in n9.c) allowed so
       +        the unansified stuff for non-ansi compilers (cc on Sun's) will
       +        work as well.
       +
       +Sep 9, 1993:
       +
       +        Be nice to Gerard. Now also word spaces in .tl and after
       +        tabs/fleids etc.
       +
       +Aug 12, 1993:
       +
       +        Tabs setting can now be humongous. We also allow 99 tabs to
       +        accomodate tbl. As a side effect, NTM buffers are now 1K
       +
       +Aug 11, 1993:
       +
       +        .R register, now contains maximum number of addessable
       +        registers minus the number actually used.
       +
       +        Small esthetic changes in error messages; removed a statement
       +        which wasn't reached anyway.
       +
       +Aug 10, 1993:
       +
       +        Some more speed hacks: be smarter doing the linear table
       +        lookups in alloc() and finds().
       +
       +        The real name of the det diversion size macro is now gd.
       +
       +Aug 9, 1993:
       +
       +        A much faster way to find the end of a string/macro, by
       +        remembering that when defined.
       +
       +Aug 6, 1993:
       +
       +         Slightly more eficient way of skipping to the end of a
       +         string/macro
       +
       +Aug 5, 1993:
       +
       +        Prevent character sign extension for 8-bit charnames diversions
       +        etc. by unpair
       +
       +Aug 4, 1993:
       +
       +        Growing the dynamical macro/strings name space and registers
       +        space (See the experiment of 21 July) now with bigger
       +        increments. Casts added to satisfy non-ANSI compilers.
       +
       +Aug 3, 1993:
       +
       +        Should check return value in alloc (n3.c), to prevent core dump
       +        when memory gets tight.
       +
       +July 28, 1993:
       +
       +        New request: .sg <div> sets the dn and dl registers to the size
       +        of the diversion named in the argument. Doesn't do anything
       +        when the named diversion doesn't exist. The name sg is
       +        temporary until we find a better one.
       +
       +July 21, 1993:
       +
       +        Experiment: Macro space  & registers name allocated
       +        dynamically. Note that current reallocation occurs in
       +        increments of 1, to force the code to be executed a lot; a kind
       +        of stress testing. Also, eight bit characters allowed in
       +        macro/string names.
       +
       +July 21, 1993:
       +
       +        Turn on the escape mode if the end macro is called.
       +
       +July 20, 1993:
       +
       +        Tracing mode now default off
       +
       +        Don't print s stackdump either when a file specfied on the
       +        command line argument cannot be opened
       +
       +July 15, 1993:
       +
       +        Don't print useless line & current file informations when a
       +        file specfied on the command line argument cannot be opened.
       +
       +        Sun ansi compiler doesn't default adhere to standards. Undid
       +        the kludge in tdef.h
       +
       +July 14, 1993:
       +
       +        Coding error made the tab type R not function properly
       +
       +July 12, 1993:
       +
       +        Fixed a typo in the version stuff, noticed by Rich
       +
       +July 9, 1993:
       +
       +        Added the dwb home configuration stuff, thanks RIch. Also,
       +        NCHARS is big enough. Added a fflush to casetm, so .fm <file>
       +        will be up to date.
       +
       +June 25, 1993 (Rich):
       +
       +    -t option
       +
       +        reinstated for the sake of compatibility. Some old
       +        shells scripts and man(1) from SunOs want this, sigh
       +
       +    Compiler and system dependencies
       +
       +        Some systems pull in sys/types.h via #include <time.h> and then
       +        the compiler complains about two ushort typedefs. Therefore,
       +        ushort is now Ushort (and uchar Uchar).
       +
       +        The SVID specifies a strdup, POSIX doesn't, anyway, troff
       +        provides its own version, slightly different then the standard
       +        one. A To prevent name clashes with that definion, renamed to
       +        strdupl.
       +
       +June 24, 1993 (Rich):
       +
       +        -V option added for DWB3.4 (rich)
       +
       +May 18, 1993:
       +
       +    Trivial fix (.cf) request for troff -a 
       +
       +        issuing
       +
       +                .cf /dev/null
       +
       +        with troff -a gives some spurious output:
       +
       +                H720
       +                H720
       +                s10
       +                f1
       +
       +        fixed  by checking for ascii mode it ptesc(), ptps() and
       +        ptfont() in t10.c
       +
       +
       +    Enhancement
       +
       +        Added a .tm request to roff. Works just like .tm, but now
       +        it will do it to file. The name is coined by Carmela. Great
       +        for creating indeces & toc's (we hope).
       +
       +May 18 1993:
       +
       +    Compatibilty change
       +
       +        Somebody complained that his favorite macro didn't work:
       +        it had a BELL (^G) in the name.  This was a non-documented
       +        feature of earlier versions of troff (although the
       +        documentation actually doesn't say that you can. (They can
       +        only be used for delimiters or with the tr request), so it
       +        isn't that important).
       +
       +        But the sake of eternal backward compatibilaty I allowed
       +        some control characters like, STX, ACK,  etc. also be part
       +        of a macro/string name.
       +
       +        While at it, I made it also possible to have eight bit
       +        characters be part of the name. It might be that this screws
       +        up the way users think about these things. For UNICODE
       +        versions, they probably want to do that as well, and that
       +        won't work as easy, (because these characters are 16-bits
       +        wide), so it is dubious whether we actually want this.
       +
       +        BTW. Now
       +
       +                .de \(ts\ts
       +                .tm terminal sigma macro
       +                ..
       +                .\(ts\(ts
       +
       +        also works, as long the internal cookie for ts isn't more then
       +        eight bits.
       +
       +May 12, 1993:
       +
       +    Syntax change
       +
       +        Some requests accept tabs as a separator, some don't and
       +        this can be a nuisance.  Now a tab is also recognized as
       +        an argument separator for requests, this makes
       +
       +                .so        /dev/null
       +
       +        works.
       +
       +        To be more precise, any motion character is allowed, so
       +
       +                .so\h'5i'/dev/null
       +
       +        will work as well, if one really wants that.
       +
       +        It will be a problem for users who really relied on this as in
       +
       +                .ds x        string
       +        
       +        and expect the tab to become part of the string a, but I haven't
       +        seen any use of that (obscure trick).
       +
       +May 6, 1993:
       +
       +    Eileen count fixed
       +
       +        Troff sometimes went in a loop, and exited with: ``job
       +        looping; check abuse of macros'' (also known as the Eileen's
       +        loop). It can be forced with the next trivial programme:
       +
       +                .de ff
       +                .di xx
       +                ..
       +                .wh -1 ff
       +                .bp
       +
       +        Basically what happens is that a page transition now will
       +        happen in a diversion, which doesn't make sense. Wat really
       +        happens is that eject() (in n7.c) doesn't eject the frame
       +        because we are in a diversion.  This cause the loop in n1.c
       +        (because now always stack->pname <= ejl). Adding check on
       +        whether we are not in a diversion takes care of the problem.
       +
       +March 30, 1993:
       +
       +    Need request, .ne
       +
       +        When there is a begin of page trap set, and the first thing
       +        in the file is a .ne request, the trap gets fired, but,
       +        the x font R etc. cookies doen't come out, because the
       +        troff thinks that the first page pseudo transition already
       +        took place.  Fixed by forcing the start of the first page
       +        in the casene request with the same code as in casetl (which
       +        caused a similar problem quite some time ago).
       +
       +    Change to .cf request ``Here document''
       +
       +        If the argument of .cf starts with a <<, the rest of it is taken
       +        as an EOF token. It will reat the rest of the input until it hits
       +        the EOF token and copies it to the output. This is similar as
       +        the shell's ``here document'' mechanisme and put in place to
       +        improve the kludgy way picasso, picpack etc. now include
       +        postscript.
       +
       +    Using troff -TLatin1 (DWB version) and \N'...' caused core dump
       +
       +        In t11, in chadd, it should test on NCHARS - ALPHABET to see
       +        whether we run out of table space (and we probably should beaf
       +        up NCHARS for the DWB version).
       +
       +March 16, 1993:
       +
       +    Diversion rename bug fix
       +
       +        It is possible to get troff in an infinite loop by renaming a
       +        diversion in progress, and calling it later with the
       +        new name (as in .di xx, .rn xx yy, .yy). The effect depends on
       +        whether troff already put stuff in the diversion or not.
       +
       +        Fix by having .rn also rename the current diversion (if
       +        there is any and when appropriate).  If the diversion calls
       +        itself by the new name and given the fix made on 11 nov
       +        1992, this will now result in an error.  (BTW, the fix from
       +        11 nov is improved: diversions nest, so we have to account
       +        for that).
       +
       +December 18, 1992:
       +        Some people have complete novels as comments, so we need
       +        to skip comments while checking the legality of font files.
       +        thaks Rixh
       +
       +December 16, 1992
       +
       +        Some people rely on the order that -r arguments are given,
       +        so that troff -rC1 -rC3 ends up setting register C to 3.
       +        Because cpushback() pushes things in a LIFO order back, we
       +        have to do the same to get -r args in a FIFO order.
       +
       +Nov 17, 1992:
       +
       +        Giving a -rL8 option cuased the string .nr L 8 to be printed
       +        on the output, using the wonderful 3b2. Some garbage was
       +        left in buf[100] in main(). Fixed by setting buf[0] explicitly
       +        to 0 (because some C-compilers complain about ``no automatic
       +        aggregate initialization'').
       +
       +Nov 11, 1992:
       +
       +    Diversion bug fix
       +
       +        If a diversion was being read and the input is faulty so
       +        the diversion was reading in itself, it caused troff to
       +        loop undefinitely. This was easily fixed by a test in
       +        control(a,b) in n1.c.
       +
       +        Something similar things might happen with macros causing
       +        the ``eileenct problem'', but I didn't look for that. We
       +        have to wait until it happens.
       +
       +Oct 26, 1992:
       +
       +    Numeric arguments:
       +
       +        Illegal argments are treated as missing arguments. This
       +        changed the semantics of .ll, .ls, .in, .lg,  .ul, .cu .lt
       +        (which acted as if the argument was 0) and .ps which was
       +        simply ignored with an illegal argument.
       +
       +        Tidied up number parsing in atoi1(). This prevents arguments
       +        like .x or 1.2.3.4 being interpret as a legal number (nonumb = 0)
       +
       +    Numeric arguments error reporting:
       +
       +        Controlled by .pt, illegal numbers are now reported (default
       +        trace mode is 1).  This is also true for the escapes:
       +        \h'..', \v'..' \H'..', \S'..', \N'..', \D'..', \l'.., \L'..
       +        and \x'..'.
       +
       +        \D'c' is the only drawing request which doesn't take a pair
       +        of numbers as arguments, so a special case is put here in
       +        setdraw() (This code actually could use an overhaul to get
       +        better parsing. As long as the \D'..' cookies are machine
       +        generated it is low on the priority list).
       +
       +        Don't generate an error if the illegal argument to a request
       +        is a \}. It is too painful to do right (although it can be
       +        done, but it would clutter getch() and getcho() even more).
       +
       +    Input line numbers (.c register) bug fixes:
       +
       +        In not taken branches of .if or .ie, the input line #
       +        (numtab[CD].val) should be raised when necessary (in eatblk()).
       +
       +        For concealed newlines, we still should count the line for input.
       +
       +        Setfield (n9.c) sometimes pushes the rest of the line back to
       +        the input (including \n), without adjusting numtab[CD].val
       +
       +        Because .c (and so numtab[CD].val) is the number of lines read
       +        and the error might actually happen in the current line
       +        (before seeing the '\n), we need to apply correction in
       +        errprint when nlflg set. (This correction needs to be undone
       +        when inside a macro because the nlflg is set by reading the
       +        args to the macro).
       +
       +    Line number setting (.lf) request bug fixes:
       +
       +        I interpret that the .c register will contain the number of
       +        read lines, not including the current one.
       +
       +        Also, don't change the input line number when the first
       +        argument of .lf is not a number.
       +
       +        As a net effect, the next input
       +
       +                .EQ
       +                .EN
       +                .ab
       +
       +        will generate the same output whether eqn has been used or not.
       +
       +    If request bug fix:
       +
       +        A ``.if page .tm foo'' caused the next line being ignored;
       +        This bcause when the 2nd delimiter of a string couldn't be
       +        found in cmpstr, the next line was always eaten. Solution:
       +        in caseif1, if the condition is false, we should check
       +        nlflg before eating a block.  (Note: We might have eaten
       +        \{\ as well.  We could disallow the \{\ in a string to be
       +        compared to prevent that but that might break other things).
       +
       +    Enhancement to .pt:
       +
       +        The .pt now pops the previous values when no argument is
       +        specified. Turned out to be handy when chasing for problems.
       +        Just ``bracked'' the code with .pt 7 and .pt and you get
       +        a trace of only that block. The meaning of the arguments
       +        is now:
       +                01      trace numeric arguments (default on)
       +                02        trace requests
       +                04        trace macros
       +
       +    Abort request (.ab) beautification:
       +
       +        Don't print the extra carriage return when .ab is called
       +        without an argument.
       +
       +Oct 12, 1992:
       +
       +        (Comments & spelling errors from this day on by jaap)
       +
       +        replaced 32767 by INT_MAX in several places to allow for very
       +        long pages (on 32-but machines).
       +
       +        The ``.fp 1 R   \"COMMENT'' complains about ``./troff: Can't
       +        open font file /usr/lib/font/devpost/h'' on some systems. It
       +        sees the tab as part of the optional font file.  Apparently it
       +        is system dependent whether isgraph() includes the tab
       +        character.  Fixed by using getach() in getname() in n1.c
       +        instead.
       +
       +Aug 28, 1992:
       +        removed call to popi from rdtty();  it was eating up the
       +        rest of the macro if it was used from within one.  (thanks, jaap)
       +
       +
       +Jul 21, 1992:
       +        added extra test in nextfile() to pop current input file
       +        only if not in .nx command.  thanks to jaap.
       +
       +        added test in getword() to avoid hyphenating after \z character,
       +        which prevents any hyphenation inside \X'...'.  thanks to jaap.
       +
       +        added, then removed, code in getword() to prevent hyphenating
       +        anything shorter than 6 characters.  looks like it changed a
       +        lot more than i thought.
       +
       +Jul 12, 1992:
       +        added .pt request to trace macros and requests (from jaap).
       +        .pt N Print trace of macros (N=1), requests (N=2) or both (N=3)
       +
       +Jun 5, 1992:
       +        added tests to t.twrest and t.twinit to avoid 0 deref in
       +        n2 and n10, for nroff -t xxxxx.  thanks to Rich Drechsler.
       +
       +May 22, 1992:
       +        added extern decls to e.g., void Tchar (*hmot)(void) in tdef.h
       +        and added definition to ni.c, so pointers are defined explicitly.
       +        makes it work on turbo c++ and probably others.
       +
       +        changed a couple of isdigit's and isgraph(getch()) to avoid
       +        multiple evaluation (even though it shouldn't happen).
       +
       +        Made /usr/bin/nroff a shell script.
       +
       +May 12, 1992:
       +        n1.c: need p++ after strrchr to skip / in program name.
       +        thanks to Rich Drechsler.
       +
       +Apr 17, 1992:
       +        casefi(), n5.c: .u register should be 0 or 1, not incremented
       +        with each .fi.
       +
       +Apr 5, 1992:
       +        fiddled n7.c and added _nmwid to the environment, to add a
       +        5th argument to .nm:  the maximum number of digits in any
       +        line number.  default is 3, which was previously hardwired in.
       +
       +        added jaap's code for yet another register which actually delivers
       +        a string, called .S (so it can easily go in the switch in setn()
       +        in n4.c); it delivers the current tabstop and alignment modes in
       +        a format suitable for a subsequent .ta \n(.S command:
       +                .ds T \n(.S
       +                ...
       +                .ta \*T
       +
       +Mar 30, 1992:
       +        added test in getword to avoid hyphenating things with motions
       +        (and avoid a core dump sometimes too).
       +
       +Mar 13, 1992:
       +        \n(sb initialized wrong in setwd().
       +
       +        TYPESETTER=foo troff -Tpost used foo instead of post.
       +
       +Mar 12, 1992:
       +        rearranged tests in popf so that .so is closed properly before
       +        moving on to the next macro package.
       +
       +Mar 1, 1992:
       +        input mechanism rearranged to use getc() instead of stack of
       +        explicit input buffers.  5-10% slowdown.
       +
       +Jan 28, 1992:
       +        fixed .tm \(mi to print something sensible.  thanks to jaap.
       +
       +Jan 2, 1992:
       +        fiddle setfp so doesn't put out font stuff if -a turned on.
       +
       +Dec 17, 1991:
       +        copy 3rd argument in .fp commands to x font ... lines when it contains
       +        a /, for testing fonts locally.
       +
       +Dec 13, 1991:
       +        parameterize the font directories, etc., so can be set in makefiles.
       +        added -N argument to run as nroff.
       +
       +Nov 8, 1991:
       +        add a maplow(towlower...) in n8.c to handle brain-damaged libraries.
       +
       +Nov 2, 1991:
       +        merged nroff into troff, based on Ken's plan 9 version.
       +        merged nii.c into ni.c, removed tw.h, etc.  more work needed
       +        to make this stuff cleaner.
       +
       +July 27, 1991:
       +        added test in setn in n4 to fix bug that permitted things like
       +        \n (ab to work "properly".  thanks to jaap for finding and fixing.
       +
       +        added paranoid testing in t11 to make sure font files look ok.
       +
       +May 13, 1991:
       +        moved evaluation of \(xx from copy mode to non-copy mode, so that
       +        weird character names wouldn't get reevaluated in argument parsing.
       +        installed july 27.
       +
       +May 6, 1991:
       +        increased size of hyphenation exception buffer to 512 from 128
       +
       +Apr 14, 1991:
       +        added an extra redundant call of ptfont in setfp, since it appears
       +        that some versions of adobe transcript assume that an "x font" command
       +        means to change the actual font as well.  the fix preserves the current font.
       +        thanks to david brailsford and friends for spotting the problem.
       +
       +        fixed up tests in alpha() in n8 to defend isalpha() against too-big inputs.
       +        punct() argument had wrong type too.  thanks to rich drexler and peter nelson.
       +
       +Mar 19, 1991:
       +        fixed bug that prevented .rd from working with new corebuf organization.
       +
       +        fixed bug that caused .ig inside diversions to give bad storage
       +        allocation.  thanks to arthur david olson, whose fix was on netnews
       +        3 years earlier.
       +
       +Mar 5, 1991:
       +        huge table sizes for kanji.
       +
       +Feb ??, 1991:
       +        working on dealing with large alphabets, notably kanji.
       +        added "defaultwidth" to font descriptions, for characters
       +        not given an explicit width.
       +
       +Jan, 1991:
       +        added tex hyphenation, using standard tex data files, but not the
       +        elaborate compressed trie, which is a lot of trouble to save maybe
       +        40k bytes.  this appears to run at exactly the same speed as before.
       +
       +        so far this stuff reads into a fixed size array; that should change.
       +        it should also be possible to deal with multiple languages.
       +
       +        the command .ha sets the algorithm.  .ha 1 => tex, with troff rules
       +        if tex doesn't hyphenate;  .ha 0 gives troff rules, and .ha resets
       +        to the default, which is tex.  the hyphenation algorithm is part of
       +        the environment, a nod to a future in which i handle more than one
       +        language.
       +
       +        replaced the fixed size corebuf array for string/macro storage by
       +        a dynamic structure that can grow.
       +
       +        this appears to slow things down by maybe 3%.  the code is about
       +        the same complexity.
       +
       +Dec 27, 1990:
       +        converted to ansi c, based on some work by ken thompson, but not
       +        as thoroughly as he did.  there is a shell script unansi and an awk
       +        program cvt that will help you step back in time if you do not have
       +        an ansi c compiler.
       +
       +        moved the special-name characters up to 256 instead of 128, although
       +        done in terms of ALPHABET, so one can pass 8 bit characters through.
       +        removed lots of 0177's and similar numbers.  input is now not filtered,
       +        and if a character with the 8th bit on comes in, it will go out again.
       +
       +        fixed t11.c to read character names in hex or octal as well as
       +        single-character ascii.
       +
       +        unknown characters are now carried through with width = spacewidth.
       +        needs a way to set widths.
       +
       +        removed all signal handling from troff.  you signal, you die.
       +
       +        added -d option to print version number.
       +
       +Dec 7, 1990:
       +        .fp 3 V VERYLONGNAME used to truncate the name to 10 chars; fixed.
       +
       +        increased the limit on FBUFSZ for tables with very long fields.
       +
       +        changed atoi1() to use double to avoid intermediate overflow.
       +
       +        moved filenames like /usr/lib/font into tdef.h for easy change.
       +        removed some dreggish definitions.
       +
       +        cleaned up non-portable error printing stuff;  fixed up some messages.
       +
       +Dec 12, 1989:
       +        Removed the .! command, an undocumented synonym for .sy.
       +
       +Dec 4, 1989:
       +        Another wart to the \X code, to try to preserve blanks in all situations.
       +
       +Nov 17, 1989:
       +        A number of small changes preparatory to getting rid of nroff.
       +        The argument -Tnroff or -Tnroff-12 changes some internal values
       +        so that the predicate .if n is true and certain arithmetic operations
       +        are done as if nroff.  This design is not yet final.
       +
       +Nov 7, 1989:
       +        Fixed hyphenation for nov-ice, ad-vice, de-vice, ser-vice, *-vice.
       +
       +Oct 11, 1989:
       +        It is now permitted to do an explicit change to font S.
       +        It is not clear what will break (though nothing seems to have).
       +
       +Oct 10, 1989:
       +        Modified flush code to always put out \nH instead of sometimes h.
       +        This makes it easier to parse the output for positioning.
       +
       +Sep 9, 1989:
       +        Fixed internal representation of \D'~...' so that it
       +        is immune to .tr ~ and variations.  No external change.
       +
       +Aug 9, 1989:
       +        Changed .tm so it outputs \e, \%, \-, \&, \(blank).
       +        This might break indexing code.
       +        Only in the new version, as are all subsequent fixes.
       +
       +July, 1989:
       +        A major internal change:  font information is read in ascii
       +        instead of the weird binary format of makedev (which is now dead).
       +        character names need not all appear in DESC;  new names that
       +        appear when a font is used become part of the set of known names.
       +
       +        There are some flaky bits here (it's conceivable that some \N
       +        number will collide with a real name), and it's probably 10-15%
       +        slower.  Tant pis.
       +
       +        As a by-product, nroff no longer compiles.  I'll probably get
       +        back to this, but an alternative is to bag it once and for all.
       +
       +May 25, 1989:
       +        Another bug in \l, this time when width is 0.  Not installed,
       +        since it's in the new font version.
       +
       +Apr 23, 1989:
       +        Fixed bug in n9 that caused core dump with unterminated
       +        \l command, like \l'1.5i
       +
       +        ptflush no longer called when -a is on.
       +
       +Apr 12, 1989:
       +        fixed bug in n2 that failed to suppress printing of \!
       +        output when a -o was in effect.
       +
       +Apr 5, 1989:
       +        .fl and \X now cause output of size, font, hpos and vpos.
       +        this is necesary for postprocessors that intend to insert
       +        independent material, such as postscript.
       +
       +Feb 1, 1989:
       +        wait for .pi pipe to empty before exiting
       +
       +Oct 2, 1988:
       +        default is now -Tpost
       +
       +Sep 19, 1988:
       +        added abortive code to handle built-up characters by
       +        passing something through as \D'b...'.  never used.
       +
       +Jul 4, 1988:
       +        replaced the sbrk nonsense in n3.c by calls to malloc.
       +
       +        \N now tests against proper font size.
       +
       +        installed Jaap Akkerhuis's code (mutatis mutandis) for
       +        permitting up to 99 fonts, swapping them into font pos 0
       +        as needed.  fixes the long-standing problem of having
       +        multiple font changes on a single output line.
       +
       +Jul 2, 1988:
       +        \X now preserves spaces even when contents are diverted.
       +
       +        \N code safer -- NTRTAB and NWIDCACHE enlarged.
       +
       +Jul 14, 1987:
       +        Fixed obscure bug causing incorrect indentation of .mc output.
 (DIR) diff --git a/src/cmd/troff/README b/src/cmd/troff/README
       t@@ -0,0 +1,31 @@
       +To make troff (actually a.out):
       +
       +        make
       +
       +You will also need to write a driver for your favorite output device.
       +d202.c provides a model, although it is specialized to a machine no
       +one has.  There are also a variety of postscript drivers that are the
       +best thing to use if you have a postscript device.
       +
       +You will also have to make a DESC file for your typesetter and some
       +font description files; see dev202 for examples.  These describe the
       +named characters, widths, kerning information, and output codes.
       +
       +Nroff is the same program as troff, so you should
       +
       +        cp a.out /usr/bin/troff
       +        ln /usr/bin/troff /usr/bin/nroff
       +
       +or the equivalent.
       +
       +You will also need terminal description files for your terminals; see
       +tab.37, tab.450 and tab.lp for examples.
       +
       +Troff uses files that are normally stored in /usr/lib/font;
       +macro packages are in /usr/lib/tmac; and nroff tables are in
       +/usr/lib/term.  You can edit tdef.h to change these assumptions.
       +
       +There have been a few features since the last version, and a number of
       +significant internal changes.  Not all are improvements, of course.
       +Most of the more recent changes, including bug fixes, are in FIXES,
       +which you should read also.
 (DIR) diff --git a/src/cmd/troff/cvt b/src/cmd/troff/cvt
       t@@ -0,0 +1,45 @@
       +
       +awk '
       +
       +/^{/ {
       +        if (prev != "") {
       +                # comments can be trouble (e.g. ffree())
       +                if ( (c = match(prev, /\/\*.*\*\/$/)) != 0 ) {
       +                        comment = substr(prev, c)
       +                        sub(/\/\*.*\*\/$/, "", prev)
       +                } else comment = ""
       +
       +                x = prev
       +
       +                # isolate argument list
       +                sub(/^[^(]*\(/, "", x)
       +                sub(/\)[^)]*$/, "", x)
       +
       +                # find the names in it
       +                n = split(x, args)
       +                arglist = ""
       +                for (i = 2; i <= n; i += 2)
       +                        arglist = arglist args[i]
       +                gsub(/\(\*f\)\(Tchar\)/, "f", arglist)        # special case for n4.c
       +                gsub(/\[[0-9]+\]/, "", arglist)                #     for n8.c
       +                gsub(/[*()\[\]]/, "", arglist)                # discard noise characters *()[]
       +                gsub(/,/, ", ", arglist)                # space nicely
       +                sub(/\(.*\)/, "(" arglist ")", prev)        # reconstruct
       +                print prev comment
       +
       +                # argument declarations
       +                gsub(/,/, ";", x)
       +                gsub(/\(\*f\)\(Tchar\)/, "(*f)()", x)        # special case for n4.c
       +                if (x != "")
       +                        print "\t" x ";"
       +        }
       +        prev = $0
       +        next
       +}
       +
       +{        print prev
       +        prev = $0
       +}
       +
       +END { print prev }
       +' $*
 (DIR) diff --git a/src/cmd/troff/dwbinit.c b/src/cmd/troff/dwbinit.c
       t@@ -0,0 +1,313 @@
       +/*
       + *
       + * Pathname management routines for DWB C programs.
       + *
       + * Applications should initialize a dwbinit array with the string
       + * pointers and arrays that need to be updated, and then hand that
       + * array to DWBinit before much else happens in their main program.
       + * DWBinit calls DWBhome to get the current home directory. DWBhome
       + * uses the last definition of DWBENV (usually "DWBHOME") in file
       + * DWBCONFIG (e.g., /usr/lib/dwb3.4) or the value assigned to that
       + * variable in the environment if the DWBCONFIG file doesn't exist,
       + * can't be read, or doesn't define DWBENV.
       + *
       + * DWBCONFIG must be a simple shell script - comments, a definition
       + * of DWBHOME, and perhaps an export or echo is about all that's
       + * allowed. The parsing in DWBhome is simple and makes no attempt
       + * to duplicate the shell. It only looks for DWBHOME= as the first
       + * non-white space string on a line, so
       + *
       + *        #
       + *        # A sample DWBCONFIG shell script
       + *        #
       + *
       + *        DWBHOME=/usr/add-on/dwb3.4
       + *        export DWBHOME
       + *
       + * means DWBhome would return "/usr/add-on/dwb3.4" for the DWB home
       + * directory. A DWBCONFIG file means there can only be one working
       + * copy of a DWB release on a system, which seems like a good idea.
       + * Using DWBCONFIG also means programs will always include correct
       + * versions of files (e.g., prologues or macro packages).
       + *
       + * Relying on an environment variable guarantees nothing. You could
       + * execute a version of dpost, but your environment might point at
       + * incorrect font tables or prologues. Despite the obvious problems
       + * we've also implemented an environment variable approach, but it's
       + * only used if there's no DWBCONFIG file.
       + *
       + * DWBinit calls DWBhome to get the DWB home directory prefix and
       + * then marches through its dwbinit argument, removing the default
       + * home directory and prepending the new home. DWBinit stops when
       + * it reaches an element that has NULL for its address and value
       + * fields. Pointers in a dwbinit array are reallocated and properly
       + * initialized; arrays are simply reinitialized if there's room.
       + * All pathnames that are to be adjusted should be relative. For
       + * example,
       + *
       + *        char        *fontdir = "lib/font";
       + *        char        xyzzy[25] = "etc/xyzzy";
       + *
       + * would be represented in a dwbinit array as,
       + *
       + *        dwbinit allpaths[] = {
       + *                &fontdir, NULL, 0,
       + *                NULL, xyzzy, sizeof(xyzzy),
       + *                NULL, NULL, 0
       + *        };
       + *                
       + * The last element must have NULL entries for the address and
       + * value fields. The main() routine would then do,
       + *
       + *        #include "dwbinit.h"
       + *
       + *        main() {
       + *
       + *                DWBinit("program name", allpaths);
       + *                ...
       + *        }
       + *
       + * Debugging is enabled if DWBDEBUG is in the environment and has
       + * the value ON. Output is occasionally useful and probably should
       + * be documented.
       + *
       + */
       +
       +#include <stdio.h>
       +#include <ctype.h>
       +#include <string.h>
       +#include <stdlib.h>
       +
       +#include "dwbinit.h"
       +
       +#ifndef DWBCONFIG
       +#define DWBCONFIG        "/dev/null"
       +#endif
       +
       +#ifndef DWBENV
       +#define DWBENV                "DWBHOME"
       +#endif
       +
       +#ifndef DWBHOME
       +#define DWBHOME                ""
       +#endif
       +
       +#ifndef DWBDEBUG
       +#define DWBDEBUG        "DWBDEBUG"
       +#endif
       +
       +#ifndef DWBPREFIX
       +#define DWBPREFIX        "\\*(.P"
       +#endif
       +
       +/*****************************************************************************/
       +
       +void DWBdebug(dwbinit *ptr, int level)
       +{
       +
       +    char        *path;
       +    char        *home;
       +    static char        *debug = NULL;
       +
       +/*
       + *
       + * Debugging output, but only if DWBDEBUG is defined to be ON in the
       + * environment. Dumps general info the first time through.
       + *
       + */
       +
       +    if ( debug == NULL && (debug = getenv(DWBDEBUG)) == NULL )
       +        debug = "OFF";
       +
       +    if ( strcmp(debug, "ON") == 0 ) {
       +        if ( level == 0 ) {
       +            fprintf(stderr, "Environment variable: %s\n", DWBENV);
       +            fprintf(stderr, "Configuration file: %s\n", DWBCONFIG);
       +            fprintf(stderr, "Default home: %s\n", DWBHOME);
       +            if ( (home = DWBhome()) != NULL )
       +                fprintf(stderr, "Current home: %s\n", home);
       +        }   /* End if */
       +
       +        fprintf(stderr, "\n%s pathnames:\n", level == 0 ? "Original" : "Final");
       +        for ( ; ptr->value != NULL || ptr->address != NULL; ptr++ ) {
       +            if ( (path = ptr->value) == NULL ) {
       +                path = *ptr->address;
       +                fprintf(stderr, " pointer: %s\n", path);
       +            } else fprintf(stderr, " array[%d]: %s\n", ptr->length, path);
       +            if ( level == 0 && *path == '/' )
       +                fprintf(stderr, "  WARNING - absolute path\n");
       +        }   /* End for */
       +    }        /* End if */
       +
       +}   /* End of DWBdebug */
       +
       +/*****************************************************************************/
       +
       +char *DWBhome(void)
       +{
       +
       +    FILE        *fp;
       +    char        *ptr;
       +    char        *path;
       +    int                len;
       +    char        buf[200];
       +    char        *home = NULL;
       +
       +/*
       + *
       + * Return the DWB home directory. Uses the last definition of DWBENV
       + * (usually "DWBHOME") in file DWBCONFIG (perhaps /usr/lib/dwb3.4) or
       + * the value assigned to the variable named by the DWBENV string in
       + * the environment if DWBCONFIG doesn't exist or doesn't define DWBENV.
       + * Skips the file lookup if DWBCONFIG can't be read. Returns NULL if
       + * there's no home directory.
       + *
       + */
       +
       +    if ( (fp = fopen(DWBCONFIG, "r")) != NULL ) {
       +        len = strlen(DWBENV);
       +        while ( fgets(buf, sizeof(buf), fp) != NULL ) {
       +            for ( ptr = buf; isspace(*ptr); ptr++ ) ;
       +            if ( strncmp(ptr, DWBENV, len) == 0 && *(ptr+len) == '=' ) {
       +                path = ptr + len + 1;
       +                for ( ptr = path; !isspace(*ptr) && *ptr != ';'; ptr++ ) ;
       +                *ptr = '\0';
       +                if ( home != NULL )
       +                    free(home);
       +                if ( (home = malloc(strlen(path)+1)) != NULL )
       +                    strcpy(home, path);
       +            }        /* End if */
       +        }   /* End while */
       +        fclose(fp);
       +    }   /* End if */
       +
       +    if ( home == NULL ) {
       +        if ( (home = getenv(DWBENV)) == NULL ) {
       +            if ( (home = DWBHOME) == NULL || *home == '\0' || *home == ' ' )
       +                home = NULL;
       +        }   /* End if */
       +    }        /* End if */
       +
       +    while (home && *home == '/' && *(home +1) == '/')        /* remove extra slashes */
       +        home++;
       +    return(home);
       +
       +}   /* End of DWBhome */
       +
       +/*****************************************************************************/
       +
       +void DWBinit(char *prog, dwbinit *paths)
       +{
       +
       +    char        *prefix;
       +    char        *value;
       +    char        *path;
       +    int                plen;
       +    int                length;
       +    dwbinit        *opaths = paths;
       +
       +/*
       + *
       + * Adjust the pathnames listed in paths, using the home directory
       + * returned by DWBhome(). Stops when it reaches an element that has
       + * NULL address and value fields. Assumes pathnames are relative,
       + * but changes everything. DWBdebug issues a warning if an original
       + * path begins with a /.
       + *
       + * A non-NULL address refers to a pointer, which is reallocated and
       + * then reinitialized. A NULL address implies a non-NULL value field
       + * and describes a character array that we only reinitialize. The
       + * length field for an array is the size of that array. The length
       + * field of a pointer is an increment that's added to the length
       + * required to store the new pathname string - should help when we
       + * want to change character arrays to pointers in applications like
       + * troff.
       + *
       + */
       +
       +    if ( (prefix = DWBhome()) == NULL ) {
       +        fprintf(stderr, "%s: no DWB home directory\n", prog);
       +        exit(1);
       +    }        /* End if */
       +
       +    DWBdebug(opaths, 0);
       +    plen = strlen(prefix);
       +
       +    for ( ; paths->value != NULL || paths->address != NULL; paths++ ) {
       +        if ( paths->address == NULL ) {
       +            length = 0;
       +            value = paths->value;
       +        } else {
       +            length = paths->length;
       +            value = *paths->address;
       +        }   /* End else */
       +
       +        length += plen + 1 + strlen(value);        /* +1 is for the '/' */
       +
       +        if ( (path = malloc(length+1)) == NULL ) {
       +            fprintf(stderr, "%s: can't allocate pathname memory\n", prog);
       +            exit(1);
       +        }   /* End if */
       +
       +        if ( *value != '\0' ) {
       +            char *eop = prefix;
       +            while(*eop++)
       +                ;
       +            eop -= 2;
       +            if (*value != '/' && *eop != '/') {
       +                sprintf(path, "%s/%s", prefix, value);
       +            } else if (*value == '/' && *eop == '/') {
       +                value++;
       +                sprintf(path, "%s%s", prefix, value);
       +            } else
       +                sprintf(path, "%s%s", prefix, value);
       +        } else
       +                sprintf(path, "%s", prefix);
       +
       +        if ( paths->address == NULL ) {
       +            if ( strlen(path) >= paths->length ) {
       +                fprintf(stderr, "%s: no room for %s\n", prog, path);
       +                exit(1);
       +            }        /* End if */
       +            strcpy(paths->value, path);
       +            free(path);
       +        } else *paths->address = path;
       +    }        /* End for */
       +
       +    DWBdebug(opaths, 1);
       +
       +}   /* End of DWBinit */
       +
       +/*****************************************************************************/
       +
       +void DWBprefix( char *prog, char *path, int length)
       +{
       +
       +    char        *home;
       +    char        buf[512];
       +    int                len = strlen(DWBPREFIX);
       +
       +/*
       + *
       + * Replace a leading DWBPREFIX string in path by the current DWBhome().
       + * Used by programs that pretend to handle .so requests. Assumes path
       + * is an array with room for length characters. The implementation is
       + * not great, but should be good enough for now. Also probably should
       + * have DWBhome() only do the lookup once, and remember the value if
       + * called again.
       + * 
       + */
       +
       +    if ( strncmp(path, DWBPREFIX, len) == 0 ) {
       +        if ( (home = DWBhome()) != NULL ) {
       +            if ( strlen(home) + strlen(path+len) < length ) {
       +                sprintf(buf, "%s%s", home, path+len);
       +                strcpy(path, buf);                /* assuming there's room in path */
       +            } else fprintf(stderr, "%s: no room to grow path %s", prog, path);
       +        }   /* End if */
       +    }        /* End if */
       +
       +}   /* End of DWBprefix */
       +
       +/*****************************************************************************/
       +
 (DIR) diff --git a/src/cmd/troff/dwbinit.h b/src/cmd/troff/dwbinit.h
       t@@ -0,0 +1,19 @@
       +/*
       + *
       + * A structure used to adjust pathnames in DWB C code. Pointers
       + * set the address field, arrays use the value field and must
       + * also set length to the number elements in the array. Pointers
       + * are always reallocated and then reinitialized; arrays are only
       + * reinitialized, if there's room.
       + *
       + */
       +
       +typedef struct {
       +        char        **address;
       +        char        *value;
       +        int        length;
       +} dwbinit;
       +
       +extern void        DWBinit(char *, dwbinit *);
       +extern char*        DWBhome(void);
       +extern void        DWBprefix(char *, char *, int);
 (DIR) diff --git a/src/cmd/troff/ext.h b/src/cmd/troff/ext.h
       t@@ -0,0 +1,184 @@
       +extern        int        TROFF;
       +
       +extern        int        alphabet;
       +extern        char        **argp;
       +extern        char        *eibuf;
       +extern        char        *ibufp;
       +extern        char        *obufp;
       +extern        char        *unlkp;
       +extern        char        *xbufp;
       +extern        char        *xeibuf;
       +extern        char        cfname[NSO+1][NS];
       +extern  int        trace;
       +extern        char        devname[];
       +extern        char        ibuf[IBUFSZ];
       +extern        char        mfiles[NMF][NS];
       +extern        char        nextf[];
       +extern        char        obuf[];
       +extern        char        termtab[];
       +extern        char        fontdir[];
       +extern        Font        fonts[MAXFONTS+1];
       +extern        char        xbuf[IBUFSZ];
       +extern        Offset        apptr;
       +extern        Offset        ip;
       +extern        Offset        nextb;
       +extern        Offset        offset;
       +extern        Offset        woff;
       +extern        Numerr        numerr;
       +extern        int        *pnp;
       +extern        int        pstab[];
       +extern        int        nsizes;
       +extern        int        app;
       +extern        int        ascii;
       +extern        int        bd;
       +extern        int        bdtab[];
       +extern        int        ccs;
       +extern        char        *chnames[];        /* chnames[n-ALPHABET] -> name of char n */
       +extern        int        copyf;
       +extern        int        cs;
       +extern        int        dfact;
       +extern        int        dfactd;
       +extern        int        diflg;
       +extern        int        dilev;
       +extern        int        donef;
       +extern        int        dotT;
       +extern        int        dpn;
       +extern        int        ds;
       +extern        int        ejf;
       +extern        int        em;
       +extern        int        eqflg;
       +extern        int        error;
       +extern        int        esc;
       +extern        int        eschar;
       +extern        int        ev;
       +extern        int        evi;
       +extern        int        evlist[EVLSZ];
       +extern        int        fc;
       +extern        int        flss;
       +extern        int        fontlab[];
       +extern        int        hflg;
       +extern        int        ibf;
       +extern        int        ifi;
       +extern        int        iflg;
       +extern        int        init;
       +extern        int        lead;
       +extern        int        lg;
       +extern        int        lgf;
       +extern        int        macerr;
       +extern        int        mflg;
       +extern        int        mfont;
       +extern        int        mlist[NTRAP];
       +extern        int        mpts;
       +extern        int        nchnames;
       +extern        int        ndone;
       +extern        int        newmn;
       +extern        int        nflush;
       +extern        int        nfo;
       +extern        int        nfonts;
       +extern        int        nform;
       +extern        int        nhyp;
       +extern        int        nlflg;
       +extern        int        nlist[NTRAP];
       +extern        int        nmfi;
       +extern        int        nonumb;
       +extern        int        noscale;
       +extern        int        npn;
       +extern        int        npnflg;
       +extern        int        nx;
       +extern        int        oldbits;
       +extern        int        oldmn;
       +extern        int        over;
       +extern        int        padc;
       +extern        int        pfont;
       +extern        int        pfrom;
       +extern        int        pipeflg;
       +extern        int        pl;
       +extern        int        pnlist[];
       +extern        int        po1;
       +extern        int        po;
       +extern        int        ppts;
       +extern        int        print;
       +extern        FILE        *ptid;
       +extern        int        pto;
       +extern        int        quiet;
       +extern        int        ralss;
       +extern        int        rargc;
       +extern        int        raw;
       +extern        int        res;
       +extern        int        sbold;
       +extern        int        setwdf;
       +extern        int        sfont;
       +extern        int        smnt;
       +extern        int        stdi;
       +extern        int        stop;
       +extern        int        sv;
       +extern        int        tabch,        ldrch;
       +extern        int        tflg;
       +extern        int        totout;
       +extern        int        trap;
       +extern        Ushort        trtab[];
       +extern        int        tty;
       +extern        int        ulfont;
       +extern        int        vflag;
       +extern        int        whichroff;
       +extern        int        widthp;
       +extern        int        xfont;
       +extern        int        xpts;
       +extern        Stack        *ejl;
       +extern        Stack        *frame;
       +extern        Stack        *stk;
       +extern        Stack        *nxf;
       +extern        Tchar        **hyp;
       +extern        Tchar        *olinep;
       +extern        Tchar        pbbuf[NC];
       +extern        Tchar        *pbp;
       +extern        Tchar        *lastpbp;
       +extern        Tchar        ch;
       +extern        Tchar        nrbits;
       +extern        Tbuf        _oline;
       +extern        Wcache        widcache[];
       +extern        char        gchtab[];
       +extern        Diver        d[NDI];
       +extern        Diver        *dip;
       +
       +
       +extern        char        xchname[];
       +extern        short        xchtab[];
       +extern        char        *codestr;
       +extern        char        *chnamep;
       +extern        short        *chtab;
       +extern        int        nchtab;
       +
       +extern Numtab *numtabp;
       +
       +/* these characters are used as various signals or values
       +/* in miscellaneous places.
       +/* values are set in specnames in t10.c
       +*/
       +
       +extern int        c_hyphen;
       +extern int        c_emdash;
       +extern int        c_rule;
       +extern int        c_minus;
       +extern int        c_fi;
       +extern int        c_fl;
       +extern int        c_ff;
       +extern int        c_ffi;
       +extern int        c_ffl;
       +extern int        c_acute;
       +extern int        c_grave;
       +extern int        c_under;
       +extern int        c_rooten;
       +extern int        c_boxrule;
       +extern int        c_lefthand;
       +extern int        c_dagger;
       +extern int        c_isalnum;
       +
       +/*
       + * String pointers for DWB pathname management.
       + */
       +
       +extern char        *DWBfontdir;
       +extern char        *DWBntermdir;
       +extern char        *DWBalthyphens;
       +
 (DIR) diff --git a/src/cmd/troff/find b/src/cmd/troff/find
       t@@ -0,0 +1 @@
       +grep $1 *.[ch]
 (DIR) diff --git a/src/cmd/troff/fns.h b/src/cmd/troff/fns.h
       t@@ -0,0 +1,384 @@
       +/*
       + * other
       + */
       +int        pclose(FILE*);
       +long        filesize(int fd);
       +int        open(char *, int);
       +int        read(int, char *, int);
       +int        lseek(int, long, int);
       +int        close(int);
       +int        getpid(void);
       +
       +/*
       + * c1.c
       + */
       +void        init0(void);
       +void        init2(void);
       +void        cvtime(void);
       +void        errprint(void);
       +int        control(int a, int b);
       +void        casept(void);
       +int        getrq(void);
       +Tchar        getch(void);
       +void        setxon(void);
       +Tchar        getch0(void);
       +Tchar        get1ch(FILE *);
       +void        pushback(Tchar *b);
       +void        cpushback(char *b);
       +int        nextfile(void);
       +int        popf(void);
       +void        flushi(void);
       +int        getach(void);
       +void        casenx(void);
       +int        getname(void);
       +void        caseso(void);
       +void        caself(void);
       +void        casecf(void);
       +void        getline(char *s, int n);
       +void        casesy(void);
       +void        getpn(char *a);
       +void        setrpt(void);
       +
       +/*
       + * n2.c
       + */
       +int        pchar(Tchar i);
       +void        pchar1(Tchar i);
       +int        pchar2(Tchar i);
       +int        flusho(void);
       +void        casedone(void);
       +void        caseex(void);
       +void        done(int x);
       +void        done1(int x);
       +void        done2(int x);
       +void        done3(int x);
       +void        edone(int x);
       +void        casepi(void);
       +
       +/*
       + * c3.c
       + */
       +void        blockinit(void);
       +char*        grow(char *, int, int);
       +void        mnspace(void);
       +void        caseig(void);
       +void        casern(void);
       +void        maddhash(Contab *rp);
       +void        munhash(Contab *mp);
       +void        mrehash(void);
       +void        caserm(void);
       +void        caseas(void);
       +void        caseds(void);
       +void        caseam(void);
       +void        casede(void);
       +int        findmn(int i);
       +void        clrmn(int i);
       +Offset        finds(int mn);
       +int        skip(void);
       +int        copyb(void);
       +void        copys(void);
       +Offset        alloc(void);
       +void        ffree(Offset i);
       +void        wbf(Tchar i);
       +Tchar        rbf(void);
       +Tchar        popi(void);
       +Offset        pushi(Offset newip, int mname);
       +void*        setbrk(int x);
       +int        getsn(void);
       +Offset        setstr(void);
       +void        collect(void);
       +void        seta(void);
       +void        caseda(void);
       +void        casegd(void);
       +void        casedi(void);
       +void        casedt(void);
       +void        casetl(void);
       +void        casepc(void);
       +void        casepm(void);
       +void        stackdump(void);
       +
       +/*
       + * c4.c
       + */
       +void        setn(void);
       +int        wrc(Tchar i);
       +void        setn1(int i, int form, Tchar bits);
       +void        nnspace(void);
       +void        nrehash(void);
       +void        nunhash(Numtab *rp);
       +int        findr(int i);
       +int        usedr(int i);
       +int        fnumb(int i, int (*f)(Tchar));
       +int        decml(int i, int (*f)(Tchar));
       +int        roman(int i, int (*f)(Tchar));
       +int        roman0(int i, int (*f)(Tchar), char *onesp, char *fivesp);
       +int        abc(int i, int (*f)(Tchar));
       +int        abc0(int i, int (*f)(Tchar));
       +long        atoi0(void);
       +long        ckph(void);
       +long        atoi1(Tchar ii);
       +void        caserr(void);
       +void        casenr(void);
       +void        caseaf(void);
       +void        setaf(void);
       +int        vnumb(int *i);
       +int        hnumb(int *i);
       +int        inumb(int *n);
       +int        quant(int n, int m);
       +
       +/*
       + * c5.c
       + */
       +void        casead(void);
       +void        casena(void);
       +void        casefi(void);
       +void        casenf(void);
       +void        casers(void);
       +void        casens(void);
       +int        chget(int c);
       +void        casecc(void);
       +void        casec2(void);
       +void        casehc(void);
       +void        casetc(void);
       +void        caselc(void);
       +void        casehy(void);
       +int        max(int aa, int bb);
       +void        casenh(void);
       +void        casece(void);
       +void        casein(void);
       +void        casell(void);
       +void        caselt(void);
       +void        caseti(void);
       +void        casels(void);
       +void        casepo(void);
       +void        casepl(void);
       +void        casewh(void);
       +void        casech(void);
       +int        findn(int i);
       +void        casepn(void);
       +void        casebp(void);
       +void        casextm(void);
       +void        casetm(void);
       +void        casefm(void);
       +void        casetm1(int ab, FILE *out);
       +void        casesp(void);
       +void        casesp1(int a);
       +void        casert(void);
       +void        caseem(void);
       +void        casefl(void);
       +void        caseev(void);
       +void        envcopy(Env *e1, Env *e2);
       +void        caseel(void);
       +void        caseie(void);
       +void        casexif(void);
       +void        caseif(void);
       +void        caseif1(int);
       +void        eatblk(int inblk);
       +int        cmpstr(Tchar c);
       +void        caserd(void);
       +int        rdtty(void);
       +void        caseec(void);
       +void        caseeo(void);
       +void        caseta(void);
       +void        casene(void);
       +void        casetr(void);
       +void        casecu(void);
       +void        caseul(void);
       +void        caseuf(void);
       +void        caseit(void);
       +void        casemc(void);
       +void        casemk(void);
       +void        casesv(void);
       +void        caseos(void);
       +void        casenm(void);
       +void        getnm(int *p, int min);
       +void        casenn(void);
       +void        caseab(void);
       +void        save_tty(void);
       +void        restore_tty(void);
       +void        set_tty(void);
       +void        echo_off(void);
       +void        echo_on(void);
       +
       +/*
       + * t6.c
       + */
       +int        t_width(Tchar j);
       +void        zapwcache(int s);
       +int        onfont(int n, int f);
       +int        getcw(int i);
       +void        xbits(Tchar i, int bitf);
       +Tchar        t_setch(int c);
       +Tchar        t_setabs(void);
       +int        t_findft(int i);
       +void        caseps(void);
       +void        casps1(int i);
       +int        findps(int i);
       +void        t_mchbits(void);
       +void        t_setps(void);
       +Tchar        t_setht(void);
       +Tchar        t_setslant(void);
       +void        caseft(void);
       +void        t_setfont(int a);
       +void        t_setwd(void);
       +Tchar        t_vmot(void);
       +Tchar        t_hmot(void);
       +Tchar        t_mot(void);
       +Tchar        t_sethl(int k);
       +Tchar        t_makem(int i);
       +Tchar        getlg(Tchar i);
       +void        caselg(void);
       +void        casefp(void);
       +char        *strdupl(const char *);
       +int        setfp(int pos, int f, char *truename, int print);
       +void        casecs(void);
       +void        casebd(void);
       +void        casevs(void);
       +void        casess(void);
       +Tchar        t_xlss(void);
       +Uchar*        unpair(int i);
       +void        outascii(Tchar i);
       +
       +/*
       + * c7.c
       + */
       +void        tbreak(void);
       +void        donum(void);
       +void        text(void);
       +void        nofill(void);
       +void        callsp(void);
       +void        ckul(void);
       +void        storeline(Tchar c, int w);
       +void        newline(int a);
       +int        findn1(int a);
       +void        chkpn(void);
       +int        findt(int a);
       +int        findt1(void);
       +void        eject(Stack *a);
       +int        movword(void);
       +void        horiz(int i);
       +void        setnel(void);
       +int        getword(int x);
       +void        storeword(Tchar c, int w);
       +Tchar        gettch(void);
       +
       +/*
       + * c8.c
       + */
       +void        hyphen(Tchar *wp);
       +int        punct(Tchar i);
       +int        alph(int i);
       +void        caseha(void);
       +void        caseht(void);
       +void        casehw(void);
       +int        exword(void);
       +int        suffix(void);
       +int        maplow(int i);
       +int        vowel(int i);
       +Tchar*        chkvow(Tchar *w);
       +void        digram(void);
       +int        dilook(int a, int b, char t[26][13]);
       +
       +/*
       + * c9.c
       + */
       +Tchar        setz(void);
       +void        setline(void);
       +int        eat(int c);
       +void        setov(void);
       +void        setbra(void);
       +void        setvline(void);
       +void        setdraw(void);
       +void        casefc(void);
       +Tchar        setfield(int x);
       +
       +/*
       + * t10.c
       + */
       +void        t_ptinit(void);
       +void        t_specnames(void);
       +void        t_ptout(Tchar i);
       +int        ptout0(Tchar *pi);
       +void        ptchname(int);
       +void        ptflush(void);
       +void        ptps(void);
       +void        ptfont(void);
       +void        ptfpcmd(int f, char *s, char *fn);
       +void        t_ptlead(void);
       +void        ptesc(void);
       +void        ptpage(int n);
       +void        pttrailer(void);
       +void        ptstop(void);
       +void        t_ptpause(void);
       +
       +/*
       + * t11.c
       + */
       +int        getdesc(char *name);
       +int        getfont(char *name, int pos);
       +int        chadd(char *s, int, int);
       +char*        chname(int n);
       +int        getlig(FILE *fin);
       +
       +/*
       + * n6.c
       + */
       +int        n_width(Tchar j);
       +Tchar        n_setch(int c);
       +Tchar        n_setabs(void);
       +int        n_findft(int i);
       +void        n_mchbits(void);
       +void        n_setps(void);
       +Tchar        n_setht(void);
       +Tchar        n_setslant(void);
       +void        n_caseft(void);
       +void        n_setfont(int a);
       +void        n_setwd(void);
       +Tchar        n_vmot(void);
       +Tchar        n_hmot(void);
       +Tchar        n_mot(void);
       +Tchar        n_sethl(int k);
       +Tchar        n_makem(int i);
       +void        n_casefp(void);
       +void        n_casebd(void);
       +void        n_casevs(void);
       +Tchar        n_xlss(void);
       +
       +/*
       + * n10.c
       + */
       +void        n_ptinit(void);
       +char*        skipstr(char *s);
       +char*        getstr(char *s, char *t);
       +char*        getint(char *s, int *pn);
       +void        twdone(void);
       +void        n_specnames(void);
       +int        findch(char *s);
       +void        n_ptout(Tchar i);
       +void        ptout1(void);
       +char*        plot(char *x);
       +void        move(void);
       +void        n_ptlead(void);
       +void        n_ptpause(void);
       +
       +/*
       + * indirect calls on TROFF/!TROFF.  these are variables!
       + */
       +extern Tchar        (*hmot)(void);
       +extern Tchar        (*makem)(int i);
       +extern Tchar        (*setabs)(void);
       +extern Tchar        (*setch)(int c);
       +extern Tchar        (*sethl)(int k);
       +extern Tchar        (*setht)(void);
       +extern Tchar        (*setslant)(void);
       +extern Tchar        (*vmot)(void);
       +extern Tchar        (*xlss)(void);
       +extern int        (*findft)(int i);
       +extern int        (*width)(Tchar j);
       +extern void        (*mchbits)(void);
       +extern void        (*ptlead)(void);
       +extern void        (*ptout)(Tchar i);
       +extern void        (*ptpause)(void);
       +extern void        (*setfont)(int a);
       +extern void        (*setps)(void);
       +extern void        (*setwd)(void);
 (DIR) diff --git a/src/cmd/troff/hytab.c b/src/cmd/troff/hytab.c
       t@@ -0,0 +1,126 @@
       +/*
       + * Hyphenation digram tables
       + */
       +
       +typedef unsigned char Uchar;
       +
       +
       +Uchar        bxh[26][13] = {
       +        0060,0000,0040,0000,0040,0000,0000,0040,0000,0000,0040,0000,0040
       +};
       +
       +Uchar        hxx[26][13] = {
       +        0006,0042,0041,0123,0021,0024,0063,0042,0002,0043,0021,0001,0022,
       +        0140,0000,0200,0003,0260,0006,0000,0160,0007,0000,0140,0000,0320,
       +        0220,0000,0160,0005,0240,0010,0000,0100,0006,0000,0200,0000,0320,
       +        0240,0000,0120,0003,0140,0000,0000,0240,0010,0000,0220,0000,0160,
       +        0042,0023,0041,0040,0040,0022,0043,0041,0030,0064,0021,0000,0041,
       +        0100,0000,0140,0000,0220,0006,0000,0140,0003,0000,0200,0000,0000,
       +        0200,0000,0120,0002,0220,0010,0000,0160,0006,0000,0140,0000,0320,
       +        0020,0000,0020,0000,0020,0000,0000,0020,0000,0000,0020,0000,0000,
       +        0043,0163,0065,0044,0022,0043,0104,0042,0061,0146,0061,0000,0007,
       +        0100,0000,0140,0000,0040,0000,0000,0100,0000,0000,0120,0000,0000,
       +        0140,0000,0040,0011,0060,0004,0001,0120,0003,0000,0140,0000,0040,
       +        0200,0000,0100,0000,0140,0000,0000,0140,0000,0000,0140,0000,0240,
       +        0200,0000,0140,0000,0160,0000,0000,0220,0000,0000,0140,0000,0240,
       +        0200,0000,0140,0000,0160,0000,0000,0220,0000,0000,0060,0000,0240,
       +        0021,0043,0041,0121,0040,0023,0042,0003,0142,0042,0061,0001,0022,
       +        0120,0000,0140,0010,0140,0010,0000,0140,0002,0000,0120,0000,0120,
       +        0000,0000,0000,0000,0360,0000,0000,0000,0000,0000,0160,0000,0000,
       +        0100,0000,0040,0005,0120,0000,0000,0100,0000,0000,0060,0000,0140,
       +        0140,0040,0100,0001,0240,0041,0000,0242,0000,0002,0140,0000,0100,
       +        0240,0000,0120,0002,0200,0000,0000,0320,0007,0000,0240,0000,0340,
       +        0101,0021,0041,0020,0040,0005,0042,0121,0002,0021,0201,0000,0020,
       +        0160,0000,0100,0000,0140,0000,0000,0160,0006,0000,0220,0000,0140,
       +        0140,0000,0020,0001,0020,0000,0000,0100,0001,0000,0300,0000,0000,
       +        0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,
       +        0106,0041,0040,0147,0040,0000,0063,0041,0001,0102,0160,0002,0002,
       +        0300,0000,0040,0017,0140,0017,0000,0240,0000,0000,0140,0000,0120,
       +};
       +
       +Uchar        bxxh[26][13] = {
       +        0005,0150,0153,0062,0062,0246,0152,0127,0146,0203,0310,0017,0206,
       +        0100,0000,0120,0000,0140,0000,0000,0100,0000,0000,0120,0000,0060,
       +        0100,0000,0040,0000,0060,0000,0000,0060,0000,0000,0220,0000,0040,
       +        0100,0000,0120,0000,0200,0000,0000,0100,0000,0000,0140,0000,0060,
       +        0043,0142,0046,0140,0062,0147,0210,0131,0046,0106,0246,0017,0111,
       +        0060,0000,0020,0000,0060,0000,0000,0040,0000,0000,0100,0000,0000,
       +        0060,0000,0040,0000,0040,0000,0000,0040,0000,0000,0100,0000,0040,
       +        0100,0000,0100,0000,0100,0000,0000,0040,0000,0000,0100,0000,0140,
       +        0066,0045,0145,0140,0000,0070,0377,0030,0130,0103,0003,0017,0006,
       +        0040,0000,0040,0000,0020,0000,0000,0040,0000,0000,0100,0000,0000,
       +        0200,0000,0020,0000,0140,0000,0000,0120,0000,0000,0120,0000,0040,
       +        0120,0000,0040,0000,0060,0000,0000,0060,0000,0000,0160,0000,0040,
       +        0120,0000,0040,0000,0120,0000,0000,0040,0000,0000,0160,0000,0040,
       +        0120,0000,0020,0000,0140,0000,0000,0120,0000,0000,0140,0000,0040,
       +        0051,0126,0150,0140,0060,0210,0146,0006,0006,0165,0003,0017,0244,
       +        0120,0000,0040,0000,0160,0000,0000,0140,0000,0000,0060,0000,0140,
       +        0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,
       +        0140,0000,0140,0000,0060,0000,0000,0100,0000,0000,0140,0000,0020,
       +        0120,0000,0020,0000,0060,0000,0000,0060,0000,0000,0060,0000,0040,
       +        0140,0000,0020,0000,0100,0000,0000,0140,0000,0000,0140,0000,0020,
       +        0070,0125,0051,0162,0120,0105,0126,0104,0006,0044,0000,0017,0052,
       +        0140,0000,0020,0000,0140,0000,0000,0060,0000,0000,0060,0000,0040,
       +        0020,0000,0000,0000,0020,0000,0000,0000,0000,0000,0000,0000,0060,
       +        0140,0000,0160,0000,0200,0000,0000,0140,0000,0000,0000,0000,0240,
       +        0065,0042,0060,0200,0000,0210,0222,0146,0006,0204,0220,0012,0003,
       +        0240,0000,0020,0000,0120,0000,0000,0200,0000,0000,0200,0000,0240,
       +};
       +
       +Uchar        xhx[26][13] = {
       +        0032,0146,0042,0107,0076,0102,0042,0146,0202,0050,0006,0000,0051,
       +        0036,0377,0057,0013,0057,0366,0377,0057,0001,0377,0057,0000,0040,
       +        0037,0377,0020,0000,0100,0022,0377,0057,0362,0116,0100,0000,0017,
       +        0057,0377,0057,0031,0137,0363,0377,0037,0362,0270,0077,0000,0117,
       +        0074,0142,0012,0236,0076,0125,0063,0165,0341,0046,0047,0000,0024,
       +        0020,0017,0075,0377,0040,0001,0377,0017,0001,0204,0020,0000,0040,
       +        0057,0017,0057,0340,0140,0362,0314,0117,0003,0302,0100,0000,0057,
       +        0057,0357,0077,0017,0100,0366,0314,0057,0342,0346,0037,0000,0060,
       +        0252,0145,0072,0157,0377,0165,0063,0066,0164,0050,0363,0000,0362,
       +        0000,0000,0020,0000,0020,0000,0000,0017,0000,0000,0020,0000,0000,
       +        0117,0017,0237,0377,0200,0354,0125,0110,0004,0257,0000,0000,0300,
       +        0057,0367,0054,0357,0157,0216,0314,0114,0217,0353,0053,0000,0057,
       +        0077,0213,0077,0077,0177,0317,0377,0114,0377,0352,0077,0000,0076,
       +        0077,0213,0077,0077,0157,0177,0377,0054,0377,0352,0117,0000,0075,
       +        0125,0230,0065,0216,0057,0066,0063,0047,0345,0126,0011,0000,0033,
       +        0057,0377,0051,0360,0120,0361,0273,0056,0001,0256,0057,0000,0060,
       +        0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,
       +        0076,0310,0056,0310,0137,0174,0273,0055,0335,0266,0033,0000,0155,
       +        0077,0157,0057,0360,0057,0063,0042,0024,0077,0206,0020,0000,0040,
       +        0057,0037,0077,0360,0100,0365,0377,0037,0362,0176,0050,0000,0026,
       +        0167,0146,0042,0112,0077,0110,0062,0254,0366,0052,0377,0000,0163,
       +        0060,0000,0040,0000,0120,0000,0377,0060,0012,0000,0037,0000,0257,
       +        0037,0232,0157,0361,0040,0003,0125,0010,0001,0256,0000,0000,0340,
       +        0377,0377,0377,0377,0377,0377,0377,0377,0377,0377,0377,0017,0277,
       +        0253,0315,0257,0216,0377,0206,0146,0306,0371,0126,0232,0000,0004,
       +        0057,0012,0100,0360,0160,0360,0000,0040,0000,0017,0157,0000,0176,
       +};
       +
       +Uchar        xxh[26][13] = {
       +        0045,0150,0154,0162,0042,0246,0210,0147,0152,0103,0230,0017,0206,
       +        0100,0000,0040,0000,0140,0000,0000,0100,0000,0021,0120,0017,0060,
       +        0100,0000,0040,0002,0140,0320,0000,0060,0000,0001,0220,0017,0040,
       +        0100,0001,0120,0001,0241,0000,0000,0100,0000,0020,0140,0017,0060,
       +        0023,0162,0046,0142,0022,0207,0210,0131,0052,0106,0250,0017,0110,
       +        0060,0000,0042,0000,0160,0000,0000,0040,0000,0212,0100,0017,0000,
       +        0140,0000,0040,0002,0140,0000,0000,0120,0000,0040,0120,0017,0040,
       +        0100,0000,0100,0000,0140,0001,0021,0140,0000,0046,0100,0017,0140,
       +        0066,0045,0025,0201,0020,0130,0146,0030,0130,0103,0025,0017,0006,
       +        0100,0000,0040,0000,0020,0000,0000,0040,0000,0000,0200,0017,0000,
       +        0200,0000,0020,0001,0140,0000,0000,0140,0000,0000,0120,0017,0040,
       +        0120,0026,0042,0020,0140,0161,0042,0143,0000,0022,0162,0017,0040,
       +        0121,0042,0060,0020,0140,0200,0000,0123,0000,0021,0220,0017,0041,
       +        0121,0042,0060,0120,0140,0200,0000,0123,0000,0021,0160,0017,0041,
       +        0051,0126,0150,0141,0060,0210,0146,0066,0026,0165,0026,0017,0247,
       +        0120,0000,0040,0003,0160,0000,0000,0140,0000,0021,0100,0017,0140,
       +        0000,0000,0000,0000,0200,0000,0000,0000,0000,0000,0000,0017,0000,
       +        0141,0023,0122,0040,0160,0143,0042,0142,0000,0047,0143,0017,0020,
       +        0120,0000,0040,0006,0140,0060,0000,0141,0000,0026,0100,0017,0040,
       +        0140,0000,0020,0007,0100,0000,0000,0140,0000,0001,0140,0017,0020,
       +        0110,0125,0051,0162,0120,0125,0127,0104,0006,0104,0000,0017,0052,
       +        0140,0000,0040,0000,0160,0000,0000,0140,0000,0000,0060,0017,0000,
       +        0040,0005,0020,0000,0040,0313,0231,0030,0000,0140,0000,0017,0056,
       +        0140,0000,0160,0000,0200,0000,0000,0140,0000,0000,0000,0017,0240,
       +        0065,0042,0060,0040,0000,0206,0231,0146,0006,0224,0220,0017,0004,
       +        0240,0000,0020,0000,0140,0000,0000,0220,0000,0000,0200,0017,0141,
       +};
 (DIR) diff --git a/src/cmd/troff/mbwc.c b/src/cmd/troff/mbwc.c
       t@@ -0,0 +1,165 @@
       +#include <stdlib.h>
       +
       +/*
       + * Use the FSS-UTF transformation proposed by posix.
       + *        We define 7 byte types:
       + *        T0        0xxxxxxx        7 free bits
       + *        Tx        10xxxxxx        6 free bits
       + *        T1        110xxxxx        5 free bits
       + *        T2        1110xxxx        4 free bits
       + *
       + *        Encoding is as follows.
       + *        From hex        Thru hex        Sequence                Bits
       + *        00000000        0000007F        T0                        7
       + *        00000080        000007FF        T1 Tx                        11
       + *        00000800        0000FFFF        T2 Tx Tx                16
       + */
       +
       +int
       +mblen(const char *s, size_t n)
       +{
       +
       +        return mbtowc(0, s, n);
       +}
       +
       +int
       +mbtowc(wchar_t *pwc, const char *s, size_t n)
       +{
       +        int c, c1, c2;
       +        long l;
       +
       +        if(!s)
       +                return 0;
       +
       +        if(n < 1)
       +                goto bad;
       +        c = s[0] & 0xff;
       +        if((c & 0x80) == 0x00) {
       +                if(pwc)
       +                        *pwc = c;
       +                if(c == 0)
       +                        return 0;
       +                return 1;
       +        }
       +
       +        if(n < 2)
       +                goto bad;
       +        c1 = (s[1] ^ 0x80) & 0xff;
       +        if((c1 & 0xC0) != 0x00)
       +                goto bad;
       +        if((c & 0xE0) == 0xC0) {
       +                l = ((c << 6) | c1) & 0x7FF;
       +                if(l < 0x080)
       +                        goto bad;
       +                if(pwc)
       +                        *pwc = l;
       +                return 2;
       +        }
       +
       +        if(n < 3)
       +                goto bad;
       +        c2 = (s[2] ^ 0x80) & 0xff;
       +        if((c2 & 0xC0) != 0x00)
       +                goto bad;
       +        if((c & 0xF0) == 0xE0) {
       +                l = ((((c << 6) | c1) << 6) | c2) & 0xFFFF;
       +                if(l < 0x0800)
       +                        goto bad;
       +                if(pwc)
       +                        *pwc = l;
       +                return 3;
       +        }
       +
       +        /*
       +         * bad decoding
       +         */
       +bad:
       +        return -1;
       +
       +}
       +
       +int
       +wctomb(char *s, wchar_t wchar)
       +{
       +        long c;
       +
       +        if(!s)
       +                return 0;
       +
       +        c = wchar & 0xFFFF;
       +        if(c < 0x80) {
       +                s[0] = c;
       +                return 1;
       +        }
       +
       +        if(c < 0x800) {
       +                s[0] = 0xC0 | (c >> 6);
       +                s[1] = 0x80 | (c & 0x3F);
       +                return 2;
       +        }
       +
       +        s[0] = 0xE0 |  (c >> 12);
       +        s[1] = 0x80 | ((c >> 6) & 0x3F);
       +        s[2] = 0x80 |  (c & 0x3F);
       +        return 3;
       +}
       +
       +size_t
       +mbstowcs(wchar_t *pwcs, const char *s, size_t n)
       +{
       +        int i, d, c;
       +
       +        for(i=0; i < n; i++) {
       +                c = *s & 0xff;
       +                if(c < 0x80) {
       +                        *pwcs = c;
       +                        if(c == 0)
       +                                break;
       +                        s++;
       +                } else {
       +                        d = mbtowc(pwcs, s, 3);
       +                        if(d <= 0)
       +                                return (size_t)((d<0) ? -1 : i);
       +                        s += d;
       +                }
       +                pwcs++;
       +        }
       +        return i;
       +}
       +
       +size_t
       +wcstombs(char *s, const wchar_t *pwcs, size_t n)
       +{
       +        int i, d;
       +        long c;
       +        char *p, *pe;
       +        char buf[3];
       +
       +        p = s;
       +        pe = p+n-3;
       +        while(p < pe) {
       +                c = *pwcs++;
       +                if(c < 0x80)
       +                        *p++ = c;
       +                else
       +                        p += wctomb(p, c);
       +                if(c == 0)
       +                        return p-s;
       +        }
       +        while(p < pe+3) {
       +                c = *pwcs++;
       +                d = wctomb(buf, c);
       +                if(p+d <= pe+3) {
       +                        *p++ = buf[0];
       +                        if(d > 1) {
       +                                *p++ = buf[2];
       +                                if(d > 2)
       +                                        *p++ = buf[3];
       +                        }
       +                }
       +                if(c == 0)
       +                        break;
       +        }
       +        return p-s;
       +}
       +
 (DIR) diff --git a/src/cmd/troff/mk.log b/src/cmd/troff/mk.log
       t@@ -0,0 +1,136 @@
       +9c -c -DUNICODE -DFONTDIR="sys/lib/troff/font" -DNTERMDIR="sys/lib/troff/term/tab." -DTEXHYPHENS="#9/sys/lib/texmf/tex/generic/hyphen/hyphen.tex" -DALTHYPHENS="sys/lib/texmf/tex/generic/hyphen/hyphen.tex" -DDWBHOME="#9/" n1.c
       +n1.c:51: warning: return type defaults to `int'
       +n1.c: In function `getch0':
       +n1.c:676: warning: unused variable `j'
       +n1.c:719: warning: label `g2' defined but not used
       +n1.c: In function `get1ch':
       +n1.c:745: warning: `n' might be used uninitialized in this function
       +n1.c:745: warning: `c' might be used uninitialized in this function
       +n1.c: In function `nextfile':
       +n1.c:830: warning: implicit declaration of function `unsharp'
       +n1.c:830: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
       +n1.c: At top level:
       +n1.c:842: warning: return type defaults to `int'
       +n1.c:875: warning: return type defaults to `int'
       +n1.c:915: warning: return type defaults to `int'
       +n1.c: In function `getname':
       +n1.c:917: warning: unused variable `i'
       +n1.c: In function `caseso':
       +n1.c:939: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
       +n1.c:935: warning: unused variable `p'
       +n1.c:935: warning: unused variable `q'
       +n1.c:934: warning: `fp' might be used uninitialized in this function
       +n1.c: In function `casecf':
       +n1.c:1008: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
       +9c -c -DUNICODE n2.c
       +n2.c: In function `outascii':
       +n2.c:140: warning: unused variable `p'
       +9c -c -DUNICODE n3.c
       +n3.c: In function `grow':
       +n3.c:67: warning: unused variable `new'
       +n3.c: In function `finds':
       +n3.c:310: warning: unused variable `j'
       +n3.c: In function `copyb':
       +n3.c:372: warning: `savoff' might be used uninitialized in this function
       +9c -c -DUNICODE n4.c
       +n4.c: In function `setn':
       +n4.c:144: warning: int format, long unsigned int arg (arg 3)
       +9c -c -DUNICODE n5.c
       +n5.c:83: warning: return type defaults to `int'
       +n5.c: In function `chget':
       +n5.c:84: warning: `i' might be used uninitialized in this function
       +n5.c: At top level:
       +n5.c:147: warning: return type defaults to `int'
       +n5.c:338: warning: return type defaults to `int'
       +n5.c: In function `casefm':
       +n5.c:411: warning: implicit declaration of function `unsharp'
       +n5.c:411: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
       +n5.c: At top level:
       +n5.c:747: warning: return type defaults to `int'
       +n5.c:835: warning: return type defaults to `int'
       +9c -c -DUNICODE t6.c
       +t6.c:18: warning: return type defaults to `int'
       +t6.c:79: warning: return type defaults to `int'
       +t6.c:112: warning: return type defaults to `int'
       +t6.c: In function `t_setch':
       +t6.c:217: warning: unused variable `j'
       +t6.c: At top level:
       +t6.c:288: warning: return type defaults to `int'
       +t6.c:367: warning: return type defaults to `int'
       +t6.c: In function `t_setps':
       +t6.c:397: warning: `j' might be used uninitialized in this function
       +t6.c: At top level:
       +t6.c:707: warning: return type defaults to `int'
       +t6.c: In function `setfp':
       +t6.c:708: warning: unused variable `sl'
       +t6.c: In function `casebd':
       +t6.c:781: warning: `j' might be used uninitialized in this function
       +9c -c -DUNICODE n6.c
       +n6.c:11: warning: return type defaults to `int'
       +n6.c: In function `n_casebd':
       +n6.c:295: warning: `j' might be used uninitialized in this function
       +9c -c -DUNICODE n7.c
       +n7.c: In function `newline':
       +n7.c:354: warning: `nlss' might be used uninitialized in this function
       +n7.c: At top level:
       +n7.c:450: warning: return type defaults to `int'
       +n7.c:482: warning: return type defaults to `int'
       +n7.c:509: warning: return type defaults to `int'
       +n7.c:544: warning: return type defaults to `int'
       +n7.c:653: warning: return type defaults to `int'
       +n7.c: In function `getword':
       +n7.c:654: warning: `j' might be used uninitialized in this function
       +9c -c -DUNICODE -DTEXHYPHENS="#9/sys/lib/texmf/tex/generic/hyphen/hyphen.tex" n8.c
       +n8.c:76: warning: return type defaults to `int'
       +n8.c:87: warning: return type defaults to `int'
       +n8.c:222: warning: return type defaults to `int'
       +n8.c:274: warning: return type defaults to `int'
       +n8.c:282: warning: return type defaults to `int'
       +n8.c: In function `digram':
       +n8.c:310: warning: `maxw' might be used uninitialized in this function
       +n8.c: At top level:
       +n8.c:346: warning: return type defaults to `int'
       +n8.c: In function `readpats':
       +n8.c:469: warning: implicit declaration of function `unsharp'
       +n8.c:469: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
       +n8.c:470: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
       +9c -c -DUNICODE n9.c
       +n9.c:80: warning: return type defaults to `int'
       +n9.c: In function `setfield':
       +n9.c:340: warning: `rchar' might be used uninitialized in this function
       +9c -c -DUNICODE -DTDEVNAME="utf" t10.c
       +t10.c: In function `ptout0':
       +t10.c:179: warning: int format, long int arg (arg 3)
       +t10.c:183: warning: int format, long unsigned int arg (arg 3)
       +t10.c:303: warning: int format, long int arg (arg 3)
       +t10.c:157: warning: `w' might be used uninitialized in this function
       +9c -c -DUNICODE -DTDEVNAME="utf" n10.c
       +n10.c: In function `getnrfont':
       +n10.c:77: warning: unused variable `fin'
       +n10.c:81: warning: unused variable `cmd'
       +n10.c:80: warning: `code' might be used uninitialized in this function
       +n10.c: In function `n_ptinit':
       +n10.c:189: warning: implicit declaration of function `unsharp'
       +n10.c:189: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
       +n10.c:142: warning: unused variable `cp'
       +9c -c -DUNICODE t11.c
       +t11.c:21: warning: return type defaults to `int'
       +t11.c: In function `getdesc':
       +t11.c:26: warning: implicit declaration of function `unsharp'
       +t11.c:26: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
       +t11.c: In function `checkfont':
       +t11.c:67: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
       +t11.c: At top level:
       +t11.c:89: warning: return type defaults to `int'
       +t11.c: In function `getfont':
       +t11.c:100: warning: passing arg 1 of `fopen' makes pointer from integer without a cast
       +t11.c:94: warning: `nw' might be used uninitialized in this function
       +t11.c:94: warning: `code' might be used uninitialized in this function
       +t11.c: At top level:
       +t11.c:193: warning: return type defaults to `int'
       +t11.c:235: warning: return type defaults to `int'
       +9c -c -DUNICODE -DTMACDIR="sys/lib/tmac/tmac." ni.c
       +9c -c -DUNICODE hytab.c
       +9c -c -DUNICODE suftab.c
       +9c -c -DUNICODE -DDWBHOME="#9/" dwbinit.c
       +9l -o o.troff n1.o n2.o n3.o n4.o n5.o t6.o n6.o n7.o n8.o n9.o t10.o n10.o t11.o ni.o hytab.o suftab.o dwbinit.o /usr/local/plan9/lib/libbio.a /usr/local/plan9/lib/lib9.a 
 (DIR) diff --git a/src/cmd/troff/mkfile b/src/cmd/troff/mkfile
       t@@ -0,0 +1,58 @@
       +<$PLAN9/src/mkhdr
       +
       +TARG=troff
       +OFILES=n1.$O\
       +        n2.$O\
       +        n3.$O\
       +        n4.$O\
       +        n5.$O\
       +        t6.$O\
       +        n6.$O\
       +        n7.$O\
       +        n8.$O\
       +        n9.$O\
       +        t10.$O\
       +        n10.$O\
       +        t11.$O\
       +        ni.$O\
       +        hytab.$O\
       +        suftab.$O\
       +        dwbinit.$O\
       +        mbwc.$O
       +
       +HFILES=tdef.h\
       +        fns.h\
       +        ext.h\
       +        dwbinit.h\
       +
       +
       +SHORTLIB=bio 9
       +<$PLAN9/src/mkone
       +CFLAGS=-c -DUNICODE
       +
       +TMACDIR='"tmac/tmac."'
       +FONTDIR='"troff/font"'
       +NTERMDIR='"troff/term/tab."'
       +ALTHYPHENS='"lib/hyphen.tex"'
       +TEXHYPHENS='"#9/lib/hyphen.tex"'
       +DWBHOME='"#9/"'
       +TDEVNAME='"utf"'
       +NDEVNAME='"utf"'
       +
       +ni.$O:        ni.c $HFILES
       +        $CC $CFLAGS -DTMACDIR=$TMACDIR ni.c
       +
       +t10.$O:        t10.c $HFILES
       +        $CC $CFLAGS -DTDEVNAME=$TDEVNAME t10.c
       +
       +n1.$O:        n1.c $HFILES
       +        $CC $CFLAGS -DFONTDIR=$FONTDIR -DNTERMDIR=$NTERMDIR -DTEXHYPHENS=$TEXHYPHENS -DALTHYPHENS=$ALTHYPHENS -DDWBHOME=$DWBHOME n1.c
       +
       +n10.$O:        n10.c $HFILES
       +        $CC $CFLAGS -DTDEVNAME=$NDEVNAME n10.c
       +
       +n8.$O:        n8.c $HFILES
       +        $CC $CFLAGS -DTEXHYPHENS=$TEXHYPHENS n8.c
       +
       +dwbinit.$O:        dwbinit.c
       +        $CC $CFLAGS -DDWBHOME=$DWBHOME dwbinit.c
 (DIR) diff --git a/src/cmd/troff/n1.c b/src/cmd/troff/n1.c
       t@@ -0,0 +1,1136 @@
       +/*
       + * n1.c
       + *
       + *        consume options, initialization, main loop,
       + *        input routines, escape function calling
       + */
       +
       +#include "tdef.h"
       +#include "fns.h"
       +#include "ext.h"
       +#include "dwbinit.h"
       +
       +#undef MB_CUR_MAX
       +#define MB_CUR_MAX 3
       +
       +#include <setjmp.h>
       +#include <time.h>
       +
       +char        *Version        = "March 11, 1994";
       +
       +#ifndef DWBVERSION
       +#define DWBVERSION      "???"
       +#endif
       +
       +char        *DWBfontdir = FONTDIR;
       +char        *DWBntermdir = NTERMDIR;
       +char        *DWBalthyphens = ALTHYPHENS;
       +char        *DWBhomedir = "";
       +
       +dwbinit dwbpaths[] = {
       +        &DWBfontdir, NULL, 0,
       +        &DWBntermdir, NULL, 0,
       +        &DWBalthyphens, NULL, 0,
       +        &DWBhomedir, NULL, 0,
       +        NULL, nextf, NS,
       +        NULL, NULL, 0
       +};
       +
       +int        TROFF        = 1;        /* assume we started in troff... */
       +
       +jmp_buf sjbuf;
       +Offset        ipl[NSO];
       +
       +static        FILE        *ifile;
       +static        FILE        *ifl[NSO];        /* open input file pointers */
       +char        cfname[NSO+1][NS] = {  "stdin" };        /* file name stack */
       +int        cfline[NSO];                /* input line count stack */
       +char        *progname;                /* program name (troff or nroff) */
       +
       +int        trace = 0;        /* tracing mode: default off */
       +int        trace1 = 0;
       +
       +main(int argc, char *argv[])
       +{
       +        char *p;
       +        int j;
       +        Tchar i;
       +        char buf[100];
       +
       +        ifile = stdin;
       +        ptid = stdout;
       +
       +        buf[0] = '\0';                /* make sure it's empty (silly 3b2) */
       +        progname = argv[0];
       +        if ((p = strrchr(progname, '/')) == NULL)
       +                p = progname;
       +        else
       +                p++;
       +        DWBinit(progname, dwbpaths);
       +        if (strcmp(p, "nroff") == 0)
       +                TROFF = 0;
       +#ifdef UNICODE
       +        alphabet = 128;        /* unicode for plan 9 */
       +#endif        /*UNICODE*/
       +        mnspace();
       +        nnspace();
       +        mrehash();
       +        nrehash();
       +        numtabp[NL].val = -1;
       +
       +        while (--argc > 0 && (++argv)[0][0] == '-')
       +                switch (argv[0][1]) {
       +
       +                case 'N':        /* ought to be used first... */
       +                        TROFF = 0;
       +                        break;
       +                case 'd':
       +                        fprintf(stderr, "troff/nroff version %s\n", Version);
       +                        break;
       +                case 'F':        /* switch font tables from default */
       +                        if (argv[0][2] != '\0') {
       +                                strcpy(termtab, &argv[0][2]);
       +                                strcpy(fontdir, &argv[0][2]);
       +                        } else {
       +                                argv++; argc--;
       +                                strcpy(termtab, argv[0]);
       +                                strcpy(fontdir, argv[0]);
       +                        }
       +                        break;
       +                case 0:
       +                        goto start;
       +                case 'i':
       +                        stdi++;
       +                        break;
       +                case 'n':
       +                        npn = atoi(&argv[0][2]);
       +                        break;
       +                case 'u':        /* set emboldening amount */
       +                        bdtab[3] = atoi(&argv[0][2]);
       +                        if (bdtab[3] < 0 || bdtab[3] > 50)
       +                                bdtab[3] = 0;
       +                        break;
       +                case 's':
       +                        if (!(stop = atoi(&argv[0][2])))
       +                                stop++;
       +                        break;
       +                case 'r':
       +                        sprintf(buf + strlen(buf), ".nr %c %s\n",
       +                                argv[0][2], &argv[0][3]);
       +                        /* not yet cpushback(buf);*/
       +                        /* dotnr(&argv[0][2], &argv[0][3]); */
       +                        break;
       +                case 'm':
       +                        if (mflg++ >= NMF) {
       +                                ERROR "Too many macro packages: %s", argv[0] WARN;
       +                                break;
       +                        }
       +                        strcpy(mfiles[nmfi], nextf);
       +                        strcat(mfiles[nmfi++], &argv[0][2]);
       +                        break;
       +                case 'o':
       +                        getpn(&argv[0][2]);
       +                        break;
       +                case 'T':
       +                        strcpy(devname, &argv[0][2]);
       +                        dotT++;
       +                        break;
       +                case 'a':
       +                        ascii = 1;
       +                        break;
       +                case 'h':
       +                        hflg++;
       +                        break;
       +                case 'e':
       +                        eqflg++;
       +                        break;
       +                case 'q':
       +                        quiet++;
       +                        save_tty();
       +                        break;
       +                case 'V':
       +                        fprintf(stdout, "%croff: DWB %s\n", 
       +                                        TROFF ? 't' : 'n', DWBVERSION);
       +                        exit(0);
       +                case 't':
       +                        if (argv[0][2] != '\0')
       +                                trace = trace1 = argv[0][2];
       +                        break;                /* for the sake of compatibility */
       +                default:
       +                        ERROR "unknown option %s", argv[0] WARN;
       +                        done(02);
       +                }
       +
       +start:
       +        /*
       +         * cpushback maintains a LIFO, so push pack the -r arguments
       +         * in reverse order to maintain a FIFO in case someone did -rC1 -rC3
       +         */
       +        if (buf[0]) {
       +                char *p = buf;
       +                while(*p++)
       +                        ;
       +                while(p > buf) {
       +                        while(strncmp(p, ".nr", 3) != 0)
       +                                p--;
       +                        cpushback(p);
       +                        *p-- = '\0';
       +                }
       +        }
       +        argp = argv;
       +        rargc = argc;
       +        nmfi = 0;
       +        init2();
       +        setjmp(sjbuf);
       +loop:
       +        copyf = lgf = nb = nflush = nlflg = 0;
       +        if (ip && rbf0(ip) == 0 && ejf && frame->pframe <= ejl && dip == d) {
       +                nflush++;
       +                trap = 0;
       +                eject((Stack *)0);
       +                goto loop;
       +        }
       +        i = getch();
       +        if (pendt)
       +                goto Lt;
       +        if ((j = cbits(i)) == XPAR) {
       +                copyf++;
       +                tflg++;
       +                while (cbits(i) != '\n')
       +                        pchar(i = getch());
       +                tflg = 0;
       +                copyf--;
       +                goto loop;
       +        }
       +        if (j == cc || j == c2) {
       +                if (j == c2)
       +                        nb++;
       +                copyf++;
       +                while ((j = cbits(i = getch())) == ' ' || j == '\t')
       +                        ;
       +                ch = i;
       +                copyf--;
       +                control(getrq(), 1);
       +                flushi();
       +                goto loop;
       +        }
       +Lt:
       +        ch = i;
       +        text();
       +        if (nlflg)
       +                numtabp[HP].val = 0;
       +        goto loop;
       +}
       +
       +
       +
       +void init2(void)
       +{
       +        int i;
       +        char buf[100];
       +
       +        for (i = NTRTAB; --i; )
       +                trtab[i] = i;
       +        trtab[UNPAD] = ' ';
       +        iflg = 0;
       +        obufp = obuf;
       +        if (TROFF)
       +                t_ptinit();
       +        else
       +                n_ptinit();
       +        mchbits();
       +        cvtime();
       +        numtabp[PID].val = getpid();
       +        numtabp[HP].val = init = 0;
       +        numtabp[NL].val = -1;
       +        nfo = 0;
       +        copyf = raw = 0;
       +        sprintf(buf, ".ds .T %s\n", devname);
       +        cpushback(buf);
       +        sprintf(buf, ".ds .P %s\n", DWBhomedir);
       +        cpushback(buf);
       +        numtabp[CD].val = -1;        /* compensation */
       +        nx = mflg;
       +        frame = stk = (Stack *)setbrk(STACKSIZE);
       +        dip = &d[0];
       +        nxf = frame + 1;
       +        for (i = 1; i < NEV; i++)        /* propagate the environment */
       +                envcopy(&env[i], &env[0]);
       +        for (i = 0; i < NEV; i++) {
       +                if ((env[i]._word._bufp = (Tchar *)calloc(WDSIZE, sizeof(Tchar))) == NULL) {
       +                        ERROR "not enough room for word buffers" WARN;
       +                        done2(1);
       +                }
       +                env[i]._word._size = WDSIZE;
       +                if ((env[i]._line._bufp = (Tchar *)calloc(LNSIZE, sizeof(Tchar))) == NULL) {
       +                        ERROR "not enough room for line buffers" WARN;
       +                        done2(1);
       +                }
       +                env[i]._line._size = LNSIZE;
       +        }
       +        if ((oline = (Tchar *)calloc(OLNSIZE, sizeof(Tchar))) == NULL) {
       +                ERROR "not enough room for line buffers" WARN;
       +                done2(1);
       +        }
       +        olinep = oline;
       +        olnsize = OLNSIZE;
       +        blockinit();
       +}
       +
       +void cvtime(void)
       +{
       +        long tt;
       +        struct tm *ltime;
       +
       +        time(&tt);
       +        ltime = localtime(&tt);
       +        numtabp[YR].val = ltime->tm_year % 100;
       +        numtabp[YR].fmt = 2;
       +        numtabp[MO].val = ltime->tm_mon + 1;        /* troff uses 1..12 */
       +        numtabp[DY].val = ltime->tm_mday;
       +        numtabp[DW].val = ltime->tm_wday + 1;        /* troff uses 1..7 */
       +}
       +
       +
       +
       +char        errbuf[200];
       +
       +void errprint(void)        /* error message printer */
       +{
       +        int savecd = numtabp[CD].val;
       +
       +        if (!nlflg)
       +                numtabp[CD].val++;
       +
       +        fprintf(stderr, "%s: ", progname);
       +        fputs(errbuf, stderr);
       +        if (cfname[ifi][0])
       +                fprintf(stderr, "; %s:%d", cfname[ifi], numtabp[CD].val);
       +        fputs("\n", stderr);
       +        if (cfname[ifi][0])
       +                stackdump();
       +        numtabp[CD].val = savecd;
       +}
       +
       +
       +int control(int a, int b)
       +{
       +        int j, k;
       +        extern Contab *contabp;
       +
       +        numerr.type = RQERR;
       +        numerr.req = a;
       +        if (a == 0 || (j = findmn(a)) == -1)
       +                return(0);
       +        if (contabp[j].f == 0) {
       +                if (trace & TRMAC)
       +                        fprintf(stderr, "invoke macro %s\n", unpair(a));
       +                if (dip != d)
       +                        for (k = dilev; k; k--)
       +                                if (d[k].curd == a) {
       +                                        ERROR "diversion %s invokes itself during diversion",
       +                                                                unpair(a) WARN;
       +                                        edone(0100);
       +                                }
       +                nxf->nargs = 0;
       +                if (b)
       +                        collect();
       +                flushi();
       +                return pushi(contabp[j].mx, a);        /* BUG??? all that matters is 0/!0 */
       +        }
       +        if (b) {
       +                if (trace & TRREQ)
       +                        fprintf(stderr, "invoke request %s\n", unpair(a));
       +                 (*contabp[j].f)();
       +        }
       +        return(0);
       +}
       +
       +void casept(void)
       +{
       +        int i;
       +
       +        noscale++;
       +        if (skip())
       +                i = trace1;
       +        else {
       +                i = max(inumb(&trace), 0);
       +                if (nonumb)
       +                        i = trace1;
       +        }
       +        trace1 = trace;
       +        trace = i;
       +        noscale = 0;
       +}
       +
       +
       +int getrq(void)
       +{
       +        int i, j;
       +
       +        if ((i = getach()) == 0 || (j = getach()) == 0)
       +                goto rtn;
       +        i = PAIR(i, j);
       +rtn:
       +        return(i);
       +}
       +
       +/*
       + * table encodes some special characters, to speed up tests
       + * in getch, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch
       + */
       +
       +char gchtab[NCHARS] = {
       +        000,004,000,000,010,000,000,000, /* fc, ldr */
       +        001,002,001,000,001,000,000,000, /* \b, tab, nl, RPT */
       +        000,000,000,000,000,000,000,000,
       +        000,001,000,001,000,000,000,000, /* FLSS, ESC */
       +        000,000,000,000,000,000,000,000,
       +        000,000,000,000,000,000,000,000,
       +        000,000,000,000,000,000,000,000,
       +        000,000,000,000,000,000,000,000,
       +        000,000,000,000,000,000,000,000,
       +        000,000,000,000,000,000,000,000,
       +        000,000,000,000,000,000,000,000,
       +        000,000,000,000,000,000,000,000,
       +        000,000,000,000,000,000,001,000, /* f */
       +        000,000,000,000,000,000,000,000,
       +        000,000,000,000,000,000,000,000,
       +        000,000,000,000,000,000,000,000,
       +};
       +
       +int realcbits(Tchar c)        /* return character bits, or MOTCH if motion */
       +{
       +        if (ismot(c))
       +                return MOTCH;
       +        else
       +                return c & 0xFFFF;
       +}
       +
       +Tchar getch(void)
       +{
       +        int k;
       +        Tchar i, j;
       +
       +g0:
       +        if (ch) {
       +                i = ch;
       +                if (cbits(i) == '\n')
       +                        nlflg++;
       +                ch = 0;
       +                return(i);
       +        }
       +
       +        if (nlflg)
       +                return('\n');
       +        i = getch0();
       +        if (ismot(i))
       +                return(i);
       +        k = cbits(i);
       +        if (k >= sizeof(gchtab)/sizeof(gchtab[0]) || gchtab[k] == 0)        /* nothing special */
       +                return(i);
       +        if (k != ESC) {
       +                if (k == '\n') {
       +                        nlflg++;
       +                        if (ip == 0)
       +                                numtabp[CD].val++; /* line number */
       +                        return(k);
       +                }
       +                if (k == FLSS) {
       +                        copyf++; 
       +                        raw++;
       +                        i = getch0();
       +                        if (!fi)
       +                                flss = i;
       +                        copyf--; 
       +                        raw--;
       +                        goto g0;
       +                }
       +                if (k == RPT) {
       +                        setrpt();
       +                        goto g0;
       +                }
       +                if (!copyf) {
       +                        if (k == 'f' && lg && !lgf) {
       +                                i = getlg(i);
       +                                return(i);
       +                        }
       +                        if (k == fc || k == tabch || k == ldrch) {
       +                                if ((i = setfield(k)) == 0)
       +                                        goto g0; 
       +                                else 
       +                                        return(i);
       +                        }
       +                        if (k == '\b') {
       +                                i = makem(-width(' ' | chbits));
       +                                return(i);
       +                        }
       +                }
       +                return(i);
       +        }
       +
       +        k = cbits(j = getch0());
       +        if (ismot(j))
       +                return(j);
       +
       +        switch (k) {
       +        case 'n':        /* number register */
       +                setn();
       +                goto g0;
       +        case '$':        /* argument indicator */
       +                seta();
       +                goto g0;
       +        case '*':        /* string indicator */
       +                setstr();
       +                goto g0;
       +        case '{':        /* LEFT */
       +                i = LEFT;
       +                goto gx;
       +        case '}':        /* RIGHT */
       +                i = RIGHT;
       +                goto gx;
       +        case '"':        /* comment */
       +                while (cbits(i = getch0()) != '\n')
       +                        ;
       +                if (ip == 0)
       +                        numtabp[CD].val++; /* line number */
       +                nlflg++;
       +                return(i);
       +
       +/* experiment: put it here instead of copy mode */
       +        case '(':        /* special char name \(xx */
       +        case 'C':        /*                 \C'...' */
       +                if ((i = setch(k)) == 0)
       +                        goto g0;
       +                goto gx;
       +
       +        case ESC:        /* double backslash */
       +                i = eschar;
       +                goto gx;
       +        case 'e':        /* printable version of current eschar */
       +                i = PRESC;
       +                goto gx;
       +        case '\n':        /* concealed newline */
       +                numtabp[CD].val++;
       +                goto g0;
       +        case ' ':        /* unpaddable space */
       +                i = UNPAD;
       +                goto gx;
       +        case '\'':        /* \(aa */
       +                i = ACUTE;
       +                goto gx;
       +        case '`':        /* \(ga */
       +                i = GRAVE;
       +                goto gx;
       +        case '_':        /* \(ul */
       +                i = UNDERLINE;
       +                goto gx;
       +        case '-':        /* current font minus */
       +                i = MINUS;
       +                goto gx;
       +        case '&':        /* filler */
       +                i = FILLER;
       +                goto gx;
       +        case 'c':        /* to be continued */
       +                i = CONT;
       +                goto gx;
       +        case '!':        /* transparent indicator */
       +                i = XPAR;
       +                goto gx;
       +        case 't':        /* tab */
       +                i = '\t';
       +                return(i);
       +        case 'a':        /* leader (SOH) */
       +/* old:                *pbp++ = LEADER; goto g0; */
       +                i = LEADER;
       +                return i;
       +        case '%':        /* ohc */
       +                i = OHC;
       +                return(i);
       +        case 'g':        /* return format of a number register */
       +                setaf();        /* should this really be in copy mode??? */
       +                goto g0;
       +        case '.':        /* . */
       +                i = '.';
       +gx:
       +                setsfbits(i, sfbits(j));
       +                return(i);
       +        }
       +        if (copyf) {
       +                *pbp++ = j;
       +                return(eschar);
       +        }
       +        switch (k) {
       +
       +        case 'f':        /* font indicator */
       +                setfont(0);
       +                goto g0;
       +        case 's':        /* size indicator */
       +                setps();
       +                goto g0;
       +        case 'v':        /* vert mot */
       +                numerr.type = numerr.escarg = 0; numerr.esc = k;
       +                if (i = vmot()) {
       +                        return(i);
       +                }
       +                goto g0;
       +        case 'h':         /* horiz mot */
       +                numerr.type = numerr.escarg = 0; numerr.esc = k;
       +                if (i = hmot())
       +                        return(i);
       +                goto g0;
       +        case '|':        /* narrow space */
       +                if (NROFF)
       +                        goto g0;
       +                return(makem((int)(EM)/6));
       +        case '^':        /* half narrow space */
       +                if (NROFF)
       +                        goto g0;
       +                return(makem((int)(EM)/12));
       +        case 'w':        /* width function */
       +                setwd();
       +                goto g0;
       +        case 'p':        /* spread */
       +                spread++;
       +                goto g0;
       +        case 'N':        /* absolute character number */
       +                numerr.type = numerr.escarg = 0; numerr.esc = k;
       +                if ((i = setabs()) == 0)
       +                        goto g0;
       +                return i;
       +        case 'H':        /* character height */
       +                numerr.type = numerr.escarg = 0; numerr.esc = k;
       +                return(setht());
       +        case 'S':        /* slant */
       +                numerr.type = numerr.escarg = 0; numerr.esc = k;
       +                return(setslant());
       +        case 'z':        /* zero with char */
       +                return(setz());
       +        case 'l':        /* hor line */
       +                numerr.type = numerr.escarg = 0; numerr.esc = k;
       +                setline();
       +                goto g0;
       +        case 'L':        /* vert line */
       +                numerr.type = numerr.escarg = 0; numerr.esc = k;
       +                setvline();
       +                goto g0;
       +        case 'D':        /* drawing function */
       +                numerr.type = numerr.escarg = 0; numerr.esc = k;
       +                setdraw();
       +                goto g0;
       +        case 'X':        /* \X'...' for copy through */
       +                setxon();
       +                goto g0;
       +        case 'b':        /* bracket */
       +                setbra();
       +                goto g0;
       +        case 'o':        /* overstrike */
       +                setov();
       +                goto g0;
       +        case 'k':        /* mark hor place */
       +                if ((k = findr(getsn())) != -1) {
       +                        numtabp[k].val = numtabp[HP].val;
       +                }
       +                goto g0;
       +        case '0':        /* number space */
       +                return(makem(width('0' | chbits)));
       +        case 'x':        /* extra line space */
       +                numerr.type = numerr.escarg = 0; numerr.esc = k;
       +                if (i = xlss())
       +                        return(i);
       +                goto g0;
       +        case 'u':        /* half em up */
       +        case 'r':        /* full em up */
       +        case 'd':        /* half em down */
       +                return(sethl(k));
       +        default:
       +                return(j);
       +        }
       +        /* NOTREACHED */
       +}
       +
       +void setxon(void)        /* \X'...' for copy through */
       +{
       +        Tchar xbuf[NC];
       +        Tchar *i;
       +        Tchar c;
       +        int delim, k;
       +
       +        if (ismot(c = getch()))
       +                return;
       +        delim = cbits(c);
       +        i = xbuf;
       +        *i++ = XON | chbits;
       +        while ((k = cbits(c = getch())) != delim && k != '\n' && i < xbuf+NC-1) {
       +                if (k == ' ')
       +                        setcbits(c, WORDSP);
       +                *i++ = c | ZBIT;
       +        }
       +        *i++ = XOFF | chbits;
       +        *i = 0;
       +        pushback(xbuf);
       +}
       +
       +
       +char        ifilt[32] = { 0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012 };
       +
       +Tchar getch0(void)
       +{
       +        int j;
       +        Tchar i;
       +
       +again:
       +        if (pbp > lastpbp)
       +                i = *--pbp;
       +        else if (ip) {
       +                /* i = rbf(); */
       +                i = rbf0(ip);
       +                if (i == 0)
       +                        i = rbf();
       +                else {
       +                        ++ip;
       +                        if (pastend(ip)) {
       +                                --ip;
       +                                rbf();
       +                        }
       +                }
       +        } else {
       +                if (donef || ndone)
       +                        done(0);
       +                if (nx || 1) {        /* BUG: was ibufp >= eibuf, so EOF test is wrong */
       +                        if (nfo < 0)
       +                                ERROR "in getch0, nfo = %d", nfo WARN;
       +                        if (nfo == 0) {
       +g0:
       +                                if (nextfile()) {
       +                                        if (ip)
       +                                                goto again;
       +                                }
       +                        }
       +                        nx = 0;
       +#ifdef UNICODE
       +                        if (MB_CUR_MAX > 1)
       +                                i = get1ch(ifile);
       +                        else
       +#endif        /*UNICODE*/
       +                                i = getc(ifile);
       +                        if (i == EOF)
       +                                goto g0;
       +                        if (ip)
       +                                goto again;
       +                }
       +g2:
       +                if (i >= 040)                        /* zapped: && i < 0177 */
       +                        goto g4;
       +                i = ifilt[i];
       +        }
       +        if (cbits(i) == IMP && !raw)
       +                goto again;
       +        if (i == 0 && !init && !raw) {                /* zapped:  || i == 0177 */
       +                goto again;
       +        }
       +g4:
       +        if (ismot(i))
       +                return i;
       +        if (copyf == 0 && sfbits(i) == 0)
       +                i |= chbits;
       +        if (cbits(i) == eschar && !raw)
       +                setcbits(i, ESC);
       +        return(i);
       +}
       +
       +
       +#ifdef UNICODE
       +Tchar get1ch(FILE *fp)        /* get one "character" from input, figure out what alphabet */
       +{
       +        wchar_t wc;
       +        char buf[100], *p;
       +        int i, n, c;
       +
       +        for (i = 0, p = buf; i < MB_CUR_MAX; i++) {
       +                if ((c = getc(fp)) == EOF)
       +                        return c;
       +                *p++ = c;
       +                if ((n = mbtowc(&wc, buf, p-buf)) >= 0)
       +                        break;
       +        }
       +        if (n == 1)        /* real ascii, presumably */
       +                return wc;
       +        if (n == 0)
       +                return p[-1];        /* illegal, but what else to do? */
       +        if (c == EOF)
       +                return EOF;
       +        *p = 0;
       +        return chadd(buf, MBchar, Install);        /* add name even if haven't seen it */
       +}
       +#endif        /*UNICODE*/
       +
       +void pushback(Tchar *b)
       +{
       +        Tchar *ob = b;
       +
       +        while (*b++)
       +                ;
       +        b--;
       +        while (b > ob && pbp < &pbbuf[NC-3])
       +                *pbp++ = *--b;
       +        if (pbp >= &pbbuf[NC-3]) {
       +                ERROR "pushback overflow" WARN;
       +                done(2);
       +        }
       +}
       +
       +void cpushback(char *b)
       +{
       +        char *ob = b;
       +
       +        while (*b++)
       +                ;
       +        b--;
       +        while (b > ob && pbp < &pbbuf[NC-3])
       +                *pbp++ = *--b;
       +        if (pbp >= &pbbuf[NC-3]) {
       +                ERROR "cpushback overflow" WARN;
       +                done(2);
       +        }
       +}
       +
       +int nextfile(void)
       +{
       +        char *p;
       +
       +n0:
       +        if (ifile != stdin)
       +                fclose(ifile);
       +        if (ifi > 0 && !nx) {
       +                if (popf())
       +                        goto n0; /* popf error */
       +                return(1);         /* popf ok */
       +        }
       +        if (nx || nmfi < mflg) {
       +                p = mfiles[nmfi++];
       +                if (*p != 0)
       +                        goto n1;
       +        }
       +        if (rargc-- <= 0) {
       +                if ((nfo -= mflg) && !stdi) {
       +                        done(0);
       +}
       +                nfo++;
       +                numtabp[CD].val = stdi = mflg = 0;
       +                ifile = stdin;
       +                strcpy(cfname[ifi], "stdin");
       +                return(0);
       +        }
       +        p = (argp++)[0];
       +        if (rargc >= 0)
       +                cfname[ifi][0] = 0;
       +n1:
       +        numtabp[CD].val = 0;
       +        if (p[0] == '-' && p[1] == 0) {
       +                ifile = stdin;
       +                strcpy(cfname[ifi], "stdin");
       +        } else if ((ifile = fopen(unsharp(p), "r")) == NULL) {
       +                ERROR "cannot open file %s", p WARN;
       +                nfo -= mflg;
       +                done(02);
       +        } else
       +                strcpy(cfname[ifi],p);
       +        nfo++;
       +        return(0);
       +}
       +
       +
       +popf(void)
       +{
       +        --ifi;
       +        if (ifi < 0) {
       +                ERROR "popf went negative" WARN;
       +                return 1;
       +        }
       +        numtabp[CD].val = cfline[ifi];        /* restore line counter */
       +        ip = ipl[ifi];                        /* input pointer */
       +        ifile = ifl[ifi];                /* input FILE * */
       +        return(0);
       +}
       +
       +
       +void flushi(void)
       +{
       +        if (nflush)
       +                return;
       +        ch = 0;
       +        copyf++;
       +        while (!nlflg) {
       +                if (donef && frame == stk)
       +                        break;
       +                getch();
       +        }
       +        copyf--;
       +}
       +
       +/*
       + * return 16-bit, ascii/alphabetic character, ignore chars with more bits,
       + * (internal names), spaces and special cookies (below 040).
       + * Leave STX ETX ENQ ACK and BELL in to maintain compatibility with v7 troff.
       + */
       +getach(void)
       +{
       +        Tchar i;
       +        int j;
       +
       +        lgf++;
       +        j = cbits(i = getch());
       +        if (ismot(i)
       +            || j > SHORTMASK
       +            || (j <= 040 && j != 002        /*STX*/
       +                        && j != 003        /*ETX*/
       +                        && j != 005        /*ENQ*/
       +                        && j != 006        /*ACK*/
       +                        && j != 007)) {        /*BELL*/
       +                ch = i;
       +                j = 0;
       +        }
       +        lgf--;
       +        return j;
       +}
       +
       +
       +void casenx(void)
       +{
       +        lgf++;
       +        skip();
       +        getname();
       +        nx++;
       +        if (nmfi > 0)
       +                nmfi--;
       +        strcpy(mfiles[nmfi], nextf);
       +        nextfile();
       +        nlflg++;
       +        ip = 0;
       +        pendt = 0;
       +        frame = stk;
       +        nxf = frame + 1;
       +}
       +
       +
       +getname(void)
       +{
       +        int j, k;
       +        Tchar i;
       +
       +        lgf++;
       +        for (k = 0; k < NS - 1; k++) {
       +                j = getach();
       +                if (!j)
       +                        break;
       +                nextf[k] = j;
       +        }
       +        nextf[k] = 0;
       +        lgf--;
       +        return(nextf[0]);
       +}
       +
       +
       +void caseso(void)
       +{
       +        FILE *fp;
       +        char *p, *q;
       +
       +        lgf++;
       +        nextf[0] = 0;
       +        if (skip() || !getname() || (fp = fopen(unsharp(nextf), "r")) == NULL || ifi >= NSO) {
       +                ERROR "can't open file %s", nextf WARN;
       +                done(02);
       +        }
       +        strcpy(cfname[ifi+1], nextf);
       +        cfline[ifi] = numtabp[CD].val;                /*hold line counter*/
       +        numtabp[CD].val = 0;
       +        flushi();
       +        ifl[ifi] = ifile;
       +        ifile = fp;
       +        ipl[ifi] = ip;
       +        ip = 0;
       +        nx++;
       +        nflush++;
       +        ifi++;
       +}
       +
       +void caself(void)        /* set line number and file */
       +{
       +        int n;
       +
       +        if (skip())
       +                return;
       +        n = atoi0();
       +        if (!nonumb)
       +                cfline[ifi] = numtabp[CD].val = n - 1;
       +        if (!skip())
       +                if (getname()) {        /* eats '\n' ? */
       +                        strcpy(cfname[ifi], nextf);
       +                        if (!nonumb)
       +                                numtabp[CD].val--;
       +                }
       +}
       +
       +void cpout(FILE *fin, char *token)
       +{
       +        int n;
       +        char buf[1024];
       +
       +        if (token) {        /* BUG: There should be no NULL bytes in input */
       +                char *newl = buf;
       +                while ((fgets(buf, sizeof buf, fin)) != NULL) {
       +                        if (newl) {
       +                                numtabp[CD].val++; /* line number */
       +                                if (strcmp(token, buf) == 0)
       +                                        return;
       +                        }
       +                        newl = strchr(buf, '\n');
       +                        fputs(buf, ptid);
       +                }
       +        } else {
       +                while ((n = fread(buf, sizeof *buf, sizeof buf, fin)) > 0)
       +                        fwrite(buf, n, 1, ptid);
       +                fclose(fin);
       +        }
       +}
       +
       +void casecf(void)
       +{        /* copy file without change */
       +        FILE *fd;
       +        char *eof, *p;
       +        extern int hpos, esc, po;
       +
       +        /* this may not make much sense in nroff... */
       +
       +        lgf++;
       +        nextf[0] = 0;
       +        if (!skip() && getname()) {
       +                if (strncmp("<<", nextf, 2) != 0) {
       +                        if ((fd = fopen(unsharp(nextf), "r")) == NULL) {
       +                                ERROR "can't open file %s", nextf WARN;
       +                                done(02);
       +                        }
       +                        eof = (char *) NULL;
       +                } else {        /* current file */
       +                        if (pbp > lastpbp || ip) {
       +                                ERROR "casecf: not reading from file" WARN;
       +                                done(02);
       +                        }
       +                        eof = &nextf[2];
       +                        if (!*eof)  {
       +                                ERROR "casecf: missing end of input token" WARN;
       +                                done(02);
       +                        }
       +                        p = eof;
       +                        while(*++p)
       +                                ;
       +                        *p++ = '\n';
       +                        *p = 0;
       +                        fd = ifile;
       +                }
       +        } else {
       +                ERROR "casecf: no argument" WARN;
       +                lgf--;
       +                return;
       +        }
       +        lgf--;
       +
       +        /* make it into a clean state, be sure that everything is out */
       +        tbreak();
       +        hpos = po;
       +        esc = 0;
       +        ptesc();        /* to left margin */
       +        esc = un;
       +        ptesc();
       +        ptlead();
       +        ptps();
       +        ptfont();
       +        flusho();
       +        cpout(fd, eof);
       +        ptps();
       +        ptfont();
       +}
       +
       +void getline(char *s, int n)        /* get rest of input line into s */
       +{
       +        int i;
       +
       +        lgf++;
       +        copyf++;
       +        skip();
       +        for (i = 0; i < n-1; i++)
       +                if ((s[i] = cbits(getch())) == '\n' || s[i] == RIGHT)
       +                        break;
       +        s[i] = 0;
       +        copyf--;
       +        lgf--;
       +}
       +
       +void casesy(void)        /* call system */
       +{
       +        char sybuf[NTM];
       +
       +        getline(sybuf, NTM);
       +        system(sybuf);
       +}
       +
       +
       +void getpn(char *a)
       +{
       +        int n, neg;
       +
       +        if (*a == 0)
       +                return;
       +        neg = 0;
       +        for ( ; *a; a++)
       +                switch (*a) {
       +                case '+':
       +                case ',':
       +                        continue;
       +                case '-':
       +                        neg = 1;
       +                        continue;
       +                default:
       +                        n = 0;
       +                        if (isdigit(*a)) {
       +                                do
       +                                        n = 10 * n + *a++ - '0';
       +                                while (isdigit(*a));
       +                                a--;
       +                        } else
       +                                n = 9999;
       +                        *pnp++ = neg ? -n : n;
       +                        neg = 0;
       +                        if (pnp >= &pnlist[NPN-2]) {
       +                                ERROR "too many page numbers" WARN;
       +                                done3(-3);
       +                        }
       +                }
       +        if (neg)
       +                *pnp++ = -9999;
       +        *pnp = -INT_MAX;
       +        print = 0;
       +        pnp = pnlist;
       +        if (*pnp != -INT_MAX)
       +                chkpn();
       +}
       +
       +
       +void setrpt(void)
       +{
       +        Tchar i, j;
       +
       +        copyf++;
       +        raw++;
       +        i = getch0();
       +        copyf--;
       +        raw--;
       +        if ((long) i < 0 || cbits(j = getch0()) == RPT)
       +                return;
       +        while (i > 0 && pbp < &pbbuf[NC-3]) {
       +                i--;
       +                *pbp++ = j;
       +        }
       +}
 (DIR) diff --git a/src/cmd/troff/n10.c b/src/cmd/troff/n10.c
       t@@ -0,0 +1,549 @@
       +/*
       +n10.c
       +
       +Device interfaces
       +*/
       +
       +#include "tdef.h"
       +#include "ext.h"
       +#include "fns.h"
       +#include <ctype.h>
       +
       +Term        t;        /* terminal characteristics */
       +
       +int        dtab;
       +int        plotmode;
       +int        esct;
       +
       +enum        { Notype = 0, Type = 1 };
       +
       +static char *parse(char *s, int typeit)        /* convert \0, etc to nroff driving table format */
       +{                /* typeit => add a type id to the front for later use */
       +        static char buf[100], *t, *obuf;
       +        int quote = 0;
       +        wchar_t wc;
       +
       +        obuf = typeit == Type ? buf : buf+1;
       +#ifdef UNICODE
       +        if (mbtowc(&wc, s, strlen(s)) > 1) {        /* it's multibyte, */
       +                buf[0] = MBchar;
       +                strcpy(buf+1, s);
       +                return obuf;
       +        }                        /* so just hand it back */
       +#endif        /*UNICODE*/
       +        buf[0] = Troffchar;
       +        t = buf + 1;
       +        if (*s == '"') {
       +                s++;
       +                quote = 1;
       +        }
       +        for (;;) {
       +                if (quote && *s == '"') {
       +                        s++;
       +                        break;
       +                }
       +                if (!quote && (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\0'))
       +                        break;
       +                if (*s != '\\')
       +                        *t++ = *s++;
       +                else {
       +                        s++;        /* skip \\ */
       +                        if (isdigit(s[0]) && isdigit(s[1]) && isdigit(s[2])) {
       +                                *t++ = (s[0]-'0')<<6 | (s[1]-'0')<<3 | s[2]-'0';
       +                                s += 2;
       +                        } else if (isdigit(s[0])) {
       +                                *t++ = *s - '0';
       +                        } else if (*s == 'b') {
       +                                *t++ = '\b';
       +                        } else if (*s == 'n') {
       +                                *t++ = '\n';
       +                        } else if (*s == 'r') {
       +                                *t++ = '\r';
       +                        } else if (*s == 't') {
       +                                *t++ = '\t';
       +                        } else {
       +                                *t++ = *s;
       +                        }
       +                        s++;
       +                }
       +        }
       +        *t = '\0';
       +        return obuf;
       +}
       +
       +
       +static int getnrfont(FILE *fp)        /* read the nroff description file */
       +{
       +        FILE *fin;
       +        Chwid chtemp[NCHARS];
       +        static Chwid chinit;
       +        int i, nw, n, wid, code, type;
       +        char buf[100], ch[100], s1[100], s2[100], cmd[300];
       +        wchar_t wc;
       +
       +
       +        chinit.wid = 1;
       +        chinit.str = "";
       +        for (i = 0; i < ALPHABET; i++) {
       +                chtemp[i] = chinit;        /* zero out to begin with */
       +                chtemp[i].num = chtemp[i].code = i;        /* every alphabetic character is itself */
       +                chtemp[i].wid = 1;        /* default ascii widths */
       +        }
       +        skipline(fp);
       +        nw = ALPHABET;
       +        while (fgets(buf, sizeof buf, fp) != NULL) {
       +                sscanf(buf, "%s %s %[^\n]", ch, s1, s2);
       +                if (!eq(s1, "\"")) {        /* genuine new character */
       +                        sscanf(s1, "%d", &wid);
       +                } /* else it's a synonym for prev character, */
       +                        /* so leave previous values intact */
       +
       +                /* decide what kind of alphabet it might come from */
       +
       +                if (strlen(ch) == 1) {        /* it's ascii */
       +                        n = ch[0];        /* origin includes non-graphics */
       +                        chtemp[n].num = ch[0];
       +                } else if (ch[0] == '\\' && ch[1] == '0') {
       +                        n = strtol(ch+1, 0, 0);        /* \0octal or \0xhex */
       +                        chtemp[n].num = n;
       +#ifdef UNICODE
       +                } else if (mbtowc(&wc, ch, strlen(ch)) > 1) {
       +                        chtemp[nw].num = chadd(ch, MBchar, Install);
       +                        n = nw;
       +                        nw++;
       +#endif        /*UNICODE*/
       +                } else {
       +                        if (strcmp(ch, "---") == 0) { /* no name */
       +                                sprintf(ch, "%d", code);
       +                                type = Number;
       +                        } else
       +                                type = Troffchar;
       +/* BUG in here somewhere when same character occurs twice in table */
       +                        chtemp[nw].num = chadd(ch, type, Install);
       +                        n = nw;
       +                        nw++;
       +                }
       +                chtemp[n].wid = wid;
       +                chtemp[n].str = strdupl(parse(s2, Type));
       +        }
       +        t.tfont.nchars = nw;
       +        t.tfont.wp = (Chwid *) malloc(nw * sizeof(Chwid));
       +        if (t.tfont.wp == NULL)
       +                return -1;
       +        for (i = 0; i < nw; i++)
       +                t.tfont.wp[i] = chtemp[i];
       +        return 1;
       +}
       +
       +
       +void n_ptinit(void)
       +{
       +        int i;
       +        char *p, *cp;
       +        char opt[50], cmd[100];
       +        FILE *fp;
       +
       +        hmot = n_hmot;
       +        makem = n_makem;
       +        setabs = n_setabs;
       +        setch = n_setch;
       +        sethl = n_sethl;
       +        setht = n_setht;
       +        setslant = n_setslant;
       +        vmot = n_vmot;
       +        xlss = n_xlss;
       +        findft = n_findft;
       +        width = n_width;
       +        mchbits = n_mchbits;
       +        ptlead = n_ptlead;
       +        ptout = n_ptout;
       +        ptpause = n_ptpause;
       +        setfont = n_setfont;
       +        setps = n_setps;
       +        setwd = n_setwd;
       +
       +        if ((p = getenv("NROFFTERM")) != 0)
       +                strcpy(devname, p);
       +        if (termtab[0] == 0)
       +                strcpy(termtab,DWBntermdir);
       +        if (fontdir[0] == 0)
       +                strcpy(fontdir, "");
       +        if (devname[0] == 0)
       +                strcpy(devname, NDEVNAME);
       +        pl = 11*INCH;
       +        po = PO;
       +        hyf = 0;
       +        ascii = 1;
       +        lg = 0;
       +        fontlab[1] = 'R';
       +        fontlab[2] = 'I';
       +        fontlab[3] = 'B';
       +        fontlab[4] = PAIR('B','I');
       +        fontlab[5] = 'D';
       +        bdtab[3] = 3;
       +        bdtab[4] = 3;
       +
       +        /* hyphalg = 0;        /* for testing */
       +
       +        strcat(termtab, devname);
       +        if ((fp = fopen(unsharp(termtab), "r")) == NULL) {
       +                ERROR "cannot open %s", termtab WARN;
       +                exit(-1);
       +        }
       +
       +
       +/* this loop isn't robust about input format errors. */
       +/* it assumes  name, name-value pairs..., charset */
       +/* god help us if we get out of sync. */
       +
       +        fscanf(fp, "%s", cmd);        /* should be device name... */
       +        if (!is(devname) && trace)
       +                ERROR "wrong terminal name: saw %s, wanted %s", cmd, devname WARN;
       +        for (;;) {
       +                fscanf(fp, "%s", cmd);
       +                if (is("charset"))
       +                        break;
       +                fscanf(fp, " %[^\n]", opt);
       +                if (is("bset")) t.bset = atoi(opt);
       +                else if (is("breset")) t.breset = atoi(opt);
       +                else if (is("Hor")) t.Hor = atoi(opt);
       +                else if (is("Vert")) t.Vert = atoi(opt);
       +                else if (is("Newline")) t.Newline = atoi(opt);
       +                else if (is("Char")) t.Char = atoi(opt);
       +                else if (is("Em")) t.Em = atoi(opt);
       +                else if (is("Halfline")) t.Halfline = atoi(opt);
       +                else if (is("Adj")) t.Adj = atoi(opt);
       +                else if (is("twinit")) t.twinit = strdupl(parse(opt, Notype));
       +                else if (is("twrest")) t.twrest = strdupl(parse(opt, Notype));
       +                else if (is("twnl")) t.twnl = strdupl(parse(opt, Notype));
       +                else if (is("hlr")) t.hlr = strdupl(parse(opt, Notype));
       +                else if (is("hlf")) t.hlf = strdupl(parse(opt, Notype));
       +                else if (is("flr")) t.flr = strdupl(parse(opt, Notype));
       +                else if (is("bdon")) t.bdon = strdupl(parse(opt, Notype));
       +                else if (is("bdoff")) t.bdoff = strdupl(parse(opt, Notype));
       +                else if (is("iton")) t.iton = strdupl(parse(opt, Notype));
       +                else if (is("itoff")) t.itoff = strdupl(parse(opt, Notype));
       +                else if (is("ploton")) t.ploton = strdupl(parse(opt, Notype));
       +                else if (is("plotoff")) t.plotoff = strdupl(parse(opt, Notype));
       +                else if (is("up")) t.up = strdupl(parse(opt, Notype));
       +                else if (is("down")) t.down = strdupl(parse(opt, Notype));
       +                else if (is("right")) t.right = strdupl(parse(opt, Notype));
       +                else if (is("left")) t.left = strdupl(parse(opt, Notype));
       +                else
       +                        ERROR "bad tab.%s file, %s %s", devname, cmd, opt WARN;
       +        }
       +
       +        getnrfont(fp);
       +        fclose(fp);
       +
       +        sps = EM;
       +        ics = EM * 2;
       +        dtab = 8 * t.Em;
       +        for (i = 0; i < 16; i++)
       +                tabtab[i] = dtab * (i + 1);
       +        pl = 11 * INCH;
       +        po = PO;
       +        spacesz = SS;
       +        lss = lss1 = VS;
       +        ll = ll1 = lt = lt1 = LL;
       +        smnt = nfonts = 5;        /* R I B BI S */
       +        n_specnames();        /* install names like "hyphen", etc. */
       +        if (eqflg)
       +                t.Adj = t.Hor;
       +}
       +
       +
       +void n_specnames(void)
       +{
       +
       +        int        i;
       +
       +        for (i = 0; spnames[i].n; i++)
       +                *spnames[i].n = chadd(spnames[i].v, Troffchar, Install);
       +        if (c_isalnum == 0)
       +                c_isalnum = NROFFCHARS;
       +}
       +
       +void twdone(void)
       +{
       +        if (!TROFF && t.twrest) {
       +                obufp = obuf;
       +                oputs(t.twrest);
       +                flusho();
       +                if (pipeflg) {
       +                        pclose(ptid);
       +                }
       +                restore_tty();
       +        }
       +}
       +
       +
       +void n_ptout(Tchar i)
       +{
       +        *olinep++ = i;
       +        if (olinep >= &oline[LNSIZE])
       +                olinep--;
       +        if (cbits(i) != '\n')
       +                return;
       +        olinep--;
       +        lead += dip->blss + lss - t.Newline;
       +        dip->blss = 0;
       +        esct = esc = 0;
       +        if (olinep > oline) {
       +                move();
       +                ptout1();
       +                oputs(t.twnl);
       +        } else {
       +                lead += t.Newline;
       +                move();
       +        }
       +        lead += dip->alss;
       +        dip->alss = 0;
       +        olinep = oline;
       +}
       +
       +
       +void ptout1(void)
       +{
       +        int k;
       +        char *codep;
       +        int w, j, phyw;
       +        Tchar *q, i;
       +        static int oxfont = FT;        /* start off in roman */
       +
       +        for (q = oline; q < olinep; q++) {
       +                i = *q;
       +                if (ismot(i)) {
       +                        j = absmot(i);
       +                        if (isnmot(i))
       +                                j = -j;
       +                        if (isvmot(i))
       +                                lead += j;
       +                        else 
       +                                esc += j;
       +                        continue;
       +                }
       +                if ((k = cbits(i)) <= ' ') {
       +                        switch (k) {
       +                        case ' ': /*space*/
       +                                esc += t.Char;
       +                                break;
       +                        case '\033':
       +                        case '\007':
       +                        case '\016':
       +                        case '\017':
       +                                oput(k);
       +                                break;
       +                        }
       +                        continue;
       +                }
       +                phyw = w = t.Char * t.tfont.wp[k].wid;
       +                if (iszbit(i))
       +                        w = 0;
       +                if (esc || lead)
       +                        move();
       +                esct += w;
       +                xfont = fbits(i);
       +                if (xfont != oxfont) {
       +                        switch (oxfont) {
       +                        case ULFONT:        oputs(t.itoff); break;
       +                        case BDFONT:        oputs(t.bdoff); break;
       +                        case BIFONT:        oputs(t.itoff); oputs(t.bdoff); break;
       +                        }
       +                        switch (xfont) {
       +                        case ULFONT:
       +                                if (*t.iton & 0377) oputs(t.iton); break;
       +                        case BDFONT:
       +                                if (*t.bdon & 0377) oputs(t.bdon); break;
       +                        case BIFONT:
       +                                if (*t.bdon & 0377) oputs(t.bdon);
       +                                if (*t.iton & 0377) oputs(t.iton);
       +                                break;
       +                        }
       +                        oxfont = xfont;
       +                }
       +                if ((xfont == ulfont || xfont == BIFONT) && !(*t.iton & 0377)) {
       +                        for (j = w / t.Char; j > 0; j--)
       +                                oput('_');
       +                        for (j = w / t.Char; j > 0; j--)
       +                                oput('\b');
       +                }
       +                if (!(*t.bdon & 0377) && ((j = bdtab[xfont]) || xfont == BDFONT || xfont == BIFONT))
       +                        j++;
       +                else
       +                        j = 1;        /* number of overstrikes for bold */
       +                if (k < ALPHABET) {        /* ordinary ascii */
       +                        oput(k);
       +                        while (--j > 0) {
       +                                oput('\b');
       +                                oput(k);
       +                        }
       +                } else if (k >= t.tfont.nchars) {        /* BUG -- not really understood */
       +/* fprintf(stderr, "big char %d, name %s\n", k, chname(k)); /* */
       +                        oputs(chname(k)+1);        /* BUG: should separate Troffchar and MBchar... */
       +                } else if (t.tfont.wp[k].str == 0) {
       +/* fprintf(stderr, "nostr char %d, name %s\n", k, chname(k)); /* */
       +                        oputs(chname(k)+1);        /* BUG: should separate Troffchar and MBchar... */
       +                } else if (t.tfont.wp[k].str[0] == MBchar) {        /* parse() puts this on */
       +/* fprintf(stderr, "MBstr char %d, name %s\n", k, chname(k)); /* */
       +                        oputs(t.tfont.wp[k].str+1);
       +                } else {
       +                        int oj = j;
       +/* fprintf(stderr, "str char %d, name %s\n", k, chname(k)); /* */
       +                        codep = t.tfont.wp[k].str+1;        /* Troffchar by default */
       +                        while (*codep != 0) {
       +                                if (*codep & 0200) {
       +                                        codep = plot(codep);
       +                                        oput(' ');
       +                                } else {
       +                                        if (*codep == '%')        /* escape */
       +                                                codep++;
       +                                        oput(*codep);
       +                                        if (*codep == '\033')
       +                                                oput(*++codep);
       +                                        else if (*codep != '\b')
       +                                                for (j = oj; --j > 0; ) {
       +                                                        oput('\b');
       +                                                        oput(*codep);
       +                                                }
       +                                        codep++;
       +                                }
       +                        }
       +                }
       +                if (!w)
       +                        for (j = phyw / t.Char; j > 0; j--)
       +                                oput('\b');
       +        }
       +}
       +
       +
       +char *plot(char *x)
       +{
       +        int        i;
       +        char        *j, *k;
       +
       +        oputs(t.ploton);
       +        k = x;
       +        if ((*k & 0377) == 0200)
       +                k++;
       +        for (; *k; k++) {
       +                if (*k == '%') {        /* quote char within plot mode */
       +                        oput(*++k);
       +                } else if (*k & 0200) {
       +                        if (*k & 0100) {
       +                                if (*k & 040)
       +                                        j = t.up; 
       +                                else 
       +                                        j = t.down;
       +                        } else {
       +                                if (*k & 040)
       +                                        j = t.left; 
       +                                else 
       +                                        j = t.right;
       +                        }
       +                        if ((i = *k & 037) == 0) {        /* 2nd 0200 turns it off */
       +                                ++k;
       +                                break;
       +                        }
       +                        while (i--)
       +                                oputs(j);
       +                } else 
       +                        oput(*k);
       +        }
       +        oputs(t.plotoff);
       +        return(k);
       +}
       +
       +
       +void move(void)
       +{
       +        int k;
       +        char *i, *j;
       +        char *p, *q;
       +        int iesct, dt;
       +
       +        iesct = esct;
       +        if (esct += esc)
       +                i = "\0"; 
       +        else 
       +                i = "\n\0";
       +        j = t.hlf;
       +        p = t.right;
       +        q = t.down;
       +        if (lead) {
       +                if (lead < 0) {
       +                        lead = -lead;
       +                        i = t.flr;
       +                        /*        if(!esct)i = t.flr; else i = "\0";*/
       +                        j = t.hlr;
       +                        q = t.up;
       +                }
       +                if (*i & 0377) {
       +                        k = lead / t.Newline;
       +                        lead = lead % t.Newline;
       +                        while (k--)
       +                                oputs(i);
       +                }
       +                if (*j & 0377) {
       +                        k = lead / t.Halfline;
       +                        lead = lead % t.Halfline;
       +                        while (k--)
       +                                oputs(j);
       +                } else { /* no half-line forward, not at line begining */
       +                        k = lead / t.Newline;
       +                        lead = lead % t.Newline;
       +                        if (k > 0) 
       +                                esc = esct;
       +                        i = "\n";
       +                        while (k--) 
       +                                oputs(i);
       +                }
       +        }
       +        if (esc) {
       +                if (esc < 0) {
       +                        esc = -esc;
       +                        j = "\b";
       +                        p = t.left;
       +                } else {
       +                        j = " ";
       +                        if (hflg)
       +                                while ((dt = dtab - (iesct % dtab)) <= esc) {
       +                                        if (dt % t.Em)
       +                                                break;
       +                                        oput(TAB);
       +                                        esc -= dt;
       +                                        iesct += dt;
       +                                }
       +                }
       +                k = esc / t.Em;
       +                esc = esc % t.Em;
       +                while (k--)
       +                        oputs(j);
       +        }
       +        if ((*t.ploton & 0377) && (esc || lead)) {
       +                oputs(t.ploton);
       +                esc /= t.Hor;
       +                lead /= t.Vert;
       +                while (esc--)
       +                        oputs(p);
       +                while (lead--)
       +                        oputs(q);
       +                oputs(t.plotoff);
       +        }
       +        esc = lead = 0;
       +}
       +
       +
       +void n_ptlead(void)
       +{
       +        move();
       +}
       +
       +
       +void n_ptpause(void )
       +{
       +        char        junk;
       +
       +        flusho();
       +        read(2, &junk, 1);
       +}
 (DIR) diff --git a/src/cmd/troff/n2.c b/src/cmd/troff/n2.c
       t@@ -0,0 +1,325 @@
       +/*
       + * n2.c
       + *
       + * output, cleanup
       + */
       +
       +#include "tdef.h"
       +#include "fns.h"
       +#include "ext.h"
       +#include <setjmp.h>
       +
       +#ifdef STRICT
       +        /* not in ANSI or POSIX */
       +FILE*        popen(char*, char*);
       +#endif
       +
       +
       +extern        jmp_buf        sjbuf;
       +int        toolate;
       +int        error;
       +
       +char        obuf[2*BUFSIZ];
       +char        *obufp = obuf;
       +
       +        /* pipe command structure; allows redicously long commends for .pi */
       +struct Pipe {
       +        char        *buf;
       +        int        tick;
       +        int        cnt;
       +} Pipe;
       +
       +
       +int        xon        = 0;        /* records if in middle of \X */
       +
       +int pchar(Tchar i)
       +{
       +        int j;
       +        static int hx = 0;        /* records if have seen HX */
       +
       +        if (hx) {
       +                hx = 0;
       +                j = absmot(i);
       +                if (isnmot(i)) {
       +                        if (j > dip->blss)
       +                                dip->blss = j;
       +                } else {
       +                        if (j > dip->alss)
       +                                dip->alss = j;
       +                        ralss = dip->alss;
       +                }
       +                return 0;
       +        }
       +        if (ismot(i)) {
       +                pchar1(i); 
       +                return 0;
       +        }
       +        switch (j = cbits(i)) {
       +        case 0:
       +        case IMP:
       +        case RIGHT:
       +        case LEFT:
       +                return 0;
       +        case HX:
       +                hx = 1;
       +                return 0;
       +        case XON:
       +                xon++;
       +                break;
       +        case XOFF:
       +                xon--;
       +                break;
       +        case PRESC:
       +                if (!xon && !tflg && dip == &d[0])
       +                        j = eschar;        /* fall through */
       +        default:
       +                setcbits(i, trtab[j]);
       +        }
       +        if (NROFF & xon)        /* rob fix for man2html */
       +                return 0;
       +        pchar1(i);
       +        return 0;
       +}
       +
       +
       +void pchar1(Tchar i)
       +{
       +        int j;
       +
       +        j = cbits(i);
       +        if (dip != &d[0]) {
       +                wbf(i);
       +                dip->op = offset;
       +                return;
       +        }
       +        if (!tflg && !print) {
       +                if (j == '\n')
       +                        dip->alss = dip->blss = 0;
       +                return;
       +        }
       +        if (j == FILLER && !xon)
       +                return;
       +        if (tflg) {        /* transparent mode, undiverted */
       +                if (print)                        /* assumes that it's ok to print */
       +                        /* OUT "%c", j PUT;        /* i.e., is ascii */
       +                        outascii(i);
       +                return;
       +        }
       +        if (TROFF && ascii)
       +                outascii(i);
       +        else
       +                ptout(i);
       +}
       +
       +
       +void outweird(int k)        /* like ptchname() but ascii */
       +{
       +        char *chn = chname(k);
       +
       +        switch (chn[0]) {
       +        case MBchar:
       +                OUT "%s", chn+1 PUT;        /* \n not needed? */
       +                break;
       +        case Number:
       +                OUT "\\N'%s'", chn+1 PUT;
       +                break;
       +        case Troffchar:
       +                if (strlen(chn+1) == 2)
       +                        OUT "\\(%s", chn+1 PUT;
       +                else
       +                        OUT "\\C'%s'", chn+1 PUT;
       +                break;
       +        default:
       +                OUT " %s? ", chn PUT;
       +                break;
       +        }
       +}
       +
       +void outascii(Tchar i)        /* print i in best-guess ascii */
       +{
       +        char *p;
       +        int j = cbits(i);
       +
       +/* is this ever called with NROFF set? probably doesn't work at all. */
       +
       +        if (ismot(i))
       +                oput(' ');
       +        else if (j < ALPHABET && j >= ' ' || j == '\n' || j == '\t')
       +                oput(j);
       +        else if (j == DRAWFCN)
       +                oputs("\\D");
       +        else if (j == HYPHEN)
       +                oput('-');
       +        else if (j == MINUS)        /* special pleading for strange encodings */
       +                oputs("\\-");
       +        else if (j == PRESC)
       +                oputs("\\e");
       +        else if (j == FILLER)
       +                oputs("\\&");
       +        else if (j == UNPAD)
       +                oputs("\\ ");
       +        else if (j == OHC)        /* this will never occur;  stripped out earlier */
       +                oputs("\\%");
       +        else if (j == XON)
       +                oputs("\\X");
       +        else if (j == XOFF)
       +                oputs(" ");
       +        else if (j == LIG_FI)
       +                oputs("fi");
       +        else if (j == LIG_FL)
       +                oputs("fl");
       +        else if (j == LIG_FF)
       +                oputs("ff");
       +        else if (j == LIG_FFI)
       +                oputs("ffi");
       +        else if (j == LIG_FFL)
       +                oputs("ffl");
       +        else if (j == WORDSP) {                /* nothing at all */
       +                if (xon)                /* except in \X */
       +                        oput(' ');
       +
       +        } else
       +                outweird(j);
       +}
       +
       +int flusho(void)
       +{
       +        if (NROFF && !toolate && t.twinit)
       +                        fwrite(t.twinit, strlen(t.twinit), 1, ptid);
       +
       +        if (obufp > obuf) {
       +                if (pipeflg && !toolate) {
       +                        /* fprintf(stderr, "Pipe to <%s>\n", Pipe.buf); */
       +                        if (!Pipe.buf[0] || (ptid = popen(Pipe.buf, "w")) == NULL)
       +                                ERROR "pipe %s not created.", Pipe.buf WARN;
       +                        if (Pipe.buf)
       +                                free(Pipe.buf);
       +                }
       +                if (!toolate)
       +                        toolate++;
       +                *obufp = 0;
       +                fputs(obuf, ptid);
       +                fflush(ptid);
       +                obufp = obuf;
       +        }
       +        return 1;
       +}
       +
       +
       +void caseex(void)
       +{
       +        done(0);
       +}
       +
       +
       +void done(int x) 
       +{
       +        int i;
       +
       +        error |= x;
       +        app = ds = lgf = 0;
       +        if (i = em) {
       +                donef = -1;
       +                eschar = '\\';
       +                em = 0;
       +                if (control(i, 0))
       +                        longjmp(sjbuf, 1);
       +        }
       +        if (!nfo)
       +                done3(0);
       +        mflg = 0;
       +        dip = &d[0];
       +        if (woff)        /* BUG!!! This isn't set anywhere */
       +                wbf((Tchar)0);
       +        if (pendw)
       +                getword(1);
       +        pendnf = 0;
       +        if (donef == 1)
       +                done1(0);
       +        donef = 1;
       +        ip = 0;
       +        frame = stk;
       +        nxf = frame + 1;
       +        if (!ejf)
       +                tbreak();
       +        nflush++;
       +        eject((Stack *)0);
       +        longjmp(sjbuf, 1);
       +}
       +
       +
       +void done1(int x) 
       +{
       +        error |= x;
       +        if (numtabp[NL].val) {
       +                trap = 0;
       +                eject((Stack *)0);
       +                longjmp(sjbuf, 1);
       +        }
       +        if (!ascii)
       +                pttrailer();
       +        done2(0);
       +}
       +
       +
       +void done2(int x) 
       +{
       +        ptlead();
       +        if (TROFF && !ascii)
       +                ptstop();
       +        flusho();
       +        done3(x);
       +}
       +
       +void done3(int x) 
       +{
       +        error |= x;
       +        flusho();
       +        if (NROFF)
       +                twdone();
       +        if (pipeflg)
       +                pclose(ptid);
       +        exit(error);
       +}
       +
       +
       +void edone(int x) 
       +{
       +        frame = stk;
       +        nxf = frame + 1;
       +        ip = 0;
       +        done(x);
       +}
       +
       +
       +void casepi(void)
       +{
       +        int j;
       +        char buf[NTM];
       +
       +        if (Pipe.buf == NULL) {
       +                if ((Pipe.buf = (char *)calloc(NTM, sizeof(char))) == NULL) {
       +                        ERROR "No buf space for pipe cmd" WARN;
       +                        return;
       +                }
       +                Pipe.tick = 1;
       +        } else
       +                Pipe.buf[Pipe.cnt++] = '|';
       +
       +        getline(buf, NTM);
       +        j = strlen(buf);
       +        if (toolate) {
       +                ERROR "Cannot create pipe to %s", buf WARN;
       +                return;
       +        }
       +        Pipe.cnt += j;
       +        if (j >= NTM +1) {
       +                Pipe.tick++;
       +                if ((Pipe.buf = (char *)realloc(Pipe.buf, Pipe.tick * NTM * sizeof(char))) == NULL) {
       +                        ERROR "No more buf space for pipe cmd" WARN;
       +                        return;
       +                }
       +        }
       +        strcat(Pipe.buf, buf);
       +        pipeflg++;
       +}
 (DIR) diff --git a/src/cmd/troff/n3.c b/src/cmd/troff/n3.c
       t@@ -0,0 +1,954 @@
       +/*
       + * troff3.c
       + * 
       + * macro and string routines, storage allocation
       + */
       +
       +#include "tdef.h"
       +#include "fns.h"
       +#include "ext.h"
       +
       +Tchar        *argtop;
       +int        pagech = '%';
       +int        strflg;
       +
       +#define        MHASHSIZE        128        /* must be 2**n */
       +#define        MHASH(x)        ((x>>6)^x) & (MHASHSIZE-1)
       +Contab        *mhash[MHASHSIZE];
       +
       +
       +Blockp        *blist;                /* allocated blocks for macros and strings */
       +int        nblist;                /* how many there are */
       +int        bfree = -1;        /* first (possible) free block in the list */
       +
       +Contab *contabp = NULL;
       +#define MDELTA 500
       +int        nm = 0;
       +
       +int savname;                /* name of macro/string being defined */
       +int savslot;                /* place in Contab of savname */
       +int freeslot = -1;        /* first (possible) free slot in contab */
       +
       +void prcontab(Contab *p)
       +{
       +        int i;
       +        for (i = 0; i < nm; i++)
       +                if (p)
       +                        if (p[i].rq != 0)
       +                                fprintf(stderr, "slot %d, %-2.2s\n", i, unpair(p[i].rq));
       +                        else
       +                                fprintf(stderr, "slot %d empty\n", i);
       +                else
       +                        fprintf(stderr, "slot %d empty\n", i);
       +}
       +
       +
       +void blockinit(void)
       +{
       +        blist = (Blockp *) calloc(NBLIST, sizeof(Blockp));
       +        if (blist == NULL) {
       +                ERROR "not enough room for %d blocks", NBLIST WARN;
       +                done2(1);
       +        }
       +        nblist = NBLIST;
       +        blist[0].nextoff = blist[1].nextoff = -1;
       +        blist[0].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
       +        blist[1].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
       +                /* -1 prevents blist[0] from being used; temporary fix */
       +                /* for a design botch: offset==0 is overloaded. */
       +                /* blist[1] reserved for .rd indicator -- also unused. */
       +                /* but someone unwittingly looks at these, so allocate something */
       +        bfree = 2;
       +}
       +
       +
       +char *grow(char *ptr, int num, int size)        /* make array bigger */
       +{
       +        char *p, new;
       +
       +        if (ptr == NULL)
       +                p = (char *) calloc(num, size);
       +        else
       +                p = (char *) realloc(ptr, num * size);
       +        return p;
       +}
       +
       +void mnspace(void)
       +{
       +        nm = sizeof(contab)/sizeof(Contab) + MDELTA;
       +        freeslot = sizeof(contab)/sizeof(Contab) + 1;
       +        contabp = (Contab *) grow((char *) contabp, nm, sizeof(Contab));
       +        if (contabp == NULL) {
       +                ERROR "not enough memory for namespace of %d marcos", nm WARN;
       +                exit(1);
       +        }
       +        contabp = (Contab *) memcpy((char *) contabp, (char *)contab,
       +                                                        sizeof(contab));
       +        if (contabp == NULL) {
       +                ERROR "Cannot reinitialize macro/request name list" WARN;
       +                exit(1);
       +        }
       +
       +}
       +
       +void caseig(void)
       +{
       +        int i;
       +        Offset oldoff = offset;
       +
       +        offset = 0;
       +        i = copyb();
       +        offset = oldoff;
       +        if (i != '.')
       +                control(i, 1);
       +}
       +
       +
       +void casern(void)
       +{
       +        int i, j, k;
       +
       +        lgf++;
       +        skip();
       +        if ((i = getrq()) == 0 || (oldmn = findmn(i)) < 0)
       +                return;
       +        skip();
       +        clrmn(findmn(j = getrq()));
       +        if (j) {
       +                munhash(&contabp[oldmn]);
       +                contabp[oldmn].rq = j;
       +                maddhash(&contabp[oldmn]);
       +                if (dip != d )
       +                        for (k = dilev; k; k--)
       +                                if (d[k].curd == i)
       +                                        d[k].curd = j;
       +        }
       +}
       +
       +void maddhash(Contab *rp)
       +{
       +        Contab **hp;
       +
       +        if (rp->rq == 0)
       +                return;
       +        hp = &mhash[MHASH(rp->rq)];
       +        rp->link = *hp;
       +        *hp = rp;
       +}
       +
       +void munhash(Contab *mp)
       +{        
       +        Contab *p;
       +        Contab **lp;
       +
       +        if (mp->rq == 0)
       +                return;
       +        lp = &mhash[MHASH(mp->rq)];
       +        p = *lp;
       +        while (p) {
       +                if (p == mp) {
       +                        *lp = p->link;
       +                        p->link = 0;
       +                        return;
       +                }
       +                lp = &p->link;
       +                p = p->link;
       +        }
       +}
       +
       +void mrehash(void)
       +{
       +        Contab *p;
       +        int i;
       +
       +        for (i=0; i < MHASHSIZE; i++)
       +                mhash[i] = 0;
       +        for (p=contabp; p < &contabp[nm]; p++)
       +                p->link = 0;
       +        for (p=contabp; p < &contabp[nm]; p++) {
       +                if (p->rq == 0)
       +                        continue;
       +                i = MHASH(p->rq);
       +                p->link = mhash[i];
       +                mhash[i] = p;
       +        }
       +}
       +
       +void caserm(void)
       +{
       +        int j;
       +        int k = 0;
       +
       +        lgf++;
       +g0:
       +        while (!skip() && (j = getrq()) != 0) {
       +                if (dip != d)
       +                        for (k = dilev; k; k--)
       +                                if (d[k].curd == j) {
       +                                        ERROR "cannot remove diversion %s during definition",
       +                                                                unpair(j) WARN;
       +                                        goto g0;
       +                                }
       +                clrmn(findmn(j));
       +        }
       +        lgf--;
       +}
       +
       +
       +void caseas(void)
       +{
       +        app++;
       +        caseds();
       +}
       +
       +
       +void caseds(void)
       +{
       +        ds++;
       +        casede();
       +}
       +
       +
       +void caseam(void)
       +{
       +        app++;
       +        casede();
       +}
       +
       +
       +void casede(void)
       +{
       +        int i, req;
       +        Offset savoff;
       +
       +        req = '.';
       +        lgf++;
       +        skip();
       +        if ((i = getrq()) == 0)
       +                goto de1;
       +        if ((offset = finds(i)) == 0)
       +                goto de1;
       +        if (newmn)
       +                savslot = newmn;
       +        else
       +                savslot = findmn(i);
       +        savname = i;
       +        if (ds)
       +                copys();
       +        else
       +                req = copyb();
       +        clrmn(oldmn);
       +        if (newmn) {
       +                if (contabp[newmn].rq)
       +                        munhash(&contabp[newmn]);
       +                contabp[newmn].rq = i;
       +                maddhash(&contabp[newmn]);
       +
       +        }
       +        if (apptr) {
       +                savoff = offset;
       +                offset = apptr;
       +                wbf((Tchar) IMP);
       +                offset = savoff;
       +        }
       +        offset = dip->op;
       +        if (req != '.')
       +                control(req, 1);
       +de1:
       +        ds = app = 0;
       +}
       +
       +
       +int findmn(int i)
       +{
       +        Contab *p;
       +
       +        for (p = mhash[MHASH(i)]; p; p = p->link)
       +                if (i == p->rq)
       +                        return(p - contabp);
       +        return(-1);
       +}
       +
       +
       +void clrmn(int i)
       +{
       +        if (i >= 0) {
       +                if (contabp[i].mx)
       +                        ffree(contabp[i].mx);
       +                munhash(&contabp[i]);
       +                contabp[i].rq = 0;
       +                contabp[i].mx = 0;
       +                contabp[i].emx = 0;
       +                contabp[i].f = 0;
       +                if (contabp[i].divsiz != NULL) {
       +                        free(contabp[i].divsiz);
       +                        contabp[i].divsiz = NULL;
       +                }
       +                if (freeslot > i)
       +                        freeslot = i;
       +        }
       +}
       +
       +void growcontab(void)
       +{
       +        nm += MDELTA;
       +        contabp = (Contab *) grow((char *) contabp , nm, sizeof(Contab));
       +        if (contabp == NULL) {
       +                ERROR "Too many (%d) string/macro names", nm WARN;
       +                done2(02);
       +        } else {
       +                memset((char *)(contabp) + (nm - MDELTA) * sizeof(Contab),
       +                                                0, MDELTA * sizeof(Contab));
       +                mrehash();
       +        }
       +}
       +
       +
       +Offset finds(int mn)
       +{
       +        int i;
       +        Tchar j = IMP;
       +        Offset savip;
       +
       +        oldmn = findmn(mn);
       +        newmn = 0;
       +        apptr = 0;
       +        if (app && oldmn >= 0 && contabp[oldmn].mx) {
       +                savip = ip;
       +                ip = contabp[oldmn].emx;
       +                oldmn = -1;
       +                apptr = ip;
       +                if (!diflg)
       +                        ip = incoff(ip);
       +                nextb = ip;
       +                ip = savip;
       +        } else {
       +                for (i = freeslot; i < nm; i++) {
       +                        if (contabp[i].rq == 0)
       +                                break;
       +                }
       +                if (i == nm) 
       +                        growcontab();
       +                freeslot = i + 1;
       +                if ((nextb = alloc()) == -1) {
       +                        app = 0;
       +                        if (macerr++ > 1)
       +                                done2(02);
       +                        if (nextb == 0)
       +                                ERROR "Not enough space for string/macro names" WARN;
       +                        edone(04);
       +                        return(offset = 0);
       +                }
       +                contabp[i].mx = nextb;
       +                if (!diflg) {
       +                        newmn = i;
       +                        if (oldmn == -1)
       +                                contabp[i].rq = -1;
       +                } else {
       +                        contabp[i].rq = mn;
       +                        maddhash(&contabp[i]);
       +                }
       +        }
       +        app = 0;
       +        return(offset = nextb);
       +}
       +
       +int skip(void)
       +{
       +        Tchar i;
       +
       +        while (cbits(i = getch()) == ' ' || ismot(i))
       +                ;
       +        ch = i;
       +        return(nlflg);
       +}
       +
       +
       +int copyb(void)
       +{
       +        int i, j, state;
       +        Tchar ii;
       +        int req, k;
       +        Offset savoff;
       +        Uchar *p;
       +
       +        if (skip() || !(j = getrq()))
       +                j = '.';
       +        req = j;
       +        p = unpair(j);
       +        /* was: k = j >> BYTE; j &= BYTEMASK; */
       +        j = p[0];
       +        k = p[1];
       +        copyf++;
       +        flushi();
       +        nlflg = 0;
       +        state = 1;
       +
       +/* state 0        eat up
       + * state 1        look for .
       + * state 2        look for first char of end macro
       + * state 3        look for second char of end macro
       + */
       +
       +        while (1) {
       +                i = cbits(ii = getch());
       +                if (state == 3) {
       +                        if (i == k)
       +                                break;
       +                        if (!k) {
       +                                ch = ii;
       +                                i = getach();
       +                                ch = ii;
       +                                if (!i)
       +                                        break;
       +                        }
       +                        state = 0;
       +                        goto c0;
       +                }
       +                if (i == '\n') {
       +                        state = 1;
       +                        nlflg = 0;
       +                        goto c0;
       +                }
       +                if (state == 1 && i == '.') {
       +                        state++;
       +                        savoff = offset;
       +                        goto c0;
       +                }
       +                if (state == 2 && i == j) {
       +                        state++;
       +                        goto c0;
       +                }
       +                state = 0;
       +c0:
       +                if (offset)
       +                        wbf(ii);
       +        }
       +        if (offset) {
       +                offset = savoff;
       +                wbf((Tchar)0);
       +        }
       +        copyf--;
       +        return(req);
       +}
       +
       +
       +void copys(void)
       +{
       +        Tchar i;
       +
       +        copyf++;
       +        if (skip())
       +                goto c0;
       +        if (cbits(i = getch()) != '"')
       +                wbf(i);
       +        while (cbits(i = getch()) != '\n')
       +                wbf(i);
       +c0:
       +        wbf((Tchar)0);
       +        copyf--;
       +}
       +
       +
       +Offset alloc(void)        /* return free Offset in nextb */
       +{
       +        int i, j;
       +
       +        for (i = bfree; i < nblist; i++)
       +                if (blist[i].nextoff == 0)
       +                        break;
       +        if (i == nblist) {
       +                blist = (Blockp *) realloc((char *) blist, 2 * nblist * sizeof(Blockp));
       +                if (blist == NULL) {
       +                        ERROR "can't grow blist for string/macro defns" WARN;
       +                        done2(2);
       +                }
       +                nblist *= 2;
       +                for (j = i; j < nblist; j++) {
       +                        blist[j].nextoff = 0;
       +                        blist[j].bp = 0;
       +                }
       +        }
       +        blist[i].nextoff = -1;        /* this block is the end */
       +        bfree = i + 1;
       +        if (blist[i].bp == 0)
       +                blist[i].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
       +        if (blist[i].bp == NULL) {
       +                ERROR "can't allocate memory for string/macro definitions" WARN;
       +                done2(2);
       +        }
       +        nextb = (Offset) i * BLK;
       +        return nextb;
       +}
       +
       +
       +void ffree(Offset i)        /* free list of blocks starting at blist(o) */
       +{                        /* (doesn't actually free the blocks, just the pointers) */
       +        int j;
       +
       +        for ( ; blist[j = bindex(i)].nextoff != -1; ) {
       +                if (bfree > j)
       +                        bfree = j;
       +                i = blist[j].nextoff;
       +                blist[j].nextoff = 0;
       +        }
       +        blist[j].nextoff = 0;
       +}
       +
       +
       +void wbf(Tchar i)        /* store i into offset, get ready for next one */
       +{
       +        int j, off;
       +
       +        if (!offset)
       +                return;
       +        j = bindex(offset);
       +        if (i == 0)
       +                contabp[savslot].emx = offset;
       +        off = boffset(offset);
       +        blist[j].bp[off++] = i;
       +        offset++;
       +        if (pastend(offset)) {        /* off the end of this block */
       +                if (blist[j].nextoff == -1) {
       +                        if ((nextb = alloc()) == -1) {
       +                                ERROR "Out of temp file space" WARN;
       +                                done2(01);
       +                        }
       +                        blist[j].nextoff = nextb;
       +                }
       +                offset = blist[j].nextoff;
       +        }
       +}
       +
       +
       +Tchar rbf(void)        /* return next char from blist[] block */
       +{
       +        Tchar i, j;
       +
       +        if (ip == RD_OFFSET) {                /* for rdtty */
       +                if (j = rdtty())
       +                        return(j);
       +                else
       +                        return(popi());
       +        }
       +        
       +        i = rbf0(ip);
       +        if (i == 0) {
       +                if (!app)
       +                        i = popi();
       +                return(i);
       +        }
       +        ip = incoff(ip);
       +        return(i);
       +}
       +
       +
       +Offset xxxincoff(Offset p)                /* get next blist[] block */
       +{
       +        p++;
       +        if (pastend(p)) {                /* off the end of this block */
       +                if ((p = blist[bindex(p-1)].nextoff) == -1) {        /* and nothing was allocated after it */
       +                        ERROR "Bad storage allocation" WARN;
       +                        done2(-5);
       +                }
       +        }
       +        return(p);
       +}
       +
       +
       +Tchar popi(void)
       +{
       +        Stack *p;
       +
       +        if (frame == stk)
       +                return(0);
       +        if (strflg)
       +                strflg--;
       +        p = nxf = frame;
       +        p->nargs = 0;
       +        frame = p->pframe;
       +        ip = p->pip;
       +        pendt = p->ppendt;
       +        lastpbp = p->lastpbp;
       +        return(p->pch);
       +}
       +
       +/*
       + *        test that the end of the allocation is above a certain location
       + *        in memory
       + */
       +#define SPACETEST(base, size) \
       +        if ((char*)base + size >= (char*)stk+STACKSIZE) \
       +                ERROR "Stacksize overflow in n3" WARN
       +
       +Offset pushi(Offset newip, int  mname)
       +{
       +        Stack *p;
       +
       +        SPACETEST(nxf, sizeof(Stack));
       +        p = nxf;
       +        p->pframe = frame;
       +        p->pip = ip;
       +        p->ppendt = pendt;
       +        p->pch = ch;
       +        p->lastpbp = lastpbp;
       +        p->mname = mname;
       +        lastpbp = pbp;
       +        pendt = ch = 0;
       +        frame = nxf;
       +        if (nxf->nargs == 0) 
       +                nxf += 1;
       +        else 
       +                nxf = (Stack *)argtop;
       +        return(ip = newip);
       +}
       +
       +
       +void *setbrk(int x)
       +{
       +        char *i;
       +
       +        if ((i = (char *) calloc(x, 1)) == 0) {
       +                ERROR "Core limit reached" WARN;
       +                edone(0100);
       +        }
       +        return(i);
       +}
       +
       +
       +int getsn(void)
       +{
       +        int i;
       +
       +        if ((i = getach()) == 0)
       +                return(0);
       +        if (i == '(')
       +                return(getrq());
       +        else 
       +                return(i);
       +}
       +
       +
       +Offset setstr(void)
       +{
       +        int i, j;
       +
       +        lgf++;
       +        if ((i = getsn()) == 0 || (j = findmn(i)) == -1 || !contabp[j].mx) {
       +                lgf--;
       +                return(0);
       +        } else {
       +                SPACETEST(nxf, sizeof(Stack));
       +                nxf->nargs = 0;
       +                strflg++;
       +                lgf--;
       +                return pushi(contabp[j].mx, i);
       +        }
       +}
       +
       +
       +
       +void collect(void)
       +{
       +        int j;
       +        Tchar i, *strp, *lim, **argpp, **argppend;
       +        int quote;
       +        Stack *savnxf;
       +
       +        copyf++;
       +        nxf->nargs = 0;
       +        savnxf = nxf;
       +        if (skip())
       +                goto rtn;
       +
       +        {
       +                char *memp;
       +                memp = (char *)savnxf;
       +                /*
       +                 *        1 s structure for the macro descriptor
       +                 *        APERMAC Tchar *'s for pointers into the strings
       +                 *        space for the Tchar's themselves
       +                 */
       +                memp += sizeof(Stack);
       +                /*
       +                 *        CPERMAC = the total # of characters for ALL arguments
       +                 */
       +#define        CPERMAC        200
       +#define        APERMAC        9
       +                memp += APERMAC * sizeof(Tchar *);
       +                memp += CPERMAC * sizeof(Tchar);
       +                nxf = (Stack *)memp;
       +        }
       +        lim = (Tchar *)nxf;
       +        argpp = (Tchar **)(savnxf + 1);
       +        argppend = &argpp[APERMAC];
       +        SPACETEST(argppend, sizeof(Tchar *));
       +        strp = (Tchar *)argppend;
       +        /*
       +         *        Zero out all the string pointers before filling them in.
       +         */
       +        for (j = 0; j < APERMAC; j++)
       +                argpp[j] = 0;
       +        /* ERROR "savnxf=0x%x,nxf=0x%x,argpp=0x%x,strp=argppend=0x%x, lim=0x%x",
       +         *         savnxf, nxf, argpp, strp, lim WARN;
       +         */
       +        strflg = 0;
       +        while (argpp != argppend && !skip()) {
       +                *argpp++ = strp;
       +                quote = 0;
       +                if (cbits(i = getch()) == '"')
       +                        quote++;
       +                else 
       +                        ch = i;
       +                while (1) {
       +                        i = getch();
       +/* fprintf(stderr, "collect %c %d\n", cbits(i), cbits(i)); */
       +                        if (nlflg || (!quote && argpp != argppend && cbits(i) == ' '))
       +                                break;        /* collects rest into $9 */
       +                        if (   quote
       +                            && cbits(i) == '"'
       +                            && cbits(i = getch()) != '"') {
       +                                ch = i;
       +                                break;
       +                        }
       +                        *strp++ = i;
       +                        if (strflg && strp >= lim) {
       +                                /* ERROR "strp=0x%x, lim = 0x%x", strp, lim WARN; */
       +                                ERROR "Macro argument too long" WARN;
       +                                copyf--;
       +                                edone(004);
       +                        }
       +                        SPACETEST(strp, 3 * sizeof(Tchar));
       +                }
       +                *strp++ = 0;
       +        }
       +        nxf = savnxf;
       +        nxf->nargs = argpp - (Tchar **)(savnxf + 1);
       +        argtop = strp;
       +rtn:
       +        copyf--;
       +}
       +
       +
       +void seta(void)
       +{
       +        int i;
       +
       +        i = cbits(getch()) - '0';
       +        if (i > 0 && i <= APERMAC && i <= frame->nargs)
       +                pushback(*(((Tchar **)(frame + 1)) + i - 1));
       +}
       +
       +
       +void caseda(void)
       +{
       +        app++;
       +        casedi();
       +}
       +
       +void casegd(void)
       +{
       +        int i, j;
       +
       +        skip();
       +        if ((i = getrq()) == 0)
       +                return;
       +        if ((j = findmn(i)) >= 0) {
       +                if (contabp[j].divsiz != NULL) {
       +                        numtabp[DN].val = contabp[j].divsiz->dix;
       +                        numtabp[DL].val = contabp[j].divsiz->diy;
       +                }
       +        }
       +}
       +
       +#define FINDDIV(o) if ((o =  findmn(dip->curd)) < 0) \
       +                        ERROR "lost diversion %s", unpair(dip->curd) WARN
       +
       +void casedi(void)
       +{
       +        int i, j, *k;
       +
       +        lgf++;
       +        if (skip() || (i = getrq()) == 0) {
       +                if (dip != d) {
       +                        FINDDIV(savslot);
       +                        wbf((Tchar)0);
       +                }
       +                if (dilev > 0) {
       +                        numtabp[DN].val = dip->dnl;
       +                        numtabp[DL].val = dip->maxl;
       +                        FINDDIV(j);
       +                        if ((contabp[j].divsiz = (Divsiz *) malloc(sizeof(Divsiz))) == NULL) {
       +                                ERROR "Cannot alloc diversion size" WARN;
       +                                done2(1);
       +                        } else {
       +                                contabp[j].divsiz->dix = numtabp[DN].val;
       +                                contabp[j].divsiz->diy = numtabp[DL].val;
       +                        }
       +                        dip = &d[--dilev];
       +                        offset = dip->op;
       +                }
       +                goto rtn;
       +        }
       +        if (++dilev == NDI) {
       +                --dilev;
       +                ERROR "Diversions nested too deep" WARN;
       +                edone(02);
       +        }
       +        if (dip != d) {
       +                FINDDIV(j);
       +                savslot = j;
       +                wbf((Tchar)0);
       +        }
       +        diflg++;
       +        dip = &d[dilev];
       +        dip->op = finds(i);
       +        dip->curd = i;
       +        clrmn(oldmn);
       +        k = (int *) & dip->dnl;
       +        for (j = 0; j < 10; j++)
       +                k[j] = 0;        /*not op and curd*/
       +rtn:
       +        app = 0;
       +        diflg = 0;
       +}
       +
       +
       +void casedt(void)
       +{
       +        lgf++;
       +        dip->dimac = dip->ditrap = dip->ditf = 0;
       +        skip();
       +        dip->ditrap = vnumb((int *)0);
       +        if (nonumb)
       +                return;
       +        skip();
       +        dip->dimac = getrq();
       +}
       +
       +#define LNSIZE 4000
       +void casetl(void)
       +{
       +        int j;
       +        int w[3];
       +        Tchar buf[LNSIZE];
       +        Tchar *tp;
       +        Tchar i, delim;
       +
       +         /*
       +          * bug fix
       +          *
       +          * if .tl is the first thing in the file, the p1
       +          * doesn't come out, also the pagenumber will be 0
       +          *
       +          * tends too confuse the device filter (and the user as well)
       +          */
       +         if (dip == d && numtabp[NL].val == -1)
       +                 newline(1);
       +        dip->nls = 0;
       +        skip();
       +        if (ismot(delim = getch())) {
       +                ch = delim;
       +                delim = '\'';
       +        } else 
       +                delim = cbits(delim);
       +        tp = buf;
       +        numtabp[HP].val = 0;
       +        w[0] = w[1] = w[2] = 0;
       +        j = 0;
       +        while (cbits(i = getch()) != '\n') {
       +                if (cbits(i) == cbits(delim)) {
       +                        if (j < 3)
       +                                w[j] = numtabp[HP].val;
       +                        numtabp[HP].val = 0;
       +                        if (w[j] != 0)
       +                                *tp++ = WORDSP;
       +                        j++;
       +                        *tp++ = 0;
       +                } else {
       +                        if (cbits(i) == pagech) {
       +                                setn1(numtabp[PN].val, numtabp[findr('%')].fmt,
       +                                      i&SFMASK);
       +                                continue;
       +                        }
       +                        numtabp[HP].val += width(i);
       +                        if (tp < &buf[LNSIZE-10]) {
       +                                if (cbits(i) == ' ' && *tp != WORDSP)
       +                                        *tp++ = WORDSP;
       +                                *tp++ = i;
       +                        } else {
       +                                ERROR "Overflow in casetl" WARN;
       +                        }
       +                }
       +        }
       +        if (j<3)
       +                w[j] = numtabp[HP].val;
       +        *tp++ = 0;
       +        *tp++ = 0;
       +        *tp = 0;
       +        tp = buf;
       +        if (NROFF)
       +                horiz(po);
       +        while (i = *tp++)
       +                pchar(i);
       +        if (w[1] || w[2])
       +                horiz(j = quant((lt - w[1]) / 2 - w[0], HOR));
       +        while (i = *tp++)
       +                pchar(i);
       +        if (w[2]) {
       +                horiz(lt - w[0] - w[1] - w[2] - j);
       +                while (i = *tp++)
       +                        pchar(i);
       +        }
       +        newline(0);
       +        if (dip != d) {
       +                if (dip->dnl > dip->hnl)
       +                        dip->hnl = dip->dnl;
       +        } else {
       +                if (numtabp[NL].val > dip->hnl)
       +                        dip->hnl = numtabp[NL].val;
       +        }
       +}
       +
       +
       +void casepc(void)
       +{
       +        pagech = chget(IMP);
       +}
       +
       +
       +void casepm(void)
       +{
       +        int i, k;
       +        int xx, cnt, tcnt, kk, tot;
       +        Offset j;
       +
       +        kk = cnt = tcnt = 0;
       +        tot = !skip();
       +        stackdump();
       +        for (i = 0; i < nm; i++) {
       +                if ((xx = contabp[i].rq) == 0 || contabp[i].mx == 0)
       +                        continue;
       +                tcnt++;
       +                j = contabp[i].mx;
       +                for (k = 1; (j = blist[bindex(j)].nextoff) != -1; )
       +                        k++; 
       +                cnt++;
       +                kk += k;
       +                if (!tot)
       +                        fprintf(stderr, "%-2.2s %d\n", unpair(xx), k);
       +        }
       +        fprintf(stderr, "pm: total %d, macros %d, space %d\n", tcnt, cnt, kk);
       +}
       +
       +void stackdump(void)        /* dumps stack of macros in process */
       +{
       +        Stack *p;
       +
       +        if (frame != stk) {
       +                fprintf(stderr, "stack: ");
       +                for (p = frame; p != stk; p = p->pframe)
       +                        fprintf(stderr, "%s ", unpair(p->mname));
       +                fprintf(stderr, "\n");
       +        }
       +}
 (DIR) diff --git a/src/cmd/troff/n4.c b/src/cmd/troff/n4.c
       t@@ -0,0 +1,828 @@
       +/*
       + * troff4.c
       + *
       + * number registers, conversion, arithmetic
       + */
       +
       +#include "tdef.h"
       +#include "fns.h"
       +#include "ext.h"
       +
       +
       +int        regcnt = NNAMES;
       +int        falsef        = 0;        /* on if inside false branch of if */
       +
       +#define        NHASHSIZE        128        /* must be 2**n */
       +#define        NHASH(i)        ((i>>6)^i) & (NHASHSIZE-1)
       +Numtab        *nhash[NHASHSIZE];
       +
       +Numtab *numtabp = NULL;
       +#define NDELTA 400
       +int ncnt = 0;
       +
       +void setn(void)
       +{
       +        int i, j, f;
       +        Tchar ii;
       +        Uchar *p;
       +        char buf[NTM];                /* for \n(.S */
       +
       +        f = nform = 0;
       +        if ((i = cbits(ii = getach())) == '+')
       +                f = 1;
       +        else if (i == '-')
       +                f = -1;
       +        else if (ii)        /* don't put it back if it's already back (thanks to jaap) */
       +                ch = ii;
       +        if (falsef)
       +                f = 0;
       +        if ((i = getsn()) == 0)
       +                return;
       +        p = unpair(i);
       +        if (p[0] == '.')
       +                switch (p[1]) {
       +                case 's':
       +                        i = pts;
       +                        break;
       +                case 'v':
       +                        i = lss;
       +                        break;
       +                case 'f':
       +                        i = font;
       +                        break;
       +                case 'p':
       +                        i = pl;
       +                        break;
       +                case 't':
       +                        i = findt1();
       +                        break;
       +                case 'o':
       +                        i = po;
       +                        break;
       +                case 'l':
       +                        i = ll;
       +                        break;
       +                case 'i':
       +                        i = in;
       +                        break;
       +                case '$':
       +                        i = frame->nargs;
       +                        break;
       +                case 'A':
       +                        i = ascii;
       +                        break;
       +                case 'c':
       +                        i = numtabp[CD].val;
       +                        break;
       +                case 'n':
       +                        i = lastl;
       +                        break;
       +                case 'a':
       +                        i = ralss;
       +                        break;
       +                case 'h':
       +                        i = dip->hnl;
       +                        break;
       +                case 'd':
       +                        if (dip != d)
       +                                i = dip->dnl;
       +                        else
       +                                i = numtabp[NL].val;
       +                        break;
       +                case 'u':
       +                        i = fi;
       +                        break;
       +                case 'j':
       +                        i = ad + 2 * admod;
       +                        break;
       +                case 'w':
       +                        i = widthp;
       +                        break;
       +                case 'x':
       +                        i = nel;
       +                        break;
       +                case 'y':
       +                        i = un;
       +                        break;
       +                case 'T':
       +                        i = dotT;
       +                        break;         /* -Tterm used in nroff */
       +                case 'V':
       +                        i = VERT;
       +                        break;
       +                case 'H':
       +                        i = HOR;
       +                        break;
       +                case 'k':
       +                        i = ne;
       +                        break;
       +                case 'P':
       +                        i = print;
       +                        break;
       +                case 'L':
       +                        i = ls;
       +                        break;
       +                case 'R':        /* maximal # of regs that can be addressed */
       +                        i = 255*256 - regcnt; 
       +                        break;
       +                case 'z':
       +                        p = unpair(dip->curd);
       +                        *pbp++ = p[1];        /* watch order */
       +                        *pbp++ = p[0];
       +                        return;
       +                case 'b':
       +                        i = bdtab[font];
       +                        break;
       +                case 'F':
       +                        cpushback(cfname[ifi]);
       +                        return;
       +                 case 'S':
       +                         buf[0] = j = 0;        
       +                         for( i = 0; tabtab[i] != 0 && i < NTAB; i++) {
       +                                 if (i > 0)
       +                                         buf[j++] = ' ';
       +                                 sprintf(&buf[j], "%d", tabtab[i] & TABMASK);
       +                                 j = strlen(buf);
       +                                 if ( tabtab[i] & RTAB)
       +                                         sprintf(&buf[j], "uR");
       +                                 else if (tabtab[i] & CTAB)
       +                                         sprintf(&buf[j], "uC");
       +                                 else
       +                                         sprintf(&buf[j], "uL");
       +                                 j += 2;
       +                         }
       +                         cpushback(buf);
       +                         return;
       +                default:
       +                        goto s0;
       +                }
       +        else {
       +s0:
       +                if ((j = findr(i)) == -1)
       +                        i = 0;
       +                else {
       +                        i = numtabp[j].val = numtabp[j].val + numtabp[j].inc * f;
       +                        nform = numtabp[j].fmt;
       +                }
       +        }
       +        setn1(i, nform, (Tchar) 0);
       +}
       +
       +Tchar        numbuf[25];
       +Tchar        *numbufp;
       +
       +int wrc(Tchar i)
       +{
       +        if (numbufp >= &numbuf[24])
       +                return(0);
       +        *numbufp++ = i;
       +        return(1);
       +}
       +
       +
       +
       +/* insert into input number i, in format form, with size-font bits bits */
       +void setn1(int i, int form, Tchar bits)
       +{
       +        numbufp = numbuf;
       +        nrbits = bits;
       +        nform = form;
       +        fnumb(i, wrc);
       +        *numbufp = 0;
       +        pushback(numbuf);
       +}
       +
       +void prnumtab(Numtab *p)
       +{
       +        int i;
       +        for (i = 0; i < ncnt; i++)
       +                if (p)
       +                        if (p[i].r != 0)
       +                                fprintf(stderr, "slot %d, %s, val %d\n", i, unpair(p[i].r), p[i].val);
       +                        else
       +                                fprintf(stderr, "slot %d empty\n", i);
       +                else
       +                        fprintf(stderr, "slot %d empty\n", i);
       +}
       +
       +void nnspace(void)
       +{
       +        ncnt = sizeof(numtab)/sizeof(Numtab) + NDELTA;
       +        numtabp = (Numtab *) grow((char *)numtabp, ncnt, sizeof(Numtab));
       +        if (numtabp == NULL) {
       +                ERROR "not enough memory for registers (%d)", ncnt WARN;
       +                exit(1);
       +        }
       +        numtabp = (Numtab *) memcpy((char *)numtabp, (char *)numtab,
       +                                                        sizeof(numtab));
       +        if (numtabp == NULL) {
       +                ERROR "Cannot initialize registers" WARN;
       +                exit(1);
       +        }
       +}
       +
       +void grownumtab(void)
       +{
       +        ncnt += NDELTA;
       +        numtabp = (Numtab *) grow((char *) numtabp, ncnt, sizeof(Numtab));
       +        if (numtabp == NULL) {
       +                ERROR "Too many number registers (%d)", ncnt WARN;
       +                done2(04);
       +        } else {
       +                memset((char *)(numtabp) + (ncnt - NDELTA) * sizeof(Numtab),
       +                                                0, NDELTA * sizeof(Numtab));
       +                nrehash();
       +        }
       +}
       +
       +void nrehash(void)
       +{
       +        Numtab *p;
       +        int i;
       +
       +        for (i=0; i<NHASHSIZE; i++)
       +                nhash[i] = 0;
       +        for (p=numtabp; p < &numtabp[ncnt]; p++)
       +                p->link = 0;
       +        for (p=numtabp; p < &numtabp[ncnt]; p++) {
       +                if (p->r == 0)
       +                        continue;
       +                i = NHASH(p->r);
       +                p->link = nhash[i];
       +                nhash[i] = p;
       +        }
       +}
       +
       +void nunhash(Numtab *rp)
       +{
       +        Numtab *p;
       +        Numtab **lp;
       +
       +        if (rp->r == 0)
       +                return;
       +        lp = &nhash[NHASH(rp->r)];
       +        p = *lp;
       +        while (p) {
       +                if (p == rp) {
       +                        *lp = p->link;
       +                        p->link = 0;
       +                        return;
       +                }
       +                lp = &p->link;
       +                p = p->link;
       +        }
       +}
       +
       +int findr(int i)
       +{
       +        Numtab *p;
       +        int h = NHASH(i);
       +
       +        if (i == 0)
       +                return(-1);
       +a0:
       +        for (p = nhash[h]; p; p = p->link)
       +                if (i == p->r)
       +                        return(p - numtabp);
       +        for (p = numtabp; p < &numtabp[ncnt]; p++) {
       +                if (p->r == 0) {
       +                        p->r = i;
       +                        p->link = nhash[h];
       +                        nhash[h] = p;
       +                        regcnt++;
       +                        return(p - numtabp);
       +                }
       +        }
       +        grownumtab();
       +        goto a0;
       +}
       +
       +int usedr(int i)        /* returns -1 if nr i has never been used */
       +{
       +        Numtab *p;
       +
       +        if (i == 0)
       +                return(-1);
       +        for (p = nhash[NHASH(i)]; p; p = p->link)
       +                if (i == p->r)
       +                        return(p - numtabp);
       +        return -1;
       +}
       +
       +
       +int fnumb(int i, int (*f)(Tchar))
       +{
       +        int j;
       +
       +        j = 0;
       +        if (i < 0) {
       +                j = (*f)('-' | nrbits);
       +                i = -i;
       +        }
       +        switch (nform) {
       +        default:
       +        case '1':
       +        case 0:
       +                return decml(i, f) + j;
       +        case 'i':
       +        case 'I':
       +                return roman(i, f) + j;
       +        case 'a':
       +        case 'A':
       +                return abc(i, f) + j;
       +        }
       +}
       +
       +
       +int decml(int i, int (*f)(Tchar))
       +{
       +        int j, k;
       +
       +        k = 0;
       +        nform--;
       +        if ((j = i / 10) || (nform > 0))
       +                k = decml(j, f);
       +        return(k + (*f)((i % 10 + '0') | nrbits));
       +}
       +
       +
       +int roman(int i, int (*f)(Tchar))
       +{
       +
       +        if (!i)
       +                return((*f)('0' | nrbits));
       +        if (nform == 'i')
       +                return(roman0(i, f, "ixcmz", "vldw"));
       +        else
       +                return(roman0(i, f, "IXCMZ", "VLDW"));
       +}
       +
       +
       +int roman0(int i, int (*f)(Tchar), char *onesp, char *fivesp)
       +{
       +        int q, rem, k;
       +
       +        if (!i)
       +                return(0);
       +        k = roman0(i / 10, f, onesp + 1, fivesp + 1);
       +        q = (i = i % 10) / 5;
       +        rem = i % 5;
       +        if (rem == 4) {
       +                k += (*f)(*onesp | nrbits);
       +                if (q)
       +                        i = *(onesp + 1);
       +                else
       +                        i = *fivesp;
       +                return(k += (*f)(i | nrbits));
       +        }
       +        if (q)
       +                k += (*f)(*fivesp | nrbits);
       +        while (--rem >= 0)
       +                k += (*f)(*onesp | nrbits);
       +        return(k);
       +}
       +
       +
       +int abc(int i, int (*f)(Tchar))
       +{
       +        if (!i)
       +                return((*f)('0' | nrbits));
       +        else
       +                return(abc0(i - 1, f));
       +}
       +
       +
       +int abc0(int i, int (*f)(Tchar))
       +{
       +        int j, k;
       +
       +        k = 0;
       +        if (j = i / 26)
       +                k = abc0(j - 1, f);
       +        return(k + (*f)((i % 26 + nform) | nrbits));
       +}
       +
       +long atoi0(void)
       +{
       +        int c, k, cnt;
       +        Tchar ii;
       +        long i, acc;
       +
       +        acc = 0;
       +        nonumb = 0;
       +        cnt = -1;
       +a0:
       +        cnt++;
       +        ii = getch();
       +        c = cbits(ii);
       +        switch (c) {
       +        default:
       +                ch = ii;
       +                if (cnt)
       +                        break;
       +        case '+':
       +                i = ckph();
       +                if (nonumb)
       +                        break;
       +                acc += i;
       +                goto a0;
       +        case '-':
       +                i = ckph();
       +                if (nonumb)
       +                        break;
       +                acc -= i;
       +                goto a0;
       +        case '*':
       +                i = ckph();
       +                if (nonumb)
       +                        break;
       +                acc *= i;
       +                goto a0;
       +        case '/':
       +                i = ckph();
       +                if (nonumb)
       +                        break;
       +                if (i == 0) {
       +                        flusho();
       +                        ERROR "divide by zero." WARN;
       +                        acc = 0;
       +                } else
       +                        acc /= i;
       +                goto a0;
       +        case '%':
       +                i = ckph();
       +                if (nonumb)
       +                        break;
       +                acc %= i;
       +                goto a0;
       +        case '&':        /*and*/
       +                i = ckph();
       +                if (nonumb)
       +                        break;
       +                if ((acc > 0) && (i > 0))
       +                        acc = 1;
       +                else
       +                        acc = 0;
       +                goto a0;
       +        case ':':        /*or*/
       +                i = ckph();
       +                if (nonumb)
       +                        break;
       +                if ((acc > 0) || (i > 0))
       +                        acc = 1;
       +                else
       +                        acc = 0;
       +                goto a0;
       +        case '=':
       +                if (cbits(ii = getch()) != '=')
       +                        ch = ii;
       +                i = ckph();
       +                if (nonumb) {
       +                        acc = 0;
       +                        break;
       +                }
       +                if (i == acc)
       +                        acc = 1;
       +                else
       +                        acc = 0;
       +                goto a0;
       +        case '>':
       +                k = 0;
       +                if (cbits(ii = getch()) == '=')
       +                        k++;
       +                else
       +                        ch = ii;
       +                i = ckph();
       +                if (nonumb) {
       +                        acc = 0;
       +                        break;
       +                }
       +                if (acc > (i - k))
       +                        acc = 1;
       +                else
       +                        acc = 0;
       +                goto a0;
       +        case '<':
       +                k = 0;
       +                if (cbits(ii = getch()) == '=')
       +                        k++;
       +                else
       +                        ch = ii;
       +                i = ckph();
       +                if (nonumb) {
       +                        acc = 0;
       +                        break;
       +                }
       +                if (acc < (i + k))
       +                        acc = 1;
       +                else
       +                        acc = 0;
       +                goto a0;
       +        case ')':
       +                break;
       +        case '(':
       +                acc = atoi0();
       +                goto a0;
       +        }
       +        return(acc);
       +}
       +
       +
       +long ckph(void)
       +{
       +        Tchar i;
       +        long j;
       +
       +        if (cbits(i = getch()) == '(')
       +                j = atoi0();
       +        else {
       +                j = atoi1(i);
       +        }
       +        return(j);
       +}
       +
       +
       +/*
       + * print error about illegal numeric argument;
       + */
       +void prnumerr(void)
       +{
       +        char err_buf[40];
       +        static char warn[] = "Numeric argument expected";
       +        int savcd = numtabp[CD].val;
       +
       +        if (numerr.type == RQERR)
       +                sprintf(err_buf, "%c%s: %s", nb ? cbits(c2) : cbits(cc),
       +                                                unpair(numerr.req), warn);
       +        else
       +                sprintf(err_buf, "\\%c'%s': %s", numerr.esc, &numerr.escarg,
       +                                                                        warn);
       +        if (frame != stk)        /* uncertainty correction */
       +                numtabp[CD].val--;
       +        ERROR err_buf WARN;
       +        numtabp[CD].val = savcd;
       +}
       +
       +
       +long atoi1(Tchar ii)
       +{
       +        int i, j, digits;
       +        double acc;        /* this is the only double in troff! */
       +        int neg, abs, field, decpnt;
       +        extern int ifnum;
       +
       +
       +        neg = abs = field = decpnt = digits = 0;
       +        acc = 0;
       +        for (;;) {
       +                i = cbits(ii);
       +                switch (i) {
       +                default:
       +                        break;
       +                case '+':
       +                        ii = getch();
       +                        continue;
       +                case '-':
       +                        neg = 1;
       +                        ii = getch();
       +                        continue;
       +                case '|':
       +                        abs = 1 + neg;
       +                        neg = 0;
       +                        ii = getch();
       +                        continue;
       +                }
       +                break;
       +        }
       +a1:
       +        while (i >= '0' && i <= '9') {
       +                field++;
       +                digits++;
       +                acc = 10 * acc + i - '0';
       +                ii = getch();
       +                i = cbits(ii);
       +        }
       +        if (i == '.' && !decpnt++) {
       +                field++;
       +                digits = 0;
       +                ii = getch();
       +                i = cbits(ii);
       +                goto a1;
       +        }
       +        if (!field) {
       +                ch = ii;
       +                goto a2;
       +        }
       +        switch (i) {
       +        case 'u':
       +                i = j = 1;        /* should this be related to HOR?? */
       +                break;
       +        case 'v':        /*VSs - vert spacing*/
       +                j = lss;
       +                i = 1;
       +                break;
       +        case 'm':        /*Ems*/
       +                j = EM;
       +                i = 1;
       +                break;
       +        case 'n':        /*Ens*/
       +                j = EM;
       +                if (TROFF)
       +                        i = 2;
       +                else
       +                        i = 1;        /*Same as Ems in NROFF*/
       +                break;
       +        case 'p':        /*Points*/
       +                j = INCH;
       +                i = 72;
       +                break;
       +        case 'i':        /*Inches*/
       +                j = INCH;
       +                i = 1;
       +                break;
       +        case 'c':        /*Centimeters*/
       +                /* if INCH is too big, this will overflow */
       +                j = INCH * 50;
       +                i = 127;
       +                break;
       +        case 'P':        /*Picas*/
       +                j = INCH;
       +                i = 6;
       +                break;
       +        default:
       +                j = dfact;
       +                ch = ii;
       +                i = dfactd;
       +        }
       +        if (neg)
       +                acc = -acc;
       +        if (!noscale) {
       +                acc = (acc * j) / i;
       +        }
       +        if (field != digits && digits > 0)
       +                while (digits--)
       +                        acc /= 10;
       +        if (abs) {
       +                if (dip != d)
       +                        j = dip->dnl;
       +                else
       +                        j = numtabp[NL].val;
       +                if (!vflag) {
       +                        j = numtabp[HP].val;
       +                }
       +                if (abs == 2)
       +                        j = -j;
       +                acc -= j;
       +        }
       +a2:
       +        nonumb = (!field || field == decpnt);
       +        if (nonumb && (trace & TRNARGS) && !ismot(ii) && !nlflg && !ifnum) {
       +                if (cbits(ii) != RIGHT ) /* Too painful to do right */
       +                        prnumerr();
       +        }
       +        return(acc);
       +}
       +
       +
       +void caserr(void)
       +{
       +        int i, j;
       +        Numtab *p;
       +
       +        lgf++;
       +        while (!skip() && (i = getrq()) ) {
       +                j = usedr(i);
       +                if (j < 0)
       +                        continue;
       +                p = &numtabp[j];
       +                nunhash(p);
       +                p->r = p->val = p->inc = p->fmt = 0;
       +                regcnt--;
       +        }
       +}
       +
       +/*
       + * .nr request; if tracing, don't check optional
       + * 2nd argument because tbl generates .in 1.5n
       + */
       +void casenr(void)
       +{
       +        int i, j;
       +        int savtr = trace;
       +
       +        lgf++;
       +        skip();
       +        if ((i = findr(getrq())) == -1)
       +                goto rtn;
       +        skip();
       +        j = inumb(&numtabp[i].val);
       +        if (nonumb)
       +                goto rtn;
       +        numtabp[i].val = j;
       +        skip();
       +        trace = 0;
       +        j = atoi0();                /* BUG??? */
       +        trace = savtr;
       +        if (nonumb)
       +                goto rtn;
       +        numtabp[i].inc = j;
       +rtn:
       +        return;
       +}
       +
       +void caseaf(void)
       +{
       +        int i, k;
       +        Tchar j;
       +
       +        lgf++;
       +        if (skip() || !(i = getrq()) || skip())
       +                return;
       +        k = 0;
       +        j = getch();
       +        if (!isalpha(cbits(j))) {
       +                ch = j;
       +                while ((j = cbits(getch())) >= '0' &&  j <= '9')
       +                        k++;
       +        }
       +        if (!k)
       +                k = j;
       +        numtabp[findr(i)].fmt = k;        /* was k & BYTEMASK */
       +}
       +
       +void setaf(void)        /* return format of number register */
       +{
       +        int i, j;
       +
       +        i = usedr(getsn());
       +        if (i == -1)
       +                return;
       +        if (numtabp[i].fmt > 20)        /* it was probably a, A, i or I */
       +                *pbp++ = numtabp[i].fmt;
       +        else
       +                for (j = (numtabp[i].fmt ? numtabp[i].fmt : 1); j; j--)
       +                        *pbp++ = '0';
       +}
       +
       +
       +int vnumb(int *i)
       +{
       +        vflag++;
       +        dfact = lss;
       +        res = VERT;
       +        return(inumb(i));
       +}
       +
       +
       +int hnumb(int *i)
       +{
       +        dfact = EM;
       +        res = HOR;
       +        return(inumb(i));
       +}
       +
       +
       +int inumb(int *n)
       +{
       +        int i, j, f;
       +        Tchar ii;
       +
       +        f = 0;
       +        if (n) {
       +                if ((j = cbits(ii = getch())) == '+')
       +                        f = 1;
       +                else if (j == '-')
       +                        f = -1;
       +                else
       +                        ch = ii;
       +        }
       +        i = atoi0();
       +        if (n && f)
       +                i = *n + f * i;
       +        i = quant(i, res);
       +        vflag = 0;
       +        res = dfactd = dfact = 1;
       +        if (nonumb)
       +                i = 0;
       +        return(i);
       +}
       +
       +
       +int quant(int n, int m)
       +{
       +        int i, neg;
       +
       +        neg = 0;
       +        if (n < 0) {
       +                neg++;
       +                n = -n;
       +        }
       +        /* better as i = ((n + m/2)/m)*m */
       +        i = n / m;
       +        if (n - m * i > m / 2)
       +                i += 1;
       +        i *= m;
       +        if (neg)
       +                i = -i;
       +        return(i);
       +}
 (DIR) diff --git a/src/cmd/troff/n5.c b/src/cmd/troff/n5.c
       t@@ -0,0 +1,1149 @@
       +/*
       + * troff5.c
       + * 
       + * misc processing requests
       + */
       +
       +#include "tdef.h"
       +#include "fns.h"
       +#include "ext.h"
       +
       +int        iflist[NIF];
       +int        ifx;
       +int        ifnum = 0;        /* trying numeric expression for .if or .ie condition */
       +
       +void casead(void)
       +{
       +        int i;
       +
       +        ad = 1;
       +        /* leave admod alone */
       +        if (skip())
       +                return;
       +        switch (i = cbits(getch())) {
       +        case 'r':        /* right adj, left ragged */
       +                admod = 2;
       +                break;
       +        case 'l':        /* left adj, right ragged */
       +                admod = ad = 0;        /* same as casena */
       +                break;
       +        case 'c':        /*centered adj*/
       +                admod = 1;
       +                break;
       +        case 'b': 
       +        case 'n':
       +                admod = 0;
       +                break;
       +        case '0': 
       +        case '2': 
       +        case '4':
       +                ad = 0;
       +        case '1': 
       +        case '3': 
       +        case '5':
       +                admod = (i - '0') / 2;
       +        }
       +}
       +
       +
       +void casena(void)
       +{
       +        ad = 0;
       +}
       +
       +
       +void casefi(void)
       +{
       +        tbreak();
       +        fi = 1;
       +        pendnf = 0;
       +}
       +
       +
       +void casenf(void)
       +{
       +        tbreak();
       +        fi = 0;
       +}
       +
       +
       +void casers(void)
       +{
       +        dip->nls = 0;
       +}
       +
       +
       +void casens(void)
       +{
       +        dip->nls++;
       +}
       +
       +
       +chget(int c)
       +{
       +        Tchar i;
       +
       +        if (skip() || ismot(i = getch()) || cbits(i) == ' ' || cbits(i) == '\n') {
       +                ch = i;
       +                return(c);
       +        } else 
       +                return cbits(i);        /* was (i & BYTEMASK) */
       +}
       +
       +
       +void casecc(void)
       +{
       +        cc = chget('.');
       +}
       +
       +
       +void casec2(void)
       +{
       +        c2 = chget('\'');
       +}
       +
       +
       +void casehc(void)
       +{
       +        ohc = chget(OHC);
       +}
       +
       +
       +void casetc(void)
       +{
       +        tabc = chget(0);
       +}
       +
       +
       +void caselc(void)
       +{
       +        dotc = chget(0);
       +}
       +
       +
       +void casehy(void)
       +{
       +        int i;
       +
       +        hyf = 1;
       +        if (skip())
       +                return;
       +        noscale++;
       +        i = atoi0();
       +        noscale = 0;
       +        if (nonumb)
       +                return;
       +        hyf = max(i, 0);
       +}
       +
       +
       +void casenh(void)
       +{
       +        hyf = 0;
       +}
       +
       +
       +max(int aa, int bb)
       +{
       +        if (aa > bb)
       +                return(aa);
       +        else 
       +                return(bb);
       +}
       +
       +
       +void casece(void)
       +{
       +        int i;
       +
       +        noscale++;
       +        skip();
       +        i = max(atoi0(), 0);
       +        if (nonumb)
       +                i = 1;
       +        tbreak();
       +        ce = i;
       +        noscale = 0;
       +}
       +
       +
       +void casein(void)
       +{
       +        int i;
       +
       +        if (skip())
       +                i = in1;
       +        else {
       +                i = max(hnumb(&in), 0);
       +                if (nonumb)
       +                        i = in1;
       +        }
       +        tbreak();
       +        in1 = in;
       +        in = i;
       +        if (!nc) {
       +                un = in;
       +                setnel();
       +        }
       +}
       +
       +
       +void casell(void)
       +{
       +        int i;
       +
       +        if (skip())
       +                i = ll1;
       +        else {
       +                i = max(hnumb(&ll), INCH / 10);
       +                if (nonumb)
       +                        i = ll1;
       +        }
       +        ll1 = ll;
       +        ll = i;
       +        setnel();
       +}
       +
       +
       +void caselt(void)
       +{
       +        int i;
       +
       +        if (skip())
       +                i = lt1;
       +        else {
       +                i = max(hnumb(&lt), 0);
       +                if (nonumb)
       +                        i = lt1;
       +        }
       +        lt1 = lt;
       +        lt = i;
       +}
       +
       +
       +void caseti(void)
       +{
       +        int i;
       +
       +        if (skip())
       +                return;
       +        i = max(hnumb(&in), 0);
       +        tbreak();
       +        un1 = i;
       +        setnel();
       +}
       +
       +
       +void casels(void)
       +{
       +        int i;
       +
       +        noscale++;
       +        if (skip())
       +                i = ls1;
       +        else {
       +                i = max(inumb(&ls), 1);
       +                if (nonumb)
       +                        i = ls1;
       +        }
       +        ls1 = ls;
       +        ls = i;
       +        noscale = 0;
       +}
       +
       +
       +void casepo(void)
       +{
       +        int i;
       +
       +        if (skip())
       +                i = po1;
       +        else {
       +                i = max(hnumb(&po), 0);
       +                if (nonumb)
       +                        i = po1;
       +        }
       +        po1 = po;
       +        po = i;
       +        if (TROFF & !ascii)
       +                esc += po - po1;
       +}
       +
       +
       +void casepl(void)
       +{
       +        int i;
       +
       +        skip();
       +        if ((i = vnumb(&pl)) == 0)
       +                pl = 11 * INCH; /*11in*/
       +        else 
       +                pl = i;
       +        if (numtabp[NL].val > pl)
       +                numtabp[NL].val = pl;
       +}
       +
       +
       +void casewh(void)
       +{
       +        int i, j, k;
       +
       +        lgf++;
       +        skip();
       +        i = vnumb((int *)0);
       +        if (nonumb)
       +                return;
       +        skip();
       +        j = getrq();
       +        if ((k = findn(i)) != NTRAP) {
       +                mlist[k] = j;
       +                return;
       +        }
       +        for (k = 0; k < NTRAP; k++)
       +                if (mlist[k] == 0)
       +                        break;
       +        if (k == NTRAP) {
       +                flusho();
       +                ERROR "cannot plant trap." WARN;
       +                return;
       +        }
       +        mlist[k] = j;
       +        nlist[k] = i;
       +}
       +
       +
       +void casech(void)
       +{
       +        int i, j, k;
       +
       +        lgf++;
       +        skip();
       +        if (!(j = getrq()))
       +                return;
       +        else 
       +                for (k = 0; k < NTRAP; k++)
       +                        if (mlist[k] == j)
       +                                break;
       +        if (k == NTRAP)
       +                return;
       +        skip();
       +        i = vnumb((int *)0);
       +        if (nonumb)
       +                mlist[k] = 0;
       +        nlist[k] = i;
       +}
       +
       +
       +findn(int i)
       +{
       +        int k;
       +
       +        for (k = 0; k < NTRAP; k++)
       +                if ((nlist[k] == i) && (mlist[k] != 0))
       +                        break;
       +        return(k);
       +}
       +
       +
       +void casepn(void)
       +{
       +        int i;
       +
       +        skip();
       +        noscale++;
       +        i = max(inumb(&numtabp[PN].val), 0);
       +        noscale = 0;
       +        if (!nonumb) {
       +                npn = i;
       +                npnflg++;
       +        }
       +}
       +
       +
       +void casebp(void)
       +{
       +        int i;
       +        Stack *savframe;
       +
       +        if (dip != d)
       +                return;
       +        savframe = frame;
       +        skip();
       +        if ((i = inumb(&numtabp[PN].val)) < 0)
       +                i = 0;
       +        tbreak();
       +        if (!nonumb) {
       +                npn = i;
       +                npnflg++;
       +        } else if (dip->nls)
       +                return;
       +        eject(savframe);
       +}
       +
       +void casetm(void)
       +{
       +        casetm1(0, stderr);
       +}
       +
       +
       +void casefm(void)
       +{
       +        static struct fcache {
       +                char *name;
       +                FILE *fp;
       +        } fcache[15];
       +        int i;
       +
       +        if ( skip() || !getname()) {
       +                ERROR "fm: missing filename" WARN;
       +                return;
       +        }
       +                
       +        for (i = 0; i < 15 && fcache[i].fp != NULL; i++) {
       +                if (strcmp(nextf, fcache[i].name) == 0)
       +                        break;
       +        }
       +        if (i >= 15) {
       +                ERROR "fm: too many streams" WARN;
       +                return;
       +        }
       +        if (fcache[i].fp == NULL) {
       +                if( (fcache[i].fp = fopen(unsharp(nextf), "w")) == NULL) {
       +                        ERROR "fm: cannot open %s", nextf WARN;
       +                        return;
       +                }
       +                fcache[i].name = strdupl(nextf);
       +        }
       +        casetm1(0, fcache[i].fp);
       +}
       +
       +void casetm1(int ab, FILE *out) 
       +{
       +        int i, j, c;
       +        char *p;
       +        char tmbuf[NTM];
       +
       +        lgf++;
       +        copyf++;
       +        if (ab) {
       +                if (skip())
       +                        ERROR "User Abort" WARN;
       +                else {
       +                        extern int error;
       +                        int savtrac = trace;
       +                        i = trace = 0;
       +                        noscale++;
       +                        i = inumb(&trace);
       +                        noscale--;
       +                        if (i) {
       +                                error = i;
       +                                if (nlflg || skip())
       +                                        ERROR "User Abort, exit code %d", i WARN;
       +                        }
       +                        trace = savtrac;
       +                }
       +        } else
       +                skip();        
       +        for (i = 0; i < NTM - 2; ) {
       +                if ((c = cbits(getch())) == '\n' || c == RIGHT)
       +                        break;
       +                else if (c == MINUS) {        /* special pleading for strange encodings */
       +                        tmbuf[i++] = '\\';
       +                        tmbuf[i++] = '-';
       +                } else if (c == PRESC) {
       +                        tmbuf[i++] = '\\';
       +                        tmbuf[i++] = 'e';
       +                } else if (c == FILLER) {
       +                        tmbuf[i++] = '\\';
       +                        tmbuf[i++] = '&';
       +                } else if (c == UNPAD) {
       +                        tmbuf[i++] = '\\';
       +                        tmbuf[i++] = ' ';
       +                } else if (c == OHC) {
       +                        tmbuf[i++] = '\\';
       +                        tmbuf[i++] = '%';
       +                } else if (c >= ALPHABET) {
       +                        p = chname(c);
       +                        switch (*p) {
       +                        case MBchar:
       +                                sprintf(&tmbuf[i], p+1);
       +                                break;
       +                        case Number:
       +                                sprintf(&tmbuf[i], "\\N'%s'", p+1);
       +                                break;
       +                        case Troffchar:
       +                                if ((j = strlen(p+1)) == 2)
       +                                        sprintf(&tmbuf[i], "\\(%s", p+1);
       +                                else
       +                                        sprintf(&tmbuf[i], "\\C'%s'", p+1);
       +                                break;
       +                        default:
       +                                sprintf(&tmbuf[i]," %s? ", p);
       +                                break;
       +                        }
       +                        j = strlen(&tmbuf[i]);
       +                        i += j;
       +                } else
       +                        tmbuf[i++] = c;
       +        }
       +        tmbuf[i] = 0;
       +        if (ab)        /* truncate output */
       +                obufp = obuf;        /* should be a function in n2.c */
       +        flusho();
       +        if (i)
       +                fprintf(out, "%s\n", tmbuf);
       +        fflush(out);
       +        copyf--;
       +        lgf--;
       +}
       +
       +
       +void casesp(void)
       +{
       +        casesp1(0);
       +}
       +
       +void casesp1(int a)
       +{
       +        int i, j, savlss;
       +
       +        tbreak();
       +        if (dip->nls || trap)
       +                return;
       +        i = findt1();
       +        if (!a) {
       +                skip();
       +                j = vnumb((int *)0);
       +                if (nonumb)
       +                        j = lss;
       +        } else 
       +                j = a;
       +        if (j == 0)
       +                return;
       +        if (i < j)
       +                j = i;
       +        savlss = lss;
       +        if (dip != d)
       +                i = dip->dnl; 
       +        else 
       +                i = numtabp[NL].val;
       +        if ((i + j) < 0)
       +                j = -i;
       +        lss = j;
       +        newline(0);
       +        lss = savlss;
       +}
       +
       +
       +void casert(void)
       +{
       +        int a, *p;
       +
       +        skip();
       +        if (dip != d)
       +                p = &dip->dnl; 
       +        else 
       +                p = &numtabp[NL].val;
       +        a = vnumb(p);
       +        if (nonumb)
       +                a = dip->mkline;
       +        if ((a < 0) || (a >= *p))
       +                return;
       +        nb++;
       +        casesp1(a - *p);
       +}
       +
       +
       +void caseem(void)
       +{
       +        lgf++;
       +        skip();
       +        em = getrq();
       +}
       +
       +
       +void casefl(void)
       +{
       +        tbreak();
       +        if (!ascii)
       +                ptflush();
       +        flusho();
       +}
       +
       +
       +void caseev(void)
       +{
       +        int nxev;
       +
       +        if (skip()) {
       +e0:
       +                if (evi == 0)
       +                        return;
       +                nxev =  evlist[--evi];
       +                goto e1;
       +        }
       +        noscale++;
       +        nxev = atoi0();
       +        noscale = 0;
       +        if (nonumb)
       +                goto e0;
       +        flushi();
       +        if (nxev >= NEV || nxev < 0 || evi >= EVLSZ) {
       +                flusho();
       +                ERROR "cannot do .ev %d", nxev WARN;
       +                if (error)
       +                        done2(040);
       +                else 
       +                        edone(040);
       +                return;
       +        }
       +        evlist[evi++] = ev;
       +e1:
       +        if (ev == nxev)
       +                return;
       +        ev = nxev;
       +        envp = &env[ev];
       +}
       +
       +void envcopy(Env *e1, Env *e2)        /* copy env e2 to e1 */
       +{
       +        *e1 = *e2;        /* rumor hath that this fails on some machines */
       +}
       +
       +
       +void caseel(void)
       +{
       +        if (--ifx < 0) {
       +                ifx = 0;
       +                iflist[0] = 0;
       +        }
       +        caseif1(2);
       +}
       +
       +
       +void caseie(void)
       +{
       +        if (ifx >= NIF) {
       +                ERROR "if-else overflow." WARN;
       +                ifx = 0;
       +                edone(040);
       +        }
       +        caseif1(1);
       +        ifx++;
       +}
       +
       +
       +void caseif(void)
       +{
       +        caseif1(0);
       +}
       +
       +void caseif1(int x)
       +{
       +        extern int falsef;
       +        int notflag, true;
       +        Tchar i;
       +
       +        if (x == 2) {
       +                notflag = 0;
       +                true = iflist[ifx];
       +                goto i1;
       +        }
       +        true = 0;
       +        skip();
       +        if ((cbits(i = getch())) == '!') {
       +                notflag = 1;
       +        } else {
       +                notflag = 0;
       +                ch = i;
       +        }
       +        ifnum++;
       +        i = atoi0();
       +        ifnum = 0;
       +        if (!nonumb) {
       +                if (i > 0)
       +                        true++;
       +                goto i1;
       +        }
       +        i = getch();
       +        switch (cbits(i)) {
       +        case 'e':
       +                if (!(numtabp[PN].val & 01))
       +                        true++;
       +                break;
       +        case 'o':
       +                if (numtabp[PN].val & 01)
       +                        true++;
       +                break;
       +        case 'n':
       +                if (NROFF)
       +                        true++;
       +                break;
       +        case 't':
       +                if (TROFF)
       +                        true++;
       +                break;
       +        case ' ':
       +                break;
       +        default:
       +                true = cmpstr(i);
       +        }
       +i1:
       +        true ^= notflag;
       +        if (x == 1)
       +                iflist[ifx] = !true;
       +        if (true) {
       +i2:
       +                while ((cbits(i = getch())) == ' ')
       +                        ;
       +                if (cbits(i) == LEFT)
       +                        goto i2;
       +                ch = i;
       +                nflush++;
       +        } else {
       +                if (!nlflg) {
       +                        copyf++;
       +                        falsef++;
       +                        eatblk(0);
       +                        copyf--;
       +                        falsef--;
       +                }
       +        }
       +}
       +
       +void eatblk(int inblk)
       +{
       +        int cnt, i;
       +
       +        cnt = 0;
       +        do {
       +                if (ch)        {
       +                        i = cbits(ch);
       +                        ch = 0;
       +                } else
       +                        i = cbits(getch0());
       +                if (i == ESC)
       +                        cnt++;
       +                else {
       +                        if (cnt == 1)
       +                                switch (i) {
       +                                case '{':  i = LEFT; break;
       +                                case '}':  i = RIGHT; break;
       +                                case '\n': i = 'x'; break;
       +                                }
       +                        cnt = 0;
       +                }
       +                if (i == LEFT) eatblk(1);
       +        } while ((!inblk && (i != '\n')) || (inblk && (i != RIGHT)));
       +        if (i == '\n') {
       +                nlflg++;
       +                if (ip == 0)
       +                        numtabp[CD].val++;
       +        }
       +}
       +
       +
       +cmpstr(Tchar c)
       +{
       +        int j, delim;
       +        Tchar i;
       +        int val;
       +        int savapts, savapts1, savfont, savfont1, savpts, savpts1;
       +        Tchar string[1280];
       +        Tchar *sp;
       +
       +        if (ismot(c))
       +                return(0);
       +        delim = cbits(c);
       +        savapts = apts;
       +        savapts1 = apts1;
       +        savfont = font;
       +        savfont1 = font1;
       +        savpts = pts;
       +        savpts1 = pts1;
       +        sp = string;
       +        while ((j = cbits(i = getch()))!=delim && j!='\n' && sp<&string[1280-1])
       +                *sp++ = i;
       +        if (sp >= string + 1280) {
       +                ERROR "too-long string compare." WARN;
       +                edone(0100);
       +        }
       +        if (nlflg) {
       +                val = sp==string;
       +                goto rtn;
       +        }
       +        *sp = 0;
       +        apts = savapts;
       +        apts1 = savapts1;
       +        font = savfont;
       +        font1 = savfont1;
       +        pts = savpts;
       +        pts1 = savpts1;
       +        mchbits();
       +        val = 1;
       +        sp = string;
       +        while ((j = cbits(i = getch())) != delim && j != '\n') {
       +                if (*sp != i) {
       +                        eat(delim);
       +                        val = 0;
       +                        goto rtn;
       +                }
       +                sp++;
       +        }
       +        if (*sp)
       +                val = 0;
       +rtn:
       +        apts = savapts;
       +        apts1 = savapts1;
       +        font = savfont;
       +        font1 = savfont1;
       +        pts = savpts;
       +        pts1 = savpts1;
       +        mchbits();
       +        return(val);
       +}
       +
       +
       +void caserd(void)
       +{
       +
       +        lgf++;
       +        skip();
       +        getname();
       +        if (!iflg) {
       +                if (quiet) {
       +                        if (NROFF) {
       +                                echo_off();
       +                                flusho();
       +                        }
       +                        fprintf(stderr, "\007"); /*bell*/
       +                } else {
       +                        if (nextf[0]) {
       +                                fprintf(stderr, "%s:", nextf);
       +                        } else {
       +                                fprintf(stderr, "\007"); /*bell*/
       +                        }
       +                }
       +        }
       +        collect();
       +        tty++;
       +        pushi(RD_OFFSET, PAIR('r','d'));
       +}
       +
       +
       +rdtty(void)
       +{
       +        char        onechar;
       +
       +        onechar = 0;
       +        if (read(0, &onechar, 1) == 1) {
       +                if (onechar == '\n')
       +                        tty++;
       +                else 
       +                        tty = 1;
       +                if (tty != 3)
       +                        return(onechar);
       +        }
       +        tty = 0;
       +        if (NROFF && quiet)
       +                echo_on();
       +        return(0);
       +}
       +
       +
       +void caseec(void)
       +{
       +        eschar = chget('\\');
       +}
       +
       +
       +void caseeo(void)
       +{
       +        eschar = 0;
       +}
       +
       +
       +void caseta(void)
       +{
       +        int i, j, k;
       +
       +        tabtab[0] = nonumb = 0;
       +        for (i = 0; ((i < (NTAB - 1)) && !nonumb); i++) {
       +                if (skip())
       +                        break;
       +                k = tabtab[max(i-1, 0)] & TABMASK;
       +                if ((j = max(hnumb(&k), 0)) > TABMASK) {
       +                        ERROR "Tab too far away" WARN;
       +                        j = TABMASK;
       +                }
       +                tabtab[i] = j & TABMASK;
       +                if (!nonumb) 
       +                        switch (cbits(ch)) {
       +                        case 'C':
       +                                tabtab[i] |= CTAB;
       +                                break;
       +                        case 'R':
       +                                tabtab[i] |= RTAB;
       +                                break;
       +                        default: /*includes L*/
       +                                break;
       +                        }
       +                nonumb = ch = 0;
       +        }
       +        if (!skip())
       +                ERROR "Too many tab stops" WARN;
       +        tabtab[i] = 0;
       +}
       +
       +
       +void casene(void)
       +{
       +        int i, j;
       +
       +        skip();
       +        i = vnumb((int *)0);
       +        if (nonumb)
       +                i = lss;
       +        if (dip == d && numtabp[NL].val == -1) {
       +                newline(1);
       +                return;
       +        }
       +        if (i > (j = findt1())) {
       +                i = lss;
       +                lss = j;
       +                dip->nls = 0;
       +                newline(0);
       +                lss = i;
       +        }
       +}
       +
       +
       +void casetr(void)
       +{
       +        int i, j;
       +        Tchar k;
       +
       +        lgf++;
       +        skip();
       +        while ((i = cbits(k=getch())) != '\n') {
       +                if (ismot(k))
       +                        return;
       +                if (ismot(k = getch()))
       +                        return;
       +                if ((j = cbits(k)) == '\n')
       +                        j = ' ';
       +                trtab[i] = j;
       +        }
       +}
       +
       +
       +void casecu(void)
       +{
       +        cu++;
       +        caseul();
       +}
       +
       +
       +void caseul(void)
       +{
       +        int i;
       +
       +        noscale++;
       +        skip();
       +        i = max(atoi0(), 0);
       +        if (nonumb)
       +                i = 1;
       +        if (ul && (i == 0)) {
       +                font = sfont;
       +                ul = cu = 0;
       +        }
       +        if (i) {
       +                if (!ul) {
       +                        sfont = font;
       +                        font = ulfont;
       +                }
       +                ul = i;
       +        }
       +        noscale = 0;
       +        mchbits();
       +}
       +
       +
       +void caseuf(void)
       +{
       +        int i, j;
       +
       +        if (skip() || !(i = getrq()) || i == 'S' ||  (j = findft(i))  == -1)
       +                ulfont = ULFONT; /*default underline position*/
       +        else 
       +                ulfont = j;
       +        if (NROFF && ulfont == FT)
       +                ulfont = ULFONT;
       +}
       +
       +
       +void caseit(void)
       +{
       +        int i;
       +
       +        lgf++;
       +        it = itmac = 0;
       +        noscale++;
       +        skip();
       +        i = atoi0();
       +        skip();
       +        if (!nonumb && (itmac = getrq()))
       +                it = i;
       +        noscale = 0;
       +}
       +
       +
       +void casemc(void)
       +{
       +        int i;
       +
       +        if (icf > 1)
       +                ic = 0;
       +        icf = 0;
       +        if (skip())
       +                return;
       +        ic = getch();
       +        icf = 1;
       +        skip();
       +        i = max(hnumb((int *)0), 0);
       +        if (!nonumb)
       +                ics = i;
       +}
       +
       +
       +void casemk(void)
       +{
       +        int i, j;
       +
       +        if (dip != d)
       +                j = dip->dnl; 
       +        else 
       +                j = numtabp[NL].val;
       +        if (skip()) {
       +                dip->mkline = j;
       +                return;
       +        }
       +        if ((i = getrq()) == 0)
       +                return;
       +        numtabp[findr(i)].val = j;
       +}
       +
       +
       +void casesv(void)
       +{
       +        int i;
       +
       +        skip();
       +        if ((i = vnumb((int *)0)) < 0)
       +                return;
       +        if (nonumb)
       +                i = 1;
       +        sv += i;
       +        caseos();
       +}
       +
       +
       +void caseos(void)
       +{
       +        int savlss;
       +
       +        if (sv <= findt1()) {
       +                savlss = lss;
       +                lss = sv;
       +                newline(0);
       +                lss = savlss;
       +                sv = 0;
       +        }
       +}
       +
       +
       +void casenm(void)
       +{
       +        int i;
       +
       +        lnmod = nn = 0;
       +        if (skip())
       +                return;
       +        lnmod++;
       +        noscale++;
       +        i = inumb(&numtabp[LN].val);
       +        if (!nonumb)
       +                numtabp[LN].val = max(i, 0);
       +        getnm(&ndf, 1);
       +        getnm(&nms, 0);
       +        getnm(&ni, 0);
       +        getnm(&nmwid, 3);        /* really kludgy! */
       +        noscale = 0;
       +        nmbits = chbits;
       +}
       +
       +/*
       + * .nm relies on the fact that illegal args are skipped; don't warn
       + * for illegality of these
       + */
       +void getnm(int *p, int min)
       +{
       +        int i;
       +        int savtr = trace;
       +
       +        eat(' ');
       +        if (skip())
       +                return;
       +        trace = 0;
       +        i = atoi0();
       +        if (nonumb)
       +                return;
       +        *p = max(i, min);
       +        trace = savtr;
       +}
       +
       +
       +void casenn(void)
       +{
       +        noscale++;
       +        skip();
       +        nn = max(atoi0(), 1);
       +        noscale = 0;
       +}
       +
       +
       +void caseab(void)
       +{
       +        casetm1(1, stderr);
       +        done3(0);
       +}
       +
       +
       +/* nroff terminal handling has been pretty well excised */
       +/* as part of the merge with troff.  these are ghostly remnants, */
       +/* called, but doing nothing. restore them at your peril. */
       +
       +
       +void save_tty(void)                        /*save any tty settings that may be changed*/
       +{
       +}
       +
       +
       +void restore_tty(void)                        /*restore tty settings from beginning*/
       +{
       +}
       +
       +
       +void set_tty(void)
       +{
       +}
       +
       +
       +void echo_off(void)                        /*turn off ECHO for .rd in "-q" mode*/
       +{
       +}
       +
       +
       +void echo_on(void)                        /*restore ECHO after .rd in "-q" mode*/
       +{
       +}
 (DIR) diff --git a/src/cmd/troff/n6.c b/src/cmd/troff/n6.c
       t@@ -0,0 +1,362 @@
       +#include "tdef.h"
       +#include "ext.h"
       +#include "fns.h"
       +#include <ctype.h>
       +
       +/*
       + * n6.c -- width functions, sizes and fonts
       +*/
       +
       +n_width(Tchar j)
       +{
       +        int i, k;
       +
       +        if (iszbit(j))
       +                return 0;
       +        if (ismot(j)) {
       +                if (isvmot(j))
       +                        return(0);
       +                k = absmot(j);
       +                if (isnmot(j))
       +                        k = -k;
       +                return(k);
       +        }
       +        i = cbits(j);
       +        if (i < ' ') {
       +                if (i == '\b')
       +                        return(-widthp);
       +                if (i == PRESC)
       +                        i = eschar;
       +                else if (i == HX)
       +                        return(0);
       +        }
       +        if (i == ohc)
       +                return(0);
       +        i = trtab[i];
       +        if (i < ' ')
       +                return(0);
       +        if (i >= t.tfont.nchars)        /* not on the font */
       +                k = t.Char;                /* really ought to check properly */
       +        else
       +                k = t.tfont.wp[i].wid * t.Char;
       +        widthp = k;
       +        return(k);
       +}
       +
       +
       +Tchar n_setch(int c)
       +{
       +        return t_setch(c);
       +}
       +
       +Tchar n_setabs(void)        /* set absolute char from \N'...' */
       +{                        /* for now, a no-op */
       +        return t_setabs();
       +}
       +
       +int n_findft(int i)
       +{
       +        int k;
       +
       +        if ((k = i - '0') >= 0 && k <= nfonts && k < smnt)
       +                return(k);
       +        for (k = 0; fontlab[k] != i; k++)
       +                if (k > nfonts)
       +                        return(-1);
       +        return(k);
       +}
       +
       +
       +
       +void n_mchbits(void)
       +{
       +        chbits = 0;
       +        setfbits(chbits, font);
       +        sps = width(' ' | chbits);
       +}
       +
       +
       +void n_setps(void )
       +{
       +        int i, j;
       +
       +        i = cbits(getch());
       +        if (isdigit(i)) {                /* \sd or \sdd */
       +                i -= '0';
       +                if (i == 0)                /* \s0 */
       +                        ;
       +                else if (i <= 3 && (ch=getch()) && isdigit(cbits(ch))) {        /* \sdd */
       +                        ch = 0;
       +                }
       +        } else if (i == '(') {                /* \s(dd */
       +                getch();
       +                getch();
       +        } else if (i == '+' || i == '-') {        /* \s+, \s- */
       +                j = cbits(getch());
       +                if (isdigit(j)) {                /* \s+d, \s-d */
       +                        ;
       +                } else if (j == '(') {                /* \s+(dd, \s-(dd */
       +                        getch();
       +                        getch();
       +                }
       +        }
       +}
       +
       +
       +Tchar n_setht(void)                /* set character height from \H'...' */
       +{
       +
       +        getch();
       +        inumb(&apts);
       +        getch();
       +        return(0);
       +}
       +
       +
       +Tchar n_setslant(void)                /* set slant from \S'...' */
       +{
       +        int n;
       +
       +        getch();
       +        n = 0;
       +        n = inumb(&n);
       +        getch();
       +        return(0);
       +}
       +
       +
       +void n_caseft(void)
       +{
       +        skip();
       +        setfont(1);
       +}
       +
       +
       +void n_setfont(int a)
       +{
       +        int i, j;
       +
       +        if (a)
       +                i = getrq();
       +        else 
       +                i = getsn();
       +        if (!i || i == 'P') {
       +                j = font1;
       +                goto s0;
       +        }
       +        if (i == 'S' || i == '0')
       +                return;
       +        if ((j = findft(i)) == -1)
       +                return;
       +s0:
       +        font1 = font;
       +        font = j;
       +        mchbits();
       +}
       +
       +
       +void n_setwd(void)
       +{
       +        int base, wid;
       +        Tchar i;
       +        int        delim, emsz, k;
       +        int        savhp, savapts, savapts1, savfont, savfont1, savpts, savpts1;
       +
       +        base = numtabp[ST].val = numtabp[ST].val = wid = numtabp[CT].val = 0;
       +        if (ismot(i = getch()))
       +                return;
       +        delim = cbits(i);
       +        savhp = numtabp[HP].val;
       +        numtabp[HP].val = 0;
       +        savapts = apts;
       +        savapts1 = apts1;
       +        savfont = font;
       +        savfont1 = font1;
       +        savpts = pts;
       +        savpts1 = pts1;
       +        setwdf++;
       +        while (cbits(i = getch()) != delim && !nlflg) {
       +                k = width(i);
       +                wid += k;
       +                numtabp[HP].val += k;
       +                if (!ismot(i)) {
       +                        emsz = (INCH * pts + 36) / 72;
       +                } else if (isvmot(i)) {
       +                        k = absmot(i);
       +                        if (isnmot(i))
       +                                k = -k;
       +                        base -= k;
       +                        emsz = 0;
       +                } else 
       +                        continue;
       +                if (base < numtabp[SB].val)
       +                        numtabp[SB].val = base;
       +                if ((k = base + emsz) > numtabp[ST].val)
       +                        numtabp[ST].val = k;
       +        }
       +        setn1(wid, 0, (Tchar) 0);
       +        numtabp[HP].val = savhp;
       +        apts = savapts;
       +        apts1 = savapts1;
       +        font = savfont;
       +        font1 = savfont1;
       +        pts = savpts;
       +        pts1 = savpts1;
       +        mchbits();
       +        setwdf = 0;
       +}
       +
       +
       +Tchar n_vmot(void)
       +{
       +        dfact = lss;
       +        vflag++;
       +        return n_mot();
       +}
       +
       +
       +Tchar n_hmot(void)
       +{
       +        dfact = EM;
       +        return n_mot();
       +}
       +
       +
       +Tchar n_mot(void)
       +{
       +        int j, n;
       +        Tchar i;
       +
       +        j = HOR;
       +        getch(); /*eat delim*/
       +        if (n = atoi0()) {
       +                if (vflag)
       +                        j = VERT;
       +                i = makem(quant(n, j));
       +        } else
       +                i = 0;
       +        getch();
       +        vflag = 0;
       +        dfact = 1;
       +        return(i);
       +}
       +
       +
       +Tchar n_sethl(int k)
       +{
       +        int j;
       +        Tchar i;
       +
       +        j = t.Halfline;
       +        if (k == 'u')
       +                j = -j;
       +        else if (k == 'r')
       +                j = -2 * j;
       +        vflag++;
       +        i = makem(j);
       +        vflag = 0;
       +        return(i);
       +}
       +
       +
       +Tchar n_makem(int i)
       +{
       +        Tchar j;
       +
       +        if (i >= 0)
       +                j = i;
       +        else
       +                j = -i;
       +        j |= MOT;
       +        if (i < 0)
       +                j |= NMOT;
       +        if (vflag)
       +                j |= VMOT;
       +        return(j);
       +}
       +
       +
       +void n_casefp(void)
       +{
       +        int i, j;
       +
       +        skip();
       +        if ((i = cbits(getch()) - '0') < 0 || i > nfonts)
       +                return;
       +        if (skip() || !(j = getrq()))
       +                return;
       +        fontlab[i] = j;
       +}
       +
       +
       +
       +void n_casebd(void)
       +{
       +        int i, j, k;
       +
       +        k = 0;
       +bd0:
       +        if (skip() || !(i = getrq()) || (j = findft(i)) == -1) {
       +                if (k)
       +                        goto bd1;
       +                else 
       +                        return;
       +        }
       +        if (j == smnt) {
       +                k = smnt;
       +                goto bd0;
       +        }
       +        if (k) {
       +                sbold = j;
       +                j = k;
       +        }
       +bd1:
       +        skip();
       +        noscale++;
       +        bdtab[j] = atoi0();
       +        noscale = 0;
       +}
       +
       +
       +void n_casevs(void)
       +{
       +        int i;
       +
       +        skip();
       +        vflag++;
       +        dfact = INCH; /*default scaling is points!*/
       +        dfactd = 72;
       +        res = VERT;
       +        i = inumb(&lss);
       +        if (nonumb)
       +                i = lss1;
       +        if (i < VERT)
       +                i = VERT;        /* was VERT */
       +        lss1 = lss;
       +        lss = i;
       +}
       +
       +
       +
       +
       +Tchar n_xlss(void)
       +{
       +        /* stores \x'...' into
       +        /* two successive Tchars.
       +        /* the first contains HX, the second the value,
       +        /* encoded as a vertical motion.
       +        /* decoding is done in n2.c by pchar().
       +        */
       +        int        i;
       +
       +        getch();
       +        dfact = lss;
       +        i = quant(atoi0(), VERT);
       +        dfact = 1;
       +        getch();
       +        if (i >= 0)
       +                *pbp++ = MOT | VMOT | i;
       +        else
       +                *pbp++ = MOT | VMOT | NMOT | -i;
       +        return(HX);
       +}
 (DIR) diff --git a/src/cmd/troff/n7.c b/src/cmd/troff/n7.c
       t@@ -0,0 +1,834 @@
       +#include "tdef.h"
       +#include "fns.h"
       +#include "ext.h"
       +
       +#ifdef STRICT
       +        /* not in ANSI or POSIX */
       +#define        isascii(a) ((a) >= 0 && (a) <= 127)
       +#endif
       +
       +#define GETCH gettch
       +Tchar        gettch(void);
       +
       +
       +/*
       + * troff7.c
       + * 
       + * text
       + */
       +
       +int        brflg;
       +
       +void tbreak(void)
       +{
       +        int pad, k;
       +        Tchar *i, j;
       +        int resol;
       +        int un0 = un;
       +
       +        trap = 0;
       +        if (nb)
       +                return;
       +        if (dip == d && numtabp[NL].val == -1) {
       +                newline(1);
       +                return;
       +        }
       +        if (!nc) {
       +                setnel();
       +                if (!wch)
       +                        return;
       +                if (pendw)
       +                        getword(1);
       +                movword();
       +        } else if (pendw && !brflg) {
       +                getword(1);
       +                movword();
       +        }
       +        *linep = dip->nls = 0;
       +        if (NROFF && dip == d)
       +                horiz(po);
       +        if (lnmod)
       +                donum();
       +        lastl = ne;
       +        if (brflg != 1) {
       +                totout = 0;
       +        } else if (ad) {
       +                if ((lastl = ll - un) < ne)
       +                        lastl = ne;
       +        }
       +        if (admod && ad && (brflg != 2)) {
       +                lastl = ne;
       +                adsp = adrem = 0;
       +                if (admod == 1)
       +                        un +=  quant(nel / 2, HOR);
       +                else if (admod == 2)
       +                        un += nel;
       +        }
       +        totout++;
       +        brflg = 0;
       +        if (lastl + un > dip->maxl)
       +                dip->maxl = lastl + un;
       +        horiz(un);
       +        if (NROFF) {
       +                if (adrem % t.Adj)
       +                        resol = t.Hor; 
       +                else 
       +                        resol = t.Adj;
       +        } else
       +                resol = HOR;
       +
       +        lastl = ne + (nwd-1) * adsp + adrem;
       +        for (i = line; nc > 0; ) {
       +                if ((cbits(j = *i++)) == ' ') {
       +                        pad = 0;
       +                        do {
       +                                pad += width(j);
       +                                nc--;
       +                        } while ((cbits(j = *i++)) == ' ');
       +                        i--;
       +                        pad += adsp;
       +                        --nwd;
       +                        if (adrem) {
       +                                if (adrem < 0) {
       +                                        pad -= resol;
       +                                        adrem += resol;
       +                                } else if ((totout & 01) || adrem / resol >= nwd) {
       +                                        pad += resol;
       +                                        adrem -= resol;
       +                                }
       +                        }
       +                        pchar((Tchar) WORDSP);
       +                        horiz(pad);
       +                } else {
       +                        pchar(j);
       +                        nc--;
       +                }
       +        }
       +        if (ic) {
       +                if ((k = ll - un0 - lastl + ics) > 0)
       +                        horiz(k);
       +                pchar(ic);
       +        }
       +        if (icf)
       +                icf++;
       +        else 
       +                ic = 0;
       +        ne = nwd = 0;
       +        un = in;
       +        setnel();
       +        newline(0);
       +        if (dip != d) {
       +                if (dip->dnl > dip->hnl)
       +                        dip->hnl = dip->dnl;
       +        } else {
       +                if (numtabp[NL].val > dip->hnl)
       +                        dip->hnl = numtabp[NL].val;
       +        }
       +        for (k = ls - 1; k > 0 && !trap; k--)
       +                newline(0);
       +        spread = 0;
       +}
       +
       +void donum(void)
       +{
       +        int i, nw;
       +        int lnv = numtabp[LN].val;
       +
       +        nrbits = nmbits;
       +        nw = width('1' | nrbits);
       +        if (nn) {
       +                nn--;
       +                goto d1;
       +        }
       +        if (lnv % ndf) {
       +                numtabp[LN].val++;
       +d1:
       +                un += nw * (nmwid + nms + ni);
       +                return;
       +        }
       +        i = 0;
       +        do {                /* count digits in numtabp[LN].val */
       +                i++;
       +        } while ((lnv /= 10) > 0);
       +        horiz(nw * (ni + max(nmwid-i, 0)));
       +        nform = 0;
       +        fnumb(numtabp[LN].val, pchar);
       +        un += nw * nms;
       +        numtabp[LN].val++;
       +}
       +
       +
       +void text(void)
       +{
       +        Tchar i;
       +        static int spcnt;
       +
       +        nflush++;
       +        numtabp[HP].val = 0;
       +        if ((dip == d) && (numtabp[NL].val == -1)) {
       +                newline(1); 
       +                return;
       +        }
       +        setnel();
       +        if (ce || !fi) {
       +                nofill();
       +                return;
       +        }
       +        if (pendw)
       +                goto t4;
       +        if (pendt)
       +                if (spcnt)
       +                        goto t2; 
       +                else 
       +                        goto t3;
       +        pendt++;
       +        if (spcnt)
       +                goto t2;
       +        while ((cbits(i = GETCH())) == ' ') {
       +                spcnt++;
       +                numtabp[HP].val += sps;
       +                widthp = sps;
       +        }
       +        if (nlflg) {
       +t1:
       +                nflush = pendt = ch = spcnt = 0;
       +                callsp();
       +                return;
       +        }
       +        ch = i;
       +        if (spcnt) {
       +t2:
       +                tbreak();
       +                if (nc || wch)
       +                        goto rtn;
       +                un += spcnt * sps;
       +                spcnt = 0;
       +                setnel();
       +                if (trap)
       +                        goto rtn;
       +                if (nlflg)
       +                        goto t1;
       +        }
       +t3:
       +        if (spread)
       +                goto t5;
       +        if (pendw || !wch)
       +t4:
       +                if (getword(0))
       +                        goto t6;
       +        if (!movword())
       +                goto t3;
       +t5:
       +        if (nlflg)
       +                pendt = 0;
       +        adsp = adrem = 0;
       +        if (ad) {
       +                if (nwd == 1)
       +                        adsp = nel; 
       +                else 
       +                        adsp = nel / (nwd - 1);
       +                adsp = (adsp / HOR) * HOR;
       +                adrem = nel - adsp*(nwd-1);
       +        }
       +        brflg = 1;
       +        tbreak();
       +        spread = 0;
       +        if (!trap)
       +                goto t3;
       +        if (!nlflg)
       +                goto rtn;
       +t6:
       +        pendt = 0;
       +        ckul();
       +rtn:
       +        nflush = 0;
       +}
       +
       +
       +void nofill(void)
       +{
       +        int j;
       +        Tchar i;
       +
       +        if (!pendnf) {
       +                over = 0;
       +                tbreak();
       +                if (trap)
       +                        goto rtn;
       +                if (nlflg) {
       +                        ch = nflush = 0;
       +                        callsp();
       +                        return;
       +                }
       +                adsp = adrem = 0;
       +                nwd = 10000;
       +        }
       +        while ((j = (cbits(i = GETCH()))) != '\n') {
       +                if (j == ohc)
       +                        continue;
       +                if (j == CONT) {
       +                        pendnf++;
       +                        nflush = 0;
       +                        flushi();
       +                        ckul();
       +                        return;
       +                }
       +                j = width(i);
       +                widthp = j;
       +                numtabp[HP].val += j;
       +                storeline(i, j);
       +        }
       +        if (ce) {
       +                ce--;
       +                if ((i = quant(nel / 2, HOR)) > 0)
       +                        un += i;
       +        }
       +        if (!nc)
       +                storeline((Tchar)FILLER, 0);
       +        brflg = 2;
       +        tbreak();
       +        ckul();
       +rtn:
       +        pendnf = nflush = 0;
       +}
       +
       +
       +void callsp(void)
       +{
       +        int i;
       +
       +        if (flss)
       +                i = flss; 
       +        else 
       +                i = lss;
       +        flss = 0;
       +        casesp1(i);
       +}
       +
       +
       +void ckul(void)
       +{
       +        if (ul && (--ul == 0)) {
       +                cu = 0;
       +                font = sfont;
       +                mchbits();
       +        }
       +        if (it && --it == 0 && itmac)
       +                control(itmac, 0);
       +}
       +
       +
       +void storeline(Tchar c, int w)
       +{
       +        int diff;
       +
       +        if (linep >= line + lnsize - 2) {
       +                lnsize += LNSIZE;
       +                diff = linep - line;
       +                if (( line = (Tchar *)realloc((char *)line, lnsize * sizeof(Tchar))) != NULL) {
       +                        if (linep && diff)
       +                                linep = line + diff;
       +                } else {
       +                        if (over) {
       +                                return;
       +                        } else {
       +                                flusho();
       +                                ERROR "Line overflow." WARN;
       +                                over++;
       +                                *linep++ = LEFTHAND;
       +                                w = width(LEFTHAND);
       +                                nc++;
       +                                c = '\n';
       +                        }
       +                }
       +        }
       +        *linep++ = c;
       +        ne += w;
       +        nel -= w;
       +        nc++;
       +}
       +
       +
       +void newline(int a)
       +{
       +        int i, j, nlss;
       +        int opn;
       +
       +        if (a)
       +                goto nl1;
       +        if (dip != d) {
       +                j = lss;
       +                pchar1((Tchar)FLSS);
       +                if (flss)
       +                        lss = flss;
       +                i = lss + dip->blss;
       +                dip->dnl += i;
       +                pchar1((Tchar)i);
       +                pchar1((Tchar)'\n');
       +                lss = j;
       +                dip->blss = flss = 0;
       +                if (dip->alss) {
       +                        pchar1((Tchar)FLSS);
       +                        pchar1((Tchar)dip->alss);
       +                        pchar1((Tchar)'\n');
       +                        dip->dnl += dip->alss;
       +                        dip->alss = 0;
       +                }
       +                if (dip->ditrap && !dip->ditf && dip->dnl >= dip->ditrap && dip->dimac)
       +                        if (control(dip->dimac, 0)) {
       +                                trap++; 
       +                                dip->ditf++;
       +                        }
       +                return;
       +        }
       +        j = lss;
       +        if (flss)
       +                lss = flss;
       +        nlss = dip->alss + dip->blss + lss;
       +        numtabp[NL].val += nlss;
       +        if (TROFF && ascii) {
       +                dip->alss = dip->blss = 0;
       +        }
       +        pchar1((Tchar)'\n');
       +        flss = 0;
       +        lss = j;
       +        if (numtabp[NL].val < pl)
       +                goto nl2;
       +nl1:
       +        ejf = dip->hnl = numtabp[NL].val = 0;
       +        ejl = frame;
       +        if (donef) {
       +                if ((!nc && !wch) || ndone)
       +                        done1(0);
       +                ndone++;
       +                donef = 0;
       +                if (frame == stk)
       +                        nflush++;
       +        }
       +        opn = numtabp[PN].val;
       +        numtabp[PN].val++;
       +        if (npnflg) {
       +                numtabp[PN].val = npn;
       +                npn = npnflg = 0;
       +        }
       +nlpn:
       +        if (numtabp[PN].val == pfrom) {
       +                print++;
       +                pfrom = -1;
       +        } else if (opn == pto) {
       +                print = 0;
       +                opn = -1;
       +                chkpn();
       +                goto nlpn;
       +        }
       +        if (print)
       +                ptpage(numtabp[PN].val);        /* supposedly in a clean state so can pause */
       +        if (stop && print) {
       +                dpn++;
       +                if (dpn >= stop) {
       +                        dpn = 0;
       +                        ptpause();
       +                }
       +        }
       +nl2:
       +        trap = 0;
       +        if (numtabp[NL].val == 0) {
       +                if ((j = findn(0)) != NTRAP)
       +                        trap = control(mlist[j], 0);
       +        } else if ((i = findt(numtabp[NL].val - nlss)) <= nlss) {
       +                if ((j = findn1(numtabp[NL].val - nlss + i)) == NTRAP) {
       +                        flusho();
       +                        ERROR "Trap botch." WARN;
       +                        done2(-5);
       +                }
       +                trap = control(mlist[j], 0);
       +        }
       +}
       +
       +
       +findn1(int a)
       +{
       +        int i, j;
       +
       +        for (i = 0; i < NTRAP; i++) {
       +                if (mlist[i]) {
       +                        if ((j = nlist[i]) < 0)
       +                                j += pl;
       +                        if (j == a)
       +                                break;
       +                }
       +        }
       +        return(i);
       +}
       +
       +
       +void chkpn(void)
       +{
       +        pto = *(pnp++);
       +        pfrom = pto>=0 ? pto : -pto;
       +        if (pto == -INT_MAX) {
       +                flusho();
       +                done1(0);
       +        }
       +        if (pto < 0) {
       +                pto = -pto;
       +                print++;
       +                pfrom = 0;
       +        }
       +}
       +
       +
       +findt(int a)
       +{
       +        int i, j, k;
       +
       +        k = INT_MAX;
       +        if (dip != d) {
       +                if (dip->dimac && (i = dip->ditrap - a) > 0)
       +                        k = i;
       +                return(k);
       +        }
       +        for (i = 0; i < NTRAP; i++) {
       +                if (mlist[i]) {
       +                        if ((j = nlist[i]) < 0)
       +                                j += pl;
       +                        if ((j -= a) <= 0)
       +                                continue;
       +                        if (j < k)
       +                                k = j;
       +                }
       +        }
       +        i = pl - a;
       +        if (k > i)
       +                k = i;
       +        return(k);
       +}
       +
       +
       +findt1(void)
       +{
       +        int i;
       +
       +        if (dip != d)
       +                i = dip->dnl;
       +        else 
       +                i = numtabp[NL].val;
       +        return(findt(i));
       +}
       +
       +
       +void eject(Stack *a)
       +{
       +        int savlss;
       +
       +        if (dip != d)
       +                return;
       +        ejf++;
       +        if (a)
       +                ejl = a;
       +        else 
       +                ejl = frame;
       +        if (trap)
       +                return;
       +e1:
       +        savlss = lss;
       +        lss = findt(numtabp[NL].val);
       +        newline(0);
       +        lss = savlss;
       +        if (numtabp[NL].val && !trap)
       +                goto e1;
       +}
       +
       +
       +movword(void)
       +{
       +        int w;
       +        Tchar i, *wp;
       +        int savwch, hys;
       +
       +        over = 0;
       +        wp = wordp;
       +        if (!nwd) {
       +                while (cbits(*wp++) == ' ') {
       +                        wch--;
       +                        wne -= sps;
       +                }
       +                wp--;
       +        }
       +        if (wne > nel && !hyoff && hyf && (!nwd || nel > 3 * sps) &&
       +           (!(hyf & 02) || (findt1() > lss)))
       +                hyphen(wp);
       +        savwch = wch;
       +        hyp = hyptr;
       +        nhyp = 0;
       +        while (*hyp && *hyp <= wp)
       +                hyp++;
       +        while (wch) {
       +                if (hyoff != 1 && *hyp == wp) {
       +                        hyp++;
       +                        if (!wdstart || (wp > wdstart + 1 && wp < wdend &&
       +                           (!(hyf & 04) || wp < wdend - 1) &&                /* 04 => last 2 */
       +                           (!(hyf & 010) || wp > wdstart + 2))) {        /* 010 => 1st 2 */
       +                                nhyp++;
       +                                storeline((Tchar)IMP, 0);
       +                        }
       +                }
       +                i = *wp++;
       +                w = width(i);
       +                wne -= w;
       +                wch--;
       +                storeline(i, w);
       +        }
       +        if (nel >= 0) {
       +                nwd++;
       +                return(0);        /* line didn't fill up */
       +        }
       +        if (TROFF)
       +                xbits((Tchar)HYPHEN, 1);
       +        hys = width((Tchar)HYPHEN);
       +m1:
       +        if (!nhyp) {
       +                if (!nwd)
       +                        goto m3;
       +                if (wch == savwch)
       +                        goto m4;
       +        }
       +        if (*--linep != IMP)
       +                goto m5;
       +        if (!(--nhyp))
       +                if (!nwd)
       +                        goto m2;
       +        if (nel < hys) {
       +                nc--;
       +                goto m1;
       +        }
       +m2:
       +        if ((i = cbits(*(linep - 1))) != '-' && i != EMDASH) {
       +                *linep = (*(linep - 1) & SFMASK) | HYPHEN;
       +                w = width(*linep);
       +                nel -= w;
       +                ne += w;
       +                linep++;
       +        }
       +m3:
       +        nwd++;
       +m4:
       +        wordp = wp;
       +        return(1);        /* line filled up */
       +m5:
       +        nc--;
       +        w = width(*linep);
       +        ne -= w;
       +        nel += w;
       +        wne += w;
       +        wch++;
       +        wp--;
       +        goto m1;
       +}
       +
       +
       +void horiz(int i)
       +{
       +        vflag = 0;
       +        if (i)
       +                pchar(makem(i));
       +}
       +
       +
       +void setnel(void)
       +{
       +        if (!nc) {
       +                linep = line;
       +                if (un1 >= 0) {
       +                        un = un1;
       +                        un1 = -1;
       +                }
       +                nel = ll - un;
       +                ne = adsp = adrem = 0;
       +        }
       +}
       +
       +
       +getword(int x)
       +{
       +        int j, k;
       +        Tchar i, *wp;
       +        int noword;
       +        int obits;
       +
       +        noword = 0;
       +        if (x)
       +                if (pendw) {
       +                        *pendw = 0;
       +                        goto rtn;
       +                }
       +        if (wordp = pendw)
       +                goto g1;
       +        hyp = hyptr;
       +        wordp = word;
       +        over = wne = wch = 0;
       +        hyoff = 0;
       +        obits = chbits;
       +        while (1) {        /* picks up 1st char of word */
       +                j = cbits(i = GETCH());
       +                if (j == '\n') {
       +                        wne = wch = 0;
       +                        noword = 1;
       +                        goto rtn;
       +                }
       +                if (j == ohc) {
       +                        hyoff = 1;        /* 1 => don't hyphenate */
       +                        continue;
       +                }
       +                if (j == ' ') {
       +                        numtabp[HP].val += sps;
       +                        widthp = sps;
       +                        storeword(i, sps);
       +                        continue;
       +                }
       +                break;
       +        }
       +        storeword(' ' | obits, sps);
       +        if (spflg) {
       +                storeword(' ' | obits, sps);
       +                spflg = 0;
       +        }
       +g0:
       +        if (j == CONT) {
       +                pendw = wordp;
       +                nflush = 0;
       +                flushi();
       +                return(1);
       +        }
       +        if (hyoff != 1) {
       +                if (j == ohc) {
       +                        hyoff = 2;
       +                        *hyp++ = wordp;
       +                        if (hyp > hyptr + NHYP - 1)
       +                                hyp = hyptr + NHYP - 1;
       +                        goto g1;
       +                }
       +                if (((j == '-' || j == EMDASH)) && !(i & ZBIT))        /* zbit avoids \X */
       +                        if (wordp > word + 1) {
       +                                hyoff = 2;
       +                                *hyp++ = wordp + 1;
       +                                if (hyp > hyptr + NHYP - 1)
       +                                        hyp = hyptr + NHYP - 1;
       +                        }
       +        }
       +        j = width(i);
       +        numtabp[HP].val += j;
       +        storeword(i, j);
       +g1:
       +        j = cbits(i = GETCH());
       +        if (j != ' ') {
       +                static char *sentchar = ".?!";        /* sentence terminators */
       +                if (j != '\n')
       +                        goto g0;
       +                wp = wordp-1;        /* handle extra space at end of sentence */
       +                while (wp >= word) {
       +                        j = cbits(*wp--);
       +                        if (j=='"' || j=='\'' || j==')' || j==']' || j=='*' || j==DAGGER)
       +                                continue;
       +                        for (k = 0; sentchar[k]; k++)
       +                                if (j == sentchar[k]) {
       +                                        spflg++;
       +                                        break;
       +                                }
       +                        break;
       +                }
       +        }
       +        *wordp = 0;
       +        numtabp[HP].val += sps;
       +rtn:
       +        for (wp = word; *wp; wp++) {
       +                if (ismot(j))
       +                        break;        /* drechsler */
       +                j = cbits(*wp);
       +                if (j == ' ')
       +                        continue;
       +                if (!(isascii(j) && isdigit(j)) && j != '-')
       +                        break;
       +        }
       +        if (*wp == 0)        /* all numbers, so don't hyphenate */
       +                hyoff = 1;
       +        wdstart = 0;
       +        wordp = word;
       +        pendw = 0;
       +        *hyp++ = 0;
       +        setnel();
       +        return(noword);
       +}
       +
       +
       +void storeword(Tchar c, int w)
       +{
       +        Tchar *savp;
       +        int i;
       +
       +        if (wordp >= word + wdsize - 2) {
       +                wdsize += WDSIZE;
       +                savp = word;
       +                if (( word = (Tchar *)realloc((char *)word, wdsize * sizeof(Tchar))) != NULL) {
       +                        if (wordp)
       +                                wordp = word + (wordp - savp);
       +                        if (pendw)
       +                                pendw = word + (pendw - savp);
       +                        if (wdstart)
       +                                wdstart = word + (wdstart - savp);
       +                        if (wdend)
       +                                wdend = word + (wdend - savp);
       +                        for (i = 0; i < NHYP; i++)
       +                                if (hyptr[i])
       +                                        hyptr[i] = word + (hyptr[i] - savp);
       +                } else {
       +                        if (over) {
       +                                return;
       +                        } else {
       +                                flusho();
       +                                ERROR "Word overflow." WARN;
       +                                over++;
       +                                c = LEFTHAND;
       +                                w = width(LEFTHAND);
       +                        }
       +                }
       +        }
       +        widthp = w;
       +        wne += w;
       +        *wordp++ = c;
       +        wch++;
       +}
       +
       +
       +Tchar gettch(void)
       +{
       +        extern int c_isalnum;
       +        Tchar i;
       +        int j;
       +
       +        if (TROFF)
       +                return getch();
       +
       +        i = getch();
       +        j = cbits(i);
       +        if (ismot(i) || fbits(i) != ulfont)
       +                return(i);
       +        if (cu) {
       +                if (trtab[j] == ' ') {
       +                        setcbits(i, '_');
       +                        setfbits(i, FT);        /* default */
       +                }
       +                return(i);
       +        }
       +        /* should test here for characters that ought to be underlined */
       +        /* in the old nroff, that was the 200 bit on the width! */
       +        /* for now, just do letters, digits and certain special chars */
       +        if (j <= 127) {
       +                if (!isalnum(j))
       +                        setfbits(i, FT);
       +        } else {
       +                if (j < c_isalnum)
       +                        setfbits(i, FT);
       +        }
       +        return(i);
       +}
 (DIR) diff --git a/src/cmd/troff/n8.c b/src/cmd/troff/n8.c
       t@@ -0,0 +1,540 @@
       +#include "tdef.h"
       +#include "fns.h"
       +#include "ext.h"
       +
       +#define        HY_BIT        0200        /* stuff in here only works for 7-bit ascii */
       +                        /* this value is used (as a literal) in suftab.c */
       +                        /* to encode possible hyphenation points in suffixes. */
       +                        /* it could be changed, by widening the tables */
       +                        /* to be shorts instead of chars. */
       +
       +/*
       + * troff8.c
       + * 
       + * hyphenation
       + */
       +
       +int        hexsize = 0;                /* hyphenation exception list size */
       +char        *hbufp = NULL;                /* base of list */
       +char        *nexth = NULL;                /* first free slot in list */
       +Tchar        *hyend;
       +
       +#define THRESH 160                 /* digram goodness threshold */
       +int        thresh = THRESH;
       +
       +int        texhyphen(void);
       +static        int        alpha(Tchar);
       +
       +void hyphen(Tchar *wp)
       +{
       +        int j;
       +        Tchar *i;
       +
       +        i = wp;
       +        while (punct((*i++)))
       +                ;
       +        if (!alpha(*--i))
       +                return;
       +        wdstart = i++;
       +        while (alpha(*i++))
       +                ;
       +        hyend = wdend = --i - 1;
       +        while (punct((*i++)))
       +                ;
       +        if (*--i)
       +                return;
       +        if (wdend - wdstart < 4)        /* 4 chars is too short to hyphenate */
       +                return;
       +        hyp = hyptr;
       +        *hyp = 0;
       +        hyoff = 2;
       +
       +        /* for now, try exceptions first, then tex (if hyphalg is non-zero),
       +           then suffix and digram if tex didn't hyphenate it at all.
       +        */
       +
       +        if (!exword() && !texhyphen() && !suffix())
       +                digram();
       +
       +        /* this appears to sort hyphenation points into increasing order */
       +        *hyp++ = 0;
       +        if (*hyptr) 
       +                for (j = 1; j; ) {
       +                        j = 0;
       +                        for (hyp = hyptr + 1; *hyp != 0; hyp++) {
       +                                if (*(hyp - 1) > *hyp) {
       +                                        j++;
       +                                        i = *hyp;
       +                                        *hyp = *(hyp - 1);
       +                                        *(hyp - 1) = i;
       +                                }
       +                        }
       +                }
       +}
       +
       +static alpha(Tchar i)        /* non-zero if really alphabetic */
       +{
       +        if (ismot(i))
       +                return 0;
       +        else if (cbits(i) >= ALPHABET)        /* this isn't very elegant, but there's */
       +                return 0;                /* no good way to make sure i is in range for */
       +        else                                /* the call of isalpha */
       +                return isalpha(cbits(i));
       +}
       +
       +
       +punct(Tchar i)
       +{
       +        if (!i || alpha(i))
       +                return(0);
       +        else
       +                return(1);
       +}
       +
       +
       +void caseha(void)        /* set hyphenation algorithm */
       +{
       +        hyphalg = HYPHALG;
       +        if (skip())
       +                return;
       +        noscale++;
       +        hyphalg = atoi0();
       +        noscale = 0;
       +}
       +
       +
       +void caseht(void)        /* set hyphenation threshold;  not in manual! */
       +{
       +        thresh = THRESH;
       +        if (skip())
       +                return;
       +        noscale++;
       +        thresh = atoi0();
       +        noscale = 0;
       +}
       +
       +
       +char *growh(char *where)
       +{
       +        char *new;
       +
       +        hexsize += NHEX;
       +        if ((new = grow(hbufp, hexsize, sizeof(char))) == NULL)
       +                return NULL;
       +        if (new == hbufp) {
       +                return where;
       +        } else {
       +                int diff;
       +                diff = where - hbufp;
       +                hbufp = new;
       +                return new + diff;
       +        }
       +}
       +
       +
       +void casehw(void)
       +{
       +        int i, k;
       +        char *j;
       +        Tchar t;
       +
       +        if (nexth == NULL) {
       +                if ((nexth = hbufp = grow(hbufp, NHEX, sizeof(char))) == NULL) {
       +                        ERROR "No space for exception word list." WARN;
       +                        return;
       +                }
       +                hexsize = NHEX;
       +        }
       +        k = 0;
       +        while (!skip()) {
       +                if ((j = nexth) >= hbufp + hexsize - 2)
       +                        if ((j = nexth = growh(j)) == NULL)
       +                                goto full;
       +                for (;;) {
       +                        if (ismot(t = getch()))
       +                                continue;
       +                        i = cbits(t);
       +                        if (i == ' ' || i == '\n') {
       +                                *j++ = 0;
       +                                nexth = j;
       +                                *j = 0;
       +                                if (i == ' ')
       +                                        break;
       +                                else
       +                                        return;
       +                        }
       +                        if (i == '-') {
       +                                k = HY_BIT;
       +                                continue;
       +                        }
       +                        *j++ = maplow(i) | k;
       +                        k = 0;
       +                        if (j >= hbufp + hexsize - 2)
       +                                if ((j = growh(j)) == NULL)
       +                                        goto full;
       +                }
       +        }
       +        return;
       +full:
       +        ERROR "Cannot grow exception word list." WARN;
       +        *nexth = 0;
       +}
       +
       +
       +int exword(void)
       +{
       +        Tchar *w;
       +        char *e, *save;
       +
       +        e = hbufp;
       +        while (1) {
       +                save = e;
       +                if (e == NULL || *e == 0)
       +                        return(0);
       +                w = wdstart;
       +                while (*e && w <= hyend && (*e & 0177) == maplow(cbits(*w))) {
       +                        e++; 
       +                        w++;
       +                }
       +                if (!*e) {
       +                        if (w-1 == hyend || (w == wdend && maplow(cbits(*w)) == 's')) {
       +                                w = wdstart;
       +                                for (e = save; *e; e++) {
       +                                        if (*e & HY_BIT)
       +                                                *hyp++ = w;
       +                                        if (hyp > hyptr + NHYP - 1)
       +                                                hyp = hyptr + NHYP - 1;
       +                                        w++;
       +                                }
       +                                return(1);
       +                        } else {
       +                                e++; 
       +                                continue;
       +                        }
       +                } else 
       +                        while (*e++)
       +                                ;
       +        }
       +}
       +
       +
       +suffix(void)
       +{
       +        Tchar *w;
       +        char *s, *s0;
       +        Tchar i;
       +        extern char *suftab[];
       +
       +again:
       +        i = cbits(*hyend);
       +        if (!alpha(i))
       +                return(0);
       +        if (i < 'a')
       +                i -= 'A' - 'a';
       +        if ((s0 = suftab[i-'a']) == 0)
       +                return(0);
       +        for (;;) {
       +                if ((i = *s0 & 017) == 0)
       +                        return(0);
       +                s = s0 + i - 1;
       +                w = hyend - 1;
       +                while (s > s0 && w >= wdstart && (*s & 0177) == maplow(cbits(*w))) {
       +                        s--;
       +                        w--;
       +                }
       +                if (s == s0)
       +                        break;
       +                s0 += i;
       +        }
       +        s = s0 + i - 1;
       +        w = hyend;
       +        if (*s0 & HY_BIT) 
       +                goto mark;
       +        while (s > s0) {
       +                w--;
       +                if (*s-- & HY_BIT) {
       +mark:
       +                        hyend = w - 1;
       +                        if (*s0 & 0100)        /* 0100 used in suftab to encode something too */
       +                                continue;
       +                        if (!chkvow(w))
       +                                return(0);
       +                        *hyp++ = w;
       +                }
       +        }
       +        if (*s0 & 040)
       +                return(0);
       +        if (exword())
       +                return(1);
       +        goto again;
       +}
       +
       +
       +maplow(int i)
       +{
       +        if (isupper(i)) 
       +                i = tolower(i);
       +        return(i);
       +}
       +
       +
       +vowel(int i)
       +{
       +        switch (i) {
       +        case 'a': case 'A':
       +        case 'e': case 'E':
       +        case 'i': case 'I':
       +        case 'o': case 'O':
       +        case 'u': case 'U':
       +        case 'y': case 'Y':
       +                return(1);
       +        default:
       +                return(0);
       +        }
       +}
       +
       +
       +Tchar *chkvow(Tchar *w)
       +{
       +        while (--w >= wdstart)
       +                if (vowel(cbits(*w)))
       +                        return(w);
       +        return(0);
       +}
       +
       +
       +void digram(void)
       +{
       +        Tchar *w;
       +        int val;
       +        Tchar *nhyend, *maxw;
       +        int maxval;
       +        extern char bxh[26][13], bxxh[26][13], xxh[26][13], xhx[26][13], hxx[26][13];
       +
       +again:
       +        if (!(w = chkvow(hyend + 1)))
       +                return;
       +        hyend = w;
       +        if (!(w = chkvow(hyend)))
       +                return;
       +        nhyend = w;
       +        maxval = 0;
       +        w--;
       +        while (++w < hyend && w < wdend - 1) {
       +                val = 1;
       +                if (w == wdstart)
       +                        val *= dilook('a', cbits(*w), bxh);
       +                else if (w == wdstart + 1)
       +                        val *= dilook(cbits(*(w-1)), cbits(*w), bxxh);
       +                else 
       +                        val *= dilook(cbits(*(w-1)), cbits(*w), xxh);
       +                val *= dilook(cbits(*w), cbits(*(w+1)), xhx);
       +                val *= dilook(cbits(*(w+1)), cbits(*(w+2)), hxx);
       +                if (val > maxval) {
       +                        maxval = val;
       +                        maxw = w + 1;
       +                }
       +        }
       +        hyend = nhyend;
       +        if (maxval > thresh)
       +                *hyp++ = maxw;
       +        goto again;
       +}
       +
       +
       +dilook(int a, int b, char t[26][13])
       +{
       +        int i, j;
       +
       +        i = t[maplow(a)-'a'][(j = maplow(b)-'a')/2];
       +        if (!(j & 01))
       +                i >>= 4;
       +        return(i & 017);
       +}
       +
       +
       +/* here beginneth the tex hyphenation code, as interpreted freely */
       +/* the main difference is that there is no attempt to squeeze space */
       +/* as tightly at tex does. */
       +
       +static int        texit(Tchar *, Tchar *);
       +static int        readpats(void);
       +static void        install(char *);
       +static void        fixup(void);
       +static int        trieindex(int, int);
       +
       +static char        pats[50000];        /* size ought to be computed dynamically */
       +static char        *nextpat = pats;
       +static char        *trie[27*27];        /* english-specific sizes */
       +
       +int texhyphen(void)
       +{
       +        static int loaded = 0;                /* -1: couldn't find tex file */
       +
       +        if (hyphalg == 0 || loaded == -1)        /* non-zero => tex for now */
       +                return 0;
       +        if (loaded == 0) {
       +                if (readpats())
       +                        loaded = 1;
       +                else
       +                        loaded = -1;
       +        }
       +        return texit(wdstart, wdend);
       +}
       +
       +static int texit(Tchar *start, Tchar *end)        /* hyphenate as in tex, return # found */
       +{
       +        int nw, i, k, equal, cnt[500];
       +        char w[500+1], *np, *pp, *wp, *xpp, *xwp;
       +
       +        w[0] = '.';
       +        for (nw = 1; start <= end && nw < 500-1; nw++, start++)
       +                w[nw] = maplow(tolower(cbits(*start)));
       +        start -= (nw - 1);
       +        w[nw++] = '.';
       +        w[nw] = 0;
       +/*
       + * printf("try %s\n", w);
       +*/
       +        for (i = 0; i <= nw; i++)
       +                cnt[i] = '0';
       +
       +        for (wp = w; wp < w + nw; wp++) {
       +                for (pp = trie[trieindex(*wp, *(wp+1))]; pp < nextpat; ) {
       +                        if (pp == 0                /* no trie entry */
       +                         || *pp != *wp                /* no match on 1st letter */
       +                         || *(pp+1) != *(wp+1))        /* no match on 2nd letter */
       +                                break;                /*   so move to next letter of word */
       +                        equal = 1;
       +                        for (xpp = pp+2, xwp = wp+2; *xpp; )
       +                                if (*xpp++ != *xwp++) {
       +                                        equal = 0;
       +                                        break;
       +                                }
       +                        if (equal) {
       +                                np = xpp+1;        /* numpat */
       +                                for (k = wp-w; *np; k++, np++)
       +                                        if (*np > cnt[k])
       +                                                cnt[k] = *np;
       +/*
       + * printf("match: %s  %s\n", pp, xpp+1);
       +*/
       +                        }
       +                        pp += *(pp-1);        /* skip over pattern and numbers to next */
       +                }
       +        }
       +/*
       + * for (i = 0; i < nw; i++) printf("%c", w[i]);
       + * printf("  ");
       + * for (i = 0; i <= nw; i++) printf("%c", cnt[i]);
       + * printf("\n");
       +*/
       +/*
       + *         for (i = 1; i < nw - 1; i++) {
       + *                 if (i > 2 && i < nw - 3 && cnt[i] % 2)
       + *                         printf("-");
       + *                 if (cbits(start[i-1]) != '.')
       + *                         printf("%c", cbits(start[i-1]));
       + *         }
       + *         printf("\n");
       +*/
       +        for (i = 1; i < nw -1; i++)
       +                if (i > 2 && i < nw - 3 && cnt[i] % 2)
       +                        *hyp++ = start + i - 1;
       +        return hyp - hyptr;        /* non-zero if a hyphen was found */
       +}
       +
       +/*
       +        This code assumes that hyphen.tex looks like
       +                % some comments
       +                \patterns{ % more comments
       +                pat5ter4ns, 1 per line, SORTED, nothing else
       +                }
       +                more goo
       +                \hyphenation{ % more comments
       +                ex-cep-tions, one per line; i ignore this part for now
       +                }
       +
       +        this code is NOT robust against variations.  unfortunately,
       +        it looks like every local language version of this file has
       +        a different format.  i have also made no provision for weird
       +        characters.  sigh.
       +*/
       +
       +static int readpats(void)
       +{
       +        FILE *fp;
       +        char buf[200], buf1[200];
       +
       +        if ((fp = fopen(unsharp(TEXHYPHENS), "r")) == NULL
       +         && (fp = fopen(unsharp(DWBalthyphens), "r")) == NULL) {
       +                ERROR "warning: can't find hyphen.tex" WARN;
       +                return 0;
       +        }
       +
       +        while (fgets(buf, sizeof buf, fp) != NULL) {
       +                sscanf(buf, "%s", buf1);
       +                if (strcmp(buf1, "\\patterns{") == 0)
       +                        break;
       +        }
       +        while (fgets(buf, sizeof buf, fp) != NULL) {
       +                if (buf[0] == '}')
       +                        break;
       +                install(buf);
       +        }
       +        fclose(fp);
       +        fixup();
       +        return 1;
       +}
       +
       +static void install(char *s)        /* map ab4c5de to: 12 abcde \0 00405 \0 */
       +{
       +        int npat, lastpat;
       +        char num[500], *onextpat = nextpat;
       +
       +        num[0] = '0';
       +        *nextpat++ = ' ';        /* fill in with count later */
       +        for (npat = lastpat = 0; *s != '\n' && *s != '\0'; s++) {
       +                if (isdigit(*s)) {
       +                        num[npat] = *s;
       +                        lastpat = npat;
       +                } else {
       +                        *nextpat++ = *s;
       +                        npat++;
       +                        num[npat] = '0';
       +                }
       +        }
       +        *nextpat++ = 0;
       +        if (nextpat > pats + sizeof(pats)-20) {
       +                ERROR "tex hyphenation table overflow, tail end ignored" WARN;
       +                nextpat = onextpat;
       +        }
       +        num[lastpat+1] = 0;
       +        strcat(nextpat, num);
       +        nextpat += strlen(nextpat) + 1;
       +}
       +
       +static void fixup(void)        /* build indexes of where . a b c ... start */
       +{
       +        char *p, *lastc;
       +        int n;
       +
       +        for (lastc = pats, p = pats+1; p < nextpat; p++)
       +                if (*p == ' ') {
       +                        *lastc = p - lastc;
       +                        lastc = p;
       +                }
       +        *lastc = p - lastc;
       +        for (p = pats+1; p < nextpat; ) {
       +                n = trieindex(p[0], p[1]);
       +                if (trie[n] == 0)
       +                        trie[n] = p;
       +                p += p[-1];
       +        }
       +        /* printf("pats = %d\n", nextpat - pats); */
       +}
       +
       +static int trieindex(int d1, int d2)
       +{
       +        return 27 * (d1 == '.' ? 0 : d1 - 'a' + 1) + (d2 == '.' ? 0 : d2 - 'a' + 1);
       +}
 (DIR) diff --git a/src/cmd/troff/n9.c b/src/cmd/troff/n9.c
       t@@ -0,0 +1,488 @@
       +#include "tdef.h"
       +#include "ext.h"
       +#include "fns.h"
       +
       +/*
       + * troff9.c
       + * 
       + * misc functions
       + */
       +
       +Tchar setz(void)
       +{
       +        Tchar i;
       +
       +        if (!ismot(i = getch()))
       +                i |= ZBIT;
       +        return(i);
       +}
       +
       +void setline(void)
       +{
       +        Tchar *i;
       +        Tchar c;
       +        int length;
       +        int j, w, cnt, delim, rem, temp;
       +        Tchar linebuf[NC];
       +
       +        if (ismot(c = getch()))
       +                return;
       +        delim = cbits(c);
       +        vflag = 0;
       +        dfact = EM;
       +        length = quant(atoi0(), HOR);
       +        dfact = 1;
       +        if (!length) {
       +                eat(delim);
       +                return;
       +        }
       +s0:
       +        if ((j = cbits(c = getch())) == delim || j == '\n') {
       +                ch = c;
       +                c = RULE | chbits;
       +        } else if (cbits(c) == FILLER)
       +                goto s0;
       +        w = width(c);
       +        if (w <= 0) {
       +                ERROR "zero-width underline character ignored" WARN;
       +                c = RULE | chbits;
       +                w = width(c);
       +        }
       +        i = linebuf;
       +        if (length < 0) {
       +                *i++ = makem(length);
       +                length = -length;
       +        }
       +        if (!(cnt = length / w)) {
       +                *i++ = makem(-(temp = ((w - length) / 2)));
       +                *i++ = c;
       +                *i++ = makem(-(w - length - temp));
       +                goto s1;
       +        }
       +        if (rem = length % w) {
       +                if (cbits(c) == RULE || cbits(c) == UNDERLINE || cbits(c) == ROOTEN)
       +                        *i++ = c | ZBIT;
       +                *i++ = makem(rem);
       +        }
       +        if (cnt) {
       +                *i++ = RPT;
       +                *i++ = cnt;
       +                *i++ = c;
       +        }
       +s1:
       +        *i = 0;
       +        eat(delim);
       +        pushback(linebuf);
       +}
       +
       +
       +eat(int c)
       +{
       +        int i;
       +
       +        while ((i = cbits(getch())) != c && i != '\n')
       +                ;
       +        return(i);
       +}
       +
       +
       +void setov(void)
       +{
       +        int j, k;
       +        Tchar i, o[NOV+1];
       +        int delim, w[NOV+1];
       +
       +        if (ismot(i = getch()))
       +                return;
       +        delim = cbits(i);
       +        for (k = 0; k < NOV && (j = cbits(i = getch())) != delim && j != '\n'; k++) {
       +                o[k] = i;
       +                w[k] = width(i);
       +        }
       +        o[k] = w[k] = 0;
       +        if (o[0])
       +                for (j = 1; j; ) {
       +                        j = 0;
       +                        for (k = 1; o[k] ; k++) {
       +                                if (w[k-1] < w[k]) {
       +                                        j++;
       +                                        i = w[k];
       +                                        w[k] = w[k-1];
       +                                        w[k-1] = i;
       +                                        i = o[k];
       +                                        o[k] = o[k-1];
       +                                        o[k-1] = i;
       +                                }
       +                        }
       +                }
       +        else 
       +                return;
       +        *pbp++ = makem(w[0] / 2);
       +        for (k = 0; o[k]; k++)
       +                ;
       +        while (k>0) {
       +                k--;
       +                *pbp++ = makem(-((w[k] + w[k+1]) / 2));
       +                *pbp++ = o[k];
       +        }
       +}
       +
       +
       +void setbra(void)
       +{
       +        int k;
       +        Tchar i, *j, dwn;
       +        int cnt, delim;
       +        Tchar brabuf[NC];
       +
       +        if (ismot(i = getch()))
       +                return;
       +        delim = cbits(i);
       +        j = brabuf + 1;
       +        cnt = 0;
       +        if (NROFF)
       +                dwn = (2 * t.Halfline) | MOT | VMOT;
       +        else
       +                dwn = EM | MOT | VMOT;
       +        while ((k = cbits(i = getch())) != delim && k != '\n' && j <= brabuf + NC - 4) {
       +                *j++ = i | ZBIT;
       +                *j++ = dwn;
       +                cnt++;
       +        }
       +        if (--cnt < 0)
       +                return;
       +        else if (!cnt) {
       +                ch = *(j - 2);
       +                return;
       +        }
       +        *j = 0;
       +        if (NROFF)
       +                *--j = *brabuf = (cnt * t.Halfline) | MOT | NMOT | VMOT;
       +        else
       +                *--j = *brabuf = (cnt * EM) / 2 | MOT | NMOT | VMOT;
       +        *--j &= ~ZBIT;
       +        pushback(brabuf);
       +}
       +
       +
       +void setvline(void)
       +{
       +        int i;
       +        Tchar c, rem, ver, neg;
       +        int cnt, delim, v;
       +        Tchar vlbuf[NC];
       +        Tchar *vlp;
       +
       +        if (ismot(c = getch()))
       +                return;
       +        delim = cbits(c);
       +        dfact = lss;
       +        vflag++;
       +        i = quant(atoi0(), VERT);
       +        dfact = 1;
       +        if (!i) {
       +                eat(delim);
       +                vflag = 0;
       +                return;
       +        }
       +        if ((cbits(c = getch())) == delim) {
       +                c = BOXRULE | chbits;        /*default box rule*/
       +        } else 
       +                getch();
       +        c |= ZBIT;
       +        neg = 0;
       +        if (i < 0) {
       +                i = -i;
       +                neg = NMOT;
       +        }
       +        if (NROFF)
       +                v = 2 * t.Halfline;
       +        else {
       +                v = EM;
       +                if (v < VERT)                /* ATT EVK hack: Erik van Konijnenburg, */
       +                        v = VERT;        /* hvlpb!evkonij, ATT NSI Hilversum, Holland */
       +        }
       +
       +        cnt = i / v;
       +        rem = makem(i % v) | neg;
       +        ver = makem(v) | neg;
       +        vlp = vlbuf;
       +        if (!neg)
       +                *vlp++ = ver;
       +        if (absmot(rem) != 0) {
       +                *vlp++ = c;
       +                *vlp++ = rem;
       +        }
       +        while (vlp < vlbuf + NC - 3 && cnt--) {
       +                *vlp++ = c;
       +                *vlp++ = ver;
       +        }
       +        *(vlp - 2) &= ~ZBIT;
       +        if (!neg)
       +                vlp--;
       +        *vlp = 0;
       +        pushback(vlbuf);
       +        vflag = 0;
       +}
       +
       +#define        NPAIR        (NC/2-6)        /* max pairs in spline, etc. */
       +
       +void setdraw(void)        /* generate internal cookies for a drawing function */
       +{
       +        int i, j, k, dx[NPAIR], dy[NPAIR], delim, type;
       +        Tchar c, drawbuf[NC];
       +        int drawch = '.';        /* character to draw with */
       +
       +        /* input is \D'f dx dy dx dy ... c' (or at least it had better be) */
       +        /* this does drawing function f with character c and the */
       +        /* specified dx,dy pairs interpreted as appropriate */
       +        /* pairs are deltas from last point, except for radii */
       +
       +        /* l dx dy:        line from here by dx,dy */
       +        /* c x:                circle of diameter x, left side here */
       +        /* e x y:        ellipse of diameters x,y, left side here */
       +        /* a dx1 dy1 dx2 dy2:
       +                        ccw arc: ctr at dx1,dy1, then end at dx2,dy2 from there */
       +        /* ~ dx1 dy1 dx2 dy2...:
       +                        spline to dx1,dy1 to dx2,dy2 ... */
       +        /* b x c:
       +                        built-up character of type c, ht x */
       +        /* f dx dy ...:        f is any other char:  like spline */
       +
       +        if (ismot(c = getch()))
       +                return;
       +        delim = cbits(c);
       +        numerr.escarg = type = cbits(getch());
       +        if (type == '~')        /* head off the .tr ~ problem */
       +                type = 's';
       +        for (i = 0; i < NPAIR ; i++) {
       +                skip();
       +                vflag = 0;
       +                dfact = EM;
       +                dx[i] = quant(atoi0(), HOR);
       +                if (dx[i] > MAXMOT)
       +                        dx[i] = MAXMOT;
       +                else if (dx[i] < -MAXMOT)
       +                        dx[i] = -MAXMOT;
       +                skip();
       +                if (type == 'c') {
       +                        dy[i] = 0;
       +                        goto eat;
       +                }
       +                vflag = 1;
       +                dfact = lss;
       +                dy[i] = quant(atoi0(), VERT);
       +                if (dy[i] > MAXMOT)
       +                        dy[i] = MAXMOT;
       +                else if (dy[i] < -MAXMOT)
       +                        dy[i] = -MAXMOT;
       +eat:
       +                if (cbits(c = getch()) != ' ') {        /* must be the end */
       +                        if (cbits(c) != delim) {
       +                                drawch = cbits(c);
       +                                getch();
       +                        }
       +                        i++;
       +                        break;
       +                }
       +        }
       +        dfact = 1;
       +        vflag = 0;
       +        if (TROFF) {
       +                drawbuf[0] = DRAWFCN | chbits | ZBIT;
       +                drawbuf[1] = type | chbits | ZBIT;
       +                drawbuf[2] = drawch | chbits | ZBIT;
       +                for (k = 0, j = 3; k < i; k++) {
       +                        drawbuf[j++] = MOT | ((dx[k] >= 0) ? dx[k] : (NMOT | -dx[k]));
       +                        drawbuf[j++] = MOT | VMOT | ((dy[k] >= 0) ? dy[k] : (NMOT | -dy[k]));
       +                }
       +                if (type == DRAWELLIPSE) {
       +                        drawbuf[5] = drawbuf[4] | NMOT;        /* so the net vertical is zero */
       +                        j = 6;
       +                } else if (type == DRAWBUILD) {
       +                        drawbuf[4] = drawbuf[3] | NMOT;        /* net horizontal motion is zero */
       +                        drawbuf[2] &= ~ZBIT;                /* width taken from drawing char */
       +                        j = 5;
       +                }
       +                drawbuf[j++] = DRAWFCN | chbits | ZBIT;        /* marks end for ptout */
       +                drawbuf[j] = 0;
       +                pushback(drawbuf);
       +        }
       +}
       +
       +
       +void casefc(void)
       +{
       +        int i;
       +        Tchar j;
       +
       +        gchtab[fc] &= ~FCBIT;
       +        fc = IMP;
       +        padc = ' ';
       +        if (skip() || ismot(j = getch()) || (i = cbits(j)) == '\n')
       +                return;
       +        fc = i;
       +        gchtab[fc] |= FCBIT;
       +        if (skip() || ismot(ch) || (ch = cbits(ch)) == fc)
       +                return;
       +        padc = ch;
       +}
       +
       +
       +Tchar setfield(int x)
       +{
       +        Tchar ii, jj, *fp;
       +        int i, j;
       +        int length, ws, npad, temp, type;
       +        Tchar **pp, *padptr[NPP];
       +        Tchar fbuf[FBUFSZ];
       +        int savfc, savtc, savlc;
       +        Tchar rchar;
       +        int savepos;
       +        static Tchar wbuf[] = { WORDSP, 0};
       +
       +        if (x == tabch) 
       +                rchar = tabc | chbits;
       +        else if (x ==  ldrch) 
       +                rchar = dotc | chbits;
       +        temp = npad = ws = 0;
       +        savfc = fc;
       +        savtc = tabch;
       +        savlc = ldrch;
       +        tabch = ldrch = fc = IMP;
       +        savepos = numtabp[HP].val;
       +        gchtab[tabch] &= ~TABBIT;
       +        gchtab[ldrch] &= ~LDRBIT;
       +        gchtab[fc] &= ~FCBIT;
       +        gchtab[IMP] |= TABBIT|LDRBIT|FCBIT;
       +        for (j = 0; ; j++) {
       +                if ((tabtab[j] & TABMASK) == 0) {
       +                        if (x == savfc)
       +                                ERROR "zero field width." WARN;
       +                        jj = 0;
       +                        goto rtn;
       +                }
       +                if ((length = ((tabtab[j] & TABMASK) - numtabp[HP].val)) > 0 )
       +                        break;
       +        }
       +        type = tabtab[j] & ~TABMASK;
       +        fp = fbuf;
       +        pp = padptr;
       +        if (x == savfc) {
       +                while (1) {
       +                        j = cbits(ii = getch());
       +                        jj = width(ii);
       +                        widthp = jj;
       +                        numtabp[HP].val += jj;
       +                        if (j == padc) {
       +                                npad++;
       +                                *pp++ = fp;
       +                                if (pp > padptr + NPP - 1)
       +                                        break;
       +                                goto s1;
       +                        } else if (j == savfc) 
       +                                break;
       +                        else if (j == '\n') {
       +                                temp = j;
       +                                if (nlflg && ip == 0) {
       +                                        numtabp[CD].val--;
       +                                        nlflg = 0;
       +                                }
       +                                break;
       +                        }
       +                        ws += jj;
       +s1:
       +                        *fp++ = ii;
       +                        if (fp > fbuf + FBUFSZ - 3)
       +                                break;
       +                }
       +                if (ws)
       +                        *fp++ = WORDSP;
       +                if (!npad) {
       +                        npad++;
       +                        *pp++ = fp;
       +                        *fp++ = 0;
       +                }
       +                *fp++ = temp;
       +                *fp = 0;
       +                temp = i = (j = length - ws) / npad;
       +                i = (i / HOR) * HOR;
       +                if ((j -= i * npad) < 0)
       +                        j = -j;
       +                ii = makem(i);
       +                if (temp < 0)
       +                        ii |= NMOT;
       +                for (; npad > 0; npad--) {
       +                        *(*--pp) = ii;
       +                        if (j) {
       +                                j -= HOR;
       +                                (*(*pp)) += HOR;
       +                        }
       +                }
       +                pushback(fbuf);
       +                jj = 0;
       +        } else if (type == 0) {
       +                /*plain tab or leader*/
       +                if ((j = width(rchar)) > 0) {
       +                        int nchar = length / j;
       +                        while (nchar-->0 && pbp < &pbbuf[NC-3]) {
       +                                numtabp[HP].val += j;
       +                                widthp = j;
       +                                *pbp++ = rchar;
       +                        }
       +                        length %= j;
       +                }
       +                if (length)
       +                        jj = length | MOT;
       +                else 
       +                        jj = getch0();
       +                if (savepos > 0)
       +                        pushback(wbuf);
       +        } else {
       +                /*center tab*/
       +                /*right tab*/
       +                while ((j = cbits(ii = getch())) != savtc && j != '\n' && j != savlc) {
       +                        jj = width(ii);
       +                        ws += jj;
       +                        numtabp[HP].val += jj;
       +                        widthp = jj;
       +                        *fp++ = ii;
       +                        if (fp > fbuf + FBUFSZ - 3) 
       +                                break;
       +                }
       +                *fp++ = ii;
       +                *fp = 0;
       +                if (type == RTAB)
       +                        length -= ws;
       +                else 
       +                        length -= ws / 2; /*CTAB*/
       +                pushback(fbuf);
       +                if ((j = width(rchar)) != 0 && length > 0) {
       +                        int nchar = length / j;
       +                        while (nchar-- > 0 && pbp < &pbbuf[NC-3])
       +                                *pbp++ = rchar;
       +                        length %= j;
       +                }
       +                if (savepos > 0)
       +                        pushback(wbuf);
       +                length = (length / HOR) * HOR;
       +                jj = makem(length);
       +                if (nlflg) {
       +                        if (ip == 0)
       +                                numtabp[CD].val--;
       +                        nlflg = 0;
       +                }
       +        }
       +rtn:
       +        gchtab[fc] &= ~FCBIT;
       +        gchtab[tabch] &= ~TABBIT;
       +        gchtab[ldrch] &= ~LDRBIT;
       +        fc = savfc;
       +        tabch = savtc;
       +        ldrch = savlc;
       +        gchtab[fc] |= FCBIT;
       +        gchtab[tabch] = TABBIT;
       +        gchtab[ldrch] |= LDRBIT;
       +        numtabp[HP].val = savepos;
       +        return(jj);
       +}
 (DIR) diff --git a/src/cmd/troff/ni.c b/src/cmd/troff/ni.c
       t@@ -0,0 +1,390 @@
       +#include <stdio.h>
       +#include "tdef.h"
       +#include "fns.h"
       +#include "ext.h"
       +
       +char        termtab[NS];        /* term type added in ptinit() */
       +char        fontdir[NS];        /* added in casefp; not used by nroff */
       +char        devname[20];        /* default output device */
       +
       +Numtab numtab[NN] = {
       +        { PAIR('%', 0) },
       +        { PAIR('n', 'l') },
       +        { PAIR('y', 'r') },
       +        { PAIR('h', 'p') },
       +        { PAIR('c', 't') },
       +        { PAIR('d', 'n') },
       +        { PAIR('m', 'o') },
       +        { PAIR('d', 'y') },
       +        { PAIR('d', 'w') },
       +        { PAIR('l', 'n') },
       +        { PAIR('d', 'l') },
       +        { PAIR('s', 't') },
       +        { PAIR('s', 'b') },
       +        { PAIR('c', '.') },
       +        { PAIR('$', '$') },
       +};
       +
       +
       +int        alphabet        = 256;        /* latin-1 */
       +int        pto        = 10000;
       +int        pfrom        = 1;
       +int        print        = 1;
       +char        nextf[NS]        = TMACDIR;
       +char        mfiles[NMF][NS];
       +int        nmfi        = 0;
       +int        oldbits        = -1;
       +int        init        = 1;
       +int        fc        = IMP;        /* field character */
       +int        eschar        = '\\';
       +int        pl;
       +int        po;
       +FILE        *ptid;
       +
       +int        dfact        = 1;
       +int        dfactd        = 1;
       +int        res        = 1;
       +int        smnt        = 0;        /* beginning of special fonts */
       +int        ascii        = 0;        /* ascii normally off for troff, on for nroff;  -a turns on */
       +int        lg;
       +int        pnlist[NPN] = { -1 };
       +
       +
       +int        *pnp        = pnlist;
       +int        npn        = 1;
       +int        npnflg        =  1;
       +int        dpn        =  -1;
       +int        totout        =  1;
       +int        ulfont        =  ULFONT;
       +int        tabch        =  TAB;
       +int        ldrch        =  LEADER;
       +
       +
       +Contab contab[NM] = {
       +        C(PAIR('d', 's'), caseds),
       +        C(PAIR('a', 's'), caseas),
       +        C(PAIR('s', 'p'), casesp),
       +        C(PAIR('f', 't'), caseft),
       +        C(PAIR('p', 's'), caseps),
       +        C(PAIR('v', 's'), casevs),
       +        C(PAIR('n', 'r'), casenr),
       +        C(PAIR('i', 'f'), caseif),
       +        C(PAIR('i', 'e'), caseie),
       +        C(PAIR('e', 'l'), caseel),
       +        C(PAIR('p', 'o'), casepo),
       +        C(PAIR('t', 'l'), casetl),
       +        C(PAIR('t', 'm'), casetm),
       +        C(PAIR('f', 'm'), casefm),
       +        C(PAIR('b', 'p'), casebp),
       +        C(PAIR('c', 'h'), casech),
       +        C(PAIR('p', 'n'), casepn),
       +        C(PAIR('b', 'r'), tbreak),
       +        C(PAIR('t', 'i'), caseti),
       +        C(PAIR('n', 'e'), casene),
       +        C(PAIR('n', 'f'), casenf),
       +        C(PAIR('c', 'e'), casece),
       +        C(PAIR('f', 'i'), casefi),
       +        C(PAIR('i', 'n'), casein),
       +        C(PAIR('l', 'l'), casell),
       +        C(PAIR('n', 's'), casens),
       +        C(PAIR('m', 'k'), casemk),
       +        C(PAIR('r', 't'), casert),
       +        C(PAIR('a', 'm'), caseam),
       +        C(PAIR('d', 'e'), casede),
       +        C(PAIR('d', 'i'), casedi),
       +        C(PAIR('d', 'a'), caseda),
       +        C(PAIR('w', 'h'), casewh),
       +        C(PAIR('d', 't'), casedt),
       +        C(PAIR('i', 't'), caseit),
       +        C(PAIR('r', 'm'), caserm),
       +        C(PAIR('r', 'r'), caserr),
       +        C(PAIR('r', 'n'), casern),
       +        C(PAIR('a', 'd'), casead),
       +        C(PAIR('r', 's'), casers),
       +        C(PAIR('n', 'a'), casena),
       +        C(PAIR('p', 'l'), casepl),
       +        C(PAIR('t', 'a'), caseta),
       +        C(PAIR('t', 'r'), casetr),
       +        C(PAIR('u', 'l'), caseul),
       +        C(PAIR('c', 'u'), casecu),
       +        C(PAIR('l', 't'), caselt),
       +        C(PAIR('n', 'x'), casenx),
       +        C(PAIR('s', 'o'), caseso),
       +        C(PAIR('i', 'g'), caseig),
       +        C(PAIR('t', 'c'), casetc),
       +        C(PAIR('f', 'c'), casefc),
       +        C(PAIR('e', 'c'), caseec),
       +        C(PAIR('e', 'o'), caseeo),
       +        C(PAIR('l', 'c'), caselc),
       +        C(PAIR('e', 'v'), caseev),
       +        C(PAIR('r', 'd'), caserd),
       +        C(PAIR('a', 'b'), caseab),
       +        C(PAIR('f', 'l'), casefl),
       +        C(PAIR('e', 'x'), caseex),
       +        C(PAIR('s', 's'), casess),
       +        C(PAIR('f', 'p'), casefp),
       +        C(PAIR('c', 's'), casecs),
       +        C(PAIR('b', 'd'), casebd),
       +        C(PAIR('l', 'g'), caselg),
       +        C(PAIR('h', 'c'), casehc),
       +        C(PAIR('h', 'y'), casehy),
       +        C(PAIR('n', 'h'), casenh),
       +        C(PAIR('n', 'm'), casenm),
       +        C(PAIR('n', 'n'), casenn),
       +        C(PAIR('s', 'v'), casesv),
       +        C(PAIR('o', 's'), caseos),
       +        C(PAIR('l', 's'), casels),
       +        C(PAIR('c', 'c'), casecc),
       +        C(PAIR('c', '2'), casec2),
       +        C(PAIR('e', 'm'), caseem),
       +        C(PAIR('a', 'f'), caseaf),
       +        C(PAIR('h', 'a'), caseha),
       +        C(PAIR('h', 'w'), casehw),
       +        C(PAIR('m', 'c'), casemc),
       +        C(PAIR('p', 'm'), casepm),
       +        C(PAIR('p', 'i'), casepi),
       +        C(PAIR('u', 'f'), caseuf),
       +        C(PAIR('p', 'c'), casepc),
       +        C(PAIR('h', 't'), caseht),
       +        C(PAIR('c', 'f'), casecf),
       +        C(PAIR('s', 'y'), casesy),
       +        C(PAIR('l', 'f'), caself),
       +        C(PAIR('p', 't'), casept),
       +        C(PAIR('g', 'd'), casegd),
       +};
       +
       +
       +Tbuf _oline;
       +
       +/*
       + * troff environment block
       + */
       +
       +Env env[NEV] = { {        /* this sets up env[0] */
       +/* int        ics         */        0,        /* insertion character space, set by .mc */
       +/* int        sps         */        0,
       +/* int        spacesz         */        0,
       +/* int        lss         */        0,
       +/* int        lss1         */        0,
       +/* int        ll         */        0,
       +/* int        ll1         */        0,
       +/* int        lt         */        0,
       +/* int        lt1         */        0,
       +/* Tchar ic         */        0,        /* insertion character (= margin character) */
       +/* int        icf         */        0,        /* insertion character flag */
       +/* Tchar chbits         */        0,        /* size+font bits for current character */
       +/* Tchar spbits         */        0,
       +/* Tchar nmbits         */        0,        /* size+font bits for number from .nm */
       +/* int        apts         */        PS,        /* actual point size -- as requested by user */
       +/* int        apts1         */        PS,        /* need not match an existent size */
       +/* int        pts         */        PS,        /* hence, this is the size that really exists */
       +/* int        pts1         */        PS,
       +/* int        font         */        FT,
       +/* int        font1         */        FT,
       +/* int        ls         */        1,
       +/* int        ls1         */        1,
       +/* int        ad         */        1,
       +/* int        nms         */        1,        /* .nm multiplier */
       +/* int        ndf         */        1,        /* .nm separator */
       +/* int        nmwid         */        3,        /* max width of .nm numbers */
       +/* int        fi         */        1,
       +/* int        cc         */        '.',
       +/* int        c2         */        '\'',
       +/* int        ohc         */        OHC,
       +/* int        tdelim         */        IMP,
       +/* int        hyf         */        1,
       +/* int        hyoff         */        0,
       +/* int        hyphalg  */        HYPHALG,
       +/* int        un1         */        -1,
       +/* int        tabc         */        0,
       +/* int        dotc         */        '.',
       +/* int        adsp         */        0,        /* add this much space to each padding point */
       +/* int        adrem         */        0,        /* excess space to add until it runs out */
       +/* int        lastl         */        0,        /* last text on current output line */
       +/* int        nel         */        0,        /* how much space left on current output line */
       +/* int        admod         */        0,        /* adjust mode */
       +/* Tchar *wordp         */        0,
       +/* int        spflg         */        0,        /* probably to indicate space after punctuation needed */
       +/* Tchar *linep         */        0,
       +/* Tchar *wdend         */        0,
       +/* Tchar *wdstart */        0,
       +/* int        wne         */        0,
       +/* int        ne         */        0,        /* how much space taken on current output line */
       +/* int        nc         */        0,        /* #characters (incl blank) on output line */
       +/* int        nb         */        0,
       +/* int        lnmod         */        0,        /* line number mode, set by .nm */
       +/* int        nwd         */        0,        /* number of words on current output line */
       +/* int        nn         */        0,        /* from .nn command */
       +/* int        ni         */        0,        /* indent of .nm numbers, probably */
       +/* int        ul         */        0,
       +/* int        cu         */        0,
       +/* int        ce         */        0,
       +/* int        in         */        0,        /* indent and previous value */
       +/* int        in1         */        0,
       +/* int        un         */        0,        /* unindent of left margin in some way */
       +/* int        wch         */        0,
       +/* int        pendt         */        0,
       +/* Tchar *pendw         */        (Tchar *)0,
       +/* int        pendnf         */        0,
       +/* int        spread         */        0,
       +/* int        it         */        0,        /* input trap count */
       +/* int        itmac         */        0,
       +} };
       +
       +Env        *envp        = env;        /* start off in env 0 */
       +
       +Numerr        numerr;
       +
       +Stack        *frame, *stk, *ejl;
       +Stack        *nxf;
       +
       +int        pipeflg;
       +int        hflg;        /* used in nroff only */
       +int        eqflg;        /* used in nroff only */
       +
       +int        xpts;
       +int        ppts;
       +int        pfont;
       +int        mpts;
       +int        mfont;
       +int        cs;
       +int        ccs;
       +int        bd;
       +
       +int        stdi;
       +int        quiet;
       +int        stop;
       +char        ibuf[IBUFSZ];
       +char        xbuf[IBUFSZ];
       +char        *ibufp;
       +char        *xbufp;
       +char        *eibuf;
       +char        *xeibuf;
       +Tchar        pbbuf[NC];                /* pushback buffer for arguments, \n, etc. */
       +Tchar        *pbp = pbbuf;                /* next free slot in pbbuf */
       +Tchar        *lastpbp = pbbuf;        /* pbp in previous stack frame */
       +int        nx;
       +int        mflg;
       +Tchar        ch = 0;
       +int        ibf;
       +int        ifi;
       +int        iflg;
       +int        rargc;
       +char        **argp;
       +Ushort        trtab[NTRTAB];
       +int        lgf;
       +int        copyf;
       +Offset        ip;
       +int        nlflg;
       +int        donef;
       +int        nflush;
       +int        nfo;
       +int        padc;
       +int        raw;
       +int        flss;
       +int        nonumb;
       +int        trap;
       +int        tflg;
       +int        ejf;
       +int        dilev;
       +Offset        offset;
       +int        em;
       +int        ds;
       +Offset        woff;
       +int        app;
       +int        ndone;
       +int        lead;
       +int        ralss;
       +Offset        nextb;
       +Tchar        nrbits;
       +int        nform;
       +int        oldmn;
       +int        newmn;
       +int        macerr;
       +Offset        apptr;
       +int        diflg;
       +int        evi;
       +int        vflag;
       +int        noscale;
       +int        po1;
       +int        nlist[NTRAP];
       +int        mlist[NTRAP];
       +int        evlist[EVLSZ];
       +int        ev;
       +int        tty;
       +int        sfont        = FT;        /* appears to be "standard" font; used by .ul */
       +int        sv;
       +int        esc;
       +int        widthp;
       +int        xfont;
       +int        setwdf;
       +int        over;
       +int        nhyp;
       +Tchar        **hyp;
       +Tchar        *olinep;
       +int        dotT;
       +char        *unlkp;
       +Wcache        widcache[NWIDCACHE];
       +Diver        d[NDI];
       +Diver        *dip;
       +
       +int        c_hyphen;
       +int        c_emdash;
       +int        c_rule;
       +int        c_minus;
       +int        c_fi;
       +int        c_fl;
       +int        c_ff;
       +int        c_ffi;
       +int        c_ffl;
       +int        c_acute;
       +int        c_grave;
       +int        c_under;
       +int        c_rooten;
       +int        c_boxrule;
       +int        c_lefthand;
       +int        c_dagger;
       +int        c_isalnum;
       +
       +Spnames        spnames[] =
       +{
       +        &c_hyphen,        "hy",
       +        &c_emdash,        "em",
       +        &c_rule,        "ru",
       +        &c_minus,        "\\-",
       +        &c_fi,                "fi",
       +        &c_fl,                "fl",
       +        &c_ff,                "ff",
       +        &c_ffi,                "Fi",
       +        &c_ffl,                "Fl",
       +        &c_acute,        "aa",
       +        &c_grave,        "ga",
       +        &c_under,        "ul",
       +        &c_rooten,        "rn",
       +        &c_boxrule,        "br",
       +        &c_lefthand,        "lh",
       +        &c_dagger,        "dg",        /* not in nroff?? */
       +        &c_isalnum,        "__",
       +        0, 0
       +};
       +
       +
       +Tchar        (*hmot)(void);
       +Tchar        (*makem)(int i);
       +Tchar        (*setabs)(void);
       +Tchar        (*setch)(int c);
       +Tchar        (*sethl)(int k);
       +Tchar        (*setht)(void);
       +Tchar        (*setslant)(void);
       +Tchar        (*vmot)(void);
       +Tchar        (*xlss)(void);
       +int        (*findft)(int i);
       +int        (*width)(Tchar j);
       +void        (*mchbits)(void);
       +void        (*ptlead)(void);
       +void        (*ptout)(Tchar i);
       +void        (*ptpause)(void);
       +void        (*setfont)(int a);
       +void        (*setps)(void);
       +void        (*setwd)(void);
       +
 (DIR) diff --git a/src/cmd/troff/suftab.c b/src/cmd/troff/suftab.c
       t@@ -0,0 +1,612 @@
       +/*
       + * Suffix table
       + */
       +
       +typedef unsigned char Uchar;
       +
       +static        Uchar sufa[] = {
       +        02,0200+'t',        /* -TA */
       +        02,0200+'s',        /* -SA */
       +        03,0200+'t','r',        /* -TRA */
       +        03,0200+'d','r',        /* -DRA */
       +        03,0200+'b','r',        /* -BRA */
       +        02,0200+'p',        /* -PA */
       +        02,0200+'n',        /* -NA */
       +        02,0200+'m',        /* -MA */
       +        03,0200+'p','l',        /* -PLA */
       +        02,0200+'l',        /* -LA */
       +        02,0200+'k',        /* -KA */
       +        03,0200+'t','h',        /* -THA */
       +        03,0200+'s','h',        /* -SHA */
       +        02,0200+'g',        /* -GA */
       +        02,0200+'d',        /* -DA */
       +        02,0200+'c',        /* -CA */
       +        02,0200+'b',        /* -BA */
       +        00
       +};
       +
       +static        Uchar sufc[] = {
       +        04,'e','t',0200+'i',        /* ET-IC */
       +        07,'a','l',0200+'i','s',0200+'t','i',        /* AL-IS-TIC */
       +        04,'s',0200+'t','i',        /* S-TIC */
       +        04,'p',0200+'t','i',        /* P-TIC */
       +        05,0200+'l','y','t',0200+'i',        /* -LYT-IC */
       +        04,'o','t',0200+'i',        /* OT-IC */
       +        05,'a','n',0200+'t','i',        /* AN-TIC */
       +        04,'n',0200+'t','i',        /* N-TIC */
       +        04,'c',0200+'t','i',        /* C-TIC */
       +        04,'a','t',0200+'i',        /* AT-IC */
       +        04,'h',0200+'n','i',        /* H-NIC */
       +        03,'n',0200+'i',        /* N-IC */
       +        03,'m',0200+'i',        /* M-IC */
       +        04,'l',0200+'l','i',        /* L-LIC */
       +        04,'b',0200+'l','i',        /* B-LIC */
       +        04,0200+'c','l','i',        /* -CLIC */
       +        03,'l',0200+'i',        /* L-IC */
       +        03,'h',0200+'i',        /* H-IC */
       +        03,'f',0200+'i',        /* F-IC */
       +        03,'d',0200+'i',        /* D-IC */
       +        03,0200+'b','i',        /* -BIC */
       +        03,'a',0200+'i',        /* A-IC */
       +        03,0200+'m','a',        /* -MAC */
       +        03,'i',0200+'a',        /* I-AC */
       +        00
       +};
       +
       +static        Uchar sufd[] = {
       +        04,0200+'w','o','r',        /* -WORD */
       +        04,0200+'l','o','r',        /* -LORD */
       +        04,0200+'f','o','r',        /* -FORD */
       +        04,0200+'y','a','r',        /* -YARD */
       +        04,0200+'w','a','r',        /* -WARD */
       +        05,0200+'g','u','a','r',        /* -GUARD */
       +        04,0200+'t','a','r',        /* -TARD */
       +        05,0200+'b','o','a','r',        /* -BOARD */
       +        04,0200+'n','a','r',        /* -NARD */
       +        05,0200+'l','i','a','r',        /* -LIARD */
       +        04,0200+'i','a','r',        /* -IARD */
       +        04,0200+'g','a','r',        /* -GARD */
       +        04,0200+'b','a','r',        /* -BARD */
       +        03,0200+'r','o',        /* -ROD */
       +        04,0200+'w','o','o',        /* -WOOD */
       +        04,0200+'h','o','o',        /* -HOOD */
       +        04,0200+'m','o','n',        /* -MOND */
       +        04,0200+'t','e','n',        /* -TEND */
       +        05,0200+'s','t','a','n',        /* -STAND */
       +        04,0200+'l','a','n',        /* -LAND */
       +        04,0200+'h','a','n',        /* -HAND */
       +        04,0200+'h','o','l',        /* -HOLD */
       +        04,0200+'f','o','l',        /* -FOLD */
       +        05,0200+'f','i','e','l',        /* -FIELD */
       +        03,0200+'v','i',        /* -VID */
       +        03,0200+'c','i',        /* -CID */
       +        04,0200+'s','a','i',        /* -SAID */
       +        04,0200+'m','a','i',        /* -MAID */
       +        04,'t',0200+'t','e',        /* T-TED */
       +        03,'t',0200+'e',        /* T-ED */
       +        04,0200+'d','r','e',        /* -DRED */
       +        04,0200+'c','r','e',        /* -CRED */
       +        04,0200+'b','r','e',        /* -BRED */
       +        05,'v',0200+'e','l','e',        /* V-ELED */
       +        0100+04,'a','l',0200+'e',        /* AL/ED */
       +        0140+03,0200+'e','e',        /* /EED */
       +        040+05,'e','d',0200+'d','e',        /* ED-DED */
       +        04,'d',0200+'d','e',        /* D-DED */
       +        040+04,'e','d',0200+'e',        /* ED-ED */
       +        03,'d',0200+'e',        /* D-ED */
       +        05,0200+'d','u','c','e',        /* -DUCED */
       +        0300+02,'e',        /* E/D */
       +        05,0200+'s','t','e','a',        /* -STEAD */
       +        05,0200+'a','h','e','a',        /* -AHEAD */
       +        04,0200+'h','e','a',        /* -HEAD */
       +        00
       +};
       +
       +static        Uchar sufe[] = {
       +        05,'a','r',0200+'i','z',        /* AR-IZE */
       +        05,'a','n',0200+'i','z',        /* AN-IZE */
       +        05,'a','l',0200+'i','z',        /* AL-IZE */
       +        06,0200+'a','r','d',0200+'i','z',        /* -ARD-IZE */
       +        05,0200+'s','e','l','v',        /* -SELVE */
       +        05,0200+'k','n','i','v',        /* -KNIVE */
       +        05,0200+'l','i','e','v',        /* -LIEVE */
       +        0100+03,0200+'q','u',        /* /QUE */
       +        07,'o','n',0200+'t','i','n',0200+'u',        /* ON-TIN-UE */
       +        03,0200+'n','u',        /* -NUE */
       +        03,0200+'d','u',        /* -DUE */
       +        0300+02,'u',        /* U/E */
       +        0300+05,'q','u','a','t',        /*  QUAT/E */
       +        04,'u',0200+'a','t',        /* U-ATE */
       +        05,0200+'s','t','a','t',        /* -STATE */
       +        04,0200+'t','a','t',        /* -TATE */
       +        06,0200+'t','o','r',0200+'a','t',        /* -TOR-ATE */
       +        05,'e','n',0200+'a','t',        /* EN-ATE */
       +        04,0200+'m','a','t',        /* -MATE */
       +        05,0200+'h','o','u','s',        /* -HOUSE */
       +        05,0200+'c','l','o','s',        /* -CLOSE */
       +        04,'i',0200+'o','s',        /* I-OSE */
       +        04,0200+'w','i','s',        /* -WISE */
       +        05,'a','s',0200+'u','r',        /* AS-URE */
       +        040+04,0200+'s','u','r',        /* -SURE */
       +        06,0200+'f','i','g',0200+'u','r',        /* -FIG-URE */
       +        040+03,0200+'t','r',        /* -TRE */
       +        05,0200+'s','t','o','r',        /* -STORE */
       +        04,0200+'f','o','r',        /* -FORE */
       +        05,0200+'w','h','e','r',        /* -WHERE */
       +        06,0200+'s','p','h','e','r',        /* -SPHERE */
       +        03,0200+'d','r',        /* -DRE */
       +        03,0200+'c','r',        /* -CRE */
       +        03,0200+'b','r',        /* -BRE */
       +        05,0200+'s','c','o','p',        /* -SCOPE */
       +        04,'y',0200+'o','n',        /* Y-ONE */
       +        05,0200+'s','t','o','n',        /* -STONE */
       +        05,0200+'p','h','o','n',        /* -PHONE */
       +        04,0200+'g','o','n',        /* -GONE */
       +        04,'e',0200+'o','n',        /* E-ONE */
       +        040+04,0200+'e','n','n',        /* -ENNE */
       +        040+05,'a',0200+'r','i','n',        /* A-RINE */
       +        05,0200+'c','l','i','n',        /* -CLINE */
       +        04,0200+'l','i','n',        /* -LINE */
       +        007,00200+'r','o','u',00200+'t','i','n',        /*-ROU-TINE */
       +        04,0200+'s','o','m',        /* -SOME */
       +        04,0200+'c','o','m',        /* -COME */
       +        04,0200+'t','i','m',        /* -TIME */
       +        03,0200+'z','l',        /* -ZLE */
       +        03,0200+'t','l',        /* -TLE */
       +        03,0200+'s','l',        /* -SLE */
       +        03,0200+'p','l',        /* -PLE */
       +        05,0200+'v','i','l','l',        /* -VILLE */
       +        04,'c','k',0200+'l',        /* CK-LE */
       +        03,0200+'k','l',        /* -KLE */
       +        03,0200+'g','l',        /* -GLE */
       +        03,0200+'f','l',        /* -FLE */
       +        03,0200+'d','l',        /* -DLE */
       +        03,0200+'c','l',        /* -CLE */
       +        05,0200+'p','a',0200+'b','l',        /* -PA-BLE */
       +        05,'f','a',0200+'b','l',        /* FA-BLE */
       +        05,0200+'c','a',0200+'b','l',        /* -CA-BLE */
       +        06,0200+'s','t','a','b','l',        /* -STABLE */
       +        04,0200+'a','b','l',        /* -ABLE */
       +        03,0200+'b','l',        /* -BLE */
       +        04,0200+'d','a','l',        /* -DALE */
       +        04,0200+'m','a','l',        /* -MALE */
       +        04,0200+'s','a','l',        /* -SALE */
       +        04,0200+'l','i','k',        /* -LIKE */
       +        0340+05,'g',0200+'u','a','g',        /* -G/UAGE */
       +        05,0200+'r','i','a','g',        /* -RIAGE */
       +        05,'e','r',0200+'a','g',        /* ER-AGE */
       +        04,'m',0200+'a','g',        /* M-AGE */
       +        04,'k',0200+'a','g',        /* K-AGE */
       +        04,'d',0200+'a','g',        /* D-AGE */
       +        04,0200+'w','i','f',        /* -WIFE */
       +        05,0200+'k','n','i','f',        /* -KNIFE */
       +        03,0200+'s','e',        /* -SEE */
       +        04,0200+'f','r','e',        /* -FREE */
       +        0340+02,'e',        /* EE */
       +        04,0200+'w','i','d',        /* -WIDE */
       +        04,0200+'t','i','d',        /* -TIDE */
       +        04,0200+'s','i','d',        /* -SIDE */
       +        06,0200+'q','u','e','n','c',        /* -QUENCE */
       +        07,0200+'f','l','u',0200+'e','n','c',        /* -FLU-ENCE */
       +        040+06,'e','s',0200+'e','n','c',        /* ES-ENCE */
       +        06,'e','r',0200+'e','n','c',        /* ER-ENCE */
       +        05,'i',0200+'e','n','c',        /* I-ENCE */
       +        040+05,0200+'s','a','n','c',        /* -SANCE */
       +        06,'e','r',0200+'a','n','c',        /* ER-ANCE */
       +        06,'a','r',0200+'a','n','c',        /* AR-ANCE */
       +        05,0200+'n','a','n','c',        /* -NANCE */
       +        07,0200+'b','a','l',0200+'a','n','c',        /* -BAL-ANCE */
       +        05,'i',0200+'a','n','c',        /* I-ANCE */
       +        07,0200+'j','u','s',0200+'t','i','c',        /* -JUS-TICE */
       +        05,0200+'s','t','i','c',        /* -STICE */
       +        06,0200+'n','o','v',0200+'i','c',        /* NOV-ICE */
       +        04,0200+'v','i','c',        /* -VICE */
       +        05,0200+'p','i','e','c',        /* -PIECE */
       +        05,0200+'p','l','a','c',        /* -PLACE */
       +        0340+01,        /* /E */
       +        00
       +};
       +
       +static        Uchar suff[] = {
       +        03,0200+'o','f',        /* -OFF */
       +        05,0200+'p','r','o','o',        /* -PROOF */
       +        04,0200+'s','e','l',        /* -SELF */
       +        03,0200+'r','i',        /* -RIF */
       +        040+04,0200+'l','i','e',        /* -LIEF */
       +        00
       +};
       +
       +static        Uchar sufg[] = {
       +        03,0200+'l','o',        /* -LOG */
       +        04,0200+'l','o','n',        /* -LONG */
       +        05,'t',0200+'t','i','n',        /* T-TING */
       +        06,0200+'s','t','r','i','n',        /*  -STRING */
       +        05,'r',0200+'r','i','n',        /* R-RING */
       +        05,'p',0200+'p','i','n',        /* P-PING */
       +        05,'n',0200+'n','i','n',        /* N-NING */
       +        05,'m',0200+'m','i','n',        /* M-MING */
       +        05,'l',0200+'l','i','n',        /*  L-LING */
       +        05,0200+'z','l','i','n',        /* -ZLING */
       +        05,0200+'t','l','i','n',        /* -TLING */
       +        040+05,'s',0200+'l','i','n',        /* S-LING */
       +        05,'r',0200+'l','i','n',        /* R-LING */
       +        05,0200+'p','l','i','n',        /* -PLING */
       +        06,'n',0200+'k','l','i','n',        /* N-KLING */
       +        05,'k',0200+'l','i','n',        /* K-LING */
       +        05,0200+'g','l','i','n',        /* -GLING */
       +        05,0200+'f','l','i','n',        /* -FLING */
       +        05,0200+'d','l','i','n',        /* -DLING */
       +        05,0200+'c','l','i','n',        /* -CLING */
       +        05,0200+'b','l','i','n',        /* -BLING */
       +        06,'y',0200+'t','h','i','n',        /* Y-THING */
       +        07,'e','e','t','h',0200+'i','n',        /* EETH-ING */
       +        06,'e',0200+'t','h','i','n',        /* E-THING */
       +        05,'g',0200+'g','i','n',        /* G-GING */
       +        05,'d',0200+'d','i','n',        /* D-DING */
       +        05,'b',0200+'b','i','n',        /* B-BING */
       +        03,0200+'i','n',        /* -ING */
       +        00
       +};
       +
       +static        Uchar sufh[] = {
       +        05,0200+'m','o','u','t',        /* -MOUTH */
       +        05,0200+'w','o','r','t',        /* -WORTH */
       +        04,0200+'w','i','t',        /* -WITH */
       +        05,'t',0200+'t','i','s',        /* T-TISH */
       +        05,'e',0200+'t','i','s',        /* E-TISH */
       +        05,'p',0200+'p','i','s',        /* P-PISH */
       +        05,'r',0200+'n','i','s',        /* R-NISH */
       +        05,'n',0200+'n','i','s',        /* N-NISH */
       +        05,0200+'p','l','i','s',        /* -PLISH */
       +        05,0200+'g','u','i','s',        /*  -GUISH */
       +        05,0200+'g','l','i','s',        /*  -GLISH */
       +        05,'b',0200+'l','i','s',        /*  B-LISH */
       +        05,'g',0200+'g','i','s',        /* G-GISH */
       +        05,'d',0200+'d','i','s',        /* D-DISH */
       +        03,0200+'i','s',        /* -ISH */
       +        05,0200+'g','r','a','p',        /* -GRAPH */
       +        07,0200+'b','o','r',0200+'o','u','g',        /* -BOR-OUGH */
       +        05,0200+'b','u','r','g',        /* -BURGH */
       +        04,0200+'v','i','c',        /* -VICH */
       +        03,0200+'n','a',        /* -NAH */
       +        03,0200+'l','a',        /* -LAH */
       +        04,0200+'m','i',0200+'a',        /* -MI-AH */
       +        00
       +};
       +
       +static        Uchar sufi[] = {
       +        03,0200+'t','r',        /* -TRI */
       +        03,0200+'c','h',        /* -CHI */
       +        0200+03,'i','f',        /* IF-I */
       +        0200+03,'e','d',        /* ED-I */
       +        05,0200+'a','s','c','i',        /* -ASCII */
       +        04,0200+'s','e','m',        /* -SEMI */
       +        00
       +};
       +
       +static        Uchar sufk[] = {
       +        04,0200+'w','o','r',        /* -WORK */
       +        04,0200+'m','a','r',        /* -MARK */
       +        04,0200+'b','o','o',        /* -BOOK */
       +        04,0200+'w','a','l',        /* -WALK */
       +        05,0200+'c','r','a','c',        /* -CRACK */
       +        04,0200+'b','a','c',        /* -BACK */
       +        00
       +};
       +
       +static        Uchar sufl[] = {
       +        03,0200+'f','u',        /* -FUL */
       +        05,'s',0200+'w','e','l',        /* S-WELL */
       +        04,0200+'t','e','l',        /* -TELL */
       +        05,0200+'s','h','e','l',        /* -SHELL */
       +        05,0200+'s','t','a','l',        /* -STALL */
       +        04,'s',0200+'t','a',        /* S-TAL */
       +        04,0200+'b','a','l',        /* -BALL */
       +        04,0200+'c','a','l',        /* -CALL */
       +        03,'v',0200+'e',        /* V-EL */
       +        03,'u',0200+'e',        /* U-EL */
       +        03,'k',0200+'e',        /* K-EL */
       +        04,'t','h',0200+'e',        /* TH-EL */
       +        05,'t','c','h',0200+'e',        /* TCH-EL */
       +        03,'a',0200+'e',        /* A-EL */
       +        0140+04,0200+'q','u','a',        /* /QUAL */
       +        040+03,'u',0200+'a',        /* U-AL */
       +        03,0200+'t','a',        /* -TAL */
       +        04,'u','r',0200+'a',        /* UR-AL */
       +        040+05,'g',0200+'o',0200+'n','a',        /* G-O-NAL */
       +        04,'o','n',0200+'a',        /* ON-AL */
       +        03,0200+'n','a',        /* -NAL */
       +        04,0200+'t','i','a',        /* -TIAL */
       +        04,0200+'s','i','a',        /* -SIAL */
       +        040+05,0200+'t','r','i',0200+'a',        /* -TRI-AL */
       +        04,'r','i',0200+'a',        /* RI-AL */
       +        04,0200+'n','i',0200+'a',        /* -NI-AL */
       +        04,0200+'d','i',0200+'a',        /* -DI-AL */
       +        04,0200+'c','i','a',        /* -CIAL */
       +        03,0200+'g','a',        /* -GAL */
       +        04,0200+'m','e','a',        /* -MEAL */
       +/*        040+04,0200+'r','e',0200+'a',        /* -RE-AL */
       +        040+04,0200+'r','e','a',        /* -REAL */
       +        06,'c',0200+'t','i',0200+'c','a',        /* C-TI-CAL */
       +        05,0200+'s','i',0200+'c','a',        /* -SI-CAL */
       +        04,0200+'i',0200+'c','a',        /* -I-CAL */
       +        03,0200+'c','a',        /* -CAL */
       +        03,0200+'b','a',        /* -BAL */
       +        06,0200+'n','o',0200+'m','i',0200+'a',        /* -NO-MI-AL */
       +        00
       +};
       +
       +static        Uchar sufm[] = {
       +        03,0200+'n','u',        /* -NUM */
       +        05,'o',0200+'r','i',0200+'u',        /* O-RI-UM */
       +        040+03,'i',0200+'u',        /* I-UM */
       +        040+03,'e',0200+'u',        /* E-UM */
       +        05,'i','v',0200+'i','s',        /* IV-ISM */
       +        04,0200+'t','i','s',        /* -TISM */
       +        05,'i',0200+'m','i','s',        /* I-MISM */
       +        05,'a','l',0200+'i','s',        /* AL-ISM */
       +        040+04,'e',0200+'i','s',        /* E-ISM */
       +        040+04,'a',0200+'i','s',        /* A-ISM */
       +        04,0200+'r','o','o',        /* -ROOM */
       +        03,0200+'d','o',        /* -DOM */
       +        03,0200+'h','a',        /* -HAM */
       +        06,0200+'a',0200+'r','i','t','h',        /* -A-RITHM */
       +        05,0200+'r','i','t','h',        /* -RITHM */
       +        00
       +};
       +
       +static        Uchar sufn[] = {
       +        05,0200+'k','n','o','w', /* -KNOWN */
       +        04,0200+'t','o','w',        /* -TOWN */
       +        04,0200+'d','o','w',        /* -DOWN */
       +        04,0200+'t','u','r',        /* -TURN */
       +        05,0200+'s','p','o','o',        /* -SPOON */
       +        04,0200+'n','o','o',        /* -NOON */
       +        04,0200+'m','o','o',        /* -MOON */
       +        011,'a','l',0200+'i',0200+'z','a',0200+'t','i','o',        /* AL-I-ZA-TION */
       +        07,0200+'i',0200+'z','a',0200+'t','i','o',        /* -I-ZA-TION */
       +        07,'l',0200+'i',0200+'a',0200+'t','i','o',        /* L-I-A-TION */
       +        04,0200+'t','i','o',        /* -TION */
       +        040+05,'s',0200+'s','i','o',        /* S-SION */
       +        04,0200+'s','i','o',        /* -SION */
       +        04,'n',0200+'i','o',        /* N-ION */
       +        04,0200+'g','i','o',        /* -GION */
       +        04,0200+'c','i','o',        /* -CION */
       +        03,0200+'c','o',        /* -CON */
       +        05,0200+'c','o','l','o',        /* -COLON */
       +        03,0200+'t','o',        /* -TON */
       +        04,'i','s',0200+'o',                /* IS-ON */
       +        03,0200+'s','o',        /* -SON */
       +        03,0200+'r','i',        /* -RIN */
       +        03,0200+'p','i',        /* -PIN */
       +        03,0200+'n','i',        /* -NIN */
       +        03,0200+'m','i',        /* -MIN */
       +        03,0200+'l','i',        /* -LIN */
       +        03,0200+'k','i',        /* -KIN */
       +        05,0200+'s','t','e','i',        /* -STEIN */
       +        04,0200+'t','a','i',        /* -TAIN */
       +        05,'g','h','t',0200+'e',        /* GHT-EN */
       +        05,0200+'w','o','m',0200+'e',        /* -WOM-EN */
       +        03,0200+'m','e',        /* -MEN */
       +        04,'o',0200+'k','e',        /* O-KEN */
       +        03,'k',0200+'e',        /* K-EN */
       +        04,0200+'t','e','e',        /* -TEEN */
       +        04,0200+'s','e','e',        /* -SEEN */
       +        040+03,0200+'s','a',        /* -SAN */
       +        05,0200+'w','o','m',0200+'a',        /* -WOM-AN */
       +        03,0200+'m','a',        /* -MAN */
       +        04,0200+'t','i','a',        /* -TIAN */
       +        04,0200+'s','i','a',        /* -SIAN */
       +        040+04,'e',0200+'i','a',        /* E-IAN */
       +        04,0200+'c','i','a',        /* -CIAN */
       +        0300+03,'i','a',        /* IA/N */
       +        05,0200+'c','l','e','a',        /* -CLEAN */
       +        04,0200+'m','e','a',        /* -MEAN */
       +        040+03,'e',0200+'a',        /* E-AN */
       +        00
       +};
       +
       +static        Uchar sufo[] = {
       +        05,0200+'m','a','c',0200+'r',        /* -MAC-RO */
       +        00
       +};
       +
       +static        Uchar sufp[] = {
       +        05,0200+'g','r','o','u',        /* -GROUP */
       +        02,0200+'u',        /* -UP */
       +        04,0200+'s','h','i',        /* -SHIP */
       +        04,0200+'k','e','e',        /* -KEEP */
       +        00
       +};
       +
       +static        Uchar sufr[] = {
       +        04,0200+'z','a','r',        /* -ZARR */
       +        0300+02,'r',        /* R/R */
       +        03,0200+'t','o',        /* -TOR */
       +        040+03,0200+'s','o',        /* -SOR */
       +        040+04,0200+'r','i',0200+'o',        /* -RI-OR */
       +        04,'i','z',0200+'e',        /* IZ-ER */
       +        05,0200+'c','o','v',0200+'e',        /* -COV-ER */
       +        04,0200+'o','v','e',        /* -OVER */
       +        04,0200+'e','v',0200+'e',        /* -EV-ER */
       +        8,0200+'c','o','m',0200+'p','u','t',0200+'e',        /* -COM-PUT-ER */
       +        040+05,'u','s',0200+'t','e',        /* US-TER */
       +        05,'o','s','t',0200+'e',        /* OST-ER */
       +        040+05,0200+'a','c',0200+'t','e',        /* -AC-TER */
       +        06,0200+'w','r','i','t',0200+'e',        /* -WRIT-ER */
       +        040+05,'i','s',0200+'t','e',        /* IS-TER */
       +        040+05,'e','s',0200+'t','e',        /* ES-TER */
       +        040+05,'a','s',0200+'t','e',        /* AS-TER */
       +        04,0200+'s','t','e',        /* -STER */
       +        05,'a','r',0200+'t','e',        /* AR-TER */
       +        04,'r','t',0200+'e',        /* RT-ER */
       +        040+05,'m',0200+'e',0200+'t','e',        /* M-E-TER */
       +        05,0200+'w','a',0200+'t','e',        /* -WA-TER */
       +        03,'r',0200+'e',        /* R-ER */
       +        04,'o','p',0200+'e',        /* OP-ER */
       +        05,0200+'p','a',0200+'p','e',        /* -PA-PER */
       +        04,'w','n',0200+'e',        /* WN-ER */
       +        040+04,'s',0200+'n','e',        /* S-NER */
       +        04,'o','n',0200+'e',        /* ON-ER */
       +        04,'r','m',0200+'e',        /* RM-ER */
       +        03,0200+'m','e',        /* -MER */
       +        04,'l','l',0200+'e',        /* LL-ER */
       +        05,'d',0200+'d','l','e',        /* D-DLER */
       +        04,0200+'b','l','e',        /* -BLER */
       +        03,'k',0200+'e',        /* K-ER */
       +        05,'n',0200+'t','h','e',        /* N-THER */
       +        06,0200+'f','a',0200+'t','h','e',        /* -FA-THER */
       +        06,'e','i',0200+'t','h','e',        /* EI-THER */
       +        04,'t','h',0200+'e',        /* TH-ER */
       +        04,'s','h',0200+'e',        /* SH-ER */
       +        04,0200+'p','h','e',        /* -PHER */
       +        04,'c','h',0200+'e',        /* CH-ER */
       +        04,'d','g',0200+'e',        /* DG-ER */
       +        04,'r','d',0200+'e',        /* RD-ER */
       +        06,'o','u','n','d',0200+'e',        /* OUND-ER */
       +        04,'l','d',0200+'e',        /* LD-ER */
       +        04,'i','d',0200+'e',        /* ID-ER */
       +        05,0200+'d','u','c',0200+'e',        /* -DUC-ER */
       +        04,'n','c',0200+'e',        /* NC-ER */
       +        0100+02, 0200+'e',        /*  /ER */
       +        03,0200+'s','a',        /* -SAR */
       +        040+06,'a','c',0200+'u',0200+'l','a',        /* AC-U-LAR */
       +        040+06,'e','c',0200+'u',0200+'l','a',        /* EC-U-LAR */
       +        040+06,'i','c',0200+'u',0200+'l','a',        /* IC-U-LAR */
       +        040+06,'e','g',0200+'u',0200+'l','a',        /* EG-U-LAR */
       +        00
       +};
       +
       +static        Uchar sufs[] = {
       +        040+04,'u',0200+'o','u',        /* U-OUS */
       +        05,0200+'t','i','o','u',        /* -TIOUS */
       +        05,0200+'g','i','o','u',        /* -GIOUS */
       +        05,0200+'c','i','o','u',        /* -CIOUS */
       +        040+04,'i',0200+'o','u',        /* I-OUS */
       +        05,0200+'g','e','o','u',        /* -GEOUS */
       +        05,0200+'c','e','o','u',        /* -CEOUS */
       +        04,'e',0200+'o','u',        /* E-OUS */
       +        0140+02,0200+'u',        /* /US */
       +        04,0200+'n','e','s',        /* -NESS */
       +        04,0200+'l','e','s',        /* -LESS */
       +        0140+02,0200+'s',        /* /SS */
       +        040+05,'p',0200+'o',0200+'l','i',        /* P-O-LIS */
       +        0140+02,0200+'i',        /* /IS */
       +        0100+03,0200+'x','e',        /* X/ES */
       +        0100+03,0200+'s','e',        /* S/ES */
       +        0100+04,'s','h',0200+'e',        /* SH/ES */
       +        0100+04,'c','h',0200+'e',        /* CH/ES */
       +        0300+01,        /* /S */
       +        00
       +};
       +
       +static        Uchar suft[] = {
       +        05,0200+'l','i','m',0200+'i',        /* -LIM-IT */
       +        06,'i','o','n',0200+'i','s',        /* ION-IST */
       +        05,'i','n',0200+'i','s',        /* IN-IST */
       +        05,'a','l',0200+'i','s',        /* AL-IST */
       +        06,'l',0200+'o',0200+'g','i','s',        /* L-O-GIST */
       +        05,'h','t',0200+'e','s',        /* HT-EST */
       +        04,'i',0200+'e','s',        /* I-EST */
       +        05,'g',0200+'g','e','s',        /* G-GEST */
       +        04,'g',0200+'e','s',        /* G-EST */
       +        05,'d',0200+'d','e','s',        /* D-DEST */
       +        04,'d',0200+'e','s',        /* D-EST */
       +        04,0200+'c','a','s',        /* -CAST */
       +        05,0200+'h','e','a','r',        /* -HEART */
       +        04,0200+'f','o','o',        /* -FOOT */
       +        03,'i',0200+'o',        /* I-OT */
       +        05,0200+'f','r','o','n',        /* -FRONT */
       +        05,0200+'p','r','i','n',        /* -PRINT */
       +        04,0200+'m','e','n',        /* -MENT */
       +        05,0200+'c','i','e','n',        /* -CIENT */
       +        04,'i',0200+'a','n',        /* I-ANT */
       +        06,0200+'w','r','i','g','h',        /* -WRIGHT */
       +        06,0200+'b','r','i','g','h',        /* -BRIGHT */
       +        06,0200+'f','l','i','g','h',        /* -FLIGHT */
       +        06,0200+'w','e','i','g','h',        /* -WEIGHT */
       +        05,0200+'s','h','i','f',        /* -SHIFT */
       +        05,0200+'c','r','a','f',        /* -CRAFT */
       +        040+04,'d','g',0200+'e',        /* DG-ET */
       +        04,0200+'g','o','a',        /* -GOAT */
       +        04,0200+'c','o','a',        /* -COAT */
       +        04,0200+'b','o','a',        /* -BOAT */
       +        04,0200+'w','h','a',        /* -WHAT */
       +        04,0200+'c','u','i',        /* -CUIT */
       +        00
       +};
       +
       +static        Uchar sufy[] = {
       +        040+04,'e','s',0200+'t',        /* ES-TY */
       +        040+05,'q','u','i',0200+'t',        /* QUI-TY */
       +        04,0200+'t','i',0200+'t',        /* -TI-TY */
       +        040+05,'o','s',0200+'i',0200+'t',        /* OS-I-TY */
       +        04,0200+'s','i',0200+'t',        /* -SI-TY */
       +        05,'i','n',0200+'i',0200+'t',        /* IN-I-TY */
       +        04,'n','i',0200+'t',        /* NI-TY */
       +        040+010,'f','a',0200+'b','i','l',0200+'i',0200+'t',        /* FA-BIL-I-TY */
       +        010,0200+'c','a',0200+'b','i','l',0200+'i',0200+'t',        /* -CA-BIL-I-TY */
       +        010,0200+'p','a',0200+'b','i','l',0200+'i',0200+'t',        /* -PA-BIL-I-TY */
       +        06,0200+'b','i','l',0200+'i',0200+'t',        /* -BIL-I-TY */
       +        03,'i',0200+'t',        /* I-TY */
       +        04,0200+'b','u','r',        /* -BUR-Y */
       +        04,0200+'t','o',0200+'r',        /* -TO-RY */
       +        05,0200+'q','u','a','r',        /* -QUAR-Y */
       +        040+04,'u',0200+'a','r',        /* U-ARY */
       +        07,0200+'m','e','n',0200+'t','a',0200+'r',        /* -MEN-TA-RY */
       +        06,'i','o','n',0200+'a','r',        /* ION-ARY */
       +        04,'i',0200+'a','r',        /* I-ARY */
       +        04,'n',0200+'o',0200+'m',        /* N-O-MY */
       +        03,0200+'p','l',        /* -PLY */
       +        04,'g',0200+'g','l',        /* G-GLY */
       +        05,0200+'p','a',0200+'b','l',        /* -PA-BLY */
       +        05,'f','a',0200+'b','l',        /* FA-BLY */
       +        05,0200+'c','a',0200+'b','l',        /* -CA-BLY */
       +        04,0200+'a','b','l',        /* -ABLY */
       +        03,0200+'b','l',        /* -BLY */
       +        02,0200+'l',        /* -LY */
       +        03,0200+'s','k',        /* -SKY */
       +        040+06,'g',0200+'r','a',0200+'p','h',        /* G-RA-PHY */
       +        04,'l',0200+'o',0200+'g',        /* L-O-GY */
       +        02,0200+'f',        /* -FY */
       +        03,0200+'n','e',        /* -NEY */
       +        03,0200+'l','e',        /* -LEY */
       +        04,'c','k',0200+'e',        /* CK-EY */
       +        03,0200+'k','e',        /* -KEY */
       +        04,0200+'b','o','d',        /* -BODY */
       +        05,0200+'s','t','u','d',        /* -STUDY */
       +        0340+04,'e','e','d',        /* EEDY */
       +        02,0200+'b',        /* -BY */
       +        03,0200+'w','a',        /* -WAY */
       +        03,0200+'d','a',        /* -DAY */
       +        00
       +};
       +
       +Uchar        *suftab[] = {
       +        sufa,
       +        0,
       +        sufc,
       +        sufd,
       +        sufe,
       +        suff,
       +        sufg,
       +        sufh,
       +        sufi,
       +        0,
       +        sufk,
       +        sufl,
       +        sufm,
       +        sufn,
       +        sufo,
       +        sufp,
       +        0,
       +        sufr,
       +        sufs,
       +        suft,
       +        0,
       +        0,
       +        0,
       +        0,
       +        sufy,
       +        0,
       +};
 (DIR) diff --git a/src/cmd/troff/t10.c b/src/cmd/troff/t10.c
       t@@ -0,0 +1,512 @@
       +#include "tdef.h"
       +#include "fns.h"
       +#include "ext.h"
       +
       +/*
       + * troff10.c
       + * 
       + * typesetter interface
       + */
       +
       +int        vpos         = 0;        /* absolute vertical position on page */
       +int        hpos         = 0;        /* ditto horizontal */
       +
       +extern Font fonts[MAXFONTS+1];
       +
       +int        Inch;
       +int        Hor;
       +int        Vert;
       +int        Unitwidth;
       +int        nfonts;
       +
       +
       +
       +void t_ptinit(void)
       +{
       +        int i;
       +        char buf[100], *p;
       +
       +        hmot = t_hmot;
       +        makem = t_makem;
       +        setabs = t_setabs;
       +        setch = t_setch;
       +        sethl = t_sethl;
       +        setht = t_setht;
       +        setslant = t_setslant;
       +        vmot = t_vmot;
       +        xlss = t_xlss;
       +        findft = t_findft;
       +        width = t_width;
       +        mchbits = t_mchbits;
       +        ptlead = t_ptlead;
       +        ptout = t_ptout;
       +        ptpause = t_ptpause;
       +        setfont = t_setfont;
       +        setps = t_setps;
       +        setwd = t_setwd;
       +
       +        /* open table for device, */
       +        /* read in resolution, size info, font info, etc., set params */
       +        if ((p = getenv("TYPESETTER")) != 0)
       +                strcpy(devname, p);
       +        if (termtab[0] == 0)
       +                strcpy(termtab, DWBfontdir);
       +        if (fontdir[0] == 0)
       +                strcpy(fontdir, DWBfontdir);
       +        if (devname[0] == 0)
       +                strcpy(devname, TDEVNAME);
       +        hyf = 1;
       +        lg = 1;
       +
       +        sprintf(buf, "/dev%s/DESC", devname);
       +        strcat(termtab, buf);
       +        if (getdesc(termtab) < 0) {
       +                ERROR "can't open DESC file %s", termtab WARN;
       +                done3(1);
       +        }
       +        if (!ascii) {
       +                OUT "x T %s\n", devname PUT;
       +                OUT "x res %d %d %d\n", Inch, Hor, Vert PUT;
       +                OUT "x init\n" PUT;
       +        }
       +        for (i = 1; i <= nfonts; i++)
       +                setfp(i, fontlab[i], (char *) 0, 0);
       +        sps = EM/3;        /* space size */
       +        ics = EM;        /* insertion character space */
       +        for (i = 0; i < (NTAB - 1) && DTAB * (i + 1) < TABMASK; i++)
       +                tabtab[i] = DTAB * (i + 1);
       +        tabtab[NTAB] = 0;
       +        pl = 11 * INCH;                        /* paper length */
       +        po = PO;                /* page offset */
       +        spacesz = SS;
       +        lss = lss1 = VS;
       +        ll = ll1 = lt = lt1 = LL;
       +        t_specnames();        /* install names like "hyphen", etc. */
       +}
       +
       +void t_specnames(void)
       +{
       +        int        i;
       +
       +        for (i = 0; spnames[i].n; i++)
       +                *spnames[i].n = chadd(spnames[i].v, Troffchar, Install);
       +}
       +
       +void t_ptout(Tchar i)
       +{
       +        int dv;
       +        Tchar *k;
       +        int temp, a, b;
       +        int diff;
       +
       +        if (cbits(i) != '\n') {
       +                if (olinep >= oline + olnsize) {
       +                        diff = olinep - oline;
       +                        olnsize += OLNSIZE;
       +                        if ((oline = (Tchar *)realloc((char *)oline, olnsize * sizeof(Tchar))) != NULL) {
       +                                if (diff && olinep)
       +                                        olinep = oline + diff;
       +                        } else {
       +                                ERROR "Output line overflow." WARN;
       +                                done(2);
       +                        }
       +                }
       +                *olinep++ = i;
       +                return;
       +        }
       +        if (olinep == oline) {
       +                lead += lss;
       +                return;
       +        }
       +
       +        hpos = po;        /* ??? */
       +        esc = 0;        /* ??? */
       +        ptesc();        /* the problem is to get back to the left end of the line */
       +        dv = 0;
       +        for (k = oline; k < olinep; k++) {
       +                if (ismot(*k) && isvmot(*k)) {
       +                        temp = absmot(*k);
       +                        if (isnmot(*k))
       +                                temp = -temp;
       +                        dv += temp;
       +                }
       +        }
       +        if (dv) {
       +                vflag++;
       +                *olinep++ = makem(-dv);
       +                vflag = 0;
       +        }
       +
       +        b = dip->blss + lss;
       +        lead += dip->blss + lss;
       +        dip->blss = 0;
       +        for (k = oline; k < olinep; )
       +                k += ptout0(k);        /* now passing a pointer! */
       +        olinep = oline;
       +        lead += dip->alss;
       +        a = dip->alss;
       +        dip->alss = 0;
       +        /*
       +        OUT "x xxx end of line: hpos=%d, vpos=%d\n", hpos, vpos PUT;
       +*/
       +        OUT "n%d %d\n", b, a PUT;        /* be nice to chuck */
       +}
       +
       +int ptout0(Tchar *pi)
       +{
       +        int j, k, w;
       +        int z, dx, dy, dx2, dy2, n;
       +        Tchar i;
       +        int outsize;        /* size of object being printed */
       +
       +        outsize = 1;        /* default */
       +        i = *pi;
       +        k = cbits(i);
       +        if (ismot(i)) {
       +                j = absmot(i);
       +                if (isnmot(i))
       +                        j = -j;
       +                if (isvmot(i))
       +                        lead += j;
       +                else 
       +                        esc += j;
       +                return(outsize);
       +        }
       +        if (k == CHARHT) {
       +                xpts = fbits(i);        /* sneaky, font bits as size bits */
       +                if (xpts != mpts)
       +                        ptps();
       +                OUT "x H %d\n", sbits(i) PUT;
       +                return(outsize);
       +        }
       +        if (k == SLANT) {
       +                OUT "x S %d\n", sfbits(i)-180 PUT;
       +                return(outsize);
       +        }
       +        if (k == WORDSP) {
       +                oput('w');
       +                return(outsize);
       +        }
       +        if (sfbits(i) == oldbits) {
       +                xfont = pfont;
       +                xpts = ppts;
       +        } else 
       +                xbits(i, 2);
       +        if (k == XON) {
       +                extern int xon;
       +                ptflush();        /* guarantee that everything is out */
       +                if (esc)
       +                        ptesc();
       +                if (xfont != mfont)
       +                        ptfont();
       +                if (xpts != mpts)
       +                        ptps();
       +                if (lead)
       +                        ptlead();
       +                OUT "x X " PUT;
       +                xon++;
       +                for (j = 1; cbits(pi[j]) != XOFF; j++)
       +                        outascii(pi[j]);
       +                oput('\n');
       +                xon--;
       +                return j+1;
       +        }
       +        if (k < 040 && k != DRAWFCN)
       +                return(outsize);
       +        j = z = 0;
       +        if (k != DRAWFCN) {
       +                if (widcache[k].fontpts == (xfont<<8) + xpts  && !setwdf) {
       +                        w = widcache[k].width;
       +                        bd = 0;
       +                        cs = 0;
       +                } else
       +                        w = getcw(k);
       +                if (cs) {
       +                        if (bd)
       +                                w += (bd - 1) * HOR;
       +                        j = (cs - w) / 2;
       +                        w = cs - j;
       +                        if (bd)
       +                                w -= (bd - 1) * HOR;
       +                }
       +                if (iszbit(i)) {
       +                        if (cs)
       +                                w = -j; 
       +                        else 
       +                                w = 0;
       +                        z = 1;
       +                }
       +        }
       +        esc += j;
       +        if (xfont != mfont)
       +                ptfont();
       +        if (xpts != mpts)
       +                ptps();
       +        if (lead)
       +                ptlead();
       +        /* put out the real character here */
       +        if (k == DRAWFCN) {
       +                if (esc)
       +                        ptesc();
       +                w = 0;
       +                dx = absmot(pi[3]);
       +                if (isnmot(pi[3]))
       +                        dx = -dx;
       +                dy = absmot(pi[4]);
       +                if (isnmot(pi[4]))
       +                        dy = -dy;
       +                switch (cbits(pi[1])) {
       +                case DRAWCIRCLE:        /* circle */
       +                        OUT "D%c %d\n", DRAWCIRCLE, dx PUT;        /* dx is diameter */
       +                        hpos += dx;
       +                        break;
       +                case DRAWELLIPSE:
       +                        OUT "D%c %d %d\n", DRAWELLIPSE, dx, dy PUT;
       +                        hpos += dx;
       +                        break;
       +                case DRAWBUILD:
       +                        k = cbits(pi[2]);
       +                        OUT "D%c %d ", DRAWBUILD, dx PUT;
       +                        if (k < ALPHABET)
       +                                OUT "%c\n", k PUT;
       +                        else
       +                                ptchname(k);
       +                        hpos += dx;
       +                        break;
       +                case DRAWLINE:        /* line */
       +                        k = cbits(pi[2]);
       +                        OUT "D%c %d %d ", DRAWLINE, dx, dy PUT;
       +                        if (k < ALPHABET)
       +                                OUT "%c\n", k PUT;
       +                        else
       +                                ptchname(k);
       +                        hpos += dx;
       +                        vpos += dy;
       +                        break;
       +                case DRAWARC:        /* arc */
       +                        dx2 = absmot(pi[5]);
       +                        if (isnmot(pi[5]))
       +                                dx2 = -dx2;
       +                        dy2 = absmot(pi[6]);
       +                        if (isnmot(pi[6]))
       +                                dy2 = -dy2;
       +                        OUT "D%c %d %d %d %d\n", DRAWARC,
       +                                dx, dy, dx2, dy2 PUT;
       +                        hpos += dx + dx2;
       +                        vpos += dy + dy2;
       +                        break;
       +
       +                case 's':        /* using 's' internally to avoid .tr ~ */
       +                        pi[1] = '~';
       +                case DRAWSPLINE:        /* spline */
       +                default:        /* something else; copy it like spline */
       +                        OUT "D%c %d %d", cbits(pi[1]), dx, dy PUT;
       +                        hpos += dx;
       +                        vpos += dy;
       +                        if (cbits(pi[3]) == DRAWFCN || cbits(pi[4]) == DRAWFCN) {
       +                                /* it was somehow defective */
       +                                OUT "\n" PUT;
       +                                break;
       +                        }
       +                        for (n = 5; cbits(pi[n]) != DRAWFCN; n += 2) {
       +                                dx = absmot(pi[n]);
       +                                if (isnmot(pi[n]))
       +                                        dx = -dx;
       +                                dy = absmot(pi[n+1]);
       +                                if (isnmot(pi[n+1]))
       +                                        dy = -dy;
       +                                OUT " %d %d", dx, dy PUT;
       +                                hpos += dx;
       +                                vpos += dy;
       +                        }
       +                        OUT "\n" PUT;
       +                        break;
       +                }
       +                for (n = 3; cbits(pi[n]) != DRAWFCN; n++)
       +                        ;
       +                outsize = n + 1;
       +        } else if (k < ALPHABET) {
       +                /* try to go faster and compress output */
       +                /* by printing nnc for small positive motion followed by c */
       +                /* kludgery; have to make sure set all the vars too */
       +                if (esc > 0 && esc < 100) {
       +                        oput(esc / 10 + '0');
       +                        oput(esc % 10 + '0');
       +                        oput(k);
       +                        hpos += esc;
       +                        esc = 0;
       +                } else {
       +                        if (esc)
       +                                ptesc();
       +                        oput('c');
       +                        oput(k);
       +                        oput('\n');
       +                }
       +        } else {
       +                if (esc)
       +                        ptesc();
       +                ptchname(k);
       +        }
       +        if (bd) {
       +                bd -= HOR;
       +                if (esc += bd)
       +                        ptesc();
       +                if (k < ALPHABET)
       +                        OUT "c%c\n", k PUT;
       +                else
       +                        ptchname(k);
       +                if (z)
       +                        esc -= bd;
       +        }
       +        esc += w;
       +        return(outsize);
       +}
       +
       +void ptchname(int k)
       +{
       +        char *chn = chname(k);
       +
       +        switch (chn[0]) {
       +        case MBchar:
       +                OUT "c%s\n", chn+1 PUT;        /* \n not needed? */
       +                break;
       +        case Number:
       +                OUT "N%s\n", chn+1 PUT;
       +                break;
       +        case Troffchar:
       +                OUT "C%s\n", chn+1 PUT;
       +                break;
       +        default:
       +                ERROR "illegal char type %s", chn WARN;
       +                break;
       +        }
       +}
       +
       +void ptflush(void)        /* get us to a clean output state */
       +{
       +        if (TROFF) {
       +                /* ptesc(); but always H, no h */
       +                hpos += esc;
       +                OUT "\nH%d\n", hpos PUT;
       +                esc = 0;
       +                ptps();
       +                ptfont();
       +                ptlead();
       +        }
       +}
       +
       +void ptps(void)
       +{
       +        int i, j, k;
       +
       +        i = xpts;
       +        for (j = 0; i > (k = pstab[j]); j++)
       +                if (!k) {
       +                        k = pstab[--j];
       +                        break;
       +                }
       +        if (!ascii)
       +                OUT "s%d\n", k PUT;        /* really should put out string rep of size */
       +        mpts = i;
       +}
       +
       +void ptfont(void)
       +{
       +        mfont = xfont;
       +        if (ascii)
       +                return;
       +        if (xfont > nfonts) {
       +                ptfpcmd(0, fonts[xfont].longname, 0);        /* Put the desired font in the
       +                                         * fontcache of the filter */
       +                OUT "f0\n" PUT;        /* make sure that it gets noticed */
       +        } else
       +                OUT "f%d\n", xfont PUT;
       +}
       +
       +void ptfpcmd(int f, char *s, char *longname)
       +{
       +        if (f > nfonts)                /* a bit risky? */
       +                f = 0;
       +        if (longname) {
       +                OUT "x font %d %s %s\n", f, s, longname PUT;
       +        } else {
       +                OUT "x font %d %s\n", f, s PUT;
       +        }
       +/*        OUT "f%d\n", xfont PUT;        /* need this for buggy version of adobe transcript */
       +                                /* which apparently believes that x font means */
       +                                /* to set the font, not just the position. */
       +}
       +
       +void t_ptlead(void)
       +{
       +        vpos += lead;
       +        if (!ascii)
       +                OUT "V%d\n", vpos PUT;
       +        lead = 0;
       +}
       +
       +void ptesc(void)
       +{
       +        hpos += esc;
       +        if (!ascii)
       +                if (esc > 0) {
       +                        oput('h');
       +                        if (esc>=10 && esc<100) {
       +                                oput(esc/10 + '0');
       +                                oput(esc%10 + '0');
       +                        } else
       +                                OUT "%d", esc PUT;
       +                } else
       +                        OUT "H%d\n", hpos PUT;
       +        esc = 0;
       +}
       +
       +void ptpage(int n)        /* called at end of each output page, we hope */
       +{
       +        int i;
       +
       +        if (NROFF)
       +                return;
       +        ptlead();
       +        vpos = 0;
       +        if (ascii)
       +                return;
       +        OUT "p%d\n", n PUT;        /* new page */
       +        for (i = 0; i <= nfonts; i++)
       +                if (fontlab[i]) {
       +                        if (fonts[i].truename)
       +                                OUT "x font %d %s %s\n", i, fonts[i].longname, fonts[i].truename PUT;
       +                        else
       +                                OUT "x font %d %s\n", i, fonts[i].longname PUT;
       +                }
       +        ptps();
       +        ptfont();
       +}
       +
       +void pttrailer(void)
       +{
       +        if (TROFF)
       +                OUT "x trailer\n" PUT;
       +}
       +
       +void ptstop(void)
       +{
       +        if (TROFF)
       +                OUT "x stop\n" PUT;
       +}
       +
       +void t_ptpause(void)
       +{
       +        if (ascii)
       +                return;
       +        ptlead();
       +        vpos = 0;
       +        pttrailer();
       +        ptlead();
       +        OUT "x pause\n" PUT;
       +        flusho();
       +        mpts = mfont = 0;
       +        ptesc();
       +        esc = po;
       +        hpos = vpos = 0;        /* probably in wrong place */
       +}
 (DIR) diff --git a/src/cmd/troff/t11.c b/src/cmd/troff/t11.c
       t@@ -0,0 +1,255 @@
       +#include "tdef.h"
       +#include "fns.h"
       +#include "ext.h"
       +
       +#define        MAXCH NCHARS                /* maximum number of global char names */
       +char        *chnames[MAXCH];        /* chnames[n-ALPHABET] -> name of char n */
       +int        nchnames;                /* number of Cxy names currently seen */
       +
       +#define        MAXPS        100                /* max number of point sizes */
       +int        pstab[MAXPS];                /* point sizes */
       +int        nsizes;                        /* number in DESC */
       +
       +Font        fonts[MAXFONTS+1];        /* font info + ptr to width info */
       +
       +
       +#define        skipline(f)        while (getc(f) != '\n')
       +
       +#define        eq(s1, s2)        (strcmp(s1, s2) == 0)
       +
       +getdesc(char *name)
       +{
       +        FILE *fin;
       +        char cmd[100], s[100];
       +        int i, v;
       +
       +        if ((fin = fopen(unsharp(name), "r")) == NULL)
       +                return -1;
       +        while (fscanf(fin, "%s", cmd) != EOF) {
       +                if (strcmp(cmd, "res") == 0) {
       +                        fscanf(fin, "%d", &Inch);
       +                } else if (strcmp(cmd, "hor") == 0) {
       +                        fscanf(fin, "%d", &Hor);
       +                } else if (strcmp(cmd, "vert") == 0) {
       +                        fscanf(fin, "%d", &Vert);
       +                } else if (strcmp(cmd, "unitwidth") == 0) {
       +                        fscanf(fin, "%d", &Unitwidth);
       +                } else if (strcmp(cmd, "sizes") == 0) {
       +                        nsizes = 0;
       +                        while (fscanf(fin, "%d", &v) != EOF && v != 0 && nsizes < MAXPS)
       +                                pstab[nsizes++] = v;
       +                } else if (strcmp(cmd, "fonts") == 0) {
       +                        fscanf(fin, "%d", &nfonts);
       +                        for (i = 1; i <= nfonts; i++) {
       +                                fscanf(fin, "%s", s);
       +                                fontlab[i] = PAIR(s[0], s[1]);
       +                        }
       +                } else if (strcmp(cmd, "charset") == 0) {        /* add any names */
       +                        while (fscanf(fin, "%s", s) != EOF)
       +                                chadd(s, Troffchar, Install);
       +                        break;
       +                }
       +                /* else 
       +                        just skip anything else */
       +                skipline(fin);
       +        }
       +        fclose(fin);
       +        return 1;
       +}
       +
       +static int checkfont(char *name)
       +{                /* in case it's not really a font description file */
       +                /* really paranoid, but consider \f. */
       +        FILE *fp;
       +        char buf[300], buf2[300];
       +        int i, status = -1;
       +
       +        if ((fp = fopen(unsharp(name), "r")) == NULL)
       +                return -1;
       +        for (i = 1; i <= 10; i++) {
       +                if (fgets(buf, sizeof buf, fp) == NULL)
       +                        break;
       +                sscanf(buf, "%s", buf2);
       +                if (buf2[0] == '#') {
       +                        i--;
       +                        continue;
       +                }
       +                if (eq(buf2, "name") || eq(buf2, "fontname") ||
       +                    eq(buf2, "special") || eq(buf2, "charset")) {
       +                        status = 1;
       +                        break;
       +                }
       +        }
       +        fclose(fp);
       +        return status;
       +        
       +}
       +
       +getfont(char *name, int pos)        /* create width tab for font */
       +{
       +        FILE *fin;
       +        Font *ftemp = &fonts[pos];
       +        Chwid chtemp[MAXCH];
       +        static Chwid chinit;
       +        int i, nw, n, wid, kern, code, type;
       +        char buf[100], ch[100], s1[100], s2[100], s3[100], cmd[300];
       +
       +        /* fprintf(stderr, "read font %s onto %d\n", name, pos); */
       +        if (checkfont(name) == -1)
       +                return -1;
       +        if ((fin = fopen(unsharp(name), "r")) == NULL)
       +                return -1;
       +        for (i = 0; i < ALPHABET; i++)
       +                chtemp[i] = chinit;        /* zero out to begin with */
       +        ftemp->specfont = ftemp->ligfont = 0;
       +        ftemp->defaultwidth = ftemp->spacewidth = Inch * Unitwidth / 72 / 3; /* should be rounded */
       +        while (fscanf(fin, "%s", cmd) != EOF) {
       +                if (strcmp(cmd, "name") == 0)
       +                        fscanf(fin, "%s", ftemp->longname);
       +                else if (strcmp(cmd, "special") == 0)
       +                        ftemp->specfont = 1;
       +                else if (strcmp(cmd, "ligatures") == 0) {
       +                        ftemp->ligfont = getlig(fin);
       +                } else if (strcmp(cmd, "spacewidth") == 0) {
       +                        fscanf(fin, "%d", &ftemp->spacewidth);
       +                } else if (strcmp(cmd, "defaultwidth") == 0) {
       +                        fscanf(fin, "%d", &ftemp->defaultwidth);
       +                } else if (strcmp(cmd, "charset") == 0) {
       +                        wchar_t wc;
       +                        skipline(fin);
       +                        nw = ALPHABET;
       +                        while (fgets(buf, sizeof buf, fin) != NULL) {
       +                                sscanf(buf, "%s %s %s %s", ch, s1, s2, s3);
       +                                if (s1[0] != '"') {        /* genuine new character */
       +                                        sscanf(s1, "%d", &wid);
       +                                        sscanf(s2, "%d", &kern);
       +                                        code = strtol(s3, 0, 0);        /* dec/oct/hex */
       +                                }
       +                                /* otherwise it's a synonym for prev character, */
       +                                /* so leave previous values intact */
       +
       +
       +                                /* decide what kind of alphabet it might come from here */
       +
       +
       +                                if (strlen(ch) == 1) {        /* it's ascii */
       +                                        n = ch[0];        /* origin includes non-graphics */
       +                                        chtemp[n].num = ch[0];
       +                                } else if (ch[0] == '\\' && ch[1] == '0') {
       +                                        n = strtol(ch+1, 0, 0);        /* \0octal or \0xhex */
       +                                        chtemp[n].num = n;
       +#ifdef UNICODE
       +                                } else if (mbtowc(&wc, ch, strlen(ch)) > 1) {
       +                                        chtemp[nw].num = chadd(ch,  MBchar, Install);
       +                                        n = nw;
       +                                        nw++;
       +#endif        /*UNICODE*/
       +                                } else {
       +                                        if (strcmp(ch, "---") == 0) { /* no name */
       +                                                sprintf(ch, "%d", code);
       +                                                type = Number;
       +                                        } else
       +                                                type = Troffchar;
       +                                        chtemp[nw].num = chadd(ch, type, Install);
       +                                        n = nw;
       +                                        nw++;
       +                                }
       +                                chtemp[n].wid = wid;
       +                                chtemp[n].kern = kern;
       +                                chtemp[n].code = code;
       +                                /*fprintf(stderr, "font %2.2s char %4.4s num %3d wid %2d code %3d\n",
       +                                        ftemp->longname, ch, n, wid, code);
       +                                */
       +                        }
       +                        break;
       +                }
       +                skipline(fin);
       +        }
       +        fclose(fin);
       +        chtemp[' '].wid = ftemp->spacewidth;        /* width of space on this font */
       +        ftemp->nchars = nw;
       +        if (ftemp->wp)
       +                free(ftemp->wp);        /* god help us if this wasn't allocated */
       +        ftemp->wp = (Chwid *) malloc(nw * sizeof(Chwid));
       +        if (ftemp->wp == NULL)
       +                return -1;
       +        for (i = 0; i < nw; i++)
       +                ftemp->wp[i] = chtemp[i];
       +/*
       + *        printf("%d chars: ", nw);
       + *        for (i = 0; i < nw; i++)
       + *                if (ftemp->wp[i].num > 0 && ftemp->wp[i].num < ALPHABET) {
       + *                        printf("%c %d ", ftemp->wp[i].num, ftemp->wp[i].wid);
       + *                else if (i >= ALPHABET)
       + *                        printf("%d (%s) %d ", ftemp->wp[i].num,
       + *                                chnames[ftemp->wp[i].num-ALPHABET], ftemp->wp[i].wid);
       + *        }
       + *        printf("\n");
       + */
       +        return 1;
       +}
       +
       +chadd(char *s, int type, int install)        /* add s to global character name table; */
       +{                                        /* or just look it up */
       +
       +        /* a temporary kludge:  store the "type" as the first character */
       +        /* of the string, so we can remember from whence it came */
       +
       +        char *p;
       +        int i;
       +
       +/* fprintf(stderr, "into chadd %s %c %c\n", s, type, install); /* */
       +        for (i = 0; i < nchnames; i++)
       +                if (type == chnames[i][0] && eq(s, chnames[i]+1)) /* +1 since type at front */
       +                        break;
       +/* fprintf(stderr, "i %d, nchnames %d\n", i, nchnames); /* */
       +        if (i < nchnames)                /* found same type and bytes at position i */
       +                return ALPHABET + i;
       +        else if (install == Lookup)        /* not found, and we were just looking */
       +                return -1;
       +
       +        chnames[nchnames] = p = (char *) malloc(strlen(s)+1+1);        /* type + \0 */
       +        if (p == NULL) {
       +                ERROR "out of space adding character %s", s WARN;
       +                return LEFTHAND;
       +        }
       +        if (nchnames >= NCHARS - ALPHABET) {
       +                ERROR "out of table space adding character %s", s WARN;
       +                return LEFTHAND;
       +        }
       +        strcpy(chnames[nchnames]+1, s);
       +        chnames[nchnames][0] = type;
       +/* fprintf(stderr, "installed %c%s at %d\n", type, s, nchnames); /* */
       +        return nchnames++ + ALPHABET;
       +}
       +
       +char *chname(int n)        /* return string for char with index n */
       +{                        /* includes type char at front, to be peeled off elsewhere */
       +        if (n >= ALPHABET && n < nchnames + ALPHABET)
       +                return chnames[n-ALPHABET];
       +        else
       +                return "";
       +}
       +
       +getlig(FILE *fin)        /* pick up ligature list */
       +{
       +        int lig;
       +        char temp[200];
       +
       +        lig = 0;
       +        while (fscanf(fin, "%s", temp) != EOF && strcmp(temp, "0") != 0) {
       +                if (strcmp(temp, "fi") == 0)
       +                        lig |= LFI;
       +                else if (strcmp(temp, "fl") == 0)
       +                        lig |= LFL;
       +                else if (strcmp(temp, "ff") == 0)
       +                        lig |= LFF;
       +                else if (strcmp(temp, "ffi") == 0)
       +                        lig |= LFFI;
       +                else if (strcmp(temp, "ffl") == 0)
       +                        lig |= LFFL;
       +                else
       +                        fprintf(stderr, "illegal ligature %s ignored\n", temp);
       +        }
       +        return lig;
       +}
 (DIR) diff --git a/src/cmd/troff/t6.c b/src/cmd/troff/t6.c
       t@@ -0,0 +1,881 @@
       +/*
       + * t6.c
       + * 
       + * width functions, sizes and fonts
       + */
       +
       +#include "tdef.h"
       +#include "fns.h"
       +#include "ext.h"
       +
       +int        fontlab[MAXFONTS+1];
       +int        cstab[MAXFONTS+1];
       +int        ccstab[MAXFONTS+1];
       +int        bdtab[MAXFONTS+1];
       +int        sbold = 0;
       +
       +t_width(Tchar j)
       +{
       +        int i, k;
       +
       +        if (iszbit(j))
       +                return 0;
       +        if (ismot(j)) {
       +                if (isvmot(j))
       +                        return(0);
       +                k = absmot(j);
       +                if (isnmot(j))
       +                        k = -k;
       +                return(k);
       +        }
       +        i = cbits(j);
       +        if (i < ' ') {
       +                if (i == '\b')
       +                        return(-widthp);
       +                if (i == PRESC)
       +                        i = eschar;
       +                else if (i == HX)
       +                        return(0);
       +        }
       +        if (i == ohc)
       +                return(0);
       +        i = trtab[i];
       +        if (i < ' ')
       +                return(0);
       +        if (sfbits(j) == oldbits) {
       +                xfont = pfont;
       +                xpts = ppts;
       +        } else 
       +                xbits(j, 0);
       +        if (i < nchnames + ALPHABET && widcache[i].fontpts == (xfont<<8) + xpts && !setwdf)
       +                k = widcache[i].width;
       +        else {
       +                k = getcw(i);
       +                if (bd)
       +                        k += (bd - 1) * HOR;
       +                if (cs)
       +                        k = cs;
       +        }
       +        widthp = k;
       +        return(k);
       +}
       +
       +/*
       + * clear width cache-- s means just space
       + */
       +void zapwcache(int s)
       +{
       +        int i;
       +
       +        if (s) {
       +                widcache[' '].fontpts = 0;
       +                return;
       +        }
       +        for (i=0; i<NWIDCACHE; i++)
       +                widcache[i].fontpts = 0;
       +}
       +
       +onfont(int n, int f)        /* is char n on font f? */
       +{
       +        int i;
       +        Font *fp = &fonts[f];
       +        Chwid *cp, *ep;
       +        char *np;
       +
       +        if (n < ALPHABET) {
       +                if (fp->wp[n].num == n)        /* ascii at front */
       +                        return n;
       +                else
       +                        return -1;
       +        }
       +        cp = &fp->wp[ALPHABET];
       +        ep = &fp->wp[fp->nchars];
       +        for ( ; cp < ep; cp++)        /* search others */
       +                if (cp->num == n)
       +                        return cp - &fp->wp[0];
       +        /* maybe it was a \N... */
       +        np = chname(n);
       +        if (*np == Number) {
       +                i = atoi(np+1);                /* sscanf(np+1, "%d", &i); */
       +                cp = &fp->wp[0];
       +                ep = &fp->wp[fp->nchars];
       +                for ( ; cp < ep; cp++) {        /* search others */
       +                        if (cp->code == i)
       +                                return cp - &fp->wp[0];
       +                }
       +                return -2;        /* a \N that doesn't have an entry */
       +        }
       +        return -1;        /* vanilla not found */
       +}
       +
       +getcw(int i)
       +{
       +        int k, n, x;
       +        Font *fp;
       +        int nocache = 0;
       +        if (i < ' ')
       +                return 0;
       +        bd = 0;
       +        fp = &fonts[xfont];
       +        if (i == ' ') {        /* a blank */
       +                k = (fp->spacewidth * spacesz + 6) / 12;
       +                /* this nonsense because .ss cmd uses 1/36 em as its units */
       +                /*         and default is 12 */
       +        } else if ((n = onfont(i, xfont)) >= 0) {        /* on this font at n */
       +                k = fp->wp[n].wid;
       +                if (setwdf)
       +                        numtabp[CT].val |= fp->wp[n].kern;
       +        } else if (n == -2) {                /* \N with default width */
       +                
       +                k = fp->defaultwidth;
       +        } else {                        /* not on current font */
       +                nocache = 1;
       +                k = fp->defaultwidth;        /* default-size space */
       +                if (smnt) {
       +                        int ii, jj;
       +                        for (ii=smnt, jj=0; jj < nfonts; jj++, ii=ii % nfonts + 1) {
       +                                if ((n = onfont(i, ii)) >= 0) {
       +                                        k = fonts[ii].wp[n].wid;
       +                                        if (xfont == sbold)
       +                                                bd = bdtab[ii];
       +                                        if (setwdf)
       +                                                numtabp[CT].val |= fonts[ii].wp[n].kern;
       +                                        break;
       +                                }
       +                        }
       +                }
       +        }
       +        if (!bd)
       +                bd = bdtab[xfont];
       +        if (cs = cstab[xfont]) {
       +                nocache = 1;
       +                if (ccs = ccstab[xfont])
       +                        x = ccs; 
       +                else 
       +                        x = xpts;
       +                cs = (cs * EMPTS(x)) / 36;
       +        }
       +        /* was (k & BYTEMASK);  since .wid is unsigned, should never happen */
       +        if (k < 0)
       +                ERROR "can't happen: negative width %d in getcw %d\n", k, i WARN;
       +        k = (k * xpts + (Unitwidth / 2)) / Unitwidth;
       +        if (nocache|bd)
       +                widcache[i].fontpts = 0;
       +        else {
       +                widcache[i].fontpts = (xfont<<8) + xpts;
       +                widcache[i].width = k;
       +        }
       +        return(k);
       +        /* Unitwidth is Units/Point, where
       +        /* Units is the fundamental digitization
       +        /* of the character set widths, and
       +        /* Point is the number of goobies in a point
       +        /* e.g., for cat, Units=36, Point=6, so Unitwidth=36/6=6
       +        /* In effect, it's the size at which the widths
       +        /* translate directly into units.
       +        */
       +}
       +
       +void xbits(Tchar i, int bitf)
       +{
       +        int k;
       +
       +        if(TROFF) {
       +                xfont = fbits(i);
       +                k = sbits(i);
       +                if(k) {
       +                        xpts = pstab[k-1];
       +                        oldbits = sfbits(i);
       +                        pfont = xfont;
       +                        ppts = xpts;
       +                        return;
       +                }
       +                switch(bitf) {
       +                case 0:
       +                        xfont = font;
       +                        xpts = pts;
       +                        break;
       +                case 1:
       +                        xfont = pfont;
       +                        xpts = ppts;
       +                        break;
       +                case 2:
       +                        xfont = mfont;
       +                        xpts = mpts;
       +                }
       +        }
       +}
       +
       +
       +/* these next two functions ought to be the same in troff and nroff, */
       +/* but the data structures they search are different. */
       +/* silly historical problem. */
       +
       +
       +Tchar t_setch(int c)
       +{
       +        int j;
       +        char temp[50];
       +        char *s;
       +
       +        s = temp;
       +        if (c == '(') {        /* \(xx */
       +                if ((*s++ = getach()) == 0 || (*s++ = getach()) == 0)
       +                        return(0);
       +        } else {        /* \C'...' */
       +                c = getach();
       +                while ((*s = getach()) != c && *s != 0 && s < temp + sizeof(temp) - 1)
       +                        s++;
       +        }
       +        *s = '\0';
       +#ifdef UNICODE
       +        return chadd(temp, Troffchar, Install) | chbits; /* add name even if haven't seen it */
       +#else
       +        if (NROFF) {
       +                j = chadd(temp, Troffchar, Lookup);
       +                if ( j == -1)
       +                        return 0;
       +                else
       +                        return j | chbits;
       +        } else
       +                return chadd(temp, Troffchar, Install) | chbits; /* add name even if haven't seen it */
       +                
       +#endif /*UNICODE*/
       +}
       +
       +Tchar t_setabs(void)                /* set absolute char from \N'...' */
       +{
       +        int n;
       +        char temp[10];
       +
       +        getch();        /* delim */
       +        n = 0;
       +        n = inumb(&n);
       +        getch();        /* delim */
       +        if (nonumb)
       +                return 0;
       +        sprintf(temp, "%d", n);        /* convert into "#n" */
       +        n = chadd(temp, Number, Install);
       +        return n | chbits;
       +}
       +
       +
       +/*
       + * fontlab[] is a cache that contains font information
       + * for each font.
       + * fontlab[] contains the 1- or 2-character name of the
       + * font current associated with that font.
       + * fonts 1..nfonts correspond to the mounted fonts;
       + * the last of these are the special fonts.
       + * If we don't use the (named) font in one of the
       + * standard positions, we install the name in the next
       + * free slot of fontlab[] and font[].
       + * Whenever we need info about the font, we
       + * read in the data into the next free slot with getfont.
       + * The ptfont() (t10.c) routine will tell
       + * the device filter to put the font always at position
       + * zero if xfont > nfonts, so no need to change these filters.
       + * Yes, this is a bit kludgy.
       + *
       + * This gives the new specs of findft:
       + *         find the font name i, where i also can be a number.
       + *         Installs the font(name) i when not present
       + *         returns -1 on error
       + */
       +
       +
       +t_findft(int i)
       +{
       +        int k;
       +        Uchar *p;
       +
       +        p = unpair(i);
       +
       +        if (isdigit(p[0])) {                /* first look for numbers */
       +                k = p[0] - '0';
       +                if (p[1] > 0 && isdigit(p[1]))
       +                        k = 10 * k + p[1] - '0';
       +                if (k > 0 && k <= nfonts && k < smnt)
       +                        return(k);        /* mounted font:  .ft 3 */
       +                if (fontlab[k] && k <= MAXFONTS) {        /* translate */
       +                        return(k);                        /*number to a name */
       +                } else {
       +                        fprintf(stderr, "troff: no font at position %d\n", k);
       +                        return(-1);        /* wild number */
       +                }
       +        }
       +
       +        /*
       +         * Now we look for font names
       +         */
       +        for (k = 1; fontlab[k] != i; k++) {
       +                if (k > MAXFONTS)
       +                        return(-1);        /* running out of fontlab space */
       +                if (fontlab[k] == 0) {        /* passed all existing names */
       +                        if (setfp(k, i, (char *) 0, 1) == -1)
       +                                return(-1);
       +                        else {
       +                                fontlab[k] = i;        /* install the name */
       +                                return(k);
       +                        }
       +                }
       +        }
       +        return(k);                        /* was one of the existing names */
       +}
       +
       +
       +void caseps(void)
       +{
       +        int i;
       +
       +        if (TROFF) {
       +                if(skip())
       +                        i = apts1;
       +                else {
       +                        noscale++;
       +                        i = inumb(&apts);        /* this is a disaster for fractional point sizes */
       +                        noscale = 0;
       +                        if(nonumb)
       +                                i = apts1;
       +                }
       +                casps1(i);
       +        }
       +}
       +
       +
       +void casps1(int i)
       +{
       +
       +/*
       + * in olden times, it used to ignore changes to 0 or negative.
       + * this is meant to allow the requested size to be anything,
       + * in particular so eqn can generate lots of \s-3's and still
       + * get back by matching \s+3's.
       +
       +        if (i <= 0)
       +                return;
       +*/
       +        apts1 = apts;
       +        apts = i;
       +        pts1 = pts;
       +        pts = findps(i);
       +        mchbits();
       +}
       +
       +
       +findps(int i)
       +{
       +        int j, k;
       +
       +        for (j=k=0 ; pstab[j] != 0 ; j++)
       +                if (abs(pstab[j]-i) < abs(pstab[k]-i))
       +                        k = j;
       +
       +        return(pstab[k]);
       +}
       +
       +
       +void t_mchbits(void)
       +{
       +        int i, j, k;
       +
       +        i = pts;
       +        for (j = 0; i > (k = pstab[j]); j++)
       +                if (!k) {
       +                        j--;
       +                        break;
       +                }
       +        chbits = 0;
       +        setsbits(chbits, ++j);
       +        setfbits(chbits, font);
       +        sps = width(' ' | chbits);
       +        zapwcache(1);
       +}
       +
       +void t_setps(void)
       +{
       +        int i, j;
       +
       +        i = cbits(getch());
       +        if (isdigit(i)) {                /* \sd or \sdd */
       +                i -= '0';
       +                if (i == 0)                /* \s0 */
       +                        j = apts1;
       +                else if (i <= 3 && (ch=getch()) && isdigit(j = cbits(ch))) {        /* \sdd */
       +                        j = 10 * i + j - '0';
       +                        ch = 0;
       +                } else                /* \sd */
       +                        j = i;
       +        } else if (i == '(') {                /* \s(dd */
       +                j = cbits(getch()) - '0';
       +                j = 10 * j + cbits(getch()) - '0';
       +                if (j == 0)                /* \s(00 */
       +                        j = apts1;
       +        } else if (i == '+' || i == '-') {        /* \s+, \s- */
       +                j = cbits(getch());
       +                if (isdigit(j)) {                /* \s+d, \s-d */
       +                        j -= '0';
       +                } else if (j == '(') {                /* \s+(dd, \s-(dd */
       +                        j = cbits(getch()) - '0';
       +                        j = 10 * j + cbits(getch()) - '0';
       +                }
       +                if (i == '-')
       +                        j = -j;
       +                j += apts;
       +        }
       +        casps1(j);
       +}
       +
       +
       +Tchar t_setht(void)                /* set character height from \H'...' */
       +{
       +        int n;
       +        Tchar c;
       +
       +        getch();
       +        n = inumb(&apts);
       +        getch();
       +        if (n == 0 || nonumb)
       +                n = apts;        /* does this work? */
       +        c = CHARHT;
       +        c |= ZBIT;
       +        setsbits(c, n);
       +        setfbits(c, pts);        /* sneaky, CHARHT font bits are size bits */
       +        return(c);
       +}
       +
       +Tchar t_setslant(void)                /* set slant from \S'...' */
       +{
       +        int n;
       +        Tchar c;
       +
       +        getch();
       +        n = 0;
       +        n = inumb(&n);
       +        getch();
       +        if (nonumb)
       +                n = 0;
       +        c = SLANT;
       +        c |= ZBIT;
       +        setsfbits(c, n+180);
       +        return(c);
       +}
       +
       +
       +void caseft(void)
       +{
       +        if (!TROFF) {
       +                n_caseft();
       +                return;
       +        }
       +        skip();
       +        setfont(1);
       +}
       +
       +
       +void t_setfont(int a)
       +{
       +        int i, j;
       +
       +        if (a)
       +                i = getrq();
       +        else 
       +                i = getsn();
       +        if (!i || i == 'P') {
       +                j = font1;
       +                goto s0;
       +        }
       +        if (/* i == 'S' || */ i == '0')        /* an experiment -- why can't we change to it? */
       +                return;
       +        if ((j = findft(i)) == -1)
       +                if ((j = setfp(0, i, (char*) 0, 1)) == -1)        /* try to put it in position 0 */
       +                        return;
       +s0:
       +        font1 = font;
       +        font = j;
       +        mchbits();
       +}
       +
       +
       +void t_setwd(void)
       +{
       +        int base, wid;
       +        Tchar i;
       +        int delim, emsz, k;
       +        int savhp, savapts, savapts1, savfont, savfont1, savpts, savpts1;
       +
       +        base = numtabp[ST].val = numtabp[SB].val = wid = numtabp[CT].val = 0;
       +        if (ismot(i = getch()))
       +                return;
       +        delim = cbits(i);
       +        savhp = numtabp[HP].val;
       +        numtabp[HP].val = 0;
       +        savapts = apts;
       +        savapts1 = apts1;
       +        savfont = font;
       +        savfont1 = font1;
       +        savpts = pts;
       +        savpts1 = pts1;
       +        setwdf++;
       +        while (cbits(i = getch()) != delim && !nlflg) {
       +                k = width(i);
       +                wid += k;
       +                numtabp[HP].val += k;
       +                if (!ismot(i)) {
       +                        emsz = (INCH/72) * xpts;
       +                } else if (isvmot(i)) {
       +                        k = absmot(i);
       +                        if (isnmot(i))
       +                                k = -k;
       +                        base -= k;
       +                        emsz = 0;
       +                } else 
       +                        continue;
       +                if (base < numtabp[SB].val)
       +                        numtabp[SB].val = base;
       +                if ((k = base + emsz) > numtabp[ST].val)
       +                        numtabp[ST].val = k;
       +        }
       +        setn1(wid, 0, (Tchar) 0);
       +        numtabp[HP].val = savhp;
       +        apts = savapts;
       +        apts1 = savapts1;
       +        font = savfont;
       +        font1 = savfont1;
       +        pts = savpts;
       +        pts1 = savpts1;
       +        mchbits();
       +        setwdf = 0;
       +}
       +
       +
       +Tchar t_vmot(void)
       +{
       +        dfact = lss;
       +        vflag++;
       +        return t_mot();
       +}
       +
       +
       +Tchar t_hmot(void)
       +{
       +        dfact = EM;
       +        return t_mot();
       +}
       +
       +
       +Tchar t_mot(void)
       +{
       +        int j, n;
       +        Tchar i;
       +
       +        j = HOR;
       +        getch(); /*eat delim*/
       +        if (n = atoi0()) {
       +                if (vflag)
       +                        j = VERT;
       +                i = makem(quant(n, j));
       +        } else
       +                i = 0;
       +        getch();
       +        vflag = 0;
       +        dfact = 1;
       +        return(i);
       +}
       +
       +
       +Tchar t_sethl(int k)
       +{
       +        int j;
       +        Tchar i;
       +
       +        j = EM / 2;
       +        if (k == 'u')
       +                j = -j;
       +        else if (k == 'r')
       +                j = -2 * j;
       +        vflag++;
       +        i = makem(j);
       +        vflag = 0;
       +        return(i);
       +}
       +
       +
       +Tchar t_makem(int i)
       +{
       +        Tchar j;
       +
       +        if (i >= 0)
       +                j = i;
       +        else
       +                j = -i;
       +        if (Hor > 1 && !vflag)
       +                j = (j + Hor/2)/Hor * Hor;
       +        j |= MOT;
       +        if (i < 0)
       +                j |= NMOT;
       +        if (vflag)
       +                j |= VMOT;
       +        return(j);
       +}
       +
       +
       +Tchar getlg(Tchar i)
       +{
       +        Tchar j, k;
       +        int lf;
       +
       +        if (!TROFF)
       +                return i;
       +        if ((lf = fonts[fbits(i)].ligfont) == 0) /* font lacks ligatures */
       +                return(i);
       +        j = getch0();
       +        if (cbits(j) == 'i' && (lf & LFI))
       +                j = LIG_FI;
       +        else if (cbits(j) == 'l' && (lf & LFL))
       +                j = LIG_FL;
       +        else if (cbits(j) == 'f' && (lf & LFF)) {
       +                if ((lf & (LFFI|LFFL)) && lg != 2) {
       +                        k = getch0();
       +                        if (cbits(k)=='i' && (lf&LFFI))
       +                                j = LIG_FFI;
       +                        else if (cbits(k)=='l' && (lf&LFFL))
       +                                j = LIG_FFL;
       +                        else {
       +                                *pbp++ = k;
       +                                j = LIG_FF;
       +                        }
       +                } else 
       +                        j = LIG_FF;
       +        } else {
       +                *pbp++ = j;
       +                j = i;
       +        }
       +        return(i & SFMASK | j);
       +}
       +
       +
       +void caselg(void)
       +{
       +
       +        if(TROFF) {
       +                skip();
       +                lg = atoi0();
       +                if (nonumb)
       +                        lg = 1;
       +        }
       +}
       +
       +void casefp(void)
       +{
       +        int i, j;
       +
       +        if (!TROFF) {
       +                n_casefp();
       +                return;
       +        }
       +        skip();
       +        i = cbits(getch());
       +        if (isdigit(i)) {
       +                i -= '0';
       +                j = cbits(getch());
       +                if (isdigit(j))
       +                        i = 10 * i + j - '0';
       +        }
       +        if (i <= 0 || i > nfonts)
       +                ERROR "fp: bad font position %d", i WARN;
       +        else if (skip() || !(j = getrq()))
       +                ERROR "fp: no font name" WARN; 
       +        else if (skip() || !getname())
       +                setfp(i, j, (char*) 0, 1);
       +        else                /* 3rd argument = filename */
       +                setfp(i, j, nextf, 1);
       +}
       +
       +char *strdupl(const char *s)        /* make a copy of s */
       +{
       +        char *t;
       +
       +        t = (char *) malloc(strlen(s) + 1);
       +        if (t == NULL)
       +                ERROR "out of space in strdupl(%s)", s FATAL;
       +        strcpy(t, s);
       +        return t;
       +}
       +
       +setfp(int pos, int f, char *truename, int print)        /* mount font f at position pos[0...nfonts] */
       +{
       +        char pathname[NS], shortname[NS], *sl;
       +
       +        zapwcache(0);
       +        if (truename)
       +                strcpy(shortname, truename);
       +        else
       +                strcpy(shortname, (char *) unpair(f));
       +        if (truename && strrchr(truename, '/')) {        /* .fp 1 R dir/file: use verbatim */
       +                sprintf(pathname, "%s", truename);
       +                if (fonts[pos].truename)
       +                        free(fonts[pos].truename);
       +                fonts[pos].truename = strdupl(truename);
       +        } else if (truename) {                        /* synonym: .fp 1 R Avant */
       +                sprintf(pathname, "%s/dev%s/%s", fontdir, devname, truename);
       +                truename = 0;        /* so doesn't get repeated by ptfpcmd */
       +        } else                                        /* vanilla: .fp 5 XX */
       +                sprintf(pathname, "%s/dev%s/%s", fontdir, devname, shortname);
       +        if (truename == 0 && fonts[pos].truename != 0) {
       +                free(fonts[pos].truename);
       +                fonts[pos].truename = 0;
       +        }
       +        if (getfont(pathname, pos) < 0) {
       +                ERROR "Can't open font file %s", pathname WARN;
       +                return -1;
       +        }
       +        if (print && !ascii) {
       +                ptfpcmd(pos, fonts[pos].longname, truename);
       +                ptfont();
       +        }
       +        if (pos == smnt) {
       +                smnt = 0; 
       +                sbold = 0; 
       +        }
       +        fontlab[pos] = f;
       +        if (smnt == 0 && fonts[pos].specfont)
       +                smnt = pos;
       +        bdtab[pos] = cstab[pos] = ccstab[pos] = 0;
       +        return pos;
       +}
       +
       +/*
       + * .cs request; don't check legality of optional arguments
       + */
       +void casecs(void)
       +{
       +        int i, j;
       +
       +        if (TROFF) {
       +                int savtr = trace;
       +
       +                trace = 0;
       +                noscale++;
       +                skip();
       +                if (!(i = getrq()) || (i = findft(i)) < 0)
       +                        goto rtn;
       +                skip();
       +                cstab[i] = atoi0();
       +                skip();
       +                j = atoi0();
       +                if(nonumb)
       +                        ccstab[i] = 0;
       +                else
       +                        ccstab[i] = findps(j);
       +        rtn:
       +                zapwcache(0);
       +                noscale = 0;
       +                trace = savtr;
       +        }
       +}
       +
       +
       +void casebd(void)
       +{
       +        int i, j, k;
       +
       +        if (!TROFF) {
       +                n_casebd();
       +                return;
       +        }
       +        zapwcache(0);
       +        k = 0;
       +bd0:
       +        if (skip() || !(i = getrq()) || (j = findft(i)) == -1) {
       +                if (k)
       +                        goto bd1;
       +                else 
       +                        return;
       +        }
       +        if (j == smnt) {
       +                k = smnt;
       +                goto bd0;
       +        }
       +        if (k) {
       +                sbold = j;
       +                j = k;
       +        }
       +bd1:
       +        skip();
       +        noscale++;
       +        bdtab[j] = atoi0();
       +        noscale = 0;
       +}
       +
       +
       +void casevs(void)
       +{
       +        int i;
       +
       +        if (!TROFF) {
       +                n_casevs();
       +                return;
       +        }
       +        skip();
       +        vflag++;
       +        dfact = INCH; /* default scaling is points! */
       +        dfactd = 72;
       +        res = VERT;
       +        i = inumb(&lss);
       +        if (nonumb)
       +                i = lss1;
       +        if (i < VERT) 
       +                i = VERT;
       +        lss1 = lss;
       +        lss = i;
       +}
       +
       +
       +void casess(void)
       +{
       +        int i;
       +
       +        if(TROFF) {
       +                noscale++;
       +                skip();
       +                if(i = atoi0()) {
       +                        spacesz = i & 0177;
       +                        zapwcache(0);
       +                        sps = width(' ' | chbits);
       +                }
       +                noscale = 0;
       +        }
       +}
       +
       +
       +Tchar t_xlss(void)
       +{
       +        /* stores \x'...' into two successive Tchars.
       +        /* the first contains HX, the second the value,
       +        /* encoded as a vertical motion.
       +        /* decoding is done in n2.c by pchar().
       +        */
       +        int i;
       +
       +        getch();
       +        dfact = lss;
       +        i = quant(atoi0(), VERT);
       +        dfact = 1;
       +        getch();
       +        if (i >= 0)
       +                *pbp++ = MOT | VMOT | i;
       +        else
       +                *pbp++ = MOT | VMOT | NMOT | -i;
       +        return(HX);
       +}
       +
       +Uchar *unpair(int i)
       +{
       +        static Uchar name[3];
       +
       +        name[0] = i & SHORTMASK;
       +        name[1] = (i >> SHORT) & SHORTMASK;
       +        name[2] = 0;
       +        return name;
       +}
 (DIR) diff --git a/src/cmd/troff/tdef.h b/src/cmd/troff/tdef.h
       t@@ -0,0 +1,670 @@
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <limits.h>
       +#include <ctype.h>
       +#include <string.h>
       +
       +#define        NROFF        (!TROFF)
       +
       +
       +/* Site dependent definitions */
       +
       +#ifndef TMACDIR
       +#define TMACDIR                "lib/tmac/tmac."
       +#endif
       +#ifndef FONTDIR
       +#define FONTDIR                "lib/font"
       +#endif
       +#ifndef NTERMDIR
       +#define NTERMDIR        "lib/term/tab."
       +#endif
       +#ifndef TDEVNAME
       +#define TDEVNAME        "post"
       +#endif
       +#ifndef NDEVNAME
       +#define NDEVNAME        "37"
       +#endif
       +#ifndef TEXHYPHENS
       +#define        TEXHYPHENS        "/usr/lib/tex/macros/hyphen.tex"
       +#endif
       +#ifndef ALTHYPHENS
       +#define        ALTHYPHENS        "lib/tmac/hyphen.tex"        /* another place to look */
       +#endif
       +
       +typedef        unsigned char        Uchar;
       +typedef unsigned short        Ushort;
       +
       +typedef        /*unsigned*/ long        Tchar;
       +
       +typedef        struct        Blockp        Blockp;
       +typedef        struct        Diver        Diver;
       +typedef        struct        Stack        Stack;
       +typedef        struct        Divsiz        Divsiz;
       +typedef        struct        Contab        Contab;
       +typedef        struct        Numtab        Numtab;
       +typedef        struct        Numerr        Numerr;
       +typedef        struct        Env        Env;
       +typedef        struct        Term        Term;
       +typedef struct        Chwid        Chwid;
       +typedef struct        Font        Font;
       +typedef        struct        Spnames        Spnames;
       +typedef        struct        Wcache        Wcache;
       +typedef        struct        Tbuf        Tbuf;
       +
       +/* this simulates printf into a buffer that gets flushed sporadically */
       +/* the BSD goo is because SunOS sprintf doesn't return anything useful */
       +
       +#ifdef BSD4_2
       +#define        OUT                (obufp += strlen(sprintf(obufp,
       +#define        PUT                ))) > obuf+BUFSIZ ? flusho() : 1
       +#else
       +#define        OUT                (obufp += sprintf(obufp,
       +#define        PUT                )) > obuf+BUFSIZ ? flusho() : 1
       +#endif
       +
       +#define        oputs(a)        OUT "%s", a PUT
       +#define        oput(c)                ( *obufp++ = (c), obufp > obuf+BUFSIZ ? flusho() : 1 )
       +
       +extern        char        errbuf[];
       +#define        ERROR        sprintf(errbuf,
       +#define        WARN        ), errprint()
       +#define        FATAL        ), errprint(), exit(1)
       +
       +/* starting values for typesetting parameters: */
       +
       +#define        PS        10        /* default point size */
       +#define        FT        1        /* default font position */
       +#define ULFONT        2        /* default underline font */
       +#define        BDFONT        3        /* default emboldening font */
       +#define        BIFONT        4        /* default bold italic font */
       +#define        LL        (unsigned) 65*INCH/10        /* line length; 39picas=6.5in */
       +#define        VS        ((12*INCH)/72)        /* initial vert space */
       +
       +
       +#define        EMPTS(pts)        (((long)Inch*(pts) + 36) / 72)
       +#define        EM        (TROFF? EMPTS(pts): t.Em)
       +#define        INCH        (TROFF? Inch: 240)
       +#define        HOR        (TROFF? Hor: t.Adj)
       +#define        VERT        (TROFF? Vert: t.Vert)
       +#define        PO        (TROFF? Inch: 0)
       +#define        SPS        (TROFF? EMPTS(pts)/3: INCH/10)
       +#define        SS        (TROFF? 12: INCH/10)
       +#define        ICS        (TROFF? EMPTS(pts): 2*INCH/10)
       +#define        DTAB        (TROFF? (INCH/2): 0)
       +
       +/* These "characters" are used to encode various internal functions
       +/* Some make use of the fact that most ascii characters between
       +/* 0 and 040 don't have any graphic or other function.
       +/* The few that do have a purpose (e.g., \n, \b, \t, ...
       +/* are avoided by the ad hoc choices here.
       +/* See ifilt[] in n1.c for others -- 1, 2, 3, 5, 6, 7, 010, 011, 012 
       +*/
       +
       +#define        LEADER        001
       +#define        IMP        004        /* impossible char; glues things together */
       +#define        TAB        011
       +#define        RPT        014        /* next character is to be repeated many times */
       +#define        CHARHT        015        /* size field sets character height */
       +#define        SLANT        016        /* size field sets amount of slant */
       +#define        DRAWFCN        017        /* next several chars describe arb drawing fcns */
       +#        define        DRAWLINE        'l'        /* line: 'l' dx dy char */
       +#        define        DRAWCIRCLE        'c'        /* circle: 'c' r */
       +#        define        DRAWELLIPSE        'e'        /* ellipse: 'e' rx ry */
       +#        define        DRAWARC                'a'        /* arc: 'a' dx dy dx dy */
       +#        define        DRAWSPLINE        '~'        /* quadratic B spline: '~' dx dy dx dy ... */
       +                                        /* other splines go thru too */
       +/* NOTE:  the use of ~ is a botch since it's often used in .tr commands */
       +/* better to use a letter like s, but change it in the postprocessors too */
       +/* for now, this is taken care of in n9.c and t10.c */
       +#        define        DRAWBUILD        'b'        /* built-up character (e.g., { */
       +
       +#define        LEFT        020        /* \{ */
       +#define        RIGHT        021        /* \} */
       +#define        FILLER        022        /* \& and similar purposes */
       +#define        XON        023        /* \X'...' starts here */
       +#define        OHC        024        /* optional hyphenation character \% */
       +#define        CONT        025        /* \c character */
       +#define        PRESC        026        /* printable escape */
       +#define        UNPAD        027        /* unpaddable blank */
       +#define        XPAR        030        /* transparent mode indicator */
       +#define        FLSS        031        /* next Tchar contains vertical space */
       +                        /* used when recalling diverted text */
       +#define        WORDSP        032        /* paddable word space */
       +#define        ESC        033        /* current escape character */
       +#define        XOFF        034        /* \X'...' ends here */
       +                        /* matches XON, but they will probably never nest */
       +                        /* so could drop this when another control is needed */
       +#define        HX        035        /* next character is value of \x'...' */
       +#define MOTCH        036        /* this "character" is really motion; used by cbits() */
       +
       +#define        HYPHEN        c_hyphen
       +#define        EMDASH        c_emdash        /* \(em */
       +#define        RULE        c_rule                /* \(ru */
       +#define        MINUS        c_minus                /* minus sign on current font */
       +#define        LIG_FI        c_fi                /* \(ff */
       +#define        LIG_FL        c_fl                /* \(fl */
       +#define        LIG_FF        c_ff                /* \(ff */
       +#define        LIG_FFI        c_ffi                /* \(Fi */
       +#define        LIG_FFL        c_ffl                /* \(Fl */
       +#define        ACUTE        c_acute                /* acute accent \(aa */
       +#define        GRAVE        c_grave                /* grave accent \(ga */
       +#define        UNDERLINE c_under        /* \(ul */
       +#define        ROOTEN        c_rooten        /* root en \(rn */
       +#define        BOXRULE        c_boxrule        /* box rule \(br */
       +#define        LEFTHAND c_lefthand        /* left hand for word overflow */
       +#define        DAGGER         c_dagger        /* dagger for end of sentence/footnote */
       +
       +#define        HYPHALG        1        /* hyphenation algorithm: 0=>good old troff, 1=>tex */
       +
       +
       +/* array sizes, and similar limits: */
       +
       +#define MAXFONTS 99        /* Maximum number of fonts in fontab */
       +#define        NM        90        /* requests + macros */
       +#define        NN        NNAMES        /* number registers */
       +#define        NNAMES        15        /* predefined reg names */
       +#define        NIF        15        /* if-else nesting */
       +#define        NS        128        /* name buffer */
       +#define        NTM        1024        /* tm buffer */
       +#define        NEV        3        /* environments */
       +#define        EVLSZ        10        /* size of ev stack */
       +
       +#define        STACKSIZE (6*1024)        /* stack for macros and strings in progress */
       +#define        NHYP        10        /* max hyphens per word */
       +#define        NHEX        512        /* byte size of exception word list */
       +#define        NTAB        100        /* tab stops */
       +#define        NSO        5        /* "so" depth */
       +#define        NMF        5        /* number of -m flags */
       +#define        WDSIZE        500        /* word buffer click size */
       +#define        LNSIZE        4000        /* line buffer click size */
       +#define        OLNSIZE        5000        /* output line buffer click; bigger for 'w', etc. */
       +#define        NDI        5        /* number of diversions */
       +
       +#define        ALPHABET alphabet        /* number of characters in basic alphabet. */
       +                        /* 128 for parochial USA 7-bit ascii, */
       +                        /* 256 for "European" mode with e.g., Latin-1 */
       +
       +        /* NCHARS must be greater than 
       +                ALPHABET (ascii stuff) + total number of distinct char names
       +                from all fonts that will be run in this job (including
       +                unnamed ones and \N's)
       +        */
       +
       +#define        NCHARS        (8*1024)        /* maximum size of troff character set*/
       +
       +
       +        /* However for nroff you want only :
       +        1. number of special codes in charset of DESC, which ends up being the
       +                value of nchtab and which must be less than 512.
       +        2. ALPHABET, which apparently is the size of the portion of the tables reserved
       +                for special control symbols
       +        Apparently the max N of \N is irrelevant; */
       +        /* to allow \N of up to 254 with up to 338 special characters
       +                you need NCHARS of 338 + ALPHABET = 466 */
       +
       +#define        NROFFCHARS        1024        /* maximum size of nroff character set */
       +
       +#define        NTRTAB                NCHARS        /* number of items in trtab[] */
       +#define NWIDCACHE        NCHARS        /* number of items in widcache[] */
       +
       +#define        NTRAP        20        /* number of traps */
       +#define        NPN        20        /* numbers in "-o" */
       +#define        FBUFSZ        512        /* field buf size words */
       +#define        IBUFSZ        4096        /* bytes */
       +#define        NC        1024        /* cbuf size words */
       +#define        NOV        10        /* number of overstrike chars */
       +#define        NPP        10        /* pads per field */
       +
       +/*
       +        Internal character representation:
       +        Internally, every character is carried around as
       +        a 32 bit cookie, called a "Tchar" (typedef long).
       +        Bits are numbered 31..0 from left to right.
       +        If bit 15 is 1, the character is motion, with
       +                if bit 16 it's vertical motion
       +                if bit 17 it's negative motion
       +        If bit 15 is 0, the character is a real character.
       +                if bit 31        zero motion
       +                bits 30..24        size
       +                bits 23..16        font
       +*/
       +
       +/* in the following, "L" should really be a Tchar, but ... */
       +/* numerology leaves room for 16 bit chars */
       +
       +#define        MOT        (01uL << 16)        /* motion character indicator */
       +#define        VMOT        (01uL << 30)        /* vertical motion bit */
       +#define        NMOT        (01uL << 29)        /* negative motion indicator */
       +/* #define        MOTV        (MOT|VMOT|NMOT)        /* motion flags */
       +/* #define        MAXMOT        (~MOTV)                /* maximum motion permitted */
       +#define        MAXMOT        0xFFFF
       +
       +#define        ismot(n)        ((n) & MOT)
       +#define        isvmot(n)        (((n) & (MOT|VMOT)) == (MOT|VMOT))        /* must have tested MOT previously */
       +#define        isnmot(n)        (((n) & (MOT|NMOT)) == (MOT|NMOT))        /* ditto */
       +#define        absmot(n)        ((n) & 0xFFFF)
       +
       +#define        ZBIT        (01uL << 31)        /* zero width char */
       +#define        iszbit(n)        ((n) &  ZBIT)
       +
       +#define        FSHIFT        17
       +#define        SSHIFT        (FSHIFT+7)
       +#define        SMASK                (0177uL << SSHIFT)        /* 128 distinct sizes */
       +#define        FMASK                (0177uL << FSHIFT)        /* 128 distinct fonts */
       +#define        SFMASK                (SMASK|FMASK)        /* size and font in a Tchar */
       +#define        sbits(n)        (((n) >> SSHIFT) & 0177)
       +#define        fbits(n)        (((n) >> FSHIFT) & 0177)
       +#define        sfbits(n)        (((n) & SFMASK) >> FSHIFT)
       +#define        cbits(n)        ((n) & 0x1FFFF)                /* isolate character bits,  */
       +                                                /* but don't include motions */
       +extern        int        realcbits(Tchar);
       +
       +#define        setsbits(n,s)        n = (n & ~SMASK) | (Tchar)(s) << SSHIFT
       +#define        setfbits(n,f)        n = (n & ~FMASK) | (Tchar)(f) << FSHIFT
       +#define        setsfbits(n,sf)        n = (n & ~SFMASK) | (Tchar)(sf) << FSHIFT
       +#define        setcbits(n,c)        n = (n & ~0xFFFFuL | (c))        /* set character bits */
       +
       +#define        BYTEMASK 0377
       +#define        BYTE         8
       +
       +#define        SHORTMASK 0XFFFF
       +#define        SHORT         16
       +
       +#define        TABMASK         ((unsigned) INT_MAX >> 1)
       +#define        RTAB        ((TABMASK << 1) & ~TABMASK)
       +#define        CTAB        (RTAB << 1)
       +
       +#define        TABBIT        02                /* bits in gchtab */
       +#define        LDRBIT        04
       +#define        FCBIT        010
       +
       +#define        PAIR(A,B)        (A|(B<<SHORT))
       +
       +
       +extern        int        Inch, Hor, Vert, Unitwidth;
       +
       +struct        Spnames
       +{
       +        int        *n;
       +        char        *v;
       +};
       +
       +extern        Spnames        spnames[];
       +
       +/*
       +        String and macro definitions are stored conceptually in a giant array
       +        indexed by type Offset.  In olden times, this array was real, and thus
       +        both huge and limited in size, leading to the "Out of temp file space"
       +        error.  In this version, the array is represented by a list of blocks,
       +        pointed to by blist[].bp.  Each block is of size BLK Tchars, and BLK
       +        MUST be a power of 2 for the macros below to work.
       +        
       +        The blocks associated with a particular string or macro are chained
       +        together in the array blist[].  Each blist[i].nextoff contains the
       +        Offset associated with the next block in the giant array, or -1 if
       +        this is the last block in the chain.  If .nextoff is 0, the block is
       +        free.
       +        
       +        To find the right index in blist for an Offset, divide by BLK.
       +*/
       +
       +#define        NBLIST        2048        /* starting number of blocks in all definitions */
       +
       +#define        BLK        128        /* number of Tchars in a block; must be 2^N with defns below */
       +
       +#define        rbf0(o)                (blist[bindex(o)].bp[boffset(o)])
       +#define        bindex(o)        ((o) / BLK)
       +#define        boffset(o)        ((o) & (BLK-1))
       +#define        pastend(o)        (((o) & (BLK-1)) == 0)
       +/* #define        incoff(o)        ( (++o & (BLK-1)) ? o : blist[bindex(o-1)].nextoff ) */
       +#define        incoff(o)        ( (((o)+1) & (BLK-1)) ? o+1 : blist[bindex(o)].nextoff )
       +
       +#define        skipline(f)        while (getc(f) != '\n')
       +#define is(s)                (strcmp(cmd, s) == 0)
       +#define        eq(s1, s2)        (strcmp(s1, s2) == 0)
       +
       +
       +typedef        unsigned long        Offset;                /* an offset in macro/string storage */
       +
       +struct Blockp {                /* info about a block: */
       +        Tchar        *bp;                /* the data */
       +        Offset        nextoff;        /* offset of next block in a chain */
       +};
       +
       +extern        Blockp        *blist;
       +
       +#define        RD_OFFSET        (1 * BLK)        /* .rd command uses block 1 */
       +
       +struct Diver {                /* diversion */
       +        Offset        op;
       +        int        dnl;
       +        int        dimac;
       +        int        ditrap;
       +        int        ditf;
       +        int        alss;
       +        int        blss;
       +        int        nls;
       +        int        mkline;
       +        int        maxl;
       +        int        hnl;
       +        int        curd;
       +};
       +
       +struct Stack {                /* stack frame */
       +        int        nargs;
       +        Stack        *pframe;
       +        Offset        pip;
       +        int        pnchar;
       +        Tchar        prchar;
       +        int        ppendt;
       +        Tchar        pch;
       +        Tchar        *lastpbp;
       +        int        mname;
       +};
       +
       +extern        Stack        s;
       +
       +struct Divsiz {
       +        int dix;
       +        int diy;
       +};
       +
       +struct Contab {                /* command or macro */
       +        unsigned int        rq;
       +        Contab        *link;
       +        void        (*f)(void);
       +        Offset        mx;
       +        Offset        emx;
       +        Divsiz        *divsiz;
       +};
       +
       +#define        C(a,b)        {a, 0, b, 0, 0}                /* how to initialize a contab entry */
       +
       +extern        Contab        contab[NM];
       +
       +struct Numtab {        /* number registers */
       +        unsigned int        r;                /* name */
       +        int        val;
       +        short        fmt;
       +        short        inc;
       +        Numtab        *link;
       +};
       +
       +extern        Numtab        numtab[NN];
       +
       +#define        PN        0
       +#define        NL        1
       +#define        YR        2
       +#define        HP        3
       +#define        CT        4
       +#define        DN        5
       +#define        MO        6
       +#define        DY        7
       +#define        DW        8
       +#define        LN        9
       +#define        DL        10
       +#define        ST        11
       +#define        SB        12
       +#define        CD        13
       +#define        PID        14
       +
       +struct        Wcache {        /* width cache, indexed by character */
       +        short        fontpts;
       +        short        width;
       +};
       +
       +struct        Tbuf {                /* growable Tchar buffer */
       +        Tchar *_bufp;
       +        unsigned int _size;
       +};
       +
       +/* the infamous environment block */
       +
       +#define        ics        envp->_ics
       +#define        sps        envp->_sps
       +#define        spacesz        envp->_spacesz
       +#define        lss        envp->_lss
       +#define        lss1        envp->_lss1
       +#define        ll        envp->_ll
       +#define        ll1        envp->_ll1
       +#define        lt        envp->_lt
       +#define        lt1        envp->_lt1
       +#define        ic        envp->_ic
       +#define        icf        envp->_icf
       +#define        chbits        envp->_chbits
       +#define        spbits        envp->_spbits
       +#define        nmbits        envp->_nmbits
       +#define        apts        envp->_apts
       +#define        apts1        envp->_apts1
       +#define        pts        envp->_pts
       +#define        pts1        envp->_pts1
       +#define        font        envp->_font
       +#define        font1        envp->_font1
       +#define        ls        envp->_ls
       +#define        ls1        envp->_ls1
       +#define        ad        envp->_ad
       +#define        nms        envp->_nms
       +#define        ndf        envp->_ndf
       +#define        nmwid        envp->_nmwid
       +#define        fi        envp->_fi
       +#define        cc        envp->_cc
       +#define        c2        envp->_c2
       +#define        ohc        envp->_ohc
       +#define        tdelim        envp->_tdelim
       +#define        hyf        envp->_hyf
       +#define        hyoff        envp->_hyoff
       +#define        hyphalg        envp->_hyphalg
       +#define        un1        envp->_un1
       +#define        tabc        envp->_tabc
       +#define        dotc        envp->_dotc
       +#define        adsp        envp->_adsp
       +#define        adrem        envp->_adrem
       +#define        lastl        envp->_lastl
       +#define        nel        envp->_nel
       +#define        admod        envp->_admod
       +#define        wordp        envp->_wordp
       +#define        spflg        envp->_spflg
       +#define        linep        envp->_linep
       +#define        wdend        envp->_wdend
       +#define        wdstart        envp->_wdstart
       +#define        wne        envp->_wne
       +#define        ne        envp->_ne
       +#define        nc        envp->_nc
       +#define        nb        envp->_nb
       +#define        lnmod        envp->_lnmod
       +#define        nwd        envp->_nwd
       +#define        nn        envp->_nn
       +#define        ni        envp->_ni
       +#define        ul        envp->_ul
       +#define        cu        envp->_cu
       +#define        ce        envp->_ce
       +#define        in        envp->_in
       +#define        in1        envp->_in1
       +#define        un        envp->_un
       +#define        wch        envp->_wch
       +#define        pendt        envp->_pendt
       +#define        pendw        envp->_pendw
       +#define        pendnf        envp->_pendnf
       +#define        spread        envp->_spread
       +#define        it        envp->_it
       +#define        itmac        envp->_itmac
       +#define        hyptr        envp->_hyptr
       +#define        tabtab        envp->_tabtab
       +#define        line        envp->_line._bufp
       +#define        lnsize        envp->_line._size
       +#define        word        envp->_word._bufp
       +#define wdsize        envp->_word._size
       +
       +#define oline        _oline._bufp
       +#define olnsize        _oline._size
       +
       +/*
       + * Note:
       + * If this structure changes in ni.c, you must change
       + * this as well, and vice versa.
       + */
       +
       +struct Env {
       +        int        _ics;
       +        int        _sps;
       +        int        _spacesz;
       +        int        _lss;
       +        int        _lss1;
       +        int        _ll;
       +        int        _ll1;
       +        int        _lt;
       +        int        _lt1;
       +        Tchar        _ic;
       +        int        _icf;
       +        Tchar        _chbits;
       +        Tchar        _spbits;
       +        Tchar        _nmbits;
       +        int        _apts;
       +        int        _apts1;
       +        int        _pts;
       +        int        _pts1;
       +        int        _font;
       +        int        _font1;
       +        int        _ls;
       +        int        _ls1;
       +        int        _ad;
       +        int        _nms;
       +        int        _ndf;
       +        int        _nmwid;
       +        int        _fi;
       +        int        _cc;
       +        int        _c2;
       +        int        _ohc;
       +        int        _tdelim;
       +        int        _hyf;
       +        int        _hyoff;
       +        int        _hyphalg;
       +        int        _un1;
       +        int        _tabc;
       +        int        _dotc;
       +        int        _adsp;
       +        int        _adrem;
       +        int        _lastl;
       +        int        _nel;
       +        int        _admod;
       +        Tchar        *_wordp;
       +        int        _spflg;
       +        Tchar        *_linep;
       +        Tchar        *_wdend;
       +        Tchar        *_wdstart;
       +        int        _wne;
       +        int        _ne;
       +        int        _nc;
       +        int        _nb;
       +        int        _lnmod;
       +        int        _nwd;
       +        int        _nn;
       +        int        _ni;
       +        int        _ul;
       +        int        _cu;
       +        int        _ce;
       +        int        _in;
       +        int        _in1;
       +        int        _un;
       +        int        _wch;
       +        int        _pendt;
       +        Tchar        *_pendw;
       +        int        _pendnf;
       +        int        _spread;
       +        int        _it;
       +        int        _itmac;
       +        Tchar        *_hyptr[NHYP];
       +        long        _tabtab[NTAB];
       +        Tbuf        _line;
       +        Tbuf        _word;
       +};
       +
       +extern        Env        env[];
       +extern        Env        *envp;
       +
       +enum {        MBchar = 'U', Troffchar = 'C', Number = 'N', Install = 'i', Lookup = 'l' };
       +        /* U => utf, for instance;  C => \(xx, N => \N'...' */
       +
       +
       +
       +struct Chwid {        /* data on one character */
       +        Ushort        num;                /* character number:
       +                                        0 -> not on this font
       +                                        >= ALPHABET -> its number among all Cxy's */
       +        Ushort        code;                /* char code for actual device.  used for \N */
       +        char        *str;                /* code string for nroff */
       +        Uchar        wid;                /* width */
       +        Uchar        kern;                /* ascender/descender */
       +};
       +
       +struct Font {        /* characteristics of a font */
       +        int        name;                /* int name, e.g., BI (2 chars) */
       +        char        longname[64];        /* long name of this font (e.g., "Bembo" */
       +        char        *truename;        /* path name of table if not in standard place */
       +        int        nchars;                /* number of width entries for this font */
       +        char        specfont;        /* 1 == special font */
       +        int        spacewidth;        /* width of space on this font */
       +        int        defaultwidth;        /* default width of characters on this font */
       +        Chwid        *wp;                /* widths, etc., of the real characters */
       +        char        ligfont;        /* 1 == ligatures exist on this font */
       +};
       +
       +/* ligatures, ORed into ligfont */
       +
       +#define        LFF        01
       +#define        LFI        02
       +#define        LFL        04
       +#define        LFFI        010
       +#define        LFFL        020
       +
       +/* tracing modes */
       +#define TRNARGS        01                /* trace legality of numeric arguments */
       +#define TRREQ        02                /* trace requests */
       +#define TRMAC        04                /* trace macros */
       +#define RQERR        01                /* processing request/macro */
       +
       +/* typewriter driving table structure */
       +
       +
       +extern        Term        t;
       +struct Term {
       +        int        bset;                /* these bits have to be on */
       +        int        breset;                /* these bits have to be off */
       +        int        Hor;                /* #units in minimum horiz motion */
       +        int        Vert;                /* #units in minimum vert motion */
       +        int        Newline;        /* #units in single line space */
       +        int        Char;                /* #units in character width */
       +        int        Em;                /* ditto */
       +        int        Halfline;        /* half line units */
       +        int        Adj;                /* minimum units for horizontal adjustment */
       +        char        *twinit;        /* initialize terminal */
       +        char        *twrest;        /* reinitialize terminal */
       +        char        *twnl;                /* terminal sequence for newline */
       +        char        *hlr;                /* half-line reverse */
       +        char        *hlf;                /* half-line forward */
       +        char        *flr;                /* full-line reverse */
       +        char        *bdon;                /* turn bold mode on */
       +        char        *bdoff;                /* turn bold mode off */
       +        char        *iton;                /* turn italic mode on */
       +        char        *itoff;                /* turn italic mode off */
       +        char        *ploton;        /* turn plot mode on */
       +        char        *plotoff;        /* turn plot mode off */
       +        char        *up;                /* sequence to move up in plot mode */
       +        char        *down;                /* ditto */
       +        char        *right;                /* ditto */
       +        char        *left;                /* ditto */
       +
       +        Font        tfont;                /* widths and other info, as in a troff font */
       +};
       +
       +extern        Term        t;
       +
       +/*
       + * for error reporting; keep track of escapes/requests with numeric arguments
       + */
       +struct Numerr {
       +        char        type;        /* request or escape? */
       +        char        esc;        /* was escape sequence named esc */
       +        char        escarg;        /* argument of esc's like \D'l' */
       +        unsigned int        req;        /* was request or macro named req */
       +};
 (DIR) diff --git a/src/cmd/troff/unansi b/src/cmd/troff/unansi
       t@@ -0,0 +1,49 @@
       +# The awk program cvt will convert the relatively sterotyped ansi c
       +# in this troff distribution into older-style c, by munging function
       +# declarations.
       +
       +# You will also have to edit fns.h, by
       +#        sed 's/(.*)/()/g' fns.h >foo; mv foo fns.h
       +# check this before doing the move!
       +
       +# you will also have to make some editing changes in
       +# tdef.h in the Contab structure: s/(void)/()/
       +# you may have to fix up some function declarations
       +# in n4.c, the ones with (*f)(Tchar).
       +
       +# you will surely also have header files to deal with.
       +
       +# the most obvious cases are dealt with by the following
       +# commands.  make sure you do this stuff on a copy!
       +
       +# function prototypes in n8.c probably belong in fns.h. readpats(void) must
       +# be readpats() before cvt runs.
       +
       +sed \
       +        -e 's/(void)/()/' \
       +        -e 's/(Tchar[^)]*);/();/' \
       +        -e 's/(char[^)]*);/();/' \
       +        -e 's/(int[^)]*);/();/' \
       +n8.c >foo
       +mv foo n8.c
       +
       +for i in *.c
       +do
       +        cvt $i >foo
       +        mv foo $i
       +done
       +
       +sed 's/(.*)/()/g' fns.h >foo
       +mv foo fns.h
       +
       +sed -e 's/(void)/()/g' -e '/stdlib/d' tdef.h >foo
       +mv foo tdef.h
       +
       +# Compliers may not approve of void *setbrk() in fns.h and n3.c.
       +
       +sed 's/^void\*[         ]setbrk/char*        setbrk/' fns.h >foo
       +mv foo fns.h
       +
       +sed 's/^void \*setbrk/char *setbrk/' n3.c >foo
       +mv foo n3.c
       +