1 /* $NetBSD: paste.c,v 1.15 2009/04/07 01:52:26 dholland Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. 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 #include <sys/cdefs.h> 36 #ifndef lint 37 __COPYRIGHT("@(#) Copyright (c) 1989, 1993\ 38 The Regents of the University of California. All rights reserved."); 39 #endif /* not lint */ 40 41 #ifndef lint 42 /*static char sccsid[] = "from: @(#)paste.c 8.1 (Berkeley) 6/6/93";*/ 43 __RCSID("$NetBSD: paste.c,v 1.15 2009/04/07 01:52:26 dholland 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 void parallel(int, char **); 56 void sequential(char **); 57 int tr(char *); 58 void usage(void); 59 60 char dflt_delim[] = "\t"; 61 char *delim = dflt_delim; 62 int delimcnt = 1; 63 64 int 65 main(int argc, char **argv) 66 { 67 int ch, seq; 68 69 seq = 0; 70 while ((ch = getopt(argc, argv, "d:s")) != -1) { 71 switch (ch) { 72 case 'd': 73 delim = strdup(optarg); 74 delimcnt = tr(delim); 75 break; 76 case 's': 77 seq = 1; 78 break; 79 case '?': 80 default: 81 usage(); 82 } 83 } 84 argc -= optind; 85 argv += optind; 86 87 if (seq) 88 sequential(argv); 89 else 90 parallel(argc, argv); 91 exit(0); 92 } 93 94 void 95 parallel(int argc, char **argv) 96 { 97 char ch, *dp, *line; 98 FILE **fpp, *fp; 99 size_t line_len; 100 int cnt, output; 101 102 fpp = calloc(argc, sizeof *fpp); 103 if (fpp == NULL) 104 err(1, "calloc"); 105 106 for (cnt = 0; cnt < argc; cnt++) { 107 if (strcmp(argv[cnt], "-") == 0) 108 fpp[cnt] = stdin; 109 else if (!(fpp[cnt] = fopen(argv[cnt], "r"))) 110 err(1, "%s", argv[cnt]); 111 } 112 113 for (;;) { 114 /* Start with the NUL at the end of 'delim' ... */ 115 dp = delim + delimcnt; 116 output = 0; 117 for (cnt = 0; cnt < argc; cnt++) { 118 fp = fpp[cnt]; 119 if (fp == NULL) 120 continue; 121 line = fgetln(fp, &line_len); 122 if (line == NULL) { 123 /* Assume EOF */ 124 if (fp != stdin) 125 fclose(fp); 126 fpp[cnt] = NULL; 127 continue; 128 } 129 /* Output enough separators to catch up */ 130 do { 131 ch = *dp++; 132 if (ch) 133 putchar(ch); 134 if (dp >= delim + delimcnt) 135 dp = delim; 136 } while (++output <= cnt); 137 /* Remove any trailing newline - check for last line */ 138 if (line[line_len - 1] == '\n') 139 line_len--; 140 printf("%.*s", (int)line_len, line); 141 } 142 143 if (!output) 144 break; 145 146 /* Add separators to end of line */ 147 while (++output <= cnt) { 148 ch = *dp++; 149 if (ch) 150 putchar(ch); 151 if (dp >= delim + delimcnt) 152 dp = delim; 153 } 154 putchar('\n'); 155 } 156 157 free(fpp); 158 } 159 160 void 161 sequential(char **argv) 162 { 163 FILE *fp; 164 int cnt; 165 char ch, *p, *dp; 166 char buf[_POSIX2_LINE_MAX + 1]; 167 168 for (; (p = *argv) != NULL; ++argv) { 169 if (p[0] == '-' && !p[1]) 170 fp = stdin; 171 else if (!(fp = fopen(p, "r"))) { 172 warn("%s", p); 173 continue; 174 } 175 if (fgets(buf, sizeof(buf), fp)) { 176 for (cnt = 0, dp = delim;;) { 177 if (!(p = strchr(buf, '\n'))) 178 err(1, "%s: input line too long.", 179 *argv); 180 *p = '\0'; 181 (void)printf("%s", buf); 182 if (!fgets(buf, sizeof(buf), fp)) 183 break; 184 if ((ch = *dp++) != 0) 185 putchar(ch); 186 if (++cnt == delimcnt) { 187 dp = delim; 188 cnt = 0; 189 } 190 } 191 putchar('\n'); 192 } 193 if (fp != stdin) 194 (void)fclose(fp); 195 } 196 } 197 198 int 199 tr(char *arg) 200 { 201 int cnt; 202 char ch, *p; 203 204 for (p = arg, cnt = 0; (ch = *p++); ++arg, ++cnt) 205 if (ch == '\\') 206 switch(ch = *p++) { 207 case 'n': 208 *arg = '\n'; 209 break; 210 case 't': 211 *arg = '\t'; 212 break; 213 case '0': 214 *arg = '\0'; 215 break; 216 default: 217 *arg = ch; 218 break; 219 } else 220 *arg = ch; 221 222 if (!cnt) 223 errx(1, "no delimiters specified."); 224 *arg = '\0'; 225 return(cnt); 226 } 227 228 void 229 usage() 230 { 231 (void)fprintf(stderr, "paste: [-s] [-d delimiters] file ...\n"); 232 exit(1); 233 } 234