From 9b5ebc1231a634962f6adbc0919c222101d38053 Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Fri, 24 May 2019 20:44:44 -0400 Subject: [PATCH] Begin work on X5 parsing CLI params --- README.md | 3 +- x5/.gitignore | 2 + x5/Makefile | 16 +++++ x5/khatus.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 x5/.gitignore create mode 100644 x5/Makefile create mode 100644 x5/khatus.c diff --git a/README.md b/README.md index 38e6f14..ca1fcf1 100644 --- a/README.md +++ b/README.md @@ -17,4 +17,5 @@ obsolete earlier ones, they're just different): | __x1__ | Archived | Bash, AWK | Ubuntu 16.04 | Single, synchronous script, saving state in text files | | __x2__ | In-use | Bash, AWK | Debian 10 | Parallel processes: collectors, cache and reporters; passing messages over pipes | | __x3__ | Scratched | OCaml | Debian 10 | Re-write and refinement of __x2__ | -| __x4__ | In-dev | Dash, AWK | Debian 10 | Sensors are completely decoupled daemons, cache is a file tree | +| __x4__ | Prototype | Dash, AWK | Debian 10 | Sensors are completely decoupled daemons, cache is a file tree | +| __x5__ | In-dev | C | Debian 10 | Re-implementation of __x4__ in C | diff --git a/x5/.gitignore b/x5/.gitignore new file mode 100644 index 0000000..fa71cac --- /dev/null +++ b/x5/.gitignore @@ -0,0 +1,2 @@ +*.o +khatus diff --git a/x5/Makefile b/x5/Makefile new file mode 100644 index 0000000..1429988 --- /dev/null +++ b/x5/Makefile @@ -0,0 +1,16 @@ +EXECUTABLES := khatus +CC := gcc -Wall + +.PHONY: \ + build \ + clean \ + rebuild + +build: $(EXECUTABLES) + +clean: + @find . -name '*.o' -type f -delete + @rm -f $(EXECUTABLES) + +rebuild: clean + @$(MAKE) -s build diff --git a/x5/khatus.c b/x5/khatus.c new file mode 100644 index 0000000..8bbaf8b --- /dev/null +++ b/x5/khatus.c @@ -0,0 +1,159 @@ +#include +#include +#include +#include +#include + +#define MAX_TOT_WIDTH 1024 + +#define debug( args...) {fprintf(stderr, "[debug] " args);} +#define error( args...) {fprintf(stderr, "[error] " args); errors++;} +#define fatal(n, args...) {fprintf(stderr, "[fatal] " args); exit(n);} +#define usage( args...) {print_usage(); fatal(1, "[usage] " args);} + + +typedef struct file * File; + +struct file { + char * name; + int width; + int ttl; + File next; +}; + +struct options { + char * argv0; + int interval; + File files; +} options = { + .argv0 = NULL, + .interval = 1, + .files = NULL +}; + +typedef struct options * Options; + +Options opts = &options; +int errors = 0; + + +int +is_pos_num(char *s) +{ + while (*s != '\0') + if (!isdigit(*(s++))) + return 0; + return 1; +} + +void +print_usage() +{ + assert(opts->argv0); + fprintf( + stderr, + "\n" + "Usage: %s [OPTIONS ...] SPEC [SPEC ...]\n" + "\n" + "\tSPEC = FILE_PATH DATA_WIDTH DATA_TTL\n" + "\tFILE_PATH = string\n" + "\tDATA_WIDTH = int (* (positive) number of characters *)\n" + "\tDATA_TTL = int (* (positive) number of seconds *)\n" + "\tOPTION = -i INTERVAL\n" + "\tINTERVAL = int (* (positive) number of seconds *)\n" + "\n", + opts->argv0 + ); + fprintf( + stderr, + "Example: %s -i 1 /dev/shm/khatus/khatus_sensor_x 4 10\n" + "\n", + opts->argv0 + ); +} + +void parse_opts(int, char *[], int); /* For mutually-recursive calls. */ + +void +parse_opts_opt_i(int argc, char *argv[], int i) +{ + if (i < argc) { + char *param = argv[i++]; + + if (is_pos_num(param)) { + opts->interval = atoi(param); + parse_opts(argc, argv, i); + } else { + usage("Option -i parameter is invalid: \"%s\"\n", param); + } + } else { + usage("Option -i parameter is missing.\n"); + } +} + +void +parse_opts_opt(int argc, char *argv[], int i) +{ + switch (argv[i][1]) { + case 'i': parse_opts_opt_i(argc, argv, ++i); break; /* TODO: Generic set_int */ + default : usage("Option \"%s\" is invalid\n", argv[i]); + } +} + +void +parse_opts_spec(int argc, char *argv[], int i) +{ + if ((i + 3) > argc) + usage("[spec] Parameter(s) missing for file \"%s\".\n", argv[i]); + + char *n = argv[i++]; + char *w = argv[i++]; + char *t = argv[i++]; + + if (!is_pos_num(w)) + usage("[spec] Invalid width: \"%s\", for file \"%s\"\n", w, n); + if (!is_pos_num(t)) + usage("[spec] Invalid TTL: \"%s\", for file \"%s\"\n", t, n); + File f = malloc(sizeof(struct file)); + if (f) { + f->name = n; + f->width = atoi(w); + f->ttl = atoi(t); + f->next = opts->files; + opts->files = f; + } else { + fatal(2, "[memory] Allocation failure."); + } + parse_opts(argc, argv, i); +} + +void +parse_opts(int argc, char *argv[], int i) +{ + if (i < argc) { + switch (argv[i][0]) { + case '-': parse_opts_opt(argc, argv, i); break; + default : parse_opts_spec(argc, argv, i); + } + } +} + +int +main(int argc, char **argv) +{ + opts->argv0 = argv[0]; + parse_opts(argc, argv, 1); + assert(!errors); + debug("[options] argv0 = %s\n", opts->argv0); + debug("[options] interval = %d\n", opts->interval); + if (opts->files == NULL) + usage("No file specs were given!\n"); + for (File f = opts->files; f; f = f->next) { + debug( + "[options] file = { name = %s, width = %d, ttl = %d }\n", + f->name, + f->width, + f->ttl + ); + } +} -- 2.20.1