summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cumsum.c159
1 files changed, 159 insertions, 0 deletions
diff --git a/src/cumsum.c b/src/cumsum.c
new file mode 100644
index 0000000..5648661
--- /dev/null
+++ b/src/cumsum.c
@@ -0,0 +1,159 @@
+/*
+ *
+ */
+
+
+#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);
+}