Mercurial > hg > octave-nkf > gnulib-hg
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;