summaryrefslogtreecommitdiff
path: root/src/getlimits.c
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2010-12-22 23:11:05 -0800
committerPaul Eggert <eggert@cs.ucla.edu>2010-12-22 23:11:40 -0800
commit83e01384804810e14a9d2765760c670b9b6a7dd8 (patch)
tree11ffb4e0ebdf22e4e71ebfc96b6138ef72bb5f13 /src/getlimits.c
parent8f90efd006fdcb8de861bba363fc5a1b8a330a76 (diff)
downloadcoreutils-83e01384804810e14a9d2765760c670b9b6a7dd8.tar.xz
getlimits: port to hosts with very wide int, or non-ASCII
* src/getlimits.c (decimal_ascii_add): Remove, replacing with ... (decimal_absval_add_one): New function, with different signature, which does not assume ASCII. All callers changed. (print_int): Remove assumptions that integers fit in 206 bits, and that characters are ASCII. These assumptions are portable in practice but are easy to remove here.
Diffstat (limited to 'src/getlimits.c')
-rw-r--r--src/getlimits.c74
1 files changed, 24 insertions, 50 deletions
diff --git a/src/getlimits.c b/src/getlimits.c
index 93d4035a7..986a5d730 100644
--- a/src/getlimits.c
+++ b/src/getlimits.c
@@ -79,53 +79,31 @@ Output platform dependent limits in a format useful for shell scripts.\n\
exit (status);
}
-/* Add absolute values of ascii decimal strings.
- * Strings can have leading spaces.
- * If any string has a '-' it's preserved in the output:
- * I.E.
- * 1 + 1 -> 2
- * -1 + -1 -> -2
- * -1 + 1 -> -2
- * 1 + -1 -> -2
- */
-static char *
-decimal_ascii_add (const char *str1, const char *str2)
+/* Add one to the absolute value of the number whose textual
+ representation is BUF + 1. Do this in-place, in the buffer.
+ Return a pointer to the result, which is normally BUF + 1, but is
+ BUF if the representation grew in size. */
+static char const *
+decimal_absval_add_one (char *buf)
{
- int len1 = strlen (str1);
- int len2 = strlen (str2);
- int rlen = MAX (len1, len2) + 3; /* space for extra digit or sign + NUL */
- char *result = xmalloc (rlen);
- char *rp = result + rlen - 1;
- const char *d1 = str1 + len1 - 1;
- const char *d2 = str2 + len2 - 1;
- int carry = 0;
- *rp = '\0';
-
- while (1)
- {
- char c1 = (d1 < str1 ? ' ' : (*d1 == '-' ? ' ' : *d1--));
- char c2 = (d2 < str2 ? ' ' : (*d2 == '-' ? ' ' : *d2--));
- char t1 = c1 + c2 + carry; /* ASCII digits are BCD */
- if (!c_isdigit (c1) && !c_isdigit (c2) && !carry)
- break;
- carry = t1 > '0' + '9' || t1 == ' ' + '9' + 1;
- t1 += 6 * carry;
- *--rp = (t1 & 0x0F) | 0x30; /* top nibble to ASCII */
- }
- if ((d1 >= str1 && *d1 == '-') || (d2 >= str2 && (*d2 == '-')))
- *--rp = '-';
-
- if (rp != result)
- memmove (result, rp, rlen - (rp - result));
-
+ bool negative = (buf[1] == '-');
+ char *absnum = buf + 1 + negative;
+ char *p = absnum + strlen (absnum);
+ absnum[-1] = '0';
+ while (*--p == '9')
+ *p = '0';
+ ++*p;
+ char *result = MIN (absnum, p);
+ if (negative)
+ *--result = '-';
return result;
}
int
main (int argc, char **argv)
{
- char limit[64]; /* big enough for 128 bit integers at least */
- char *oflow;
+ char limit[1 + MAX (INT_BUFSIZE_BOUND (intmax_t),
+ INT_BUFSIZE_BOUND (uintmax_t))];
initialize_main (&argc, &argv);
set_program_name (argv[0]);
@@ -140,18 +118,14 @@ main (int argc, char **argv)
usage, AUTHORS, (char const *) NULL);
#define print_int(TYPE) \
- snprintf (limit, sizeof limit, "%"PRIuMAX, (uintmax_t)TYPE##_MAX); \
- printf (#TYPE"_MAX=%s\n", limit); \
- oflow = decimal_ascii_add (limit, "1"); \
- printf (#TYPE"_OFLOW=%s\n", oflow); \
- free (oflow); \
+ sprintf (limit + 1, "%"PRIuMAX, (uintmax_t) TYPE##_MAX); \
+ printf (#TYPE"_MAX=%s\n", limit + 1); \
+ printf (#TYPE"_OFLOW=%s\n", decimal_absval_add_one (limit)); \
if (TYPE##_MIN) \
{ \
- snprintf (limit, sizeof limit, "%"PRIdMAX, (intmax_t)TYPE##_MIN); \
- printf (#TYPE"_MIN=%s\n", limit); \
- oflow = decimal_ascii_add (limit, "-1"); \
- printf (#TYPE"_UFLOW=%s\n", oflow); \
- free (oflow); \
+ sprintf (limit + 1, "%"PRIdMAX, (intmax_t) TYPE##_MIN); \
+ printf (#TYPE"_MIN=%s\n", limit + 1); \
+ printf (#TYPE"_UFLOW=%s\n", decimal_absval_add_one (limit)); \
}
#define print_float(TYPE) \