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:
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
+'