logo

utils-std

Collection of commonly available Unix tools
commit: 730f9471a08eb080b7972d07562fa6173d14c84e
parent 96743d0fd0b33e04b4bcceccffef33dff6219c5c
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sat, 24 Aug 2024 05:12:52 +0200

cmd/cut: Fix non-stop range support

Diffstat:

Mcmd/cut.c48+++++++++++++++++++++++++++++++++++++++++-------
Mtest-cmd/cut.sh12+++++++++++-
2 files changed, 52 insertions(+), 8 deletions(-)

diff --git a/cmd/cut.c b/cmd/cut.c @@ -6,6 +6,7 @@ #include "../lib/reallocarray.h" +#include <ctype.h> #include <errno.h> #include <locale.h> #include <stdbool.h> @@ -31,6 +32,7 @@ bool opt_n = false, opt_s = false; enum cut_mode mode = CUT_MODE_NONE; bool *list = NULL; size_t list_len = 0; +bool nostop = false; static ssize_t parse_list_num(char **s) @@ -83,13 +85,21 @@ parse_list(char *s) if(s && *s == '-') { s++; - max = parse_list_num(&s); - if(max < 0) return -1; - if(max < min) + if(!isdigit(*s)) { - fprintf(stderr, "cut: Error: decreasing range: %zu-%zu\n", min, max); - return -1; + nostop = true; + } + else + { + max = parse_list_num(&s); + if(max < 0) return -1; + + if(max < min) + { + fprintf(stderr, "cut: Error: decreasing range: %zu-%zu\n", min, max); + return -1; + } } } @@ -98,7 +108,7 @@ parse_list(char *s) if((size_t)max > list_len) { - list = reallocarray(list, max, sizeof(*list)); + list = reallocarray(list, (size_t)max, sizeof(*list)); if(list == NULL) { fprintf(stderr, "cut: Memory allocation error: %s\n", strerror(errno)); @@ -153,9 +163,13 @@ cut_b(FILE *in, const char *filename) continue; } + if(line[nread - 1] == '\n') line[nread--] = '\0'; + for(size_t i = 0; i < MIN(list_len, (size_t)nread); i++) if(list[i]) fputc(line[i], stdout); + if(nostop && (size_t)nread > list_len) fwrite(line + list_len, nread - list_len, 1, stdout); + fputc('\n', stdout); } @@ -194,6 +208,8 @@ cut_c(FILE *in, const char *filename) continue; } + if(line[nread - 1] == '\n') line[nread--] = '\0'; + if(nread > line_wsz) { line_w = reallocarray(line_w, nread, sizeof(*line_w)); @@ -218,9 +234,16 @@ cut_c(FILE *in, const char *filename) //DEBUG fprintf(stderr, "cut: mbstowcs(_, _, %zu) => %zu\n", nread, wcread); - for(size_t i = 0; i < MIN(list_len, wcread); i++) + size_t i = 0; + for(; i < MIN(list_len, wcread); i++) if(list[i]) fputwc(line_w[i], stdout); + if(nostop && wcread > list_len) + { + for(; i < wcread; i++) + fputwc(line_w[i], stdout); + } + fputc('\n', stdout); } @@ -266,6 +289,17 @@ cut_f(FILE *in, const char *filename) char *toks = NULL; for(char *c = strtok_r(line, &delim, &toks); c != NULL; c = strtok_r(NULL, &delim, &toks), i++) { + if(i >= list_len) + { + if(!nostop) break; + + if(need_sep) fputc(delim, stdout); + + fputs(c, stdout); + need_sep = true; + continue; + } + if(list[i]) { if(need_sep) fputc(delim, stdout); diff --git a/test-cmd/cut.sh b/test-cmd/cut.sh @@ -4,18 +4,23 @@ WD="$(dirname "$0")/../" target="${WD}/cmd/cut" -plans=6 +plans=9 . "${WD}/test-cmd/tap.sh" . "${WD}/test-cmd/init_env.sh" t 'bytes:2-3,10-20,4,12' "-b 2-3,10-20,4,12 ${WD}/test-cmd/inputs/alnum" '1239ABCDEFGHIJ ' +t 'bytes:11-' "-b 11- ${WD}/test-cmd/inputs/alnum" 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +' t --exit=1 'bytes:,' "-b , ${WD}/test-cmd/inputs/alnum" 'cut: Error: empty list element ' # Example taken from POSIX cut(1) t --input='abcdefghi' 'chars:6,2,4-7,1' '-c 6,2,4-7,1' 'abdefg ' +t 'chars:11-' "-c 11- ${WD}/test-cmd/inputs/alnum" 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +' + t --input='aéb' 'widechar' '-c2' 'é ' @@ -31,3 +36,8 @@ b t --input="$fields" s_f2 '-s -f2' '2 b ' + +t --input="$fields" f2- '-f2-' '2 3 4 + +b c +'