aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README8
-rw-r--r--config-parser.c76
-rw-r--r--config-parser.h1
-rw-r--r--stdu.128
-rw-r--r--stdu.c39
5 files changed, 127 insertions, 25 deletions
diff --git a/README b/README
index 10484a2..de272e3 100644
--- a/README
+++ b/README
@@ -1,6 +1,6 @@
-stdu README
-===========
+stdu 1.1.0 README
+=================
`stdu` is a program for monitoring the amount of
input data in real time.
@@ -19,7 +19,8 @@ Install by either copying/symlinking `stdu` and
`stdu.1` to the appropriate locations, or run
`make install`. You can change the installation
paths by modifying `BINPATH` and `MANPATH` in the
-makefile.
+makefile. You should run `makewhatis` on your
+`MANPATH` after installation.
Usage
-----
@@ -27,3 +28,4 @@ Usage
See the man page and help message:
`stdu --help`
`man stdu`
+
diff --git a/config-parser.c b/config-parser.c
index ef67a8e..b09bbc2 100644
--- a/config-parser.c
+++ b/config-parser.c
@@ -14,10 +14,11 @@ Result parse_config(int argc, char* argv[]) {
Result res;
res.success = false;
Config tmp;
- tmp.precision = 0;
- tmp.multiline = false;
+ tmp.forward = false;
tmp.human_readable = false;
tmp.help = false;
+ tmp.multiline = false;
+ tmp.precision = 0;
size_t i = 1;
char* argument;
@@ -58,7 +59,9 @@ Result parse_config(int argc, char* argv[]) {
size_t tacktacklen = 2;
if (strncmp(argument, "--", tacktacklen) == 0) {
argument += tacktacklen;
- if (strcmp(argument, "help") == 0) {
+ if (strcmp(argument, "forward") == 0) {
+ tmp.forward = true;
+ } else if (strcmp(argument, "help") == 0) {
tmp.help = true;
} else if (strcmp(argument, "human-readable") == 0) {
tmp.human_readable = true;
@@ -111,6 +114,9 @@ Result parse_config(int argc, char* argv[]) {
case 'm':
tmp.multiline = true;
break;
+ case 'o':
+ tmp.forward = true;
+ break;
case 'p':
next_is_precision = true;
if (opt_i != arglen - 1) {
@@ -185,6 +191,7 @@ Result parse_config(int argc, char* argv[]) {
}
Config* conf = malloc(sizeof(Config));
+ conf->forward = tmp.forward;
conf->help = tmp.help;
conf->human_readable = tmp.human_readable;
conf->multiline = tmp.multiline;
@@ -245,28 +252,73 @@ char* test_precision_parsing() {
}
+char* test_forward_parsing() {
+ int argc = 2;
+ char* argv1[] = { "stdu", "--forward" };
+ char* argv2[] = { "stdu", "-o" };
+ Result res1 = parse_config(argc, argv1);
+ Result res2 = parse_config(argc, argv2);
+ Config* conf1 = (Config*) res1.result;
+ Config* conf2 = (Config*) res2.result;
+
+ mt_assert_eq(res1.success, true);
+ mt_assert_eq(res2.success, true);
+ mt_assert_eq(conf1->forward, true);
+ mt_assert_eq(conf2->forward, true);
+ free(conf1);
+ free(conf2);
+
+ return 0;
+}
+
+char* test_help_parsing() {
+ int argc = 2;
+ char* argv1[] = { "stdu", "--help" };
+ char* argv2[] = { "stdu", "-?" };
+ Result res1 = parse_config(argc, argv1);
+ Result res2 = parse_config(argc, argv2);
+ Config* conf1 = (Config*) res1.result;
+ Config* conf2 = (Config*) res2.result;
+
+ mt_assert_eq(res1.success, true);
+ mt_assert_eq(res2.success, true);
+ mt_assert_eq(conf1->help, true);
+ mt_assert_eq(conf2->help, true);
+ free(conf1);
+ free(conf2);
+
+ return 0;
+}
+
char* test_human_readability_parsing() {
int argc = 2;
- char* argv[] = { "stdu", "--human-readable" };
- Result res = parse_config(argc, argv);
- Config* conf = (Config*) res.result;
+ char* argv1[] = { "stdu", "--human-readable" };
+ char* argv2[] = { "stdu", "-h" };
+ Result res1 = parse_config(argc, argv1);
+ Result res2 = parse_config(argc, argv2);
+ Config* conf1 = (Config*) res1.result;
+ Config* conf2 = (Config*) res2.result;
- mt_assert_eq(res.success, true);
- mt_assert_eq(conf->human_readable, true);
- free(conf);
+ mt_assert_eq(res1.success, true);
+ mt_assert_eq(res2.success, true);
+ mt_assert_eq(conf1->human_readable, true);
+ mt_assert_eq(conf2->human_readable, true);
+ free(conf1);
+ free(conf2);
return 0;
}
char* test_multioption_parsing() {
int argc = 3;
- char* argv[] = { "stdu", "-mh?p", "3"};
+ char* argv[] = { "stdu", "-mho?p", "3"};
Result res = parse_config(argc, argv);
Config* conf = (Config*) res.result;
mt_assert_eq(res.success, true);
mt_assert_eq(conf->help, true);
mt_assert_eq(conf->human_readable, true);
mt_assert_eq(conf->multiline, true);
+ mt_assert_eq(conf->forward, true);
mt_assert_eq(conf->precision, 3);
free(conf);
@@ -275,7 +327,9 @@ char* test_multioption_parsing() {
void parsing_tests() {
mt_run_test(test_default_config);
- mt_run_test(test_precision_parsing);
+ mt_run_test(test_forward_parsing);
mt_run_test(test_human_readability_parsing);
+ mt_run_test(test_help_parsing);
mt_run_test(test_multioption_parsing);
+ mt_run_test(test_precision_parsing);
}
diff --git a/config-parser.h b/config-parser.h
index 3446826..a2988f0 100644
--- a/config-parser.h
+++ b/config-parser.h
@@ -1,5 +1,6 @@
struct Config {
+ bool forward;
bool human_readable;
bool help;
bool multiline;
diff --git a/stdu.1 b/stdu.1
index 79fbcba..5693270 100644
--- a/stdu.1
+++ b/stdu.1
@@ -1,16 +1,17 @@
-.Dd 2024-04-14
+.Dd 2024-05-31
.Dt STDU 1
.Sh NAME
.Nm stdu
.Nd monitor amount of data read from stdin
.Sh SYNOPSIS
.Nm stdu
+.Op Fl Fl forward
.Op Fl Fl help
.Op Fl Fl human-readable
.Op Fl Fl multiline
.Op Fl Fl precision Ar n
.Nm stdu
-.Op Fl hm?
+.Op Fl hmo?
.Op Fl p Ar n
.Sh DESCRIPTION
.Nm
@@ -23,6 +24,9 @@ in chunks) if \fB--precision\fR or \fB--human-readable\fR aren't specified,
so specifying them is recommended.
.Sh OPTIONS
.Bl -tag -width 3n
+.It Fl Fl forward | Fl o
+Writes data read from STDIN to STDOUT and prints amount of read data
+to STDERR instead of STDOUT.
.It Fl Fl help | Fl ?
Displays a help message.
.It Fl Fl human-readable | Fl h
@@ -43,9 +47,27 @@ may add trailing zeroes.
.Sh EXAMPLES
.Nm
is useful as a progress bar replacement when transmitting large files.
-.Bd -literal
+.Bd -literal -offset indent
nc -l 1234 | tee backup.tar.gz | stdu -p3 -h
.Ed
+.Bd -literal -offset indent
+cat void-live-x86_64-musl-base.iso | stdu -ho > /dev/sdb1
+.Ed
+.Sh CAVEATS
+.Bd -literal -offset indent
+cat void-live-x86_64-musl-base.iso | sudo tee /dev/sdb1 | stdu -p3
+.Ed
+
+Is not very informative because
+.Nm
+probably reads the data faster from
+.Xr tee 1
+than /dev/sdb1 does. This is why
+.Ar forward
+has been implemented.
.Sh "SEE ALSO"
+.Xr dd 1
.Xr du 1
+.Xr progress 1
+.Xr pv 1
diff --git a/stdu.c b/stdu.c
index 2cd0aa4..e549440 100644
--- a/stdu.c
+++ b/stdu.c
@@ -27,6 +27,8 @@ int main (int argc, char* argv[]) {
Config* conf = (Config*) res.result;
+ FILE* progress_destination = conf->forward ? stderr : stdout;
+
if (conf->help) {
printf(
"Usage: stdu [-hm?] [-p n]\n\
@@ -34,6 +36,7 @@ Print amount of data piped to stdin.\n\
--help | -?: print this help message\n\
--human-readable | -h: output in a human readable format\n\
--multiline | -m: output with line breaks\n\
+--forward | -o: forward STDIN to STDOUT and print amount of transferred data to STDERR\n\
--precision n | -p n | -pn: output with n significant digits\n"
);
return 0;
@@ -89,12 +92,17 @@ Print amount of data piped to stdin.\n\
conf->precision
);
if (res < 0) {
- printf("\r%llu \
+ fprintf(
+ progress_destination,
+ "\r%llu \
(error when getting prefix)%s",
- bytes_read, endl);
+ bytes_read,
+ endl
+ );
continue;
}
- printf(
+ fprintf(
+ progress_destination,
"\r%sB%*s",
stdout_buffer,
int_max(previous_line_strlen - res, 0),
@@ -109,11 +117,16 @@ Print amount of data piped to stdin.\n\
bytes_read
);
if (res < 0) {
- printf("\r%llu \
+ fprintf(
+ progress_destination,
+ "\r%llu \
(error when getting prefix)%s",
- bytes_read, endl);
+ bytes_read,
+ endl
+ );
}
- printf(
+ fprintf(
+ progress_destination,
"\r%sB%*s",
stdout_buffer,
int_max(previous_line_strlen - res, 0),
@@ -122,9 +135,14 @@ Print amount of data piped to stdin.\n\
previous_line_strlen
= int_max(res, previous_line_strlen);
} else {
- printf("\r%llu%s", bytes_read, endl);
+ fprintf(
+ progress_destination,
+ "\r%llu%s",
+ bytes_read,
+ endl
+ );
}
- if (fflush(stdout) == EOF) {
+ if (fflush(progress_destination) == EOF) {
printf("\n");
perror("error during fflush");
return 1;
@@ -148,6 +166,11 @@ Print amount of data piped to stdin.\n\
}
bytes_read += new_read_bytes;
+ /* writing */
+ if (conf->forward) {
+ printf("%s", buf);
+ }
+
/* resizing buffer and blocksize to read as much as possible
* at once
*/