diff --git a/src/seq.c b/src/seq.c
index 997fd73..377836a 100644
--- a/src/seq.c
+++ b/src/seq.c
@@ -19,6 +19,9 @@
#include <config.h>
#include <getopt.h>
+// Reintroduce header inclusion as it is necessary for the old version
+#include <math.h>
+// ---------------
#include <stdio.h>
#include <sys/types.h>
@@ -26,6 +29,9 @@
#include "c-strtod.h"
#include "error.h"
#include "quote.h"
+// Reintroduce header inclusion as it is necessary for the old version
+#include "xstrtol.h"
+// ---------------
#include "xstrtod.h"
/* Roll our own isfinite rather than using <math.h>, so that we don't
@@ -53,6 +59,21 @@ static char const *separator;
/* FIXME: make this an option. */
static char const terminator[] = "\n";
+
+// From the old version
+/* The representation of the decimal point in the current locale. */
+static char decimal_point;
+
+/* The starting number. */
+static double old_first;
+
+/* The increment. */
+static double old_step = 1.0;
+
+/* The last number. */
+static double old_last;
+// =======================================
+
static struct option const long_options[] =
{
{ "equal-width", no_argument, NULL, 'w'},
@@ -133,10 +154,11 @@ scan_arg (const char *arg)
usage (EXIT_FAILURE);
}
+ // Those fields are introduced in the new version, no point to model them with change
ret.width = strlen (arg);
ret.precision = INT_MAX;
- if (! arg[strcspn (arg, "eExX")] && isfinite (ret.value))
+ if (change(0, ! arg[strcspn (arg, "eExX")] && isfinite (ret.value)))
{
char const *decimal_point = strchr (arg, '.');
if (! decimal_point)
@@ -211,8 +233,8 @@ print_numbers (char const *fmt,
for (i = 0; /* empty */; i++)
{
- long double x = first + i * step;
- if (step < 0 ? x < last : last < x)
+ long double x = change(old_first, first) + i * change(old_step, step);
+ if (change(old_step, step) < 0 ? x < change(old_last, last) : change(old_last, last) < x)
break;
if (i)
fputs (separator, stdout);
@@ -223,6 +245,103 @@ print_numbers (char const *fmt,
fputs (terminator, stdout);
}
+// From the old version:
+
+#if HAVE_RINT && HAVE_MODF && HAVE_FLOOR
+
+/* Return a printf-style format string with which all selected numbers
+ will format to strings of the same width. */
+
+static char *
+get_width_format (void)
+{
+ static char buffer[256];
+ int full_width;
+ int frac_width;
+ int width1, width2;
+ double max_val;
+ double min_val;
+ double temp;
+
+ if (old_first > old_last)
+ {
+ min_val = old_first - old_step * floor ((old_first - old_last) / old_step);
+ max_val = old_first;
+ }
+ else
+ {
+ min_val = old_first;
+ max_val = old_first + old_step * floor ((old_last - old_first) / old_step);
+ }
+
+ sprintf (buffer, "%g", rint (max_val));
+ if (buffer[strspn (buffer, "-0123456789")] != '\0')
+ return "%g";
+ width1 = strlen (buffer);
+
+ if (min_val < 0.0)
+ {
+ double int_min_val = rint (min_val);
+ sprintf (buffer, "%g", int_min_val);
+ if (buffer[strspn (buffer, "-0123456789")] != '\0')
+ return "%g";
+ /* On some systems, `seq -w -.1 .1 .1' results in buffer being `-0'.
+ On others, it is just `0'. The former results in better output. */
+ width2 = (int_min_val == 0 ? 2 : strlen (buffer));
+
+ width1 = width1 > width2 ? width1 : width2;
+ }
+ full_width = width1;
+
+ sprintf (buffer, "%g", 1.0 + modf (fabs (min_val), &temp));
+ width1 = strlen (buffer);
+ if (width1 == 1)
+ width1 = 0;
+ else
+ {
+ if (buffer[0] != '1'
+ || buffer[1] != decimal_point
+ || buffer[2 + strspn (&buffer[2], "0123456789")] != '\0')
+ return "%g";
+ width1 -= 2;
+ }
+
+ sprintf (buffer, "%g", 1.0 + modf (fabs (old_step), &temp));
+ width2 = strlen (buffer);
+ if (width2 == 1)
+ width2 = 0;
+ else
+ {
+ if (buffer[0] != '1'
+ || buffer[1] != decimal_point
+ || buffer[2 + strspn (&buffer[2], "0123456789")] != '\0')
+ return "%g";
+ width2 -= 2;
+ }
+ frac_width = width1 > width2 ? width1 : width2;
+
+ if (frac_width)
+ sprintf (buffer, "%%0%d.%df", full_width + 1 + frac_width, frac_width);
+ else
+ sprintf (buffer, "%%0%dg", full_width);
+
+ return buffer;
+}
+
+#else /* one of the math functions rint, modf, floor is missing. */
+
+static char *
+get_width_format (void)
+{
+ /* We cannot compute the needed information to determine the correct
+ answer. So we simply return a value that works for all cases. */
+ return "%g";
+}
+
+#endif
+
+// =======================
+
/* Return the default format given FIRST, STEP, and LAST. */
static char const *
get_default_format (operand first, operand step, operand last)
@@ -281,13 +400,32 @@ main (int argc, char **argv)
equal_width = false;
separator = "\n";
+ // This is in the old version only (global variable)
+ old_first = 1.0;
+
+ {
+ // We can model this without if (change(1, 0)) ?
+ // because localeconv () does not have side effects.
+ /* Get locale's representation of the decimal point. */
+ struct lconv const *locale = localeconv ();
+
+ /* If the locale doesn't define a decimal point, or if the decimal
+ point is multibyte, use the C locale's decimal point. FIXME:
+ add support for multibyte decimal points. */
+
+ // No need to model this, global variable decimal_point present in the new old version only
+ decimal_point = locale->decimal_point[0];
+ if (! decimal_point || locale->decimal_point[1])
+ decimal_point = '.';
+ }
+
/* 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)
{
if (argv[optind][0] == '-'
- && ((optc = argv[optind][1]) == '.' || ISDIGIT (optc)))
+ && ((optc = argv[optind][1]) == change(decimal_point, '.') || ISDIGIT (optc)))
{
/* means negative number */
break;
@@ -332,15 +470,19 @@ main (int argc, char **argv)
usage (EXIT_FAILURE);
}
- if (format_str)
+ // This would work if the corresponding functions
+ // + static char const *long_double_format (char const *fmt) and
+ // - static bool valid_format (const char *fmt)
+ // have no side effects, to reconsider
+ if (format_str && change(valid_format (format_str), 1))
{
char const *f = long_double_format (format_str);
- if (! f)
+ if (change(1, ! f))
{
error (0, 0, _("invalid format string: %s"), quote (format_str));
usage (EXIT_FAILURE);
}
- format_str = f;
+ format_str = change(format_str, f);
}
last = scan_arg (argv[optind++]);
@@ -364,8 +506,11 @@ format string may not be specified when printing equal width strings"));
usage (EXIT_FAILURE);
}
+ // assuming get_width_format() and get_default_format() have no side effects, to be reconsidered
if (format_str == NULL)
- format_str = get_default_format (first, step, last);
+ format_str = change(
+ equal_width ? get_width_format () : "%g",
+ get_default_format (first, step, last));
print_numbers (format_str, first.value, step.value, last.value);