home *** CD-ROM | disk | FTP | other *** search
- /*-------------------------------------------------------------------------*/
- /* Program: CC .C */
- /* Purpose: Processes ASA carriage control characters in a file. */
- /* Notes: Compiles under TURBO C, v2.0. Should work on any machine */
- /* running MS-DOS, v2.xx or higher. */
- /* Status: Released into the public domain. Enjoy! If you use it, */
- /* let me know what you think. You don't have to send */
- /* any money, just comments and suggestions. */
- /* Updates: 02-Mar-89, v1.0, GAT */
- /* - initial version. */
- /* 02-May-89, v1.1, GAT */
- /* - eliminated some start-up code. */
- /* 03-Dec-89, v1.2, GAT */
- /* - Improved efficiency of help message display. */
- /* - Renamed ErrMsg() to write_ErrMsg(). */
- /* - Now write_ErrMsg adds a period and CR/LF combination. */
- /* 03-Jan-90, v2.0, GAT */
- /* - Rewrote principal functions. */
- /* - Replaced most #defines with enumerations. */
- /* - Used AT&T's getopt() for program args. */
- /* - Separated usage message into its own function. */
- /* - Tweaked variable storage. */
- /* - Eliminated -t option for processing tab characters. */
- /* - Added headers in case of multiple files. */
- /* 02-Aug-90, v2.1a, GAT */
- /* - Added a CR to output stream before each formfeed. */
- /* - Used return in main() rather than exit(). */
- /*-------------------------------------------------------------------------*/
-
- /*-------------------------------------------------------------------------*/
- /* Author: George A. Theall */
- /* Phone: (215) 662-0558 */
- /* SnailMail: TifaWARE */
- /* 506 South 41st St., #3M */
- /* Philadelphia, PA. 19104 USA */
- /* E-Mail: GTHEALL@PENNDRLS.UPENN.EDU (ARPA Internet) */
- /*-------------------------------------------------------------------------*/
-
- /* Useful type definitions. */
- typedef int BOOLEAN;
-
- typedef enum { /* error classes */
- err_open, /* can't open a file */
- err_read, /* can't read from file */
- err_write /* can't write to file */
- } ERR_TYPE;
-
- typedef enum { /* return codes */
- rc_ok = 0,
- rc_help = 1,
- rc_open = 10,
- rc_read = 15,
- rc_write = 20
- } RC_TYPE;
-
- #define FALSE 0
- #define TRUE 1
- #define VERS "2.1a"
-
- #include <stdio.h>
- #include <ctype.h> /* for isdigit() */
- #include <dir.h> /* for fnsplit(), MAXFILE, etc */
- #include <stdarg.h> /* for va_arg, etc.. */
- #include <stdlib.h> /* for exit() */
- #include <string.h> /* for strlwr() */
- #include "getopt.h"
-
- static char ProgName[MAXFILE]; /* space for filename */
- char *ifn, *ofn; /* input/output file names */
- static BOOLEAN /* flags for various options */
- HFlag = FALSE; /* needs help? */
-
- /* Define the program's error messages. */
- /*
- * NB: getopt() itself is responsible for generating the following
- * error messages, which do not appear in the structure below:
- * ": illegal option -- %c"
- * ": option requires an argument -- %c"
- */
- const static struct {
- ERR_TYPE Type;
- char *Msg;
- } Error[] = {
- err_open, ": can't open %s",
- err_read, ": can't read from %s; processing halted at line %lu",
- err_write, ": can't write to %s; processing halted at line %lu of %s"
- };
-
- void _setenvp(void) {}; /* drop some start-up code */
-
-
- /*--- main --------------------------------------------------------------+
- | Purpose: Main body of program. |
- | Notes: none |
- | Entry: argc = ARGument Count, |
- | argv = array of ARGument Variables. |
- | Exit: Return code as enumerated by RC_TYPE. |
- +-------------------------------------------------------------------------*/
- int main(int argc, char *argv[])
- {
- char ch;
- BOOLEAN hdrs; /* need headers? */
- RC_TYPE rc = rc_ok; /* program return code */
- FILE *ifp, *ofp; /* input/output file pointers */
- void write_Usage(void);
- void write_ErrMsg(const char *, ...);
- void process_InputFile(FILE *, FILE *);
-
- /*
- * Isolate program name to keep error messages neat. This kludge
- * is necessary for DOS v2.xx when argv[0] is NULL.
- */
- fnsplit((*argv == NULL) ? __FILE__ : *argv, /* TURBO C extension! */
- NULL, NULL, ProgName, NULL);
- *argv = strlwr(ProgName); /* TURBO C extension! */
-
- /* All options must appear before any filenames. */
- while ((ch = getopt(argc, argv, "?")) != EOF)
- switch (ch) {
- case '?': HFlag = TRUE; break; /* help needed or requested */
- default: ; /* EMPTY */ /* Unreached */
- }
- do {
- --argc;
- ++argv;
- } while (--optind); /* nb: optind >= 1 in getopt() */
-
- if (HFlag == TRUE) {
- write_Usage();
- exit(rc_help);
- }
-
- /* Loop thru each file named on commandline. */
- ofp = stdout; /* might be changed later */
- ofn = "stdout";
- if (argc == 0) {
- ifn = "stdin";
- process_InputFile(stdin, ofp);
- }
- else {
- hdrs = (argc > 1) ? TRUE : FALSE; /* headers needed if > 1 file */
- do {
- ifn = *argv++;
- if ((ifp = fopen(ifn, "r")) == NULL) {
- write_ErrMsg(Error[err_open].Msg, ifn);
- rc = rc_open;
- continue; /* skip file; don't abort */
- }
- if (hdrs == TRUE)
- fprintf(ofp, "==> %s <==\n", ifn);
- process_InputFile(ifp, ofp);
- fclose(ifp);
- } while (--argc);
- }
-
- return rc;
- }
-
- /*--- write_ErrMsg ------------------------------------------------------+
- | Purpose: Writes an error message to stderr. |
- | Notes: Refer to TURBO C _REFERENCE GUIDE_ for information about |
- | functions with a variable number of args. |
- | Entry: MsgFmt = string containing message format, |
- | ... = optional arguments in same format as printf(). |
- | Exit: n/a |
- +-------------------------------------------------------------------------*/
- void write_ErrMsg(const char *MsgFmt, ...)
- {
- va_list ArgPtr;
-
- fputs(ProgName, stderr);
- va_start(ArgPtr, MsgFmt);
- vfprintf(stderr, MsgFmt, ArgPtr);
- va_end(ArgPtr);
- fputs(".\n", stderr);
- }
-
-
- /*--- write_Usage -------------------------------------------------------+
- | Purpose: Provides a brief message about program usage. |
- | Notes: none |
- | Entry: n/a |
- | Exit: n/a |
- +-------------------------------------------------------------------------*/
- void write_Usage(void)
- {
- fprintf(stderr, "\n"
- "TifaWARE CC, v" VERS ", " __DATE__
- " - processes ASA carriage control characters.\n"
- "Usage: %s [-options] [file(s)]\n"
- "\n"
- "Options:\n"
- " -? = provide this help message\n"
- "\n"
- "Stdin is used if no files are specified. Wildcards are not allowed.\n",
- ProgName);
- }
-
-
- /*--- process_InputFile -------------------------------------------------+
- | Purpose: Processes carriage controls in a given file. |
- | Notes: An error here will cause program to abort via exit(). |
- | Global variables ifn, ofn are used but not changed. |
- | Entry: ifp = pointer to input file, |
- | ofp = pointer to output file. |
- | Exit: n/a |
- +-------------------------------------------------------------------------*/
- void process_InputFile(FILE *ifp, FILE *ofp)
- {
- char ch;
- unsigned long line = 0L; /* up to ~4 billion in Turbo C! */
- BOOLEAN BadCC; /* an invalid CC? */
-
- /*
- * Process a line at a time. Read each character separately to avoid
- * reserving space for a line and arbitary limits on line length.
- */
- do {
-
- ++line;
-
- /*
- * As described in IBM's _CMS Command and Macro Reference_, p. 568,
- * ASA carriage control characters have the following meanings:
- *
- * space advance 1 line before printing,
- * 0 advance 2 lines before printing,
- * - advance 3 lines before printing,
- * + surpress line advance before printing,
- * 1 advance to new page.
- *
- * An invalid control character causes the line advance to be
- * surpressed before printing but added afterwards.
- */
- /*
- * NB: an empty line is treated as if it had a sole blank. This
- * behaviour is not spelled out anywhere, but then again records
- * in files under CMS must contain at least 1 character.
- */
- BadCC = FALSE;
- switch (ch = fgetc(ifp)) {
- case '-': fputc('\n', ofp); /* 3 line feeds */
- /* FALL THROUGH */
- case '0': fputc('\n', ofp); /* 2 line feeds */
- /* FALL THROUGH */
- case ' ': fputc('\n', ofp); break; /* 1 line feed */
- case '+': fputc('\r', ofp); break; /* carriage return */
- case '1': fputc('\r', ofp); /* top of form */
- fputc('\f', ofp); break;
- case '\n': fputc('\n', ofp); continue; /* line is empty */
- case EOF: continue; /* nothing more */
- default: /* invalid character */
- fputc('\r', ofp);
- BadCC = TRUE;
- break;
- }
-
- /* Print rest of line. NB: EOF = fgetc() if eof or error arises. */
- while ((ch = fgetc(ifp)) != '\n' && ch != EOF)
- fputc(ch, ofp);
-
- /* Handle any bad carriage controls. */
- if (BadCC == TRUE)
- fputc('\n', ofp);
- } while (ch != EOF && !ferror(ofp)); /* EOF => eof or error wrt ifp */
-
- /* Test for errors. */
- if (ferror(ifp)) {
- write_ErrMsg(Error[err_read].Msg, ifn, line);
- exit(rc_read);
- }
- fputc('\n', ofp); /* for good measure */
- if (ferror(ofp)) {
- write_ErrMsg(Error[err_write].Msg, ofn, line, ifn);
- exit(rc_write);
- }
- }
-