logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git
commit: fae6a89ddb02a54da798899cd915a15570b3662d
parent 6e3032548ebadc45699644e33b1c06abe3362c9e
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Fri, 27 Sep 2024 02:20:43 +0200

cmd/paste: add support for no-argument usage

Diffstat:

Mcmd/paste.123++++++++++++++++-------
Mcmd/paste.c134++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mtest-cmd/paste.sh7++++++-
3 files changed, 90 insertions(+), 74 deletions(-)

diff --git a/cmd/paste.1 b/cmd/paste.1 @@ -43,17 +43,23 @@ .Nm .Op Fl sz .Op Fl d Ar list -.Ar +.Op Ar file... .Sh DESCRIPTION The .Nm -utility concatenates the corresponding lines of the given input files, +utility concatenates the corresponding lines of the given +.Ar file , replacing all but the last file's newline characters with a single tab character, and writes the resulting lines to standard output. -If end-of-file is reached on an input file while other input files +If end-of-file is reached on an input file while other +.Ar file still contain data, the file is treated as if it were an endless source of empty lines. .Pp +If no +.Ar file +is passed, standard input is read instead. +.Sh OPTIONS The options are as follows: .Bl -tag -width Fl .It Fl d Ar list @@ -105,8 +111,9 @@ Delimiter is NULL not newline. .Pp If .Sq Fl -is specified for one or more of the input files, the standard -input is used; standard input is read one line at a time, circularly, +is passed to one or more +.Ar file +argument, the standard input is used; standard input is read one line at a time, circularly, for each instance of .Sq Fl . .Sh EXIT STATUS @@ -141,9 +148,11 @@ should be compliant with the IEEE Std 1003.1-2024 (“POSIX.1”) specification. .Pp -The +Usage with no +.Ar file +passed and the .Fl z -option is an extension. +option are extensions. .Sh HISTORY A .Nm diff --git a/cmd/paste.c b/cmd/paste.c @@ -48,74 +48,9 @@ static wchar_t *delim; static int delimcnt; static wint_t linedelim = L'\n'; -static int parallel(char **); -static int sequential(char **); -static int tr(wchar_t *); -static void usage(void); - static wchar_t tab[] = L"\t"; const char *argv0 = "paste"; -int -main(int argc, char *argv[]) -{ - int ch, rval, seq; - wchar_t *warg; - const char *arg; - size_t len; - - setlocale(LC_CTYPE, ""); - - seq = 0; - while((ch = getopt(argc, argv, ":d:sz")) != -1) - switch(ch) - { - case 'd': - arg = optarg; - len = mbsrtowcs(NULL, &arg, 0, NULL); - if(len == (size_t)-1) err(1, "error: delimiters"); - if(len == SIZE_MAX) err(1, NULL); - warg = calloc((len + 1), sizeof(*warg)); - if(warg == NULL) err(1, NULL); - arg = optarg; - len = mbsrtowcs(warg, &arg, len + 1, NULL); - if(len == (size_t)-1) err(1, "error: delimiters"); - delimcnt = tr(delim = warg); - break; - case 's': - seq = 1; - break; - case 'z': - linedelim = L'\0'; - break; - case ':': - fprintf(stderr, "%s: error: Missing operand for option: '-%c'\n", argv0, optopt); - usage(); - return 1; - case '?': - fprintf(stderr, "%s: error: Unrecognised option: '-%c'\n", argv0, optopt); - usage(); - return 1; - default: - abort(); - } - argc -= optind; - argv += optind; - - if(*argv == NULL) usage(); - if(!delim) - { - delimcnt = 1; - delim = tab; - } - - if(seq) - rval = sequential(argv); - else - rval = parallel(argv); - exit(rval); -} - typedef struct _list { struct _list *next; @@ -266,6 +201,73 @@ tr(wchar_t *arg) static void usage(void) { - (void)fprintf(stderr, "usage: paste [-sz] [-d delimiters] file ...\n"); + (void)fprintf(stderr, "usage: paste [-sz] [-d delimiters] [file...]\n"); exit(1); } + +int +main(int argc, char *argv[]) +{ + errno = 0; + setlocale(LC_ALL, ""); + if(errno != 0) + { + fprintf(stderr, "%s: warning: Failed to initialize locales: %s\n", argv0, strerror(errno)); + errno = 0; + } + + int c = -1, seq = 0; + while((c = getopt(argc, argv, ":d:sz")) != -1) + { + switch(c) + { + case 'd': + { + const char *arg = optarg; + size_t len = mbsrtowcs(NULL, &arg, 0, NULL); + if(len == (size_t)-1) err(1, "error: delimiters"); + if(len == SIZE_MAX) err(1, NULL); + wchar_t *warg = calloc((len + 1), sizeof(*warg)); + if(warg == NULL) err(1, NULL); + arg = optarg; + len = mbsrtowcs(warg, &arg, len + 1, NULL); + if(len == (size_t)-1) err(1, "error: delimiters"); + delimcnt = tr(delim = warg); + break; + } + case 's': + seq = 1; + break; + case 'z': + linedelim = L'\0'; + break; + case ':': + fprintf(stderr, "%s: error: Missing operand for option: '-%c'\n", argv0, optopt); + usage(); + return 1; + case '?': + fprintf(stderr, "%s: error: Unrecognised option: '-%c'\n", argv0, optopt); + usage(); + return 1; + default: + abort(); + } + } + + argc -= optind; + argv += optind; + + char *dash[] = {(char *)"-", NULL}; + char **args = argc > 0 ? argv : dash; + + if(!delim) + { + delimcnt = 1; + delim = tab; + } + + if(seq) + return sequential(args); + else + return parallel(args); +} diff --git a/test-cmd/paste.sh b/test-cmd/paste.sh @@ -4,7 +4,7 @@ WD="$(dirname "$0")/../" target="${WD}/cmd/paste" -plans=2 +plans=3 . "${WD}/test-cmd/tap.sh" banzai=$(mktemp) @@ -21,3 +21,8 @@ t_foobar_z() { printf '%s\0' foo bar baz | "$target" -z - - } t_cmd foobar_z "$(printf 'foo\tbar\0baz\t\0')" t_foobar_z + +t --input='foo bar +baz' input_noargs '' 'foo bar +baz +'