about summary refs log tree commit diff
path: root/Src/builtin.c
diff options
context:
space:
mode:
authorOliver Kiddle <opk@users.sourceforge.net>2001-10-15 11:34:27 +0000
committerOliver Kiddle <opk@users.sourceforge.net>2001-10-15 11:34:27 +0000
commit577ebe0b8ad4289221be0b4bc2bb03aea8477cfc (patch)
tree7fa4504c7048b90f38a187009c1813bbcac144c1 /Src/builtin.c
parent0e6f26551664f4aa6fa5b4bb5ae0638930f8cf0f (diff)
downloadzsh-577ebe0b8ad4289221be0b4bc2bb03aea8477cfc.tar.gz
zsh-577ebe0b8ad4289221be0b4bc2bb03aea8477cfc.tar.xz
zsh-577ebe0b8ad4289221be0b4bc2bb03aea8477cfc.zip
use arithmetic evaluation for numeric arguments to printf (16042)
Diffstat (limited to 'Src/builtin.c')
-rw-r--r--Src/builtin.c129
1 files changed, 77 insertions, 52 deletions
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 */