home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / unix_c / textproc / roff.c < prev    next >
C/C++ Source or Header  |  1989-03-21  |  20KB  |  1,221 lines

  1.  2-Jul-85 15:52:11-MDT,21576;000000000001
  2. Return-Path: <unix-sources-request@BRL.ARPA>
  3. Received: from BRL-TGR.ARPA by SIMTEL20.ARPA with TCP; Tue 2 Jul 85 15:51:06-MDT
  4. Received: from usenet by TGR.BRL.ARPA id a023513; 2 Jul 85 6:49 EDT
  5. From: "Col. G. L. Sicherman" <colonel@gloria.uucp>
  6. Newsgroups: net.sources
  7. Subject: roff.c - complete with fixes
  8. Message-ID: <890@gloria.UUCP>
  9. Date: 1 Jul 85 15:03:52 GMT
  10. To:       unix-sources@BRL-TGR.ARPA
  11.  
  12. Here as promised: the up-to-date version of roff.c.  If you need the
  13. manual page, I'll mail it rather than post it.  Thanks to those who
  14. sent fixes!
  15.  
  16. It still doesn't hyphenate except on demand.
  17. -----
  18. /*
  19.  *    roff - C version.
  20.  *    the Colonel.  19 May 1983.
  21.  *
  22.  *    fix by Tim Maroney, 31 Dec 1984.
  23.  *    .hc implemented, 8 Feb 1985.
  24.  *    fix to hyphenating with underlining, 12 Feb 1985.
  25.  *    fixes to long-line hang and .bp by Dave Tutelman, 30 Mar 1985.
  26.  */
  27.  
  28. #include <sgtty.h>
  29. #include <signal.h>
  30. #include <stdio.h>
  31. #include <sys/types.h>
  32. #include <sys/stat.h>
  33.  
  34. #define SUFTAB    "/usr/lib/suftab"
  35. #define TXTLEN    (o_pl-o_m1-o_m2-o_m3-o_m4-2)
  36. #define IDTLEN    (o_ti>=0?o_ti:o_in)
  37. #define MAXMAC    64
  38. #define MAXDEPTH 10
  39. #define MAXLENGTH 255
  40. #define UNDERL    '\200'
  41.  
  42. char spacechars[] = " \t\n";
  43. int sflag, hflag, startpage, stoppage;
  44. char holdword[MAXLENGTH], *holdp;
  45. char assyline[MAXLENGTH];
  46. int assylen;
  47. char ehead[100], efoot[100], ohead[100], ofoot[100];
  48. struct macrotype {
  49.     char mname[3];
  50.     long int moff;
  51. } macro[MAXMAC];
  52. int n_macros;
  53. int depth;
  54. int adjtoggle;
  55. int isrequest = 0;
  56. char o_tr[40][2];    /* OUTPUT TRANSLATION TABLE */
  57. int o_cc = '.';    /* CONTROL CHARACTER */
  58. int o_hc = -1;    /* HYPHENATION CHARACTER */
  59. int o_tc = ' ';    /* TABULATION CHARACTER */
  60. int o_in = 0;    /* INDENT SIZE */
  61. int o_ix = -1;    /* NEXT INDENT SIZE */
  62. int o_ta[20] = {
  63.     9, 17, 25, 33, 41, 49, 57, 65, 73, 81, 89, 97, 105, 
  64.     113, 121, 129, 137, 145, 153, 161};
  65. int n_ta = 20;    /* #TAB STOPS */
  66. int o_ll = 65, o_ad = 1, o_po = 0, o_ls = 1, o_ig = 0, o_fi = 1;
  67. int o_pl = 66, o_ro = 0, o_hx = 0, o_bl = 0, o_sp = 0, o_sk = 0;
  68. int o_ce = 0, o_m1 = 2, o_m2 = 2, o_m3 = 1, o_m4 = 3, o_ul = 0;
  69. int o_li = 0, o_n1 = 0, o_n2 = 0, o_bp = -1, o_hy = 1;
  70. int o_ni = 1;    /* LINE-NUMBER INDENT */
  71. int o_nn = 0;    /* #LINES TO SUPPRESS NUMBERING */
  72. int o_ti = -1;    /* TEMPORARY INDENT */
  73. int center = 0;
  74. int page_no = -1;
  75. int line_no = 9999;
  76. int n_outwords;
  77. FILE *File, *Macread, *Macwrite;
  78. FILE *Save;
  79. long int teller[MAXDEPTH], ftell();
  80. char *strcat(), *strcpy(), *strend(), *strhas();
  81. char *sprintf();
  82. char *request[] = {
  83.     "ad","ar","bl","bp","br","cc","ce","de",
  84.     "ds","ef","eh","fi","fo","hc","he","hx","hy","ig",
  85.     "in","ix","li","ll","ls","m1","m2","m3","m4",
  86.     "n1","n2","na","ne","nf","ni","nn","nx","of","oh",
  87.     "pa","pl","po","ro","sk","sp","ss","ta","tc","ti",
  88.     "tr","ul",0};
  89. char *mktemp(), *mfilnam = "/tmp/rtmXXXXXX";
  90. int c;        /* LAST CHAR READ */
  91. struct sgttyb tty;
  92.  
  93. main(argc,argv)
  94. int argc;
  95. char **argv;
  96. {
  97.     while (--argc) switch (**++argv) {
  98.     case '+':
  99.         startpage=atoi(++*argv);
  100.         break;
  101.     case '-':
  102.         ++*argv;
  103.         if (isdigit(**argv)) stoppage=atoi(*argv);
  104.         else switch(**argv) {
  105.         case 's':
  106.             sflag++;
  107.             break;
  108.         case 'h':
  109.             hflag++;
  110.             break;
  111.         default:
  112.             bomb();
  113.         }
  114.         break;
  115.     default:
  116.         argc++;
  117.         goto endargs;
  118.     }
  119. endargs:
  120.     if (sflag) gtty(0,&tty);
  121.     mesg(0);    /* BLOCK OUT MESSAGES */
  122.     assylen=0;
  123.     assyline[0]='\0';
  124.     if (!argc) {
  125.         File=stdin;
  126.         readfile();
  127.     }
  128.     else while (--argc) {
  129.         File=fopen(*argv,"r");
  130.         if (NULL==File) {
  131.             fprintf(stderr,"roff: cannot read %s\n",*argv);
  132.             exit(1);
  133.         }
  134.         readfile();
  135.         fclose(File);
  136.         argv++;
  137.     }
  138.     writebreak();
  139.     endpage();
  140.     for (; o_sk; o_sk--) blankpage();
  141.     mesg(1);    /* ALLOW MESSAGES */
  142. }
  143.  
  144. mesg(f)
  145. int f;
  146. {
  147.     static int mode;
  148.     struct stat cbuf;
  149.     char *ttyname();
  150.  
  151.     if (!isatty(1)) return;
  152.     if (!f) {
  153.         fstat(1,&cbuf);
  154.         mode = cbuf.st_mode;
  155.         chmod(ttyname(1),mode & ~022);
  156.     }
  157.     else chmod(ttyname(1),mode);
  158. }
  159.  
  160. readfile()
  161. {
  162.     while (readline()) {
  163.         if (isrequest) continue;
  164.         if (center || !o_fi) {
  165.             if (assylen) writeline(0,1);
  166.             else blankline();
  167.         }
  168.     }
  169. }
  170.  
  171. readline()
  172. {
  173.     int startline, doingword;
  174.     isrequest = 0;
  175.     startline = 1;
  176.     doingword = 0;
  177.     c=suck();
  178.     if (c == '\n') {
  179.         o_sp = 1;
  180.         writebreak();
  181.         goto out;
  182.     }
  183.     else if (isspace(c)) writebreak();
  184.     for (;;) {
  185.         if (c==EOF) {
  186.             if (doingword) bumpword();
  187.             break;
  188.         }
  189.         if (c!=o_cc && o_ig) {
  190.             while (c!='\n' && c!=EOF) c=suck();
  191.             break;
  192.         }
  193.         if (isspace(c) && !doingword) {
  194.             startline=0;
  195.             switch (c) {
  196.             case ' ':
  197.                 assyline[assylen++]=' ';
  198.                 break;
  199.             case '\t':
  200.                 tabulate();
  201.                 break;
  202.             case '\n':
  203.                 goto out;
  204.             }
  205.             c = suck();
  206.             continue;
  207.         }
  208.         if (isspace(c) && doingword) {
  209.             bumpword();
  210.             if (c=='\t') tabulate();
  211.             else if (assylen) assyline[assylen++]=' ';
  212.             doingword=0;
  213.             if (c=='\n') break;
  214.         }
  215.         if (!isspace(c)) {
  216.             if (doingword) *holdp++ = o_ul? c|UNDERL: c;
  217.             else if (startline && c==o_cc && !o_li) {
  218.                 isrequest=1;
  219.                 return readreq();
  220.             }
  221.             else {
  222.                 doingword=1;
  223.                 holdp=holdword;
  224.                 *holdp++ = o_ul? c|UNDERL: c;
  225.             }
  226.         }
  227.         startline=0;
  228.         c = suck();
  229.     }
  230. out:
  231.     if (o_ul) o_ul--;
  232.     center=o_ce;
  233.     if (o_ce) o_ce--;
  234.     if (o_li) o_li--;
  235.     return c!=EOF;
  236. }
  237.  
  238. /*
  239.  *    bumpword - add word to current line.
  240.  */
  241.  
  242. bumpword()
  243. {
  244.     char *hc;
  245.     *holdp = '\0';
  246. /*
  247.  *    Tutelman's fix #1.
  248.  */
  249.     if (!o_fi) goto giveup;
  250. /*
  251.  *    We use a while-loop in case of ridiculously long words with
  252.  *    multiple hyphenation indicators.
  253.  */
  254.     if (assylen + reallen(holdword) > o_ll - IDTLEN) {
  255.         if (!o_hy) writeline(o_ad,0);
  256.         else while (assylen + reallen(holdword) > o_ll - IDTLEN) {
  257. /*
  258.  *    Try hyphenating it.
  259.  */
  260.             if (o_hc && strhas(holdword,o_hc)) {
  261. /*
  262.  *    There are hyphenation marks.  Use them!
  263.  */
  264.                 for (hc=strend(holdword); hc>=holdword; hc--) {
  265.                     if ((*hc&~UNDERL)!=o_hc) continue;
  266.                     *hc = '\0';
  267.                     if (assylen + reallen(holdword) + 1 >
  268.                     o_ll - IDTLEN) {
  269.                         *hc = o_hc;
  270.                         continue;
  271.                     }
  272. /*
  273.  *    Yay - it fits!
  274.  */
  275.                     dehyph(holdword);
  276.                     strcpy(&assyline[assylen],holdword);
  277.                     strcat(assyline,"-");
  278.                     assylen += strlen(holdword) + 1;
  279.                     strcpy(holdword,++hc);
  280.                     break;    /* STOP LOOKING */
  281.                 } /* for */
  282. /*
  283.  *    It won't fit, or we've succeeded in breaking the word.
  284.  */
  285.                 writeline(o_ad,0);
  286.                 if (hc<holdword) goto giveup;
  287.             }
  288.             else {
  289. /*
  290.  *    If no hyphenation marks, give up.
  291.  *    Let somebody else implement it.
  292.  */
  293.                 writeline(o_ad,0);
  294.                 goto giveup;
  295.             }
  296.         } /* while */
  297.     }
  298. giveup:
  299. /*
  300.  *    remove hyphenation marks, even if hyphenation is disabled.
  301.  */
  302.     if (o_hc) dehyph(holdword);
  303.     strcpy(&assyline[assylen],holdword);
  304.     assylen+=strlen(holdword);
  305.     holdp = holdword;
  306. }
  307.  
  308. /*
  309.  *    dehyph - remove hyphenation marks.
  310.  */
  311.  
  312. dehyph(s)
  313. char *s;
  314. {
  315.     char *t;
  316.     for (t=s; *s; s++) if ((*s&~UNDERL) != o_hc) *t++ = *s;
  317.     *t='\0';
  318. }
  319.  
  320. /*
  321.  *    reallen - length of a word, excluding hyphenation marks.
  322.  */
  323.  
  324. int
  325. reallen(s)
  326. char *s;
  327. {
  328.     register n;
  329.     n=0;
  330.     while (*s) n += (o_hc != (~UNDERL & *s++));
  331.     return n;
  332. }
  333.  
  334. tabulate()
  335. {
  336.     int j;
  337.     for (j=0; j<n_ta; j++) if (o_ta[j]-1>assylen+IDTLEN) {
  338.         for (; assylen+IDTLEN<o_ta[j]-1; assylen++)
  339.             assyline[assylen]=o_tc;
  340.         return;
  341.     }
  342.     /* NO TAB STOPS REMAIN */
  343.     assyline[assylen++]=o_tc;
  344. }
  345.  
  346. int
  347. readreq()
  348. {
  349.     char req[3];
  350.     int r, s;
  351.     if (skipsp()) return c!=EOF;
  352.     c=suck();
  353.     if (c==EOF || c=='\n') return c!=EOF;
  354.     if (c=='.') {
  355.         o_ig = 0;
  356.         do (c=suck());
  357.         while (c!=EOF && c!='\n');
  358.         if (depth) endmac();
  359.         return c!=EOF;
  360.     }
  361.     if (o_ig) {
  362.         while (c!=EOF && c!='\n') c=suck();
  363.         return c!=EOF;
  364.     }
  365.     req[0]=c;
  366.     c=suck();
  367.     if (c==EOF || c=='\n') req[1]='\0';
  368.     else req[1]=c;
  369.     req[2]='\0';
  370.     for (r=0; r<n_macros; r++) if (!strcmp(macro[r].mname,req)) {
  371.         submac(r);
  372.         goto reqflsh;
  373.     }
  374.     for (r=0; request[r]; r++) if (!strcmp(request[r],req)) break;
  375.     if (!request[r]) {
  376.         do (c=suck());
  377.         while (c!=EOF && c!='\n');
  378.         return c!=EOF;
  379.     }
  380.     switch (r) {
  381.     case 0: /* ad */
  382.         o_ad=1;
  383.         writebreak();
  384.         break;
  385.     case 1: /* ar */
  386.         o_ro=0;
  387.         break;
  388.     case 2: /* bl */
  389.         nread(&o_bl);
  390.         writebreak();
  391.         break;
  392.     case 3: /* bp */
  393.     case 37: /* pa */
  394.         c=snread(&r,&s,1);
  395. /*
  396.  *    Tutelman's fix #2 - the signs were reversed!
  397.  */
  398.         if (s>0) o_bp=page_no+r;
  399.         else if (s<0) o_bp=page_no-r;
  400.         else o_bp=r;
  401.         writebreak();
  402.         if (line_no) {
  403.             endpage();
  404.             beginpage();
  405.         }
  406.         break;
  407.     case 4: /* br */
  408.         writebreak();
  409.         break;
  410.     case 5: /* cc */
  411.         c=cread(&o_cc);
  412.         break;
  413.     case 6: /* ce */
  414.         nread(&o_ce);
  415.         writebreak();
  416.         break;
  417.     case 7: /* de */
  418.         defmac();
  419.         break;
  420.     case 8: /* ds */
  421.         o_ls=2;
  422.         writebreak();
  423.         break;
  424.     case 9: /* ef */
  425.         c=tread(efoot);
  426.         break;
  427.     case 10: /* eh */
  428.         c=tread(ehead);
  429.         break;
  430.     case 11: /* fi */
  431.         o_fi=1;
  432.         writebreak();
  433.         break;
  434.     case 12: /* fo */
  435.         c=tread(efoot);
  436.         strcpy(ofoot,efoot);
  437.         break;
  438.     case 13: /* hc */
  439.         c=cread(&o_hc);
  440.         break;
  441.     case 14: /* he */
  442.         c=tread(ehead);
  443.         strcpy(ohead,ehead);
  444.         break;
  445.     case 15: /* hx */
  446.         o_hx=1;
  447.         break;
  448.     case 16: /* hy */
  449.         nread(&o_hy);
  450.         break;
  451.     case 17: /* ig */
  452.         o_ig=1;
  453.         break;
  454.     case 18: /* in */
  455.         writebreak();
  456.         snset(&o_in);
  457.         o_ix = -1;
  458.         break;
  459.     case 19: /* ix */
  460.         snset(&o_ix);
  461.         if (!n_outwords) o_in=o_ix;
  462.         break;
  463.     case 20: /* li */
  464.         nread(&o_li);
  465.         break;
  466.     case 21: /* ll */
  467.         snset(&o_ll);
  468.         break;
  469.     case 22: /* ls */
  470.         snset(&o_ls);
  471.         break;
  472.     case 23: /* m1 */
  473.         nread(&o_m1);
  474.         break;
  475.     case 24: /* m2 */
  476.         nread(&o_m2);
  477.         break;
  478.     case 25: /* m3 */
  479.         nread(&o_m3);
  480.         break;
  481.     case 26: /* m4 */
  482.         nread(&o_m4);
  483.         break;
  484.     case 27: /* n1 */
  485.         o_n1=1;
  486.         break;
  487.     case 28: /* n2 */
  488.         nread(&o_n2);
  489.         break;
  490.     case 29: /* na */
  491.         o_ad=0;
  492.         writebreak();
  493.         break;
  494.     case 30: /* ne */
  495.         nread(&r);
  496.         if (line_no+(r-1)*o_ls+1 > TXTLEN) {
  497.             writebreak();
  498.             endpage();
  499.             beginpage();
  500.         }
  501.         break;
  502.     case 31: /* nf */
  503.         o_fi=0;
  504.         writebreak();
  505.         break;
  506.     case 32: /* ni */
  507.         snset(&o_ni);
  508.         break;
  509.     case 33: /* nn */
  510.         snset(&o_nn);
  511.         break;
  512.     case 34: /* nx */
  513.         do_nx();
  514.         c='\n';    /* SO WE DON'T FLUSH THE FIRST LINE */
  515.         break;
  516.     case 35: /* of */
  517.         c=tread(ofoot);
  518.         break;
  519.     case 36: /* oh */
  520.         c=tread(ohead);
  521.         break;
  522.     case 38: /* pl */
  523.         snset(&o_pl);
  524.         break;
  525.     case 39: /* po */
  526.         snset(&o_po);
  527.         break;
  528.     case 40: /* ro */
  529.         o_ro=1;
  530.         break;
  531.     case 41: /* sk */
  532.         nread(&o_sk);
  533.         break;
  534.     case 42: /* sp */
  535.         nread(&o_sp);
  536.         writebreak();
  537.         break;
  538.     case 43: /* ss */
  539.         writebreak();
  540.         o_ls=1;
  541.         break;
  542.     case 44: /* ta */
  543.         do_ta();
  544.         break;
  545.     case 45: /* tc */
  546.         c=cread(&o_tc);
  547.         break;
  548.     case 46: /* ti */
  549.         writebreak();
  550.         c=snread(&r,&s,0);
  551.         if (s>0) o_ti=o_in+r;
  552.         else if (s<0) o_ti=o_in-r;
  553.         else o_ti=r;
  554.         break;
  555.     case 47: /* tr */
  556.         do_tr();
  557.         break;
  558.     case 48: /* ul */
  559.         nread(&o_ul);
  560.         break;
  561.     }
  562. reqflsh:
  563.     while (c!=EOF && c!='\n') c=suck();
  564.     return c!=EOF;
  565. }
  566.  
  567. snset(par)
  568. int *par;
  569. {
  570.     int r, s;
  571.     c=snread(&r,&s,0);
  572.     if (s>0) *par+=r;
  573.     else if (s<0) *par-=r;
  574.     else *par=r;
  575. }
  576.  
  577. tread(s)
  578. char *s;
  579. {
  580.     int leadbl;
  581.     leadbl=0;
  582.     for (;;) {
  583.         c=suck();
  584.         if (c==' ' && !leadbl) continue;
  585.         if (c==EOF || c=='\n') {
  586.             *s = '\0';
  587.             return c;
  588.         }
  589.         *s++ = c;
  590.         leadbl++;
  591.     }
  592. }
  593.  
  594. nread(i)
  595. int *i;
  596. {
  597.     int f;
  598.     f=0;
  599.     *i=0;
  600.     if (!skipsp()) for (;;) {
  601.         c=suck();
  602.         if (c==EOF) break;
  603.         if (isspace(c)) break;
  604.         if (isdigit(c)) {
  605.             f++;
  606.             *i = *i*10 + c - '0';
  607.         }
  608.         else break;
  609.     }
  610.     if (!f) *i=1;
  611. }
  612.  
  613. int
  614. snread(i,s,sdef)
  615. int *i, *s, sdef;
  616. {
  617.     int f;
  618.     f = *i = *s = 0;
  619.     for (;;) {
  620.         c=suck();
  621.         if (c==EOF || c=='\n') break;
  622.         if (isspace(c)) {
  623.             if (f) break;
  624.             else continue;
  625.         }
  626.         if (isdigit(c)) {
  627.             f++;
  628.             *i = *i*10 + c - '0';
  629.         }
  630.         else if ((c=='+' || c=='-') && !f) {
  631.             f++;
  632.             *s = c=='+' ? 1 : -1;
  633.         }
  634.         else break;
  635.     }
  636.     while (c!=EOF && c!='\n') c=suck();
  637.     if (!f) {
  638.         *i=1;
  639.         *s=sdef;
  640.     }
  641.     return c;
  642. }
  643.  
  644. int
  645. cread(k)
  646. int *k;
  647. {
  648.     int u;
  649.     *k = -1;
  650.     for (;;) {
  651.         u=suck();
  652.         if (u==EOF || u=='\n') return u;
  653.         if (isspace(u)) continue;
  654.         if (*k < 0) *k=u;
  655.     }
  656. }
  657.  
  658. defmac()
  659. {
  660.     int i;
  661.     char newmac[3], *nm;
  662.     if (skipsp()) return;
  663.     nm=newmac;
  664.     if (!Macwrite) openmac();
  665.     *nm++ = suck();
  666.     c=suck();
  667.     if (c!=EOF && c!='\n' && c!=' ' && c!='\t') *nm++ = c;
  668.     *nm = '\0';
  669.         /* KILL OLD DEFINITION IF ANY */
  670.     for (i=0; i<n_macros; i++) if (!strcmp(newmac,macro[i].mname)) {
  671.         macro[i].mname[0]='\0';
  672.         break;
  673.     }
  674.     macro[n_macros].moff=ftell(Macwrite);
  675.     strcpy(macro[n_macros++].mname,newmac);
  676.     while (c!=EOF && c!='\n') c=suck();    /* FLUSH HEADER LINE */
  677.     while (copyline());
  678.     fflush(Macwrite);
  679. }
  680.  
  681. openmac()
  682. {
  683.     if (NULL==(Macwrite=fopen(mktemp(mfilnam),"w"))) {
  684.         fprintf(stderr,"roff: cannot open temp file\n");
  685.         exit(1);
  686.     }
  687.     Macread=fopen(mfilnam,"r");
  688.     unlink(mfilnam);
  689. }
  690.  
  691. int
  692. copyline()
  693. {
  694.     int n, first, second;
  695.     if (c==EOF) {
  696.         fprintf(Macwrite,"..\n");
  697.         return 0;
  698.     }
  699.     n=0;
  700.     first=1;
  701.     second=0;
  702.     for (;;) {
  703.         c=suck();
  704.         if (c==EOF) {
  705.             if (!first) putc('\n',Macwrite);
  706.             return 0;
  707.         }
  708.         if (c=='\n') {
  709.             putc('\n',Macwrite);
  710.             return n!=2;
  711.         }
  712.         if (first && c=='.') n++;
  713.         else if (second && n==1 && c=='.') n++;
  714.         putc(c,Macwrite);
  715.         second=first;
  716.         first=0;
  717.     }
  718. }
  719.  
  720. submac(r)
  721. int r;
  722. {
  723.     while (c!=EOF && c!='\n') c=suck();
  724.     if (depth) teller[depth-1]=ftell(Macread);
  725.     else {
  726.         Save = File;
  727.         File = Macread;
  728.     }
  729.     depth++;
  730.     fseek(Macread,macro[r].moff,0);
  731. }
  732.  
  733. endmac()
  734. {
  735.     depth--;
  736.     if (depth) fseek(Macread,teller[depth-1],0);
  737.     else File = Save;
  738.     c='\n';
  739. }
  740.  
  741. do_ta()
  742. {
  743.     int v;
  744.     n_ta = 0;
  745.     for (;;) {
  746.         nread(&v);
  747.         if (v==1) return;
  748.         else o_ta[n_ta++]=v;
  749.         if (c=='\n' || c==EOF) break;
  750.     }
  751. }
  752.  
  753. do_tr()
  754. {
  755.     char *t;
  756.     t = &o_tr[0][0];
  757.     *t='\0';
  758.     if (skipsp()) return;
  759.     for (;;) {
  760.         c=suck();
  761.         if (c==EOF || c=='\n') break;
  762.         *t++ = c;
  763.     }
  764.     *t = '\0';
  765. }
  766.  
  767. do_nx()
  768. {
  769.     char fname[100], *f;
  770.     f=fname;
  771.     if (skipsp()) return;
  772.     for (;;) switch(c=suck()) {
  773.     case EOF:
  774.     case '\n':
  775.     case ' ':
  776.     case '\t':
  777.         if (f==fname) return;
  778.         goto got_nx;
  779.     default:
  780.         *f++ = c;
  781.     }
  782. got_nx:
  783.     fclose(File);
  784.     *f = '\0';
  785.     if (!(File=fopen(fname,"r"))) {
  786.         fprintf(stderr,"roff: cannot read %s\n",fname);
  787.         exit(1);
  788.     }
  789. }
  790.  
  791. int
  792. skipsp()
  793. {
  794.     for (;;) switch(c=suck()) {
  795.     case EOF:
  796.     case '\n':
  797.         return 1;
  798.     case ' ':
  799.     case '\t':
  800.         continue;
  801.     default:
  802.         ungetc(c,File);
  803.         return 0;
  804.     }
  805. }
  806.  
  807. writebreak()
  808. {
  809.     int q;
  810.     if (assylen) writeline(0,1);
  811.     q = TXTLEN;
  812.     if (o_bl) {
  813.         if (o_bl + line_no > q) {
  814.             endpage();
  815.             beginpage();
  816.         }
  817.         for (; o_bl; o_bl--) blankline();
  818.     }
  819.     else if (o_sp) {
  820.         if (o_sp + line_no > q) newpage();
  821.         else if (line_no) for (; o_sp; o_sp--) blankline();
  822.     }
  823. }
  824.  
  825. blankline()
  826. {
  827.     if (line_no >= TXTLEN) newpage();
  828.     if (o_n2) o_n2++;
  829.     spit('\n');
  830.     line_no++;
  831. }
  832.  
  833. writeline(adflag,flushflag)
  834. int adflag, flushflag;
  835. {
  836.     int j, q;
  837.     char lnstring[7];
  838.     for (j=assylen-1; j; j--) {
  839.         if (assyline[j]==' ') assylen--;
  840.         else break;
  841.     }
  842.     q = TXTLEN;
  843.     if (line_no >= q) newpage();
  844.     for (j=0; j<o_po; j++) spit(' ');
  845.     if (o_n1) {
  846.         if (o_nn) for (j=0; j<o_ni+4; j++) spit(' ');
  847.         else {
  848.             for (j=0; j<o_ni; j++) spit(' ');
  849.             sprintf(lnstring,"%3d ",line_no+1);
  850.             spits(lnstring);
  851.         }
  852.     }
  853.     if (o_n2) {
  854.         if (o_nn) for (j=0; j<o_ni+4; j++) spit(' ');
  855.         else {
  856.             for (j=0; j<o_ni; j++) spit(' ');
  857.             sprintf(lnstring,"%3d ",o_n2++);
  858.             spits(lnstring);
  859.         }
  860.     }
  861.     if (o_nn) o_nn--;
  862.     if (center) for (j=0; j<(o_ll-assylen+1)/2; j++) spit(' ');
  863.     else for (j=0; j<IDTLEN; j++) spit(' ');
  864.     if (adflag && !flushflag) fillline();
  865.     for (j=0; j<assylen; j++) spit(assyline[j]);
  866.     spit('\n');
  867.     assylen=0;
  868.     assyline[0]='\0';
  869.     line_no++;
  870.     for (j=1; j<o_ls; j++) if (line_no <= q) blankline();
  871.     if (!flushflag)  {
  872.         if (o_hc) dehyph(holdword);
  873.         strcpy(assyline,holdword);
  874.         assylen=strlen(holdword);
  875.         *holdword='\0';
  876.         holdp=holdword;
  877.     }
  878.     if (o_ix>=0) o_in=o_ix;
  879.     o_ix = o_ti = -1;
  880. }
  881.  
  882. fillline()
  883. {
  884.     int excess, j, s, inc, spaces;
  885.     adjtoggle^=1;
  886.     if (!(excess = o_ll - IDTLEN - assylen)) return;
  887.     if (excess < 0) {
  888.         fprintf(stderr,"roff: internal error #2 [%d]\n",excess);
  889.         exit(1);
  890.     }
  891.     for (j=2;; j++) {
  892.         if (adjtoggle) {
  893.             s=0;
  894.             inc = 1;
  895.         }
  896.         else {
  897.             s=assylen-1;
  898.             inc = -1;
  899.         }
  900.         spaces=0;
  901.         while (s>=0 && s<assylen) {
  902.             if (assyline[s]==' ') spaces++;
  903.             else {
  904.                 if (0<spaces && spaces<j) {
  905.                     insrt(s-inc);
  906.                     if (inc>0) s++;
  907.                     if (!--excess) return;
  908.                 }
  909.                 spaces=0;
  910.             }
  911.             s+=inc;
  912.         }
  913.     }
  914. }
  915.  
  916. insrt(p)
  917. int p;
  918. {
  919.     int i;
  920.     for (i=assylen; i>p; i--) assyline[i]=assyline[i-1];
  921.     assylen++;
  922. }
  923.  
  924. newpage()
  925. {
  926.     if (page_no >= 0) endpage();
  927.     else page_no=1;
  928.     for (; o_sk; o_sk--) blankpage();
  929.     beginpage();
  930. }
  931.  
  932. beginpage()
  933. {
  934.     int i;
  935.     if (sflag) waitawhile();
  936.     for (i=0; i<o_m1; i++) spit('\n');
  937.     writetitle(page_no&1? ohead: ehead);
  938.     for (i=0; i<o_m2; i++) spit('\n');
  939.     line_no=0;
  940. }
  941.  
  942. endpage()
  943. {
  944.     int i;
  945.     for (i=line_no; i<TXTLEN; i++) blankline();
  946.     for (i=0; i<o_m3; i++) spit('\n');
  947.     writetitle(page_no&1? ofoot: efoot);
  948.     for (i=0; i<o_m4; i++) spit('\n');
  949.     if (o_bp < 0) page_no++;
  950.     else {
  951.         page_no = o_bp;
  952.         o_bp = -1;
  953.     }
  954. }
  955.  
  956. blankpage()
  957. {
  958.     int i;
  959.     if (sflag) waitawhile();
  960.     for (i=0; i<o_m1; i++) spit('\n');
  961.     writetitle(page_no&1? ohead: ehead);
  962.     for (i=0; i<o_m2; i++) spit('\n');
  963.     for (i=0; i<TXTLEN; i++) spit('\n');
  964.     for (i=0; i<o_m3; i++) spit('\n');
  965.     writetitle(page_no&1? ofoot: efoot);
  966.     page_no++;
  967.     for (i=0; i<o_m4; i++) spit('\n');
  968.     line_no=0;
  969. }
  970.  
  971. waitawhile()
  972. {
  973.     int nix(), oldflags;
  974.     if (isatty(0)) {
  975.         oldflags=tty.sg_flags;
  976.         tty.sg_flags &= ~ECHO;    /* DON'T ECHO THE RUBOUT */
  977.         stty(0,&tty);
  978.     }
  979.     signal(SIGINT,nix);
  980.     pause();
  981.     if (isatty(0)) {
  982.         tty.sg_flags = oldflags;
  983.         stty(0,&tty);
  984.     }
  985. }
  986.  
  987. nix()
  988. {}
  989.  
  990. writetitle(t)
  991. char *t;
  992. {
  993.     char d, *pst, *pgform();
  994.     int j, l, m, n;
  995.     d = *t;
  996.     if (o_hx || !d) {
  997.         spit('\n');
  998.         return;
  999.     }
  1000.     pst=pgform();
  1001.     for (j=0; j<o_po; j++) spit(' ');
  1002.     l=titlen(++t,d,strlen(pst));
  1003.     while (*t && *t!=d) {
  1004.         if (*t=='%') spits(pst);
  1005.         else spit(*t);
  1006.         t++;
  1007.     }
  1008.     if (!*t) {
  1009.         spit('\n');
  1010.         return;
  1011.     }
  1012.     m=titlen(++t,d,strlen(pst));
  1013.     for (j=l; j<(o_ll-m)/2; j++) spit(' ');
  1014.     while (*t && *t!=d) {
  1015.         if (*t=='%') spits(pst);
  1016.         else spit(*t);
  1017.         t++;
  1018.     }
  1019.     if (!*t) {
  1020.         spit('\n');
  1021.         return;
  1022.     }
  1023.     if ((o_ll-m)/2 > l) m+=(o_ll-m)/2;
  1024.     else m+=l;
  1025.     n=titlen(++t,d,strlen(pst));
  1026.     for (j=m; j<o_ll-n; j++) spit(' ');
  1027.     while (*t && *t!=d) {
  1028.         if (*t=='%') spits(pst);
  1029.         else spit(*t);
  1030.         t++;
  1031.     }
  1032.     spit('\n');
  1033. }
  1034.  
  1035. char *
  1036. pgform()
  1037. {
  1038.     static char pst[11];
  1039.     int i;
  1040.     if (o_ro) {
  1041.         *pst='\0';
  1042.         i=page_no;
  1043.         if (i>=400) {
  1044.             strcat(pst,"cd");
  1045.             i-=400;
  1046.         }
  1047.         while (i>=100) {
  1048.             strcat(pst,"c");
  1049.             i-=100;
  1050.         }
  1051.         if (i>=90) {
  1052.             strcat(pst,"xc");
  1053.             i-=90;
  1054.         }
  1055.         if (i>=50) {
  1056.             strcat(pst,"l");
  1057.             i-=50;
  1058.         }
  1059.         if (i>=40) {
  1060.             strcat(pst,"xl");
  1061.             i-=40;
  1062.         }
  1063.         while (i>=10) {
  1064.             strcat(pst,"x");
  1065.             i-=10;
  1066.         }
  1067.         if (i>=9) {
  1068.             strcat(pst,"ix");
  1069.             i-=9;
  1070.         }
  1071.         if (i>=5) {
  1072.             strcat(pst,"v");
  1073.             i-=5;
  1074.         }
  1075.         if (i>=4) {
  1076.             strcat(pst,"iv");
  1077.             i-=4;
  1078.         }
  1079.         while (i--) strcat(pst,"i");
  1080.     }
  1081.     else sprintf(pst,"%d",page_no);
  1082.     return pst;
  1083. }
  1084.  
  1085. int
  1086. titlen(t,c,k)
  1087. char *t, c;
  1088. int k;
  1089. {
  1090.     int q;
  1091.     q=0;
  1092.     while (*t && *t!=c) q += *t++ == '%' ? k : 1;
  1093.     return q;
  1094. }
  1095.  
  1096. spits(s)
  1097. char *s;
  1098. {
  1099.     while (*s) spit(*s++);
  1100. }
  1101.  
  1102. spit(c)
  1103. char c;
  1104. {
  1105.     static int col_no, n_blanks;
  1106.     int ulflag;
  1107.     char *t;
  1108.     ulflag=c&UNDERL;
  1109.     c&=~UNDERL;
  1110.     for (t = (char *)o_tr; *t; t++) if (*t++==c) {
  1111. /*
  1112.  *    fix - last char translates to space.
  1113.  */
  1114.         c = *t? *t: ' ';
  1115.         break;
  1116.     }
  1117.     if (page_no < startpage || (stoppage && page_no > stoppage)) return;
  1118.     if (c != ' ' && c != '\n' && n_blanks) {
  1119.         if (hflag && n_blanks>1)
  1120.         while (col_no/8 < (col_no+n_blanks)/8) {
  1121.             putc('\t',stdout);
  1122.             n_blanks-= 8 - (col_no & 07);
  1123.             col_no = 8 + col_no & ~07;
  1124.         }
  1125.         for (; n_blanks; n_blanks--) {
  1126.             putc(' ',stdout);
  1127.             col_no++;
  1128.         }
  1129.     }
  1130.     if (ulflag && isalnum(c)) fputs("_\b",stdout);
  1131.     if (c == ' ') n_blanks++;
  1132.     else {
  1133.         putc(c,stdout);
  1134.         col_no++;
  1135.     }
  1136.     if (c == '\n') {
  1137.         col_no=0;
  1138.         n_blanks=0;
  1139.     }
  1140. }
  1141.  
  1142. int
  1143. suck()
  1144. {
  1145.     for (;;) {
  1146.         c=getc(File);
  1147.         if (islegal(c)) return c;
  1148.     }
  1149. }
  1150.  
  1151. /*
  1152.  *    strhas - does string have character?  Allow UNDERL flag.
  1153.  */
  1154.  
  1155. char *
  1156. strhas(p,c)
  1157. char *p, c;
  1158. {
  1159.     for (; *p; p++) if ((*p&~UNDERL)==c) return p;
  1160.     return NULL;
  1161. }
  1162.  
  1163. /*
  1164.  *    strend - find NULL at end of string.
  1165.  */
  1166.  
  1167. char *
  1168. strend(p)
  1169. char *p;
  1170. {
  1171.     while (*p++);
  1172.     return p;
  1173. }
  1174.  
  1175. /*
  1176.  *    isspace, isalnum, isdigit, islegal - classify a character.
  1177.  *    We could just as well use <ctype.h> if it didn't vary from
  1178.  *    one version of Unix to another.  As it is, these routines
  1179.  *    must be modified for weird character sets, like EBCDIC and
  1180.  *    CDC Scientific.
  1181.  */
  1182.  
  1183. int
  1184. isspace(c)
  1185. int c;
  1186. {
  1187.     char *s;
  1188.     for (s=spacechars; *s; s++) if (*s==c) return 1;
  1189.     return 0;
  1190. }
  1191.  
  1192. int
  1193. isalnum(c)
  1194. int c;
  1195. {
  1196.     return (c>='A'&&c<='Z') || (c>='a'&&c<='z') || (c>='0'&&c<='9');
  1197. }
  1198.  
  1199. int
  1200. isdigit(c)
  1201. int c;
  1202. {
  1203.     return c>='0' && c<='9';
  1204. }
  1205.  
  1206. int
  1207. islegal(c)
  1208. int c;
  1209. {
  1210.     return c>=' ' && c<='~' || isspace(c) || c=='\n' || c==EOF;
  1211. }
  1212.  
  1213. bomb()
  1214. {
  1215.     fprintf(stderr,"usage: roff [+00] [-00] [-s] [-h] file ...\n");
  1216.     exit(1);
  1217. }
  1218. -- 
  1219. Col. G. L. Sicherman
  1220. ...{rocksvax|decvax}!sunybcs!colonel
  1221.