summaryrefslogtreecommitdiff
path: root/src/seq.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2015-07-04 17:13:50 +0300
committerIgor Pashev <pashev.igor@gmail.com>2015-07-04 17:13:50 +0300
commit71cd8e3a743046573744123777061b64881bf372 (patch)
tree82522befe647f4fff186a5630cad0cad33f8ef53 /src/seq.c
parentc18578632fd3c9e513e613a86ba2b7c4ebee6c45 (diff)
downloadcoreutils-upstream.tar.gz
Imported Upstream version 8.24upstream/8.24upstream
Diffstat (limited to 'src/seq.c')
-rw-r--r--src/seq.c123
1 files changed, 86 insertions, 37 deletions
diff --git a/src/seq.c b/src/seq.c
index 1124358c..2426c4de 100644
--- a/src/seq.c
+++ b/src/seq.c
@@ -1,5 +1,5 @@
/* seq - print sequence of numbers to standard output.
- Copyright (C) 1994-2014 Free Software Foundation, Inc.
+ Copyright (C) 1994-2015 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -98,7 +98,7 @@ FORMAT must be suitable for printing one argument of type 'double';\n\
it defaults to %.PRECf if FIRST, INCREMENT, and LAST are all fixed point\n\
decimal numbers with maximum precision PREC, and to %g otherwise.\n\
"), stdout);
- emit_ancillary_info ();
+ emit_ancillary_info (PROGRAM_NAME);
}
exit (status);
}
@@ -147,17 +147,24 @@ scan_arg (const char *arg)
while (isspace (to_uchar (*arg)) || *arg == '+')
arg++;
- ret.width = strlen (arg);
+ /* Default to auto width and precision. */
+ ret.width = 0;
ret.precision = INT_MAX;
+ /* Use no precision (and possibly fast generation) for integers. */
+ char const *decimal_point = strchr (arg, '.');
+ if (! decimal_point && ! strchr (arg, 'p') /* not a hex float */)
+ ret.precision = 0;
+
+ /* auto set width and precision for decimal inputs. */
if (! arg[strcspn (arg, "xX")] && isfinite (ret.value))
{
- char const *decimal_point = strchr (arg, '.');
- if (! decimal_point)
- ret.precision = 0;
- else
+ size_t fraction_len = 0;
+ ret.width = strlen (arg);
+
+ if (decimal_point)
{
- size_t fraction_len = strcspn (decimal_point + 1, "eE");
+ fraction_len = strcspn (decimal_point + 1, "eE");
if (fraction_len <= INT_MAX)
ret.precision = fraction_len;
ret.width += (fraction_len == 0 /* #. -> # */
@@ -171,7 +178,8 @@ scan_arg (const char *arg)
if (e)
{
long exponent = strtol (e + 1, NULL, 10);
- ret.precision += exponent < 0 ? -exponent : 0;
+ ret.precision += exponent < 0 ? -exponent
+ : - MIN (ret.precision, exponent);
/* Don't account for e.... in the width since this is not output. */
ret.width -= strlen (arg) - (e - arg);
/* Adjust the width as per the exponent. */
@@ -186,6 +194,12 @@ scan_arg (const char *arg)
ret.width++;
exponent = -exponent;
}
+ else
+ {
+ if (decimal_point && ret.precision == 0 && fraction_len)
+ ret.width--; /* discount space for '.' */
+ exponent -= MIN (fraction_len, exponent);
+ }
ret.width += exponent;
}
}
@@ -411,52 +425,84 @@ trim_leading_zeros (char const *s)
static bool
seq_fast (char const *a, char const *b)
{
+ bool inf = STREQ (b, "inf");
+
/* Skip past any leading 0's. Without this, our naive cmp
function would declare 000 to be larger than 99. */
a = trim_leading_zeros (a);
b = trim_leading_zeros (b);
size_t p_len = strlen (a);
- size_t q_len = strlen (b);
- size_t n = MAX (p_len, q_len);
- char *p0 = xmalloc (n + 1);
- char *p = memcpy (p0 + n - p_len, a, p_len + 1);
- char *q0 = xmalloc (n + 1);
- char *q = memcpy (q0 + n - q_len, b, q_len + 1);
-
- bool ok = cmp (p, p_len, q, q_len) <= 0;
+ size_t q_len = inf ? 0 : strlen (b);
+
+ /* Allow for at least 31 digits without realloc.
+ 1 more than p_len is needed for the inf case. */
+ size_t inc_size = MAX (MAX (p_len + 1, q_len), 31);
+
+ /* Copy input strings (incl NUL) to end of new buffers. */
+ char *p0 = xmalloc (inc_size + 1);
+ char *p = memcpy (p0 + inc_size - p_len, a, p_len + 1);
+ char *q;
+ char *q0;
+ if (! inf)
+ {
+ q0 = xmalloc (inc_size + 1);
+ q = memcpy (q0 + inc_size - q_len, b, q_len + 1);
+ }
+ else
+ q = q0 = NULL;
+
+ bool ok = inf || cmp (p, p_len, q, q_len) <= 0;
if (ok)
{
- /* Buffer at least this many numbers per fwrite call.
- This gives a speed-up of more than 2x over the unbuffered code
+ /* Reduce number of fwrite calls which is seen to
+ give a speed-up of more than 2x over the unbuffered code
when printing the first 10^9 integers. */
- enum {N = 40};
- char *buf = xmalloc (N * (n + 1));
- char const *buf_end = buf + N * (n + 1);
+ size_t buf_size = MAX (BUFSIZ, (inc_size + 1) * 2);
+ char *buf = xmalloc (buf_size);
+ char const *buf_end = buf + buf_size;
- char *z = buf;
+ char *bufp = buf;
/* Write first number to buffer. */
- z = mempcpy (z, p, p_len);
+ bufp = mempcpy (bufp, p, p_len);
/* Append separator then number. */
- while (cmp (p, p_len, q, q_len) < 0)
+ while (inf || cmp (p, p_len, q, q_len) < 0)
{
- *z++ = *separator;
+ *bufp++ = *separator;
incr (&p, &p_len);
- z = mempcpy (z, p, p_len);
+
+ /* Double up the buffers when needed for the inf case. */
+ if (p_len == inc_size)
+ {
+ inc_size *= 2;
+ p0 = xrealloc (p0, inc_size + 1);
+ p = memmove (p0 + p_len, p0, p_len + 1);
+
+ if (buf_size < (inc_size + 1) * 2)
+ {
+ size_t buf_offset = bufp - buf;
+ buf_size = (inc_size + 1) * 2;
+ buf = xrealloc (buf, buf_size);
+ buf_end = buf + buf_size;
+ bufp = buf + buf_offset;
+ }
+ }
+
+ bufp = mempcpy (bufp, p, p_len);
/* If no place for another separator + number then
output buffer so far, and reset to start of buffer. */
- if (buf_end - (n + 1) < z)
+ if (buf_end - (p_len + 1) < bufp)
{
- fwrite (buf, z - buf, 1, stdout);
- z = buf;
+ fwrite (buf, bufp - buf, 1, stdout);
+ bufp = buf;
}
}
/* Write any remaining buffered output, and the terminator. */
- *z++ = *terminator;
- fwrite (buf, z - buf, 1, stdout);
+ *bufp++ = *terminator;
+ fwrite (buf, bufp - buf, 1, stdout);
IF_LINT (free (buf));
}
@@ -574,7 +620,7 @@ main (int argc, char **argv)
char const *s1 = n_args == 1 ? "1" : argv[optind];
char const *s2 = argv[optind + (n_args - 1)];
if (seq_fast (s1, s2))
- exit (EXIT_SUCCESS);
+ return EXIT_SUCCESS;
/* Upon any failure, let the more general code deal with it. */
}
@@ -593,7 +639,8 @@ main (int argc, char **argv)
}
}
- if (first.precision == 0 && step.precision == 0 && last.precision == 0
+ if ((isfinite (first.value) && first.precision == 0)
+ && step.precision == 0 && last.precision == 0
&& 0 <= first.value && step.value == 1 && 0 <= last.value
&& !equal_width && !format_str && strlen (separator) == 1)
{
@@ -601,14 +648,16 @@ main (int argc, char **argv)
char *s2;
if (asprintf (&s1, "%0.Lf", first.value) < 0)
xalloc_die ();
- if (asprintf (&s2, "%0.Lf", last.value) < 0)
+ if (! isfinite (last.value))
+ s2 = xstrdup ("inf"); /* Ensure "inf" is used. */
+ else if (asprintf (&s2, "%0.Lf", last.value) < 0)
xalloc_die ();
if (*s1 != '-' && *s2 != '-' && seq_fast (s1, s2))
{
IF_LINT (free (s1));
IF_LINT (free (s2));
- exit (EXIT_SUCCESS);
+ return EXIT_SUCCESS;
}
free (s1);
@@ -621,5 +670,5 @@ main (int argc, char **argv)
print_numbers (format_str, layout, first.value, step.value, last.value);
- exit (EXIT_SUCCESS);
+ return EXIT_SUCCESS;
}