zsh-workers
 help / color / mirror / code / Atom feed
* PATCH: arithmetic evaluation for printf
@ 2001-10-15 11:20 Oliver Kiddle
  2001-10-16 11:09 ` Oliver Kiddle
  0 siblings, 1 reply; 2+ messages in thread
From: Oliver Kiddle @ 2001-10-15 11:20 UTC (permalink / raw)
  To: zsh-workers

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


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: PATCH: arithmetic evaluation for printf
  2001-10-15 11:20 PATCH: arithmetic evaluation for printf Oliver Kiddle
@ 2001-10-16 11:09 ` Oliver Kiddle
  0 siblings, 0 replies; 2+ messages in thread
From: Oliver Kiddle @ 2001-10-16 11:09 UTC (permalink / raw)
  To: zsh-workers

I wrote:
> 
> I've only been able to test it where a zlong is a long long.

It is fine where zlong is a long and where long is 64 bits such as the
alpha on sourceforge. Problems might arise if the 64 bit type is
anything else but I can't see anything in zshconfig.ac to indicate that
that is yet the case anywhere (it only tries long and long long).

> 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.

The changed test file is below. I also forgot to make it return 1 after
math errors so that fix is also below. The comment above bslashquote()
in utils.c was incomplete so even though I'm ditching the changes to
that function, I'll bring the comment up-to-date.

Oliver

Index: Src/builtin.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/builtin.c,v
retrieving revision 1.58
diff -u -r1.58 builtin.c
--- Src/builtin.c	2001/10/15 11:34:27	1.58
+++ Src/builtin.c	2001/10/16 11:05:32
@@ -3125,6 +3125,10 @@
 
 	    if (*c == '*') {
 		if (*args) width = (int)mathevali(*args++);
+		if (errflag) {
+	    	    errflag = 0;
+		    ret = 1;
+		}
 		c++;
 	    } else if (idigit(*c)) {
 		width = strtoul(c, &endptr, 0);
@@ -3136,6 +3140,10 @@
 		c++;
 		if (*c == '*') {
 		    prec = (*args) ? (int)mathevali(*args++) : 0;
+		    if (errflag) {
+	    	    	errflag = 0;
+			ret = 1;
+		    }
 		    c++;
 		} else if (idigit(*c)) {
 		    prec = strtoul(c, &endptr, 0);
@@ -3147,7 +3155,6 @@
 	    /* ignore any size modifier */
 	    if (*c == 'l' || *c == 'L' || *c == 'h') c++;
 
-	    errflag = 0;
 	    d[1] = '\0';
 	    switch (*d = *c) {
 	    case 'c':
@@ -3226,6 +3233,7 @@
 			if (errflag) {
 			    zlongval = 0;
 			    errflag = 0;
+			    ret = 1;
 			}
 			print_val(zlongval)
 			break;
@@ -3238,11 +3246,12 @@
 			if (errflag) {
 			    doubleval = 0;
 			    errflag = 0;
+			    ret = 1;
 			}
 			print_val(doubleval)
 			break;
 		    case 3:
-#ifdef ZSH_64_BIT_TYPE
+#ifdef ZSH_64_BIT_UTYPE
  		    	*d++ = 'l';
 #endif
 		    	*d++ = 'l', *d++ = *c, *d = '\0';
@@ -3250,6 +3259,7 @@
 			if (errflag) {
 			    doubleval = 0;
 			    errflag = 0;
+			    ret = 1;
 			}
 			print_val(zulongval)
 		    }
Index: Src/utils.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/utils.c,v
retrieving revision 1.35
diff -u -r1.35 utils.c
--- Src/utils.c	2001/06/15 23:55:08	1.35
+++ Src/utils.c	2001/10/16 11:05:32
@@ -2929,8 +2929,9 @@
  * pointer it points to may point to a position in s and in e the position  *
  * of the corresponding character in the quoted string is returned.         *
  * The last argument should be zero if this is to be used outside a string, *
- * one if it is to be quoted for the inside of a single quoted string, and  *
- * two if it is for the inside of  double quoted string.                    *
+ * one if it is to be quoted for the inside of a single quoted string,      *
+ * two if it is for the inside of a double quoted string, and               *
+ * three if it is for the inside of a posix quoted string.                  *
  * The string may be metafied and contain tokens.                           */
 
 /**/
Index: Test/B03print.ztst
===================================================================
RCS file: /cvsroot/zsh/zsh/Test/B03print.ztst,v
retrieving revision 1.1
diff -u -r1.1 B03print.ztst
--- Test/B03print.ztst	2001/10/08 10:47:47	1.1
+++ Test/B03print.ztst	2001/10/16 11:05:32
@@ -78,6 +78,10 @@
 0:initial quote to get numeric value of character with double
 >6.6E+01
 
+ printf '%x\n' $(printf '"\xf0')
+0:numeric value of high numbered character
+>f0
+
 # code will probably be changed to print the literal `%s' in this case
  printf '\x25s\n' arg
 0:using \x25 to introduce a format specifier
@@ -95,24 +99,15 @@
 0:width/precision specified in arguments
 > 10.20
 
- printf '%d\n' 3000000000
-1d:out of range numeric result
-?(eval):printf:1: `3000000000' arithmetic overflow
-
- printf '%G\n' letters
-1:non numeric argument
-?(eval):printf:1: `letters' expected numeric value
->0
-
- print -f '%d\n' 2e4
-1:letters in numeric argument
-?(eval):print:1: `2e4' not completely converted
->2
-
  printf '%z'
-1:test invalid directive
+1:use of invalid directive
 ?(eval):printf:1: %z: invalid directive
 
+ printf '%d\n' 3a
+1:bad arithmetic expression
+?(eval):1: bad math expression: operator expected at `a'
+>0
+
  print -m -f 'format - %s.\n' 'z' a b c
 0:format not printed if no arguments left after -m removal
 
@@ -133,3 +128,15 @@
 >one	a:0x1%
 >two	b:0x2%
 >three	c:0x3%
+
+ printf '%0+- #-08.5dx\n' 123
+0:maximal length format specification
+>+00123  x
+
+ printf '%*smorning\n' -5 good
+0:negative width specified
+>good morning
+
+ printf '%.*g\n' -1 .1
+0:negative precision specified
+>0.1

_____________________________________________________________________
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


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2001-10-16 11:11 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-10-15 11:20 PATCH: arithmetic evaluation for printf Oliver Kiddle
2001-10-16 11:09 ` Oliver Kiddle

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).