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