paste.c revision 1.8 1 /* $NetBSD: paste.c,v 1.8 2006/03/31 17:20:07 dsl Exp $ */
2
3 /*
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Adam S. Moskowitz of Menlo Consulting.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 #ifndef lint
37 __COPYRIGHT("@(#) Copyright (c) 1989, 1993\n"
38 "The Regents of the University of California. All rights reserved.\n");
39 #endif /* not lint */
40
41 #ifndef lint
42 /*static char sccsid[] = "from: @(#)paste.c 8.1 (Berkeley) 6/6/93";*/
43 __RCSID("$NetBSD: paste.c,v 1.8 2006/03/31 17:20:07 dsl Exp $");
44 #endif /* not lint */
45
46 #include <sys/types.h>
47 #include <err.h>
48 #include <errno.h>
49 #include <limits.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53 #include <string.h>
54 #include <unistd.h>
55
56 void parallel(char **);
57 void sequential(char **);
58 int tr(char *);
59 void usage(void);
60
61 char *delim;
62 int delimcnt;
63
64 int
65 main(int argc, char **argv)
66 {
67 int ch, seq;
68
69 seq = 0;
70 while ((ch = getopt(argc, argv, "d:s")) != -1)
71 switch (ch) {
72 case 'd':
73 delimcnt = tr(delim = optarg);
74 break;
75 case 's':
76 seq = 1;
77 break;
78 case '?':
79 default:
80 usage();
81 }
82 argc -= optind;
83 argv += optind;
84
85 if (!delim) {
86 delimcnt = 1;
87 delim = "\t";
88 }
89
90 if (seq)
91 sequential(argv);
92 else
93 parallel(argv);
94 exit(0);
95 }
96
97 typedef struct _list {
98 struct _list *next;
99 FILE *fp;
100 int cnt;
101 char *name;
102 } LIST;
103
104 void
105 parallel(char **argv)
106 {
107 LIST *lp;
108 int cnt;
109 char ch, *p;
110 LIST *head, *tmp;
111 int opencnt, output;
112 char buf[_POSIX2_LINE_MAX + 1];
113
114 tmp = NULL;
115 for (cnt = 0, head = NULL; (p = *argv) != NULL; ++argv, ++cnt) {
116 if (!(lp = (LIST *)malloc((u_int)sizeof(LIST))))
117 err(1, "malloc");
118 if (p[0] == '-' && !p[1])
119 lp->fp = stdin;
120 else if (!(lp->fp = fopen(p, "r")))
121 err(1, "%s", p);
122 lp->next = NULL;
123 lp->cnt = cnt;
124 lp->name = p;
125 if (!head)
126 head = tmp = lp;
127 else {
128 tmp->next = lp;
129 tmp = lp;
130 }
131 }
132
133 for (opencnt = cnt; opencnt;) {
134 for (output = 0, lp = head; lp; lp = lp->next) {
135 if (!lp->fp) {
136 if (output && lp->cnt &&
137 (ch = delim[(lp->cnt - 1) % delimcnt]))
138 putchar(ch);
139 continue;
140 }
141 if (!fgets(buf, sizeof(buf), lp->fp)) {
142 if (!--opencnt)
143 break;
144 lp->fp = NULL;
145 if (output && lp->cnt &&
146 (ch = delim[(lp->cnt - 1) % delimcnt]))
147 putchar(ch);
148 continue;
149 }
150 if (!(p = strchr(buf, '\n')))
151 err(1, "%s: input line too long.", lp->name);
152 *p = '\0';
153 /*
154 * make sure that we don't print any delimiters
155 * unless there's a non-empty file.
156 */
157 if (!output) {
158 output = 1;
159 for (cnt = 0; cnt < lp->cnt; ++cnt)
160 if ((ch = delim[cnt % delimcnt]) != 0)
161 putchar(ch);
162 } else if ((ch = delim[(lp->cnt - 1) % delimcnt]) != 0)
163 putchar(ch);
164 (void)printf("%s", buf);
165 }
166 if (output)
167 putchar('\n');
168 }
169 }
170
171 void
172 sequential(char **argv)
173 {
174 FILE *fp;
175 int cnt;
176 char ch, *p, *dp;
177 char buf[_POSIX2_LINE_MAX + 1];
178
179 for (; (p = *argv) != NULL; ++argv) {
180 if (p[0] == '-' && !p[1])
181 fp = stdin;
182 else if (!(fp = fopen(p, "r"))) {
183 warn("%s", p);
184 continue;
185 }
186 if (fgets(buf, sizeof(buf), fp)) {
187 for (cnt = 0, dp = delim;;) {
188 if (!(p = strchr(buf, '\n')))
189 err(1, "%s: input line too long.",
190 *argv);
191 *p = '\0';
192 (void)printf("%s", buf);
193 if (!fgets(buf, sizeof(buf), fp))
194 break;
195 if ((ch = *dp++) != 0)
196 putchar(ch);
197 if (++cnt == delimcnt) {
198 dp = delim;
199 cnt = 0;
200 }
201 }
202 putchar('\n');
203 }
204 if (fp != stdin)
205 (void)fclose(fp);
206 }
207 }
208
209 int
210 tr(char *arg)
211 {
212 int cnt;
213 char ch, *p;
214
215 for (p = arg, cnt = 0; (ch = *p++); ++arg, ++cnt)
216 if (ch == '\\')
217 switch(ch = *p++) {
218 case 'n':
219 *arg = '\n';
220 break;
221 case 't':
222 *arg = '\t';
223 break;
224 case '0':
225 *arg = '\0';
226 break;
227 default:
228 *arg = ch;
229 break;
230 } else
231 *arg = ch;
232
233 if (!cnt)
234 errx(1, "no delimiters specified.");
235 return(cnt);
236 }
237
238 void
239 usage()
240 {
241 (void)fprintf(stderr, "paste: [-s] [-d delimiters] file ...\n");
242 exit(1);
243 }
244