logo

utils-std

Collection of commonly available Unix tools
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:

Mcmd/wc.14++++
Mcmd/wc.c45+++++++++++++++++++++++++++------------------
Mtest-cmd/wc.t44++++++++++++++++++++++++++++++++++++++++++++
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 . + .