n1.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       n1.c (20331B)
       ---
            1 /*
            2  * n1.c
            3  *
            4  *        consume options, initialization, main loop,
            5  *        input routines, escape function calling
            6  */
            7 
            8 #include <u.h>
            9 #include "tdef.h"
           10 #include "fns.h"
           11 #include "ext.h"
           12 #include "dwbinit.h"
           13 
           14 #include <setjmp.h>
           15 #include <time.h>
           16 
           17 char        *Version        = "March 11, 1994";
           18 
           19 #ifndef DWBVERSION
           20 #define DWBVERSION      "???"
           21 #endif
           22 
           23 char        *DWBfontdir = FONTDIR;
           24 char        *DWBntermdir = NTERMDIR;
           25 char        *DWBalthyphens = ALTHYPHENS;
           26 char        *DWBhomedir = "";
           27 
           28 dwbinit dwbpaths[] = {
           29         &DWBfontdir, NULL, 0,
           30         &DWBntermdir, NULL, 0,
           31         &DWBalthyphens, NULL, 0,
           32         &DWBhomedir, NULL, 0,
           33         NULL, nextf, NS,
           34         NULL, NULL, 0
           35 };
           36 
           37 int        TROFF        = 1;        /* assume we started in troff... */
           38 
           39 jmp_buf sjbuf;
           40 Offset        ipl[NSO];
           41 
           42 static        FILE        *ifile;
           43 static        FILE        *ifl[NSO];        /* open input file pointers */
           44 char        cfname[NSO+1][NS] = {  "stdin" };        /* file name stack */
           45 int        cfline[NSO];                /* input line count stack */
           46 char        *progname;                /* program name (troff or nroff) */
           47 
           48 int        trace = 0;        /* tracing mode: default off */
           49 int        trace1 = 0;
           50 
           51 int
           52 main(int argc, char *argv[])
           53 {
           54         char *p;
           55         int j;
           56         Tchar i;
           57         char buf[100];
           58 
           59         ifile = stdin;                /* gcc */
           60         ptid = stdout;
           61 
           62         buf[0] = '\0';                /* make sure it's empty (silly 3b2) */
           63         progname = argv[0];
           64         if ((p = strrchr(progname, '/')) == NULL)
           65                 p = progname;
           66         else
           67                 p++;
           68         DWBinit(progname, dwbpaths);
           69         if (strcmp(p, "nroff") == 0)
           70                 TROFF = 0;
           71 #ifdef UNICODE
           72         alphabet = 128;        /* unicode for plan 9 */
           73 #endif        /*UNICODE*/
           74         mnspace();
           75         nnspace();
           76         mrehash();
           77         nrehash();
           78         numtabp[NL].val = -1;
           79 
           80         while (--argc > 0 && (++argv)[0][0] == '-')
           81                 switch (argv[0][1]) {
           82 
           83                 case 'N':        /* ought to be used first... */
           84                         TROFF = 0;
           85                         break;
           86                 case 'd':
           87                         fprintf(stderr, "troff/nroff version %s\n", Version);
           88                         break;
           89                 case 'F':        /* switch font tables from default */
           90                         if (argv[0][2] != '\0') {
           91                                 strcpy(termtab, &argv[0][2]);
           92                                 strcpy(fontdir, &argv[0][2]);
           93                         } else {
           94                                 argv++; argc--;
           95                                 strcpy(termtab, argv[0]);
           96                                 strcpy(fontdir, argv[0]);
           97                         }
           98                         break;
           99                 case 0:
          100                         goto start;
          101                 case 'i':
          102                         stdi++;
          103                         break;
          104                 case 'n':
          105                         npn = atoi(&argv[0][2]);
          106                         break;
          107                 case 'u':        /* set emboldening amount */
          108                         bdtab[3] = atoi(&argv[0][2]);
          109                         if (bdtab[3] < 0 || bdtab[3] > 50)
          110                                 bdtab[3] = 0;
          111                         break;
          112                 case 's':
          113                         if (!(stop = atoi(&argv[0][2])))
          114                                 stop++;
          115                         break;
          116                 case 'r':
          117                         sprintf(buf + strlen(buf), ".nr %c %s\n",
          118                                 argv[0][2], &argv[0][3]);
          119                         /* not yet cpushback(buf);*/
          120                         /* dotnr(&argv[0][2], &argv[0][3]); */
          121                         break;
          122                 case 'm':
          123                         if (mflg++ >= NMF) {
          124                                 ERROR "Too many macro packages: %s", argv[0] WARN;
          125                                 break;
          126                         }
          127                         strcpy(mfiles[nmfi], nextf);
          128                         strcat(mfiles[nmfi++], &argv[0][2]);
          129                         break;
          130                 case 'o':
          131                         getpn(&argv[0][2]);
          132                         break;
          133                 case 'T':
          134                         strcpy(devname, &argv[0][2]);
          135                         dotT++;
          136                         break;
          137                 case 'a':
          138                         ascii = 1;
          139                         break;
          140                 case 'h':
          141                         hflg++;
          142                         break;
          143                 case 'e':
          144                         eqflg++;
          145                         break;
          146                 case 'q':
          147                         quiet++;
          148                         save_tty();
          149                         break;
          150                 case 'V':
          151                         fprintf(stdout, "%croff: DWB %s\n", 
          152                                         TROFF ? 't' : 'n', DWBVERSION);
          153                         exit(0);
          154                 case 't':
          155                         if (argv[0][2] != '\0')
          156                                 trace = trace1 = argv[0][2];
          157                         break;                /* for the sake of compatibility */
          158                 default:
          159                         ERROR "unknown option %s", argv[0] WARN;
          160                         done(02);
          161                 }
          162 
          163 start:
          164         /*
          165          * cpushback maintains a LIFO, so push pack the -r arguments
          166          * in reverse order to maintain a FIFO in case someone did -rC1 -rC3
          167          */
          168         if (buf[0]) {
          169                 char *p = buf;
          170                 while(*p++)
          171                         ;
          172                 while(p > buf) {
          173                         while(strncmp(p, ".nr", 3) != 0)
          174                                 p--;
          175                         cpushback(p);
          176                         *p-- = '\0';
          177                 }
          178         }
          179         argp = argv;
          180         rargc = argc;
          181         nmfi = 0;
          182         init2();
          183         setjmp(sjbuf);
          184 loop:
          185         copyf = lgf = nb = nflush = nlflg = 0;
          186         if (ip && rbf0(ip) == 0 && ejf && frame->pframe <= ejl && dip == d) {
          187                 nflush++;
          188                 trap = 0;
          189                 eject((Stack *)0);
          190                 goto loop;
          191         }
          192         i = getch();
          193         if (pendt)
          194                 goto Lt;
          195         if ((j = cbits(i)) == XPAR) {
          196                 copyf++;
          197                 tflg++;
          198                 while (cbits(i) != '\n')
          199                         pchar(i = getch());
          200                 tflg = 0;
          201                 copyf--;
          202                 goto loop;
          203         }
          204         if (j == cc || j == c2) {
          205                 if (j == c2)
          206                         nb++;
          207                 copyf++;
          208                 while ((j = cbits(i = getch())) == ' ' || j == '\t')
          209                         ;
          210                 ch = i;
          211                 copyf--;
          212                 control(getrq(), 1);
          213                 flushi();
          214                 goto loop;
          215         }
          216 Lt:
          217         ch = i;
          218         text();
          219         if (nlflg)
          220                 numtabp[HP].val = 0;
          221         goto loop;
          222 }
          223 
          224 
          225 
          226 void init2(void)
          227 {
          228         int i;
          229         char buf[100];
          230 
          231         for (i = NTRTAB; --i; )
          232                 trtab[i] = i;
          233         trtab[UNPAD] = ' ';
          234         iflg = 0;
          235         obufp = obuf;
          236         if (TROFF)
          237                 t_ptinit();
          238         else
          239                 n_ptinit();
          240         mchbits();
          241         cvtime();
          242         numtabp[PID].val = getpid();
          243         numtabp[HP].val = init = 0;
          244         numtabp[NL].val = -1;
          245         nfo = 0;
          246         copyf = raw = 0;
          247         sprintf(buf, ".ds .T %s\n", devname);
          248         cpushback(buf);
          249         sprintf(buf, ".ds .P %s\n", DWBhomedir);
          250         cpushback(buf);
          251         numtabp[CD].val = -1;        /* compensation */
          252         nx = mflg;
          253         frame = stk = (Stack *)setbrk(STACKSIZE);
          254         dip = &d[0];
          255         nxf = frame + 1;
          256         for (i = 1; i < NEV; i++)        /* propagate the environment */
          257                 envcopy(&env[i], &env[0]);
          258         for (i = 0; i < NEV; i++) {
          259                 if ((env[i]._word._bufp = (Tchar *)calloc(WDSIZE, sizeof(Tchar))) == NULL) {
          260                         ERROR "not enough room for word buffers" WARN;
          261                         done2(1);
          262                 }
          263                 env[i]._word._size = WDSIZE;
          264                 if ((env[i]._line._bufp = (Tchar *)calloc(LNSIZE, sizeof(Tchar))) == NULL) {
          265                         ERROR "not enough room for line buffers" WARN;
          266                         done2(1);
          267                 }
          268                 env[i]._line._size = LNSIZE;
          269         }
          270         if ((oline = (Tchar *)calloc(OLNSIZE, sizeof(Tchar))) == NULL) {
          271                 ERROR "not enough room for line buffers" WARN;
          272                 done2(1);
          273         }
          274         olinep = oline;
          275         olnsize = OLNSIZE;
          276         blockinit();
          277 }
          278 
          279 void cvtime(void)
          280 {
          281         time_t tt;
          282         struct tm *ltime;
          283 
          284         time(&tt);
          285         ltime = localtime(&tt);
          286         numtabp[YR].val = ltime->tm_year % 100;
          287         numtabp[YR].fmt = 2;
          288         numtabp[MO].val = ltime->tm_mon + 1;        /* troff uses 1..12 */
          289         numtabp[DY].val = ltime->tm_mday;
          290         numtabp[DW].val = ltime->tm_wday + 1;        /* troff uses 1..7 */
          291 }
          292 
          293 
          294 
          295 char        errbuf[200];
          296 
          297 void errprint(void)        /* error message printer */
          298 {
          299         int savecd = numtabp[CD].val;
          300 
          301         if (!nlflg)
          302                 numtabp[CD].val++;
          303 
          304         fprintf(stderr, "%s: ", progname);
          305         fputs(errbuf, stderr);
          306         if (cfname[ifi][0])
          307                 fprintf(stderr, "; %s:%d", cfname[ifi], numtabp[CD].val);
          308         fputs("\n", stderr);
          309         if (cfname[ifi][0])
          310                 stackdump();
          311         numtabp[CD].val = savecd;
          312 }
          313 
          314 
          315 int control(int a, int b)
          316 {
          317         int j, k;
          318         extern Contab *contabp;
          319 
          320         numerr.type = RQERR;
          321         numerr.req = a;
          322         if (a == 0 || (j = findmn(a)) == -1)
          323                 return(0);
          324         if (contabp[j].f == 0) {
          325                 if (trace & TRMAC)
          326                         fprintf(stderr, "invoke macro %s\n", unpair(a));
          327                 if (dip != d)
          328                         for (k = dilev; k; k--)
          329                                 if (d[k].curd == a) {
          330                                         ERROR "diversion %s invokes itself during diversion",
          331                                                                 unpair(a) WARN;
          332                                         edone(0100);
          333                                 }
          334                 nxf->nargs = 0;
          335                 if (b)
          336                         collect();
          337                 flushi();
          338                 return pushi(contabp[j].mx, a);        /* BUG??? all that matters is 0/!0 */
          339         }
          340         if (b) {
          341                 if (trace & TRREQ)
          342                         fprintf(stderr, "invoke request %s\n", unpair(a));
          343                  (*contabp[j].f)();
          344         }
          345         return(0);
          346 }
          347 
          348 void casept(void)
          349 {
          350         int i;
          351 
          352         noscale++;
          353         if (skip())
          354                 i = trace1;
          355         else {
          356                 i = max(inumb(&trace), 0);
          357                 if (nonumb)
          358                         i = trace1;
          359         }
          360         trace1 = trace;
          361         trace = i;
          362         noscale = 0;
          363 }
          364 
          365 
          366 int getrq(void)
          367 {
          368         int i, j;
          369 
          370         if ((i = getach()) == 0 || (j = getach()) == 0)
          371                 goto rtn;
          372         i = PAIR(i, j);
          373 rtn:
          374         return(i);
          375 }
          376 
          377 /*
          378  * table encodes some special characters, to speed up tests
          379  * in getch, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch
          380  */
          381 
          382 char gchtab[NCHARS] = {
          383         000,004,000,000,010,000,000,000, /* fc, ldr */
          384         001,002,001,000,001,000,000,000, /* \b, tab, nl, RPT */
          385         000,000,000,000,000,000,000,000,
          386         000,001,000,001,000,000,000,000, /* FLSS, ESC */
          387         000,000,000,000,000,000,000,000,
          388         000,000,000,000,000,000,000,000,
          389         000,000,000,000,000,000,000,000,
          390         000,000,000,000,000,000,000,000,
          391         000,000,000,000,000,000,000,000,
          392         000,000,000,000,000,000,000,000,
          393         000,000,000,000,000,000,000,000,
          394         000,000,000,000,000,000,000,000,
          395         000,000,000,000,000,000,001,000, /* f */
          396         000,000,000,000,000,000,000,000,
          397         000,000,000,000,000,000,000,000,
          398         000,000,000,000,000,000,000,000
          399 };
          400 
          401 int realcbits(Tchar c)        /* return character bits, or MOTCH if motion */
          402 {
          403         if (ismot(c))
          404                 return MOTCH;
          405         else
          406                 return c & 0xFFFF;
          407 }
          408 
          409 Tchar getch(void)
          410 {
          411         int k;
          412         Tchar i, j;
          413 
          414 g0:
          415         if (ch) {
          416                 i = ch;
          417                 if (cbits(i) == '\n')
          418                         nlflg++;
          419                 ch = 0;
          420                 return(i);
          421         }
          422 
          423         if (nlflg)
          424                 return('\n');
          425         i = getch0();
          426         if (ismot(i))
          427                 return(i);
          428         k = cbits(i);
          429         if (k >= sizeof(gchtab)/sizeof(gchtab[0]) || gchtab[k] == 0)        /* nothing special */
          430                 return(i);
          431         if (k != ESC) {
          432                 if (k == '\n') {
          433                         nlflg++;
          434                         if (ip == 0)
          435                                 numtabp[CD].val++; /* line number */
          436                         return(k);
          437                 }
          438                 if (k == FLSS) {
          439                         copyf++; 
          440                         raw++;
          441                         i = getch0();
          442                         if (!fi)
          443                                 flss = i;
          444                         copyf--; 
          445                         raw--;
          446                         goto g0;
          447                 }
          448                 if (k == RPT) {
          449                         setrpt();
          450                         goto g0;
          451                 }
          452                 if (!copyf) {
          453                         if (k == 'f' && lg && !lgf) {
          454                                 i = getlg(i);
          455                                 return(i);
          456                         }
          457                         if (k == fc || k == tabch || k == ldrch) {
          458                                 if ((i = setfield(k)) == 0)
          459                                         goto g0; 
          460                                 else 
          461                                         return(i);
          462                         }
          463                         if (k == '\b') {
          464                                 i = makem(-width(' ' | chbits));
          465                                 return(i);
          466                         }
          467                 }
          468                 return(i);
          469         }
          470 
          471         k = cbits(j = getch0());
          472         if (ismot(j))
          473                 return(j);
          474 
          475         switch (k) {
          476         case 'n':        /* number register */
          477                 setn();
          478                 goto g0;
          479         case '$':        /* argument indicator */
          480                 seta();
          481                 goto g0;
          482         case '*':        /* string indicator */
          483                 setstr();
          484                 goto g0;
          485         case '{':        /* LEFT */
          486                 i = LEFT;
          487                 goto gx;
          488         case '}':        /* RIGHT */
          489                 i = RIGHT;
          490                 goto gx;
          491         case '"':        /* comment */
          492                 while (cbits(i = getch0()) != '\n')
          493                         ;
          494                 if (ip == 0)
          495                         numtabp[CD].val++; /* line number */
          496                 nlflg++;
          497                 return(i);
          498 
          499 /* experiment: put it here instead of copy mode */
          500         case '(':        /* special char name \(xx */
          501         case 'C':        /*                 \C'...' */
          502                 if ((i = setch(k)) == 0)
          503                         goto g0;
          504                 goto gx;
          505 
          506         case ESC:        /* double backslash */
          507                 i = eschar;
          508                 goto gx;
          509         case 'e':        /* printable version of current eschar */
          510                 i = PRESC;
          511                 goto gx;
          512         case '\n':        /* concealed newline */
          513                 numtabp[CD].val++;
          514                 goto g0;
          515         case ' ':        /* unpaddable space */
          516                 i = UNPAD;
          517                 goto gx;
          518         case '\'':        /* \(aa */
          519                 i = ACUTE;
          520                 goto gx;
          521         case '`':        /* \(ga */
          522                 i = GRAVE;
          523                 goto gx;
          524         case '_':        /* \(ul */
          525                 i = UNDERLINE;
          526                 goto gx;
          527         case '-':        /* current font minus */
          528                 i = MINUS;
          529                 goto gx;
          530         case '&':        /* filler */
          531                 i = FILLER;
          532                 goto gx;
          533         case 'c':        /* to be continued */
          534                 i = CONT;
          535                 goto gx;
          536         case '!':        /* transparent indicator */
          537                 i = XPAR;
          538                 goto gx;
          539         case 't':        /* tab */
          540                 i = '\t';
          541                 return(i);
          542         case 'a':        /* leader (SOH) */
          543 /* old:                *pbp++ = LEADER; goto g0; */
          544                 i = LEADER;
          545                 return i;
          546         case '%':        /* ohc */
          547                 i = OHC;
          548                 return(i);
          549         case 'g':        /* return format of a number register */
          550                 setaf();        /* should this really be in copy mode??? */
          551                 goto g0;
          552         case '.':        /* . */
          553                 i = '.';
          554 gx:
          555                 setsfbits(i, sfbits(j));
          556                 return(i);
          557         }
          558         if (copyf) {
          559                 *pbp++ = j;
          560                 return(eschar);
          561         }
          562         switch (k) {
          563 
          564         case 'f':        /* font indicator */
          565                 setfont(0);
          566                 goto g0;
          567         case 's':        /* size indicator */
          568                 setps();
          569                 goto g0;
          570         case 'v':        /* vert mot */
          571                 numerr.type = numerr.escarg = 0; numerr.esc = k;
          572                 if (i = vmot()) {
          573                         return(i);
          574                 }
          575                 goto g0;
          576         case 'h':         /* horiz mot */
          577                 numerr.type = numerr.escarg = 0; numerr.esc = k;
          578                 if (i = hmot())
          579                         return(i);
          580                 goto g0;
          581         case '|':        /* narrow space */
          582                 if (NROFF)
          583                         goto g0;
          584                 return(makem((int)(EM)/6));
          585         case '^':        /* half narrow space */
          586                 if (NROFF)
          587                         goto g0;
          588                 return(makem((int)(EM)/12));
          589         case 'w':        /* width function */
          590                 setwd();
          591                 goto g0;
          592         case 'p':        /* spread */
          593                 spread++;
          594                 goto g0;
          595         case 'N':        /* absolute character number */
          596                 numerr.type = numerr.escarg = 0; numerr.esc = k;
          597                 if ((i = setabs()) == 0)
          598                         goto g0;
          599                 return i;
          600         case 'H':        /* character height */
          601                 numerr.type = numerr.escarg = 0; numerr.esc = k;
          602                 return(setht());
          603         case 'S':        /* slant */
          604                 numerr.type = numerr.escarg = 0; numerr.esc = k;
          605                 return(setslant());
          606         case 'z':        /* zero with char */
          607                 return(setz());
          608         case 'l':        /* hor line */
          609                 numerr.type = numerr.escarg = 0; numerr.esc = k;
          610                 setline();
          611                 goto g0;
          612         case 'L':        /* vert line */
          613                 numerr.type = numerr.escarg = 0; numerr.esc = k;
          614                 setvline();
          615                 goto g0;
          616         case 'D':        /* drawing function */
          617                 numerr.type = numerr.escarg = 0; numerr.esc = k;
          618                 setdraw();
          619                 goto g0;
          620         case 'X':        /* \X'...' for copy through */
          621                 setxon();
          622                 goto g0;
          623         case 'b':        /* bracket */
          624                 setbra();
          625                 goto g0;
          626         case 'o':        /* overstrike */
          627                 setov();
          628                 goto g0;
          629         case 'k':        /* mark hor place */
          630                 if ((k = findr(getsn())) != -1) {
          631                         numtabp[k].val = numtabp[HP].val;
          632                 }
          633                 goto g0;
          634         case '0':        /* number space */
          635                 return(makem(width('0' | chbits)));
          636         case 'x':        /* extra line space */
          637                 numerr.type = numerr.escarg = 0; numerr.esc = k;
          638                 if (i = xlss())
          639                         return(i);
          640                 goto g0;
          641         case 'u':        /* half em up */
          642         case 'r':        /* full em up */
          643         case 'd':        /* half em down */
          644                 return(sethl(k));
          645         default:
          646                 return(j);
          647         }
          648         /* NOTREACHED */
          649 }
          650 
          651 void setxon(void)        /* \X'...' for copy through */
          652 {
          653         Tchar xbuf[NC];
          654         Tchar *i;
          655         Tchar c;
          656         int delim, k;
          657 
          658         if (ismot(c = getch()))
          659                 return;
          660         delim = cbits(c);
          661         i = xbuf;
          662         *i++ = XON | chbits;
          663         while ((k = cbits(c = getch())) != delim && k != '\n' && i < xbuf+NC-1) {
          664                 if (k == ' ')
          665                         setcbits(c, WORDSP);
          666                 *i++ = c | ZBIT;
          667         }
          668         *i++ = XOFF | chbits;
          669         *i = 0;
          670         pushback(xbuf);
          671 }
          672 
          673 
          674 char        ifilt[32] = { 0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012 };
          675 
          676 Tchar getch0(void)
          677 {
          678         Tchar i;
          679 
          680 again:
          681         if (pbp > lastpbp)
          682                 i = *--pbp;
          683         else if (ip) {
          684                 /* i = rbf(); */
          685                 i = rbf0(ip);
          686                 if (i == 0)
          687                         i = rbf();
          688                 else {
          689                         ++ip;
          690                         if (pastend(ip)) {
          691                                 --ip;
          692                                 rbf();
          693                         }
          694                 }
          695         } else {
          696                 if (donef || ndone)
          697                         done(0);
          698                 if (nx || 1) {        /* BUG: was ibufp >= eibuf, so EOF test is wrong */
          699                         if (nfo < 0)
          700                                 ERROR "in getch0, nfo = %d", nfo WARN;
          701                         if (nfo == 0) {
          702 g0:
          703                                 if (nextfile()) {
          704                                         if (ip)
          705                                                 goto again;
          706                                 }
          707                         }
          708                         nx = 0;
          709 #ifdef UNICODE
          710                         if (MB_CUR_MAX > 1)
          711                                 i = get1ch(ifile);
          712                         else
          713 #endif        /*UNICODE*/
          714                                 i = getc(ifile);
          715                         if (i == EOF)
          716                                 goto g0;
          717                         if (ip)
          718                                 goto again;
          719                 }
          720 /*g2: */
          721                 if (i >= 040)                        /* zapped: && i < 0177 */
          722                         goto g4;
          723                 i = ifilt[i];
          724         }
          725         if (cbits(i) == IMP && !raw)
          726                 goto again;
          727         if (i == 0 && !init && !raw) {                /* zapped:  || i == 0177 */
          728                 goto again;
          729         }
          730 g4:
          731         if (ismot(i))
          732                 return i;
          733         if (copyf == 0 && sfbits(i) == 0)
          734                 i |= chbits;
          735         if (cbits(i) == eschar && !raw)
          736                 setcbits(i, ESC);
          737         return(i);
          738 }
          739 
          740 
          741 #ifdef UNICODE
          742 Tchar get1ch(FILE *fp)        /* get one "character" from input, figure out what alphabet */
          743 {
          744         wchar_t wc;
          745         char buf[100], *p;
          746         int i, n, c;
          747 
          748         for (i = 0, p = buf; i < MB_CUR_MAX; i++) {
          749                 if ((c = getc(fp)) == EOF)
          750                         return c;
          751                 *p++ = c;
          752                 if ((n = mbtowc(&wc, buf, p-buf)) >= 0)
          753                         break;
          754         }
          755 
          756         if (n == 1)        /* real ascii, presumably */
          757                 return wc;
          758         if (n == 0)
          759                 return p[-1];        /* illegal, but what else to do? */
          760         if (c == EOF)
          761                 return EOF;
          762         *p = 0;
          763         return chadd(buf, MBchar, Install);        /* add name even if haven't seen it */
          764 }
          765 #endif        /*UNICODE*/
          766 
          767 void pushback(Tchar *b)
          768 {
          769         Tchar *ob = b;
          770 
          771         while (*b++)
          772                 ;
          773         b--;
          774         while (b > ob && pbp < &pbbuf[NC-3])
          775                 *pbp++ = *--b;
          776         if (pbp >= &pbbuf[NC-3]) {
          777                 ERROR "pushback overflow" WARN;
          778                 done(2);
          779         }
          780 }
          781 
          782 void cpushback(char *b)
          783 {
          784         char *ob = b;
          785 
          786         while (*b++)
          787                 ;
          788         b--;
          789         while (b > ob && pbp < &pbbuf[NC-3])
          790                 *pbp++ = *--b;
          791         if (pbp >= &pbbuf[NC-3]) {
          792                 ERROR "cpushback overflow" WARN;
          793                 done(2);
          794         }
          795 }
          796 
          797 int nextfile(void)
          798 {
          799         char *p;
          800 
          801 n0:
          802         if (ifile != stdin)
          803                 fclose(ifile);
          804         if (ifi > 0 && !nx) {
          805                 if (popf())
          806                         goto n0; /* popf error */
          807                 return(1);         /* popf ok */
          808         }
          809         if (nx || nmfi < mflg) {
          810                 p = mfiles[nmfi++];
          811                 if (*p != 0)
          812                         goto n1;
          813         }
          814         if (rargc-- <= 0) {
          815                 if ((nfo -= mflg) && !stdi) {
          816                         done(0);
          817 }
          818                 nfo++;
          819                 numtabp[CD].val = stdi = mflg = 0;
          820                 ifile = stdin;
          821                 strcpy(cfname[ifi], "stdin");
          822                 return(0);
          823         }
          824         p = (argp++)[0];
          825         if (rargc >= 0)
          826                 cfname[ifi][0] = 0;
          827 n1:
          828         numtabp[CD].val = 0;
          829         if (p[0] == '-' && p[1] == 0) {
          830                 ifile = stdin;
          831                 strcpy(cfname[ifi], "stdin");
          832         } else if ((ifile = fopen(unsharp(p), "r")) == NULL) {
          833                 ERROR "cannot open file %s", p WARN;
          834                 nfo -= mflg;
          835                 done(02);
          836         } else
          837                 strcpy(cfname[ifi],p);
          838         nfo++;
          839         return(0);
          840 }
          841 
          842 int
          843 popf(void)
          844 {
          845         --ifi;
          846         if (ifi < 0) {
          847                 ERROR "popf went negative" WARN;
          848                 return 1;
          849         }
          850         numtabp[CD].val = cfline[ifi];        /* restore line counter */
          851         ip = ipl[ifi];                        /* input pointer */
          852         ifile = ifl[ifi];                /* input FILE * */
          853         return(0);
          854 }
          855 
          856 
          857 void flushi(void)
          858 {
          859         if (nflush)
          860                 return;
          861         ch = 0;
          862         copyf++;
          863         while (!nlflg) {
          864                 if (donef && frame == stk)
          865                         break;
          866                 getch();
          867         }
          868         copyf--;
          869 }
          870 
          871 /*
          872  * return 16-bit, ascii/alphabetic character, ignore chars with more bits,
          873  * (internal names), spaces and special cookies (below 040).
          874  * Leave STX ETX ENQ ACK and BELL in to maintain compatibility with v7 troff.
          875  */
          876 int
          877 getach(void)
          878 {
          879         Tchar i;
          880         int j;
          881 
          882         lgf++;
          883         j = cbits(i = getch());
          884         if (ismot(i)
          885             || j > SHORTMASK
          886             || (j <= 040 && j != 002        /*STX*/
          887                         && j != 003        /*ETX*/
          888                         && j != 005        /*ENQ*/
          889                         && j != 006        /*ACK*/
          890                         && j != 007)) {        /*BELL*/
          891                 ch = i;
          892                 j = 0;
          893         }
          894         lgf--;
          895         return j;
          896 }
          897 
          898 
          899 void casenx(void)
          900 {
          901         lgf++;
          902         skip();
          903         getname();
          904         nx++;
          905         if (nmfi > 0)
          906                 nmfi--;
          907         strcpy(mfiles[nmfi], nextf);
          908         nextfile();
          909         nlflg++;
          910         ip = 0;
          911         pendt = 0;
          912         frame = stk;
          913         nxf = frame + 1;
          914 }
          915 
          916 int
          917 getname(void)
          918 {
          919         int j, k;
          920 
          921         lgf++;
          922         for (k = 0; k < NS - 1; k++) {
          923                 j = getach();
          924                 if (!j)
          925                         break;
          926                 nextf[k] = j;
          927         }
          928         nextf[k] = 0;
          929         lgf--;
          930         return(nextf[0]);
          931 }
          932 
          933 
          934 void caseso(void)
          935 {
          936         FILE *fp = 0;
          937 
          938         lgf++;
          939         nextf[0] = 0;
          940         if (skip() || !getname() || (fp = fopen(unsharp(nextf), "r")) == NULL || ifi >= NSO) {
          941                 ERROR "can't open file %s", nextf WARN;
          942                 done(02);
          943         }
          944         strcpy(cfname[ifi+1], nextf);
          945         cfline[ifi] = numtabp[CD].val;                /*hold line counter*/
          946         numtabp[CD].val = 0;
          947         flushi();
          948         ifl[ifi] = ifile;
          949         ifile = fp;
          950         ipl[ifi] = ip;
          951         ip = 0;
          952         nx++;
          953         nflush++;
          954         ifi++;
          955 }
          956 
          957 void caself(void)        /* set line number and file */
          958 {
          959         int n;
          960 
          961         if (skip())
          962                 return;
          963         n = atoi0();
          964         if (!nonumb)
          965                 cfline[ifi] = numtabp[CD].val = n - 1;
          966         if (!skip())
          967                 if (getname()) {        /* eats '\n' ? */
          968                         strcpy(cfname[ifi], nextf);
          969                         if (!nonumb)
          970                                 numtabp[CD].val--;
          971                 }
          972 }
          973 
          974 void cpout(FILE *fin, char *token)
          975 {
          976         int n;
          977         char buf[1024];
          978 
          979         if (token) {        /* BUG: There should be no NULL bytes in input */
          980                 char *newl = buf;
          981                 while ((fgets(buf, sizeof buf, fin)) != NULL) {
          982                         if (newl) {
          983                                 numtabp[CD].val++; /* line number */
          984                                 if (strcmp(token, buf) == 0)
          985                                         return;
          986                         }
          987                         newl = strchr(buf, '\n');
          988                         fputs(buf, ptid);
          989                 }
          990         } else {
          991                 while ((n = fread(buf, sizeof *buf, sizeof buf, fin)) > 0)
          992                         fwrite(buf, n, 1, ptid);
          993                 fclose(fin);
          994         }
          995 }
          996 
          997 void casecf(void)
          998 {        /* copy file without change */
          999         FILE *fd;
         1000         char *eof, *p;
         1001         extern int hpos, esc, po;
         1002 
         1003         /* this may not make much sense in nroff... */
         1004 
         1005         lgf++;
         1006         nextf[0] = 0;
         1007         if (!skip() && getname()) {
         1008                 if (strncmp("<<", nextf, 2) != 0) {
         1009                         if ((fd = fopen(unsharp(nextf), "r")) == NULL) {
         1010                                 ERROR "can't open file %s", nextf WARN;
         1011                                 done(02);
         1012                         }
         1013                         eof = (char *) NULL;
         1014                 } else {        /* current file */
         1015                         if (pbp > lastpbp || ip) {
         1016                                 ERROR "casecf: not reading from file" WARN;
         1017                                 done(02);
         1018                         }
         1019                         eof = &nextf[2];
         1020                         if (!*eof)  {
         1021                                 ERROR "casecf: missing end of input token" WARN;
         1022                                 done(02);
         1023                         }
         1024                         p = eof;
         1025                         while(*++p)
         1026                                 ;
         1027                         *p++ = '\n';
         1028                         *p = 0;
         1029                         fd = ifile;
         1030                 }
         1031         } else {
         1032                 ERROR "casecf: no argument" WARN;
         1033                 lgf--;
         1034                 return;
         1035         }
         1036         lgf--;
         1037 
         1038         /* make it into a clean state, be sure that everything is out */
         1039         tbreak();
         1040         hpos = po;
         1041         esc = 0;
         1042         ptesc();        /* to left margin */
         1043         esc = un;
         1044         ptesc();
         1045         ptlead();
         1046         ptps();
         1047         ptfont();
         1048         flusho();
         1049         cpout(fd, eof);
         1050         ptps();
         1051         ptfont();
         1052 }
         1053 
         1054 void getline(char *s, int n)        /* get rest of input line into s */
         1055 {
         1056         int i;
         1057 
         1058         lgf++;
         1059         copyf++;
         1060         skip();
         1061         for (i = 0; i < n-1; i++)
         1062                 if ((s[i] = cbits(getch())) == '\n' || s[i] == RIGHT)
         1063                         break;
         1064         s[i] = 0;
         1065         copyf--;
         1066         lgf--;
         1067 }
         1068 
         1069 void casesy(void)        /* call system */
         1070 {
         1071         char sybuf[NTM];
         1072 
         1073         getline(sybuf, NTM);
         1074         system(sybuf);
         1075 }
         1076 
         1077 
         1078 void getpn(char *a)
         1079 {
         1080         int n, neg;
         1081 
         1082         if (*a == 0)
         1083                 return;
         1084         neg = 0;
         1085         for ( ; *a; a++)
         1086                 switch (*a) {
         1087                 case '+':
         1088                 case ',':
         1089                         continue;
         1090                 case '-':
         1091                         neg = 1;
         1092                         continue;
         1093                 default:
         1094                         n = 0;
         1095                         if (isdigit((uchar)*a)) {
         1096                                 do
         1097                                         n = 10 * n + *a++ - '0';
         1098                                 while (isdigit((uchar)*a));
         1099                                 a--;
         1100                         } else
         1101                                 n = 9999;
         1102                         *pnp++ = neg ? -n : n;
         1103                         neg = 0;
         1104                         if (pnp >= &pnlist[NPN-2]) {
         1105                                 ERROR "too many page numbers" WARN;
         1106                                 done3(-3);
         1107                         }
         1108                 }
         1109         if (neg)
         1110                 *pnp++ = -9999;
         1111         *pnp = -INT_MAX;
         1112         print = 0;
         1113         pnp = pnlist;
         1114         if (*pnp != -INT_MAX)
         1115                 chkpn();
         1116 }
         1117 
         1118 
         1119 void setrpt(void)
         1120 {
         1121         Tchar i, j;
         1122 
         1123         copyf++;
         1124         raw++;
         1125         i = getch0();
         1126         copyf--;
         1127         raw--;
         1128         if ((long) i < 0 || cbits(j = getch0()) == RPT)
         1129                 return;
         1130         while (i > 0 && pbp < &pbbuf[NC-3]) {
         1131                 i--;
         1132                 *pbp++ = j;
         1133         }
         1134 }