aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Kronqvist <joelkronqvist@proton.me>2024-04-10 16:54:50 +0300
committerJoel Kronqvist <joelkronqvist@proton.me>2024-04-11 16:01:36 +0300
commita793df3e2a07c65f36fb2f5f43d2c51ab0c47bf2 (patch)
tree49858b1ef415ce16c843c4fbb4ab7eccaa73033d
parent4ff6a08d73f0ef1e2fcb7a93a74cc6fa66c24e2b (diff)
downloadstdu-a793df3e2a07c65f36fb2f5f43d2c51ab0c47bf2.tar.gz
stdu-a793df3e2a07c65f36fb2f5f43d2c51ab0c47bf2.zip
Added help message & fixed blocksize bug
The bug was caused by integer overflow with too large precisions.
-rw-r--r--config-parser.c29
-rw-r--r--config-parser.h1
-rw-r--r--intmath.c12
-rw-r--r--intmath.h1
-rw-r--r--stdu.c21
5 files changed, 48 insertions, 16 deletions
diff --git a/config-parser.c b/config-parser.c
index 5e403f8..075ef47 100644
--- a/config-parser.c
+++ b/config-parser.c
@@ -17,6 +17,7 @@ Result parse_config(int argc, char* argv[]) {
Config tmp;
tmp.precision = 0;
tmp.human_readable = false;
+ tmp.help = false;
size_t i = 1;
char* argument;
@@ -25,6 +26,16 @@ Result parse_config(int argc, char* argv[]) {
argument = argv[i];
int comp1 = strcmp(argument, "--precision") == 0;
if (
+ strcmp(argument, "--help") == 0
+ || strcmp(argument, "-?") == 0
+ ) {
+ tmp.help = true;
+ } else if (
+ strcmp(argument, "--human-readable") == 0
+ || strcmp(argument, "-h") == 0
+ ) {
+ tmp.human_readable = true;
+ } else if (
comp1 || strncmp(argument, "-p", 2) == 0
) {
if (precision != NULL) {
@@ -54,21 +65,6 @@ Result parse_config(int argc, char* argv[]) {
return res;
}
precision = argv[i];
- } else if (
- strcmp(argument, "--human-readable") == 0
- || strcmp(argument, "-h") == 0
- ) {
- if (tmp.human_readable != false) {
- char* error_msg = malloc(52);
- snprintf(
- error_msg,
- 52,
- "human readability can't be specified multiple times"
- );
- res.result = error_msg;
- return res;
- }
- tmp.human_readable = true;
} else {
size_t msg_size = 21 + strlen(argument);
char* error_msg = malloc(msg_size);
@@ -126,8 +122,9 @@ Result parse_config(int argc, char* argv[]) {
}
Config* conf = malloc(sizeof(int) + sizeof(bool));
- conf->precision = tmp.precision;
+ conf->help = tmp.help;
conf->human_readable = tmp.human_readable;
+ conf->precision = tmp.precision;
res.success = true;
res.result = conf;
diff --git a/config-parser.h b/config-parser.h
index 1026a98..08aa934 100644
--- a/config-parser.h
+++ b/config-parser.h
@@ -2,6 +2,7 @@
struct Config {
int precision;
bool human_readable;
+ bool help;
};
typedef struct Config Config;
struct Result {
diff --git a/intmath.c b/intmath.c
index 9e1f3ed..a4738b9 100644
--- a/intmath.c
+++ b/intmath.c
@@ -14,6 +14,18 @@ int int_pown(unsigned int base, unsigned int exp) {
return res;
}
+int int_logn(unsigned int base, unsigned int a) {
+ unsigned int exp = 1;
+ int res = (int) base;
+ int lastres = res - 1;
+ while ((res < a) && (lastres < res)) {
+ lastres = res;
+ res *= base;
+ exp++;
+ }
+ return exp;
+}
+
unsigned long long ull_pown(unsigned int base, unsigned int exp) {
unsigned long long res = 1;
while (exp > 0) {
diff --git a/intmath.h b/intmath.h
index 5d0b56b..b86ce72 100644
--- a/intmath.h
+++ b/intmath.h
@@ -1,5 +1,6 @@
int int_pown(unsigned int base, unsigned int exp);
unsigned long long ull_pown(unsigned int base, unsigned int exp);
+int int_logn(unsigned int base, unsigned int a);
int int_pow10(unsigned int exp);
int int_floor(int x, int precision);
int int_ceil(int x, int precision);
diff --git a/stdu.c b/stdu.c
index 64f19a5..466d2f5 100644
--- a/stdu.c
+++ b/stdu.c
@@ -4,6 +4,7 @@
#include <string.h>
#include <errno.h>
#include <stdbool.h>
+#include <limits.h>
#include "intmath.h"
#include "formatting.h"
@@ -26,6 +27,17 @@ int main (int argc, char* argv[]) {
Config* conf = (Config*) res.result;
+ if (conf->help) {
+ printf(
+"Usage: stdu [-h] [-p n]\n\
+Print amount of data piped to stdin.\n\
+--help | -?: print this help message\n\
+--human-readable | -h: output in a human readable format\n\
+--precision n | -p n | -pn: output with n significant digits\n "
+ );
+ return 0;
+ }
+
unsigned int base = 10;
if (conf->human_readable && conf->precision == 0) {
conf->precision = 1;
@@ -38,6 +50,15 @@ int main (int argc, char* argv[]) {
unsigned long long bytes_read = 0;
size_t new_read_bytes = 0;
if (conf->precision != 0) {
+ int max_precision = int_logn(base, (unsigned int) INT_MAX);
+ if (conf->precision > max_precision) {
+ fprintf(
+ stderr,
+ "Overflow error: precision may not be greater than %d\n",
+ max_precision
+ );
+ return 1;
+ }
blocksize = exp_notated_to_ull(ull_ceiled_exponent_notation_base(
bytes_read + 1,
conf->precision,