/* * */ #include "cumsum.h" /* * Global configuration variables. These are set based on command-line * arguments, and read-only beyond that point. */ static bool ARG_FP_INPUT = false; static bool ARG_UINT_INPUT = false; static bool ARG_HELP = false; static int parse_options(int argc, char*const* argv) { int arg_index = 0; int arg; bool error = false; while ((arg = getopt(argc, argv, "frhu")) != -1) { switch (arg) { case 'f': ARG_FP_INPUT = true; break; case 'u': ARG_UINT_INPUT = true; case 'h': ARG_HELP = true; break; case '?': if (isprint(optopt)) { fprintf(stderr, "Unknown option `-%c`.\n", optopt); } else { fprintf(stderr, "Unknown option character `\\x%x`.\n", optopt); } error = true; break; default: error = true; break; } } if (ARG_UINT_INPUT && ARG_FP_INPUT) { fprintf(stderr, "Error: the -u and -f flags are mutually exclusive.\n"); error = true; } if (!error) { arg_index = optind; } return arg_index; } static void help() { fprintf(stderr, "Usage:\ncumsum [-f|-u] [filename]\n"); } void print_sum(Number sum) { if (ARG_FP_INPUT) { fprintf(stdout, "%lf\n", sum.d); } else if (ARG_UINT_INPUT) { fprintf(stdout, "%ld\n", sum.u); } else { fprintf(stdout, "%ld\n", sum.i); } } static int read_data_fp(FILE *file, Number *num) { double val; while (fscanf(file, "%lf ", &val) != EOF) { num->d += val; } return 1; } static int read_data_int(FILE *file, Number *num) { int64_t val; while (fscanf(file, "%ld ", &val) != EOF) { num->i += val; } return 1; } static int read_data_uint(FILE *file, Number *num) { uint64_t val; while (fscanf(file, "%ld ", &val) != EOF) { num->u += val; } return 1; } static int process_data(FILE *file) { int rc = 1; Number sum = {}; /* FIXME: this could probably use a type-based macro to collapse the if statements into a single macro call */ if (ARG_FP_INPUT) { rc = read_data_fp(file, &sum); } else if (ARG_UINT_INPUT) { rc = read_data_uint(file, &sum); } else { rc = read_data_int(file, &sum); } if (rc) { print_sum(sum); } process_data_end: return rc; } int main(int argc, char **argv) { int rc = EXIT_SUCCESS; int file_index = 0; if (!(file_index = parse_options(argc, argv))) { help(); rc = EXIT_FAILURE; goto program_exit; } /* if the -h argument is supplied, print usage and exit successfully */ if (ARG_HELP) { help(); goto program_exit; } /* open the input file, if one is specified, otherwise default to stdin */ FILE *input_file; if (file_index < argc && strcmp(argv[file_index], "-") != 0) { if (!(input_file = fopen(argv[file_index], "r"))) { fprintf(stderr, "Error: Unable to open input file %s\n", argv[file_index]); rc = EXIT_FAILURE; goto program_exit; } } else { input_file = stdin; } if (!process_data(input_file)) { rc = EXIT_FAILURE; } close_file: fclose(input_file); program_exit: exit(rc); }