home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 September / Simtel20_Sept92.cdr / msdos / printer / pcroff.arc / SOURCE.ARC / PCROFF.C < prev    next >
Text File  |  1985-03-24  |  35KB  |  1,327 lines

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