/* cscan.c - program to scan for control chars in source 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 FMAX 1024 /* file max line length */ #define CMAX 32 /* ctrl chars max */ /*********************************************************************/ /* Global variables */ /*********************************************************************/ static char *cscan_synopsis[] = { "Usage: cscan [-v] filename ...", "", " -v Verbose log output mode", " (HINT - redirect verbose log output to a file)", "", "Ex: cscan -v myfile.txt >myfile.log", " (scan 'myfile.txt',", " verbose log output to file 'myfile.log')", "", "'cscan' is a utility to count print/control/graphic chars", "Copyright (c) 1998 by Ira E McDonald (High North Inc)", NULL }; /* 'cscan_synopsis' */ static long delcnt; /* DEL (0x7f) count */ static long gracnt; /* Graphics char count */ static long prtcnt; /* Printing char count */ static long ctlcnt[CMAX]; /* Ctrl chars count array */ static char *cname[CMAX] = /* Ctrl chars names array */ { /* 'cname' */ "NUL(^@)", "SOH(^A)", "STX(^B)", "ETX(^C)", "EOT(^D)", "ENQ(^E)", "ACK(^F)", "BEL(^G)", "BS (^H)", "HT (^I)", "LF (^J)", "VT (^K)", "FF (^L)", "CR (^M)", "SO (^N)", "SI (^O)", "DLE(^P)", "DC1(^Q)", "DC2(^R)", "DC3(^S)", "DC4(^T)", "NAK(^U)", "SYN(^V)", "ETB(^W)", "CAN(^X)", "EM (^Y)", "SUB(^Z)", "ESC(^[)", "FS (^\\)", "GS (^])", "RS (^^)", "US (^_)", }; /* 'cname' */ /*********************************************************************/ /* 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 cscan_show_synopsis ( /* Display Program Synopsis */ void); /* No Arguments */ #else static void cscan_show_synopsis (); /* Display Program Synopsis */ #endif #ifdef __STDC__ static void cscan_scan_file ( /* Scan File */ char *fn, /* File Name */ boolean vf); /* Verbose Flag */ #else static void cscan_scan_file (); /* Scan File */ #endif #ifdef __STDC__ static void cscan_error_exit ( /* Log Error and Exit */ char *es); /* Error Message String */ #else static void cscan_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 vf = FALSE; /* verbose flag */ /* Check for missing input parameters */ if (argc LT 2) cscan_show_synopsis (); /* Check for switches */ for (ai = 1; ai LT argc; ai++) { ap = argv[ai]; if (*ap NE '-') break; for (ap++; *ap; ap++) { switch (*ap) { case 'v': case 'V': vf = TRUE; break; default: break; } } } /* Check for missing input filenames */ if (ai GE argc) cscan_show_synopsis (); /* Check all specified files */ for (; ai LT argc; ai++) { /* Get next input filename */ ap = argv[ai]; if (strlen (ap) EQ 0) cscan_show_synopsis (); /* Process next input file */ cscan_scan_file (ap, vf); } printf ("cscan: Normal termination\n"); return (0); } /* 'main' */ /*********************************************************************/ /* Function: cscan_show_synopsis() */ /*********************************************************************/ #ifdef __STDC__ static void cscan_show_synopsis ( /* Display Program Synopsis */ void) /* No Arguments */ #else static void cscan_show_synopsis ( /* Display Program Synopsis */ ) /* No Arguments */ #endif { /* 'cscan_show_synopsis' */ int si; /* synopsis index */ /* Display program synopsis */ for (si = 0; cscan_synopsis[si]; si++) (void) printf ("%s\n", cscan_synopsis[si]); exit (0); } /* 'cscan_show_synopsis' */ /*********************************************************************/ /* Function: cscan_scan_file() */ /*********************************************************************/ #ifdef __STDC__ static void cscan_scan_file ( /* Scan File */ char *fn, /* File Name */ boolean vf) /* Verbose Flag */ #else static void cscan_scan_file ( /* Scan File */ fn, /* File Name */ vf) /* Verbose Flag */ char *fn; /* File Name */ boolean vf; /* Verbose Flag */ #endif { /* 'cscan_scan_file' */ long flc = 1; /* file lines count */ int cti; /* ctrl chars array index */ char *s; /* work string pointer */ static FILE *fp = 0; /* file pointer */ char fs[FMAX]; /* file input string */ int fl; /* file buffer length */ int fi; /* file buffer index */ boolean ff = FALSE; /* file (printed) flag */ char ms[80]; /* message string */ /* Open input file */ if (fp) fp = freopen (fn, "rb", fp); else fp = fopen (fn, "rb"); if (NOT fp) { sprintf (ms, "Error opening file '%s'", fn); cscan_error_exit (ms); } /* Clear counters */ delcnt = gracnt = prtcnt = 0; for (cti = 0; cti LT CMAX; cti++) ctlcnt[cti] = 0; /* Read input file, scanning for control characters */ for (;;) { fl = fread (fs, 1, FMAX, fp); if (NOT fl) break; for (s = fs, fi = 0; fi LT fl; s++, fi++) { if ((*s GE 0x20) /* Printing character? */ AND (*s LE 0x7e)) { prtcnt++; continue; } if (*s & 0x80) /* Graphic character? */ gracnt++; if (*s EQ 0x7f) /* DEL character? */ delcnt++; if ((*s & 0x80) /* Graphic character... */ OR (*s EQ 0x7f)) /* OR DEL character? */ { if (NOT vf) continue; if (NOT ff) { printf ("File: %s\n", fn); ff = TRUE; } printf ("Line: %6ld Char: 0x%02x\n", flc, *s); continue; } ctlcnt[*s] += 1; if (*s EQ '\r') continue; if (*s EQ '\n') { flc++; continue; } if (NOT vf) continue; if (NOT ff) { printf ("File: %s\n", fn); ff = TRUE; } printf ("Line: %6ld Char: %s\n", flc, cname[*s]); } } /* Close input file */ fclose (fp); /* Report on this file */ flc--; printf ("File: %s\n", fn); printf ("Lines: %8ld | Print: %8ld | Graph: %8ld | DEL: %8ld |\n", flc, prtcnt, gracnt, delcnt); for (cti = 0; cti LT CMAX; cti++) { printf ("%s%8ld | ", cname[cti], ctlcnt[cti]); if ((cti + 1) % 4) continue; printf ("\n"); } } /* 'cscan_scan_file' */ /*********************************************************************/ /* Function: cscan_error_exit() */ /*********************************************************************/ #ifdef __STDC__ static void cscan_error_exit ( /* Log Error and Exit */ char *es) /* Error Message String */ #else static void cscan_error_exit ( /* Log Error and Exit */ es) /* Error Message String */ char *es; /* Error Message String */ #endif { /* 'cscan_error_exit' */ printf ("cscan: %s\n", es); printf ("cscan: Abnormal termination\n"); exit (1); } /* 'cscan_error_exit' */