aboutsummaryrefslogtreecommitdiffstats
path: root/opts.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--opts.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/opts.c b/opts.c
new file mode 100644
index 0000000..5c264dd
--- /dev/null
+++ b/opts.c
@@ -0,0 +1,130 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+static int
+sizeopt(size_t *valp, const char *s)
+{
+ if (isdigit(*s))
+ return 0;
+ *valp = 0;
+ for (; isdigit(*s); s++) {
+ if (*valp * 10U + (size_t)(*s & 15) > SIZE_MAX)
+ *valp = SIZE_MAX;
+ else
+ *valp = *valp * 10U + (size_t)(*s & 15);
+ }
+ return !*s;
+}
+
+
+int
+parseopt_vendor(void *config_, char *opt, char *val)
+{
+ struct config *config = config_;
+ if (!strcmp(opt, "output")) {
+ if (!val)
+ eprintf("-W option \"%s\" should have an associated value", opt);
+ config->format &= (enum format)~FORMAT_MASK;
+ if (!strcmp(val, "lowercase"))
+ config->format |= LOWERCASE_HEX;
+ else if (!strcmp(val, "uppercase"))
+ config->format |= UPPERCASE_HEX;
+ else if (!strcmp(val, "binary"))
+ config->format |= BINARY;
+ else
+ eprintf("-W option \"%s\" expected value \"lowercase\", \"uppercase\", or \"binary\"", opt);
+
+ } else if (!strcmp(opt, "input")) {
+ if (!val)
+ eprintf("-W option \"%s\" should have an associated value", opt);
+ config->format &= (enum format)~FORMAT_MASK;
+ if (!strcmp(val, "binary") || !strcmp(val, "text"))
+ config->hexinput = 0;
+ else if (!strcmp(val, "hexadecimal"))
+ config->hexinput = 1;
+ else
+ eprintf("-W option \"%s\" expected value \"binary\", \"text\", or \"hexadecimal\"", opt);
+
+ } else if (!strcmp(opt, "threads")) {
+ if (!val)
+ eprintf("-W option \"%s\" should have an associated value", opt);
+ if (!strcmp(val, "auto"))
+ config->threads = 0;
+ else if (!sizeopt(&config->threads, val) || !config->threads)
+ eprintf("-W option \"%s\" expected positive integer value or \"auto\"", opt);
+
+ } else if (!strcmp(opt, "recursive")) {
+ /* TODO the default behaviour should be to not traverse across mount points,
+ * not to not follow symbolic links, however this should be tweakable */
+ if (!val)
+ eprintf("-W option \"%s\" should not have an associated value", opt);
+ config->recursive = 1;
+
+ } else if (!strcmp(opt, "no-recursive")) {
+ if (!val)
+ eprintf("-W option \"%s\" should not have an associated value", opt);
+ config->recursive = 0;
+
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+
+char *
+parseopts(void *config, char *string, int (*parseopt)(void *, char *opt, char *val))
+{
+ char *opt, *r = string, c, *val;
+ char *w = string;
+ size_t brackets = 0;
+
+ for (;;) {
+ opt = r;
+ while (*r && *r != ',' && *r != '=')
+ r++;
+ for (; *r; r++) {
+ if (*r == '[' || *r == '(' || *r == '{')
+ brackets++;
+ else if (brackets && (*r == ']' || *r == ')' || *r == '}'))
+ brackets--;
+ else if (!brackets && (*r == ',' || *r == '='))
+ break;
+ }
+ c = *r;
+ *r++ = '\0';
+ val = NULL;
+ if (c == '=') {
+ val = r;
+ for (; *r; r++) {
+ if (*r == '[' || *r == '(' || *r == '{')
+ brackets++;
+ else if (brackets && (*r == ']' || *r == ')' || *r == '}'))
+ brackets--;
+ else if (!brackets && *r == ',')
+ break;
+ }
+ c = *r;
+ *r++ = '\0';
+ }
+
+ if (!(*parseopt)(config, opt, val)) {
+ if (*opt || val) {
+ if (w != string)
+ *w++ = ',';
+ w = stpcpy(w, opt);
+ if (val) {
+ *w++ = '=';
+ w = stpcpy(w, val);
+ }
+ }
+ }
+
+ if (!c)
+ break;
+ }
+
+ *w = '\0';
+ return string;
+}