about summary refs log tree commit diff
path: root/Src/Modules/zutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Modules/zutil.c')
-rw-r--r--Src/Modules/zutil.c139
1 files changed, 139 insertions, 0 deletions
diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c
index 3c04d03d8..56b22b5f9 100644
--- a/Src/Modules/zutil.c
+++ b/Src/Modules/zutil.c
@@ -1155,10 +1155,149 @@ bin_zregexparse(char *nam, char **args, char *ops, int func)
     return ret;
 }
 
+typedef struct zoptdesc *Zoptdesc;
+typedef struct zoptarr *Zoptarr;
+typedef struct zoptval *Zoptval;
+
+struct zoptdesc {
+    int arg;
+    Zoptarr arr;
+};
+
+struct zoptarr {
+    char *name;
+    Zoptval vals, last;
+    Zoptarr next;
+    int num;
+};
+
+#define ZOF_ARG 1
+#define ZOF_ADD 2
+
+struct zoptval {
+    char *str;
+    Zoptval next;
+};
+
+static Zoptarr opt_arrs;
+
+static Zoptarr
+get_opt_arr(char *name)
+{
+    Zoptarr p;
+
+    for (p = opt_arrs; p; p = p->next)
+	if (!strcmp(name, p->name))
+	    return p;
+
+    return NULL;
+}
+
+static int
+bin_zparseopts(char *nam, char **args, char *ops, int func)
+{
+    char *o, *n, **pp, *str, **aval;
+    Zoptdesc opts[256], d;
+    Zoptarr a;
+    Zoptval v;
+
+    memset(opts, 0, 256 * sizeof(Zoptdesc));
+    opt_arrs = NULL;
+
+    while ((o = *args++)) {
+	if (opts[STOUC(*o)]) {
+	    zerrnam(nam, "option described more than once: %s", o, 0);
+	    return 1;
+	}
+	d = (Zoptdesc) zhalloc(sizeof(*d));
+	d->arg = (o[1] == ':' ? ZOF_ARG : (o[1] == '+' ? ZOF_ADD : 0));
+	if (!(a = get_opt_arr((n = o + (d->arg ? 2 : 1))))) {
+	    a = (Zoptarr) zhalloc(sizeof(*a));
+	    a->name = n;
+	    a->num = 0;
+	    a->vals = a->last = NULL;
+	    a->next = opt_arrs;
+	    opt_arrs = a;
+	}
+	d->arr = a;
+	opts[STOUC(*o)] = d;
+    }
+    for (pp = pparams; (o = *pp); pp++) {
+	if (*o != '-')
+	    break;
+	while (*++o) {
+	    if (!(d = opts[STOUC(*o)]))
+		break;
+	    if (d->arg) {
+		if (o[1]) {
+		    str = (char *) zhalloc(strlen(o) + 2);
+		    str[0] = '-';
+		    strcpy(str + 1, o);
+		} else if (!pp[1]) {
+		    zerrnam(nam, "missing argument for option: -%c", NULL, *o);
+		    return 1;
+		} else {
+		    str = (char *) zhalloc(strlen(pp[1]) + 3);
+		    str[0] = '-';
+		    str[1] = *o;
+		    strcpy(str + 2, pp[1]);
+		    pp++;
+		}
+		o = "" - 1;
+	    } else {
+		str = (char *) zhalloc(3);
+		str[0] = '-';
+		str[1] = *o;
+		str[2] = '\0';
+	    }
+	    if (d->arg != ZOF_ADD) {
+		for (v = d->arr->vals; v; v = v->next) {
+		    if (str[1] == v->str[1]) {
+			v->str = str;
+			str = NULL;
+			break;
+		    }
+		}
+	    }
+	    if (str) {
+		v = (Zoptval) zhalloc(sizeof(*v));
+		v->str = str;
+		v->next = NULL;
+
+		if (d->arr->last)
+		    d->arr->last->next = v;
+		else
+		    d->arr->vals = v;
+		d->arr->last = v;
+		d->arr->num++;
+	    }
+	}
+	if (*o)
+	    break;
+    }
+    if (ops['D']) {
+	PERMALLOC {
+	    pp = arrdup(pp);
+	} LASTALLOC;
+
+	freearray(pparams);
+	pparams = pp;
+    }
+    for (a = opt_arrs; a; a = a->next) {
+	aval = (char **) zalloc((a->num + 1) * sizeof(char *));
+	for (pp = aval, v = a->vals; v; pp++, v = v->next)
+	    *pp = ztrdup(v->str);
+	*pp = NULL;
+	setaparam(a->name, aval);
+    }
+    return 0;
+}
+
 static struct builtin bintab[] = {
     BUILTIN("zstyle", 0, bin_zstyle, 0, -1, 0, NULL, NULL),
     BUILTIN("zformat", 0, bin_zformat, 3, -1, 0, NULL, NULL),
     BUILTIN("zregexparse", 0, bin_zregexparse, 3, -1, 0, "c", NULL),
+    BUILTIN("zparseopts", 0, bin_zparseopts, 1, -1, 0, "D", NULL),
 };