changeset 1394:06bd54ef3e0e

* lib/xstrtol.c (bkm_scale): Don't assume that you can convert unsigned long to double without losing information. (bkm_scale_by_power): New function. * lib/xstrtol.c (__xstrtol), src/dd.c (parse_integer): Add support for SI-like suffixes like "GB" and "TD". * src/dd.c (usage): Describe it.
author Jim Meyering <jim@meyering.net>
date Mon, 29 Jun 1998 15:24:43 +0000
parents 942e099ca5e1
children 87e3c1c3497a
files lib/xstrtol.c
diffstat 1 files changed, 86 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/lib/xstrtol.c
+++ b/lib/xstrtol.c
@@ -75,36 +75,42 @@
      __unsigned long int *x;
      int scale_factor;
 {
-  /* The cast to `__unsigned long int' before the cast to double is
-     required to work around a bug in SunOS's /bin/cc.  */
-  if (*x > (double) ((__unsigned long int) __ZLONG_MAX) / scale_factor)
-    {
+  __unsigned long int product = *x * scale_factor;
+  if (*x != product / scale_factor)
+    return 1;
+  *x = product;
+  return 0;
+}
+
+static int
+bkm_scale_by_power (x, base, power)
+     __unsigned long int *x;
+     int base;
+     int power;
+{
+  while (power--)
+    if (bkm_scale (x, base))
       return 1;
-    }
-  *x *= scale_factor;
+
   return 0;
 }
 
 /* FIXME: comment.  */
 
 strtol_error
-__xstrtol (s, ptr, base, val, valid_suffixes)
-     const char *s;
-     char **ptr;
-     int base;
-     __unsigned long int *val;
-     const char *valid_suffixes;
+__xstrtol (const char *s, char **ptr, int strtol_base,
+	   __unsigned long int *val, const char *valid_suffixes)
 {
   char *t_ptr;
   char **p;
   __unsigned long int tmp;
 
-  assert (0 <= base && base <= 36);
+  assert (0 <= strtol_base && strtol_base <= 36);
 
   p = (ptr ? ptr : &t_ptr);
 
   errno = 0;
-  tmp = __strtol (s, p, base);
+  tmp = __strtol (s, p, strtol_base);
   if (errno != 0)
     return LONGINT_OVERFLOW;
   if (*p == s)
@@ -121,44 +127,92 @@
 
   if (**p != '\0')
     {
+      int base = 1024;
+      int suffixes = 1;
+      int overflow;
+
       if (!strchr (valid_suffixes, **p))
 	return LONGINT_INVALID_SUFFIX_CHAR;
 
+      if (strchr (valid_suffixes, '0'))
+	{
+	  /* The ``valid suffix'' '0' is a special flag meaning that
+	     an optional second suffix is allowed, which can change
+	     the base, e.g. "100MD" for 100 megabytes decimal.  */
+
+	  switch (p[0][1])
+	    {
+	    case 'B':
+	      suffixes++;
+	      break;
+
+	    case 'D':
+	      base = 1000;
+	      suffixes++;
+	      break;
+	    }
+	}
+
       switch (**p)
 	{
 	case 'b':
-	  if (bkm_scale (&tmp, 512))
-	    return LONGINT_OVERFLOW;
-	  ++(*p);
-	  break;
-
-	case 'c':
-	  ++(*p);
+	  overflow = bkm_scale (&tmp, 512);
 	  break;
 
 	case 'B':
-	case 'k':
-	  if (bkm_scale (&tmp, 1024))
-	    return LONGINT_OVERFLOW;
-	  ++(*p);
+	  overflow = bkm_scale (&tmp, 1024);
+	  break;
+
+	case 'c':
+	  overflow = 0;
+	  break;
+
+	case 'E': /* Exa */
+	  overflow = bkm_scale_by_power (&tmp, base, 6);
+	  break;
+
+	case 'G': /* Giga */
+	  overflow = bkm_scale_by_power (&tmp, base, 3);
 	  break;
 
-	case 'm':
-	  if (bkm_scale (&tmp, 1024 * 1024))
-	    return LONGINT_OVERFLOW;
-	  ++(*p);
+	case 'k': /* kilo */
+	  overflow = bkm_scale_by_power (&tmp, base, 1);
+	  break;
+
+	case 'M': /* Mega */
+	case 'm': /* 'm' is undocumented; for backward compatibility only */
+	  overflow = bkm_scale_by_power (&tmp, base, 2);
+	  break;
+
+	case 'P': /* Peta */
+	  overflow = bkm_scale_by_power (&tmp, base, 5);
+	  break;
+
+	case 'T': /* Tera */
+	  overflow = bkm_scale_by_power (&tmp, base, 4);
 	  break;
 
 	case 'w':
-	  if (bkm_scale (&tmp, 2))
-	    return LONGINT_OVERFLOW;
-	  ++(*p);
+	  overflow = bkm_scale (&tmp, 2);
+	  break;
+
+	case 'Y': /* Yotta */
+	  overflow = bkm_scale_by_power (&tmp, base, 8);
+	  break;
+
+	case 'Z': /* Zetta */
+	  overflow = bkm_scale_by_power (&tmp, base, 7);
 	  break;
 
 	default:
 	  return LONGINT_INVALID_SUFFIX_CHAR;
 	  break;
 	}
+
+      if (overflow)
+	return LONGINT_OVERFLOW;
+
+      (*p) += suffixes;
     }
 
   *val = tmp;