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 /* The official name of this program (e.g., no `g' prefix). */
32 #define PROGRAM_NAME "seq"
34 #define AUTHORS "Ulrich Drepper"
36 static double scan_double_arg PARAMS ((const char *arg));
37 static int check_format PARAMS ((const char *format_string));
38 static char *get_width_format PARAMS ((void));
39 static int print_numbers PARAMS ((const char *format_str));
41 /* If nonzero print all number with equal width. */
42 static int equal_width;
44 /* The printf(3) format used for output. */
45 static char *format_str;
47 /* The starting number. */
50 /* The name that this program was run with. */
53 /* The string used to separate two numbers. */
54 static char *separator;
56 /* The string output after all numbers have been output.
57 Usually "\n" or "\0". */
58 /* FIXME: make this an option. */
59 static char *terminator = "\n";
64 /* The last number. */
67 static struct option const long_options[] =
69 { "equal-width", no_argument, NULL, 'w'},
70 { "format", required_argument, NULL, 'f'},
71 { "separator", required_argument, NULL, 's'},
79 fprintf (stderr, _("Try `%s --help' for more information.\n"),
84 Usage: %s [OPTION]... LAST\n\
85 or: %s [OPTION]... FIRST LAST\n\
86 or: %s [OPTION]... FIRST INCREMENT LAST\n\
87 "), program_name, program_name, program_name);
89 Print numbers from FIRST to LAST, in steps of INCREMENT.\n\
91 -f, --format FORMAT use printf(3) style FORMAT (default: %%g)\n\
92 -s, --separator STRING use STRING to separate numbers (default: \\n)\n\
93 -w, --equal-width equalize width by padding with leading zeroes\n\
94 --help display this help and exit\n\
95 --version output version information and exit\n\
97 If FIRST or INCREMENT is omitted, it defaults to 1.\n\
98 FIRST, INCREMENT, and LAST are interpreted as floating point values.\n\
99 INCREMENT should be positive if FIRST is smaller than LAST, and negative\n\
100 otherwise. When given, the FORMAT argument must contain exactly one of\n\
101 the printf-style, floating point output formats %%e, %%f, or %%g.\n\
103 puts (_("\nReport bugs to <bug-sh-utils@gnu.org>."));
109 main (int argc, char **argv)
115 program_name = argv[0];
116 setlocale (LC_ALL, "");
117 bindtextdomain (PACKAGE, LOCALEDIR);
118 textdomain (PACKAGE);
120 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
129 /* We have to handle negative numbers in the command line but this
130 conflicts with the command line arguments. So the getopt mode is
131 REQUIRE_ORDER (the '+' in the format string) and it abort on the
132 first non-option or negative number. */
133 while ((optc = getopt_long (argc, argv, "+0123456789f:s:w", long_options,
136 if ('0' <= optc && optc <= '9')
138 /* means negative number */
168 error (0, 0, _("too few arguments"));
172 last = scan_double_arg (argv[optind++]);
177 last = scan_double_arg (argv[optind++]);
183 last = scan_double_arg (argv[optind++]);
193 if (format_str != NULL && equal_width)
196 format string may not be specified when printing equal width strings"));
202 step = first <= last ? 1.0 : -1.0;
205 if (format_str != NULL)
207 if (!check_format (format_str))
209 error (0, 0, _("invalid format string: `%s'"), format_str);
216 format_str = get_width_format ();
221 errs = print_numbers (format_str);
227 /* Read a double value from the command line.
228 Return if the string is correct else signal error. */
231 scan_double_arg (const char *arg)
235 if (xstrtod (arg, NULL, &ret_val))
237 error (0, 0, _("invalid floating point argument: %s"), arg);
245 /* Check whether the format string is valid for a single double
247 Return 0 if not, 1 if correct. */
250 check_format (const char *fmt)
266 fmt += strspn (fmt, "-+#0");
269 fmt += strspn (fmt, "0123456789");
272 fmt += strspn (++fmt, "0123456789");
275 if (*fmt != 'e' && *fmt != 'f' && *fmt != 'g')
294 #if defined (HAVE_RINT) && defined (HAVE_MODF) && defined (HAVE_FLOOR)
296 /* Return a printf-style format string with which all selected numbers
297 will format to strings of the same width. */
302 static char buffer[256];
312 min_val = first - step * floor ((first - last) / step);
318 max_val = first + step * floor ((last - first) / step);
321 sprintf (buffer, "%g", rint (max_val));
322 if (buffer[strspn (buffer, "0123456789")] != '\0')
324 width1 = strlen (buffer);
328 sprintf (buffer, "%g", rint (min_val));
329 if (buffer[strspn (buffer, "-0123456789")] != '\0')
331 width2 = strlen (buffer);
333 width1 = width1 > width2 ? width1 : width2;
337 sprintf (buffer, "%g", 1.0 + modf (min_val, &temp));
338 width1 = strlen (buffer);
343 if (buffer[0] != '1' || buffer[1] != '.' ||
344 buffer[2 + strspn (&buffer[2], "0123456789")] != '\0')
349 sprintf (buffer, "%g", 1.0 + modf (step, &temp));
350 width2 = strlen (buffer);
355 if (buffer[0] != '1' || buffer[1] != '.' ||
356 buffer[2 + strspn (&buffer[2], "0123456789")] != '\0')
360 frac_width = width1 > width2 ? width1 : width2;
363 sprintf (buffer, "%%0%d.%df", full_width + 1 + frac_width, frac_width);
365 sprintf (buffer, "%%0%dg", full_width);
370 #else /* one of the math functions rint, modf, floor is missing. */
373 get_width_format (void)
375 /* We cannot compute the needed information to determine the correct
376 answer. So we simply return a value that works for all cases. */
382 /* Actually print the sequence of numbers in the specified range, with the
383 given or default stepping and format. */
385 print_numbers (const char *fmt)
394 _("when the starting value is larger than the limit,\n\
395 the increment must be negative"));
401 for (i = 1; /* empty */; i++)
403 double x = first + i * step;
408 fputs (separator, stdout);
419 _("when the starting value is smaller than the limit,\n\
420 the increment must be positive"));
426 for (i = 1; /* empty */; i++)
428 double x = first + i * step;
433 fputs (separator, stdout);
434 printf (format_str, x);
437 fputs (terminator, stdout);