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