home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / TEXT / UTILITY / CC21.ZIP / CC.C next >
Encoding:
C/C++ Source or Header  |  1990-08-02  |  12.0 KB  |  278 lines

  1. /*-------------------------------------------------------------------------*/
  2. /* Program:    CC      .C                                                  */
  3. /* Purpose:    Processes ASA carriage control characters in a file.        */
  4. /* Notes:      Compiles under TURBO C, v2.0. Should work on any machine    */
  5. /*                running MS-DOS, v2.xx or higher.                         */
  6. /* Status:     Released into the public domain. Enjoy! If you use it,      */
  7. /*                let me know what you think. You don't have to send       */
  8. /*                any money, just comments and suggestions.                */
  9. /* Updates:    02-Mar-89, v1.0, GAT                                        */
  10. /*                - initial version.                                       */
  11. /*             02-May-89, v1.1, GAT                                        */
  12. /*                - eliminated some start-up code.                         */
  13. /*             03-Dec-89, v1.2, GAT                                        */
  14. /*                - Improved efficiency of help message display.           */
  15. /*                - Renamed ErrMsg() to write_ErrMsg().                    */
  16. /*                - Now write_ErrMsg adds a period and CR/LF combination.  */
  17. /*             03-Jan-90, v2.0, GAT                                        */
  18. /*                - Rewrote principal functions.                           */
  19. /*                - Replaced most #defines with enumerations.              */
  20. /*                - Used AT&T's getopt() for program args.                 */
  21. /*                - Separated usage message into its own function.         */
  22. /*                - Tweaked variable storage.                              */
  23. /*                - Eliminated -t option for processing tab characters.    */
  24. /*                - Added headers in case of multiple files.               */
  25. /*             02-Aug-90, v2.1a, GAT                                       */
  26. /*                - Added a CR to output stream before each formfeed.      */
  27. /*                - Used return in main() rather than exit().              */
  28. /*-------------------------------------------------------------------------*/
  29.  
  30. /*-------------------------------------------------------------------------*/
  31. /* Author:     George A. Theall                                            */
  32. /* Phone:      (215) 662-0558                                              */
  33. /* SnailMail:  TifaWARE                                                    */
  34. /*             506 South 41st St., #3M                                     */
  35. /*             Philadelphia, PA.  19104   USA                              */
  36. /* E-Mail:     GTHEALL@PENNDRLS.UPENN.EDU (ARPA Internet)                  */
  37. /*-------------------------------------------------------------------------*/
  38.  
  39. /* Useful type definitions. */
  40. typedef int BOOLEAN;
  41.  
  42. typedef enum {                               /* error classes           */
  43.    err_open,                                 /*    can't open a file    */
  44.    err_read,                                 /*    can't read from file */
  45.    err_write                                 /*    can't write to file  */
  46. } ERR_TYPE;
  47.  
  48. typedef enum {                               /* return codes */
  49.    rc_ok    = 0,
  50.    rc_help  = 1,
  51.    rc_open  = 10,
  52.    rc_read  = 15,
  53.    rc_write = 20
  54. } RC_TYPE;
  55.  
  56. #define FALSE        0
  57. #define TRUE         1
  58. #define VERS         "2.1a"
  59.  
  60. #include <stdio.h>
  61. #include <ctype.h>                           /* for isdigit() */
  62. #include <dir.h>                             /* for fnsplit(), MAXFILE, etc */
  63. #include <stdarg.h>                          /* for va_arg, etc.. */
  64. #include <stdlib.h>                          /* for exit() */
  65. #include <string.h>                          /* for strlwr() */
  66. #include "getopt.h"
  67.  
  68. static char ProgName[MAXFILE];               /* space for filename */
  69. char *ifn, *ofn;                             /* input/output file names */
  70. static BOOLEAN                               /* flags for various options */
  71.    HFlag = FALSE;                            /*    needs help?            */
  72.  
  73. /* Define the program's error messages. */
  74. /*
  75.  * NB: getopt() itself is responsible for generating the following
  76.  * error messages, which do not appear in the structure below:
  77.  *    ": illegal option -- %c"
  78.  *    ": option requires an argument -- %c"
  79.  */
  80. const static struct {
  81.    ERR_TYPE Type;
  82.    char *Msg;
  83. } Error[] = {
  84.    err_open,  ": can't open %s",
  85.    err_read,  ": can't read from %s; processing halted at line %lu",
  86.    err_write, ": can't write to %s; processing halted at line %lu of %s"
  87. };
  88.  
  89. void _setenvp(void) {};                      /* drop some start-up code */
  90.  
  91.  
  92. /*---  main  --------------------------------------------------------------+
  93. |  Purpose:    Main body of program.                                       |
  94. |  Notes:      none                                                        |
  95. |  Entry:      argc = ARGument Count,                                      |
  96. |              argv = array of ARGument Variables.                         |
  97. |  Exit:       Return code as enumerated by RC_TYPE.                       |
  98. +-------------------------------------------------------------------------*/
  99. int main(int argc, char *argv[])
  100. {
  101.    char ch;
  102.    BOOLEAN hdrs;                             /* need headers? */
  103.    RC_TYPE rc = rc_ok;                       /* program return code */
  104.    FILE *ifp, *ofp;                          /* input/output file pointers */
  105.    void write_Usage(void);
  106.    void write_ErrMsg(const char *, ...);
  107.    void process_InputFile(FILE *, FILE *);
  108.  
  109.    /*
  110.     * Isolate program name to keep error messages neat. This kludge
  111.     * is necessary for DOS v2.xx when argv[0] is NULL.
  112.     */
  113.    fnsplit((*argv == NULL) ? __FILE__ : *argv,  /* TURBO C extension! */   
  114.       NULL, NULL, ProgName, NULL);
  115.    *argv = strlwr(ProgName);                    /* TURBO C extension! */
  116.  
  117.    /* All options must appear before any filenames. */
  118.    while ((ch = getopt(argc, argv, "?")) != EOF)
  119.       switch (ch) {
  120.          case '?': HFlag = TRUE; break;      /* help needed or requested */
  121.          default:  ; /* EMPTY */             /* Unreached */
  122.       }
  123.    do {
  124.       --argc;
  125.       ++argv;
  126.    } while (--optind);                       /* nb: optind >= 1 in getopt() */
  127.  
  128.    if (HFlag == TRUE) {
  129.       write_Usage();
  130.       exit(rc_help);
  131.    }
  132.  
  133.    /* Loop thru each file named on commandline. */
  134.    ofp = stdout;                             /* might be changed later */
  135.    ofn = "stdout";
  136.    if (argc == 0) {
  137.       ifn = "stdin";
  138.       process_InputFile(stdin, ofp);
  139.    }
  140.    else {
  141.       hdrs = (argc > 1) ? TRUE : FALSE;      /* headers needed if > 1 file */
  142.       do {
  143.          ifn = *argv++;
  144.          if ((ifp = fopen(ifn, "r")) == NULL) {
  145.             write_ErrMsg(Error[err_open].Msg, ifn);
  146.             rc = rc_open;
  147.             continue;                        /* skip file; don't abort */
  148.          }
  149.          if (hdrs == TRUE)
  150.             fprintf(ofp, "==> %s <==\n", ifn);
  151.          process_InputFile(ifp, ofp);
  152.          fclose(ifp);
  153.       } while (--argc);
  154.    }
  155.  
  156.    return rc;
  157. }
  158.  
  159. /*---  write_ErrMsg  ------------------------------------------------------+
  160. |  Purpose:    Writes an error message to stderr.                          |
  161. |  Notes:      Refer to TURBO C _REFERENCE GUIDE_ for information about    |
  162. |                 functions with a variable number of args.                |
  163. |  Entry:      MsgFmt = string containing message format,                  |
  164. |              ... = optional arguments in same format as printf().        |
  165. |  Exit:       n/a                                                         |
  166. +-------------------------------------------------------------------------*/
  167. void write_ErrMsg(const char *MsgFmt, ...)
  168. {
  169.    va_list ArgPtr;
  170.  
  171.    fputs(ProgName, stderr);
  172.    va_start(ArgPtr, MsgFmt);
  173.    vfprintf(stderr, MsgFmt, ArgPtr);
  174.    va_end(ArgPtr);
  175.    fputs(".\n", stderr);
  176. }
  177.  
  178.  
  179. /*---  write_Usage  -------------------------------------------------------+
  180. |  Purpose:    Provides a brief message about program usage.               |
  181. |  Notes:      none                                                        |
  182. |  Entry:      n/a                                                         |
  183. |  Exit:       n/a                                                         |
  184. +-------------------------------------------------------------------------*/
  185. void write_Usage(void)
  186. {
  187.    fprintf(stderr, "\n"
  188.       "TifaWARE CC, v" VERS ", " __DATE__
  189.          " - processes ASA carriage control characters.\n"
  190.       "Usage:  %s [-options] [file(s)]\n"
  191.       "\n"
  192.       "Options:\n"
  193.       "  -? = provide this help message\n"
  194.       "\n"
  195.       "Stdin is used if no files are specified. Wildcards are not allowed.\n",
  196.       ProgName);
  197. }
  198.  
  199.  
  200. /*---  process_InputFile  -------------------------------------------------+
  201. |  Purpose:    Processes carriage controls in a given file.                |
  202. |  Notes:      An error here will cause program to abort via exit().       |
  203. |              Global variables ifn, ofn are used but not changed.         |
  204. |  Entry:      ifp = pointer to input file,                                |
  205. |              ofp = pointer to output file.                               |
  206. |  Exit:       n/a                                                         |
  207. +-------------------------------------------------------------------------*/
  208. void process_InputFile(FILE *ifp, FILE *ofp)
  209. {
  210.    char ch;
  211.    unsigned long line = 0L;                  /* up to ~4 billion in Turbo C! */
  212.    BOOLEAN BadCC;                            /* an invalid CC? */
  213.  
  214.    /*
  215.     * Process a line at a time. Read each character separately to avoid
  216.     * reserving space for a line and arbitary limits on line length.
  217.     */
  218.    do {
  219.  
  220.       ++line;
  221.  
  222.       /*
  223.        * As described in IBM's _CMS Command and Macro Reference_, p. 568, 
  224.        * ASA carriage control characters have the following meanings:
  225.        * 
  226.        *    space   advance 1 line before printing,
  227.        *    0       advance 2 lines before printing,
  228.        *    -       advance 3 lines before printing,
  229.        *    +       surpress line advance before printing,
  230.        *    1       advance to new page.
  231.        *
  232.        * An invalid control character causes the line advance to be
  233.        * surpressed before printing but added afterwards. 
  234.        */
  235.       /*
  236.        * NB: an empty line is treated as if it had a sole blank. This
  237.        * behaviour is not spelled out anywhere, but then again records
  238.        * in files under CMS must contain at least 1 character.
  239.        */
  240.       BadCC = FALSE;
  241.       switch (ch = fgetc(ifp)) {
  242.          case '-':  fputc('\n', ofp);           /* 3 line feeds */
  243.                     /* FALL THROUGH */
  244.          case '0':  fputc('\n', ofp);           /* 2 line feeds */
  245.                     /* FALL THROUGH */
  246.          case ' ':  fputc('\n', ofp); break;    /* 1 line feed */
  247.          case '+':  fputc('\r', ofp); break;    /* carriage return */
  248.          case '1':  fputc('\r', ofp);           /* top of form */
  249.                     fputc('\f', ofp); break;
  250.          case '\n': fputc('\n', ofp); continue; /* line is empty */
  251.          case EOF:  continue;                   /* nothing more */
  252.          default:                               /* invalid character */
  253.             fputc('\r', ofp);
  254.             BadCC = TRUE;
  255.             break;
  256.       }
  257.  
  258.       /* Print rest of line. NB: EOF = fgetc() if eof or error arises. */
  259.       while ((ch = fgetc(ifp)) != '\n' && ch != EOF)
  260.          fputc(ch, ofp);
  261.  
  262.       /* Handle any bad carriage controls. */
  263.       if (BadCC == TRUE)
  264.          fputc('\n', ofp);
  265.    } while (ch != EOF && !ferror(ofp));      /* EOF => eof or error wrt ifp */
  266.  
  267.    /* Test for errors. */
  268.    if (ferror(ifp)) {
  269.       write_ErrMsg(Error[err_read].Msg, ifn, line);
  270.       exit(rc_read);
  271.    }
  272.    fputc('\n', ofp);                         /* for good measure */
  273.    if (ferror(ofp)) {
  274.       write_ErrMsg(Error[err_write].Msg, ofn, line, ifn);
  275.       exit(rc_write);
  276.    }
  277. }
  278.