Begin work on X5
authorSiraaj Khandkar <siraaj@khandkar.net>
Sat, 25 May 2019 00:44:44 +0000 (20:44 -0400)
committerSiraaj Khandkar <siraaj@khandkar.net>
Sat, 25 May 2019 00:44:44 +0000 (20:44 -0400)
parsing CLI params

README.md
x5/.gitignore [new file with mode: 0644]
x5/Makefile [new file with mode: 0644]
x5/khatus.c [new file with mode: 0644]

index 38e6f14..ca1fcf1 100644 (file)
--- 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__ |
 | __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 (file)
index 0000000..fa71cac
--- /dev/null
@@ -0,0 +1,2 @@
+*.o
+khatus
diff --git a/x5/Makefile b/x5/Makefile
new file mode 100644 (file)
index 0000000..1429988
--- /dev/null
@@ -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 (file)
index 0000000..8bbaf8b
--- /dev/null
@@ -0,0 +1,159 @@
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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
+               );
+       }
+}
This page took 0.021349 seconds and 4 git commands to generate.