From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10740 invoked from network); 15 Oct 2001 11:25:29 -0000 Received: from unknown (HELO sunsite.dk) (130.225.247.90) by ns1.primenet.com.au with SMTP; 15 Oct 2001 11:25:29 -0000 Received: (qmail 18759 invoked by alias); 15 Oct 2001 11:25:22 -0000 Mailing-List: contact zsh-workers-help@sunsite.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 16042 Received: (qmail 18739 invoked from network); 15 Oct 2001 11:25:20 -0000 X-VirusChecked: Checked Sender: kiddleo@cav.logica.co.uk Message-ID: <3BCAC666.9DC9EF09@yahoo.co.uk> Date: Mon, 15 Oct 2001 12:20:06 +0100 From: Oliver Kiddle X-Mailer: Mozilla 4.77 [en] (X11; U; Linux 2.2.15 i686) X-Accept-Language: en MIME-Version: 1.0 To: zsh-workers@sunsite.dk Subject: PATCH: arithmetic evaluation for printf Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit 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