#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ERROR_UNKNOWN_FLAG -1
#define ERROR_WRONG_OPTION_FORMAT -2
#define ERROR_MULTIPLE_INPUT_FILES -3
#define ERROR_CANNOT_OPEN_FILE -4
#define ERROR_CANNOT_CREATE_FILE -5
#define MAX_LINE_LENGTH 1024
typedef struct
{
char delimiter;
const char * inputFile;
const char * outputFile;
} Configuration;
void Exit(int errorCode, const char * message, const char * arg)
{
fprintf(stderr, "ERROR: %s: %s\n", message, arg);
exit(errorCode);
}
Configuration Configure(int argc, char * argv[])
{
// runReport [-d | -o] [INPUT FILE]
// [INPUT FILE] : the path to the input file, i.e. a csv file
// -d [c] : set delimiter to be character [c]. The default is ',
// -o [OUTPUT FILE]: the report file to generate
Configuration configuration = { 0 };
for (int i = 1; i < argc; i++)
{
const char * arg = argv[i];
// Check for flags
if (arg[0] == '-')
{
bool hasError = arg[2] != '\0';
if (!hasError)
{
if (arg[1] == 'd')
{
if (i + 1 >= argc)
Exit(ERROR_WRONG_OPTION_FORMAT, "Delimiter not specified", NULL);
const char * str = argv[++i];
if (str[0] == '\0' || str[1] != '\0')
Exit(ERROR_WRONG_OPTION_FORMAT, "Delimiter must be a single character", str);
configuration.delimiter = str[0];
}
else if (arg[1] == 'o')
{
if (i + 1 >= argc)
Exit(ERROR_WRONG_OPTION_FORMAT, "Output file not specified", NULL);
const char * str = argv[++i];
if (str[0] == '\0')
Exit(ERROR_WRONG_OPTION_FORMAT, "Output file cannot be empty", str);
configuration.outputFile = str;
}
else // unknown arg
{
hasError = true;
}
}
if (hasError)
{
fprintf(stderr, "Unknown flag: %s\n", arg);
exit(ERROR_UNKNOWN_FLAG);
}
}
else // check for input file
{
if (configuration.inputFile != NULL)
Exit(ERROR_MULTIPLE_INPUT_FILES, "Input file may be specified only once", arg);
configuration.inputFile = arg;
}
}
// Apply the default configurations if not specified by the user
if (configuration.delimiter == '\0') configuration.delimiter = ',';
if (configuration.inputFile == NULL) configuration.inputFile = "data.csv";
if (configuration.outputFile == NULL) configuration.outputFile = "report.txt";
return configuration;
}
int main(int argc, char * argv[])
{
Configuration configuration = Configure(argc, argv);
FILE * input = fopen(configuration.inputFile, "r");
if (input == NULL)
Exit(ERROR_CANNOT_OPEN_FILE, "Cannot open file", configuration.inputFile);
FILE * output = fopen(configuration.outputFile, "w");
if (output == NULL)
Exit(ERROR_CANNOT_CREATE_FILE, "Cannot create file", configuration.outputFile);
// Process the data. In this example we convert it to a tab delimited file.
unsigned long lineCount = 0u;
char buffer[MAX_LINE_LENGTH];
char delimiters[2] = { configuration.delimiter, 0};
while (fgets(buffer, MAX_LINE_LENGTH, input) != NULL)
{
unsigned count = 0;
char * token = strtok(buffer, delimiters); // Break the read line into tokens
while (token != NULL)
{
if (count++ > 0)
fprintf(output, "\t"); // Separate tokens in the ouput file if separation is needed
fprintf(output, "%s", token); // Print the token into the output file
token = strtok(NULL, delimiters); // Keep looking for more tokens in the last read string
}
lineCount++;
}
fclose(input);
fprintf(output, "\nNumber of lines read: %lu", lineCount);
fclose(output);
return 0;
}
one,two,three
1,2,3