seq.c (2798B)
- // utils-std: Collection of commonly available Unix tools
- // SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
- // SPDX-License-Identifier: MPL-2.0
- #define _POSIX_C_SOURCE 200809L
- #include <ctype.h> // isdigit
- #include <errno.h> // errno
- #include <math.h> // fabs
- #include <stdbool.h> // bool, true, false
- #include <stdio.h> // fprintf
- #include <stdlib.h> // exit, strtod
- #include <string.h> // strerror
- #include <unistd.h> // getopt, optarg, optind
- const char *sep = "\n";
- const char *term = "\n";
- int len = 0;
- bool opt_w = false;
- double g_last = 1.0;
- static void
- seq(double i, double step, double last)
- {
- printf("%0*g", len, i);
- if(i < last)
- {
- while((i + step) <= last)
- printf("%s%0*g", sep, len, i += step);
- }
- else if(i > last)
- {
- while((i - step) >= last)
- printf("%s%0*g", sep, len, i -= step);
- }
- printf("%s", term);
- if(opt_w && i != g_last)
- fprintf(stderr, "seq: error: Failed to guess last, got: %g; expected: %g\n", i, g_last);
- }
- static double
- get_num(char *str)
- {
- errno = 0;
- char *endptr = NULL;
- double num = strtod(str, &endptr);
- if(errno != 0)
- {
- fprintf(stderr, "seq: error: strtod(\"%s\"): %s\n", str, strerror(errno));
- exit(1);
- }
- if(!(endptr == NULL || endptr[0] == 0))
- {
- fprintf(stderr,
- "seq: error: strtod(\"%s\"), invalid remaining characters found '%s'\n",
- str,
- endptr);
- exit(1);
- }
- return num;
- }
- static void
- usage(void)
- {
- fprintf(stderr, "usage: seq [-w] [-s separator] [first [step]] last\n");
- }
- int
- main(int argc, char *argv[])
- {
- int c;
- while((c = getopt(argc, argv, ":ws:t:")) != -1)
- {
- switch(c)
- {
- case 'w':
- opt_w = true;
- break;
- case 's':
- sep = optarg;
- break;
- case 't':
- term = optarg;
- break;
- case ':':
- fprintf(stderr, "seq: error: Option -%c requires an operand\n", optopt);
- usage();
- return 1;
- case '?':
- if(isdigit(optopt))
- {
- fprintf(stderr,
- "seq: warning: Pass -- if the first non-option argument starts with a dash(-)\n");
- optind--;
- goto getopt_end;
- }
- usage();
- return 1;
- }
- }
- getopt_end:
- argc -= optind;
- argv += optind;
- double first = 1.0;
- double step = 1.0;
- double last = 1.0;
- switch(argc)
- {
- case 1:
- last = get_num(argv[0]);
- break;
- case 2:
- first = get_num(argv[0]);
- last = get_num(argv[1]);
- break;
- case 3:
- first = get_num(argv[0]);
- step = fabs(get_num(argv[1]));
- last = get_num(argv[2]);
- break;
- default:
- usage();
- return 1;
- }
- if(opt_w)
- {
- double f_mod = fmod(first, step);
- double l_mod = fmod(last, step);
- g_last = last - l_mod + f_mod;
- int f_len = snprintf(NULL, 0, "%g", first);
- int l_len = snprintf(NULL, 0, "%g", g_last);
- len = f_len > l_len ? f_len : l_len;
- }
- seq(first, step, last);
- return 0;
- }