Created
November 28, 2013 15:08
-
-
Save anupdhml/7693322 to your computer and use it in GitHub Desktop.
Emulates the unix command cat, with a few new tricks added
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Emulates the unix command cat, with a few new tricks added | |
* By <[email protected]> | |
* April 7, 2010 | |
* | |
* Program arguments | |
* -r: reverses the letters of the input | |
* -c N, where N is a no between 0 and 25: ciphers the input by adding N to | |
* the ASCII value of each letter and printing the result as a character | |
*/ | |
/* Credits: | |
* http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/ | |
* http://mazack.org/unix/errno.php | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <ctype.h> | |
#include <string.h> | |
#include <stdbool.h> | |
#define INIT_BUFFERSIZE 80 | |
#define MAXFILECOUNT 1 | |
static size_t read_input(FILE *source, char *buffer[], int buffersize); | |
static void reverse(char *input[], size_t inputlen); | |
static void encode(int cipher_val, char *input[], size_t inputlen); | |
static bool isnum(char arg[]); | |
static void argparse (int argc, char *argv[], bool *doreverse, bool *doencode, | |
bool *dofileread, int *cipher_val, FILE **input_file); | |
static void print_output (bool doreverse, bool doencode, bool dofileread, | |
int cipher_val, FILE *input_file); | |
/* --------------------------------------------------------------------------*/ | |
int main(int argc, char *argv[]) { | |
bool doreverse, doencode, dofileread; | |
doreverse = doencode = dofileread = false; | |
int cipher_val = 0; | |
FILE *input_file = NULL; | |
argparse(argc, argv, &doreverse, &doencode, &dofileread, | |
&cipher_val, &input_file); | |
print_output(doreverse, doencode, dofileread, cipher_val, input_file); | |
return EXIT_SUCCESS; | |
} | |
/* --------------------------------------------------------------------------*/ | |
static void print_output (bool doreverse, bool doencode, bool dofileread, | |
int cipher_val, FILE *input_file) { | |
char *str; | |
size_t strlength = 0; | |
str = (char *) malloc(INIT_BUFFERSIZE * sizeof(char)); | |
if (str == (char *) NULL) { | |
fprintf(stderr, "dog: Cannot allocate memory"); | |
exit(12); // With suitable unix error code | |
} | |
if(dofileread) { | |
strlength = read_input (input_file, &str, INIT_BUFFERSIZE); | |
fclose(input_file); | |
} | |
else | |
strlength = read_input(stdin, &str, INIT_BUFFERSIZE); | |
if(doreverse) | |
reverse(&str, strlength); | |
if(doencode) | |
encode(cipher_val, &str, strlength); | |
printf("%s\n", str); | |
free(str); | |
return; | |
} | |
// Determine whether the user asked dog to perform its other tricks. | |
static void argparse (int argc, char *argv[], bool *doreverse, bool *doencode, | |
bool *dofileread, int *cipher_val, FILE **inputfile) { | |
int file_count = 0; | |
for (int i = 1; i < argc; i++) { | |
// Check for reverse switch | |
if (strcmp(argv[i], "-r") == 0) | |
*doreverse = true; | |
// Check for the cipher option | |
else if (strcmp(argv[i], "-c") == 0) { | |
if (i + 1 <= argc - 1) { // Check if an argument follows the switch -c. | |
i++; | |
if (isnum (argv[i])) { | |
*cipher_val = atoi(argv[i]); // Writing the value string as int | |
if (*cipher_val >= 0 && *cipher_val <= 25) | |
*doencode = true; | |
else { | |
fprintf(stderr, "dog: %d: Invalid argument for the switch -c." | |
"Use integers between 0 and 25.\n", *cipher_val); | |
exit(33); | |
} | |
} | |
else { | |
fprintf(stderr, "dog: %s: Invalid argument for the switch -c. " | |
"Only numerical values are allowed.\n", argv[i]); | |
exit(22); | |
} | |
} | |
else { | |
fprintf(stderr, "dog: Missing argument for the switch -c\n"); | |
exit(22); | |
} | |
} | |
// Check if filenames were provided as arguments. | |
else { | |
*inputfile = fopen(argv[i], "r"); | |
if (*inputfile == NULL) { | |
fprintf(stderr, "dog: %s: No such file\n", argv[i]); | |
exit(2); | |
} | |
else { | |
file_count++; | |
if (file_count <= MAXFILECOUNT) | |
*dofileread = true; | |
else { | |
fprintf(stderr, "dog: Can't open more than %d file\n", MAXFILECOUNT); | |
fclose(*inputfile); | |
exit(7); | |
} | |
} | |
} | |
} | |
} | |
// Returns true if the given string is numeric, false otherwise. | |
static bool isnum(char arg[]) { | |
int i; | |
for (i = 0; i < strlen(arg); i++) | |
if (!isdigit(arg[i])) { | |
return false; | |
break; | |
} | |
return true; | |
} | |
// Reverse the given string. | |
static void reverse(char *input[], size_t inputlen) { | |
size_t i,j; | |
char temp; | |
for (i = 0, j = inputlen - 1 ; i <= j; i++, j--) { | |
temp = (*input)[i]; | |
(*input)[i] = (*input)[j]; | |
(*input)[j] = temp; | |
} | |
return; | |
} | |
// A basic rotation cipher. | |
static void encode(int cipher_val, char *input[], size_t inputlen) { | |
size_t i; | |
char input_char; | |
char shifted_char; | |
for (i = 0; i < inputlen; i++) { | |
input_char = (*input)[i]; | |
if(input_char < 'A' || input_char > 'z'); | |
else { | |
shifted_char = input_char + cipher_val; | |
if(isupper(input_char)) | |
(*input)[i] = ((shifted_char - 'A') % ('Z' - 'A') ) + 'A'; | |
else | |
(*input)[i] = ((shifted_char - 'a') % ('z' - 'a') ) + 'a'; | |
} | |
} | |
return; | |
} | |
// Reads the given input until EOF marker is encounterd. | |
// So at the moment, must press EOF marker to see the output of the program. | |
static size_t read_input(FILE *source, char *buffer[], int buffersize) { | |
size_t chars_read = 0; | |
char c; | |
while ( (c = fgetc(source)) != EOF ) { | |
if (chars_read == buffersize) { | |
buffersize *= 2; | |
*buffer = (char *) realloc(*buffer, buffersize); | |
if (*buffer == (char *) NULL) { | |
fprintf(stderr, "dog: Cannot allocate memory"); | |
exit(12); | |
} | |
} | |
(*buffer)[chars_read] = c; | |
chars_read++; | |
} | |
return chars_read; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment