/* seq - print sequence of numbers to standard output. This is the seq utility
Copyright (C) 1994-2018 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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ The GNUv3 license
/* Written by Ulrich Drepper. */
#include <config.h> Provides system specific information
#include <getopt.h> ...!includes auto-comment...
#include <stdio.h> Provides standard I/O capability
#include <sys/types.h> Provides system data types
#include "system.h" ...!includes auto-comment...
#include "die.h" ...!includes auto-comment...
#include "c-strtod.h" ...!includes auto-comment...
#include "error.h" ...!includes auto-comment...
#include "quote.h" ...!includes auto-comment...
#include "xstrtod.h" ...!includes auto-comment...
/* Roll our own isfinite/isnan rather than using <math.h>, so that we don't
have to worry about linking -lm just for isfinite. */
#ifndef isfinite Line 33
# define isfinite(x) ((x) * 0 == 0) Line 34
#endif Line 35
#ifndef isnan Line 36
# define isnan(x) ((x) != (x)) Line 37
#endif Line 38
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "seq" Line 41
#define AUTHORS proper_name ("Ulrich Drepper") Line 43
/* If true print all number with equal width. */
static bool equal_width; Line 46
/* The string used to separate two numbers. */
static char const *separator; Line 49
/* The string output after all numbers have been output.
Usually "\n" or "\0". */
static char const terminator[] = "\n"; Line 53
static struct option const long_options[] = Line 55
{
{ "equal-width", no_argument, NULL, 'w'}, Line 57
{ "format", required_argument, NULL, 'f'}, Line 58
{ "separator", required_argument, NULL, 's'}, Line 59
{GETOPT_HELP_OPTION_DECL}, Line 60
{GETOPT_VERSION_OPTION_DECL}, Line 61
{ NULL, 0, NULL, 0} Line 62
}; Block 1
void Line 65
usage (int status) Line 66
{
if (status != EXIT_SUCCESS) Line 68
emit_try_help (); ...!common auto-comment...
else Line 70
{
printf (_("\ Line 72
Usage: %s [OPTION]... LAST\n\ Line 73
or: %s [OPTION]... FIRST LAST\n\ Line 74
or: %s [OPTION]... FIRST INCREMENT LAST\n\ Line 75
"), program_name, program_name, program_name); Line 76
fputs (_("\ Line 77
Print numbers from FIRST to LAST, in steps of INCREMENT.\n\ Line 78
"), stdout); Line 79
emit_mandatory_arg_note (); ...!common auto-comment...
fputs (_("\ Line 83
-f, --format=FORMAT use printf style floating-point FORMAT\n\ Line 84
-s, --separator=STRING use STRING to separate numbers (default: \\n)\n\ Line 85
-w, --equal-width equalize width by padding with leading zeroes\n\ Line 86
"), stdout); Line 87
fputs (HELP_OPTION_DESCRIPTION, stdout); Line 88
fputs (VERSION_OPTION_DESCRIPTION, stdout); Line 89
fputs (_("\ Line 90
\n\
If FIRST or INCREMENT is omitted, it defaults to 1. That is, an\n\ Line 92
omitted INCREMENT defaults to 1 even when LAST is smaller than FIRST.\n\ Line 93
The sequence of numbers ends when the sum of the current number and\n\ Line 94
INCREMENT would become greater than LAST.\n\ Line 95
FIRST, INCREMENT, and LAST are interpreted as floating point values.\n\ Line 96
INCREMENT is usually positive if FIRST is smaller than LAST, and\n\ Line 97
INCREMENT is usually negative if FIRST is greater than LAST.\n\ Line 98
INCREMENT must not be 0; none of FIRST, INCREMENT and LAST may be NaN.\n\ Line 99
"), stdout); Line 100
fputs (_("\ Line 101
FORMAT must be suitable for printing one argument of type 'double';\n\ Line 102
it defaults to %.PRECf if FIRST, INCREMENT, and LAST are all fixed point\n\ Line 103
decimal numbers with maximum precision PREC, and to %g otherwise.\n\ Line 104
"), stdout); Line 105
emit_ancillary_info (PROGRAM_NAME); Line 106
}
exit (status); Line 108
} Block 2
/* A command-line operand. */
struct operand Line 112
{
/* Its value, converted to 'long double'. */
long double value; Line 115
/* Its print width, if it were printed out in a form similar to its
input form. An input like "-.1" is treated like "-0.1", and an
input like "1." is treated like "1", but otherwise widths are
left alone. */
size_t width; Line 121
/* Number of digits after the decimal point, or INT_MAX if the
number can't easily be expressed as a fixed-point number. */
int precision; Line 125
};
typedef struct operand operand; Line 127
/* Description of what a number-generating format will generate. */
struct layout Line 130
{
/* Number of bytes before and after the number. */
size_t prefix_len; Line 133
size_t suffix_len; Line 134
};
/* Read a long double value from the command line.
Return if the string is correct else signal error. */
static operand Line 140
scan_arg (const char *arg) Line 141
{
operand ret; Line 143
if (! xstrtold (arg, NULL, &ret.value, c_strtold)) Line 145
{
error (0, 0, _("invalid floating point argument: %s"), quote (arg)); Line 147
usage (EXIT_FAILURE); Line 148
}
if (isnan (ret.value)) Line 151
{
error (0, 0, _("invalid %s argument: %s"), quote_n (0, "not-a-number"), Line 153
quote_n (1, arg)); Line 154
usage (EXIT_FAILURE); Line 155
}
/* We don't output spaces or '+' so don't include in width */
while (isspace (to_uchar (*arg)) || *arg == '+') Line 159
arg++; Line 160
/* Default to auto width and precision. */
ret.width = 0; Line 163
ret.precision = INT_MAX; Line 164
/* Use no precision (and possibly fast generation) for integers. */
char const *decimal_point = strchr (arg, '.'); Line 167
if (! decimal_point && ! strchr (arg, 'p') /* not a hex float */) Line 168
ret.precision = 0; Line 169
/* auto set width and precision for decimal inputs. */
if (! arg[strcspn (arg, "xX")] && isfinite (ret.value)) Line 172
{
size_t fraction_len = 0; Line 174
ret.width = strlen (arg); Line 175
if (decimal_point) Line 177
{
fraction_len = strcspn (decimal_point + 1, "eE"); Line 179
if (fraction_len <= INT_MAX) Line 180
ret.precision = fraction_len; Line 181
ret.width += (fraction_len == 0 /* #. -> # */ Line 182
? -1 Line 183
: (decimal_point == arg /* .# -> 0.# */ Line 184
|| ! ISDIGIT (decimal_point[-1]))); /* -.# -> 0.# */ Line 185
}
char const *e = strchr (arg, 'e'); Line 187
if (! e) Line 188
e = strchr (arg, 'E'); Line 189
if (e) Line 190
{
long exponent = strtol (e + 1, NULL, 10); Line 192
ret.precision += exponent < 0 ? -exponent Line 193
: - MIN (ret.precision, exponent); Line 194
/* Don't account for e.... in the width since this is not output. */
ret.width -= strlen (arg) - (e - arg); Line 196
/* Adjust the width as per the exponent. */
if (exponent < 0) Line 198
{
if (decimal_point) Line 200
{
if (e == decimal_point + 1) /* undo #. -> # above */ Line 202
ret.width++; Line 203
}
else Line 205
ret.width++; Line 206
exponent = -exponent; Line 207
}
else Line 209
{
if (decimal_point && ret.precision == 0 && fraction_len) Line 211
ret.width--; /* discount space for '.' */ Line 212
exponent -= MIN (fraction_len, exponent); Line 213
}
ret.width += exponent; Line 215
}
}
return ret; Line 219
} Block 5
/* If FORMAT is a valid printf format for a double argument, return
its long double equivalent, allocated from dynamic storage, and
store into *LAYOUT a description of the output layout; otherwise,
report an error and exit. */
static char const * Line 227
long_double_format (char const *fmt, struct layout *layout) Line 228
{
size_t i; Line 230
size_t prefix_len = 0; Line 231
size_t suffix_len = 0; Line 232
size_t length_modifier_offset; Line 233
bool has_L; Line 234
for (i = 0; ! (fmt[i] == '%' && fmt[i + 1] != '%'); i += (fmt[i] == '%') + 1) Line 236
{
if (!fmt[i]) Line 238
die (EXIT_FAILURE, 0, Line 239
_("format %s has no %% directive"), quote (fmt)); Line 240
prefix_len++; Line 241
}
i++; Line 244
i += strspn (fmt + i, "-+#0 '"); Line 245
i += strspn (fmt + i, "0123456789"); Line 246
if (fmt[i] == '.') Line 247
{
i++; Line 249
i += strspn (fmt + i, "0123456789"); Line 250
}
length_modifier_offset = i; Line 253
has_L = (fmt[i] == 'L'); Line 254
i += has_L; Line 255
if (fmt[i] == '\0') Line 256
die (EXIT_FAILURE, 0, _("format %s ends in %%"), quote (fmt)); Line 257
if (! strchr ("efgaEFGA", fmt[i])) Line 258
die (EXIT_FAILURE, 0, Line 259
_("format %s has unknown %%%c directive"), quote (fmt), fmt[i]); Line 260
for (i++; ; i += (fmt[i] == '%') + 1) Line 262
if (fmt[i] == '%' && fmt[i + 1] != '%') Line 263
die (EXIT_FAILURE, 0, _("format %s has too many %% directives"), Line 264
quote (fmt)); Line 265
else if (fmt[i]) Line 266
suffix_len++; Line 267
else Line 268
{
size_t format_size = i + 1; Line 270
char *ldfmt = xmalloc (format_size + 1); Line 271
memcpy (ldfmt, fmt, length_modifier_offset); Line 272
ldfmt[length_modifier_offset] = 'L'; Line 273
strcpy (ldfmt + length_modifier_offset + 1, Line 274
fmt + length_modifier_offset + has_L); Line 275
layout->prefix_len = prefix_len; Line 276
layout->suffix_len = suffix_len; Line 277
return ldfmt; Line 278
}
} Block 6
static void ATTRIBUTE_NORETURN Line 282
io_error (void) Line 283
{
/* FIXME: consider option to silently ignore errno=EPIPE */
clearerr (stdout); Line 286
die (EXIT_FAILURE, errno, _("write error")); Line 287
}
/* Actually print the sequence of numbers in the specified range, with the
given or default stepping and format. */
static void Line 293
print_numbers (char const *fmt, struct layout layout, Line 294
long double first, long double step, long double last) Line 295
{
bool out_of_range = (step < 0 ? first < last : last < first); Line 297
if (! out_of_range) Line 299
{
long double x = first; Line 301
long double i; Line 302
for (i = 1; ; i++) Line 304
{
long double x0 = x; Line 306
if (printf (fmt, x) < 0) Line 307
io_error (); Line 308
if (out_of_range) Line 309
break; Line 310
x = first + i * step; Line 311
out_of_range = (step < 0 ? x < last : last < x); Line 312
if (out_of_range) Line 314
{
/* If the number just past LAST prints as a value equal
to LAST, and prints differently from the previous
number, then print the number. This avoids problems
with rounding. For example, with the x86 it causes
"seq 0 0.000001 0.000003" to print 0.000003 instead
of stopping at 0.000002. */
bool print_extra_number = false; Line 323
long double x_val; Line 324
char *x_str; Line 325
int x_strlen; Line 326
setlocale (LC_NUMERIC, "C"); Sets up internationalization (i18n)
x_strlen = asprintf (&x_str, fmt, x); Line 328
setlocale (LC_NUMERIC, ""); Sets up internationalization (i18n)
if (x_strlen < 0) Line 330
xalloc_die (); ...!common auto-comment...
x_str[x_strlen - layout.suffix_len] = '\0'; Line 332
if (xstrtold (x_str + layout.prefix_len, NULL, &x_val, c_strtold) Line 334
&& x_val == last) Line 335
{
char *x0_str = NULL; Line 337
if (asprintf (&x0_str, fmt, x0) < 0) Line 338
xalloc_die (); ...!common auto-comment...
print_extra_number = !STREQ (x0_str, x_str); Line 340
free (x0_str); Line 341
}
free (x_str); Line 344
if (! print_extra_number) Line 345
break; Line 346
}
if (fputs (separator, stdout) == EOF) Line 349
io_error (); Line 350
}
if (fputs (terminator, stdout) == EOF) Line 353
io_error (); Line 354
}
} Block 8
/* Return the default format given FIRST, STEP, and LAST. */
static char const * Line 359
get_default_format (operand first, operand step, operand last) Line 360
{
static char format_buf[sizeof "%0.Lf" + 2 * INT_STRLEN_BOUND (int)]; Line 362
int prec = MAX (first.precision, step.precision); Line 364
if (prec != INT_MAX && last.precision != INT_MAX) Line 366
{
if (equal_width) Line 368
{
/* increase first_width by any increased precision in step */
size_t first_width = first.width + (prec - first.precision); Line 371
/* adjust last_width to use precision from first/step */
size_t last_width = last.width + (prec - last.precision); Line 373
if (last.precision && prec == 0) Line 374
last_width--; /* don't include space for '.' */ Line 375
if (last.precision == 0 && prec) Line 376
last_width++; /* include space for '.' */ Line 377
if (first.precision == 0 && prec) Line 378
first_width++; /* include space for '.' */ Line 379
size_t width = MAX (first_width, last_width); Line 380
if (width <= INT_MAX) Line 381
{
int w = width; Line 383
sprintf (format_buf, "%%0%d.%dLf", w, prec); Line 384
return format_buf; Line 385
}
}
else Line 388
{
sprintf (format_buf, "%%.%dLf", prec); Line 390
return format_buf; Line 391
}
}
return "%Lg"; Line 395
} Block 9
/* The NUL-terminated string S0 of length S_LEN represents a valid
non-negative decimal integer. Adjust the string and length so
that the pair describe the next-larger value. */
static void Line 401
incr (char **s0, size_t *s_len) Line 402
{
char *s = *s0; Line 404
char *endp = s + *s_len - 1; Line 405
do
{
if ((*endp)++ < '9') Line 409
return; Line 410
*endp-- = '0'; Line 411
}
while (endp >= s); Line 413
*--(*s0) = '1'; Line 414
++*s_len; Line 415
} Block 10
/* Compare A and B (each a NUL-terminated digit string), with lengths
given by A_LEN and B_LEN. Return +1 if A < B, -1 if B < A, else 0. */
static int Line 420
cmp (char const *a, size_t a_len, char const *b, size_t b_len) Line 421
{
if (a_len < b_len) Line 423
return -1; Line 424
if (b_len < a_len) Line 425
return 1; Line 426
return (strcmp (a, b)); Line 427
} Block 11
/* Trim leading 0's from S, but if S is all 0's, leave one.
Return a pointer to the trimmed string. */
static char const * _GL_ATTRIBUTE_PURE Line 432
trim_leading_zeros (char const *s) Line 433
{
char const *p = s; Line 435
while (*s == '0') Line 436
++s; Line 437
/* If there were only 0's, back up, to leave one. */
if (!*s && s != p) Line 440
--s; Line 441
return s; Line 442
} Block 12
/* Print all whole numbers from A to B, inclusive -- to stdout, each
followed by a newline. If B < A, return false and print nothing.
Otherwise, return true. */
static bool Line 448
seq_fast (char const *a, char const *b) Line 449
{
bool inf = STREQ (b, "inf"); Line 451
/* 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); Line 455
b = trim_leading_zeros (b); Line 456
size_t p_len = strlen (a); Line 458
size_t q_len = inf ? 0 : strlen (b); Line 459
/* 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); Line 463
/* Copy input strings (incl NUL) to end of new buffers. */
char *p0 = xmalloc (inc_size + 1); Line 466
char *p = memcpy (p0 + inc_size - p_len, a, p_len + 1); Line 467
char *q; Line 468
char *q0; Line 469
if (! inf) Line 470
{
q0 = xmalloc (inc_size + 1); Line 472
q = memcpy (q0 + inc_size - q_len, b, q_len + 1); Line 473
}
else Line 475
q = q0 = NULL; Line 476
bool ok = inf || cmp (p, p_len, q, q_len) <= 0; Line 478
if (ok) Line 479
{
/* 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. */
size_t buf_size = MAX (BUFSIZ, (inc_size + 1) * 2); Line 484
char *buf = xmalloc (buf_size); Line 485
char const *buf_end = buf + buf_size; Line 486
char *bufp = buf; Line 488
/* Write first number to buffer. */
bufp = mempcpy (bufp, p, p_len); Line 491
/* Append separator then number. */
while (inf || cmp (p, p_len, q, q_len) < 0) Line 494
{
*bufp++ = *separator; Line 496
incr (&p, &p_len); Line 497
/* Double up the buffers when needed for the inf case. */
if (p_len == inc_size) Line 500
{
inc_size *= 2; Line 502
p0 = xrealloc (p0, inc_size + 1); Line 503
p = memmove (p0 + p_len, p0, p_len + 1); Line 504
if (buf_size < (inc_size + 1) * 2) Line 506
{
size_t buf_offset = bufp - buf; Line 508
buf_size = (inc_size + 1) * 2; Line 509
buf = xrealloc (buf, buf_size); Line 510
buf_end = buf + buf_size; Line 511
bufp = buf + buf_offset; Line 512
}
}
bufp = mempcpy (bufp, p, p_len); Line 516
/* If no place for another separator + number then
output buffer so far, and reset to start of buffer. */
if (buf_end - (p_len + 1) < bufp) Line 519
{
if (fwrite (buf, bufp - buf, 1, stdout) != 1) Line 521...!syscalls auto-comment...
io_error (); Line 522
bufp = buf; Line 523
}
}
/* Write any remaining buffered output, and the terminator. */
*bufp++ = *terminator; Line 528
if (fwrite (buf, bufp - buf, 1, stdout) != 1) Line 529...!syscalls auto-comment...
io_error (); Line 530
IF_LINT (free (buf)); Line 532
}
free (p0); Line 535
free (q0); Line 536
return ok; Line 537
} Block 13
/* Return true if S consists of at least one digit and no non-digits. */
static bool _GL_ATTRIBUTE_PURE Line 541
all_digits_p (char const *s) Line 542
{
size_t n = strlen (s); Line 544
return ISDIGIT (s[0]) && n == strspn (s, "0123456789"); Line 545
} Block 14
int
main (int argc, char **argv) Line 549
{
int optc; Line 551
operand first = { 1, 1, 0 }; Line 552
operand step = { 1, 1, 0 }; Line 553
operand last; Line 554
struct layout layout = { 0, 0 }; Line 555
/* The printf(3) format used for output. */
char const *format_str = NULL; Line 558
initialize_main (&argc, &argv); VMS-specific entry point handling wildcard expansion
set_program_name (argv[0]); Retains program name and discards path
setlocale (LC_ALL, ""); Sets up internationalization (i18n)
bindtextdomain (PACKAGE, LOCALEDIR); Assigns i18n directorySets text domain for _() [gettext()] function
textdomain (PACKAGE); Sets text domain for _() [gettext()] function
atexit (close_stdout); Close stdout on exit (see gnulib)
equal_width = false; Line 568
separator = "\n"; Line 569
/* We have to handle negative numbers in the command line but this
conflicts with the command line arguments. So explicitly check first
whether the next argument looks like a negative number. */
while (optind < argc) Line 574
{
if (argv[optind][0] == '-' Line 576
&& ((optc = argv[optind][1]) == '.' || ISDIGIT (optc))) Line 577
{
/* means negative number */
break; Line 580
}
optc = getopt_long (argc, argv, "+f:s:w", long_options, NULL); Line 583
if (optc == -1) Line 584
break; Line 585
switch (optc) Line 587
{
case 'f': Line 589
format_str = optarg; Line 590
break; Line 591
case 's': Line 593
separator = optarg; Line 594
break; Line 595
case 'w': Line 597
equal_width = true; Line 598
break; Line 599
case_GETOPT_HELP_CHAR; Line 601
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); Line 603
default: Line 605
usage (EXIT_FAILURE); Line 606
}
}
unsigned int n_args = argc - optind; Line 610
if (n_args < 1) Line 611
{
error (0, 0, _("missing operand")); Line 613
usage (EXIT_FAILURE); Line 614
}
if (3 < n_args) Line 617
{
error (0, 0, _("extra operand %s"), quote (argv[optind + 3])); Line 619
usage (EXIT_FAILURE); Line 620
}
if (format_str) Line 623
format_str = long_double_format (format_str, &layout); Line 624
if (format_str != NULL && equal_width) Line 626
{
error (0, 0, _("format string may not be specified" Line 628
" when printing equal width strings")); Line 629
usage (EXIT_FAILURE); Line 630
}
/* If the following hold:
- no format string, [FIXME: relax this, eventually]
- integer start (or no start)
- integer end
- increment == 1 or not specified [FIXME: relax this, eventually]
then use the much more efficient integer-only code. */
if (all_digits_p (argv[optind]) Line 639
&& (n_args == 1 || all_digits_p (argv[optind + 1])) Line 640
&& (n_args < 3 || (STREQ ("1", argv[optind + 1]) Line 641
&& all_digits_p (argv[optind + 2]))) Line 642
&& !equal_width && !format_str && strlen (separator) == 1) Line 643
{
char const *s1 = n_args == 1 ? "1" : argv[optind]; Line 645
char const *s2 = argv[optind + (n_args - 1)]; Line 646
if (seq_fast (s1, s2)) Line 647
return EXIT_SUCCESS; Line 648
/* Upon any failure, let the more general code deal with it. */
}
last = scan_arg (argv[optind++]); Line 653
if (optind < argc) Line 655
{
first = last; Line 657
last = scan_arg (argv[optind++]); Line 658
if (optind < argc) Line 660
{
step = last; Line 662
if (step.value == 0) Line 663
{
error (0, 0, _("invalid Zero increment value: %s"), Line 665
quote (argv[optind-1])); Line 666
usage (EXIT_FAILURE); Line 667
}
last = scan_arg (argv[optind++]); Line 670
}
}
if ((isfinite (first.value) && first.precision == 0) Line 674
&& step.precision == 0 && last.precision == 0 Line 675
&& 0 <= first.value && step.value == 1 && 0 <= last.value Line 676
&& !equal_width && !format_str && strlen (separator) == 1) Line 677
{
char *s1; Line 679
char *s2; Line 680
if (asprintf (&s1, "%0.Lf", first.value) < 0) Line 681
xalloc_die (); ...!common auto-comment...
if (! isfinite (last.value)) Line 683
s2 = xstrdup ("inf"); /* Ensure "inf" is used. */ Line 684
else if (asprintf (&s2, "%0.Lf", last.value) < 0) Line 685
xalloc_die (); ...!common auto-comment...
if (*s1 != '-' && *s2 != '-' && seq_fast (s1, s2)) Line 688
{
IF_LINT (free (s1)); Line 690
IF_LINT (free (s2)); Line 691
return EXIT_SUCCESS; Line 692
}
free (s1); Line 695
free (s2); Line 696
/* Upon any failure, let the more general code deal with it. */
}
if (format_str == NULL) Line 700
format_str = get_default_format (first, step, last); Line 701
print_numbers (format_str, layout, first.value, step.value, last.value); Line 703
return EXIT_SUCCESS; Line 705
} Block 15