commit: 4cdf14a67781289ee1920f6e882476a65c86dc74
parent 6b414d8c17858223bcba256b33b355e61f479e0e
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Fri, 13 Sep 2024 02:34:15 +0200
cmd/paste: import from FreeBSD
Diffstat:
A | cmd/paste.1 | 157 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | cmd/paste.c | 269 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 426 insertions(+), 0 deletions(-)
diff --git a/cmd/paste.1 b/cmd/paste.1
@@ -0,0 +1,157 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Adam S. Moskowitz and the Institute of Electrical and Electronics
+.\" Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)paste.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd November 6, 2022
+.Dt PASTE 1
+.Os
+.Sh NAME
+.Nm paste
+.Nd merge corresponding or subsequent lines of files
+.Sh SYNOPSIS
+.Nm
+.Op Fl s
+.Op Fl d Ar list
+.Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility concatenates the corresponding lines of the given input files,
+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
+still contain data, the file is treated as if it were an endless source
+of empty lines.
+.Pp
+The options are as follows:
+.Bl -tag -width Fl
+.It Fl d Ar list
+Use one or more of the provided characters to replace the newline
+characters instead of the default tab.
+The characters in
+.Ar list
+are used circularly, i.e., when
+.Ar list
+is exhausted the first character from
+.Ar list
+is reused.
+This continues until a line from the last input file (in default operation)
+or the last line in each file (using the
+.Fl s
+option) is displayed, at which
+time
+.Nm
+begins selecting characters from the beginning of
+.Ar list
+again.
+.Pp
+The following special characters can also be used in list:
+.Pp
+.Bl -tag -width flag -compact
+.It Li \en
+newline character
+.It Li \et
+tab character
+.It Li \e\e
+backslash character
+.It Li \e0
+Empty string (not a null character).
+.El
+.Pp
+Any other character preceded by a backslash is equivalent to the
+character itself.
+.It Fl s
+Concatenate all of the lines of each separate input file in command line
+order.
+The newline character of every line except the last line in each input
+file is replaced with the tab character, unless otherwise specified by
+the
+.Fl d
+option.
+.El
+.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,
+for each instance of
+.Sq Fl .
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+List the files in the current directory in three columns:
+.Pp
+.Dl "ls | paste - - -"
+.Pp
+Combine pairs of lines from a file into single lines:
+.Pp
+.Dl "paste -s -d '\et\en' myfile"
+.Pp
+Number the lines in a file, similar to
+.Xr nl 1 :
+.Pp
+.Dl "sed = myfile | paste - -"
+.Pp
+Create a colon-separated list of directories named
+.Pa bin ,
+suitable
+for use in the
+.Ev PATH
+environment variable:
+.Pp
+.Dl "find / -name bin -type d | paste -s -d : -"
+.Sh SEE ALSO
+.Xr cut 1 ,
+.Xr lam 1
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compatible.
+.Sh HISTORY
+A
+.Nm
+command first appeared in
+.At III
+and has been available since
+.Bx 4.3 Reno .
+.Sh AUTHORS
+.An -nosplit
+The original Bell Labs version was written by
+.An Gottfried W. R. Luderer
+and the
+.Bx
+version by
+.An Adam S. Moskowitz
+and
+.An Marciano Pitargue .
diff --git a/cmd/paste.c b/cmd/paste.c
@@ -0,0 +1,269 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam S. Moskowitz of Menlo Consulting.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] = "@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)paste.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <wchar.h>
+
+static wchar_t *delim;
+static int delimcnt;
+
+static int parallel(char **);
+static int sequential(char **);
+static int tr(wchar_t *);
+static void usage(void) __dead2;
+
+static wchar_t tab[] = L"\t";
+
+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:s")) != -1)
+ switch(ch)
+ {
+ case 'd':
+ arg = optarg;
+ len = mbsrtowcs(NULL, &arg, 0, NULL);
+ if(len == (size_t)-1) err(1, "delimiters");
+ warg = malloc((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, "delimiters");
+ delimcnt = tr(delim = warg);
+ break;
+ case 's':
+ seq = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ 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;
+ FILE *fp;
+ int cnt;
+ char *name;
+} LIST;
+
+static int
+parallel(char **argv)
+{
+ LIST *lp;
+ int cnt;
+ wint_t ich;
+ wchar_t ch;
+ char *p;
+ LIST *head, *tmp;
+ int opencnt, output;
+
+ for(cnt = 0, head = tmp = NULL; (p = *argv); ++argv, ++cnt)
+ {
+ if((lp = malloc(sizeof(LIST))) == NULL) err(1, NULL);
+ if(p[0] == '-' && !p[1])
+ lp->fp = stdin;
+ else if(!(lp->fp = fopen(p, "r")))
+ err(1, "%s", p);
+ lp->next = NULL;
+ lp->cnt = cnt;
+ lp->name = p;
+ if(!head)
+ head = tmp = lp;
+ else
+ {
+ tmp->next = lp;
+ tmp = lp;
+ }
+ }
+
+ for(opencnt = cnt; opencnt;)
+ {
+ for(output = 0, lp = head; lp; lp = lp->next)
+ {
+ if(!lp->fp)
+ {
+ if(output && lp->cnt && (ch = delim[(lp->cnt - 1) % delimcnt])) putwchar(ch);
+ continue;
+ }
+ if((ich = getwc(lp->fp)) == WEOF)
+ {
+ if(!--opencnt) break;
+ lp->fp = NULL;
+ if(output && lp->cnt && (ch = delim[(lp->cnt - 1) % delimcnt])) putwchar(ch);
+ continue;
+ }
+ /*
+ * make sure that we don't print any delimiters
+ * unless there's a non-empty file.
+ */
+ if(!output)
+ {
+ output = 1;
+ for(cnt = 0; cnt < lp->cnt; ++cnt)
+ if((ch = delim[cnt % delimcnt])) putwchar(ch);
+ }
+ else if((ch = delim[(lp->cnt - 1) % delimcnt]))
+ putwchar(ch);
+ if(ich == '\n') continue;
+ do
+ {
+ putwchar(ich);
+ } while((ich = getwc(lp->fp)) != WEOF && ich != '\n');
+ }
+ if(output) putwchar('\n');
+ }
+
+ return (0);
+}
+
+static int
+sequential(char **argv)
+{
+ FILE *fp;
+ int cnt, failed, needdelim;
+ wint_t ch;
+ char *p;
+
+ failed = 0;
+ for(; (p = *argv); ++argv)
+ {
+ if(p[0] == '-' && !p[1])
+ fp = stdin;
+ else if(!(fp = fopen(p, "r")))
+ {
+ warn("%s", p);
+ failed = 1;
+ continue;
+ }
+ cnt = needdelim = 0;
+ while((ch = getwc(fp)) != WEOF)
+ {
+ if(needdelim)
+ {
+ needdelim = 0;
+ if(delim[cnt] != '\0') putwchar(delim[cnt]);
+ if(++cnt == delimcnt) cnt = 0;
+ }
+ if(ch != '\n')
+ putwchar(ch);
+ else
+ needdelim = 1;
+ }
+ if(needdelim) putwchar('\n');
+ if(fp != stdin) (void)fclose(fp);
+ }
+
+ return (failed != 0);
+}
+
+static int
+tr(wchar_t *arg)
+{
+ int cnt;
+ wchar_t ch, *p;
+
+ for(p = arg, cnt = 0; (ch = *p++); ++arg, ++cnt)
+ if(ch == '\\') switch(ch = *p++)
+ {
+ case 'n':
+ *arg = '\n';
+ break;
+ case 't':
+ *arg = '\t';
+ break;
+ case '0':
+ *arg = '\0';
+ break;
+ default:
+ *arg = ch;
+ break;
+ }
+ else
+ *arg = ch;
+
+ if(!cnt) errx(1, "no delimiters specified");
+ return (cnt);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: paste [-s] [-d delimiters] file ...\n");
+ exit(1);
+}