Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

[PATCH 2/2] persistent locals - zsh/param/persistent module



diff --git a/Src/Modules/param_persistent.c b/Src/Modules/param_persistent.c
new file mode 100644
index 000000000..728559fc9
--- /dev/null
+++ b/Src/Modules/param_persistent.c
@@ -0,0 +1,219 @@
+/*
+ * param_persistent.c - bindings for persistent parameter scopes
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 2015 Barton E. Schaefer
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Barton E. Schaefer or the Zsh Development
+ * Group be liable to any party for direct, indirect, special, incidental, or
+ * consequential damages arising out of the use of this software and its
+ * documentation, even if Barton E. Schaefer and the Zsh
+ * Development Group have been advised of the possibility of such damage.
+ *
+ * Barton E. Schaefer and the Zsh Development Group
+ * specifically disclaim any warranties, including, but not limited to, the
+ * implied warranties of merchantability and fitness for a particular purpose.
+ * The software provided hereunder is on an "as is" basis, and
+ * Barton E. Schaefer and the Zsh Development Group have no
+ * obligation to provide maintenance, support, updates, enhancements, or
+ * modifications.
+ *
+ */
+
+#include "param_persistent.mdh"
+#include "param_persistent.pro"
+
+/*
+ * The trick here is:
+ *
+ * bin_persistent() calls makepersistent() on its "args" array.  It
+ * is not a keyword, so the "assigns" list should be empty.
+ *
+ * makepersistent() walks the array of arguments and, for each name,
+ * pastes up a ".persistent_FUNC.name" string where FUNC is the name
+ * of the function that invoked "persistent".  It tests whether there
+ * is already a parameter having that name.  If not, the name in the
+ * assign struct is changed to this name.  A new assignment of the
+ * original name to this new name is placed in a new list.  The new
+ * list of assignments thus created is returned.
+ *
+ * Assignments for which the persistent name already exists are dropped,
+ * so the parameter retains its flags and value from the previous call.
+ *
+ * bin_persistent() then calls bin_typeset() on the new list with opts
+ * arranged so a to create named references.  If this succeeds, it calls
+ * bin_typeset() again on the rewritten array to handle creation of any
+ * actual parameters to which the named references (the original names
+ * to be made persistent) need to point.
+ *
+ * The end result is that after the first call to "persistent" there is
+ * a global variable in a hidden namespace to which each persistent name
+ * is a reference.  Thereafter, everything happens via the named reference.
+ */
+
+static int makepersistent_error = 0;
+
+/**/
+static Asgment
+cpyasg(char ***argvp)
+{
+    char *s = **argvp, *v = NULL, *new;
+    Asgment a;
+
+    /* Like builtin.c:getasg() without assigns */
+    if (!s || !*s)
+	return NULL;
+    if (*s == '=') {
+	makepersistent_error = 1;
+	return NULL;
+    }
+
+    a = (Asgment)zhalloc(sizeof(struct asgment));
+    a->name = s;
+    a->flags = 0;
+    new = zhtricat(".persistent_",argzero,".");    
+
+    for (; *s && *s != '='; s++);
+    if (*s) {
+	*s = '\0';
+	v = s + 1;
+    }
+    a->value.scalar = new = dyncat(new, **argvp);
+
+    if (is_persistent(new))
+	for (char **argv = *argvp; *argv; argv++)
+	    argv[0] = argv[1];
+    else {
+	if (v)
+	    **argvp = zhtricat(new, "=", v);
+	else
+	    **argvp = dupstring(new);
+	(*argvp)++;
+    }
+    return a;
+}
+
+/**/
+static LinkList
+makepersistent(char **argv)
+{
+    LinkList persist = newlinklist();
+    char ***argvp = &argv;
+    Asgment asg;
+
+    while (**argvp) {
+	if ((asg = cpyasg(argvp)))
+	    uaddlinknode(persist, &asg->node);
+    }
+
+    return persist;
+}
+
+/**/
+static int
+is_persistent(const char *name)
+{
+    return (!strncmp(name, ".persistent_", 12) &&
+	    !!paramtab->getnode(paramtab, name));
+}
+
+/**/
+static int
+bin_persistent(char *nam, char **args, LinkList assigns, Options ops, int func)
+{
+    int from_typeset = 0;
+    int save_llevel = locallevel;
+    makepersistent_error = 0;
+
+    if (*itype_end(argzero, IIDENT, 0)) {
+	zwarnnam("persistent", "invalid scope: %s", argzero);
+	return 1;
+    }
+
+    LinkList namerefs = makepersistent(args);
+    if (makepersistent_error)
+	return 1;
+    if (*args) {
+	queue_signals();
+	locallevel = 0;	/* Does this work? */
+	from_typeset = bin_typeset(nam, args, assigns, ops, func);
+	locallevel = save_llevel;
+	unqueue_signals();
+    }
+    if (!from_typeset) {
+	*args = 0;
+	memset((void *)ops, 0, sizeof(struct options));
+	ops->ind['n'] = ops->ind['H'] = 1;
+	return bin_typeset(nam, args, namerefs, ops, func);
+    }
+
+    return makepersistent_error | from_typeset;
+}
+
+/*
+ * Standard module configuration/linkage
+ */
+
+static struct builtin bintab[] = {
+    /* Copied from BUILTIN("local"), removed "m" and "p" */
+    BUILTIN("persistent", BINF_MAGICEQUALS | BINF_ASSIGN, (HandlerFunc)bin_persistent, 0, -1, 0, "AE:%F:%HL:%PR:%TUZ:%ahi:%lnrtux", NULL)
+};
+
+static struct features module_features = {
+    bintab, sizeof(bintab)/sizeof(*bintab),
+    NULL, 0,
+    NULL, 0,
+    NULL, 0,
+    0
+};
+
+/**/
+int
+setup_(UNUSED(Module m))
+{
+    return 0;
+}
+
+/**/
+int
+features_(Module m, char ***features)
+{
+    *features = featuresarray(m, &module_features);
+    return 0;
+}
+
+/**/
+int
+enables_(Module m, int **enables)
+{
+    return handlefeatures(m, &module_features, enables);
+}
+
+/**/
+int
+boot_(Module m)
+{
+    return 0;
+}
+
+/**/
+int
+cleanup_(Module m)
+{
+    return setfeatureenables(m, &module_features, NULL);
+}
+
+/**/
+int
+finish_(UNUSED(Module m))
+{
+    return 0;
+}
diff --git a/Src/Modules/param_persistent.mdd b/Src/Modules/param_persistent.mdd
new file mode 100644
index 000000000..8f95451d5
--- /dev/null
+++ b/Src/Modules/param_persistent.mdd
@@ -0,0 +1,7 @@
+name=zsh/param/persistent
+link=dynamic
+load=yes
+
+autofeatures="b:persistent"
+
+objects="param_persistent.o"


Messages sorted by: Reverse Date, Date, Thread, Author