Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/usr.bin/units Improve the parser. Now we understand negative...
details: https://anonhg.NetBSD.org/src/rev/8a6926fd2224
branches: trunk
changeset: 343453:8a6926fd2224
user: dholland <dholland%NetBSD.org@localhost>
date: Fri Feb 05 03:30:08 2016 +0000
description:
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.
diffstat:
usr.bin/units/units.c | 76 ++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 64 insertions(+), 12 deletions(-)
diffs (117 lines):
diff -r b584cb34ab23 -r 8a6926fd2224 usr.bin/units/units.c
--- a/usr.bin/units/units.c Fri Feb 05 03:04:52 2016 +0000
+++ b/usr.bin/units/units.c Fri Feb 05 03:30:08 2016 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: units.c,v 1.25 2014/01/07 02:07:09 joerg Exp $ */
+/* $NetBSD: units.c,v 1.26 2016/02/05 03:30:08 dholland Exp $ */
/*
* units.c Copyright (c) 1993 by Adrian Mariano (adrian%cam.cornell.edu@localhost)
@@ -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 @@
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 @@
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,36 @@
}
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 > 0 && item[pos - 1] == '-') {
+ /* 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");
Home |
Main Index |
Thread Index |
Old Index