diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2015-07-04 17:13:50 +0300 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2015-07-04 17:13:50 +0300 |
commit | 71cd8e3a743046573744123777061b64881bf372 (patch) | |
tree | 82522befe647f4fff186a5630cad0cad33f8ef53 /src/seq.c | |
parent | c18578632fd3c9e513e613a86ba2b7c4ebee6c45 (diff) | |
download | coreutils-upstream.tar.gz |
Imported Upstream version 8.24upstream/8.24upstream
Diffstat (limited to 'src/seq.c')
-rw-r--r-- | src/seq.c | 123 |
1 files changed, 86 insertions, 37 deletions
@@ -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; } |