Module Name:    src
Committed By:   martin
Date:           Sun Jul 15 10:47:54 UTC 2018

Modified Files:
        src/usr.bin/units [netbsd-7]: units.c

Log Message:
Pull up following revision(s) (requested by dholland in ticket #1620):

        usr.bin/units/units.c: revision 1.26,1.27

Improve the parser. Now we understand negative exponents; fixes PR 50768.

Also handle negative numbers better in general (don't randomly drop
the sign in a number of cases) and don't choke on exponents > 9.

This commit alters the meaning of a few previously valid but marginal
inputs (e.g. "3 foot-5 pound" is now treated as "3*-5 foot-pound"
rather than "3*5 foot-pound"; if you want the latter insert another
space) but corrects obviously wrong handling of many more.

 -

Improve previous slightly; while we accept e.g. "meter2" to mean "meter^2",
don't allow "meter-2" to be interpreted as "meter^-2" as that's very
confusing.


To generate a diff of this commit:
cvs rdiff -u -r1.25 -r1.25.4.1 src/usr.bin/units/units.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/units/units.c
diff -u src/usr.bin/units/units.c:1.25 src/usr.bin/units/units.c:1.25.4.1
--- src/usr.bin/units/units.c:1.25	Tue Jan  7 02:07:09 2014
+++ src/usr.bin/units/units.c	Sun Jul 15 10:47:54 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: units.c,v 1.25 2014/01/07 02:07:09 joerg Exp $	*/
+/*	$NetBSD: units.c,v 1.25.4.1 2018/07/15 10:47:54 martin Exp $	*/
 
 /*
  * units.c   Copyright (c) 1993 by Adrian Mariano (adr...@cam.cornell.edu)
@@ -17,6 +17,7 @@
  * improvements you might make to this program.
  */
 
+#include <assert.h>
 #include <ctype.h>
 #include <err.h>
 #include <float.h>
@@ -344,14 +345,41 @@ addunit(struct unittype * theunit, const
 	char *scratch, *savescr;
 	char *item;
 	char *divider, *slash;
+	char *minus;
+	size_t pos, len;
 	int doingtop;
 
 	savescr = scratch = dupstr(toadd);
-	for (slash = scratch + 1; *slash; slash++)
-		if (*slash == '-' &&
-		    (tolower((unsigned char)*(slash - 1)) != 'e' ||
-		    !strchr(".0123456789", *(slash + 1))))
-			*slash = ' ';
+
+	/*
+	 * "foot-pound" is the same as "foot pound". But don't
+	 * trash minus signs on numbers.
+	 *
+	 * 20160204 dholland: this used to let through only minus
+	 * signs at the beginning of the string or in the middle of a
+	 * floating constant (e.g. 3.6e-5), and a minus sign at the
+	 * beginning of the string failed further on. I have changed
+	 * it so any minus sign before a digit (or decimal point) is
+	 * treated as going with that digit.
+	 *
+	 * Note that this changed the interpretation of certain
+	 * marginally valid inputs like "3 N-5 s"; that used to be
+	 * interpreted as "3 N 5 s" or 15 N s, but now it reads as
+	 * "3 N -5 s" or -15 N s. However, it also makes negative
+	 * exponents on units work, which used to be silently trashed.
+	 */
+	for (minus = scratch + 1; *minus; minus++) {
+		if (*minus != '-') {
+			continue;
+		}
+		if (strchr(".0123456789", *(minus + 1))) {
+			continue;
+		}
+		*minus = ' ';
+	}
+
+	/* Process up to the next / in one go. */
+
 	slash = strchr(scratch, '/');
 	if (slash)
 		*slash = 0;
@@ -359,7 +387,9 @@ addunit(struct unittype * theunit, const
 	do {
 		item = strtok(scratch, " *\t\n/");
 		while (item) {
-			if (strchr("0123456789.", *item)) {
+			if ((*item == '-' && strchr("0123456789.", *(item+1)))
+			    || strchr("0123456789.", *item)) {
+			    
 				/* item starts with a number */
 				char *endptr;
 				double num;
@@ -415,14 +445,37 @@ addunit(struct unittype * theunit, const
 			}
 			else {	/* item is not a number */
 				int repeat = 1;
+				int flipthis = 0;
 
-				if (strchr("23456789",
-				    item[strlen(item) - 1])) {
-					repeat = item[strlen(item) - 1] - '0';
-					item[strlen(item) - 1] = 0;
+				pos = len = strlen(item);
+				assert(pos > 0);
+				while (strchr("0123456789", item[pos - 1])) {
+					pos--;
+					/* string began with non-digit */
+					assert(pos > 0);
+				}
+				if (pos < len) {
+					if (pos > 1 && item[pos - 1] == '-' &&
+					    item[pos - 2] == '^') {
+						/* allow negative exponents */
+						pos--;
+					}
+					/* have an exponent */
+					repeat = strtol(item + pos, NULL, 10);
+					item[pos] = 0;
+					if (repeat == 0) {
+						/* not really the right msg */
+						zeroerror();
+						return 1;
+					}
+					if (repeat < 0) {
+						flipthis = 1;
+						repeat = -repeat;
+					}
 				}
+				flipthis ^= doingtop ^ flip;
 				for (; repeat; repeat--)
-					if (addsubunit(doingtop ^ flip ? theunit->numerator : theunit->denominator, item))
+					if (addsubunit(flipthis ? theunit->numerator : theunit->denominator, item))
 						return 1;
 			}
 			item = strtok(NULL, " *\t/\n");

Reply via email to