Annotation of src/usr.bin/paste/paste.c, Revision 1.18
1.18 ! tedu 1: /* $OpenBSD: paste.c,v 1.17 2009/10/27 23:59:41 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.
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;
133: lp->fp = NULL;
134: if (output && lp->cnt &&
135: (ch = delim[(lp->cnt - 1) % delimcnt]))
136: putchar(ch);
137: continue;
138: }
1.18 ! tedu 139: if (buf[len - 1] == '\n')
! 140: buf[len - 1] = '\0';
1.6 aaron 141: else {
1.8 aaron 142: if ((lbuf = malloc(len + 1)) == NULL)
1.14 mickey 143: err(1, "malloc");
1.7 aaron 144: memcpy(lbuf, buf, len);
145: lbuf[len] = '\0';
146: buf = lbuf;
1.1 deraadt 147: }
148: /*
149: * make sure that we don't print any delimiters
150: * unless there's a non-empty file.
151: */
152: if (!output) {
153: output = 1;
154: for (cnt = 0; cnt < lp->cnt; ++cnt)
1.5 deraadt 155: if ((ch = delim[cnt % delimcnt]))
1.1 deraadt 156: putchar(ch);
1.5 deraadt 157: } else if ((ch = delim[(lp->cnt - 1) % delimcnt]))
1.1 deraadt 158: putchar(ch);
1.7 aaron 159: (void)printf("%s", buf);
1.8 aaron 160: if (lbuf)
1.7 aaron 161: free(lbuf);
1.1 deraadt 162: }
163: if (output)
164: putchar('\n');
165: }
166: }
167:
1.5 deraadt 168: void
1.12 deraadt 169: sequential(char **argv)
1.1 deraadt 170: {
1.9 mpech 171: FILE *fp;
172: int cnt;
173: char ch, *p, *dp;
1.7 aaron 174: char *buf, *lbuf;
175: size_t len;
1.1 deraadt 176:
1.5 deraadt 177: for (; (p = *argv); ++argv) {
1.8 aaron 178: lbuf = NULL;
1.1 deraadt 179: if (p[0] == '-' && !p[1])
180: fp = stdin;
181: else if (!(fp = fopen(p, "r"))) {
1.14 mickey 182: warn("%s", p);
1.1 deraadt 183: continue;
184: }
1.7 aaron 185: if ((buf = fgetln(fp, &len))) {
1.1 deraadt 186: for (cnt = 0, dp = delim;;) {
1.18 ! tedu 187: if (buf[len - 1] == '\n')
! 188: buf[len - 1] = '\0';
1.7 aaron 189: else {
1.8 aaron 190: if ((lbuf = malloc(len + 1)) == NULL)
1.14 mickey 191: err(1, "malloc");
1.7 aaron 192: memcpy(lbuf, buf, len);
193: lbuf[len] = '\0';
194: buf = lbuf;
1.1 deraadt 195: }
196: (void)printf("%s", buf);
1.7 aaron 197: if (!(buf = fgetln(fp, &len)))
1.1 deraadt 198: break;
1.5 deraadt 199: if ((ch = *dp++))
1.1 deraadt 200: putchar(ch);
201: if (++cnt == delimcnt) {
202: dp = delim;
203: cnt = 0;
204: }
205: }
206: putchar('\n');
207: }
208: if (fp != stdin)
209: (void)fclose(fp);
1.8 aaron 210: if (lbuf)
1.7 aaron 211: free(lbuf);
1.1 deraadt 212: }
213: }
214:
1.5 deraadt 215: int
1.12 deraadt 216: tr(char *arg)
1.1 deraadt 217: {
1.9 mpech 218: int cnt;
219: char ch, *p;
1.1 deraadt 220:
1.18 ! tedu 221: for (p = arg, cnt = 0; (ch = *p++); ++arg, ++cnt) {
! 222: if (ch == '\\') {
! 223: switch (ch = *p++) {
1.1 deraadt 224: case 'n':
225: *arg = '\n';
226: break;
227: case 't':
228: *arg = '\t';
229: break;
230: case '0':
231: *arg = '\0';
232: break;
233: default:
234: *arg = ch;
235: break;
1.18 ! tedu 236: }
1.1 deraadt 237: } else
238: *arg = ch;
1.18 ! tedu 239: }
1.1 deraadt 240:
1.14 mickey 241: if (!cnt)
242: errx(1, "no delimiters specified");
1.18 ! tedu 243: return (cnt);
1.1 deraadt 244: }
245:
1.5 deraadt 246: void
1.12 deraadt 247: usage(void)
1.1 deraadt 248: {
1.14 mickey 249: extern char *__progname;
1.16 sobrado 250: (void)fprintf(stderr, "usage: %s [-s] [-d list] file ...\n",
251: __progname);
1.1 deraadt 252: exit(1);
253: }