1 1.16 joerg /* $NetBSD: paste.c,v 1.16 2011/09/06 18:24:43 joerg Exp $ */ 2 1.3 tls 3 1.1 cgd /* 4 1.3 tls * Copyright (c) 1989, 1993 5 1.3 tls * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This code is derived from software contributed to Berkeley by 8 1.1 cgd * Adam S. Moskowitz of Menlo Consulting. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.7 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd */ 34 1.1 cgd 35 1.4 lukem #include <sys/cdefs.h> 36 1.1 cgd #ifndef lint 37 1.14 lukem __COPYRIGHT("@(#) Copyright (c) 1989, 1993\ 38 1.14 lukem The Regents of the University of California. All rights reserved."); 39 1.1 cgd #endif /* not lint */ 40 1.1 cgd 41 1.1 cgd #ifndef lint 42 1.3 tls /*static char sccsid[] = "from: @(#)paste.c 8.1 (Berkeley) 6/6/93";*/ 43 1.16 joerg __RCSID("$NetBSD: paste.c,v 1.16 2011/09/06 18:24:43 joerg Exp $"); 44 1.1 cgd #endif /* not lint */ 45 1.1 cgd 46 1.1 cgd #include <sys/types.h> 47 1.4 lukem #include <err.h> 48 1.1 cgd #include <errno.h> 49 1.1 cgd #include <limits.h> 50 1.1 cgd #include <stdio.h> 51 1.4 lukem #include <stdlib.h> 52 1.1 cgd #include <string.h> 53 1.5 perry #include <unistd.h> 54 1.1 cgd 55 1.16 joerg static void parallel(int, char **); 56 1.16 joerg static void sequential(char **); 57 1.16 joerg static int tr(char *); 58 1.16 joerg __dead static void usage(void); 59 1.16 joerg 60 1.16 joerg static char dflt_delim[] = "\t"; 61 1.16 joerg static char *delim = dflt_delim; 62 1.16 joerg static int delimcnt = 1; 63 1.1 cgd 64 1.4 lukem int 65 1.8 dsl main(int argc, char **argv) 66 1.1 cgd { 67 1.1 cgd int ch, seq; 68 1.1 cgd 69 1.1 cgd seq = 0; 70 1.9 dsl while ((ch = getopt(argc, argv, "d:s")) != -1) { 71 1.8 dsl switch (ch) { 72 1.1 cgd case 'd': 73 1.9 dsl delim = strdup(optarg); 74 1.9 dsl delimcnt = tr(delim); 75 1.1 cgd break; 76 1.1 cgd case 's': 77 1.1 cgd seq = 1; 78 1.1 cgd break; 79 1.1 cgd case '?': 80 1.1 cgd default: 81 1.1 cgd usage(); 82 1.1 cgd } 83 1.9 dsl } 84 1.1 cgd argc -= optind; 85 1.1 cgd argv += optind; 86 1.1 cgd 87 1.1 cgd if (seq) 88 1.1 cgd sequential(argv); 89 1.1 cgd else 90 1.9 dsl parallel(argc, argv); 91 1.1 cgd exit(0); 92 1.1 cgd } 93 1.1 cgd 94 1.16 joerg static void 95 1.9 dsl parallel(int argc, char **argv) 96 1.1 cgd { 97 1.9 dsl char ch, *dp, *line; 98 1.9 dsl FILE **fpp, *fp; 99 1.9 dsl size_t line_len; 100 1.9 dsl int cnt, output; 101 1.9 dsl 102 1.9 dsl fpp = calloc(argc, sizeof *fpp); 103 1.9 dsl if (fpp == NULL) 104 1.9 dsl err(1, "calloc"); 105 1.9 dsl 106 1.9 dsl for (cnt = 0; cnt < argc; cnt++) { 107 1.9 dsl if (strcmp(argv[cnt], "-") == 0) 108 1.9 dsl fpp[cnt] = stdin; 109 1.9 dsl else if (!(fpp[cnt] = fopen(argv[cnt], "r"))) 110 1.9 dsl err(1, "%s", argv[cnt]); 111 1.1 cgd } 112 1.1 cgd 113 1.9 dsl for (;;) { 114 1.9 dsl /* Start with the NUL at the end of 'delim' ... */ 115 1.9 dsl dp = delim + delimcnt; 116 1.9 dsl output = 0; 117 1.9 dsl for (cnt = 0; cnt < argc; cnt++) { 118 1.9 dsl fp = fpp[cnt]; 119 1.9 dsl if (fp == NULL) 120 1.9 dsl continue; 121 1.9 dsl line = fgetln(fp, &line_len); 122 1.9 dsl if (line == NULL) { 123 1.9 dsl /* Assume EOF */ 124 1.9 dsl if (fp != stdin) 125 1.9 dsl fclose(fp); 126 1.9 dsl fpp[cnt] = NULL; 127 1.1 cgd continue; 128 1.1 cgd } 129 1.9 dsl /* Output enough separators to catch up */ 130 1.9 dsl do { 131 1.9 dsl ch = *dp++; 132 1.9 dsl if (ch) 133 1.1 cgd putchar(ch); 134 1.9 dsl if (dp >= delim + delimcnt) 135 1.9 dsl dp = delim; 136 1.9 dsl } while (++output <= cnt); 137 1.9 dsl /* Remove any trailing newline - check for last line */ 138 1.9 dsl if (line[line_len - 1] == '\n') 139 1.9 dsl line_len--; 140 1.12 rtr printf("%.*s", (int)line_len, line); 141 1.9 dsl } 142 1.9 dsl 143 1.9 dsl if (!output) 144 1.9 dsl break; 145 1.9 dsl 146 1.9 dsl /* Add separators to end of line */ 147 1.9 dsl while (++output <= cnt) { 148 1.9 dsl ch = *dp++; 149 1.9 dsl if (ch) 150 1.1 cgd putchar(ch); 151 1.9 dsl if (dp >= delim + delimcnt) 152 1.9 dsl dp = delim; 153 1.1 cgd } 154 1.9 dsl putchar('\n'); 155 1.1 cgd } 156 1.9 dsl 157 1.9 dsl free(fpp); 158 1.1 cgd } 159 1.1 cgd 160 1.16 joerg static void 161 1.8 dsl sequential(char **argv) 162 1.1 cgd { 163 1.4 lukem FILE *fp; 164 1.4 lukem int cnt; 165 1.4 lukem char ch, *p, *dp; 166 1.1 cgd char buf[_POSIX2_LINE_MAX + 1]; 167 1.1 cgd 168 1.4 lukem for (; (p = *argv) != NULL; ++argv) { 169 1.1 cgd if (p[0] == '-' && !p[1]) 170 1.1 cgd fp = stdin; 171 1.1 cgd else if (!(fp = fopen(p, "r"))) { 172 1.4 lukem warn("%s", p); 173 1.1 cgd continue; 174 1.1 cgd } 175 1.1 cgd if (fgets(buf, sizeof(buf), fp)) { 176 1.1 cgd for (cnt = 0, dp = delim;;) { 177 1.4 lukem if (!(p = strchr(buf, '\n'))) 178 1.4 lukem err(1, "%s: input line too long.", 179 1.1 cgd *argv); 180 1.1 cgd *p = '\0'; 181 1.1 cgd (void)printf("%s", buf); 182 1.1 cgd if (!fgets(buf, sizeof(buf), fp)) 183 1.1 cgd break; 184 1.4 lukem if ((ch = *dp++) != 0) 185 1.1 cgd putchar(ch); 186 1.1 cgd if (++cnt == delimcnt) { 187 1.1 cgd dp = delim; 188 1.1 cgd cnt = 0; 189 1.1 cgd } 190 1.1 cgd } 191 1.1 cgd putchar('\n'); 192 1.1 cgd } 193 1.1 cgd if (fp != stdin) 194 1.1 cgd (void)fclose(fp); 195 1.1 cgd } 196 1.1 cgd } 197 1.1 cgd 198 1.16 joerg static int 199 1.8 dsl tr(char *arg) 200 1.1 cgd { 201 1.4 lukem int cnt; 202 1.4 lukem char ch, *p; 203 1.1 cgd 204 1.1 cgd for (p = arg, cnt = 0; (ch = *p++); ++arg, ++cnt) 205 1.1 cgd if (ch == '\\') 206 1.1 cgd switch(ch = *p++) { 207 1.1 cgd case 'n': 208 1.1 cgd *arg = '\n'; 209 1.1 cgd break; 210 1.1 cgd case 't': 211 1.1 cgd *arg = '\t'; 212 1.1 cgd break; 213 1.1 cgd case '0': 214 1.1 cgd *arg = '\0'; 215 1.1 cgd break; 216 1.1 cgd default: 217 1.1 cgd *arg = ch; 218 1.1 cgd break; 219 1.1 cgd } else 220 1.1 cgd *arg = ch; 221 1.1 cgd 222 1.4 lukem if (!cnt) 223 1.4 lukem errx(1, "no delimiters specified."); 224 1.15 dholland *arg = '\0'; 225 1.1 cgd return(cnt); 226 1.1 cgd } 227 1.1 cgd 228 1.16 joerg static void 229 1.16 joerg usage(void) 230 1.1 cgd { 231 1.1 cgd (void)fprintf(stderr, "paste: [-s] [-d delimiters] file ...\n"); 232 1.1 cgd exit(1); 233 1.1 cgd } 234