about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--Doc/Zsh/builtins.yo6
-rw-r--r--Src/builtin.c129
3 files changed, 87 insertions, 55 deletions
diff --git a/ChangeLog b/ChangeLog
index fa5028100..3ba11d725 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2001-10-15  Oliver Kiddle  <opk@zsh.org>
+
+	* 16042: Src/builtin.c, Doc/Zsh/builtins.yo: use arithmetic
+	evaluation for numeric arguments to printf
+
 2001-10-15  Sven Wischnowsky  <wischnow@zsh.org>
 
 	* Bart: 16038 and 16041: Src/cond.c, Src/loop.c: for caching of
@@ -35,7 +40,7 @@
 
 2001-10-10  Oliver Kiddle  <opk@zsh.org>
 
-	* 16xxx: acconfig.h, zshconfig.ac, Etc/MACHINES,
+	* 16018: acconfig.h, zshconfig.ac, Etc/MACHINES,
 	Test/C02cond.ztst: allow dynamic loading to work on MacOS X
 	if the dlcompat library is installed.
 
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 8d23fc175..91df46c06 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -732,8 +732,10 @@ recognised and `tt(%q)' can be used to quote the argument in such a way
 that allows it to be reused as shell input. With the numeric format
 specifiers, if the corresponding argument starts with a quote character,
 the numeric value of the following character is used as the number to
-print. With `tt(%n)', the corresponding argument is taken as an identifier
-which is created as an integer parameter.
+print otherwise the argument is evaluated as an arithmetic expression. See
+noderef(Arithmetic Evaluation) for a description of arithmetic
+expressions. With `tt(%n)', the corresponding argument is taken as an
+identifier which is created as an integer parameter.
 
 If arguments remain unused after formatting, the format string is reused
 until all arguments have been consumed. If more arguments are required by
diff --git a/Src/builtin.c b/Src/builtin.c
index a04b57163..8b05759b7 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2883,32 +2883,27 @@ mod_export LinkList bufstack;
 /* echo, print, printf, pushln */
 
 #define print_val(VAL) \
-  if (width >= 0) { \
-      if (prec >= 0) \
-	  count += fprintf(fout, start, width, prec, VAL); \
-      else \
-	  count += fprintf(fout, start, width, VAL); \
-  } else { \
-      if (prec >= 0) \
-	  count += fprintf(fout, start, prec, VAL); \
-      else \
-	  count += fprintf(fout, start, VAL); \
-  }
+    if (prec >= 0) \
+	count += fprintf(fout, spec, width, prec, VAL); \
+    else \
+	count += fprintf(fout, spec, width, VAL);
 
 /**/
 int
 bin_print(char *name, char **args, char *ops, int func)
 {
     int flen, width, prec, type, argc, n, nnl = 0, ret = 0;
-    int *len;
-    char *start, *endptr, *c, *fmt = NULL;
-    char **first, nullstr = '\0', save = '\0';
+    int flags[5], *len;
+    char *start, *endptr, *c, *d, *flag, spec[11], *fmt = NULL;
+    char **first, *flagch = "0+- #", save, nullstr = '\0';
     zlong count = 0;
     FILE *fout = stdout;
 
+    mnumber mnumval;
     double doubleval;
     int intval;
-    unsigned int uintval;
+    zlong zlongval;
+    zulong zulongval;
     char *stringval;
 
     if (func == BIN_PRINTF) auxdata = *args++;
@@ -2940,7 +2935,7 @@ bin_print(char *name, char **args, char *ops, int func)
     len = (int *) hcalloc(argc * sizeof(int));
     for(n = 0; n < argc; n++) {
 	/* first \ sequences */
-	if (fmt || !ops['e'] && (ops['R'] || ops['r'] || ops['E']))
+	if (fmt || (!ops['e'] && (ops['R'] || ops['r'] || ops['E'])))
 	    unmetafy(args[n], &len[n]);
 	else
 	    args[n] = getkeystring(args[n], &len[n], ops['b'] ? 2 :
@@ -3098,6 +3093,7 @@ bin_print(char *name, char **args, char *ops, int func)
     }
     
     /* printf style output */
+    *spec='%';
     do {
 	for (c = fmt;c-fmt < flen;c++) {
 	    if (*c != '%') {
@@ -3112,34 +3108,48 @@ bin_print(char *name, char **args, char *ops, int func)
 		++count;
 		continue;
 	    }
-	    type = prec = width = -1;
 
-	    if (strchr("+- #", *c)) c++;
+	    type = prec = -1;
+	    width = 0;
+	    d = spec + 1;
+
+	    /* copy only one of each flag as spec has finite size */
+	    memset(flags, 0, sizeof(flags));
+	    while (flag = strchr(flagch, *c)) {
+	    	if (!flags[flag - flagch]) {
+	    	    flags[flag - flagch] = 1;
+		    *d++ = *c;
+		}
+	    	c++;
+	    }
 
 	    if (*c == '*') {
-		width = (*args) ? strtoul(*args++, NULL, 0) : 0;
+		if (*args) width = (int)mathevali(*args++);
 		c++;
-	    } else {
-		while (idigit(*c)) c++;
+	    } else if (idigit(*c)) {
+		width = strtoul(c, &endptr, 0);
+		c = endptr;
 	    }
+	    *d++ = '*';
 
 	    if (*c == '.') {
 		c++;
 		if (*c == '*') {
-		    prec = (*args) ? strtoul(*args++, NULL, 0) : 0;
+		    prec = (*args) ? (int)mathevali(*args++) : 0;
 		    c++;
-		} else {
-		    while (idigit(*c)) c++;
+		} else if (idigit(*c)) {
+		    prec = strtoul(c, &endptr, 0);
+		    c = endptr;
 		}
+		if (prec >= 0) *d++ = '.', *d++ = '*';
 	    }
 
+	    /* ignore any size modifier */
 	    if (*c == 'l' || *c == 'L' || *c == 'h') c++;
 
-	    if (*c) {
-		save = c[1];
-		c[1] = '\0';
-	    }
-	    switch (*c) {
+	    errflag = 0;
+	    d[1] = '\0';
+	    switch (*d = *c) {
 	    case 'c':
 		if (*args) {
 		    intval = **args;
@@ -3162,7 +3172,7 @@ bin_print(char *name, char **args, char *ops, int func)
 		break;
 	    case 'q':
 		stringval = *args ? bslashquote(*args++, NULL, 0) : &nullstr;
-		*c = 's';
+		*d = 's';
 		print_val(stringval);
 		break;
 	    case 'd':
@@ -3186,50 +3196,65 @@ bin_print(char *name, char **args, char *ops, int func)
 		if (*args) setiparam(*args++, count);
 		break;
 	    default:
-		zerrnam(name, "%s: invalid directive", start, 0);
+	        if (*c) {
+		    save = c[1];
+	            c[1] = '\0';
+		}
+		zwarnnam(name, "%s: invalid directive", start, 0);
 		ret = 1;
+		if (*c) c[1] = save;
 	    }
 
 	    if (type > 0) {
 		if (*args && (**args == '\'' || **args == '"' )) {
 		    if (type == 2) {
-			doubleval = (*args)[1];
+			doubleval = (unsigned char)(*args)[1];
 			print_val(doubleval);
 		    } else {
-			intval = (*args)[1];
+			intval = (unsigned char)(*args)[1];
 			print_val(intval);
 		    }
 		    args++;
 		} else {
 		    switch (type) {
 		    case 1:
-			intval = (*args) ? strtol(*args, &endptr, 0) : 0;
-			print_val(intval);
+#ifdef ZSH_64_BIT_TYPE
+ 		    	*d++ = 'l';
+#endif
+		    	*d++ = 'l', *d++ = *c, *d = '\0';
+			zlongval = (*args) ? mathevali(*args++) : 0;
+			if (errflag) {
+			    zlongval = 0;
+			    errflag = 0;
+			}
+			print_val(zlongval)
 			break;
 		    case 2:
-			doubleval = (*args) ? strtod(*args, &endptr) : 0;
-			print_val(doubleval);
+			if (*args) {
+			    mnumval = matheval(*args++);
+			    doubleval = (mnumval.type & MN_FLOAT) ?
+			    	mnumval.u.d : (double)mnumval.u.l;
+			} else doubleval = 0;
+			if (errflag) {
+			    doubleval = 0;
+			    errflag = 0;
+			}
+			print_val(doubleval)
 			break;
 		    case 3:
-			uintval = (*args) ? strtoul(*args, &endptr, 0) : 0;
-			print_val(uintval);
-		    }
-		    if (*args) {
-			if (errno == ERANGE) {
-			    zerrnam(name, "`%s' arithmetic overflow", *args, 0);
-			    ret = 1;
-			} else if (**args && endptr == *args) {
-			    zerrnam(name, "`%s' expected numeric value", endptr, 0);
-			    ret = 1;
-			} else if (*endptr) {
-			    zerrnam(name, "`%s' not completely converted", *args, 0);
-			    ret = 1;
+#ifdef ZSH_64_BIT_TYPE
+ 		    	*d++ = 'l';
+#endif
+		    	*d++ = 'l', *d++ = *c, *d = '\0';
+			zulongval = (*args) ? mathevali(*args++) : 0;
+			if (errflag) {
+			    doubleval = 0;
+			    errflag = 0;
 			}
-			args++;
+			print_val(zulongval)
 		    }
 		}
 	    }
-	    if (*c) c[1] = save;
 	}
 
     /* if there are remaining args, reuse format string */