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.c134
1 files changed, 97 insertions, 37 deletions
diff --git a/Src/builtin.c b/Src/builtin.c
index 113c5931e..038e1a199 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2892,10 +2892,11 @@ mod_export LinkList bufstack;
 int
 bin_print(char *name, char **args, char *ops, int func)
 {
-    int flen, width, prec, type, argc, n, nnl = 0, ret = 0;
+    int flen, width, prec, type, argc, n, narg;
+    int nnl = 0, ret = 0, maxarg = 0;
     int flags[5], *len;
     char *start, *endptr, *c, *d, *flag, spec[11], *fmt = NULL;
-    char **first, *flagch = "0+- #", save, nullstr = '\0';
+    char **first, *curarg, *flagch = "0+- #", save, nullstr = '\0';
     zlong count = 0;
     FILE *fout = stdout;
 
@@ -3095,6 +3096,11 @@ bin_print(char *name, char **args, char *ops, int func)
     /* printf style output */
     *spec='%';
     do {
+    	if (maxarg) {
+	    first += maxarg;
+	    argc -= maxarg;
+    	    maxarg = 0;
+	}
 	for (c = fmt;c-fmt < flen;c++) {
 	    if (*c != '%') {
 		putc(*c, fout);
@@ -3111,11 +3117,29 @@ bin_print(char *name, char **args, char *ops, int func)
 
 	    type = prec = -1;
 	    width = 0;
+	    curarg = NULL;
 	    d = spec + 1;
 
+	    if (*c >= '1' && *c <= '9') {
+	    	narg = strtoul(c, &endptr, 0);
+		if (*endptr == '$') {
+		    c = endptr + 1;
+		    DPUTS(narg <= 0, "specified zero or negative arg");
+		    if (narg > argc) {
+		    	zwarnnam(name, "%d: argument specifier out of range",
+			    0, narg);
+			return 1;
+		    } else {
+		    	if (narg > maxarg) maxarg = narg;
+		    	curarg = *(first + narg - 1);
+		    }
+		}
+	    }
+		    
+	    
 	    /* copy only one of each flag as spec has finite size */
 	    memset(flags, 0, sizeof(flags));
-	    while (flag = strchr(flagch, *c)) {
+	    while ((flag = strchr(flagch, *c))) {
 	    	if (!flags[flag - flagch]) {
 	    	    flags[flag - flagch] = 1;
 		    *d++ = *c;
@@ -3123,28 +3147,60 @@ bin_print(char *name, char **args, char *ops, int func)
 	    	c++;
 	    }
 
-	    if (*c == '*') {
-		if (*args) width = (int)mathevali(*args++);
-		if (errflag) {
-	    	    errflag = 0;
-		    ret = 1;
-		}
-		c++;
-	    } else if (idigit(*c)) {
+	    if (idigit(*c)) {
 		width = strtoul(c, &endptr, 0);
 		c = endptr;
+	    } else if (*c == '*') {
+		if (idigit(*++c)) {
+		    narg = strtoul(c, &endptr, 0);
+		    if (*endptr == '$') {
+		    	c = endptr + 1;
+			if (narg > argc || narg <= 0) {
+		    	    zwarnnam(name,
+			    	"%d: argument specifier out of range",
+				0, narg);
+			    return 1;
+			} else {
+		    	    if (narg > maxarg) maxarg = narg;
+		    	    args = first + narg - 1;
+			}
+		    }
+		}
+		if (*args) {
+		    width = (int)mathevali(*args++);
+		    if (errflag) {
+			errflag = 0;
+			ret = 1;
+		    }
+		}
 	    }
 	    *d++ = '*';
 
 	    if (*c == '.') {
-		c++;
-		if (*c == '*') {
-		    prec = (*args) ? (int)mathevali(*args++) : 0;
-		    if (errflag) {
-	    	    	errflag = 0;
-			ret = 1;
+		if (*++c == '*') {
+		    if (idigit(*++c)) {
+			narg = strtoul(c, &endptr, 0);
+			if (*endptr == '$') {
+			    c = endptr + 1;
+			    if (narg > argc || narg <= 0) {
+		    		zwarnnam(name,
+				    "%d: argument specifier out of range",
+				    0, narg);
+				return 1;
+			    } else {
+		    		if (narg > maxarg) maxarg = narg;
+		    		args = first + narg - 1;
+			    }
+			}
+		    }
+		    
+		    if (*args) {
+			prec = (int)mathevali(*args++);
+			if (errflag) {
+			    errflag = 0;
+			    ret = 1;
+			}
 		    }
-		    c++;
 		} else if (idigit(*c)) {
 		    prec = strtoul(c, &endptr, 0);
 		    c = endptr;
@@ -3155,30 +3211,30 @@ bin_print(char *name, char **args, char *ops, int func)
 	    /* ignore any size modifier */
 	    if (*c == 'l' || *c == 'L' || *c == 'h') c++;
 
+	    if (!curarg && *args) curarg = *args++;
 	    d[1] = '\0';
 	    switch (*d = *c) {
 	    case 'c':
-		if (*args) {
-		    intval = **args;
-		    args++;
+		if (curarg) {
+		    intval = *curarg;
 		} else
 		    intval = 0;
 		print_val(intval);
 		break;
 	    case 's':
-		stringval = *args ? *args++ : &nullstr;
+		stringval = curarg ? curarg : &nullstr;
 		print_val(stringval);
 		break;
 	    case 'b':
-		if (*args) {
+		if (curarg) {
 		    int l;
-		    char *b = getkeystring(*args++, &l, ops['b'] ? 2 : 0, &nnl);
+		    char *b = getkeystring(curarg, &l, ops['b'] ? 2 : 0, &nnl);
 		    fwrite(b, l, 1, fout);
 		    count += l;
 		}
 		break;
 	    case 'q':
-		stringval = *args ? bslashquote(*args++, NULL, 0) : &nullstr;
+		stringval = curarg ? bslashquote(curarg, NULL, 0) : &nullstr;
 		*d = 's';
 		print_val(stringval);
 		break;
@@ -3200,7 +3256,7 @@ bin_print(char *name, char **args, char *ops, int func)
 		type=3;
 		break;
 	    case 'n':
-		if (*args) setiparam(*args++, count);
+		if (curarg) setiparam(curarg, count);
 		break;
 	    default:
 	        if (*c) {
@@ -3208,20 +3264,21 @@ bin_print(char *name, char **args, char *ops, int func)
 	            c[1] = '\0';
 		}
 		zwarnnam(name, "%s: invalid directive", start, 0);
-		ret = 1;
 		if (*c) c[1] = save;
+		if (fout != stdout)
+		    fclose(fout);
+		return 1;
 	    }
 
 	    if (type > 0) {
-		if (*args && (**args == '\'' || **args == '"' )) {
+		if (curarg && (*curarg == '\'' || *curarg == '"' )) {
 		    if (type == 2) {
-			doubleval = (unsigned char)(*args)[1];
+			doubleval = (unsigned char)curarg[1];
 			print_val(doubleval);
 		    } else {
-			intval = (unsigned char)(*args)[1];
+			intval = (unsigned char)curarg[1];
 			print_val(intval);
 		    }
-		    args++;
 		} else {
 		    switch (type) {
 		    case 1:
@@ -3229,7 +3286,7 @@ bin_print(char *name, char **args, char *ops, int func)
  		    	*d++ = 'l';
 #endif
 		    	*d++ = 'l', *d++ = *c, *d = '\0';
-			zlongval = (*args) ? mathevali(*args++) : 0;
+			zlongval = (curarg) ? mathevali(curarg) : 0;
 			if (errflag) {
 			    zlongval = 0;
 			    errflag = 0;
@@ -3238,8 +3295,8 @@ bin_print(char *name, char **args, char *ops, int func)
 			print_val(zlongval)
 			break;
 		    case 2:
-			if (*args) {
-			    mnumval = matheval(*args++);
+			if (curarg) {
+			    mnumval = matheval(curarg);
 			    doubleval = (mnumval.type & MN_FLOAT) ?
 			    	mnumval.u.d : (double)mnumval.u.l;
 			} else doubleval = 0;
@@ -3255,9 +3312,9 @@ bin_print(char *name, char **args, char *ops, int func)
  		    	*d++ = 'l';
 #endif
 		    	*d++ = 'l', *d++ = *c, *d = '\0';
-			zulongval = (*args) ? mathevali(*args++) : 0;
+			zulongval = (curarg) ? mathevali(curarg) : 0;
 			if (errflag) {
-			    doubleval = 0;
+			    zulongval = 0;
 			    errflag = 0;
 			    ret = 1;
 			}
@@ -3265,10 +3322,13 @@ bin_print(char *name, char **args, char *ops, int func)
 		    }
 		}
 	    }
+	    if (maxarg && (args - first > maxarg))
+	    	maxarg = args - first;
 	}
 
+    	if (maxarg) args = first + maxarg;
     /* if there are remaining args, reuse format string */
-    } while (*args && args != first);
+    } while (*args && args != first && !ops['r']);
 
     if (fout != stdout)
 	fclose(fout);