/***************************************************************************** * PROGRAMMER: William L. Bahn * PROJECT: CSCI400 HW 01 * DATE: 25 JAN 13 * * USAGE: CS400_Wbahn_HW_01 inputfile [outputfile [key [mode]]] * * inputfile (required): name of file containing input text. * outputfule (optional): name of file to write output to. (default=stdout) * key (optional): key string (default="Colorado School of Mines") * mode (optional): 'e'/'E' to encrypt, 'd'/'D' to decrypt (default=encrypt) ***************************************************************************** */ #include #include #include #define ARG_INFILE (1) #define ARG_OUTFILE (2) #define ARG_KEY (3) #define ARG_MODE (4) #define ENCRYPT (0) #define DECRYPT (1) #define ID (0) #define CHARS (1) #define LINES (2) #define UPPER (3) #define LOWER (4) #define DIGIT (5) #define WHITE (6) #define OTHER (7) #define STATS (8) // Total number of categories - dimension array to this. //=========================================================================== // LoadKey() //=========================================================================== char *LoadKey(char *s) { char *key; // Will point to the sanitized key string and be returned int i; // Index into key string // If a NULL pointer is supplied, use the default key string. if (!s) return LoadKey("Colorado School of Mines"); // Count characters in s and allocate enough memory for key of same size for (i = 0; s[i]; i++); Empty Loop // Allocate a string the same size as the key key = (char *) malloc ((i + 1)*sizeof(char)); if (!key) return NULL; // Key string failed to allocate for (i = 0; *s != 0; s++) { // Check if the current character is upper case if (('A' <= *s)&&('Z' >= *s)) key[i++] = *s; // Check if the current character is lower case if (('a' <= *s)&&('z' >= *s)) key[i++] = 'A' + (*s - 'a'); // Convert to upper // The above two blocks could be replaced with // if (c = isupper(toupper(*s))) // key[i++] = c; // must declare c } key[i] = 0; // NUL terminate the key string return key; } //=========================================================================== // Vigenere() //=========================================================================== /* The inputs c and k are assumed to be uppercase characters. */ int Vigenere(int c, int k, int mode) { c -= 'A'; k -= 'A'; if (ENCRYPT == mode) c += k; // encrypt else c -= k; // decrypt return 'A' + (c + 26)%26; } //=========================================================================== // Stats() //=========================================================================== /* The Stats() function serves two purposes. When a character is processed * by either the Input() or the Output() function, the Stats() function is * called with the ASCII code of the character along with the stats array * from the Input() or Output() function. The Stats() function then classifies * the character and updates the stats array as necessary. In addition, it * converts the character to upper case and then returns either the ASCII code * for the converted character, if the result is an upper case character, or * returns a 0. The second purpose is to report the statistics to the screen, * which it will do if the character given to it is the EOF code. In this case, * the function will also return the EOF code. */ int Stats(int c, int stats[]) { if (EOF == c) // Display Stats { printf("\n%s%s\n", (stats[ID]? "OUT":"IN"), "PUT STREAM STATISTICS"); printf("Characters:..... %i\n", stats[CHARS]); printf("Lines:.......... %i\n", stats[LINES]+1); printf("Letters:........ %i\n", stats[UPPER]+stats[LOWER]); printf(" Upper Case:.. %i\n", stats[UPPER]); printf(" Lower Case:.. %i\n", stats[LOWER]); printf("Digits:......... %i\n", stats[DIGIT]); printf("Whitespace:..... %i\n", stats[WHITE]); printf("Other:.......... %i\n", stats[OTHER]); return EOF; } // Update Stats stats[CHARS]++; if (('a' <= c)&&('z' >= c)) stats[LOWER]++; else if (('A' <= c)&&('Z' >= c)) stats[UPPER]++; else if (('0' <= c)&&('9' >= c)) stats[DIGIT]++; else if ((' ' == c)||('\t' == c)) stats[WHITE]++; else if ('\n' == c) stats[LINES]++; else stats[OTHER]++;; if (('a' <= c)&&('z' >= c)) // Convert lower to upper c += ('A' - 'a'); return (('A' <= c)&&('Z' >= c))? c : 0; } //=========================================================================== // Input() //=========================================================================== /* The Input() assumes that fp is a valid file pointer. It scans the input * stream for the next letter by reading a character from the file and * passing it, along with the stats array, to the Stats() function. The * Stats() function returns 0 unless the end of file has been reached (in * which case it returns EOF after printing out the statistics) or the * character is a letter (upper or lower case) in which case it returns the * ASCII code for the uppercase version. The while() loop continues reading * from the file until the next letter is reached or the EOF is encountered. * * The Input() function returns either EOF or the ASCII code of an upper case * character. */ int Input(FILE *fp) { static int stats[STATS] = {0}; // Will initialize all others to 0. int c; while (!(c=Stats(fgetc(fp), stats))) ; // Empty Loop return c; } //=========================================================================== // Output() //=========================================================================== /* The Output() function assumes that c is an upper case character and * that fp is a valid file pointer (possibly stdout). The exception is if * c is EOF, then the stats are output. */ int Output(int c, FILE *fp, char *key, int mode) { static int stats[STATS] = {1}; // Will initialize all others to 0. static int group = 0; // Number of characters within the present group static int groups = 0; // Number of complete groups on present line static int kpos = 0; // Position within the key int space; if (EOF == c) return Stats(c, stats); if (group >= 5) // Start a new group { group = 0; groups++; groups%=10; // If ten groups, start next line space = groups? ' ' : '\n'; fputc(space, fp); Stats(space, stats); } c = Vigenere(c, key[kpos++], mode); // Encrypt/Decrypt the character if (!key[kpos]) kpos = 0; fputc(c, fp); Stats(c, stats); group++; return c; } //=========================================================================== // Command Line Argument Extractors //=========================================================================== FILE *ExtractInputFile(int argc, char *argv[], int n, FILE *hardcode) { FILE *fp; if (argc <= n) // No command line arguments provided. fp = hardcode; else fp = fopen(argv[n], "rt"); return fp; } FILE *ExtractOutputFile(int argc, char *argv[], int n, FILE *hardcode) { FILE *fp; if (argc <= n) // No output file specified on command line. fp = hardcode; else if (!(fp = fopen(argv[n], "wt"))) fp = stdout; return fp; } char *ExtractKey(int argc, char *argv[], int n, char *hardcode) { return LoadKey( (argc <= n)? hardcode : argv[n] ); } int ExtractMode(int argc, char *argv[], int n, int hardcode) { int mode; switch ((argc <= n)? hardcode : *(argv[n])) { case ENCRYPT: case 'e': case 'E': mode = ENCRYPT; break; case DECRYPT: case 'd': case 'D': mode = DECRYPT; break; default: mode = hardcode; } return mode; } //=========================================================================== // ValidateParameters() //=========================================================================== int ValidateParameters(int argc, char *argv[], FILE *fp_i, FILE *fp_o, char *key, int mode) { int i, valid; // Echo command line to screen printf("COMMAND LINE:"); for (i = 0; i < argc; i++) printf(" %s", argv[i]); printf("\n"); valid = 1; // Input file must be specified if (!fp_i) { valid = 0; printf("ABORT - "); if (argc <= ARG_INFILE) printf("Input file must be specified on the command line.\n"); else printf("Failed to open input file <%s>\n", argv[ARG_INFILE]); } // Output file may be stdout because output file didn't open if ((stdout == fp_o)&&(argc > ARG_OUTFILE)) { printf("WARNING - "); printf("Failed to open output file <%s>\n", argv[ARG_OUTFILE]); printf("Using instead.\n"); } // Key may not have allocated if (!key) { valid = 0; printf("ABORT - "); printf("Failed to allocated memory for key.\n"); } // Display parameters printf("IN FILE:.. <%s>\n", (argc > ARG_INFILE)? argv[ARG_INFILE]:NULL); printf("OUT FILE:.. <%s>\n", (stdout == fp_o)? "stdout" : argv[ARG_OUTFILE]); printf("KEY:....... %s\n", key); printf("MODE:...... %s\n", (ENCRYPT == mode)? "ENCRYPT" : "DECRYPT"); return valid; } void FinalHousekeeping(FILE *fp_i, FILE *fp_o, char *key) { if (key) free(key); if (fp_i && (stdin != fp_i)) fclose(fp_i); if (fp_o && (stdout != fp_o)) fclose(fp_o); } void HoldWindowOpen(void) { // Prevent window from closing too quickly printf("\nHit RETURN to exit:"); getc(stdin); } //=========================================================================== // MAIN FUNCTION //=========================================================================== int main(int argc, char *argv[]) { FILE *fp_i, *fp_o; char *key; int mode; fp_i = ExtractInputFile(argc, argv, ARG_INFILE, NULL); fp_o = ExtractOutputFile(argc, argv, ARG_OUTFILE, stdout); key = ExtractKey(argc, argv, ARG_KEY, "Colorado School of Mines"); mode = ExtractMode(argc, argv, ARG_MODE, ENCRYPT); if (!ValidateParameters(argc, argv, fp_i, fp_o, key, mode)) return EXIT_FAILURE; // Process input file and produce output (stats displayed automatically) while (EOF != Output(Input(fp_i), fp_o, key, mode)) ; // Empty loop FinalHousekeeping(fp_i, fp_o, key); HoldWindowOpen(); return EXIT_SUCCESS; }