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/77cee1247433
branches:  trunk
changeset: 813595:77cee1247433
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 d5a6432ad1bb -r 77cee1247433 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