home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / PRINTING / CRAM_V21.ZIP / CRAM.C next >
C/C++ Source or Header  |  1990-12-31  |  15KB  |  440 lines

  1. /*
  2.  *   ------------------------------------
  3.  *   C R A M   -   the ASCII file reducer
  4.  *   ------------------------------------
  5.  *
  6.  *   CRAM  -  ASCII File Reducer  - V2.1
  7.  *   Copyright (c) 1988-90  -  Dean Tutterow  -  All Rights Reserved
  8.  *   
  9.  *   What  does  it do?   It crams as  much text  as possible onto a page
  10.  *   in  reduced format.   Using  subscript characters as  the font on an
  11.  *   Epson printer,  you  can print up to 79 characters wide and 154 rows
  12.  *   long in 2 columns.   That  works  out to  5-6 pages of  text on each
  13.  *   printed  page.   In  normal use  with  files with embedded formfeeds
  14.  *   respected, you get 4 pages of text on each printed page.
  15.  *
  16.  *   CRAM  was  written  after  I  had  printed  another  of  those  LONG
  17.  *   documentation files.  I was tired of those STACKS of listings, etc.,
  18.  *   that  gathered  dust  simply  because they  were too much trouble to
  19.  *   handle  once I printed  them.   Now  the  printed listings are small
  20.  *   enough to keep in notebooks.   As a bonus, CRAM is especially useful
  21.  *   for printing program listings.  The reduced format is just the thing
  22.  *   to show program structure and the BIG picture!
  23.  *
  24.  *   While not limited to Epson printers,  it is hardcoded for my FX-86e.
  25.  *   Of course you can provide your own setup and un-setup codes for your
  26.  *   printer, and include them in a printer setup file for CRAM to use.
  27.  *
  28.  *   USAGE:
  29.  *   
  30.  *   CRAM srcfile crammedfile [/options]
  31.  *
  32.  *   where [/options] are:
  33.  *          /COLUMN=n       with 1 ≤ n ≥ 10
  34.  *          /FF             if <FF> encountered, align to next logical page
  35.  *          /LARGE          use PICA format to get 137 characters/line
  36.  *          /PAGELENGTH=n   may vary printed page length from 1-154 lines
  37.  *          /SKIP=n         number of columns to ignore in srcfile
  38.  *          /WHITE=n        number of characters of whitespace on left of page
  39.  *   
  40.  *   The  srcfile  should  be  a  valid DOS filename;  wildcards  are not
  41.  *   accepted.   You  need  only  supply  enough  to the  option  name to
  42.  *   distinguish it from the other options, for example /C=1 and /R.
  43.  *   
  44.  *   As a daily VAX user,  I  have tried to implement the straightforward
  45.  *   command-line interface that VMS affords the user.  While the srcfile
  46.  *   and crammedfile must be in that order,  the options may be spread at
  47.  *   will along the command line.
  48.  *
  49.  *   The options are much easier understood after a few practice sessions.
  50.  *   '/COLUMN=n' is  used whenever you want more or less than the standard
  51.  *   two columns on each page.   While  normally  defaulted  to two-column
  52.  *   operation, only the first 79 characters on each line (unless some are
  53.  *   /SKIP-ped) are  visible.   '/FF' respects  embedded  formfeeds in the
  54.  *   text.   Normally off, this option moves to the next logical page when
  55.  *   encountered.   The pagelength is adjustable  through  '/PAGELENGTH=n'
  56.  *   The default is 132 rows,  which allows two pages in each column since
  57.  *   most formatters place 66 lines per page.  If you want your one-column
  58.  *   printing shifted right on the page so that you have whitespace on the
  59.  *   left  side of the page,  then '/WHITE' is just the ticket.   Finally,
  60.  *   '/SKIP=n' ignores the first 'n' characters on each line.  This allows
  61.  *   you  to  print  79  useful  characters  in each  column when printing
  62.  *   formatted files with spaces or tabs in the first 'n' columns.
  63.  */
  64.  
  65. #include <stdio.h>
  66. #include <string.h>
  67.  
  68. /*  G L O B A L   D E F I N E S  */
  69. #define byte         unsigned char
  70. #define MAX_CHAR     161
  71. #define MAX_ROWS     154
  72. #define MAX_ELEMENTS 8
  73. #define PICA         137
  74. #define ELITE        160
  75.  
  76.  
  77. /*  E R R O R   C O D E S  */
  78. #define FILENAME_TROUBLE    0x101
  79. #define INVALID_OPTION      0x102
  80. #define MISSING_FILE        0x103
  81. #define INVLD_NUM_COLUMNS   0x104
  82.  
  83. /*  S E V E R I T Y   C O D E S  */
  84. #define FATAL         "F"
  85. #define SEVERE        "S"
  86. #define WARNING       "W"
  87. #define INFORMATIONAL "I"
  88.  
  89. /*  G L O B A L   D A T A  */ 
  90. char    BUFFER[MAX_ROWS][MAX_CHAR];
  91. char    PRINTER_INIT[200];
  92. char    PRINTER_TERM[200];
  93. int     SKIP_PT   = 0;
  94. int     NUM_COLS  = 2;
  95. int     NUM_CHAR  = MAX_CHAR - 1;
  96. int     NUM_ROWS  = MAX_ROWS;
  97. byte    NUM_FILES = 0;
  98. byte    WHITE     = 0;
  99. byte    FF        = 0;
  100. byte    DISPLAYABLE;
  101. byte    LEFT_EDGE;
  102. char    *INFILE, *OUTFILE;
  103. FILE    *INPUT,  *OUTPUT;
  104.  
  105.  
  106. main (argc,argv)
  107.  
  108. int    argc;
  109. char    *argv[];
  110. {
  111.         int     i, j, carryover, value, lr, lc, current_col;
  112.         char    equivalence[100], parsed[120], *elements[MAX_ELEMENTS];
  113.         char    *option, *parse_option(), *status, *file_status, line[161];
  114.  
  115.         /* Tell them who I am. */
  116.         print_copyright ();
  117.  
  118.         /* Parse the command line for files and switches. */
  119.         memset (equivalence, '\0', sizeof (equivalence));
  120.     memset (parsed, '\0', sizeof (parsed));
  121.     for (i = 0; i < argc; i++) { 
  122.             strcat (equivalence, argv[i]);
  123.             strcat (equivalence, " ");
  124.         };
  125.         value = MAX_ELEMENTS;
  126.     parse_command_line (equivalence, parsed, elements, &value);
  127.     get_filenames_and_options (elements, &value, &INFILE, &OUTFILE);
  128.         get_printer_defaults ();
  129.     if (NUM_FILES != 2) err_exit (MISSING_FILE, FATAL);
  130.     if (NUM_ROWS > MAX_ROWS) NUM_ROWS = MAX_ROWS;
  131.     
  132.         /* Open the proper files for reading/writing. */
  133.         INPUT  = fopen (INFILE,  "rt");
  134.     OUTPUT = fopen (OUTFILE, "wt");
  135.         if (!INPUT || !OUTPUT) err_exit (FILENAME_TROUBLE, FATAL);
  136.     
  137.         /* Send the printer setup string. */
  138.         fputs (PRINTER_INIT, OUTPUT);
  139.  
  140.         /* Compute the maximum displayable portion of the input line. */
  141.         DISPLAYABLE = ( NUM_CHAR - NUM_COLS + 1 - WHITE ) / NUM_COLS;
  142.  
  143.         /* Read from the input file and build the output file in memory. */
  144.         carryover = 0;
  145.         do {
  146.             LEFT_EDGE = WHITE;
  147.             memset (BUFFER, ' ', NUM_ROWS * MAX_CHAR);
  148.             for ( i=0; i < NUM_ROWS; i++ ) BUFFER[i][NUM_CHAR] = 0;
  149.             for ( current_col=1,lc=lr=0; current_col<=NUM_COLS; current_col++ ) {
  150.               if ( carryover ) {
  151.                 filter_input(&line[0]);
  152.                 line[DISPLAYABLE] = '\0';
  153.                 if ( current_col != NUM_COLS )
  154.                     strncpy (&BUFFER[0][LEFT_EDGE], &line[0], strlen(line));
  155.                 else
  156.                     strcpy (&BUFFER[0][LEFT_EDGE], &line[0]);
  157.               };
  158.               for ( i=carryover; i < NUM_ROWS; i++ ) {
  159.                 carryover = 0;
  160.                 file_status = fgets (line, 159, INPUT);
  161.                 if (file_status == NULL) break;
  162.                 if ( FF && (line[0] == '\f') )
  163.                   if (i <= (NUM_ROWS+1)/2) i = carryover = (NUM_ROWS+1)/2;
  164.                   else  {carryover = 1; break; }
  165.                 filter_input(&line[0]);
  166.                 line[DISPLAYABLE] = '\0';
  167.                 if ( current_col != NUM_COLS )
  168.                     strncpy (&BUFFER[i][LEFT_EDGE], &line[0], strlen(line));
  169.                 else
  170.                     strcpy (&BUFFER[i][LEFT_EDGE], &line[0]);
  171.               };
  172.               if ( i > lr ) lr = i;
  173.               if (file_status == NULL) break;
  174.               LEFT_EDGE  = LEFT_EDGE + DISPLAYABLE + 1;
  175.               if ( carryover > 1 ) carryover = 0;
  176.             };
  177.  
  178.             /* Write out a page buffer and get ready for next page. */
  179.             for (i=0; i < lr; i++) {
  180.               j = strlen(&BUFFER[i][0]);
  181.               if (j)
  182.                 if (BUFFER[i][j-1] == '\n') j--;
  183.               if ( j > (NUM_CHAR - 1) ) j = NUM_CHAR - 1;
  184.               BUFFER[i][j]   = '\n';
  185.               BUFFER[i][j+1] = '\0';
  186.               fputs (&BUFFER[i][0], OUTPUT);
  187.             };
  188.             if (file_status != NULL) fputs ("\xc\0", OUTPUT);
  189.         } while (file_status);
  190.  
  191.         /* Send the printer termination string and close all files. */
  192.         fputs (PRINTER_TERM, OUTPUT);
  193.     fclose(INPUT);
  194.     fclose(OUTPUT);
  195. }
  196.  
  197. int     _nullcheck () {};
  198. int     _setenvp () {};
  199.  
  200.  
  201. int    print_copyright ()
  202.  
  203. {
  204.         fprintf (stderr, "CRAM  -  ASCII File Reducer  -  V2.1\n");
  205.         fprintf (stderr, "Copyright (c) 1988-90  -  Dean Tutterow  -  All Rights Reserved\n");
  206. }
  207.  
  208.  
  209.  
  210. int     filter_input (line)
  211.  
  212. char    *line;
  213. {
  214.     int     i, n;
  215.         char    newline[161], *oldline;
  216.  
  217.     /* Clean all tabs and formfeeds from the input line. */
  218.     oldline = line;
  219.     memset (newline, '\0', sizeof (newline));
  220.     for ( i = 0; i < sizeof(newline); ) {
  221.       if (*line == '\0') { newline[i] = '\0'; break; }
  222.           if (*line == '\n') *line = ' ';
  223.           if (*line == '\f') { 
  224.         *line = ' '; strcpy (&newline[i], "<FF>"); i += 4; }
  225.       if (*line == '\t') {
  226.         n = i;
  227.         while (n >= 0) 
  228.           n -= 8;
  229.         n = -n;
  230.         strncpy (&newline[i], "        ", n);
  231.         i += (n - 1); }
  232.       else 
  233.         newline[i] = *line;
  234.       i++;
  235.           line++;
  236.         };
  237.     if (newline[0] != 0x0D)
  238.       strcpy (oldline, &newline[SKIP_PT]);
  239.     else
  240.       strcpy (oldline, &newline[0]);
  241. }
  242.  
  243.  
  244. int     get_printer_defaults ()
  245.  
  246. {
  247.         char    *file_status;
  248.  
  249.         INPUT = fopen ("CRAM.DAT", "rt");
  250.         if ( !INPUT ) {
  251.           if ( NUM_CHAR == PICA )
  252.               strcpy ( PRINTER_INIT, "\x1b\x33\xf\x1b\x53\x30\xf\0" );
  253.           else
  254.               strcpy ( PRINTER_INIT, "\x1b\x33\xf\x1b\x53\x30\x1b\x4d\xf\0" );
  255.           strcpy ( PRINTER_TERM, "\x1b\x32\x1b\x54\x1b\x50\x12\x1a\0" );
  256.           return;
  257.         }
  258.         file_status = fgets (PRINTER_INIT, sizeof (PRINTER_INIT), INPUT);
  259.         if ( file_status == NULL ) goto file_error;
  260.         file_status = fgets (PRINTER_TERM, sizeof (PRINTER_TERM), INPUT);
  261.         if ( file_status == NULL ) goto file_error;
  262.         file_error:
  263.         fclose (INPUT);
  264.         return;
  265. }
  266.  
  267.  
  268.  
  269. int    parse_command_line (input, output, arrayed, number)
  270.  
  271. char    *input, *output, *arrayed[];
  272. int    *number;
  273. {
  274.     int     i, j, k, paren;
  275.  
  276.     /* Convert input line to upper case */
  277.     for (i=0; i < strlen(input); i++) 
  278.       (input)[i] = toupper ( (input)[i] );
  279.  
  280.     (output)[0] = ' ';
  281.  
  282.     for (i=k=paren=0, j=1; (i < strlen (input) && k <= *number); i++) {
  283.       switch ( (input)[i] ) {
  284.         case ','  : if (paren) { (output)[j] = (input)[i]; break; }
  285.         case ' '  : 
  286.         case '\t' : (output)[j] = ' '; break;
  287.         case '/'  : (output)[j] = ' '; j++; paren--;
  288.         case '('  : paren += 2;
  289.         case ')'  : paren--;
  290.         default   : (output)[j] = (input)[i];
  291.       }
  292.       j++;
  293.       /* 
  294.        * If this is the start of an argument, then place its address
  295.        * in the argument list & null-terminate the previous argument.
  296.        */
  297.       if ( (output)[j-1] != ' '  &&  (output)[j-2] == ' ' ) {
  298.         if (k != *number) {
  299.           (arrayed)[k] = (&(output)[j-1]);
  300.           k++; 
  301.         }
  302.         (output)[j-2] = '\0';
  303.       }
  304.         };
  305.     (output)[j] = '\0';
  306.     *number = k;
  307. };
  308.  
  309.  
  310.  
  311. char    *parse_option (option, output)
  312.  
  313. char    *option, **output;
  314. {
  315.     int    length_to_option;
  316.  
  317.     if (*option != '/') return (0);
  318.     if (!(length_to_option = strcspn (option, "=:"))) return (0);
  319.     if (length_to_option == strlen (option)) return (0);
  320.     *output = option + length_to_option + 1;
  321.     return ((char *)output);
  322. }
  323.  
  324.  
  325.  
  326. int    get_filenames_and_options (elements, value, INFILE, OUTFILE)
  327.  
  328. char    **INFILE, **OUTFILE, *elements[];
  329. int    *value;
  330. {
  331.     int    first, i;
  332.     char    *status, *option, *parse_option(), first_char;
  333.  
  334.     for (i = first = 1; i < *value; i++) {
  335.       if (*elements[i] != '/') {
  336.         if (first) { *INFILE = elements[i]; first = 0; }
  337.         else *OUTFILE = elements[i];
  338.         NUM_FILES++; }
  339.       else {
  340.         first_char = *(elements[i] + 1);
  341.         switch (first_char) {
  342.  
  343.         case 'C' :    /* # OF COLUMNS PARAMETER */
  344.             status = parse_option (elements[i], &option);
  345.                         if (status) sscanf (option, "%d", &NUM_COLS);
  346.                         else NUM_COLS = 2;
  347.                         if ( NUM_COLS > 10  || NUM_COLS < 1 )
  348.                             err_exit (INVLD_NUM_COLUMNS, FATAL);
  349.             break;
  350.  
  351.         case 'F' :    /* RECOGNIZE FORMFEEDS */
  352.             FF = 1;
  353.             break;
  354.  
  355.                 case 'L' :      /* LARGE-SMALL PRINT (CHARS/LINE = 137) */
  356.                         NUM_CHAR = PICA;
  357.                         break;
  358.  
  359.         case 'P' :    /* LINES-PER-PAGE PARAMETER */
  360.                         status = parse_option (elements[i], &option);
  361.                         if (status) sscanf (option, "%d", &NUM_ROWS);
  362.             else NUM_ROWS = MAX_ROWS;
  363.             break;
  364.  
  365.         case 'S' :    /* START INPUT PROCESSING AT THIS POSITON */
  366.             status = parse_option (elements[i], &option);
  367.             if (status) sscanf (option, "%d", &SKIP_PT);
  368.             else SKIP_PT = 0;
  369.             break;
  370.  
  371.                 case 'W' :      /* WHITE SPACE ON LEFT */
  372.                         status = parse_option (elements[i], &option);
  373.                         if (status) sscanf (option, "%d", &WHITE);
  374.                         else WHITE = 35;
  375.                         if ( WHITE > MAX_CHAR/2 )  WHITE = 35;
  376.                         break;
  377.  
  378.                 default : 
  379.             err_exit (INVALID_OPTION, WARNING);
  380.         }
  381.       }
  382.         };
  383. }
  384.  
  385.  
  386.  
  387. int    err_exit (code, severity)
  388.  
  389. int    code;
  390. char    *severity;
  391. {
  392.     char     err_code[20], msg[50];
  393.  
  394.     /* Display an error message, delete output file, exit. */
  395.  
  396.     switch (code) {
  397.  
  398.       case FILENAME_TROUBLE :
  399.                strcpy (msg, "Trouble opening files, please check filenames.");
  400.                strcpy (err_code, "FILEOPEN");
  401.                break;
  402.  
  403.       case MISSING_FILE :
  404.                strcpy (msg, "You must specify an input and output file.");
  405.                strcpy (err_code, "MISSFILE");
  406.                break;
  407.  
  408.       case INVALID_OPTION :
  409.                strcpy (msg, "You have specified an invalid option.");
  410.                strcpy (err_code, "INVLDOPT");
  411.                break;
  412.  
  413.           case INVLD_NUM_COLUMNS :
  414.                strcpy (msg, "You have specified an invalid number of columns.");
  415.                strcpy (err_code, "IVLDCOLS");
  416.                break;
  417.  
  418.           default : 
  419.                strcpy (msg, "Unknown error!");
  420.                strcpy (err_code, "UNKNOWN");
  421.     }
  422.  
  423.     fprintf (stderr, "\nCRAM-%c-%s, %s\n", *severity, err_code, msg);
  424.  
  425.     if ( (*severity == 'F')  ||  (*severity == 'S') ) {
  426.           fprintf (stderr, "\n  usage: CRAM infile outfile [options]\n\n");
  427.           fprintf (stderr, "  where [options] are:\n\t[/column=N]\n\t[/ff]\n\t");
  428.           fprintf (stderr, "[/large]\n\t[/pagelength=N]\n\t");
  429.           fprintf (stderr, "[/skip=N]\n\t[/white=N]\n");
  430.  
  431.           /* Close two files and delete partial output */
  432.       fclose (INPUT);
  433.       fclose (OUTPUT);
  434.       unlink (OUTFILE);
  435.     
  436.       /* Exit with errorlevel 1 */
  437.       exit (1);
  438.     }
  439. }
  440.