paste.c revision 27787
1312591Sbapt/*
2312591Sbapt * Copyright (c) 1989, 1993
3312591Sbapt *	The Regents of the University of California.  All rights reserved.
4312591Sbapt *
5312591Sbapt * This code is derived from software contributed to Berkeley by
6312591Sbapt * Adam S. Moskowitz of Menlo Consulting.
7312591Sbapt *
8312591Sbapt * Redistribution and use in source and binary forms, with or without
9312591Sbapt * modification, are permitted provided that the following conditions
10312591Sbapt * are met:
11312591Sbapt * 1. Redistributions of source code must retain the above copyright
12312591Sbapt *    notice, this list of conditions and the following disclaimer.
13312591Sbapt * 2. Redistributions in binary form must reproduce the above copyright
14312591Sbapt *    notice, this list of conditions and the following disclaimer in the
15312591Sbapt *    documentation and/or other materials provided with the distribution.
16312591Sbapt * 3. All advertising materials mentioning features or use of this software
17312591Sbapt *    must display the following acknowledgement:
18312591Sbapt *	This product includes software developed by the University of
19312591Sbapt *	California, Berkeley and its contributors.
20312591Sbapt * 4. Neither the name of the University nor the names of its contributors
21312591Sbapt *    may be used to endorse or promote products derived from this software
22312591Sbapt *    without specific prior written permission.
23312591Sbapt *
24312591Sbapt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25312591Sbapt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26312591Sbapt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27312591Sbapt * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28312591Sbapt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29312591Sbapt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30312591Sbapt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31312591Sbapt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32312591Sbapt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33312591Sbapt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34312591Sbapt * SUCH DAMAGE.
35312591Sbapt */
36312591Sbapt
37312591Sbapt#ifndef lint
38312591Sbaptstatic const char copyright[] =
39312591Sbapt"@(#) Copyright (c) 1989, 1993\n\
40312591Sbapt	The Regents of the University of California.  All rights reserved.\n";
41312591Sbapt#endif /* not lint */
42312591Sbapt
43312591Sbapt#ifndef lint
44312591Sbapt#if 0
45312591Sbaptstatic char sccsid[] = "@(#)paste.c	8.1 (Berkeley) 6/6/93";
46312591Sbapt#endif
47312591Sbaptstatic const char rcsid[] =
48312591Sbapt	"$Id$";
49312591Sbapt#endif /* not lint */
50312591Sbapt
51312591Sbapt#include <sys/types.h>
52312591Sbapt#include <err.h>
53312591Sbapt#include <errno.h>
54312591Sbapt#include <limits.h>
55312591Sbapt#include <stdio.h>
56312591Sbapt#include <string.h>
57312591Sbapt#include <unistd.h>
58312591Sbapt
59312591Sbaptchar *delim;
60312591Sbaptint delimcnt;
61312591Sbapt
62312591Sbaptvoid parallel __P((char **));
63312591Sbaptvoid sequential __P((char **));
64312591Sbaptint tr __P((char *));
65312591Sbaptstatic void usage __P((void));
66312591Sbapt
67312591Sbaptint
68312591Sbaptmain(argc, argv)
69312591Sbapt	int argc;
70312591Sbapt	char **argv;
71312591Sbapt{
72312591Sbapt	int ch, seq;
73312591Sbapt
74312591Sbapt	seq = 0;
75312591Sbapt	while ((ch = getopt(argc, argv, "d:s")) != -1)
76312591Sbapt		switch(ch) {
77312591Sbapt		case 'd':
78312591Sbapt			delimcnt = tr(delim = optarg);
79312591Sbapt			break;
80312591Sbapt		case 's':
81312591Sbapt			seq = 1;
82312591Sbapt			break;
83312591Sbapt		case '?':
84312591Sbapt		default:
85312591Sbapt			usage();
86312591Sbapt		}
87312591Sbapt	argc -= optind;
88312591Sbapt	argv += optind;
89312591Sbapt
90312591Sbapt	if (!delim) {
91312591Sbapt		delimcnt = 1;
92312591Sbapt		delim = "\t";
93312591Sbapt	}
94312591Sbapt
95312591Sbapt	if (seq)
96312591Sbapt		sequential(argv);
97312591Sbapt	else
98312591Sbapt		parallel(argv);
99312591Sbapt	exit(0);
100312591Sbapt}
101312591Sbapt
102312591Sbapttypedef struct _list {
103312591Sbapt	struct _list *next;
104312591Sbapt	FILE *fp;
105312591Sbapt	int cnt;
106312591Sbapt	char *name;
107312591Sbapt} LIST;
108312591Sbapt
109312591Sbaptvoid
110312591Sbaptparallel(argv)
111312591Sbapt	char **argv;
112312591Sbapt{
113312591Sbapt	register LIST *lp;
114312591Sbapt	register int cnt;
115312591Sbapt	register char ch, *p;
116312591Sbapt	LIST *head, *tmp;
117312591Sbapt	int opencnt, output;
118312591Sbapt	char buf[_POSIX2_LINE_MAX + 1], *malloc();
119312591Sbapt
120312591Sbapt	for (cnt = 0, head = NULL; (p = *argv); ++argv, ++cnt) {
121312591Sbapt		if (!(lp = (LIST *)malloc((u_int)sizeof(LIST))))
122312591Sbapt			errx(1, "%s", strerror(ENOMEM));
123312591Sbapt		if (p[0] == '-' && !p[1])
124312591Sbapt			lp->fp = stdin;
125312591Sbapt		else if (!(lp->fp = fopen(p, "r")))
126312591Sbapt			err(1, "%s", p);
127312591Sbapt		lp->next = NULL;
128312591Sbapt		lp->cnt = cnt;
129312591Sbapt		lp->name = p;
130312591Sbapt		if (!head)
131312591Sbapt			head = tmp = lp;
132312591Sbapt		else {
133312591Sbapt			tmp->next = lp;
134312591Sbapt			tmp = lp;
135312591Sbapt		}
136312591Sbapt	}
137312591Sbapt
138312591Sbapt	for (opencnt = cnt; opencnt;) {
139312591Sbapt		for (output = 0, lp = head; lp; lp = lp->next) {
140312591Sbapt			if (!lp->fp) {
141312591Sbapt				if (output && lp->cnt &&
142312591Sbapt				    (ch = delim[(lp->cnt - 1) % delimcnt]))
143312591Sbapt					putchar(ch);
144312591Sbapt				continue;
145312591Sbapt			}
146312591Sbapt			if (!fgets(buf, sizeof(buf), lp->fp)) {
147312591Sbapt				if (!--opencnt)
148312591Sbapt					break;
149312591Sbapt				lp->fp = NULL;
150312591Sbapt				if (output && lp->cnt &&
151312591Sbapt				    (ch = delim[(lp->cnt - 1) % delimcnt]))
152312591Sbapt					putchar(ch);
153312591Sbapt				continue;
154312591Sbapt			}
155312591Sbapt			if (!(p = index(buf, '\n')))
156312591Sbapt				errx(1, "%s: input line too long", lp->name);
157312591Sbapt			*p = '\0';
158312591Sbapt			/*
159312591Sbapt			 * make sure that we don't print any delimiters
160312591Sbapt			 * unless there's a non-empty file.
161312591Sbapt			 */
162312591Sbapt			if (!output) {
163312591Sbapt				output = 1;
164312591Sbapt				for (cnt = 0; cnt < lp->cnt; ++cnt)
165312591Sbapt					if ((ch = delim[cnt % delimcnt]))
166312591Sbapt						putchar(ch);
167312591Sbapt			} else if ((ch = delim[(lp->cnt - 1) % delimcnt]))
168312591Sbapt				putchar(ch);
169312591Sbapt			(void)printf("%s", buf);
170312591Sbapt		}
171312591Sbapt		if (output)
172312591Sbapt			putchar('\n');
173312591Sbapt	}
174312591Sbapt}
175312591Sbapt
176312591Sbaptvoid
177312591Sbaptsequential(argv)
178312591Sbapt	char **argv;
179312591Sbapt{
180312591Sbapt	register FILE *fp;
181312591Sbapt	register int cnt;
182312591Sbapt	register char ch, *p, *dp;
183312591Sbapt	char buf[_POSIX2_LINE_MAX + 1];
184312591Sbapt
185312591Sbapt	for (; (p = *argv); ++argv) {
186312591Sbapt		if (p[0] == '-' && !p[1])
187312591Sbapt			fp = stdin;
188312591Sbapt		else if (!(fp = fopen(p, "r"))) {
189			warn("%s", p);
190			continue;
191		}
192		if (fgets(buf, sizeof(buf), fp)) {
193			for (cnt = 0, dp = delim;;) {
194				if (!(p = index(buf, '\n')))
195					errx(1, "%s: input line too long", *argv);
196				*p = '\0';
197				(void)printf("%s", buf);
198				if (!fgets(buf, sizeof(buf), fp))
199					break;
200				if ((ch = *dp++))
201					putchar(ch);
202				if (++cnt == delimcnt) {
203					dp = delim;
204					cnt = 0;
205				}
206			}
207			putchar('\n');
208		}
209		if (fp != stdin)
210			(void)fclose(fp);
211	}
212}
213
214int
215tr(arg)
216	char *arg;
217{
218	register int cnt;
219	register char ch, *p;
220
221	for (p = arg, cnt = 0; (ch = *p++); ++arg, ++cnt)
222		if (ch == '\\')
223			switch(ch = *p++) {
224			case 'n':
225				*arg = '\n';
226				break;
227			case 't':
228				*arg = '\t';
229				break;
230			case '0':
231				*arg = '\0';
232				break;
233			default:
234				*arg = ch;
235				break;
236		} else
237			*arg = ch;
238
239	if (!cnt)
240		errx(1, "no delimiters specified");
241	return(cnt);
242}
243
244static void
245usage()
246{
247	(void)fprintf(stderr, "usage: paste [-s] [-d delimiters] file ...\n");
248	exit(1);
249}
250