1 /* seq - print sequence of numbers to standard output.
2 Copyright (C) 1994-1999 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Written by Ulrich Drepper. */
24 #include <sys/types.h>
28 #include "long-options.h"
31 static double scan_double_arg PARAMS ((const char *arg));
32 static int check_format PARAMS ((const char *format_string));
33 static char *get_width_format PARAMS ((void));
34 static int print_numbers PARAMS ((const char *format_str));
36 /* If nonzero print all number with equal width. */
37 static int equal_width;
39 /* The printf(3) format used for output. */
40 static char *format_str;
42 /* The starting number. */
45 /* The name that this program was run with. */
48 /* The string used to separate two numbers. */
49 static char *separator;
51 /* The string output after all numbers have been output.
52 Usually "\n" or "\0". */
53 /* FIXME: make this an option. */
54 static char *terminator = "\n";
59 /* The last number. */
62 static struct option const long_options[] =
64 { "equal-width", no_argument, NULL, 'w'},
65 { "format", required_argument, NULL, 'f'},
66 { "separator", required_argument, NULL, 's'},
74 fprintf (stderr, _("Try `%s --help' for more information.\n"),
79 Usage: %s [OPTION]... LAST\n\
80 or: %s [OPTION]... FIRST LAST\n\
81 or: %s [OPTION]... FIRST INCREMENT LAST\n\
82 "), program_name, program_name, program_name);
84 Print numbers from FIRST to LAST, in steps of INCREMENT.\n\
86 -f, --format FORMAT use printf(3) style FORMAT (default: %%g)\n\
87 -s, --separator STRING use STRING to separate numbers (default: \\n)\n\
88 -w, --equal-width equalize width by padding with leading zeroes\n\
89 --help display this help and exit\n\
90 --version output version information and exit\n\
92 If FIRST or INCREMENT is omitted, it defaults to 1.\n\
93 FIRST, INCREMENT, and LAST are interpreted as floating point values.\n\
94 INCREMENT should be positive if FIRST is smaller than LAST, and negative\n\
95 otherwise. When given, the FORMAT argument must contain exactly one of\n\
96 the printf-style, floating point output formats %%e, %%f, or %%g.\n\
98 puts (_("\nReport bugs to <bug-sh-utils@gnu.org>."));
104 main (int argc, char **argv)
110 program_name = argv[0];
111 setlocale (LC_ALL, "");
112 bindtextdomain (PACKAGE, LOCALEDIR);
113 textdomain (PACKAGE);
115 parse_long_options (argc, argv, "seq", GNU_PACKAGE, VERSION,
116 "Ulrich Drepper", usage);
124 /* We have to handle negative numbers in the command line but this
125 conflicts with the command line arguments. So the getopt mode is
126 REQUIRE_ORDER (the '+' in the format string) and it abort on the
127 first non-option or negative number. */
128 while ((optc = getopt_long (argc, argv, "+0123456789f:s:w", long_options,
131 if ('0' <= optc && optc <= '9')
133 /* means negative number */
163 error (0, 0, _("too few arguments"));
167 last = scan_double_arg (argv[optind++]);
172 last = scan_double_arg (argv[optind++]);
178 last = scan_double_arg (argv[optind++]);
188 if (format_str != NULL && equal_width)
191 format string may not be specified when printing equal width strings"));
197 step = first <= last ? 1.0 : -1.0;
200 if (format_str != NULL)
202 if (!check_format (format_str))
204 error (0, 0, _("invalid format string: `%s'"), format_str);
211 format_str = get_width_format ();
216 errs = print_numbers (format_str);
222 /* Read a double value from the command line.
223 Return if the string is correct else signal error. */
226 scan_double_arg (const char *arg)
230 if (xstrtod (arg, NULL, &ret_val))
232 error (0, 0, _("invalid floating point argument: %s"), arg);
240 /* Check whether the format string is valid for a single double
242 Return 0 if not, 1 if correct. */
245 check_format (const char *fmt)
261 fmt += strspn (fmt, "-+#0");
264 fmt += strspn (fmt, "0123456789");
267 fmt += strspn (++fmt, "0123456789");
270 if (*fmt != 'e' && *fmt != 'f' && *fmt != 'g')
289 #if defined (HAVE_RINT) && defined (HAVE_MODF) && defined (HAVE_FLOOR)
291 /* Return a printf-style format string with which all selected numbers
292 will format to strings of the same width. */
297 static char buffer[256];
307 min_val = first - step * floor ((first - last) / step);
313 max_val = first + step * floor ((last - first) / step);
316 sprintf (buffer, "%g", rint (max_val));
317 if (buffer[strspn (buffer, "0123456789")] != '\0')
319 width1 = strlen (buffer);
323 sprintf (buffer, "%g", rint (min_val));
324 if (buffer[strspn (buffer, "-0123456789")] != '\0')
326 width2 = strlen (buffer);
328 width1 = width1 > width2 ? width1 : width2;
332 sprintf (buffer, "%g", 1.0 + modf (min_val, &temp));
333 width1 = strlen (buffer);
338 if (buffer[0] != '1' || buffer[1] != '.' ||
339 buffer[2 + strspn (&buffer[2], "0123456789")] != '\0')
344 sprintf (buffer, "%g", 1.0 + modf (step, &temp));
345 width2 = strlen (buffer);
350 if (buffer[0] != '1' || buffer[1] != '.' ||
351 buffer[2 + strspn (&buffer[2], "0123456789")] != '\0')
355 frac_width = width1 > width2 ? width1 : width2;
358 sprintf (buffer, "%%0%d.%df", full_width + 1 + frac_width, frac_width);
360 sprintf (buffer, "%%0%dg", full_width);
365 #else /* one of the math functions rint, modf, floor is missing. */
368 get_width_format (void)
370 /* We cannot compute the needed information to determine the correct
371 answer. So we simply return a value that works for all cases. */
377 /* Actually print the sequence of numbers in the specified range, with the
378 given or default stepping and format. */
380 print_numbers (const char *fmt)
389 _("when the starting value is larger than the limit,\n\
390 the increment must be negative"));
396 for (i = 1; /* empty */; i++)
398 double x = first + i * step;
403 fputs (separator, stdout);
414 _("when the starting value is smaller than the limit,\n\
415 the increment must be positive"));
421 for (i = 1; /* empty */; i++)
423 double x = first + i * step;
428 fputs (separator, stdout);
429 printf (format_str, x);
432 fputs (terminator, stdout);