home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 150_01 / roff1.c < prev    next >
Text File  |  1985-09-07  |  13KB  |  478 lines

  1. /*
  2.        HEADER:  150.??;
  3.         TITLE:  ROFF - "RUNOFF" Text Formatter Program;
  4.       VERSION:  5.1;
  5.          DATE:  08/28/1982;
  6.   DESCRIPTION:  "A Text formatter based upon the one in Kernighan and Plauger's
  7.                  book SOFTWARE TOOLS.  Contains provisions for right justifi-
  8.                  cation, page headings and footings, variable margins, inden-
  9.                  tation, page numbers in header text, centered text, underlin-
  10.                  ing, and page lengths.  Easy to use.  Processes plain ASCII
  11.                  text from almost any editor, and formats it to to drive most  
  12.                  printers in straightforward fashion.  No provisions for fancy
  13.                  fonts, proportional spacing, etc.  DOC file contains good but 
  14.                  brief tutorial; sufficient for most semi-experienced users.";
  15.      KEYWORDS:  ROFF, Text Formatter, Software Tools;
  16.        SYSTEM:  any system with C compiler;
  17.      FILENAME:  ROFF1.C;
  18.      SEE-ALSO:  ROFF.DOC, ROFF.H, ROFF.HE, ROFF2.C, ROFF.EXE;
  19.       AUTHORS:  modified "for IBM-PC" by M. S. Zachmann;
  20.     COMPILERS:  BDS-C originally, IBM C compiler unknown;
  21.    REFERENCES:  AUTHORS: M. S. Zachmann; TITLE: "ROFF";
  22.                 CITATION: "PC-SIG Disk 50 or 142";
  23.                 AUTHORS: Kernighan and Plauger; TITLE: "Software Tools";
  24.                 CITATION: "available in many computer stores" 
  25.        ENDREF;
  26. */
  27. #define FALSE 0
  28. #define TRUE 1
  29.  
  30. /* 7 MAY 81 */
  31. /* based on the formatter presented in Kernighan and Plauger's
  32. SOFTWARE TOOLS, modified for BDS C */
  33.  
  34.  
  35.  
  36. #include "stdio.h"
  37. #include "ctype.h"
  38. #include "ROFF.H"
  39.  
  40.  
  41. main(argc, argv)
  42. int argc;
  43. char **argv;
  44. {
  45.    char filename[20];
  46.    char line[MAXLINE];
  47.    struct _iobuf *bufr;
  48.  
  49.  
  50.     errprnt("\nVersion 5.1\n");
  51.  
  52.     debug = FALSE;
  53.     if (argc == 1)
  54.     { errprnt("\nUSAGE:  roff >destination origin_file \n");
  55.       errprnt("Where origin_file is any valid text file name\n");
  56.       errprnt("And destination is a filename, or LST: (printer)\n");
  57.       errprnt("\tor left out (to console)\n");
  58.         exit();
  59.     }
  60.  
  61.     argv++;
  62.     while ( --argc > 0 )
  63.     { strcpy (filename, *argv++);        /* get next argument */
  64.         errprnt("\nNow processing <%s>",filename );
  65.         if (filename[0] == '-' && filename[1]=='d')
  66.         {
  67.             debug=TRUE;
  68.             continue;
  69.         }
  70.  
  71.  
  72.         if ((bufr = fopen(filename, "r")) == NULL)
  73.         { errprnt("\ncan not open <%s>", filename );
  74.             continue;
  75.         }
  76.  
  77.         init_defaults();
  78.  
  79.         while ( fgets( line,MAXLINE, bufr ) != 0 ) /*until EOF or CPMEOF */
  80.         { if (line[0] == COMMAND )
  81.                 comand (line);
  82.             else
  83.                 text (line);
  84.  
  85.         }
  86.         if (LINENO > 0  || OUTBUF[0] !='\0')
  87.             space (HUGE);        /* flush last output */
  88.         errprnt("\nDone processing <%s>", filename );
  89.  
  90.     }     /* end while (--argc > 0 ) */
  91.     exit(0);
  92. }        /* end main()           */
  93.  
  94.  
  95. /********************************************************************
  96. initializes the global variables governing the execution of the
  97.  format commands.
  98. ********************************************************************/
  99. init_defaults()
  100. {
  101.  
  102.     FILL = FI_DEF;    /* yes we want filled lines */
  103.     LSVAL = LS_DEF;    /* line spacing = 1 */
  104.     INVAL = IN_DEF;    /* left margin indent  0 */
  105.     RMVAL = RM_DEF;    /* right margin = page width  */
  106.     TIVAL = TI_DEF;    /* left margin temporary indent    0 */
  107.     CEVAL = CE_DEF;    /* next n lines to be centered -  0  */
  108.     ULVAL = UL_DEF;    /* next n lines to be underlined -  0  */
  109.  
  110.     PAGESTOP = FALSE;
  111.     PLVAL = PAGELEN;
  112.     M1VAL = M1_DEF;        /* top and bottom margins */
  113.     M2VAL = M2_DEF;
  114.     M3VAL = M3_DEF;
  115.     M4VAL = M4_DEF;
  116.     CURPAG = 0;
  117.     NEWPAG = 1;
  118.     LINENO = 0;
  119.     BOTTOM = PLVAL - M3VAL - M4VAL;
  120.  
  121.     OUTWRDS = 0;    /* no. of words in outbuf */
  122.     OUTBUF [0] = '\0';
  123.     DIR = 0;
  124.  
  125.     strcpy ( HEADER, "\n" );
  126.     strcpy ( FOOTER, "\n" );
  127. }
  128.  
  129.  
  130. /*****************************************************************
  131. this function decodes the command type, returning the type, or
  132.     UNKNOWN.
  133. *******************************************************************/
  134. int comtyp (line)
  135. char *line;
  136. {
  137.     char let1, let2;
  138.  
  139.     let1 = toupper( line[1] );
  140.     let2 = toupper( line[2] );
  141.  
  142.     if ( let1=='F' && let2=='I')    return( FI );
  143.     if ( let1=='F' && let2=='O')    return( FO );
  144.     if ( let1=='T' && let2=='I')    return( TI );
  145.     if ( let1=='B' && let2=='P')    return( BP );
  146.     if ( let1=='B' && let2=='R')    return( BR );
  147.     if ( let1=='C' && let2=='E')    return( CE );
  148.     if ( let1=='H' && let2=='E')    return( HE );
  149.     if ( let1=='I' && let2=='N')    return( IN );
  150.     if ( let1=='L' && let2=='S')    return( LS );
  151.     if ( let1=='N' && let2=='F')    return( NF );
  152.     if ( let1=='P' && let2=='L')    return( PL );
  153.     if ( let1=='R' && let2=='M')    return( RM );
  154.     if ( let1=='S' && let2=='P')    return( SP );
  155.     if ( let1=='U' && let2=='L')    return( UL );
  156.     if ( let1=='M')
  157.     { if (let2=='1')        return( M1 );
  158.         if (let2=='2')        return( M2 );
  159.         if (let2=='3')        return( M3 );
  160.         if (let2=='4')        return( M4 );
  161.     }
  162.  
  163.     return( UNKNOWN );        /* no match */
  164.  
  165. }
  166.  
  167.  
  168. /*********************************************************************
  169. Skips white-space characters at the beginning of a string.
  170. *********************************************************************/
  171. skip_blanks ( string )
  172. char *string;
  173. {
  174.     char local[ MAXLINE ];
  175.     int i, j, k;
  176.  
  177.  
  178.  
  179.     strcpy ( local, string );
  180.  
  181.     for (i=0; local[i]==' ' || local[i]=='\t' || local[i]=='\n' ; i++);
  182.  
  183.     for (j=0; (string[j]=local[i]) != '\0' ; i++, j++ )    ;
  184.  
  185.     return;
  186. }
  187.  
  188.  
  189. /*********************************************************************
  190.  
  191. Truncates white-space characters at the end of a string.
  192.  
  193. *********************************************************************/
  194. trunc_bl (string)
  195. char *string;
  196. {
  197.     char *ptr;
  198.     int k;
  199.  
  200.     k = strlen (string);
  201.     ptr = &string[ k-1 ];    /* char before terminating nul */
  202.  
  203.     while (*ptr==BLANK || *ptr==TAB || *ptr==NEWLINE)    
  204.         *ptr--  = '\0';
  205. }
  206.  
  207.  
  208. /*******************************************************************
  209. performs the formatting command returned by comtyp - sets global
  210.   variables ( indenting, underlining, etc. )
  211. *******************************************************************/
  212.  
  213. comand ( line )
  214. char *line;
  215. {
  216.     int c_type;    /* command type  */
  217.     int arg_val;    /* argument value, if any */
  218.     char arg_typ;    /* relative (+ or -) or absolute */
  219.     int i;
  220.  
  221.     c_type = comtyp (line);
  222.     if DEBUG errprnt("\n\nCOMAND %d",c_type);
  223.  
  224.     if (c_type == UNKNOWN)    /* IGNORE ALIEN ORDERS */
  225.     {
  226.         errprnt( "UNKNOWN COMMAND: <%s>\n", line);
  227.         return;
  228.     }
  229.  
  230.     arg_val = get_val ( line, &arg_typ );
  231.     if DEBUG errprnt( " \n    get_val returned arg_val=%d, arg_typ= %c   ",
  232.       arg_val,    arg_typ   );
  233.     if DEBUG errprnt("\n\n");
  234.  
  235.     switch (c_type)
  236.     {
  237.     case FI :    /* filled lines  */
  238.         brk();    /* flush out last unfilled */
  239.         FILL = YES;
  240.         break;
  241.  
  242.     case NF :    /* non-filled lines */
  243.         brk();    /* flush out */
  244.         FILL = NO;
  245.         break;    /* down and cry */
  246.  
  247.     case BR :    /* just cause a break */
  248.         brk();
  249.         break;
  250.  
  251.     case LS :    /* set line spacing value */
  252.         set (&LSVAL, arg_val, arg_typ, LS_DEF, 1, HUGE );
  253.         break;
  254.  
  255.     case TI :    /* set temporary left indent */
  256.         brk();
  257.         set ( &TIVAL, arg_val, arg_typ, TI_DEF, 0, RMVAL );
  258.         break;
  259.  
  260.     case IN :    /* set left indent */
  261.         set ( &INVAL, arg_val, arg_typ, IN_DEF, 0, RMVAL-1 );
  262.         TIVAL = INVAL;
  263.         break;
  264.  
  265.     case RM:    /* set right margin */
  266.         set ( &RMVAL, arg_val, arg_typ, RM_DEF, TIVAL+1, HUGE );
  267.         break;
  268.     case M1:    /* set topmost margin */
  269.         set ( &M1VAL, arg_val, arg_typ, M1_DEF, 0, HUGE);
  270.         break;
  271.  
  272.     case M2:    /* set second top margin */
  273.         set ( &M2VAL, arg_val, arg_typ, M2_DEF, 0, HUGE);
  274.         break;
  275.  
  276.     case M3:    /* set first bottom margin */
  277.         set ( &M3VAL, arg_val, arg_typ, M3_DEF, 0, HUGE);
  278.         break;
  279.  
  280.     case M4:    /* set bottom-most margin */
  281.         set ( &M4VAL, arg_val, arg_typ, M4_DEF, 0, HUGE);
  282.         break;
  283.  
  284.     case CE :    /* center next arg_val lines */
  285.         brk();
  286.         set ( &CEVAL, arg_val, arg_typ, CE_DEF, 0, HUGE);
  287.         break;
  288.  
  289.     case UL :    /* underline next arg_val lines */
  290.         set ( &ULVAL, arg_val, arg_typ, UL_DEF, 1, HUGE );
  291.         break;
  292.  
  293.     case HE :    /* get header title for pages */
  294.         gettl ( line, HEADER );
  295.         break;
  296.  
  297.     case FO :    /* get footer title for pages */
  298.         gettl ( line, FOOTER );
  299.         break;
  300.  
  301.     case SP :    /* space down arg_val blank lines */
  302.         set (&SPVAL, arg_val, arg_typ, 1, 0, HUGE);
  303.         space ( SPVAL );
  304.         break;
  305.  
  306.     case BP :    /* set pageno arg_val - begin page */
  307.         if ( LINENO > 0 )    space (HUGE);
  308.         set ( &CURPAG, arg_val, arg_typ, CURPAG+1, -HUGE, HUGE);
  309.         NEWPAG = CURPAG;
  310.         break;
  311.  
  312.     case PL :    /* set page length */
  313.         set (&PLVAL, arg_val, arg_typ, PAGELEN,
  314.           M1VAL+M2VAL+M3VAL+M4VAL+1, HUGE);
  315.         BOTTOM = PLVAL - M3VAL - M4VAL;
  316.         break;
  317.  
  318.  
  319.     }
  320.  
  321.     return;
  322. }
  323.  
  324. /******************************************************************
  325.  
  326. gets the number ( if any ) associated with any command 
  327.  
  328. *******************************************************************/
  329. int get_val ( line, typ )
  330. char *line, *typ;
  331. {
  332.     int i,j;
  333.     char local[ MAXLINE ];
  334.  
  335.     strcpy (local, line);    /* local copy */
  336.  
  337. /* skip over the command line */
  338.     for (i=1; local[i]!=' ' && local[i]!='\t' && local[i]!='\n' ; i++ )
  339.         ;
  340.  
  341.     skip_blanks (&local[i]);    /* find the number */
  342.     *typ = local[i];    /* relative or absolute */
  343.  
  344.     if ( *typ=='+' || *typ=='-' )    i++;
  345.     else if ( !isdigit( *typ ) )    return( NO_VAL );
  346.  
  347.     stcd_i( &local[i], &j);
  348.     return(j);
  349.  
  350. }
  351.  
  352.  
  353. /*****************************************************************
  354.  sets a global parameter like line-spacing, underlining, etc.
  355.  Also checks that the new value is within the range of that 
  356.  parameter.  Assigns the default for that parameter if no value
  357.   is specified.
  358. ******************************************************************/
  359.  
  360. set ( param, val, arg_typ, defval, minval, maxval )
  361. int *param, val, defval, minval, maxval;
  362. char arg_typ;
  363. {
  364.     if (val == NO_VAL )        /* defaulted */
  365.         *param = defval;
  366.     else if (arg_typ == '+')    /* relative + */
  367.         *param += val;
  368.     else if (arg_typ == '-')    /* relative - */
  369.         *param -= val;
  370.     else    *param = val;        /* absolute */
  371.  
  372.     *param = min(*param,maxval);
  373.     *param = max(*param, minval);
  374.  
  375.     if DEBUG errprnt("\n    SET *param = %d", *param);
  376.     return;
  377. }
  378.  
  379.  
  380.  
  381. /**********************************************************
  382.         centers a line of text
  383. **********************************************************/
  384. center (line)
  385. char *line;
  386. {
  387.     TIVAL = max(( RMVAL+TIVAL-strlen(line))/2, 0 );
  388.     return;
  389. }
  390.  
  391.  
  392. /**************************************************************
  393.     get next word from input line
  394. *************************************************************/
  395. int getwrd (in,  out )
  396. char *in, *out;
  397. {
  398.     int i, j, n;
  399.  
  400. /* find first non-blank */
  401.     skip_blanks (in);
  402.     replace_char ( in, TAB, BLANK); /* replace tabs w/space */
  403.  
  404. /* scan off a word */
  405.     if ( 1 == (n = movwrd( in, out)))
  406.     { if DEBUG errprnt("\nafter sscanf out = <%s>",out);
  407.         j = strlen (out);
  408.         replace_char (out, NEWLINE, BLANK);
  409.         for (i=0; i<j; i++ )    in[i] = BLANK;    /* blank out word in input */
  410.     }
  411.     if DEBUG errprnt("\ngetwrd will return %d", n);
  412.     return(n);    /* WE_HAVE_A_WORD = 1 */
  413. }
  414.  
  415.  
  416.  
  417.  
  418. /*****************************************************************
  419.     distibute words evenly across a line
  420. *****************************************************************/
  421. spread ( line, nextra, no_words)
  422. char *line;
  423. int nextra;    /* no. extra places left in line */
  424. int no_words;   /* no. words in the line         */
  425. {
  426.     int i, j, nblanks, nholes;
  427.  
  428.     if (nextra <= 0 || no_words <= 1)    return;
  429.  
  430.     DIR = !(DIR);
  431.     nholes = no_words - 1;
  432.     trunc_bl (line);
  433.     i = strlen(line) - 1 ; /* last character of string */
  434.     j = min(MAXLINE - 2,  i + nextra);    /* last  position in output */
  435.     line[j+1] = '\0';
  436.  
  437.     for ( ; i<j ; i--, j-- )
  438.     { line[j] = line[i];
  439.         if DEBUG errprnt("[%c i=%d j=%d] ", line[j], i, j);
  440.         if ( line[i] == BLANK)
  441.         { if (DIR == 0)
  442.                 nblanks = (nextra - 1)/nholes   +   1;
  443.             else
  444.                 nblanks = nextra/nholes;
  445.             nextra = nextra - nblanks;
  446.             nholes = nholes - 1;
  447.  
  448.             if DEBUG errprnt("\nnblanks=%d, nextra=%d",
  449.               nblanks,    nextra   );
  450.             for ( ; nblanks > 0;  nblanks-- )
  451.                 line[--j] = BLANK;
  452.         }
  453.     }
  454.     if DEBUG errprnt("\nafter spreading, line is:\n<%s>", line);
  455.     return;
  456. }
  457.  
  458.  
  459. /****************************************************************
  460.     end current filled line 
  461. *****************************************************************/
  462. brk()
  463. {
  464.     int l;
  465.     if DEBUG errprnt("\nbrk: OUTBUF=<%s>", OUTBUF);
  466.  
  467.     if ( 0!= ( l = strlen (OUTBUF)))
  468.     { OUTBUF[l] = NEWLINE;
  469.         OUTBUF[l+1] = '\0';
  470.         put (OUTBUF);
  471.     }
  472.  
  473.     OUTWRDS = 0;
  474.     OUTBUF[0] = '\0';
  475.     return;
  476.  
  477. }
  478.