It echoes files or strings to output, never both at once. It does work (in both Linux and Windows), but I can NOT guarantee that it is bug free. It works much like echo, but it works with files as well, and has fewer formal arguments.
I'm looking for helpful and useful critiques, mainly in programming style, organization, and if it's easily understood (or if there was difficulty in understanding) source code. If any critiques are made, please add in how I can improve upon my "misdeeds".
//Problem 11-15
/*
*************************************************************
CHP 11 Problem #15
*************************************************************
Write a program that reads input until end-of-file and echoes
it to the display. Have the program recognize and implement
the following command-line arguments:
*************************************************************
-p -- Print input as is
-u -- Map input to all uppercase
-l -- Map input to all lowercase
*************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define TITLE "Chapter 11 Exercise 13"
_Bool true = 1, false = 0;
void display(char * string, char arg)
{ //display the string in stdout "as is"
int col = 0;
//go character by character to avoid bugs
//while not null char '\0' or End-of-FILE
if (arg == 'p')
while (string[col] && string[col] != EOF)
putchar(string[col++]);
if (arg == 'u')
while (string[col] && string[col] != EOF)
putchar(toupper(string[col++]));
if (arg == 'l')
while (string[col] && string[col] != EOF)
putchar(tolower(string[col++]));
putchar('\n'); //formatted padding
}
void pfile(char * fname, char arg)
{ //print the files contents to stdout "as is"
FILE * fp;
char ch;
fp = fopen(fname, "r"); //open file for reading
if(fp == NULL) //attempt failed
{
printf("Oops! Something went wrong while attempting to open the file.\n");
puts("The file may be missing, corrupted, or may not exist.");
exit(1); //quit program
}
//getc(fp) gets a character from the open file
if (arg == 'p')
while((ch = getc(fp)) != EOF)
putchar(ch);
if (arg == 'u')
while((ch = getc(fp)) != EOF)
putchar(toupper(ch));
if (arg == 'l')
while((ch = getc(fp)) != EOF)
putchar(tolower(ch));
fclose(fp); //close the file
}
int fext(char * string)
{//determine if there is a file extension
//flag which value to return
int i, ch, scan, place, flag = false;
//while string is not a null character,
//assign flag a boolean value,
//break while if a character matches
for (i = 0; string[i]; i++)
{
if (string[i] == '.')
{
//check if next char is a space char
if (isspace(string[i + 1])) break;
//count characters after '.'
for (scan = i, place = 0; string[i+scan]; scan++) ++place;
scan = i + 1; //advance by one character
//only ASCII or Plain Text files are allowed
if (!strncmp(string+scan,"txt",place))
{
flag = true;
break;
}
if (!strncmp(string+scan,"asc",place))
{
flag = true;
break;
}
if (!strncmp(string+scan,"c",place))
{
flag = true;
break;
}
if (!strncmp(string+scan,"csv",place))
{
flag = true;
break;
}
if (!strncmp(string+scan,"html",place))
{
flag = true;
break;
}
if (!strncmp(string+scan,"log",place))
{
flag = true;
break;
}
if (!strncmp(string+scan,"xhtml",place))
{
flag = true;
break;
}
if (!strncmp(string+scan,"xml",place))
{
flag = true;
break;
}
}
}
return flag; //assume *string is a string literal
}
int option(char * string)
{//determine if string is a formal argument
auto int i, place, arg = false;
if (string[0] == '-' && string[1] == '-' && isalpha(string[2]))
{
for (i = 0; string[i]; i++) //count alpha based chars
if (isalpha(string[i]))
++place;
if (!strncmp((string + 2),"help",place))
{
arg = 'h'; //return the help argument
}
if (!strncmp((string + 2),"print",place))
{
arg = 'p'; //return the argument to print as is
}
if (!strncmp((string + 2),"uppercase",place))
{
arg = 'u'; //return the uppercase argument
}
if (!strncmp((string + 2),"lowercase",place))
{
arg = 'l'; //return the lowercase argument
}
}
else if (string[0] == '-' && isalpha(string[1]))
{
switch (string[1])
{
case 'h':
arg = 'h';
break;
case 'p':
arg = 'p';
break;
case 'u':
arg = 'u';
break;
case 'l':
arg = 'l';
break;
default:
arg = false;
break;
}
}
else
{
arg = false;
}
return arg; //assume *string is a string literal
}
void help(char * string)
{
printf("Usage: %s [OPTION]... [FILE] or [STRING]...\n", string);
puts("Echoes FILE or STRING until End-of-FILE to the display.\n");
printf("%s%50s\n", "-h, --help", "Prints this help text to the display.");
printf("%s%49s\n", "-p, --print", "Prints the FILE as is to the display.");
printf("%s%40s\n", "-u, --uppercase", "Maps the input to all uppercase.");
printf("%s%40s\n", "-l, --lowercase", "Maps the input to all lowercase.");
}
int main(int argc, char *argv[])
{ //main program
//extension, option
auto int ext, opt;
switch(argc)
{
case 2:
//check to see if input is an argument
if ((opt = option(argv[1])) == 'h') //if argument is for help
{
help(argv[0]); //print only the help text to the display
break;
}
if (opt) //if only an optional argument is made
{
printf("%s: missing FILE or STRING operand\n", argv[0]);
printf("Try '%s --help' for more information.\n", argv[0]);
break;
}
//check to see if input is string or file
if (!opt && (ext = fext(argv[1]))) //if a file was provided with no opt
pfile(argv[1], 'p'); //print FILE as is -- default argument
else if (!opt && !ext) //if no opt or file was provided
display(argv[1], 'p'); //print STRING as is -- default argument
break;
case 3:
if ((opt = option(argv[1])) == 'h')
{
help(argv[0]);
break;
}
else if (opt)
ext = fext(argv[2]);
else
{
opt = false;
ext = false;
}
if (opt && ext) //if option and file extension are valid and present
pfile(argv[2], opt);
else if (opt && !ext) //if option is present, but file is missing
display(argv[2], opt);
else
{
printf("%s: invalid OPTION was provided\n", argv[0]);
printf("Try '%s --help' for more information.\n", argv[0]);
}
break;
default:
printf("%s: invalid arguments were made\n", argv[0]);
printf("Try '%s --help' for more information.\n", argv[0]);
break;
}
return 0;
}