Annotation of src/usr.bin/paste/paste.c, Revision 1.19
1.19 ! tobias 1: /* $OpenBSD: paste.c,v 1.18 2010/08/12 05:02:52 tedu 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.
1.11 millert 18: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 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:
1.15 ray 35: #include <sys/queue.h>
1.1 deraadt 36: #include <sys/types.h>
1.13 david 37: #include <err.h>
1.1 deraadt 38: #include <errno.h>
39: #include <limits.h>
40: #include <stdio.h>
1.6 aaron 41: #include <stdlib.h>
1.1 deraadt 42: #include <string.h>
1.6 aaron 43: #include <unistd.h>
1.1 deraadt 44:
45: char *delim;
46: int delimcnt;
47:
1.10 millert 48: int tr(char *);
49: void usage(void);
50: void parallel(char **);
51: void sequential(char **);
1.5 deraadt 52:
53: int
1.12 deraadt 54: main(int argc, char *argv[])
1.1 deraadt 55: {
56: extern char *optarg;
57: extern int optind;
58: int ch, seq;
59:
60: seq = 0;
1.18 tedu 61: while ((ch = getopt(argc, argv, "d:s")) != -1) {
62: switch (ch) {
1.1 deraadt 63: case 'd':
64: delimcnt = tr(delim = optarg);
65: break;
66: case 's':
67: seq = 1;
68: break;
69: case '?':
70: default:
71: usage();
72: }
1.18 tedu 73: }
1.1 deraadt 74: argc -= optind;
75: argv += optind;
76:
77: if (!delim) {
78: delimcnt = 1;
79: delim = "\t";
80: }
81:
82: if (seq)
83: sequential(argv);
84: else
85: parallel(argv);
86: exit(0);
87: }
88:
1.15 ray 89: struct list {
90: SIMPLEQ_ENTRY(list) entries;
1.1 deraadt 91: FILE *fp;
92: int cnt;
93: char *name;
1.15 ray 94: };
1.1 deraadt 95:
1.5 deraadt 96: void
1.12 deraadt 97: parallel(char **argv)
1.1 deraadt 98: {
1.15 ray 99: SIMPLEQ_HEAD(, list) head = SIMPLEQ_HEAD_INITIALIZER(head);
100: struct list *lp;
1.9 mpech 101: int cnt;
102: char ch, *p;
1.1 deraadt 103: int opencnt, output;
1.7 aaron 104: char *buf, *lbuf;
1.6 aaron 105: size_t len;
1.1 deraadt 106:
1.15 ray 107: for (cnt = 0; (p = *argv); ++argv, ++cnt) {
108: if (!(lp = malloc(sizeof(struct list))))
1.14 mickey 109: err(1, "malloc");
110:
1.1 deraadt 111: if (p[0] == '-' && !p[1])
112: lp->fp = stdin;
1.14 mickey 113: else if (!(lp->fp = fopen(p, "r")))
114: err(1, "%s", p);
1.1 deraadt 115: lp->cnt = cnt;
116: lp->name = p;
1.15 ray 117: SIMPLEQ_INSERT_TAIL(&head, lp, entries);
1.1 deraadt 118: }
119:
120: for (opencnt = cnt; opencnt;) {
1.15 ray 121: output = 0;
122: SIMPLEQ_FOREACH(lp, &head, entries) {
1.8 aaron 123: lbuf = NULL;
1.1 deraadt 124: if (!lp->fp) {
125: if (output && lp->cnt &&
126: (ch = delim[(lp->cnt - 1) % delimcnt]))
127: putchar(ch);
128: continue;
129: }
1.7 aaron 130: if (!(buf = fgetln(lp->fp, &len))) {
1.1 deraadt 131: if (!--opencnt)
132: break;
1.19 ! tobias 133: if (lp->fp != stdin)
! 134: (void)fclose(lp->fp);
1.1 deraadt 135: lp->fp = NULL;
136: if (output && lp->cnt &&
137: (ch = delim[(lp->cnt - 1) % delimcnt]))
138: putchar(ch);
139: continue;
140: }
1.18 tedu 141: if (buf[len - 1] == '\n')
142: buf[len - 1] = '\0';
1.6 aaron 143: else {
1.8 aaron 144: if ((lbuf = malloc(len + 1)) == NULL)
1.14 mickey 145: err(1, "malloc");
1.7 aaron 146: memcpy(lbuf, buf, len);
147: lbuf[len] = '\0';
148: buf = lbuf;
1.1 deraadt 149: }
150: /*
151: * make sure that we don't print any delimiters
152: * unless there's a non-empty file.
153: */
154: if (!output) {
155: output = 1;
156: for (cnt = 0; cnt < lp->cnt; ++cnt)
1.5 deraadt 157: if ((ch = delim[cnt % delimcnt]))
1.1 deraadt 158: putchar(ch);
1.5 deraadt 159: } else if ((ch = delim[(lp->cnt - 1) % delimcnt]))
1.1 deraadt 160: putchar(ch);
1.7 aaron 161: (void)printf("%s", buf);
1.8 aaron 162: if (lbuf)
1.7 aaron 163: free(lbuf);
1.1 deraadt 164: }
165: if (output)
166: putchar('\n');
167: }
168: }
169:
1.5 deraadt 170: void
1.12 deraadt 171: sequential(char **argv)
1.1 deraadt 172: {
1.9 mpech 173: FILE *fp;
174: int cnt;
175: char ch, *p, *dp;
1.7 aaron 176: char *buf, *lbuf;
177: size_t len;
1.1 deraadt 178:
1.5 deraadt 179: for (; (p = *argv); ++argv) {
1.8 aaron 180: lbuf = NULL;
1.1 deraadt 181: if (p[0] == '-' && !p[1])
182: fp = stdin;
183: else if (!(fp = fopen(p, "r"))) {
1.14 mickey 184: warn("%s", p);
1.1 deraadt 185: continue;
186: }
1.7 aaron 187: if ((buf = fgetln(fp, &len))) {
1.1 deraadt 188: for (cnt = 0, dp = delim;;) {
1.18 tedu 189: if (buf[len - 1] == '\n')
190: buf[len - 1] = '\0';
1.7 aaron 191: else {
1.8 aaron 192: if ((lbuf = malloc(len + 1)) == NULL)
1.14 mickey 193: err(1, "malloc");
1.7 aaron 194: memcpy(lbuf, buf, len);
195: lbuf[len] = '\0';
196: buf = lbuf;
1.1 deraadt 197: }
198: (void)printf("%s", buf);
1.7 aaron 199: if (!(buf = fgetln(fp, &len)))
1.1 deraadt 200: break;
1.5 deraadt 201: if ((ch = *dp++))
1.1 deraadt 202: putchar(ch);
203: if (++cnt == delimcnt) {
204: dp = delim;
205: cnt = 0;
206: }
207: }
208: putchar('\n');
209: }
210: if (fp != stdin)
211: (void)fclose(fp);
1.8 aaron 212: if (lbuf)
1.7 aaron 213: free(lbuf);
1.1 deraadt 214: }
215: }
216:
1.5 deraadt 217: int
1.12 deraadt 218: tr(char *arg)
1.1 deraadt 219: {
1.9 mpech 220: int cnt;
221: char ch, *p;
1.1 deraadt 222:
1.18 tedu 223: for (p = arg, cnt = 0; (ch = *p++); ++arg, ++cnt) {
224: if (ch == '\\') {
225: switch (ch = *p++) {
1.1 deraadt 226: case 'n':
227: *arg = '\n';
228: break;
229: case 't':
230: *arg = '\t';
231: break;
232: case '0':
233: *arg = '\0';
234: break;
235: default:
236: *arg = ch;
237: break;
1.18 tedu 238: }
1.1 deraadt 239: } else
240: *arg = ch;
1.18 tedu 241: }
1.1 deraadt 242:
1.14 mickey 243: if (!cnt)
244: errx(1, "no delimiters specified");
1.18 tedu 245: return (cnt);
1.1 deraadt 246: }
247:
1.5 deraadt 248: void
1.12 deraadt 249: usage(void)
1.1 deraadt 250: {
1.14 mickey 251: extern char *__progname;
1.16 sobrado 252: (void)fprintf(stderr, "usage: %s [-s] [-d list] file ...\n",
253: __progname);
1.1 deraadt 254: exit(1);
255: }