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