Good Day
To print a sequence of numbers, I use GNU seq command, but the switch -w which equalizes width by padding with leading zeroes, does not work over 999999 ???
Also numbers over 999999 are shown as scientific notation 6.022E06 !!!
Please can someone check the source code ?
Thanks a lot
Ed
-----------------------------------------------------------------------------------
#include <config.h>
#include <getopt.h>
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
#include "c-strtod.h"
#include "error.h"
#include "quote.h"
#include "xstrtod.h"
#ifndef isfinite
# define isfinite(x) ((x) * 0 == 0)
#endif
#define PROGRAM_NAME "seq"
#define AUTHORS proper_name ("Ulrich Drepper")
static bool equal_width;
static char const *separator;
static char const terminator[] = "\n";
static struct option const long_options[] =
{
{ "equal-width", no_argument, NULL, 'w'},
{ "format", required_argument, NULL, 'f'},
{ "separator", required_argument, NULL, 's'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{ NULL, 0, NULL, 0}
};
void
usage (int status)
{
if (status != EXIT_SUCCESS)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... LAST\n\
or: %s [OPTION]... FIRST LAST\n\
or: %s [OPTION]... FIRST INCREMENT LAST\n\
"), program_name, program_name, program_name);
fputs (_("\
Print numbers from FIRST to LAST, in steps of INCREMENT.\n\
\n\
-f, --format=FORMAT use printf style floating-point FORMAT\n\
-s, --separator=STRING use STRING to separate numbers (default: \\n)\n\
-w, --equal-width equalize width by padding with leading zeroes\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
If FIRST or INCREMENT is omitted, it defaults to 1. That is, an\n\
omitted INCREMENT defaults to 1 even when LAST is smaller than FIRST.\n\
FIRST, INCREMENT, and LAST are interpreted as floating point values.\n\
INCREMENT is usually positive if FIRST is smaller than LAST, and\n\
INCREMENT is usually negative if FIRST is greater than LAST.\n\
"), stdout);
fputs (_("\
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 ();
}
exit (status);
}
struct operand
{
long double value;
size_t width;
int precision;
};
typedef struct operand operand;
struct layout
{
size_t prefix_len;
size_t suffix_len;
};
static operand
scan_arg (const char *arg)
{
operand ret;
if (! xstrtold (arg, NULL, &ret.value, c_strtold))
{
error (0, 0, _("invalid floating point argument: %s"), arg);
usage (EXIT_FAILURE);
}
while (isspace (to_uchar (*arg)) || *arg == '+')
arg++;
ret.width = strlen (arg);
ret.precision = INT_MAX;
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 = strcspn (decimal_point + 1, "eE");
if (fraction_len <= INT_MAX)
ret.precision = fraction_len;
ret.width += (fraction_len == 0
? -1
: (decimal_point == arg
|| ! ISDIGIT (decimal_point[-1])));
}
char const *e = strchr (arg, 'e');
if (! e)
e = strchr (arg, 'E');
if (e)
{
long exponent = strtol (e + 1, NULL, 10);
ret.precision += exponent < 0 ? -exponent : 0;
}
}
return ret;
}
static char const *
long_double_format (char const *fmt, struct layout *layout)
{
size_t i;
size_t prefix_len = 0;
size_t suffix_len = 0;
size_t length_modifier_offset;
bool has_L;
for (i = 0; ! (fmt[i] == '%' && fmt[i + 1] != '%'); i += (fmt[i] == '%') + 1)
{
if (!fmt[i])
error (EXIT_FAILURE, 0,
_("format %s has no %% directive"), quote (fmt));
prefix_len++;
}
i++;
i += strspn (fmt + i, "-+#0 '");
i += strspn (fmt + i, "0123456789");
if (fmt[i] == '.')
{
i++;
i += strspn (fmt + i, "0123456789");
}
length_modifier_offset = i;
has_L = (fmt[i] == 'L');
i += has_L;
if (fmt[i] == '\0')
error (EXIT_FAILURE, 0, _("format %s ends in %%"), quote (fmt));
if (! strchr ("efgaEFGA", fmt[i]))
error (EXIT_FAILURE, 0,
_("format %s has unknown %%%c directive"), quote (fmt), fmt[i]);
for (i++; ; i += (fmt[i] == '%') + 1)
if (fmt[i] == '%' && fmt[i + 1] != '%')
error (EXIT_FAILURE, 0, _("format %s has too many %% directives"),
quote (fmt));
else if (fmt[i])
suffix_len++;
else
{
size_t format_size = i + 1;
char *ldfmt = xmalloc (format_size + 1);
memcpy (ldfmt, fmt, length_modifier_offset);
ldfmt[length_modifier_offset] = 'L';
strcpy (ldfmt + length_modifier_offset + 1,
fmt + length_modifier_offset + has_L);
layout->prefix_len = prefix_len;
layout->suffix_len = suffix_len;
return ldfmt;
}
}
static void
print_numbers (char const *fmt, struct layout layout,
long double first, long double step, long double last)
{
bool out_of_range = (step < 0 ? first < last : last < first);
if (! out_of_range)
{
long double x = first;
long double i;
for (i = 1; ; i++)
{
long double x0 = x;
printf (fmt, x);
if (out_of_range)
break;
x = first + i * step;
out_of_range = (step < 0 ? x < last : last < x);
if (out_of_range)
{
bool print_extra_number = false;
long double x_val;
char *x_str;
int x_strlen;
setlocale (LC_NUMERIC, "C");
x_strlen = asprintf (&x_str, fmt, x);
setlocale (LC_NUMERIC, "");
if (x_strlen < 0)
xalloc_die ();
x_str[x_strlen - layout.suffix_len] = '\0';
if (xstrtold (x_str + layout.prefix_len, NULL, &x_val, c_strtold)
&& x_val == last)
{
char *x0_str = NULL;
if (asprintf (&x0_str, fmt, x0) < 0)
xalloc_die ();
print_extra_number = !STREQ (x0_str, x_str);
free (x0_str);
}
free (x_str);
if (! print_extra_number)
break;
}
fputs (separator, stdout);
}
fputs (terminator, stdout);
}
}
static char const *
get_default_format (operand first, operand step, operand last)
{
static char format_buf[sizeof "%0.Lf" + 2 * INT_STRLEN_BOUND (int)];
int prec = MAX (first.precision, step.precision);
if (prec != INT_MAX && last.precision != INT_MAX)
{
if (equal_width)
{
size_t first_width = first.width + (prec - first.precision);
size_t last_width = last.width + (prec - last.precision);
if (last.precision && prec == 0)
last_width--;
if (last.precision == 0 && prec)
last_width++;
size_t width = MAX (first_width, last_width);
if (width <= INT_MAX)
{
int w = width;
sprintf (format_buf, "%%0%d.%dLf", w, prec);
return format_buf;
}
}
else
{
sprintf (format_buf, "%%.%dLf", prec);
return format_buf;
}
}
return "%Lg";
}
int
main (int argc, char **argv)
{
int optc;
operand first = { 1, 1, 0 };
operand step = { 1, 1, 0 };
operand last;
struct layout layout = { 0, 0 };
char const *format_str = NULL;
initialize_main (&argc, &argv);
set_program_name (argv[0]);
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
equal_width = false;
separator = "\n";
while (optind < argc)
{
if (argv[optind][0] == '-'
&& ((optc = argv[optind][1]) == '.' || ISDIGIT (optc)))
{
break;
}
optc = getopt_long (argc, argv, "+f:s:w", long_options, NULL);
if (optc == -1)
break;
switch (optc)
{
case 'f':
format_str = optarg;
break;
case 's':
separator = optarg;
break;
case 'w':
equal_width = true;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (argc - optind < 1)
{
error (0, 0, _("missing operand"));
usage (EXIT_FAILURE);
}
if (3 < argc - optind)
{
error (0, 0, _("extra operand %s"), quote (argv[optind + 3]));
usage (EXIT_FAILURE);
}
if (format_str)
format_str = long_double_format (format_str, &layout);
last = scan_arg (argv[optind++]);
if (optind < argc)
{
first = last;
last = scan_arg (argv[optind++]);
if (optind < argc)
{
step = last;
last = scan_arg (argv[optind++]);
}
}
if (format_str != NULL && equal_width)
{
error (0, 0, _("\
format string may not be specified when printing equal width strings"));
usage (EXIT_FAILURE);
}
if (format_str == NULL)
format_str = get_default_format (first, step, last);
print_numbers (format_str, layout, first.value, step.value, last.value);
exit (EXIT_SUCCESS);
}