home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 6 File / 06-File.zip / cols.zip / cols.c next >
C/C++ Source or Header  |  1994-05-25  |  25KB  |  677 lines

  1. /*************************************************************************\
  2.  * Program to format ASCII text in several columns.                   
  3.  * This program is also useable to break text with long lines.
  4.  * You can type
  5.  *     cols -h
  6.  * to get a description of the valid command line parameters.
  7.  *
  8.  * (c) 10.92 by Ralf Seidel
  9.  *          Wuelfrahter Str. 45
  10.  *          42105 Wuppertal
  11.  *          email: seidel3@wrcs3.uni-wuppertal.de
  12.  *
  13.  * This program is free software; you can redistribute it and/or modify
  14.  * it under the terms of the GNU General Public License as published by
  15.  * the Free Software Foundation; either version 2 of the License, or
  16.  * (at your option) any later version.
  17.  * 
  18.  * This program is distributed in the hope that it will be useful,
  19.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21.  * GNU General Public License for more details.
  22.  * 
  23.  * You should have received a copy of the GNU General Public License
  24.  * along with this program; if not, write to the Free Software
  25.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26.  *
  27.  * Set tabs to 3 to get a readable source.
  28. \*************************************************************************/
  29. #include <ctype.h>
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include <stdlib.h>
  33. #include <malloc.h>
  34. #include <getopt.h>
  35.  
  36. #ifndef __GNUC__
  37. #define __inline__
  38. #define __atribute__( dummy )
  39. #define __const__
  40. #endif
  41.  
  42. /*
  43. #define DEBUG
  44. */
  45. /*************************************************************************\
  46.  * Type definitions
  47. \*************************************************************************/
  48. typedef unsigned char uchar;
  49.  
  50. /*************************************************************************\
  51.  * Prototypes of defined functions 
  52. \*************************************************************************/
  53. void usage() __attribute__(( noreturn ));
  54. void wrong_parameter() __attribute__(( noreturn ));
  55. void help() __attribute__(( noreturn ));
  56. void spc( uchar* string, __const__ size_t n );
  57. void printpg();
  58. void printpgrest();
  59. void puttooutbuf( uchar *string );
  60. void setnewline();
  61.  
  62. /*************************************************************************\
  63.  * Global variables used in this program 
  64. \*************************************************************************/
  65. #define DEFAULT_MARGIN 4
  66. static uchar *prog = NULL;                /* Name of this program found in argv[0] */
  67. /* Variables which represent the command line options initialised with
  68.  * default values */
  69. static int pg_lines = 66;                /* Number of lines per page */
  70. static int pg_width = 72;                /* Number of characters per output line: */
  71. static int col_width = 72;          /* characters per column:
  72.                                      * maximal length of displayed text in one
  73.                                      * column */
  74. static int cols = 1;                /* number of text columns */
  75. static int sepfiles = 0;            /* flag: start new files on new page? */
  76. static int word_wrap = 0;                /* flag: word wrap? */
  77. static int sendff = 0;              /* flag: send chr(12) afer each page? */
  78. static int expand_tabs = 0;            /* flag: expand tabs to spaces? */
  79. static int dbllf = 0;                    /* flag: double newline characters? */
  80. static int tab_spc = 4;                    /* number of spaces to insert for one tab */
  81. static int left_spc = 0;                /* number of blanks at the beginning of */
  82.                                     /* each line */
  83. static int mid_spc = 1;                    /* number of blanks between columns */
  84.  
  85. /* Global variables which are used during file processing */                                    
  86. static FILE *out_file = NULL;
  87.  
  88. static int cur_col;                 /* current text column in access */
  89. static int cur_col_pos;                    /* next postion to write characters */
  90. static int cur_line;                /* current text line  */
  91. static uchar *pcur_pos;                    /* character arrays */
  92. static uchar **cur_page;                 /* pointer to the page to be printed 
  93.                                                  * next */
  94.  
  95. #define USAGE "%s [-BdfhW -cn -ln -mn -ofile -tn -wn -Wn files]\n"
  96.  
  97. /*************************************************************************\
  98.  * Fill a string with n blanks and append a NULL character 
  99. \*************************************************************************/
  100. void spc( uchar* string, __const__ size_t n )
  101. {
  102.    memset( string, (int)' ', n );
  103.    string[n] = '\0';
  104.    return;
  105. }
  106.  
  107. /*************************************************************************\
  108.  * Print help lines and exit program.
  109. \*************************************************************************/
  110. void help()
  111. {
  112.     fprintf( stderr,
  113.         USAGE 
  114.         "Format text in several columns\n" 
  115.         "\t-c: number of columns (%d)\n" 
  116.         "\t-d: double every new line character found in input\n" 
  117.         "\t-f: send formfeed (chr 12) after each page of output\n" 
  118.         "\t-h: show this help\n" 
  119.         "\t-l: lines per page (%d)\n" 
  120.         "\t-m: set left left margin to n (%d)\n"
  121.         "\t-o: name of output file (stdout)\n" 
  122.         "\t-t: expand tabs to blanks - n = tab_spc (%d)\n" 
  123.         "\t-w: width of one column (%d)\n" 
  124.         "\t-W: width of output page (%d)\n" 
  125.         "\t-s: seperate files - each file will begin on a new page\n" 
  126.         "\t-B: break lines between words only (word wrap)\n" 
  127.         "\nIf no file is specified stdin is used for input and stdout for output.\n" 
  128.         "Values in brackets are the defaults\n", 
  129.         prog, cols, pg_lines, DEFAULT_MARGIN, tab_spc, col_width, pg_width
  130.     ); /* end fprintf */
  131.     exit(0);
  132. }
  133.  
  134. /*************************************************************************\
  135.  * Print error message and exit if an unknown parameter is found.
  136. \*************************************************************************/
  137. void usage()
  138. {
  139.     fprintf(stderr, "usage: " USAGE, prog );
  140.     exit(1);
  141. }
  142.  
  143. /*************************************************************************\
  144.  * Print error message and exit if some parameters are wrong
  145. \*************************************************************************/
  146. void wrong_parameter()
  147. {
  148.     fprintf( stderr, "%s: wrong parameters found!\n", prog );
  149.     exit(1);
  150. }
  151.  
  152. void setnewline()
  153. /*************************************************************************\
  154.  * This fuction is called after proceding to a new line. It checks if the end
  155.  * of a column is reached, if necessary does the output of a finished page and
  156.  * updates the global variables pcur_pos and cur_col_pos.
  157.  * Global variables changed:
  158.  *     pcur_pos        : Set to the start of the new line.
  159.  *     cur_col_pos    : = 0
  160.  *     cur_line        : New line number of current output page.
  161.  *     cur_col        : Changed if a new column starts.
  162.  *     cur_page        : Printed and cleared, if the currend page is full.
  163. \*************************************************************************/
  164. {
  165.     int abs_pos;            /* Absolute position in the new line of cur_page */
  166.     int len;                    /* Absolute length or the new line */
  167.     int spc_to_ins;        /* Number of blanks to insert in the new line */
  168.  
  169.     if ( cur_line >= pg_lines ) {     /* End of column reached? */
  170.         cur_col++;                                /* Begin a new column and */
  171.         cur_line = 0;                            /* start at line 0 */
  172.         if ( cur_col >= cols ) {            /* End of page reached? */
  173.             printpg();                                /* Print page and */
  174.             cur_col = 0;                            /* restart at column 0 */
  175.         } /* end if */
  176.     } /* end if */
  177.     /* fill the space between the end of the last column and */
  178.     /* the begining of the current column with blanks */
  179.     len = strlen( cur_page[cur_line] );
  180.     abs_pos = left_spc + cur_col * (col_width + mid_spc);
  181.     spc_to_ins = abs_pos - len;
  182.     spc( &cur_page[cur_line][len], spc_to_ins );
  183.     cur_col_pos = 0;
  184.     pcur_pos = &cur_page[cur_line][abs_pos];
  185.     return;
  186. }
  187.  
  188.  
  189. /*************************************************************************\
  190.  * Insert the string to the output buffer (cur_page)
  191. \*************************************************************************/
  192. void puttooutbuf( uchar *string )
  193. {
  194.    int n;
  195.    size_t l;
  196.    uchar *pstrc;            /* points to the next character in param "string"  */
  197.    uchar *pc;                /* temporary pointer used during word wraping */
  198.    uchar *pcol_start;    /* " */
  199.    uchar *pwrap_str;        /* " */
  200.    uchar c;                    /* temporary character variable used during word
  201.                                  * wraping */
  202.     uchar *tabstr;            /* inserted string for tabs if the flag "expand_tabs"
  203.                                  * is set */
  204.     for ( pstrc = string; *pstrc != '\0'; pstrc++ ) {
  205.         /* Examine every character in string before putting it to the */
  206.         /* output buffer. */
  207.         switch( *pstrc ) {
  208.             case '\n':
  209.                 /* mark the end of the line */
  210.                 *pcur_pos = '\0';
  211.                 /* increment cur_line */
  212.                 cur_line+= dbllf + 1;
  213.                 setnewline();
  214.                 break;
  215.             case '\t':
  216.                 if ( expand_tabs ) {
  217.                     n = tab_spc - cur_col_pos % tab_spc;
  218.                     if ( cur_col_pos + n >= col_width ) {
  219.                         *pcur_pos = '\0';
  220.                         cur_line++;
  221.                         setnewline();
  222.                     } else {
  223.                         if ( (tabstr = alloca(n + 1)) == NULL ) {
  224.                             perror( "alloca" );
  225.                             exit( 1 );
  226.                         }
  227.                         spc( tabstr, n );
  228.                         puttooutbuf( tabstr );
  229.                     }
  230.                     break;
  231.                 }
  232.             default:
  233.                 /* copy character from parameter string to output page
  234.                  * and increment the output position */
  235.                 *pcur_pos++ = *pstrc;
  236.                 cur_col_pos++;
  237.                 /* test, if the end of a column is reached
  238.                  * if word wrapping is on, one more character can temporarly
  239.                  * be written in a line because the line will be broken
  240.                  * in front of this position */
  241.                 if ( cur_col_pos >= col_width + word_wrap ) {
  242.                     if ( word_wrap ) {
  243.                         /* calculate the beginning of the current column */
  244.                         pcol_start = &cur_page[cur_line][left_spc + cur_col * ( col_width + mid_spc )];
  245.                         /* Find the last space character in the string */
  246.                         for ( pc = pcur_pos - 1; !isspace(*pc) && pc > pcol_start; pc-- );
  247.                         if ( pc > pcol_start ) {
  248.                             /* A blank was found and pc points to its position */
  249.                             /* delete the blank and set pc to the next character */
  250.                             /* following */
  251.                             *pc++ = '\0';
  252.                             /* calculate the length of the string which has to be */
  253.                             /* wraped */
  254.                             l = (size_t)( pcur_pos - pc );
  255.                             /* save the rest of the line */
  256.                             pwrap_str = alloca( l );
  257.                             strncpy( pwrap_str, pc, l );
  258.                             cur_line++;
  259.                             setnewline();
  260.                             /* copy the reset to the next line */
  261.                             strncpy( pcur_pos, pwrap_str, l);
  262.                             pcur_pos+= l;
  263.                             cur_col_pos = l;
  264.                         } else {
  265.                             /* No blank was found in the current line: */
  266.                             c = *(--pcur_pos);
  267.                             *pcur_pos = '\0';
  268.                             cur_line++;
  269.                             setnewline();
  270.                             *pcur_pos++ = c;
  271.                             cur_col_pos = 1;
  272.                         } /* end if */
  273.                     } else { /* no word wraping: */
  274.                         *pcur_pos = '\0';
  275.                         cur_line++;
  276.                         setnewline();
  277.                     } /* end if word_wrap */
  278.                 } /* end if ( cur_col_pos >= col_width ) */
  279.         } /* end switch */
  280.     } /* end for */
  281.     return;
  282. }
  283.  
  284. /*************************************************************************\
  285.  * Function to print a page if it is full. After printing each line is
  286.  * cleared and the global variables cur_col and cur_line are reset to zero
  287.  * Global variables changed:
  288.  *     cur_page    : Printed and cleared.
  289. \************************************************************************/
  290. void printpg()
  291. {
  292.     register int j;
  293.     
  294.     for (j = 0; j < pg_lines; j++) {
  295.         fputs( cur_page[j], out_file );        /* print line j of cur_page */
  296.         fputc( '\n', out_file );
  297.         spc( cur_page[j], left_spc );            /* fill left margin */
  298.     } /* end for */
  299.     if ( sendff ) fputc( '\f', out_file );
  300.     return;
  301. }
  302.  
  303. /*************************************************************************\
  304.  * Function to print the rest of a page at the end of the program.
  305.  * This function also frees all memmory allocated by cur_page.
  306.  * Global variables changed:
  307.  *     cur_page    : Printed and freed.
  308. \************************************************************************/
  309. void printpgrest()
  310. {
  311.     register int j;
  312.     int n;
  313.  
  314.     n = cur_col > 0 ? pg_lines : cur_line;
  315.     
  316.     for ( j = 0; j < n; j++ ) {
  317.         fputs( cur_page[j], out_file );        /* print line j of cur_page */
  318.         fputc( '\n', out_file );
  319.         free( cur_page[j] );
  320.     } /* end for */
  321.     for ( ; j < pg_lines; j++ )
  322.         free( cur_page[j] );
  323.     free( cur_page );
  324.     if ( sendff ) fputc( '\f', out_file );
  325.     return;
  326. }
  327.     
  328.  
  329. /************************************************************************\
  330.  - - - - - - - - - - - - - - - - - - main - - - - - - - - - - - - - - - -
  331. \************************************************************************/
  332.  
  333. int main( int argc, char *argv[] )
  334. {
  335.     uchar *ofname = NULL;                 /* Name of outputfile */
  336.     FILE *in_file = NULL;                /* Handle of inputfile */
  337.     uchar in_buf[129];                         /* buffer to read the files */
  338.  
  339.     char *errptr;                            /* pointer for return value of strtol */
  340.     int i;                                    /* index used for loops */
  341.     int c;                                    /* value returned by getopt */
  342.     int pw_spec = 0;                        /* flag: was the width of the page given
  343.                                                  * as a parameter ? */
  344.     int cw_spec = 0;                        /* flag: was the width of a column given
  345.                                                  * as a parameter ? */
  346.     int cn_spec = 0;                        /* flag: number of columns given as a
  347.                                                  * parameter ? */
  348.     int mw_spec = 0;                        /* flag: left margin specified? *
  349.                                                  * mw means margin width */
  350.    
  351.     #ifdef __EMX__  /* Use wildcard expansion with EMX-GCC (MSDOS & OS2) */
  352.     /* Neither DOS nor OS/2 "standard" shells expand wildcards in the command-
  353.      * line. Using the emx port of gcc it is possible to exand these parameters
  354.      * with the following function.
  355.      * Wildcards found in any argv string are replaced by filenames found
  356.      * in the current directory.
  357.      * After calling this function argc and argv may have changed */
  358.    _wildcard( &argc, &argv );
  359.     #endif
  360.     /* Get name of this program from parameter 0 and delete all preceding
  361.      * path information */
  362.     prog = argv[0];
  363.     if ( prog && strrchr( prog, '/' ) )
  364.        prog = strrchr( prog, '/' ) + 1;
  365.     #if defined MSDOS || defined OS2
  366.     if ( prog && strrchr( prog, '\\' ) )
  367.         prog = strrchr(prog, '\\') + 1;
  368.     #endif
  369.    /* Get all given parameters and check if they are valid */
  370.     while ((c = getopt( argc, argv, "c:dfhl:m::o:t::w:W:sB" )) != EOF) {
  371.         switch (c) {
  372.             case 'c':                /* Parameter specifies number of columns */
  373.                 cn_spec = 1;
  374.                 cols = strtol(optarg, &errptr, 0);
  375.                 if ( cols <= 0 || *errptr != '\0' ) {
  376.                     fprintf( stderr, "Invalid parameter for option -c\n" );
  377.                     exit( 1 );
  378.                 }
  379.                 #ifdef DEBUG
  380.                 fprintf( stderr, "number of columns set to %d\n", cols );
  381.                 #endif                
  382.                 break;
  383.             case 'd':                /* Print an empty line after each line feed */
  384.                 dbllf = 1;
  385.                 #ifdef DEBUG
  386.                 fprintf( stderr, "double linefeed set on\n" );
  387.                 #endif                
  388.                 break;
  389.             case 'f':                /* Send a form feed at the end of each page */
  390.                 sendff = 1;
  391.                 #ifdef DEBUG
  392.                 fprintf( stderr, "linefeed after every page set on\n" );
  393.                 #endif                
  394.                 break;
  395.             case 'l':                /* Number of lines on one page */
  396.                 pg_lines = strtol( optarg, &errptr, 0);
  397.                 if ( pg_lines <= 0 || *errptr != '\0' ) {
  398.                     fprintf( stderr, "Invalid parameter for option -l\n" );
  399.                     exit( 1 );
  400.                 }
  401.                 #ifdef DEBUG
  402.                 fprintf( stderr, "page lines set to %d\n", pg_lines );
  403.                 #endif                
  404.                 break;
  405.             case 'h':                /* give help */
  406.                 help();
  407.                 break;
  408.             case 'm':                /*  Print a left margin */
  409.                 mw_spec = 1;
  410.                 if ( optarg != NULL ) {
  411.                     left_spc = strtol( optarg, &errptr, 0 );
  412.                     if ( left_spc < 0 || *errptr != '\0' ) {
  413.                         fprintf( stderr, "Invalid parameter for option -m\n" );
  414.                         exit( 1 );
  415.                     }
  416.                 } else {
  417.                     left_spc = DEFAULT_MARGIN;
  418.                 }
  419.                 #ifdef DEBUG
  420.                 fprintf( stderr, "left margin set to %d\n", left_spc );
  421.                 #endif                
  422.                 break;
  423.             case 'o':                /* print output in a file */
  424.                 ofname = optarg;
  425.                 if ( ofname == NULL ) usage();
  426.                 #ifdef DEBUG
  427.                 fprintf( stderr, "name of output file set to %s\n", ofname );
  428.                 #endif                
  429.                 break;
  430.             case 't':
  431.                 expand_tabs = 1;
  432.                 if ( optarg != NULL ) {
  433.                      tab_spc = strtol( optarg, &errptr, 0 );
  434.                     if ( tab_spc <= 0 || *errptr != '\0' ) {
  435.                         fprintf( stderr, "Invalid parameter for option -t\n" );
  436.                         exit( 1 );
  437.                     }
  438.                     if ( tab_spc == 0 ) usage();
  439.                 } /* end if */
  440.                 #ifdef DEBUG
  441.                 fprintf( stderr, "tabs set to %d\n", tab_spc );
  442.                 #endif                
  443.                 break;
  444.             case 'w':                /* specify the width of one column */
  445.                 cw_spec = 1;
  446.                 col_width = strtol( optarg, &errptr, 0 );
  447.                 if ( col_width <= 0 || *errptr != '\0' ) {
  448.                     fprintf( stderr, "Invalid parameter for option -w\n" );
  449.                     exit( 1 );
  450.                 }
  451.                 #ifdef DEBUG
  452.                 fprintf( stderr, "width of one column set to %d\n", col_width );
  453.                 #endif                
  454.                 break;
  455.             case 'W':                /* width of a total page */
  456.                 pw_spec = 1;
  457.                 pg_width = strtol( optarg, &errptr, 0 );
  458.                 if ( pg_width <= 0 || *errptr != '\0' ) {
  459.                     fprintf( stderr, "Invalid parameter for option -W\n" );
  460.                     exit( 1 );
  461.                 }
  462.                 #ifdef DEBUG
  463.                 fprintf( stderr, "width of page set to %d\n", pg_width );
  464.                 #endif                
  465.                 break;
  466.             case 's':                /* begin each file on a new page */
  467.                sepfiles = 1;
  468.                 #ifdef DEBUG
  469.                 fprintf( stderr, "seperate files set on\n" );
  470.                 #endif                
  471.                break;
  472.             case 'B':                /* Break text between words only */
  473.                 word_wrap = 1;
  474.                 #ifdef DEBUG
  475.                 fprintf( stderr, "word wrap set on\n" );
  476.                 #endif                
  477.                 break;
  478.             default:
  479.                 usage();
  480.         }
  481.     }  /* while ((c = getopt) != EOF) */
  482.     /* assume the rest of parameters to be filesnames
  483.      * optind reflects the first command line argument which doesn't begin
  484.      * with a dash */
  485.  
  486.     if ( pw_spec ) { /* width of the page specified in the command line? */
  487.         if( cw_spec ) { /* width of one column specified? */
  488.             if( cn_spec ) { /* number of columns given? */
  489.                 if ( mw_spec ) { /* width of the left margin specified? */
  490.                     /* pw_spec & cw_spec & cn_spec & mw_spec */
  491.                     /* Test if everything fits */
  492.                     if ( cols * col_width + left_spc > pg_width )
  493.                         wrong_parameter();
  494.                     if ( cols > 1 )
  495.                         mid_spc = (pg_width - col_width * cols - left_spc ) / (cols - 1);
  496.                     #ifdef DEBUG
  497.                     fprintf( stderr, "space between columns set to %d\n", mid_spc);
  498.                     #endif
  499.                 } else {
  500.                     /* pw_spec & cw_spec & cn_spec & !mw_spec */
  501.                     /* Test if everything fits */
  502.                     if ( cols * col_width > pg_width ) wrong_parameter();
  503.                     /* Use as much space as possible between two columns and
  504.                      * if there is a rest use it as a left margin */
  505.                     if ( cols > 1 )
  506.                         mid_spc = (pg_width - col_width * cols ) / (cols - 1);
  507.                     left_spc = pg_width - col_width * cols - mid_spc * (cols - 1);
  508.                     #ifdef DEBUG
  509.                     fprintf( stderr, "space between columns set to %d\n", mid_spc);
  510.                     fprintf( stderr, "left margin set to %d\n", left_spc);
  511.                     #endif
  512.                 } /* end mw_spec */
  513.             } else { /* number of columns not given! */
  514.                 if ( mw_spec ) { /* width of the left margin specified? */
  515.                     /* pw_spec & cw_spec & !cn_spec & mw_spec */
  516.                     if ( col_width + left_spc > pg_width ) wrong_parameter();
  517.                     cols = (pg_width - left_spc) / col_width;
  518.                     if ( cols > 1 )
  519.                         mid_spc = (pg_width - left_spc - col_width * cols ) / (cols - 1);
  520.                     #ifdef DEBUG
  521.                     fprintf( stderr, "number of columns set to %d\n", cols );
  522.                     fprintf( stderr, "space between columns set to %d\n", mid_spc );
  523.                     #endif          
  524.                 } else {
  525.                     /* pw_spec & cw_spec & !cn_spec & !mw_spec */
  526.                     if ( col_width > pg_width ) wrong_parameter();
  527.                     cols = pg_width / col_width;
  528.                     if ( cols > 1 )
  529.                         mid_spc = (pg_width - col_width * cols ) / (cols - 1);
  530.                     left_spc = pg_width - col_width * cols - mid_spc * (cols - 1);
  531.                     #ifdef DEBUG
  532.                     fprintf( stderr, "number of columns set to %d\n", cols );
  533.                     fprintf( stderr, "space between columns set to %d\n", mid_spc);
  534.                     fprintf( stderr, "left margin set to %d\n", left_spc);
  535.                     #endif          
  536.                 }
  537.             }
  538.         } else { /* width of a column not specified! */
  539.             if( cn_spec ) { /* number of columns given? */
  540.                 if ( mw_spec ) { /* width of the left margin specified? */
  541.                     /* pw_spec & !cw_spec & cn_spec & mw_spec */
  542.                     /* Test if everything fits - assume at least one character
  543.                      * per column */
  544.                     if ( cols + left_spc > pg_width ) wrong_parameter();
  545.                     col_width = (pg_width - left_spc) / cols;
  546.                     if ( cols > 1 )
  547.                         mid_spc = (pg_width - col_width * cols - left_spc ) / (cols - 1);
  548.                     #ifdef DEBUG
  549.                     fprintf( stderr, "width of one column set to %d\n", col_width );
  550.                     fprintf( stderr, "space between columns set to %d\n", mid_spc );
  551.                     #endif
  552.                 } else {
  553.                     /* mw_spec & pw_spec & cn_spec & !mw_spec */
  554.                     /* Test if everything fits - assume at least one character
  555.                      * per column */
  556.                     if ( cols > pg_width ) wrong_parameter();
  557.                     col_width = pg_width / cols;
  558.                     if ( cols > 1 )
  559.                         mid_spc = (pg_width - col_width * cols ) / (cols - 1);
  560.                     left_spc = pg_width - col_width * cols - mid_spc * (cols - 1);
  561.                     #ifdef DEBUG
  562.                     fprintf( stderr, "width of one column set to %d\n", col_width );
  563.                     fprintf( stderr, "space between columns set to %d\n", mid_spc);
  564.                     fprintf( stderr, "left margin set to %d\n", left_spc);
  565.                     #endif
  566.                 } /* end mw_spec */
  567.             } else { /* number of columns not given! */
  568.                 /* Use default value for cols (1) */
  569.                 if ( mw_spec ) { /* width of the left margin specified? */
  570.                     /* pw_spec & !cw_spec & !cn_spec & mw_spec */
  571.                     /* Test if everything fits - assume at least one character
  572.                      * per column */
  573.                     if ( left_spc >= pg_width ) wrong_parameter();
  574.                     col_width = (pg_width - left_spc);
  575.                     #ifdef DEBUG
  576.                     fprintf( stderr, "width of the column set to %d\n", col_width );
  577.                     #endif
  578.                 } else {
  579.                     /* cw_spec & cw_spec & cn_spec & !mw_spec */
  580.                     if ( 0 >= pg_width ) wrong_parameter();
  581.                     col_width = pg_width;
  582.                     #ifdef DEBUG
  583.                     fprintf( stderr, "width of the column set to %d\n", col_width );
  584.                     #endif
  585.                 } /* end mw_spec */
  586.             }
  587.         }
  588.     } else { /* width of page not specified! */
  589.         /* Don't mind if any parameter was specified or if the default value
  590.          * is used */
  591.         pg_width = cols * col_width + (cols - 1) * mid_spc + left_spc;
  592.         #ifdef DEBUG
  593.         fprintf( stderr, "width of page set to %d\n", pg_width );
  594.         #endif
  595.     }
  596.  
  597.    /* Open output file or set output to stdout if no output name was found
  598.      * as a command line parameter. */
  599.    if ( ofname == NULL )
  600.       out_file = stdout;
  601.    else
  602.       if ( (out_file = fopen( ofname, "wt" )) == NULL ) {
  603.           perror( "fopen" );
  604.           exit( 1 );
  605.       } /* end if ofname */
  606.       
  607.     /*  Allocate memory for the output page */
  608.     if ( !(cur_page = (uchar**)malloc( pg_lines * sizeof( uchar* ) )) ) {
  609.         perror( "malloc" );
  610.         exit(1);
  611.     } /* end if */
  612.    for (i = 0; i < pg_lines; i++) {
  613.        /* allocate memory for every line. We need one extra byte if word
  614.          * wrapping is on, because of a posible overlapping last character */
  615.       if ( !(cur_page[i] = (uchar*)malloc( (pg_width + word_wrap) * sizeof(uchar)))) {
  616.          perror( "malloc" );
  617.          exit(1);
  618.       } /* end if */
  619.       spc( cur_page[i], left_spc );
  620.    } /* end for */
  621.     pcur_pos = &cur_page[0][left_spc];
  622.    /* Set input file to first filename for input or stdin if no input name
  623.     * was specified. */
  624.     if ( optind >= argc )
  625.         in_file = stdin;
  626.     else {
  627.         if ( (in_file = fopen( argv[optind], "rt" )) == NULL ) {
  628.             perror( "fopen" );
  629.             exit(1);
  630.         } /* end if */
  631.         #ifdef DEBUG
  632.        fprintf( stderr, "File %s opened succesfully\n", argv[optind] );
  633.         #endif
  634.     }       
  635.     /* first loop which opens every file given as a parameter */
  636.     do {
  637.         optind++;
  638.         /* second loop which reads every file until eof is reached */
  639.         while ( fgets( in_buf, sizeof( in_buf ), in_file ) ) {
  640.             puttooutbuf( in_buf );
  641.         } /* end while */
  642.         fclose( in_file );
  643.  
  644.       if ( sepfiles && !((cur_col == 0) & (cur_line == 0)) ) {
  645.           /* print the rest of the last file and fill buffer */
  646.           printpg();
  647.             cur_col = cur_col_pos = cur_line = 0;
  648.             pcur_pos = &cur_page[0][left_spc];
  649.         }
  650.           
  651.         if ( optind < argc ) {
  652.             if ( (in_file = fopen( argv[optind], "rt" )) == NULL ) {
  653.                 /* The file was not found
  654.                  * Nevertheless print the rest contents of the buffer
  655.                  * and stop executing afterwards */
  656.                 printpgrest();
  657.                 perror( "fopen" );
  658.                 exit(1);
  659.             } /* end if */
  660.             #ifdef DEBUG
  661.            fprintf( stderr, "file %s opened succesfully\n", argv[optind] );
  662.             #endif
  663.         } /* end if (optind < argc) */
  664.     } while ( optind < argc ); /* end do while */
  665.  
  666.     /* print the rest of the output buffer and free the memory used for it */
  667.     printpgrest();
  668.  
  669.    /* exit program */
  670.     if ( out_file != stdout ) {
  671.         fclose( out_file );
  672.         printf( "%s ready\n", prog );
  673.         printf( "Name of output file: %s\n", ofname );
  674.     }
  675.    return 0;
  676. }
  677.