about summary refs log tree commit diff
path: root/Src/module.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/module.c')
-rw-r--r--Src/module.c378
1 files changed, 272 insertions, 106 deletions
diff --git a/Src/module.c b/Src/module.c
index d40bb133a..ef158c6a3 100644
--- a/Src/module.c
+++ b/Src/module.c
@@ -197,14 +197,24 @@ addbuiltin(Builtin b)
 
 /**/
 int
-add_autobin(char *nam, char *module)
+add_autobin(char *cmdnam, char *bnam, char *module, int opt_i)
 {
-    Builtin bn = zshcalloc(sizeof(*bn));
-    bn->node.nam = ztrdup(nam);
+    Builtin bn;
+
+    if (strchr(bnam, '/')) {
+	zwarnnam(cmdnam, "%s: `/' is illegal in a builtin", bnam);
+	return 1;
+    }
+
+    bn = zshcalloc(sizeof(*bn));
+    bn->node.nam = ztrdup(bnam);
     bn->optstr = ztrdup(module);
     if (addbuiltin(bn)) {
 	builtintab->freenode(&bn->node);
-	return 1;
+	if (!opt_i) {
+	    zwarnnam(cmdnam, "failed to add builtin %s", bnam);
+	    return 1;
+	}
     }
     return 0;
 }
@@ -225,6 +235,27 @@ deletebuiltin(char *nam)
     return 0;
 }
 
+/* Remove an autoloaded added by add_autobin */
+
+/**/
+static int
+del_autobin(char *cmdnam, char *bnam, int opt_i)
+{
+    Builtin bn = (Builtin) builtintab->getnode2(builtintab, bnam);
+    if (!bn) {
+	if(!opt_i) {
+	    zwarnnam(cmdnam, "%s: no such builtin", bnam);
+	    return 1;
+	}
+    } else if (bn->node.flags & BINF_ADDED) {
+	zwarnnam(cmdnam, "%s: builtin is already defined", bnam);
+	return 1;
+    } else
+	deletebuiltin(bnam);
+
+    return 0;
+}
+
 /*
  * Manipulate a set of builtins.  This should be called
  * via setfeatureenables() (or, usually, via the next level up,
@@ -406,10 +437,14 @@ getconddef(int inf, char *name, int autol)
 		break;
 	}
 	if (autol && p && p->module) {
-	    /* This is a definition for an autoloaded condition, load the *
-	     * module if we haven't tried that already. */
+	    /*
+	     * This is a definition for an autoloaded condition; load the
+	     * module if we haven't tried that already.
+	     */
 	    if (f) {
-		(void)ensurefeature(p->module, "c:", name);
+		(void)ensurefeature(p->module,
+				    (p->flags & CONDF_INFIX) ?
+				    "C:" : "c:", name);
 		f = 0;
 		p = NULL;
 	    } else {
@@ -523,11 +558,18 @@ setconddefs(char const *nam, Conddef c, int size, int *e)
 
 /**/
 int
-add_autocond(char *nam, int inf, char *module)
+add_autocond(char *cmdnam, char *cnam, int inf, char *module, int opt_i)
 {
-    Conddef c = (Conddef) zalloc(sizeof(*c));
+    Conddef c;
+
+    if (strchr(cnam, '/')) {
+	zwarnnam(cmdnam, "%s: `/' is illegal in a condition", cnam);
+	return 1;
+    }
+
+    c = (Conddef) zalloc(sizeof(*c));
 
-    c->name = ztrdup(nam);
+    c->name = ztrdup(cnam);
     c->flags = (inf  ? CONDF_INFIX : 0);
     c->module = ztrdup(module);
 
@@ -536,11 +578,35 @@ add_autocond(char *nam, int inf, char *module)
 	zsfree(c->module);
 	zfree(c, sizeof(*c));
 
-	return 1;
+	if (!opt_i) {
+	    zwarnnam(cmdnam, "failed to add condition `%s'", cnam);
+	    return 1;
+	}
     }
     return 0;
 }
 
