Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 23 Jun 2000 19:05:14 +0200
From:      Stefan Esser <se@freebsd.org>
To:        FreeBSD-current@FreeBSD.org
Cc:        Stefan Esser <se@freebsd.org>
Subject:   Extend "test" and "expr" to 64 bit integers
Message-ID:  <20000623190514.A3633@StefanEsser.FreeBSD.org>

next in thread | raw e-mail | index | archive | help
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 <sys/types.h> 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 <ctype.h>
 #include <err.h>
-  
+#include <sys/types.h>  
+#include <regex.h>
+
 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 <sys/types.h>
-#include <regex.h>
-
 struct val *
 op_colon (a, b)




To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20000623190514.A3633>