Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: arithmetic evaluation for printf



This is the next instalment of printf, the main addition being the use
of math evaluation for numeric arguments. Negative widths and
precisions are now properly handled.

I've only been able to test it where a zlong is a long long. Also, the
POSIX compliance related issues I mentioned last week apply. Should I
have used zhalloc for the char spec[11] and int flags[5] variables at
all?

And don't bother pointing out the resulting test failure in B03 - I
forgot the changed test file when I put this on a floppy at home
yesterday.

Oliver

Index: Doc/Zsh/builtins.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/builtins.yo,v
retrieving revision 1.38
diff -u -r1.38 builtins.yo
--- Doc/Zsh/builtins.yo	2001/10/08 10:47:47	1.38
+++ Doc/Zsh/builtins.yo	2001/10/15 11:13:21
@@ -732,8 +732,10 @@
 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
Index: Src/builtin.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/builtin.c,v
retrieving revision 1.57
diff -u -r1.57 builtin.c
--- Src/builtin.c	2001/10/08 10:47:47	1.57
+++ Src/builtin.c	2001/10/15 11:13:22
@@ -2883,32 +2883,27 @@
 /* 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 @@
     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 @@
     }
     
     /* printf style output */
+    *spec='%';
     do {
 	for (c = fmt;c-fmt < flen;c++) {
 	    if (*c != '%') {
@@ -3112,34 +3108,48 @@
 		++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 @@
 		break;
 	    case 'q':
 		stringval = *args ? bslashquote(*args++, NULL, 0) : &nullstr;
-		*c = 's';
+		*d = 's';
 		print_val(stringval);
 		break;
 	    case 'd':
@@ -3186,50 +3196,65 @@
 		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 */

_____________________________________________________________________
This message has been checked for all known viruses by the 
MessageLabs Virus Scanning Service. For further information visit
http://www.messagelabs.com/stats.asp



Messages sorted by: Reverse Date, Date, Thread, Author