diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/cdf.c | 6 | ||||
| -rw-r--r-- | src/cumsum.c | 142 |
2 files changed, 115 insertions, 33 deletions
@@ -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); } |