paste.c revision 1.12 1 /* $NetBSD: paste.c,v 1.12 2006/04/01 06:36:58 rtr 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.12 2006/04/01 06:36:58 rtr 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(int, char **);
57 void sequential(char **);
58 int tr(char *);
59 void usage(void);
60
61 char dflt_delim[] = "\t";
62 char *delim = dflt_delim;
63 int delimcnt = 1;
64
65 int
66 main(int argc, char **argv)
67 {
68 int ch, seq;
69
70 seq = 0;
71 while ((ch = getopt(argc, argv, "d:s")) != -1) {
72 switch (ch) {
73 case 'd':
74 delim = strdup(optarg);
75 delimcnt = tr(delim);
76 break;
77 case 's':
78 seq = 1;
79 break;
80 case '?':
81 default:
82 usage();
83 }
84 }
85 argc -= optind;
86 argv += optind;
87
88 if (seq)
89 sequential(argv);
90 else
91 parallel(argc, argv);
92 exit(0);
93 }
94
95 void
96 parallel(int argc, char **argv)
97 {
98 char ch, *dp, *line;
99 FILE **fpp, *fp;
100 size_t line_len;
101 int cnt, output;
102
103 fpp = calloc(argc, sizeof *fpp);
104 if (fpp == NULL)
105 err(1, "calloc");
106
107 for (cnt = 0; cnt < argc; cnt++) {
108 if (strcmp(argv[cnt], "-") == 0)
109 fpp[cnt] = stdin;
110 else if (!(fpp[cnt] = fopen(argv[cnt], "r")))
111 err(1, "%s", argv[cnt]);
112 }
113
114 for (;;) {
115 /* Start with the NUL at the end of 'delim' ... */
116 dp = delim + delimcnt;
117 output = 0;
118 for (cnt = 0; cnt < argc; cnt++) {
119 fp = fpp[cnt];
120 if (fp == NULL)
121 continue;
122 line = fgetln(fp, &line_len);
123 if (line == NULL) {
124 /* Assume EOF */
125 if (fp != stdin)
126 fclose(fp);
127 fpp[cnt] = NULL;
128 continue;
129 }
130 /* Output enough separators to catch up */
131 do {
132 ch = *dp++;
133 if (ch)
134 putchar(ch);
135 if (dp >= delim + delimcnt)
136 dp = delim;
137 } while (++output <= cnt);
138 /* Remove any trailing newline - check for last line */
139 if (line[line_len - 1] == '\n')
140 line_len--;
141 printf("%.*s", (int)line_len, line);
142 }
143
144 if (!output)
145 break;
146
147 /* Add separators to end of line */
148 while (++output <= cnt) {
149 ch = *dp++;
150 if (ch)
151 putchar(ch);
152 if (dp >= delim + delimcnt)
153 dp = delim;
154 }
155 putchar('\n');
156 }
157
158 free(fpp);
159 }
160
161 void
162 sequential(char **argv)
163 {
164 FILE *fp;
165 int cnt;
166 char ch, *p, *dp;
167 char buf[_POSIX2_LINE_MAX + 1];
168
169 for (; (p = *argv) != NULL; ++argv) {
170 if (p[0] == '-' && !p[1])
171 fp = stdin;
172 else if (!(fp = fopen(p, "r"))) {
173 warn("%s", p);
174 continue;
175 }
176 if (fgets(buf, sizeof(buf), fp)) {
177 for (cnt = 0, dp = delim;;) {
178 if (!(p = strchr(buf, '\n')))
179 err(1, "%s: input line too long.",
180 *argv);
181 *p = '\0';
182 (void)printf("%s", buf);
183 if (!fgets(buf, sizeof(buf), fp))
184 break;
185 if ((ch = *dp++) != 0)
186 putchar(ch);
187 if (++cnt == delimcnt) {
188 dp = delim;
189 cnt = 0;
190 }
191 }
192 putchar('\n');
193 }
194 if (fp != stdin)
195 (void)fclose(fp);
196 }
197 }
198
199 int
200 tr(char *arg)
201 {
202 int cnt;
203 char ch, *p;
204
205 for (p = arg, cnt = 0; (ch = *p++); ++arg, ++cnt)
206 if (ch == '\\')
207 switch(ch = *p++) {
208 case 'n':
209 *arg = '\n';
210 break;
211 case 't':
212 *arg = '\t';
213 break;
214 case '0':
215 *arg = '\0';
216 break;
217 default:
218 *arg = ch;
219 break;
220 } else
221 *arg = ch;
222
223 if (!cnt)
224 errx(1, "no delimiters specified.");
225 return(cnt);
226 }
227
228 void
229 usage()
230 {
231 (void)fprintf(stderr, "paste: [-s] [-d delimiters] file ...\n");
232 exit(1);
233 }
234