1 /* $OpenBSD: paste.c,v 1.13 2003/07/10 00:06:51 david Exp $ */ 2 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. 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 #ifndef lint 36 char copyright[] = 37 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 38 All rights reserved.\n"; 39 #endif /* not lint */ 40 41 #ifndef lint 42 /*static char sccsid[] = "from: @(#)paste.c 5.7 (Berkeley) 10/30/90";*/ 43 static char rcsid[] = "$OpenBSD: paste.c,v 1.13 2003/07/10 00:06:51 david 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 <string.h> 53 #include <unistd.h> 54 55 char *delim; 56 int delimcnt; 57 58 int tr(char *); 59 void usage(void); 60 void parallel(char **); 61 void sequential(char **); 62 63 int 64 main(int argc, char *argv[]) 65 { 66 extern char *optarg; 67 extern int optind; 68 int ch, seq; 69 70 seq = 0; 71 while ((ch = getopt(argc, argv, "d:s")) != -1) 72 switch(ch) { 73 case 'd': 74 delimcnt = tr(delim = optarg); 75 break; 76 case 's': 77 seq = 1; 78 break; 79 case '?': 80 default: 81 usage(); 82 } 83 argc -= optind; 84 argv += optind; 85 86 if (!delim) { 87 delimcnt = 1; 88 delim = "\t"; 89 } 90 91 if (seq) 92 sequential(argv); 93 else 94 parallel(argv); 95 exit(0); 96 } 97 98 typedef struct _list { 99 struct _list *next; 100 FILE *fp; 101 int cnt; 102 char *name; 103 } LIST; 104 105 void 106 parallel(char **argv) 107 { 108 LIST *lp; 109 int cnt; 110 char ch, *p; 111 LIST *head, *tmp; 112 int opencnt, output; 113 char *buf, *lbuf; 114 size_t len; 115 116 for (cnt = 0, head = NULL; (p = *argv); ++argv, ++cnt) { 117 if (!(lp = (LIST *)malloc((u_int)sizeof(LIST)))) { 118 (void)fprintf(stderr, "paste: %s.\n", strerror(ENOMEM)); 119 exit(1); 120 } 121 if (p[0] == '-' && !p[1]) 122 lp->fp = stdin; 123 else if (!(lp->fp = fopen(p, "r"))) { 124 (void)fprintf(stderr, "paste: %s: %s.\n", p, 125 strerror(errno)); 126 exit(1); 127 } 128 lp->next = NULL; 129 lp->cnt = cnt; 130 lp->name = p; 131 if (!head) 132 head = tmp = lp; 133 else { 134 tmp->next = lp; 135 tmp = lp; 136 } 137 } 138 139 for (opencnt = cnt; opencnt;) { 140 for (output = 0, lp = head; lp; lp = lp->next) { 141 lbuf = NULL; 142 if (!lp->fp) { 143 if (output && lp->cnt && 144 (ch = delim[(lp->cnt - 1) % delimcnt])) 145 putchar(ch); 146 continue; 147 } 148 if (!(buf = fgetln(lp->fp, &len))) { 149 if (!--opencnt) 150 break; 151 lp->fp = NULL; 152 if (output && lp->cnt && 153 (ch = delim[(lp->cnt - 1) % delimcnt])) 154 putchar(ch); 155 continue; 156 } 157 if (*(buf + len - 1) == '\n') 158 *(buf + len - 1) = '\0'; 159 else { 160 if ((lbuf = malloc(len + 1)) == NULL) 161 err(1, NULL); 162 memcpy(lbuf, buf, len); 163 lbuf[len] = '\0'; 164 buf = lbuf; 165 } 166 /* 167 * make sure that we don't print any delimiters 168 * unless there's a non-empty file. 169 */ 170 if (!output) { 171 output = 1; 172 for (cnt = 0; cnt < lp->cnt; ++cnt) 173 if ((ch = delim[cnt % delimcnt])) 174 putchar(ch); 175 } else if ((ch = delim[(lp->cnt - 1) % delimcnt])) 176 putchar(ch); 177 (void)printf("%s", buf); 178 if (lbuf) 179 free(lbuf); 180 } 181 if (output) 182 putchar('\n'); 183 } 184 } 185 186 void 187 sequential(char **argv) 188 { 189 FILE *fp; 190 int cnt; 191 char ch, *p, *dp; 192 char *buf, *lbuf; 193 size_t len; 194 195 for (; (p = *argv); ++argv) { 196 lbuf = NULL; 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 ((buf = fgetln(fp, &len))) { 205 for (cnt = 0, dp = delim;;) { 206 if (*(buf + len - 1) == '\n') 207 *(buf + len - 1) = '\0'; 208 else { 209 if ((lbuf = malloc(len + 1)) == NULL) 210 err(1, NULL); 211 memcpy(lbuf, buf, len); 212 lbuf[len] = '\0'; 213 buf = lbuf; 214 } 215 (void)printf("%s", buf); 216 if (!(buf = fgetln(fp, &len))) 217 break; 218 if ((ch = *dp++)) 219 putchar(ch); 220 if (++cnt == delimcnt) { 221 dp = delim; 222 cnt = 0; 223 } 224 } 225 putchar('\n'); 226 } 227 if (fp != stdin) 228 (void)fclose(fp); 229 if (lbuf) 230 free(lbuf); 231 } 232 } 233 234 int 235 tr(char *arg) 236 { 237 int cnt; 238 char ch, *p; 239 240 for (p = arg, cnt = 0; (ch = *p++); ++arg, ++cnt) 241 if (ch == '\\') 242 switch(ch = *p++) { 243 case 'n': 244 *arg = '\n'; 245 break; 246 case 't': 247 *arg = '\t'; 248 break; 249 case '0': 250 *arg = '\0'; 251 break; 252 default: 253 *arg = ch; 254 break; 255 } else 256 *arg = ch; 257 258 if (!cnt) { 259 (void)fprintf(stderr, "paste: no delimiters specified.\n"); 260 exit(1); 261 } 262 return(cnt); 263 } 264 265 void 266 usage(void) 267 { 268 (void)fprintf(stderr, "paste: [-s] [-d delimiters] file ...\n"); 269 exit(1); 270 } 271