+/* Remove a condition added with add_autocond */
+
+/**/
+static int
+del_autocond(char *cmdnam, char *cnam, int infix, int opt_i)
+{
+    Conddef cd = getconddef(infix, cnam, 0);
+
+    if (!cd) {
+	if (!opt_i) {
+	    zwarnnam(cmdnam, "%s: no such condition", cnam);
+	    return 1;
+	}
+    } else if (cd->flags & CONDF_ADDED) {
+	zwarnnam(cmdnam, "%s: condition is already defined", cnam);
+	return 1;
+    } else
+	deleteconddef(cd);
+
+    return 0;
+}
 
 /************************************************************************
  * Hook functions.
@@ -722,10 +788,13 @@ runhookdef(Hookdef h, void *d)
  * Check that it's possible to add a parameter.  This
  * requires that either there's no parameter already present,
  * or it's a global parameter marked for autoloading.
+ *
+ * The special status 2 is to indicate it didn't work but
+ * -i was in use so we didn't print a warning.
  */
 
 static int
-checkaddparam(char *nam)
+checkaddparam(char *nam, int opt_i)
 {
     Param pm;
 
@@ -733,11 +802,22 @@ checkaddparam(char *nam)
 	return 0;
 
     if (pm->level || !(pm->node.flags & PM_AUTOLOAD)) {
-	zwarn("Can't add module parameter `%s': %s",
-	      nam, pm->level ?
-	      "local parameter exists" :
-	      "parameter already exists");
-	return 1;
+	/*
+	 * -i suppresses "it's already that way" warnings,
+	 * but not "this can't possibly work" warnings, so we print
+	 * the message anyway if there's a local parameter blocking
+	 * the parameter we want to add, not if there's a
+	 * non-autoloadable parameter already there.  This
+	 * is consistent with the way add_auto* functions work.
+	 */
+	if (!opt_i || !pm->level) {
+	    zwarn("Can't add module parameter `%s': %s",
+		  nam, pm->level ?
+		  "local parameter exists" :
+		  "parameter already exists");
+	    return 1;
+	}
+	return 2;
     }
 
     unsetparam_pm(pm, 0, 1);
@@ -753,7 +833,7 @@ addparamdef(Paramdef d)
 {
     Param pm;
 
-    if (checkaddparam(d->name))
+    if (checkaddparam(d->name, 0))
 	return 1;
 
     if (d->getnfn) {
@@ -879,23 +959,60 @@ setparamdefs(char const *nam, Paramdef d, int size, int *e)
 /* This adds a definition for autoloading a module for a parameter. */
 
 /**/
-void
-add_autoparam(char *nam, char *module)
+int
+add_autoparam(char *cmdnam, char *pnam, char *module, int opt_i)
 {
     Param pm;
+    int ret;
+
+    if (strchr(pnam, '/')) {
+	zwarnnam(cmdnam, "%s: `/' is illegal in a parameter", pnam);
+	return 1;
+    }
 
     queue_signals();
-    if (checkaddparam(nam)) {
+    if ((ret = checkaddparam(pnam, opt_i))) {
 	unqueue_signals();
-	return;
+	/*
+	 * checkaddparam() has already printed a message
+	 * if one was needed.  If it wasn't because of -i,
+	 * ret is 2; for consistency with other add_auto*
+	 * functions we return status 0 to indicate there's
+	 * already such a parameter and we've been told not
+	 * to worry if so.
+	 */
+	return ret == 2 ? 0 : 1;
     }
 
-    pm = setsparam(nam, ztrdup(module));
+    pm = setsparam(pnam, ztrdup(module));
 
     pm->node.flags |= PM_AUTOLOAD;
     unqueue_signals();
+
+    return 0;
 }
 
+/* Remove a parameter added with add_autoparam() */
+
+/**/
+static int
+del_autoparam(char *cmdnam, char *pnam, int opt_i)
+{
+    Param pm = (Param) gethashnode2(paramtab, pnam);
+
+    if (!pm) {
+	if (!opt_i) {
+	    zwarnnam(cmdnam, "%s: no such parameter", pnam);
+	    return 1;
+	}
+    } else if (!(pm->node.flags & PM_AUTOLOAD)) {
+	zwarnnam(cmdnam, "%s: parameter is already defined", pnam);
+	return 1;
+    } else
+	unsetparam_pm(pm, 0, 1);
+
+    return 0;
+}
 
 /************************************************************************
  * Math functions.
@@ -1053,11 +1170,18 @@ setmathfuncs(char const *nam, MathFunc f, int size, int *e)
 
 /**/
 int
-add_automathfunc(char *nam, char *module)
+add_automathfunc(char *cmdnam, char *fnam, char *module, int opt_i)
 {
-    MathFunc f = (MathFunc) zalloc(sizeof(*f));
+    MathFunc f;
+
+    if (strchr(fnam, '/')) {
+	zwarnnam(cmdnam, "%s: `/' is illegal in a math function", fnam);
+	return 1;
+    }
 
-    f->name = ztrdup(nam);
+    f = (MathFunc) zalloc(sizeof(*f));
+
+    f->name = ztrdup(fnam);
     f->module = ztrdup(module);
     f->flags = 0;
 
@@ -1066,12 +1190,36 @@ add_automathfunc(char *nam, char *module)
 	zsfree(f->module);
 	zfree(f, sizeof(*f));
 
-	return 1;
+	if (!opt_i) {
+	    zwarnnam(cmdnam, "failed to add math function `%s'", fnam);
+	    return 1;
+	}
     }
 
     return 0;
 }
 
+/* Remove a math function added with add_automathfunc() */
+
+/**/
+static int
+del_automathfunc(char *cmdnam, char *fnam, int opt_i)
+{
+    MathFunc f = getmathfunc(fnam, 0);
+    
+    if (!f) {
+	if (!opt_i) {
+	    zwarnnam(cmdnam, "%s: no such math function", fnam);
+	    return 1;
+	}
+    } else if (f->flags & MFF_ADDED) {
+	zwarnnam(cmdnam, "%s: math function is already defined", fnam);
+	return 1;
+    } else
+	deletemathfunc(f);
+
+    return 0;
+}
 
 /************************************************************************
  * Now support for dynamical loading and the fallback functions
@@ -2002,15 +2150,13 @@ bin_zmodload(char *nam, char **args, Options ops, UNUSED(int func))
     /* options only allowed with -F */
     char *fonly = "lP", *fp;
 
-    if (ops_bcpf) {
-	if (!ops_au) {
-	    zwarnnam(nam, "-b, -c, -f, and -p must be combined with -a or -u");
-	    return 1;
-	}
-	if (OPT_ISSET(ops,'F')) {
-	    zwarnnam(nam, "-b, -c, -f, and -p cannot be combined with -F");
-	    return 1;
-	}
+    if (ops_bcpf && !ops_au) {
+	zwarnnam(nam, "-b, -c, -f, and -p must be combined with -a or -u");
+	return 1;
+    }
+    if (OPT_ISSET(ops,'F') && (ops_bcpf || OPT_ISSET(ops,'u'))) {
+	zwarnnam(nam, "-b, -c, -f, -p and -u cannot be combined with -F");
+	return 1;
     }
     if (OPT_ISSET(ops,'A') || OPT_ISSET(ops,'R')) {
 	if (ops_bcpf || ops_au || OPT_ISSET(ops,'d') || 
@@ -2304,20 +2450,11 @@ static int
 bin_zmodload_auto(char *nam, char **args, Options ops)
 {
     int ret = 0;
-    if(OPT_ISSET(ops,'u')) {
-	/* remove autoloaded builtins */
+    if (OPT_ISSET(ops,'u')) {
+	/* removed autoloaded builtins */
 	for (; *args; args++) {
-	    Builtin bn = (Builtin) builtintab->getnode2(builtintab, *args);
-	    if (!bn) {
-		if(!OPT_ISSET(ops,'i')) {
-		    zwarnnam(nam, "%s: no such builtin", *args);
-		    ret = 1;
-		}
-	    } else if (bn->node.flags & BINF_ADDED) {
-		zwarnnam(nam, "%s: builtin is already defined", *args);
+	    if (del_autobin(nam, *args, OPT_ISSET(ops,'i')))
 		ret = 1;
-	    } else
-		deletebuiltin(*args);
 	}
 	return ret;
     } else if(!*args) {
@@ -2331,13 +2468,8 @@ bin_zmodload_auto(char *nam, char **args, Options ops)
 	modnam = *args++;
 	do {
 	    char *bnam = *args ? *args++ : modnam;
-	    if (strchr(bnam, '/')) {
-		zwarnnam(nam, "%s: `/' is illegal in a builtin", bnam);
+	    if (add_autobin(nam, bnam, modnam, OPT_ISSET(ops,'i')))
 		ret = 1;
-	    } else if (add_autobin(bnam, modnam) && !OPT_ISSET(ops,'i')) {
-		zwarnnam(nam, "failed to add builtin %s", bnam);
-		ret = 1;
-	    }
 	} while(*args);
 	return ret;
     }
@@ -2354,18 +2486,9 @@ bin_zmodload_cond(char *nam, char **args, Options ops)
     if (OPT_ISSET(ops,'u')) {
 	/* remove autoloaded conditions */
 	for (; *args; args++) {
-	    Conddef cd = getconddef(OPT_ISSET(ops,'I'), *args, 0);
-
-	    if (!cd) {
-		if (!OPT_ISSET(ops,'i')) {
-		    zwarnnam(nam, "%s: no such condition", *args);
-		    ret = 1;
-		}
-	    } else if (cd->flags & CONDF_ADDED) {
-		zwarnnam(nam, "%s: condition is already defined", *args);
+	    if (del_autocond(nam, *args, OPT_ISSET(ops,'I'),
+			     OPT_ISSET(ops,'i')))
 		ret = 1;
-	    } else
-		deleteconddef(cd);
 	}
 	return ret;
     } else if (!*args) {
@@ -2396,14 +2519,9 @@ bin_zmodload_cond(char *nam, char **args, Options ops)
 	modnam = *args++;
 	do {
 	    char *cnam = *args ? *args++ : modnam;
-	    if (strchr(cnam, '/')) {
-		zwarnnam(nam, "%s: `/' is illegal in a condition", cnam);
+	    if (add_autocond(nam, cnam, OPT_ISSET(ops, 'I'),
+			     modnam, OPT_ISSET(ops,'i')))
 		ret = 1;
-	    } else if (add_autocond(cnam, OPT_ISSET(ops,'I'), modnam) &&
-		       !OPT_ISSET(ops,'i')) {
-		zwarnnam(nam, "failed to add condition `%s'", cnam);
-		ret = 1;
-	    }
 	} while(*args);
 	return ret;
     }
@@ -2420,18 +2538,8 @@ bin_zmodload_math(char *nam, char **args, Options ops)
     if (OPT_ISSET(ops,'u')) {
 	/* remove autoloaded math functions */
 	for (; *args; args++) {
-	    MathFunc f = getmathfunc(*args, 0);
-
-	    if (!f) {
-		if (!OPT_ISSET(ops,'i')) {
-		    zwarnnam(nam, "%s: no such math function", *args);
-		    ret = 1;
-		}
-	    } else if (f->flags & MFF_ADDED) {
-		zwarnnam(nam, "%s: math function is already defined", *args);
+	    if (del_automathfunc(nam, *args, OPT_ISSET(ops,'i')))
 		ret = 1;
-	    } else
-		deletemathfunc(f);
 	}
 	return ret;
     } else if (!*args) {
@@ -2455,13 +2563,8 @@ bin_zmodload_math(char *nam, char **args, Options ops)
 	modnam = *args++;
 	do {
 	    char *fnam = *args ? *args++ : modnam;
-	    if (strchr(fnam, '/')) {
-		zwarnnam(nam, "%s: `/' is illegal in a math function", fnam);
+	    if (add_automathfunc(nam, fnam, modnam, OPT_ISSET(ops,'i')))
 		ret = 1;
-	    } else if (add_automathfunc(fnam, modnam) && !OPT_ISSET(ops,'i')) {
-		zwarnnam(nam, "failed to add math function `%s'", fnam);
-		ret = 1;
-	    }
 	} while(*args);
 	return ret;
     }
@@ -2496,18 +2599,8 @@ bin_zmodload_param(char *nam, char **args, Options ops)
     if (OPT_ISSET(ops,'u')) {
 	/* remove autoloaded parameters */
 	for (; *args; args++) {
-	    Param pm = (Param) gethashnode2(paramtab, *args);
-
-	    if (!pm) {
-		if (!OPT_ISSET(ops,'i')) {
-		    zwarnnam(nam, "%s: no such parameter", *args);
-		    ret = 1;
-		}
-	    } else if (!(pm->node.flags & PM_AUTOLOAD)) {
-		zwarnnam(nam, "%s: parameter is already defined", *args);
+	    if (del_autoparam(nam, *args, OPT_ISSET(ops,'i')))
 		ret = 1;
-	    } else
-		unsetparam_pm(pm, 0, 1);
 	}
 	return ret;
     } else if (!*args) {
@@ -2520,11 +2613,8 @@ bin_zmodload_param(char *nam, char **args, Options ops)
 	modnam = *args++;
 	do {
 	    char *pnam = *args ? *args++ : modnam;
-	    if (strchr(pnam, '/')) {
-		zwarnnam(nam, "%s: `/' is illegal in a parameter", pnam);
+	    if (add_autoparam(nam, pnam, modnam, OPT_ISSET(ops,'i')))
 		ret = 1;
-	    } else
-		add_autoparam(pnam, modnam);
 	} while(*args);
 	return ret;
     }
@@ -2733,6 +2823,8 @@ bin_zmodload_features(char *nam, char **args, Options ops)
 	 * only options turned on.
 	 * With both options, list as zmodload showing options
 	 * to be turned both on and off.
+	 *
+	 * TODO: handle -a, list only autoloads.
 	 */
 	LinkNode node;
 	Module m = NULL;
@@ -2856,6 +2948,8 @@ bin_zmodload_features(char *nam, char **args, Options ops)
     } else if (OPT_ISSET(ops,'P')) {
 	zwarnnam(nam, "-P can only be used with -l or -L");
 	return 1;
+    } else if (OPT_ISSET(ops,'a')) {
+	return autofeatures(nam, args, modname, OPT_ISSET(ops,'i'));
     }
 
     return require_module(modname, args);
@@ -2891,8 +2985,11 @@ featuresarray(char const *nam, Features f)
 
     while (bn_size--)
 	*featurep++ = dyncat("b:", (bnp++)->node.nam);
-    while (cd_size--)
-	*featurep++ = dyncat("c:", (cdp++)->name);
+    while (cd_size--) {
+	*featurep++ = dyncat((cdp->flags & CONDF_INFIX) ? "C:" : "c:",
+			     cdp->name);
+	cdp++;
+    }
     while (pd_size--)
 	*featurep++ = dyncat("p:", (pdp++)->name);
     while (mf_size--)
@@ -3011,3 +3108,72 @@ ensurefeature(char *modname, char *prefix, char *feature)
     features[1] = NULL;
     return require_module(modname, features);
 }
+
+/*
+ * Add autoloadable features for a given module.
+ */
+
+/**/
+int
+autofeatures(char *cmdnam, char **features, char *module, int opt_i)
+{
+    int ret = 0, infix;
+
+    while (*features) {
+	char *feature = *features, *fnam;
+	int add;
+
+	if (*feature == '-') {
+	    add = 0;
+	    feature ++;
+	} else {
+	    add = 1;
+	    if (*feature == '+')
+		feature++;
+	}
+
+	if (!*feature || feature[1] != ':') {
+	    zwarnnam(cmdnam, "bad format for autoloadable feature: `%s'",
+		     feature);
+	    ret = 1;
+	}
+	fnam = feature + 2;
+	switch (feature[0]) {
+	case 'b':
+	    if (add ? add_autobin(cmdnam, fnam, module, opt_i) :
+		del_autobin(cmdnam, fnam, opt_i));
+		ret = 1;
+	    break;
+
+	case 'c':
+	case 'C':
+	    infix = (feature[0] == 'C');
+	    if (add ? add_autocond(cmdnam, fnam, infix, module, opt_i) :
+		del_autocond(cmdnam, fnam, infix, opt_i))
+		ret = 1;
+	    break;
+
+	case 'p':
+	    if (add ? add_autoparam(cmdnam, fnam, module, opt_i) :
+		del_autoparam(cmdnam, fnam, opt_i));
+		ret = 1;
+	    break;
+
+	case 'f':
+	    if (add ? add_automathfunc(cmdnam, fnam, module, opt_i) :
+		del_automathfunc(cmdnam, fnam, opt_i))
+		ret = 1;
+	    break;
+
+	default:
+	    zwarnnam(cmdnam, "bad autoloadable feature type: `%s'",
+		     feature);
+	    ret = 1;
+	    break;
+	}
+
+	features++;
+    }
+
+    return ret;
+}