/* strip.c - Strip control characters from text files */ /* Copyright (c) 1998 by Ira E McDonald (High North Inc) */ /* NOTE -- Please read full description at 'strip_synopsis[]' */ /* later in this program source file. */ /* NOTE -- This program uses strictly ISO 9899:1990 (ISO C) */ /* compliant header files, functions, and statements. */ /* However, this program declares BOTH strictly ISO C */ /* compliant fully specified function prototypes AND */ /* traditional C function declarations for greater */ /* portability to older systems (eg, SunOS). */ /* NOTE -- This program compiles warning free in strict ISO C. */ /* Standard Header Files */ #include #include #include #include #include /* Standard Logicals for C (Pascal Style) */ /* NOTE -- The specific intent behind the use of the 'Standard */ /* Logicals for C' in a program is to ensure: 1) the */ /* appearance of an equal sign ('=') ALWAYS indicates */ /* an assignment operation; 2) the appearance of an */ /* ampersand ('&') ALWAYS indicates EITHER a bitwise */ /* AND or a Reference operation; and 3) the appearance */ /* of a vertical bar ('|') ALWAYS indicates a bitwise */ /* OR operation. */ /* NOTE -- For strict compliance with ISO 9899 AM1:1994 (ISO C) */ /* the following logicals should be in lowercase, */ /* as per the header file 'iso646.h'. */ #ifdef __STDC__ #undef LT #undef GT #undef LE #undef GE #undef EQ #undef NE #undef AND #undef OR #undef NOT #undef TRUE #undef FALSE #endif #define LT < #define GT > #define LE <= #define GE >= #define EQ == #define NE != #define AND && #define OR || #define NOT ! #define TRUE 1 #define FALSE 0 /* Standard Simple Types for C */ /* NOTE -- The specific intent behind the use of the 'Standard */ /* Simple Types for C' is to ensure: 1) the maximal */ /* clarity of intended program behavior; and 2) the use */ /* of a single token for any simple type declaration. */ /* NOTE -- For strict compliance with the 'Clean C' dialect, */ /* compatible with both ISO C and ISO C++ (draft) and */ /* described in 'C: A Reference Manual' by Harbison */ /* and Steele (4th Edition, January 1995), the simple */ /* type 'boolean' should be respelled 'bool'. */ #ifdef __STDC__ #undef uchar #undef ushort #undef uint #undef ulong #undef boolean #endif #define uchar unsigned char #define ushort unsigned short #define uint unsigned int #define ulong unsigned long #define boolean unsigned char /*********************************************************************/ /* Global constants */ /*********************************************************************/ #define STRIP_READ_MAX 1024 /* Buffer Read Max Length */ /*********************************************************************/ /* Global variables */ /*********************************************************************/ char *strip_synopsis[] = { /* 'strip_synopsis' */ "Usage: strip [-ftv] filename ...", "", " filename = < file_root.file_ext >", " -f Replace each FORMFEED with one SPACE", " else, copy each FORMFEED 'as is'", " -t Replace each TAB with one SPACE", " else, copy each TAB 'as is'", " -v Verbose log output mode", " (HINT - redirect verbose log output to a file)", "", "Ex: strip -v myfile.txt >myfile.log", " (strip 'myfile.txt',", " verbose log to file 'myfile.log',", " new 'stripped' version to 'myfile.out')", "", "Note: The 'stripped' result is written to 'file_root.out'", "", "'strip' is a utility to remove control characters from text files", "Copyright (c) 1998 by Ira E McDonald (High North Inc)", NULL }; /* 'strip_synopsis' */ char strip_ibuffer[STRIP_READ_MAX+2];/* Input File Buffer */ char strip_obuffer[STRIP_READ_MAX+2];/* Output File Buffer */ /*********************************************************************/ /* Global function declarations */ /*********************************************************************/ #ifdef __STDC__ extern int main ( /* Mainline */ int argc, /* Argument Count */ char *argv[]); /* Argument Vector */ #else extern int main (); /* Mainline */ #endif #ifdef __STDC__ static void strip_show_synopsis ( /* Display Program Synopsis */ void); /* No Arguments */ #else static void strip_show_synopsis (); /* Display Program Synopsis */ #endif #ifdef __STDC__ static void strip_scan_file ( /* Scan File */ char *ifn, /* Input File Name */ boolean ff, /* Formfeed To Space Flag */ boolean tf, /* Tab To Space Flag */ boolean vf); /* Verbose Flag */ #else static void strip_scan_file (); /* Scan File */ #endif #ifdef __STDC__ static void strip_error_exit ( /* Log Error and Exit */ char *es); /* Error Message String */ #else static void strip_error_exit (); /* Log Error and Exit */ #endif /*********************************************************************/ /* Function: main() */ /*********************************************************************/ #ifdef __STDC__ extern int main ( /* Mainline */ int argc, /* Argument Count */ char *argv[]) /* Argument Vector */ #else extern int main ( /* Mainline */ argc, /* Argument Count */ argv) /* Argument Vector */ int argc; /* Argument Count */ char *argv[]; /* Argument Vector */ #endif { /* 'main' */ int ai; /* Argument Index */ char *ap; /* Argument Pointer */ boolean ff = FALSE; /* Formfeed Flag */ boolean tf = FALSE; /* Tab Flag */ boolean vf = FALSE; /* Verbose Flag */ /* Check for missing input arguments */ if (argc LT 2) strip_show_synopsis (); /* Check for options */ for (ai = 1; ai LT argc; ai++) { /* Get pointer to next input argument */ ap = argv[ai]; /* Check for for leading dash (option token) */ if (*ap NE '-') break; /* Parse zero or more options (case insensitive) */ for (ap++; *ap; ap++) { switch (*ap) { case 'f': /* Formfeed Chars to Spaces */ case 'F': /* Formfeed Chars to Spaces */ ff = TRUE; break; case 't': /* Tab Chars to Spaces */ case 'T': /* Tab Chars to Spaces */ tf = TRUE; break; case 'v': /* Verbose */ case 'V': /* Verbose */ vf = TRUE; break; default: break; } } } /* Check for missing input filename(s) */ if (ai GE argc) strip_show_synopsis (); /* Process all input files */ for (; ai LT argc; ai++) { /* Get next input filename */ ap = argv[ai]; if (strlen (ap) EQ 0) strip_error_exit ("Missing iuput filename"); /* Process next input file */ strip_scan_file (ap, ff, tf, vf); } (void) printf ("strip: Normal termination\n"); return (0); } /* 'main' */ /*********************************************************************/ /* Function: strip_show_synopsis() */ /*********************************************************************/ #ifdef __STDC__ static void strip_show_synopsis ( /* Display Program Synopsis */ void) /* No Arguments */ #else static void strip_show_synopsis ( /* Display Program Synopsis */ ) /* No Arguments */ #endif { /* 'strip_show_synopsis' */ int si; /* Synopsis Index */ /* Display program synopsis */ for (si = 0; strip_synopsis[si]; si++) (void) printf ("%s\n", strip_synopsis[si]); exit (0); } /* 'strip_show_synopsis' */ /*********************************************************************/ /* Function: strip_scan_file() */ /*********************************************************************/ #ifdef __STDC__ static void strip_scan_file ( /* Scan File */ char *ifn, /* Input File Name */ boolean ff, /* Formfeed To Space Flag */ boolean tf, /* Tab To Space Flag */ boolean vf) /* Verbose Flag */ #else static void strip_scan_file ( /* Scan File */ ifn, /* Input File Name */ ff, /* Formfeed To Space Flag */ tf, /* Tab To Space Flag */ vf) /* Verbose Flag */ char *ifn; /* Input File Name */ boolean ff; /* Formfeed Flag */ boolean tf; /* Tab Flag */ boolean vf; /* Verbose Flag */ #endif { /* 'strip_scan_file' */ static FILE *ifp = NULL; /* Input File Pointer */ char *ibp; /* Input Buffer Pointer */ int ibl; /* Input Buffer Length */ int ibc; /* Input Buffer Count */ long icc; /* Input Control Count */ long igc; /* Input Graphic Count */ long itc; /* Input Tab Count */ long ilc; /* Input Line Count */ static FILE *ofp = NULL; /* Output File Pointer */ char *ofn; /* Output File Name */ char ofs[80]; /* Output File String */ char *obp; /* Output Buffer Pointer */ int obl; /* Output Buffer Length */ int owl; /* Output Write Length */ char es[80]; /* Error Message String */ /* Construct output file name */ ofn = &ofs[0]; strcpy (ofn, ifn); while ((*ofn NE '.') AND (*ofn NE '\0')) ofn++; strcpy (ofn, ".out"); ofn = &ofs[0]; if (strcmp (ifn, ofn) EQ 0) { (void) sprintf (es, "Input file ('%s') EQ output file", ifn); strip_error_exit (es); } /* Open input file */ if (ifp) ifp = freopen (ifn, "rb", ifp); else ifp = fopen (ifn, "rb"); if (NOT ifp) { (void) sprintf (es, "Error opening input file '%s'", ifn); strip_error_exit (es); } /* Open output file */ if (ofp) ofp = freopen (ofn, "wb", ofp); else ofp = fopen (ofn, "wb"); if (NOT ofp) { (void) sprintf (es, "Error opening output file '%s'", ofn); strip_error_exit (es); } /* Read and scan input file */ for (icc = igc = itc = ilc = 0; ;) { /* Perform BINARY read of input file */ ibp = &strip_ibuffer[0]; ibl = fread (ibp, 1, STRIP_READ_MAX, ifp); if (NOT ibl) break; obp = &strip_obuffer[0]; for (ibc = 0; ibc LT ibl; ibc++, ibp++) { /* Check for carriage return (and remove) */ if (*ibp EQ '\r') continue; /* Check for newline/linefeed (and handle for MSDOS) */ if (*ibp EQ '\n') { #ifdef OSMSDOS *obp++ = '\r'; #endif *obp++ = '\n'; ilc++; continue; } /* Check for formfeed (convert to space or 'as is') */ if (*ibp EQ '\f') { if (ff) *obp++ = ' '; else *obp++ = '\f'; itc++; continue; } /* Check for tab (convert to space or 'as is') */ if (*ibp EQ '\t') { if (tf) *obp++ = ' '; else *obp++ = '\t'; itc++; continue; } /* Check for graphic character (and remove) */ if (*ibp & 0x80) { igc++; continue; } /* Check for DEL or OTHER control character (and remove)*/ if ((*ibp EQ 0x7F) OR ((*ibp & 0x1F) EQ (*ibp))) { icc++; continue; } /* Copy all printing characters 'as is' */ *obp++ = *ibp; } /* Compute output buffer length and perform BINARY write */ obl = (int) (obp - &strip_obuffer[0]); obp = &strip_obuffer[0]; owl = fwrite (obp, 1, obl, ofp); if (owl NE obl) { (void) sprintf (es, "Error writing output file '%s'", ofn); strip_error_exit (es); } } /* Close input file */ (void) fclose (ifp); /* Close output file */ (void) fclose (ofp); /* Report on this file */ (void) printf ("From File='%s' To File='%s' Lines=%ld\n", ifn, ofn, ilc); /* Check for verbose report mode */ if (NOT vf) return; (void) printf ("<>\n", icc, igc, itc); return; } /* 'strip_scan_file' */ /*********************************************************************/ /* Function: strip_error_exit() */ /*********************************************************************/ #ifdef __STDC__ static void strip_error_exit ( /* Log Error and Exit */ char *es) /* Error Message String */ #else static void strip_error_exit ( /* Log Error and Exit */ es) /* Error Message String */ char *es; /* Error Message String */ #endif { /* 'strip_error_exit' */ (void) printf ("strip: %s\n", es); (void) printf ("strip: Abnormal termination\n"); exit (1); } /* 'strip_error_exit' */