Skip to content

Instantly share code, notes, and snippets.

@anupdhml
Created November 28, 2013 15:08
Show Gist options
  • Save anupdhml/7693322 to your computer and use it in GitHub Desktop.
Save anupdhml/7693322 to your computer and use it in GitHub Desktop.
Emulates the unix command cat, with a few new tricks added
/* Emulates the unix command cat, with a few new tricks added
* By <anupdhml@gmail.com>
* 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