logo

utils-std

Collection of commonly available Unix tools
commit: cba1ca39fa8088519928b2dbc0ae7d911fde20b5
parent 2b468c15978601c03613bcf7106ee30d8998167b
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sat, 16 Mar 2024 20:30:25 +0100

cmd/seq: Switch to double to match common implementations

Diffstat:

Mcmd/seq.c110++++++++++++++++++++++++++++++++++++++-----------------------------------------
1 file changed, 53 insertions(+), 57 deletions(-)

diff --git a/cmd/seq.c b/cmd/seq.c @@ -3,69 +3,68 @@ // SPDX-License-Identifier: MPL-2.0 #define _POSIX_C_SOURCE 200809L -#include "../lib/absu.h" - #include <ctype.h> // isdigit #include <errno.h> // errno +#include <math.h> // fabs #include <stdbool.h> // bool, true, false -#include <stdio.h> // puts, fprintf -#include <stdlib.h> // atoi, exit -#include <string.h> // strlen +#include <stdio.h> // fprintf +#include <stdlib.h> // exit, strtod +#include <string.h> // strerror #include <unistd.h> // getopt, optarg, optind char *sep = "\n"; int len = 0; +bool opt_w = false; +double g_last = 1.0; + static void -seq(long i, unsigned long step, long last) +seq(double i, double step, double last) { - if(i == last) - { - printf("%0*li\n", len, i); - } - else if(i < last) - { - for(; i < last; i += step) - printf("%0*li%s", len, i, sep); + printf("%0*g", len, i); - if(i <= last) printf("%0*li\n", len, i); + if(i < last) + { + while((i + step) <= last) + printf("%s%0*g", sep, len, i += step); } else if(i > last) { - for(; i > last; i -= step) - printf("%0*li%s", len, i, sep); - - if(i >= last) printf("%0*li\n", len, i); + while((i - step) >= last) + printf("%s%0*g", sep, len, i -= step); } + + printf("\n"); + + if(opt_w && i != g_last) + fprintf(stderr, "seq: Failed to guess last, got: %g; expected: %g\n", i, g_last); } -static long +static double get_num(char *str) { errno = 0; - long num = strtol(str, NULL, 10); + char *endptr = NULL; + + double num = strtod(str, &endptr); if(errno != 0) { - perror("seq: strtol:"); + fprintf(stderr, "seq: Error strtod(\"%s\"): %s\n", str, strerror(errno)); exit(1); } - return num; -} - -static size_t -digits(char *s) -{ - size_t c = 0; - - if(*s == '-') s++, c++; - - for(; *s != 0; s++) - if(isdigit(*s)) c++; + if(!(endptr == NULL || endptr[0] == 0)) + { + fprintf(stderr, + "seq: Error strtod(\"%s\"), invalid remaining characters found '%s'\n", + str, + endptr); + exit(1); + } - return c; + return num; } static void @@ -78,7 +77,6 @@ int main(int argc, char *argv[]) { int c; - bool opt_w = false; /* flawfinder: ignore. Old implementations of getopt should fix themselves */ while((c = getopt(argc, argv, ":ws:")) != -1) @@ -98,7 +96,8 @@ main(int argc, char *argv[]) case '?': if(isdigit(optopt)) { - fprintf(stderr, "seq: Warning: Pass -- if the first non-option argument starts with a dash(-)\n"); + fprintf(stderr, + "seq: Warning: Pass -- if the first non-option argument starts with a dash(-)\n"); optind--; goto getopt_end; } @@ -111,45 +110,42 @@ getopt_end: argc -= optind; argv += optind; - long first = 1; - unsigned long step = 1; - long last = 1; + double first = 1.0; + double step = 1.0; + double last = 1.0; switch(argc) { case 1: last = get_num(argv[0]); - - if(opt_w) len = digits(argv[0]); break; case 2: first = get_num(argv[0]); last = get_num(argv[1]); - - if(opt_w) - { - size_t f_len = digits(argv[0]); - size_t l_len = digits(argv[1]); - len = f_len > l_len ? f_len : l_len; - } break; case 3: first = get_num(argv[0]); - step = labsu(get_num(argv[1])); + step = fabs(get_num(argv[1])); last = get_num(argv[2]); - - if(opt_w) - { - size_t f_len = digits(argv[0]); - size_t l_len = digits(argv[2]); - len = f_len > l_len ? f_len : l_len; - } break; default: usage(); return 1; } + if(opt_w) + { + double f_mod = remainder(first, step); + double l_mod = remainder(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;