home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 331_01 / roff.c < prev    next >
Text File  |  1990-05-31  |  16KB  |  657 lines

  1. /*
  2. HEADER
  3.  */
  4. /* Reform paragraphs.  Dot commands in the text are interpreted and
  5.  * left in the result.  Adapted from CUG .. 3/15/87 G. Osborn.
  6.  *
  7.  * All automatic pagination output is suppressed until a .he command
  8.  * is processed.  The text portion of the .he command may be null.
  9.  *
  10.  * dot commands to not contribute to the line count if left
  11.  * in the output.
  12.  */
  13.  
  14. #include <ctype.h>
  15. #include <stdio.h>
  16. #include "ged.h"
  17.  
  18.  
  19.  
  20. #define PAGEWIDTH 72    /* default page width */
  21. #define PAGELINES  66   /* default page length */
  22. #define PAGECHAR '#'    /* page number escape char */
  23.  
  24. static int fill;                 /* in fill mode if YES */
  25. static int lsval;                /* current line spacing */
  26. static int inval;                /* current indent; >= 0 */
  27. static int rmval;                /* current right margin */
  28. static int ceval;                /* number of lines to center */
  29. static int ulval;                /* number of lines to underline */
  30. static int curpag;               /* current output page number */
  31. static int newpag;               /* next output page number */
  32. static int pageline;             /* next line to be printed */
  33. static int plval;                /* page length in lines */
  34. static int m1val;                /* top margin, including header */
  35. static int m2val;                /* margin after header */
  36. static int m3val;                /* margin after last text line */
  37. static int m4val;                /* bottom margin, including footer */
  38. static int bottom;               /* last live line on page: */
  39. static int dir;                  /* directions flag */
  40. static char *header;             /* top of page title */
  41. static char *footer;             /* bottom of page title */
  42. static char *outbuf;             /* lines to be filled go here */
  43. static int inline, outline;
  44. static int outp;
  45. static int para1;                 /* excess paragraph indentation of 1st line of paragraph */
  46. static int paraphase;
  47.  
  48. /* ----------------------------- */
  49. /* keep dot commands if keep not 0.
  50.  */
  51. roff(keep)
  52. int keep;
  53. {
  54.     register i;
  55.     char inbuf[LLIM];
  56.     int c, ncline, msgline, lastlsav;
  57.     char *sp;
  58.     char *getline();
  59.     char temp[81];
  60.     char buf1[LLIM];
  61.     char buf2[LLIM];
  62.     char buf3[LLIM];
  63.  
  64.  
  65. /* the large buffers are automatic so that they do not occupy permanent
  66.  * storage.  The pointers to them are global within this file.
  67.  */
  68.     header = &buf1[0];
  69.     footer = &buf2[0];
  70.     outbuf = &buf3[0];
  71.  
  72. /* don't retain memory of state after previous call */
  73.     fill = YES;
  74.     lsval = 1;
  75.     inval = 0;
  76.     rmval = PAGEWIDTH;
  77.     ceval = 0;
  78.     ulval = 0;
  79.     curpag = 0;
  80.     newpag = 1;
  81.     pageline = 0;
  82.     plval = PAGELINES;
  83.     m1val = 2;
  84.     m2val = 3;
  85.     m3val = 2;
  86.     m4val = 3;
  87.     bottom = plval - m3val - m4val; /* invariant */
  88.     header[0] = '\0';
  89.     footer[0] = '\0';
  90.  
  91.  
  92. /* Old lines are deleted in blocks of 100 because deltp is slow for large
  93.  * documents.  Its execution time is independent of the number of
  94.  * lines deleted.
  95.  */
  96.     inline = 1;
  97.     lastlsav = lastl;
  98.     msgline = 0;
  99.     outline = lastl;
  100.     outbuf[0] = '\0';
  101.     outp = 0;
  102.     paraphase = 0;    /* expecting first line of paragraph */
  103.  
  104.     while (inline <= lastlsav) {
  105.         strcpy(inbuf,getline(inline));
  106.         if ( (inline + msgline ) == 1 || (inline % 100) == 0) {
  107.             sprintf(temp,"Reforming per dot commands.  Line %d", inline+msgline);
  108.             putmess(temp);
  109.         }
  110.         if ((inline % 100) == 0) {
  111.             deltp(1,100);
  112.             inline -= 100;
  113.             lastlsav -= 100;
  114.             outline -= 100;
  115.             msgline += 100;
  116.         }
  117.         if (inline + msgline == cline)
  118.             ncline = outline - lastlsav;
  119.         inline++;
  120.  
  121. /* it is necessary to flush the output buffer before dot commands
  122.  * if they are left in the output.
  123.  */
  124.         if (inbuf[0] == '.' && isalpha(inbuf[1]) ) {
  125.             if (keep) {
  126.                 putwrd("");   /* flush the output buffer */
  127.                 inject(outline++,inbuf);  /* leave the dot commands in for further editing */
  128.             }
  129.             command(inbuf);
  130.         }
  131.         else {
  132.             proctext(inbuf);
  133.         }
  134.     }
  135.     putwrd("");   /* round it out */
  136.     space(10000);
  137.  
  138.     if (lastlsav > 0)
  139.         deltp(1,lastlsav);  /* delete the last of the old */
  140.  
  141.     plast = -1;
  142.     moveline (ncline-cline);  /* go back to the original point, which is not now at the same line number */
  143.     blankedmess = YES;
  144.     return;
  145. }
  146.  
  147.  
  148.  
  149.  
  150.  
  151. /* perform formatting command */
  152.  
  153. command(buf)
  154. char *buf;
  155. {
  156.     int val, spval;
  157.     char *argtyp;
  158.  
  159.     val = getval(buf,argtyp);  /* get numerical argument and type */
  160. /* begin page */
  161.     if (lookup(buf, "bp")) {
  162.         if (pageline > 0)
  163.             space(10000);   /* maxint overflows */
  164.         set(&curpag, val, argtyp, curpag+1, -MAXINT, MAXINT);
  165.         newpag = curpag;
  166.     }
  167. /* break */
  168.     else if (lookup(buf,"br"))
  169.         putwrd("");
  170. /* center */
  171.     else if (lookup(buf,"ce")) {
  172.         putwrd("");
  173.         set(&ceval,val,argtyp,1,0,MAXINT);
  174.     }
  175. /* fill */
  176.     else if (lookup(buf,"fi")) {
  177.         putwrd("");
  178.         fill = YES;
  179.     }
  180. /* footnote */
  181.     else if (lookup(buf,"fo")) {
  182.         putwrd("");
  183.         strcpy(footer,buf+3);
  184.     }
  185. /* header */
  186.     else if (lookup(buf,"he")) {
  187.         putwrd("");
  188.         strcpy(header,buf+3);
  189.         if (header[0] == '\0')
  190.             strcpy(header," ");   /* activate pagination */
  191.     }
  192. /* indent */
  193.     else if (lookup(buf,"in")) {
  194.         set(&inval, val, argtyp, 0, 0, rmval-1);
  195.     }
  196.     else if (lookup(buf,"ls"))
  197.         set(&lsval,val,argtyp,1,1,MAXINT);
  198.  
  199. /* need at least n lines before new page */
  200.     else if (lookup(buf, "ne")) {
  201.         if (val + pageline - 1  > bottom)
  202.             space(10000);
  203.     }
  204.     else if (lookup(buf,"nf")) {
  205.         putwrd("");  /* runout */
  206.         fill = NO;
  207.     }
  208.     else if (lookup(buf,"pl")) {
  209.         set(&plval, val, argtyp, PAGELINES, m1val+m2val+m3val+m4val+1, MAXINT);
  210.         bottom=plval-m3val-m4val;
  211.     }
  212.     else if (lookup(buf,"rm")) {
  213.         putwrd("");
  214.         set(&rmval, val, argtyp, PAGEWIDTH, inval+1, MAXINT);
  215.     }
  216.     else if (lookup(buf,"sp")) {
  217.         set(&spval,val,argtyp,1,0,MAXINT);
  218.         putwrd("");
  219.         space(spval);
  220.     }
  221.     else if (lookup(buf,"ul"))
  222.         set(&ulval,val,argtyp,0,1,MAXINT);
  223.     else
  224.         return;    /* ignore unknown commands */
  225. }
  226.  
  227.  
  228. /* lookup routine for commands */
  229.  
  230. lookup(buf,string)
  231. char *buf, *string;
  232. {
  233.     return (buf[1] == string[0]) && (buf[2] == string[1]);
  234. }
  235.  
  236.  
  237. /* evaluate optional numeric argument */
  238.  
  239. getval(buf,argtyp)
  240. char *buf, *argtyp;
  241. {
  242.     int i;
  243.  
  244.     i = 3;
  245. /* ..find argument.. */
  246.     while (buf[i] == ' ' || buf[i] == '\t')
  247.         ++i;
  248.     *argtyp = buf[i];
  249.     if (*argtyp == '+' || *argtyp=='-')
  250.         i++;
  251.  
  252.     return(atoi(buf+i));
  253. }
  254.  
  255.  
  256. /* set parameter and check range */
  257.  
  258. set(param,val,argtyp,defval,minval,maxval)
  259. int *param,val,defval,minval,maxval;
  260. char *argtyp;
  261. {
  262.     if (*argtyp == '\0')
  263.         *param = defval;
  264.     else if (*argtyp == '+')
  265.         *param += val;
  266.     else if (*argtyp == '-')
  267.         *param -= val;
  268.     else
  269.         *param = val;
  270.  
  271.     *param = min(*param,maxval);
  272.     *param = max(*param,minval);
  273. }
  274.  
  275. /* ------------- reformat text lines ------------------- */
  276.  
  277. proctext(inbuf)
  278. char *inbuf;
  279. {
  280.     char wrdbuf[LLIM];
  281.     char *nl;
  282.     int save, inpoint;
  283.     int i, j;
  284.  
  285.  
  286.     for (inpoint = 0; inbuf[inpoint] == ' '; inpoint++)
  287.         ;
  288.     if (fill) {
  289.  
  290. /* determine additional indentation for first line of paragraph, if any */
  291.         if (inbuf[0] == '\0') {
  292.             paraphase = 0;    /* looking for 1st line of paaragraph */
  293.         }
  294.         else if (paraphase == 0) {
  295.             paraphase = 1;
  296.             if (inline <= lastl) {   /* use preceeding value if last line */
  297.                 nl = getline(inline);   /* next line */
  298.                 for (j = 0; nl[j] == ' '; j++)
  299.                     ;
  300.                 para1 = max(inpoint - j, 0);
  301.             }
  302.         }
  303.     }
  304.     if (ulval > 0) {
  305.         underl(inbuf, wrdbuf, LLIM);
  306.         ulval--;
  307.     }
  308.     if (ceval > 0) {   /* nofill lines can be centered */
  309.         paraphase = 0;
  310.         putwrd("");
  311.         save = inval;
  312.         inval = max( inval + (rmval - inval)/2 - width(inbuf+inpoint)/2 -1, 0);
  313.         put(inbuf+inpoint);
  314.         inval = save;
  315.         ceval--;
  316.         return;
  317.     }
  318.     if (!fill) {
  319.         paraphase = 0;
  320.         putwrd("");
  321.         put(inbuf);
  322.     }
  323.     else if (inbuf[0] == '\0') {
  324.         putwrd("");
  325.         put(inbuf);
  326.     }
  327.     else {
  328.         while (getwrd(inbuf, &inpoint, wrdbuf) > 0)
  329.             putwrd(wrdbuf);
  330.     }
  331.     return;
  332. }
  333.  
  334.  
  335. /* put out line with proper spacing and indenting */
  336.  
  337. put(buf)
  338. char *buf;
  339. {
  340.     register i, j;
  341.     char temp[LLIM];
  342.  
  343.     if (pageline == 0 || pageline > bottom)
  344.         if (header[0] != '\0')
  345.             phead();
  346.  
  347.     i = 0;
  348.     while (i < inval)   /* indent */
  349.         temp[i++] = ' ';
  350.  
  351. /* optional extra indentation for first line of paragraph.
  352.  */
  353.     if (paraphase == 1) {
  354.         for (j = 0; j < para1; j++)
  355.             temp[i++] = ' ';  /* i continued from preceeding loop */
  356.         paraphase = 2;
  357.     }
  358.  
  359.     strcpy(temp + i, buf);
  360.     if (strlen(temp) >= LLIM-1)
  361.         cerr(130);
  362.     inject(outline++, temp);
  363.  
  364.     if (header[0] != '\0')
  365.         skip(min(lsval-1, bottom-pageline));
  366.     else
  367.         skip(lsval-1);
  368.  
  369.     pageline += lsval;
  370.     if (pageline > bottom && header[0] != '\0')
  371.         pfoot();
  372.     return;
  373. }
  374.  
  375.  
  376. /* put out page header */
  377.  
  378. phead()
  379. {
  380.     curpag = newpag++;
  381.     if (m1val > 0) {
  382.         skip(m1val-1);
  383.         puttl(header,curpag);
  384.     }
  385.     skip(m2val);
  386.     pageline = m1val + m2val + 1;
  387.     return;
  388. }
  389.  
  390.  
  391. /* put out page footer */
  392.  
  393. pfoot()
  394. {
  395.     skip(m3val);
  396.     if (m4val > 0) {
  397.         puttl(footer,curpag);
  398.         skip(m4val-1);
  399.     }
  400. }
  401.  
  402.  
  403. /* put out title line with optional page number */
  404.  
  405. puttl(buf,pageno)
  406. char *buf;
  407. int pageno;
  408. {
  409.     char tbuf[LLIM];
  410.     int i, j;
  411.  
  412.     j = 0;
  413.     for (i = 0; buf[i] != '\0'; i++) {
  414.         if (buf[i] == PAGECHAR) {
  415.             j += sprintf(tbuf+j,"%*d",1,pageno);
  416.         }
  417.         else {
  418.             tbuf[j++] = buf[i];
  419.         }
  420.     }
  421.     tbuf[j] = '\0';
  422.     inject(outline++, tbuf);
  423.     return;
  424. }
  425.  
  426.  
  427. /* space n lines, or to bottom of page for large n */
  428.  
  429. space(n)
  430. int n;
  431. {
  432.     putwrd("");
  433.     if (pageline > bottom)
  434.         return;
  435.  
  436.     if (pageline == 0)
  437.         phead();
  438.  
  439.     skip(min(n,bottom+1-pageline));
  440.     pageline += n;
  441.     if (pageline > bottom)
  442.         pfoot();
  443. }
  444.  
  445.  
  446. /* output n blank lines */
  447.  
  448. skip(n)
  449. int n;
  450. {
  451.     while ((n--) > 0)
  452.         inject(outline++, "");
  453.     return;
  454. }
  455.  
  456.  
  457. /* get non-blank word from in[i] into out.
  458.  * increment *i.
  459.  */
  460.  
  461. getwrd(in, inx, out)
  462. char *in, *out;
  463. int *inx;
  464. {
  465.     register i, j;
  466.     char c;
  467.  
  468.     i = *inx;
  469.     while ((in[i]  == ' ') || (in[i] == '\t'))
  470.         i++;
  471.  
  472.     j = 0;
  473.     while ( ( c = (out[j++] = in[i++]))  > ' ' || c == '\b')
  474.         ;
  475.     out[--j] = '\0';
  476.     *inx = i-1;        /* return new index  */
  477.     return(j);    /* return length of word */
  478. }
  479.  
  480.  
  481. /* put a word in outbuf; includes margin justification */
  482.  
  483. putwrd(wrdbuf)
  484. char *wrdbuf;
  485. {
  486.     static int outwds, outw;
  487.     int sw, w, nextra, i;
  488.     char cl;
  489.  
  490.     if (wrdbuf[0] == '\0') {      /* runout */
  491.         if (outp > 0) {
  492.             outbuf[outp] = '\0';
  493.             put(outbuf);
  494.         }
  495.         outp = outw = outwds = 0;
  496.         outbuf[0] = '\0';
  497.     }
  498.     else {
  499.         w = width(wrdbuf);
  500.         sw = strlen(wrdbuf);
  501.  
  502. /* two spaces between sentences */
  503.         if ( (outp >= 3) && (outbuf[outp-1] == ' ') ) {
  504.             cl = outbuf[outp-2];
  505.             if ( (cl == ':') || (cl == '.') || (cl == '?') || (cl == '!') || (cl == ';') ) {
  506.                 if (isupper(wrdbuf[0])) {
  507.                     outbuf[outp++] = ' ';
  508.                     outw += 1;
  509.                 }
  510.             }
  511.         }
  512.         i = inval;
  513.         if (paraphase == 1)
  514.             i += para1;
  515.         if ( outp > 0 && (outw + w + i) > rmval || sw + outp + 1 >= LLIM ) {
  516. /* too big */
  517.             nextra = rmval-i-outp+1;       /* no. spaces to be inserted */
  518.             for (i=0; i < nextra; i++)
  519.                 outbuf[outp++]=' ';
  520. /*+++        spread(outbuf,outp-1,nextra,outwds); */
  521.             if (nextra > 0 && outwds > 1)
  522. /*+++     outp += nextra*/
  523.                 ;
  524.             outbuf[outp] = '\0';
  525.             put(outbuf);    /* write the filled line */
  526.             outp = outw = outwds = 0;
  527.             outbuf[0] = '\0';
  528.         }
  529.         strcpy(outbuf+outp, wrdbuf);
  530.         outp += sw;
  531.         outw += w;
  532.         outbuf[outp++] = ' ';    /* blank between words */
  533.         outw += 1;
  534.         outwds++;
  535.     }
  536.     return;
  537. }
  538.  
  539. /* --------- */
  540.  
  541. /* spread words to justify right margin */
  542. /* an attempt at proportional spacing */
  543.  
  544. spread(buf, outp1, ne, outwds)
  545. char *buf;
  546. int outp1, ne, outwds;
  547. {
  548.     register nholes, i, j, nb;
  549.     if (ne <= 0 || outwds <= 1)
  550.         return;
  551.  
  552.     dir = 1-dir;    /* reverse direction */
  553.     nholes = outwds-1;
  554.     i = outp1-1;
  555. /* leave room for NEWLINE, EOS */
  556.     j = min(LLIM-2, i+ne);
  557.     while (i < j)
  558.     {
  559.         buf[j] = buf[i];
  560.         if (buf[i] == ' ')
  561.         {
  562. /* compute # of blanks */
  563.             if (dir == 0)
  564.                 nb = (ne-1)/nholes+1;
  565.             else
  566.                 nb = ne/nholes;
  567.             ne -= nb;
  568.             nholes--;
  569. /* put blanks in buffer */
  570.             while (nb-- > 0)
  571.                 buf[--j] = ' ';
  572.         }
  573.         i--;
  574.         j--;
  575.     }
  576.     return;
  577. }
  578.  
  579.  
  580. /* compute printed width of character string */
  581.  
  582. width(buf)
  583. char *buf;
  584. {
  585.     register i, val;
  586.  
  587.     for (val = i = 0; (buf[i]); i++)
  588.         if (buf[i] == '\b')
  589.             val--;
  590.         else
  591.             val++;
  592.     return(val);
  593. }
  594.  
  595.  
  596.  
  597.  
  598. /* underline a line */
  599.  
  600. underl(buf,tbuf,size)
  601. char *buf, *tbuf;
  602. int size;
  603. {
  604.     int i, j,
  605.     k, k1;    /* how many chars in last word */
  606.  
  607.     i = j = k = 0;
  608.     while (j < size-2) {
  609.         if (isspace(buf[i]) || buf[i] == '\0') {
  610.             k1 = k;
  611.             while (k-- > 0) {
  612.                 if (j >= size-2)
  613.                     break;
  614.                 tbuf[j++] = '\b';
  615.             }
  616.             k = k1;
  617.             while (k-- > 0) {
  618.                 if (j >= size-2)
  619.                     break;
  620.                 tbuf[j++] = '_';
  621.             }
  622.         }
  623.         if (buf[i] == '\0')
  624.             break;
  625.         else if (j >= size-2)
  626.             break;
  627.         else {
  628.             if (buf[i] != ' ' && buf[i] != '\t')
  629.                 k++;
  630.             else
  631.                 k = 0;
  632.             tbuf[j++] = buf[i++];
  633.         }
  634.     }
  635.     tbuf[j++] = '\0';
  636.     strcpy(buf,tbuf);
  637.     return;
  638. }
  639. /* ----------------- help display ---------------- */
  640. helpdot()
  641. {
  642.     cleareop(1);
  643.     putstr("*.bp [p]  begin new page\n .br  break\n .ce [l]  center\n");
  644.     putstr(" .fi  fill paragraphs\n*.fo [text#]  footer\n*.he [text#]  header\n");
  645.     putstr(" .in c  indent\n*.ls l  line spacing\n*.ne l  need l for entity\n .nf   no fill\n");
  646.     putstr(" .pl l  lines/page\n .rm c  right margin\n*.sp l  space l lines\n");
  647.     putstr("*.ul [l]  underline\n\n");
  648.     putstr("[] optional.  +n, -n relative to existing value. l = line, c = col, p = page\n");
  649.     putstr(".he activates pagination.  # becomes page no.  * irreversible.\n");
  650.     putstr("-----------------------------------------");
  651.     topline = 19;
  652.     calp();
  653.     putpage();
  654.     return;
  655. }
  656.  
  657.