1 /* $OpenBSD: paste.c,v 1.14 2004/10/10 03:29:29 mickey 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.14 2004/10/10 03:29:29 mickey 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 err(1, "malloc"); 119 120 if (p[0] == '-' && !p[1]) 121 lp->fp = stdin; 122 else if (!(lp->fp = fopen(p, "r"))) 123 err(1, "%s", p); 124 lp->next = NULL; 125 lp->cnt = cnt; 126 lp->name = p; 127 if (!head) 128 head = tmp = lp; 129 else { 130 tmp->next = lp; 131 tmp = lp; 132 } 133 } 134 135 for (opencnt = cnt; opencnt;) { 136 for (output = 0, lp = head; lp; lp = lp->next) { 137 lbuf = NULL; 138 if (!lp->fp) { 139 if (output && lp->cnt && 140 (ch = delim[(lp->cnt - 1) % delimcnt])) 141 putchar(ch); 142 continue; 143 } 144 if (!(buf = fgetln(lp->fp, &len))) { 145 if (!--opencnt) 146 break; 147 lp->fp = NULL; 148 if (output && lp->cnt && 149 (ch = delim[(lp->cnt - 1) % delimcnt])) 150 putchar(ch); 151 continue; 152 } 153 if (*(buf + len - 1) == '\n') 154 *(buf + len - 1) = '\0'; 155 else { 156 if ((lbuf = malloc(len + 1)) == NULL) 157 err(1, "malloc"); 158 memcpy(lbuf, buf, len); 159 lbuf[len] = '\0'; 160 buf = lbuf; 161 } 162 /* 163 * make sure that we don't print any delimiters 164 * unless there's a non-empty file. 165 */ 166 if (!output) { 167 output = 1; 168 for (cnt = 0; cnt < lp->cnt; ++cnt) 169 if ((ch = delim[cnt % delimcnt])) 170 putchar(ch); 171 } else if ((ch = delim[(lp->cnt - 1) % delimcnt])) 172 putchar(ch); 173 (void)printf("%s", buf); 174 if (lbuf) 175 free(lbuf); 176 } 177 if (output) 178 putchar('\n'); 179 } 180 } 181 182 void 183 sequential(char **argv) 184 { 185 FILE *fp; 186 int cnt; 187 char ch, *p, *dp; 188 char *buf, *lbuf; 189 size_t len; 190 191 for (; (p = *argv); ++argv) { 192 lbuf = NULL; 193 if (p[0] == '-' && !p[1]) 194 fp = stdin; 195 else if (!(fp = fopen(p, "r"))) { 196 warn("%s", p); 197 continue; 198 } 199 if ((buf = fgetln(fp, &len))) { 200 for (cnt = 0, dp = delim;;) { 201 if (*(buf + len - 1) == '\n') 202 *(buf + len - 1) = '\0'; 203 else { 204 if ((lbuf = malloc(len + 1)) == NULL) 205 err(1, "malloc"); 206 memcpy(lbuf, buf, len); 207 lbuf[len] = '\0'; 208 buf = lbuf; 209 } 210 (void)printf("%s", buf); 211 if (!(buf = fgetln(fp, &len))) 212 break; 213 if ((ch = *dp++)) 214 putchar(ch); 215 if (++cnt == delimcnt) { 216 dp = delim; 217 cnt = 0; 218 } 219 } 220 putchar('\n'); 221 } 222 if (fp != stdin) 223 (void)fclose(fp); 224 if (lbuf) 225 free(lbuf); 226 } 227 } 228 229 int 230 tr(char *arg) 231 { 232 int cnt; 233 char ch, *p; 234 235 for (p = arg, cnt = 0; (ch = *p++); ++arg, ++cnt) 236 if (ch == '\\') 237 switch(ch = *p++) { 238 case 'n': 239 *arg = '\n'; 240 break; 241 case 't': 242 *arg = '\t'; 243 break; 244 case '0': 245 *arg = '\0'; 246 break; 247 default: 248 *arg = ch; 249 break; 250 } else 251 *arg = ch; 252 253 if (!cnt) 254 errx(1, "no delimiters specified"); 255 return(cnt); 256 } 257 258 void 259 usage(void) 260 { 261 extern char *__progname; 262 (void)fprintf(stderr, "usage: %s [-s] [-d delimiters] file ...\n", 263 __progname); 264 exit(1); 265 } 266