11590Srgrimes/*
21590Srgrimes * Copyright (c) 1989, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * This code is derived from software contributed to Berkeley by
61590Srgrimes * Adam S. Moskowitz of Menlo Consulting.
71590Srgrimes *
81590Srgrimes * Redistribution and use in source and binary forms, with or without
91590Srgrimes * modification, are permitted provided that the following conditions
101590Srgrimes * are met:
111590Srgrimes * 1. Redistributions of source code must retain the above copyright
121590Srgrimes *    notice, this list of conditions and the following disclaimer.
131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141590Srgrimes *    notice, this list of conditions and the following disclaimer in the
151590Srgrimes *    documentation and/or other materials provided with the distribution.
161590Srgrimes * 4. Neither the name of the University nor the names of its contributors
171590Srgrimes *    may be used to endorse or promote products derived from this software
181590Srgrimes *    without specific prior written permission.
191590Srgrimes *
201590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301590Srgrimes * SUCH DAMAGE.
311590Srgrimes */
321590Srgrimes
331590Srgrimes#ifndef lint
3427787Scharnierstatic const char copyright[] =
351590Srgrimes"@(#) Copyright (c) 1989, 1993\n\
361590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
371590Srgrimes#endif /* not lint */
381590Srgrimes
3992772Smike#if 0
401590Srgrimes#ifndef lint
411590Srgrimesstatic char sccsid[] = "@(#)paste.c	8.1 (Berkeley) 6/6/93";
4292772Smike#endif /* not lint */
4327787Scharnier#endif
441590Srgrimes
4592772Smike#include <sys/cdefs.h>
4692772Smike__FBSDID("$FreeBSD$");
4792772Smike
481590Srgrimes#include <sys/types.h>
4995626Smarkm
5027787Scharnier#include <err.h>
51200462Sdelphij#include <errno.h>
52200462Sdelphij#include <limits.h>
53131076Stjr#include <locale.h>
541590Srgrimes#include <stdio.h>
5533644Sjb#include <stdlib.h>
56200462Sdelphij#include <string.h>
5727787Scharnier#include <unistd.h>
58131076Stjr#include <wchar.h>
591590Srgrimes
60227242Sedstatic wchar_t *delim;
61227242Sedstatic int delimcnt;
621590Srgrimes
63227242Sedstatic int parallel(char **);
64227242Sedstatic int sequential(char **);
65227242Sedstatic int tr(wchar_t *);
6692921Simpstatic void usage(void);
6727787Scharnier
68227242Sedstatic wchar_t tab[] = L"\t";
6995626Smarkm
7027787Scharnierint
7195626Smarkmmain(int argc, char *argv[])
721590Srgrimes{
7397223Stjr	int ch, rval, seq;
74131076Stjr	wchar_t *warg;
75131076Stjr	const char *arg;
76131076Stjr	size_t len;
771590Srgrimes
78131076Stjr	setlocale(LC_CTYPE, "");
79131076Stjr
801590Srgrimes	seq = 0;
8124360Simp	while ((ch = getopt(argc, argv, "d:s")) != -1)
821590Srgrimes		switch(ch) {
831590Srgrimes		case 'd':
84131076Stjr			arg = optarg;
85131076Stjr			len = mbsrtowcs(NULL, &arg, 0, NULL);
86131076Stjr			if (len == (size_t)-1)
87131076Stjr				err(1, "delimiters");
88131076Stjr			warg = malloc((len + 1) * sizeof(*warg));
89131076Stjr			if (warg == NULL)
90131076Stjr				err(1, NULL);
91131076Stjr			arg = optarg;
92131076Stjr			len = mbsrtowcs(warg, &arg, len + 1, NULL);
93131076Stjr			if (len == (size_t)-1)
94131076Stjr				err(1, "delimiters");
95131076Stjr			delimcnt = tr(delim = warg);
961590Srgrimes			break;
971590Srgrimes		case 's':
981590Srgrimes			seq = 1;
991590Srgrimes			break;
1001590Srgrimes		case '?':
1011590Srgrimes		default:
1021590Srgrimes			usage();
1031590Srgrimes		}
1041590Srgrimes	argc -= optind;
1051590Srgrimes	argv += optind;
1061590Srgrimes
10792772Smike	if (*argv == NULL)
10892772Smike		usage();
1091590Srgrimes	if (!delim) {
1101590Srgrimes		delimcnt = 1;
11195626Smarkm		delim = tab;
1121590Srgrimes	}
1131590Srgrimes
1141590Srgrimes	if (seq)
11597223Stjr		rval = sequential(argv);
1161590Srgrimes	else
11797223Stjr		rval = parallel(argv);
11897223Stjr	exit(rval);
1191590Srgrimes}
1201590Srgrimes
1211590Srgrimestypedef struct _list {
1221590Srgrimes	struct _list *next;
1231590Srgrimes	FILE *fp;
1241590Srgrimes	int cnt;
1251590Srgrimes	char *name;
1261590Srgrimes} LIST;
1271590Srgrimes
128227242Sedstatic int
12995626Smarkmparallel(char **argv)
1301590Srgrimes{
13195626Smarkm	LIST *lp;
13297233Stjr	int cnt;
133131076Stjr	wint_t ich;
134131076Stjr	wchar_t ch;
135131076Stjr	char *p;
1361590Srgrimes	LIST *head, *tmp;
1371590Srgrimes	int opencnt, output;
1381590Srgrimes
139162239Scharnier	for (cnt = 0, head = tmp = NULL; (p = *argv); ++argv, ++cnt) {
14096785Sjmallett		if ((lp = malloc(sizeof(LIST))) == NULL)
14196785Sjmallett			err(1, NULL);
1421590Srgrimes		if (p[0] == '-' && !p[1])
1431590Srgrimes			lp->fp = stdin;
14427787Scharnier		else if (!(lp->fp = fopen(p, "r")))
14527787Scharnier			err(1, "%s", p);
1461590Srgrimes		lp->next = NULL;
1471590Srgrimes		lp->cnt = cnt;
1481590Srgrimes		lp->name = p;
1491590Srgrimes		if (!head)
1501590Srgrimes			head = tmp = lp;
1511590Srgrimes		else {
1521590Srgrimes			tmp->next = lp;
1531590Srgrimes			tmp = lp;
1541590Srgrimes		}
1551590Srgrimes	}
1561590Srgrimes
1571590Srgrimes	for (opencnt = cnt; opencnt;) {
1581590Srgrimes		for (output = 0, lp = head; lp; lp = lp->next) {
1591590Srgrimes			if (!lp->fp) {
1601590Srgrimes				if (output && lp->cnt &&
1611590Srgrimes				    (ch = delim[(lp->cnt - 1) % delimcnt]))
162131076Stjr					putwchar(ch);
1631590Srgrimes				continue;
1641590Srgrimes			}
165131076Stjr			if ((ich = getwc(lp->fp)) == WEOF) {
1661590Srgrimes				if (!--opencnt)
1671590Srgrimes					break;
1681590Srgrimes				lp->fp = NULL;
1691590Srgrimes				if (output && lp->cnt &&
1701590Srgrimes				    (ch = delim[(lp->cnt - 1) % delimcnt]))
171131076Stjr					putwchar(ch);
1721590Srgrimes				continue;
1731590Srgrimes			}
1741590Srgrimes			/*
1751590Srgrimes			 * make sure that we don't print any delimiters
1761590Srgrimes			 * unless there's a non-empty file.
1771590Srgrimes			 */
1781590Srgrimes			if (!output) {
1791590Srgrimes				output = 1;
1801590Srgrimes				for (cnt = 0; cnt < lp->cnt; ++cnt)
18127787Scharnier					if ((ch = delim[cnt % delimcnt]))
182131076Stjr						putwchar(ch);
18327787Scharnier			} else if ((ch = delim[(lp->cnt - 1) % delimcnt]))
184131076Stjr				putwchar(ch);
185131076Stjr			if (ich == '\n')
186131076Stjr				continue;
187131076Stjr			do {
188131076Stjr				putwchar(ich);
189131076Stjr			} while ((ich = getwc(lp->fp)) != WEOF && ich != '\n');
1901590Srgrimes		}
1911590Srgrimes		if (output)
192131076Stjr			putwchar('\n');
1931590Srgrimes	}
19497223Stjr
19597223Stjr	return (0);
1961590Srgrimes}
1971590Srgrimes
198227242Sedstatic int
19995626Smarkmsequential(char **argv)
2001590Srgrimes{
20195626Smarkm	FILE *fp;
20297233Stjr	int cnt, failed, needdelim;
203131076Stjr	wint_t ch;
204131076Stjr	char *p;
2051590Srgrimes
20697223Stjr	failed = 0;
20727787Scharnier	for (; (p = *argv); ++argv) {
2081590Srgrimes		if (p[0] == '-' && !p[1])
2091590Srgrimes			fp = stdin;
2101590Srgrimes		else if (!(fp = fopen(p, "r"))) {
21127787Scharnier			warn("%s", p);
21297223Stjr			failed = 1;
2131590Srgrimes			continue;
2141590Srgrimes		}
21597230Stjr		cnt = needdelim = 0;
216131076Stjr		while ((ch = getwc(fp)) != WEOF) {
21797230Stjr			if (needdelim) {
21897230Stjr				needdelim = 0;
21997230Stjr				if (delim[cnt] != '\0')
220131076Stjr					putwchar(delim[cnt]);
22197230Stjr				if (++cnt == delimcnt)
2221590Srgrimes					cnt = 0;
2231590Srgrimes			}
224131076Stjr			if (ch != '\n')
225131076Stjr				putwchar(ch);
226131076Stjr			else
227131076Stjr				needdelim = 1;
22897230Stjr		}
22997230Stjr		if (needdelim)
230131076Stjr			putwchar('\n');
2311590Srgrimes		if (fp != stdin)
2321590Srgrimes			(void)fclose(fp);
2331590Srgrimes	}
23497223Stjr
23597223Stjr	return (failed != 0);
2361590Srgrimes}
2371590Srgrimes
238227242Sedstatic int
239131076Stjrtr(wchar_t *arg)
2401590Srgrimes{
24195626Smarkm	int cnt;
242131076Stjr	wchar_t ch, *p;
2431590Srgrimes
2441590Srgrimes	for (p = arg, cnt = 0; (ch = *p++); ++arg, ++cnt)
2451590Srgrimes		if (ch == '\\')
2461590Srgrimes			switch(ch = *p++) {
2471590Srgrimes			case 'n':
2481590Srgrimes				*arg = '\n';
2491590Srgrimes				break;
2501590Srgrimes			case 't':
2511590Srgrimes				*arg = '\t';
2521590Srgrimes				break;
2531590Srgrimes			case '0':
2541590Srgrimes				*arg = '\0';
2551590Srgrimes				break;
2561590Srgrimes			default:
2571590Srgrimes				*arg = ch;
2581590Srgrimes				break;
2591590Srgrimes		} else
2601590Srgrimes			*arg = ch;
2611590Srgrimes
26227787Scharnier	if (!cnt)
26327787Scharnier		errx(1, "no delimiters specified");
2641590Srgrimes	return(cnt);
2651590Srgrimes}
2661590Srgrimes
26727787Scharnierstatic void
26895626Smarkmusage(void)
2691590Srgrimes{
27027787Scharnier	(void)fprintf(stderr, "usage: paste [-s] [-d delimiters] file ...\n");
2711590Srgrimes	exit(1);
2721590Srgrimes}
273