logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git
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:

Acmd/paste.1157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acmd/paste.c269+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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); +}