about summary refs log tree commit diff
path: root/Src/builtin.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/builtin.c')
-rw-r--r--Src/builtin.c171
1 files changed, 113 insertions, 58 deletions
diff --git a/Src/builtin.c b/Src/builtin.c
index 3a471760a..a3e7149d9 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -71,7 +71,7 @@ static struct builtin builtins[] =
      */
     BUILTIN("fc", 0, bin_fc, 0, -1, BIN_FC, "nlre:IRWAdDfEimpPa", NULL),
     BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL),
-    BUILTIN("float", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "E:%F:%Hghlprtux", "E"),
+    BUILTIN("float", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "E:%F:%HL:%R:%Z:%ghlprtux", "E"),
     BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "kmtuUz", NULL),
     BUILTIN("getln", 0, bin_read, 0, -1, 0, "ecnAlE", "zr"),
     BUILTIN("getopts", 0, bin_getopts, 2, -1, 0, NULL, NULL),
@@ -82,7 +82,7 @@ static struct builtin builtins[] =
 #endif
 
     BUILTIN("history", 0, bin_fc, 0, -1, BIN_FC, "nrdDfEimpPa", "l"),
-    BUILTIN("integer", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "Hghi:%lprtux", "i"),
+    BUILTIN("integer", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "HL:%R:%Z:%ghi:%lprtux", "i"),
     BUILTIN("jobs", 0, bin_fg, 0, -1, BIN_JOBS, "dlpZrs", NULL),
     BUILTIN("kill", 0, bin_kill, 0, -1, 0, NULL, NULL),
     BUILTIN("let", 0, bin_let, 1, -1, 0, NULL, NULL),
@@ -1719,13 +1719,73 @@ enum {
     NS_SECONDS
 };
 
+static const struct gsu_scalar tiedarr_gsu =
+{ tiedarrgetfn, tiedarrsetfn, tiedarrunsetfn };
+
+/* Install a base if we are turning on a numeric option with an argument */
+
+static int
+typeset_setbase(const char *name, Param pm, Options ops, int on, int always)
+{
+    char *arg = NULL;
+
+    if ((on & PM_INTEGER) && OPT_HASARG(ops,'i'))
+	arg = OPT_ARG(ops,'i');
+    else if ((on & PM_EFLOAT) && OPT_HASARG(ops,'E'))
+	arg = OPT_ARG(ops,'E');
+    else if ((on & PM_FFLOAT) && OPT_HASARG(ops,'F'))
+	arg = OPT_ARG(ops,'F');
+
+    if (arg) {
+	char *eptr;
+	pm->base = (int)zstrtol(arg, &eptr, 10);
+	if (*eptr) {
+	    if (on & PM_INTEGER)
+		zwarnnam(name, "bad base value: %s", arg, 0);
+	    else
+		zwarnnam(name, "bad precision value: %s", arg, 0);
+	    return 1;
+	}
+    } else if (always)
+	pm->base = 0;
+
+    return 0;
+}
+
+/* Install a width if we are turning on a padding option with an argument */
+
+static int
+typeset_setwidth(const char * name, Param pm, Options ops, int on, int always)
+{
+    char *arg = NULL;
+
+    if ((on & PM_LEFT) && OPT_HASARG(ops,'L'))
+	arg = OPT_ARG(ops,'L');
+    else if ((on & PM_RIGHT_B) && OPT_HASARG(ops,'R'))
+	arg = OPT_ARG(ops,'R');
+    else if ((on & PM_RIGHT_Z) && OPT_HASARG(ops,'Z'))
+	arg = OPT_ARG(ops,'Z');
+
+    if (arg) {
+	char *eptr;
+	pm->width = (int)zstrtol(arg, &eptr, 10);
+	if (*eptr) {
+	    zwarnnam(name, "bad width value: %s", arg, 0);
+	    return 1;
+	}
+    } else if (always)
+	pm->width = 0;
+
+    return 0;
+}
+
 /* function to set a single parameter */
 
 /**/
 static Param
 typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	       int on, int off, int roff, char *value, Param altpm,
-	       Options ops, int auxlen, int joinchar)
+	       Options ops, int joinchar)
 {
     int usepm, tc, keeplocal = 0, newspecial = NS_NONE, readonly;
     char *subscript;
@@ -1862,25 +1922,28 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	    Param apm;
 	    char **x;
 	    if (PM_TYPE(pm->flags) == PM_ARRAY) {
-		x = (*pm->gets.afn)(pm);
+		x = (*pm->gsu.a->getfn)(pm);
 		uniqarray(x);
 		if (pm->ename && x)
 		    arrfixenv(pm->ename, x);
 	    } else if (PM_TYPE(pm->flags) == PM_SCALAR && pm->ename &&
 		       (apm =
 			(Param) paramtab->getnode(paramtab, pm->ename))) {
-		x = (*apm->gets.afn)(apm);
+		x = (*apm->gsu.a->getfn)(apm);
 		uniqarray(x);
 		if (x)
 		    arrfixenv(pm->nam, x);
 	    }
 	}
 	pm->flags = (pm->flags | (on & ~PM_READONLY)) & ~(off | PM_UNSET);
