commit: 73a04f2dd3faea132f01c810ad5bfdd0b5e08daa
parent 3ee4f0b9884c59fd1d0d33d68d50abd223ce0c06
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Thu, 25 Apr 2024 20:47:34 +0200
cmd/wc: Don't output trailing whitespaces
Diffstat:
3 files changed, 75 insertions(+), 18 deletions(-)
diff --git a/cmd/wc.1 b/cmd/wc.1
@@ -59,6 +59,10 @@ By default the standard output reports each file in the form:
"%d %d %d %s", <newlines>, <words>, <bytes>, <file>
.Ed
.Pp
+Similarly to GNU and BusyBox, this implementation also makes sure
+to not print trailing whitespace, which would have to be trimmed
+in most scripts.
+.Pp
If more than one
.Ar file
is given, a final line is printed with "total" instead of a pathname.
diff --git a/cmd/wc.c b/cmd/wc.c
@@ -24,12 +24,35 @@ static char *argv0 = "wc";
static enum {
WC_OPT_C = 1 << 0,
WC_OPT_L = 1 << 1,
- WC_OPT_W = 1 << 3,
+ WC_OPT_W = 1 << 2,
WC_OPT_ALL = WC_OPT_C | WC_OPT_L | WC_OPT_W,
} wc_opts = 0;
off_t total_bytes = 0, total_lines = 0, total_words = 0;
+static void
+print_counts(off_t lines, off_t words, off_t bytes, char *filename)
+{
+ char *fmt = "%ld";
+ if(FIELD_MATCH(wc_opts, WC_OPT_L))
+ {
+ printf(fmt, lines);
+ fmt = " %ld";
+ }
+ if(FIELD_MATCH(wc_opts, WC_OPT_W))
+ {
+ printf(fmt, words);
+ fmt = " %ld";
+ }
+ if(FIELD_MATCH(wc_opts, WC_OPT_C))
+ {
+ printf(fmt, bytes);
+ }
+
+ if(filename != NULL) printf(" %s", filename);
+ printf("\n");
+}
+
static int
wc_file_bytes(FILE *file, char *filename)
{
@@ -74,11 +97,7 @@ wc_file_bytes(FILE *file, char *filename)
total_bytes += bytes, total_lines += lines, total_words += words;
- if(FIELD_MATCH(wc_opts, WC_OPT_L)) printf("%ld ", lines);
- if(FIELD_MATCH(wc_opts, WC_OPT_W)) printf("%ld ", words);
- if(FIELD_MATCH(wc_opts, WC_OPT_C)) printf("%ld ", bytes);
- if(filename != NULL) printf("%s", filename);
- printf("\n");
+ print_counts(lines, words, bytes, filename);
return 0;
}
@@ -125,11 +144,7 @@ wc_file_chars(FILE *file, char *filename)
if(wordlen > 0) words++;
- if(FIELD_MATCH(wc_opts, WC_OPT_L)) printf("%ld ", lines);
- if(FIELD_MATCH(wc_opts, WC_OPT_W)) printf("%ld ", words);
- if(FIELD_MATCH(wc_opts, WC_OPT_C)) printf("%ld ", chars);
- if(filename != NULL) printf("%s", filename);
- printf("\n");
+ print_counts(lines, words, chars, filename);
return 0;
}
@@ -243,13 +258,7 @@ main(int argc, char *argv[])
}
}
- if(argc > 1)
- {
- if(FIELD_MATCH(wc_opts, WC_OPT_L)) printf("%ld ", total_lines);
- if(FIELD_MATCH(wc_opts, WC_OPT_W)) printf("%ld ", total_words);
- if(FIELD_MATCH(wc_opts, WC_OPT_C)) printf("%ld ", total_bytes);
- printf("total\n");
- }
+ if(argc > 1) print_counts(total_lines, total_words, total_bytes, "total");
return 0;
}
diff --git a/test-cmd/wc.t b/test-cmd/wc.t
@@ -41,3 +41,47 @@
$ wc /var/empty/e/no/ent
wc: Failed opening file '/var/empty/e/no/ent': No such file or directory
[1]
+
+Formatting with reduced counts
+ $ echo | wc -l
+ 1
+ $ echo a | wc -l
+ 1
+
+ $ echo | wc -c
+ 1
+ $ echo a | wc -c
+ 2
+
+ $ echo | wc -w
+ 0
+ $ echo a | wc -w
+ 1
+
+ $ echo | wc -cl
+ 1 1
+ $ echo a | wc -cl
+ 1 2
+
+ $ wc -c empty
+ 0 empty
+ $ wc -cl empty
+ 0 0 empty
+ $ wc -w empty
+ 0 empty
+
+Total when multiple files are specified
+ $ echo foo | wc empty -
+ 0 0 0 empty
+ 1 1 4
+ 1 1 4 total
+ $ printf 'foo bar\n' > foobar
+ $ wc foobar empty
+ 1 2 8 foobar
+ 0 0 0 empty
+ 1 2 8 total
+
+ $ rm foobar
+ $ rm empty
+ $ find .
+ .