1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Adam S. Moskowitz of Menlo Consulting. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 static const char copyright[] = 39 "@(#) Copyright (c) 1989, 1993\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41 #endif /* not lint */ 42 43 #if 0 44 #ifndef lint 45 static char sccsid[] = "@(#)paste.c 8.1 (Berkeley) 6/6/93"; 46 #endif /* not lint */ 47 #endif 48 49 #include <sys/cdefs.h> 50 __FBSDID("$FreeBSD$"); 51 52 #include <sys/types.h> 53 54 #include <err.h> 55 #include <errno.h> 56 #include <limits.h> 57 #include <locale.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <unistd.h> 62 #include <wchar.h> 63 64 wchar_t *delim; 65 int delimcnt; 66 67 int parallel(char **); 68 int sequential(char **); 69 int tr(wchar_t *); 70 static void usage(void); 71 72 wchar_t tab[] = L"\t"; 73 74 int 75 main(int argc, char *argv[]) 76 { 77 int ch, rval, seq; 78 wchar_t *warg; 79 const char *arg; 80 size_t len; 81 82 setlocale(LC_CTYPE, ""); 83 84 seq = 0; 85 while ((ch = getopt(argc, argv, "d:s")) != -1) 86 switch(ch) { 87 case 'd': 88 arg = optarg; 89 len = mbsrtowcs(NULL, &arg, 0, NULL); 90 if (len == (size_t)-1) 91 err(1, "delimiters"); 92 warg = malloc((len + 1) * sizeof(*warg)); 93 if (warg == NULL) 94 err(1, NULL); 95 arg = optarg; 96 len = mbsrtowcs(warg, &arg, len + 1, NULL); 97 if (len == (size_t)-1) 98 err(1, "delimiters"); 99 delimcnt = tr(delim = warg); 100 break; 101 case 's': 102 seq = 1; 103 break; 104 case '?': 105 default: 106 usage(); 107 } 108 argc -= optind; 109 argv += optind; 110 111 if (*argv == NULL) 112 usage(); 113 if (!delim) { 114 delimcnt = 1; 115 delim = tab; 116 } 117 118 if (seq) 119 rval = sequential(argv); 120 else 121 rval = parallel(argv); 122 exit(rval); 123 } 124 125 typedef struct _list { 126 struct _list *next; 127 FILE *fp; 128 int cnt; 129 char *name; 130 } LIST; 131 132 int 133 parallel(char **argv) 134 { 135 LIST *lp; 136 int cnt; 137 wint_t ich; 138 wchar_t ch; 139 char *p; 140 LIST *head, *tmp; 141 int opencnt, output; 142 143 for (cnt = 0, head = NULL; (p = *argv); ++argv, ++cnt) { 144 if ((lp = malloc(sizeof(LIST))) == NULL) 145 err(1, NULL); 146 if (p[0] == '-' && !p[1]) 147 lp->fp = stdin; 148 else if (!(lp->fp = fopen(p, "r"))) 149 err(1, "%s", p); 150 lp->next = NULL; 151 lp->cnt = cnt; 152 lp->name = p; 153 if (!head) 154 head = tmp = lp; 155 else { 156 tmp->next = lp; 157 tmp = lp; 158 } 159 } 160 161 for (opencnt = cnt; opencnt;) { 162 for (output = 0, lp = head; lp; lp = lp->next) { 163 if (!lp->fp) { 164 if (output && lp->cnt && 165 (ch = delim[(lp->cnt - 1) % delimcnt])) 166 putwchar(ch); 167 continue; 168 } 169 if ((ich = getwc(lp->fp)) == WEOF) { 170 if (!--opencnt) 171 break; 172 lp->fp = NULL; 173 if (output && lp->cnt && 174 (ch = delim[(lp->cnt - 1) % delimcnt])) 175 putwchar(ch); 176 continue; 177 } 178 /* 179 * make sure that we don't print any delimiters 180 * unless there's a non-empty file. 181 */ 182 if (!output) { 183 output = 1; 184 for (cnt = 0; cnt < lp->cnt; ++cnt) 185 if ((ch = delim[cnt % delimcnt])) 186 putwchar(ch); 187 } else if ((ch = delim[(lp->cnt - 1) % delimcnt])) 188 putwchar(ch); 189 if (ich == '\n') 190 continue; 191 do { 192 putwchar(ich); 193 } while ((ich = getwc(lp->fp)) != WEOF && ich != '\n'); 194 } 195 if (output) 196 putwchar('\n'); 197 } 198 199 return (0); 200 } 201 202 int 203 sequential(char **argv) 204 { 205 FILE *fp; 206 int cnt, failed, needdelim; 207 wint_t ch; 208 char *p; 209 210 failed = 0; 211 for (; (p = *argv); ++argv) { 212 if (p[0] == '-' && !p[1]) 213 fp = stdin; 214 else if (!(fp = fopen(p, "r"))) { 215 warn("%s", p); 216 failed = 1; 217 continue; 218 } 219 cnt = needdelim = 0; 220 while ((ch = getwc(fp)) != WEOF) { 221 if (needdelim) { 222 needdelim = 0; 223 if (delim[cnt] != '\0') 224 putwchar(delim[cnt]); 225 if (++cnt == delimcnt) 226 cnt = 0; 227 } 228 if (ch != '\n') 229 putwchar(ch); 230 else 231 needdelim = 1; 232 } 233 if (needdelim) 234 putwchar('\n'); 235 if (fp != stdin) 236 (void)fclose(fp); 237 } 238 239 return (failed != 0); 240 } 241 242 int 243 tr(wchar_t *arg) 244 { 245 int cnt; 246 wchar_t ch, *p; 247 248 for (p = arg, cnt = 0; (ch = *p++); ++arg, ++cnt) 249 if (ch == '\\') 250 switch(ch = *p++) { 251 case 'n': 252 *arg = '\n'; 253 break; 254 case 't': 255 *arg = '\t'; 256 break; 257 case '0': 258 *arg = '\0'; 259 break; 260 default: 261 *arg = ch; 262 break; 263 } else 264 *arg = ch; 265 266 if (!cnt) 267 errx(1, "no delimiters specified"); 268 return(cnt); 269 } 270 271 static void 272 usage(void) 273 { 274 (void)fprintf(stderr, "usage: paste [-s] [-d delimiters] file ...\n"); 275 exit(1); 276 } 277