summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDouglas B. Rumbaugh <doug@douglasrumbaugh.com>2025-01-06 12:41:54 -0500
committerDouglas B. Rumbaugh <doug@douglasrumbaugh.com>2025-01-06 12:41:54 -0500
commitbd0772bb4a1950b3f438d7b9d8a82daac796f59d (patch)
treea8d53c02294beccdbf8df6074d2c8b03d63b8036
parentb99427c3dc18e95f7ccecae07211511399d0ae5d (diff)
downloadmath-utils-bd0772bb4a1950b3f438d7b9d8a82daac796f59d.tar.gz
Added first version of a cumulative sum program
-rw-r--r--Makefile5
-rw-r--r--include/cumsum.h33
-rw-r--r--src/cumsum.c159
3 files changed, 196 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 0374e62..5c57a72 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,7 @@
-all: bin/cdf
+all: bin/cdf bin/cumsum
bin/cdf: src/cdf.c include/cdf.h
gcc -std=c23 -Iinclude src/cdf.c -o bin/cdf
+
+bin/cumsum: src/cumsum.c include/cumsum.h
+ gcc -std=c23 -Iinclude src/cumsum.c -o bin/cumsum
diff --git a/include/cumsum.h b/include/cumsum.h
new file mode 100644
index 0000000..9761a08
--- /dev/null
+++ b/include/cumsum.h
@@ -0,0 +1,33 @@
+/*
+ */
+
+#ifndef H_CDF
+#define H_CDF
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <string.h>
+#include <stdint.h>
+#include <assert.h>
+
+typedef union {
+ int64_t i;
+ uint64_t u;
+ double d;
+} Number;
+
+static int parse_options(int argc, char*const* argv);
+static void help();
+static int process_data(FILE *file);
+static void print_sum(Number sum);
+
+static int read_data_int(FILE *file, Number *num);
+static int read_data_uint(FILE *file, Number *num);
+static int read_data_fp(FILE *file, Number *num);
+
+#endif
+
+
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);
+}