summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compile_flags.txt2
-rw-r--r--include/cdf.h1
-rw-r--r--include/cumsum.h1
-rw-r--r--src/cdf.c6
-rw-r--r--src/cumsum.c142
5 files changed, 119 insertions, 33 deletions
diff --git a/compile_flags.txt b/compile_flags.txt
new file mode 100644
index 0000000..cb54364
--- /dev/null
+++ b/compile_flags.txt
@@ -0,0 +1,2 @@
+-Iinclude
+-std=c23
diff --git a/include/cdf.h b/include/cdf.h
index 956e630..6c218cf 100644
--- a/include/cdf.h
+++ b/include/cdf.h
@@ -8,6 +8,7 @@
#include <unistd.h>
#include <stdio.h>
#include <getopt.h>
+#include <ctype.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>
diff --git a/include/cumsum.h b/include/cumsum.h
index 9761a08..50ff0b1 100644
--- a/include/cumsum.h
+++ b/include/cumsum.h
@@ -5,6 +5,7 @@
#define H_CDF
#include <stdlib.h>
+#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
diff --git a/src/cdf.c b/src/cdf.c
index 3bf39fe..2b26e27 100644
--- a/src/cdf.c
+++ b/src/cdf.c
@@ -18,7 +18,7 @@ static int parse_options(int argc, char *const *argv) {
int arg;
bool error = false;
- while ((arg = getopt(argc, argv, "frhu")) != -1) {
+ while ((arg = getopt(argc, argv, "frhu")) != -1 && !error) {
switch (arg) {
case 'f':
ARG_FP_INPUT = true;
@@ -34,9 +34,9 @@ static int parse_options(int argc, char *const *argv) {
break;
case '?':
if (isprint(optopt)) {
- fprintf(stderr, "Unknown option `-%c`.\n", optopt);
+ fprintf(stderr, "Error: unknown option `-%c`.\n", optopt);
} else {
- fprintf(stderr, "Unknown option character `\\x%x`.\n", optopt);
+ fprintf(stderr, "Error: unknown option character `\\x%x`.\n", optopt);
}
error = true;
break;
diff --git a/src/cumsum.c b/src/cumsum.c
index 268a548..99c7651 100644
--- a/src/cumsum.c
+++ b/src/cumsum.c
@@ -11,27 +11,56 @@
static bool ARG_FP_INPUT = false;
static bool ARG_UINT_INPUT = false;
static bool ARG_HELP = false;
+static bool ARG_RUNNING_SUM = false;
+static int64_t ARG_WINDOW_SIZE = 0;
+
+/*
+ * Circular buffer for windowed sums. I made this global for
+ * convenience--it's a simple enough program that this'll work
+ * fine. It could be refactored to have a more restricted scope.
+ */
+static Number *window_buffer = nullptr;
+static size_t window_idx = 0;
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) {
+ while ((arg = getopt(argc, argv, "fhurw:")) != -1 && !error) {
switch (arg) {
case 'f':
ARG_FP_INPUT = true;
break;
case 'u':
ARG_UINT_INPUT = true;
+ break;
case 'h':
ARG_HELP = true;
break;
+ case 'r':
+ ARG_RUNNING_SUM = true;
+ break;
+ case 'w':
+ ARG_WINDOW_SIZE = atol(optarg);
+ if (ARG_WINDOW_SIZE <= 0) {
+ fprintf(stderr, "Error: invalid window size: %lld. Must be > 0.\n",
+ ARG_WINDOW_SIZE);
+ error = true;
+ break;
+ }
+
+ window_buffer = calloc(ARG_WINDOW_SIZE, sizeof(window_buffer[0]));
+ if (!window_buffer) {
+ fprintf(stderr, "Error: memory allocation failed\n");
+ error = true;
+ }
+ break;
case '?':
if (isprint(optopt)) {
- fprintf(stderr, "Unknown option `-%c`.\n", optopt);
+ fprintf(stderr, "Error: unknown option `-%c`.\n", optopt);
} else {
- fprintf(stderr, "Unknown option character `\\x%x`.\n", optopt);
+ fprintf(stderr, "Error: unknown option character `\\x%x`.\n", optopt);
}
error = true;
break;
@@ -46,6 +75,11 @@ static int parse_options(int argc, char *const *argv) {
error = true;
}
+ if (ARG_RUNNING_SUM && ARG_WINDOW_SIZE) {
+ fprintf(stderr, "Error: the -w and -r flags are mutually exclusive.\n");
+ error = true;
+ }
+
if (!error) {
arg_index = optind;
}
@@ -53,7 +87,9 @@ static int parse_options(int argc, char *const *argv) {
return arg_index;
}
-static void help() { fprintf(stderr, "Usage:\ncumsum [-f|-u] [filename]\n"); }
+static void help() {
+ fprintf(stderr, "Usage:\ncumsum [-f|-u] [-r|-w window_size] [filename]\n");
+}
void print_sum(Number sum) {
if (ARG_FP_INPUT) {
@@ -65,28 +101,81 @@ void print_sum(Number sum) {
}
}
-static int read_data_fp(FILE *file, Number *num) {
- double val;
- while (fscanf(file, "%lf ", &val) != EOF) {
- num->d += val;
+static int get_next_number(FILE *file, Number *num) {
+ /* read the next white-space seperated token */
+ char buffer[512];
+
+ int rc = fscanf(file, "%511s", buffer);
+ if (rc == EOF) {
+ return 0;
+ } else if (rc != -1) {
+ return -1;
+ }
+
+ errno = 0;
+ char *endptr;
+ if (ARG_FP_INPUT) {
+ double val = strtod(buffer, &endptr);
+ if (*endptr != 0 || endptr == buffer || errno == ERANGE) {
+ fprintf(stderr, "Skipping invalid input token: %s\n", buffer);
+ return -1;
+ }
+ num->d = val;
+ } else if (ARG_UINT_INPUT) {
+ uint64_t val = strtoull(buffer, &endptr, 10);
+ if (*endptr != 0 || endptr == buffer || errno == ERANGE) {
+ fprintf(stderr, "Skipping invalid input token: %s\n", buffer);
+ return -1;
+ }
+ num->u = val;
+ } else {
+ int64_t val = strtoll(buffer, &endptr, 10);
+ if (*endptr != 0 || endptr == buffer || errno == ERANGE) {
+ fprintf(stderr, "Skipping invalid input token: %s\n", buffer);
+ return -1;
+ }
+ num->i = val;
}
return 1;
}
-static int read_data_int(FILE *file, Number *num) {
- int64_t val;
- while (fscanf(file, "%lld ", &val) != EOF) {
- num->i += val;
+void accumulate_number(Number *sum, Number num) {
+ if (ARG_FP_INPUT) {
+ sum->d += num.d;
+ } else if (ARG_UINT_INPUT) {
+ sum->u += num.u;
+ } else {
+ sum->i += num.i;
}
+}
- return 1;
+void print_buffer_sum() {
+ Number sum = {};
+ for (size_t i = 0; i < ARG_WINDOW_SIZE; i++) {
+ accumulate_number(&sum, window_buffer[i]);
+ }
+ print_sum(sum);
}
-static int read_data_uint(FILE *file, Number *num) {
- uint64_t val;
- while (fscanf(file, "%lld ", &val) != EOF) {
- num->u += val;
+static int read_data(FILE *file, Number *sum) {
+ Number rec = {};
+ int rc;
+ while ((rc = get_next_number(file, &rec))) {
+ if (rc == -1) {
+ continue;
+ }
+
+ if (ARG_WINDOW_SIZE > 1) {
+ window_buffer[window_idx] = rec;
+ window_idx = (window_idx + 1) % ARG_WINDOW_SIZE;
+ print_buffer_sum();
+ } else {
+ accumulate_number(sum, rec);
+ if (ARG_RUNNING_SUM) {
+ print_sum(*sum);
+ }
+ }
}
return 1;
@@ -96,19 +185,9 @@ static int process_data(FILE *file) {
int rc = 1;
Number sum = {};
+ rc = read_data(file, &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) {
+ if (rc && !ARG_RUNNING_SUM) {
print_sum(sum);
}
@@ -149,8 +228,11 @@ int main(int argc, char **argv) {
}
close_file:
- fclose(input_file);
+ if (input_file != stdin) {
+ fclose(input_file);
+ }
+ free(window_buffer);
program_exit:
exit(rc);
}