From owner-freebsd-current Fri Jun 23 10: 6:23 2000 Delivered-To: freebsd-current@freebsd.org Received: from mout0.freenet.de (mout0.freenet.de [194.97.50.131]) by hub.freebsd.org (Postfix) with ESMTP id D050237C421; Fri, 23 Jun 2000 10:06:11 -0700 (PDT) (envelope-from se@freebsd.org) Received: from [194.97.50.136] (helo=mx3.freenet.de) by mout0.freenet.de with esmtp (Exim 3.14 #3) id 135Wu8-0000zp-00; Fri, 23 Jun 2000 19:06:08 +0200 Received: from [213.6.107.5] (helo=StefanEsser.FreeBSD.org) by mx3.freenet.de with esmtp (Exim 3.14 #3) id 135Wu5-0005C3-00; Fri, 23 Jun 2000 19:06:07 +0200 Received: by StefanEsser.FreeBSD.org (Postfix, from userid 200) id 6257CC23; Fri, 23 Jun 2000 19:05:14 +0200 (CEST) Date: Fri, 23 Jun 2000 19:05:14 +0200 From: Stefan Esser To: FreeBSD-current@FreeBSD.org Cc: Stefan Esser Subject: Extend "test" and "expr" to 64 bit integers Message-ID: <20000623190514.A3633@StefanEsser.FreeBSD.org> Reply-To: Stefan Esser Mail-Followup-To: Stefan Esser , FreeBSD-current@FreeBSD.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.2i Sender: owner-freebsd-current@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG These simple changes make "test" and "expr" operate on 64 bit integers (tested on i86 only, but I plan to test them on Alpha next week). Motivation: I recently found a third party shell skript, which used "test" to verify the (numeric) match of a checksum. The algorithm worked on unsigned integers, and thus "test" failed when the checksum happened to come out > MAXINT ... Interestingly, the built in test command in Bash seemed to work, but when I performed a few tests, I've got the impression, that bash just silently fails! (Try "test 3000000000 -lt 3000000001" and "test 3000000000 -gt 3000000001" in Bash ... :) Obvious cost of my proposed changes is a little processing overhead (diminishing if compared to the cycles spent loading test or expr). But there are other issues that I'm worried about: 1) I choose "quad_t" for long integers. Is this a good choice ? In the kernel I'd use int64_t, but I'm not sure what is most appropriate here. 2) There is a new dependency on in test.c (for any of our 64 bit integer types). 3) The changes to "expr" rely on 32 bit integers being promoted to 64 bit integers in function calls (actually only invocations of make_integer().) This is in contrast to the old code, which strictly conformed to K&R C. I can fix the need for an implicit conversion by adding casts in all invocations of make_intereger(). Any opinios ? What does Posix say about these programs ? Regards, STefan Index: /usr/src/bin/test/test.c =================================================================== RCS file: /usr/cvs/src/bin/test/test.c,v retrieving revision 1.29 diff -u -2 -r1.29 test.c --- /usr/src/bin/test/test.c 1999/12/28 09:34:57 1.29 +++ /usr/src/bin/test/test.c 2000/06/23 15:56:26 @@ -154,4 +154,6 @@ static int isoperand __P((void)); static int getn __P((const char *)); +static quad_t getq __P((const char *)); +static int intcmp __P((const char *, const char *)); static int newerf __P((const char *, const char *)); static int olderf __P((const char *, const char *)); @@ -299,15 +301,15 @@ return strcmp(opnd1, opnd2) > 0; case INTEQ: - return getn(opnd1) == getn(opnd2); + return intcmp(opnd1, opnd2) == 0; case INTNE: - return getn(opnd1) != getn(opnd2); + return intcmp(opnd1, opnd2) != 0; case INTGE: - return getn(opnd1) >= getn(opnd2); + return intcmp(opnd1, opnd2) >= 0; case INTGT: - return getn(opnd1) > getn(opnd2); + return intcmp(opnd1, opnd2) > 0; case INTLE: - return getn(opnd1) <= getn(opnd2); + return intcmp(opnd1, opnd2) <= 0; case INTLT: - return getn(opnd1) < getn(opnd2); + return intcmp(opnd1, opnd2) < 0; case FILNT: return newerf (opnd1, opnd2); @@ -442,4 +444,46 @@ return (int) r; +} + +/* atoi with error detection and 64 bit range */ +static quad_t +getq(s) + const char *s; +{ + char *p; + quad_t r; + + errno = 0; + r = strtoq(s, &p, 10); + + if (errno != 0) + errx(2, "%s: out of range", s); + + while (isspace((unsigned char)*p)) + p++; + + if (*p) + errx(2, "%s: bad number", s); + + return r; +} + +static int +intcmp (s1, s2) + const char *s1, *s2; +{ + quad_t q1, q2; + + + q1 = getq(s1); + q2 = getq(s2); + + if (q1 > q2) + return 1; + + if (q1 < q2) + return -1; + + return 0; } Index: /usr/src/bin/expr/expr.y =================================================================== RCS file: /usr/cvs/src/bin/expr/expr.y,v retrieving revision 1.14 diff -u -2 -r1.14 expr.y --- /usr/src/bin/expr/expr.y 1999/08/27 23:14:22 1.14 +++ /usr/src/bin/expr/expr.y 2000/06/23 16:21:13 @@ -14,5 +14,7 @@ #include #include - +#include +#include + enum valtype { integer, numeric_string, string @@ -23,5 +25,5 @@ union { char *s; - int i; + quad_t i; } u; } ; @@ -88,5 +90,5 @@ struct val * make_integer (i) -int i; +quad_t i; { struct val *vp; @@ -140,9 +142,9 @@ -int +quad_t to_integer (vp) struct val *vp; { - int i; + quad_t i; if (vp->type == integer) @@ -153,5 +155,5 @@ /* vp->type == numeric_string, make it numeric */ - i = atoi(vp->u.s); + i = strtoq(vp->u.s, (char**)NULL, 10); free (vp->u.s); vp->u.i = i; @@ -174,5 +176,5 @@ } - sprintf (tmp, "%d", vp->u.i); + sprintf (tmp, "%lld", vp->u.i); vp->type = string; vp->u.s = tmp; @@ -240,5 +242,5 @@ if (result->type == integer) - printf ("%d\n", result->u.i); + printf ("%lld\n", result->u.i); else printf ("%s\n", result->u.s); @@ -496,7 +498,4 @@ } -#include -#include - struct val * op_colon (a, b) To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message