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:
M | cmd/seq.c | 110 | ++++++++++++++++++++++++++++++++++++++----------------------------------------- |
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;