-	/* This auxlen/pm->ct stuff is a nasty hack. */
-	if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER |
-		   PM_EFLOAT | PM_FFLOAT)) &&
-	    auxlen)
-	    pm->ct = auxlen;
+	if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) {
+	    if (typeset_setwidth(cname, pm, ops, on, 0))
+		return NULL;
+	}
+	if (on & (PM_INTEGER | PM_EFLOAT | PM_FFLOAT)) {
+	    if (typeset_setbase(cname, pm, ops, on, 0))
+		return NULL;
+	}
 	if (!(pm->flags & (PM_ARRAY|PM_HASHED))) {
 	    if (pm->flags & PM_EXPORTED) {
 		if (!(pm->flags & PM_UNSET) && !pm->env && !value)
@@ -1960,7 +2023,8 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	}
 	tpm->old = pm->old;
 	tpm->level = pm->level;
-	tpm->ct = pm->ct;
+	tpm->base = pm->base;
+	tpm->width = pm->width;
 	if (pm->env)
 	    delenv(pm);
 	tpm->env = NULL;
@@ -1981,11 +2045,14 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	 * Final tweak: if we've turned on one of the flags with
 	 * numbers, we should use the appropriate integer.
 	 */
-	if (on & (PM_LEFT|PM_RIGHT_B|PM_RIGHT_Z|PM_INTEGER|
-		  PM_EFLOAT|PM_FFLOAT))
-	    pm->ct = auxlen;
-	else
-	    pm->ct = 0;
+	if (on & (PM_LEFT|PM_RIGHT_B|PM_RIGHT_Z)) {
+	    if (typeset_setwidth(cname, pm, ops, on, 1))
+		return NULL;
+	}
+	if (on & (PM_INTEGER|PM_EFLOAT|PM_FFLOAT)) {
+	    if (typeset_setbase(cname, pm, ops, on, 1))
+		return NULL;
+	}
     } else if ((subscript = strchr(pname, '['))) {
 	if (on & PM_READONLY) {
 	    zerrnam(cname,
@@ -2027,7 +2094,14 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	 */
 	pm = createparam(pname, on & ~PM_READONLY);
 	DPUTS(!pm, "BUG: parameter not created");
-	pm->ct = auxlen;
+	if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) {
+	    if (typeset_setwidth(cname, pm, ops, on, 0))
+		return NULL;
+	}
+	if (on & (PM_INTEGER | PM_EFLOAT | PM_FFLOAT)) {
+	    if (typeset_setbase(cname, pm, ops, on, 0))
+		return NULL;
+	}
     } else {
 	if (isident(pname))
 	    zerrnam(cname, "not valid in this context: %s", pname, 0);
@@ -2049,9 +2123,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	tdp->joinchar = joinchar;
 	tdp->arrptr = &altpm->u.arr;
 
-	pm->sets.cfn = tiedarrsetfn;
-	pm->gets.cfn = tiedarrgetfn;
-	pm->unsetfn = tiedarrunsetfn;
+	pm->gsu.s = &tiedarr_gsu;
 	pm->u.data = tdp;
     }
 
@@ -2075,20 +2147,20 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	 */
 	switch (PM_TYPE(pm->flags)) {
 	case PM_SCALAR:
-	    pm->sets.cfn(pm, ztrdup(""));
+	    pm->gsu.s->setfn(pm, ztrdup(""));
 	    break;
 	case PM_INTEGER:
-	    pm->sets.ifn(pm, 0);
+	    pm->gsu.i->setfn(pm, 0);
 	    break;
 	case PM_EFLOAT:
 	case PM_FFLOAT:
-	    pm->sets.ffn(pm, 0.0);
+	    pm->gsu.f->setfn(pm, 0.0);
 	    break;
 	case PM_ARRAY:
-	    pm->sets.afn(pm, mkarray(NULL));
+	    pm->gsu.a->setfn(pm, mkarray(NULL));
 	    break;
 	case PM_HASHED:
-	    pm->sets.hfn(pm, newparamtable(17, pm->nam));
+	    pm->gsu.h->setfn(pm, newparamtable(17, pm->nam));
 	    break;
 	}
     }
@@ -2118,7 +2190,7 @@ bin_typeset(char *name, char **argv, Options ops, int func)
     char *optstr = TYPESET_OPTSTR;
     int on = 0, off = 0, roff, bit = PM_ARRAY;
     int i;
-    int returnval = 0, printflags = 0, auxlen = 0;
+    int returnval = 0, printflags = 0;
 
     /* hash -f is really the builtin `functions' */
     if (OPT_ISSET(ops,'f'))
@@ -2134,43 +2206,27 @@ bin_typeset(char *name, char **argv, Options ops, int func)
 	    on |= bit;
 	else if (OPT_PLUS(ops,optval))
 	    off |= bit;
-	/*
-	 * There is only a single field in struct param for widths,
-	 * precisions and bases.  Until this gets fixed, we can therefore
-	 * bundle all optional arguments up into a single word.  You
-	 * may think this is very nasty, but then you should have seen the
-	 * code before option arguments were handled properly.
-	 */
-	if (OPT_HASARG(ops,optval)) {
-	    char *eptr, *arg = OPT_ARG(ops,optval);
-	    auxlen = (int)zstrtol(arg, &eptr, 10);
-	    if (*eptr) {
-		zwarnnam(name, "bad integer value: %s", arg, 0);
-		return 1;
-	    }
-	}
     }
     roff = off;
 
     /* Sanity checks on the options.  Remove conflicting options. */
     if (on & PM_FFLOAT) {
-	off |= PM_RIGHT_B | PM_LEFT | PM_RIGHT_Z | PM_UPPER | PM_ARRAY |
-	    PM_HASHED | PM_INTEGER | PM_EFLOAT;
+	off |= PM_UPPER | PM_ARRAY | PM_HASHED | PM_INTEGER | PM_EFLOAT;
 	/* Allow `float -F' to work even though float sets -E by default */
 	on &= ~PM_EFLOAT;
     }
     if (on & PM_EFLOAT)
-	off |= PM_RIGHT_B | PM_LEFT | PM_RIGHT_Z | PM_UPPER | PM_ARRAY |
-	    PM_HASHED | PM_INTEGER | PM_FFLOAT;
+	off |= PM_UPPER | PM_ARRAY | PM_HASHED | PM_INTEGER | PM_FFLOAT;
     if (on & PM_INTEGER)
-	off |= PM_RIGHT_B | PM_LEFT | PM_RIGHT_Z | PM_UPPER | PM_ARRAY |
-	    PM_HASHED | PM_EFLOAT | PM_FFLOAT;
-    if (on & PM_LEFT)
-	off |= PM_RIGHT_B | PM_INTEGER | PM_EFLOAT | PM_FFLOAT;
+	off |= PM_UPPER | PM_ARRAY | PM_HASHED | PM_EFLOAT | PM_FFLOAT;
+    /*
+     * Allowing -Z with -L is a feature: left justify, suppressing
+     * leading zeroes.
+     */
+    if (on & (PM_LEFT|PM_RIGHT_Z))
+	off |= PM_RIGHT_B;
     if (on & PM_RIGHT_B)
-	off |= PM_LEFT | PM_INTEGER | PM_EFLOAT | PM_FFLOAT;
-    if (on & PM_RIGHT_Z)
-	off |= PM_INTEGER | PM_EFLOAT | PM_FFLOAT;
+	off |= PM_LEFT | PM_RIGHT_Z;
     if (on & PM_UPPER)
 	off |= PM_LOWER;
     if (on & PM_LOWER)
@@ -2279,8 +2335,7 @@ bin_typeset(char *name, char **argv, Options ops, int func)
 				 (Param)paramtab->getnode(paramtab,
 							  asg->name),
 				 func, (on | PM_ARRAY) & ~PM_EXPORTED,
-				 off, roff, asg->value, NULL, ops, auxlen,
-				 0))) {
+				 off, roff, asg->value, NULL, ops, 0))) {
 	    unqueue_signals();
 	    return 1;
 	}
@@ -2292,7 +2347,7 @@ bin_typeset(char *name, char **argv, Options ops, int func)
 				(Param)paramtab->getnode(paramtab,
 							 asg0.name),
 				func, on, off, roff, asg0.value, apm,
-				ops, auxlen, joinchar))) {
+				ops, joinchar))) {
 	    if (oldval)
 		zsfree(oldval);
 	    unsetparam_pm(apm, 1, 1);
@@ -2367,7 +2422,7 @@ bin_typeset(char *name, char **argv, Options ops, int func)
 	    for (pmnode = firstnode(pmlist); pmnode; incnode(pmnode)) {
 		pm = (Param) getdata(pmnode);
 		if (!typeset_single(name, pm->nam, pm, func, on, off, roff,
-				    asg->value, NULL, ops, auxlen, 0))
+				    asg->value, NULL, ops, 0))
 		    returnval = 1;
 	    }
 	}
@@ -2382,7 +2437,7 @@ bin_typeset(char *name, char **argv, Options ops, int func)
 				     gethashnode2(paramtab, asg->name) :
 				     paramtab->getnode(paramtab, asg->name)),
 			    func, on, off, roff, asg->value, NULL,
-			    ops, auxlen, 0))
+			    ops, 0))
 	    returnval = 1;
     }
     unqueue_signals();
@@ -2681,7 +2736,7 @@ bin_unset(char *name, char **argv, Options ops, int func)
 	} else if (ss) {
 	    if (PM_TYPE(pm->flags) == PM_HASHED) {
 		HashTable tht = paramtab;
-		if ((paramtab = pm->gets.hfn(pm))) {
+		if ((paramtab = pm->gsu.h->getfn(pm))) {
 		    *--sse = 0;
 		    unsetparam(ss+1);
 		    *sse = ']';