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 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 static char copyright[] = 13 "@(#) Copyright (c) 1989, 1993\n\ 14 The Regents of the University of California. All rights reserved.\n"; 15 #endif /* not lint */ 16 17 #ifndef lint 18 static char sccsid[] = "@(#)paste.c 8.1 (Berkeley) 06/06/93"; 19 #endif /* not lint */ 20 21 #include <sys/types.h> 22 #include <errno.h> 23 #include <limits.h> 24 #include <stdio.h> 25 #include <string.h> 26 27 char *delim; 28 int delimcnt; 29 30 main(argc, argv) 31 int argc; 32 char **argv; 33 { 34 extern char *optarg; 35 extern int optind; 36 int ch, seq; 37 38 seq = 0; 39 while ((ch = getopt(argc, argv, "d:s")) != EOF) 40 switch(ch) { 41 case 'd': 42 delimcnt = tr(delim = optarg); 43 break; 44 case 's': 45 seq = 1; 46 break; 47 case '?': 48 default: 49 usage(); 50 } 51 argc -= optind; 52 argv += optind; 53 54 if (!delim) { 55 delimcnt = 1; 56 delim = "\t"; 57 } 58 59 if (seq) 60 sequential(argv); 61 else 62 parallel(argv); 63 exit(0); 64 } 65 66 typedef struct _list { 67 struct _list *next; 68 FILE *fp; 69 int cnt; 70 char *name; 71 } LIST; 72 73 parallel(argv) 74 char **argv; 75 { 76 register LIST *lp; 77 register int cnt; 78 register char ch, *p; 79 LIST *head, *tmp; 80 int opencnt, output; 81 char buf[_POSIX2_LINE_MAX + 1], *malloc(); 82 83 for (cnt = 0, head = NULL; p = *argv; ++argv, ++cnt) { 84 if (!(lp = (LIST *)malloc((u_int)sizeof(LIST)))) { 85 (void)fprintf(stderr, "paste: %s.\n", strerror(ENOMEM)); 86 exit(1); 87 } 88 if (p[0] == '-' && !p[1]) 89 lp->fp = stdin; 90 else if (!(lp->fp = fopen(p, "r"))) { 91 (void)fprintf(stderr, "paste: %s: %s.\n", p, 92 strerror(errno)); 93 exit(1); 94 } 95 lp->next = NULL; 96 lp->cnt = cnt; 97 lp->name = p; 98 if (!head) 99 head = tmp = lp; 100 else { 101 tmp->next = lp; 102 tmp = lp; 103 } 104 } 105 106 for (opencnt = cnt; opencnt;) { 107 for (output = 0, lp = head; lp; lp = lp->next) { 108 if (!lp->fp) { 109 if (output && lp->cnt && 110 (ch = delim[(lp->cnt - 1) % delimcnt])) 111 putchar(ch); 112 continue; 113 } 114 if (!fgets(buf, sizeof(buf), lp->fp)) { 115 if (!--opencnt) 116 break; 117 lp->fp = NULL; 118 if (output && lp->cnt && 119 (ch = delim[(lp->cnt - 1) % delimcnt])) 120 putchar(ch); 121 continue; 122 } 123 if (!(p = index(buf, '\n'))) { 124 (void)fprintf(stderr, 125 "paste: %s: input line too long.\n", 126 lp->name); 127 exit(1); 128 } 129 *p = '\0'; 130 /* 131 * make sure that we don't print any delimiters 132 * unless there's a non-empty file. 133 */ 134 if (!output) { 135 output = 1; 136 for (cnt = 0; cnt < lp->cnt; ++cnt) 137 if (ch = delim[cnt % delimcnt]) 138 putchar(ch); 139 } else if (ch = delim[(lp->cnt - 1) % delimcnt]) 140 putchar(ch); 141 (void)printf("%s", buf); 142 } 143 if (output) 144 putchar('\n'); 145 } 146 } 147 148 sequential(argv) 149 char **argv; 150 { 151 register FILE *fp; 152 register int cnt; 153 register char ch, *p, *dp; 154 char buf[_POSIX2_LINE_MAX + 1]; 155 156 for (; p = *argv; ++argv) { 157 if (p[0] == '-' && !p[1]) 158 fp = stdin; 159 else if (!(fp = fopen(p, "r"))) { 160 (void)fprintf(stderr, "paste: %s: %s.\n", p, 161 strerror(errno)); 162 continue; 163 } 164 if (fgets(buf, sizeof(buf), fp)) { 165 for (cnt = 0, dp = delim;;) { 166 if (!(p = index(buf, '\n'))) { 167 (void)fprintf(stderr, 168 "paste: %s: input line too long.\n", 169 *argv); 170 exit(1); 171 } 172 *p = '\0'; 173 (void)printf("%s", buf); 174 if (!fgets(buf, sizeof(buf), fp)) 175 break; 176 if (ch = *dp++) 177 putchar(ch); 178 if (++cnt == delimcnt) { 179 dp = delim; 180 cnt = 0; 181 } 182 } 183 putchar('\n'); 184 } 185 if (fp != stdin) 186 (void)fclose(fp); 187 } 188 } 189 190 tr(arg) 191 char *arg; 192 { 193 register int cnt; 194 register char ch, *p; 195 196 for (p = arg, cnt = 0; (ch = *p++); ++arg, ++cnt) 197 if (ch == '\\') 198 switch(ch = *p++) { 199 case 'n': 200 *arg = '\n'; 201 break; 202 case 't': 203 *arg = '\t'; 204 break; 205 case '0': 206 *arg = '\0'; 207 break; 208 default: 209 *arg = ch; 210 break; 211 } else 212 *arg = ch; 213 214 if (!cnt) { 215 (void)fprintf(stderr, "paste: no delimiters specified.\n"); 216 exit(1); 217 } 218 return(cnt); 219 } 220 221 usage() 222 { 223 (void)fprintf(stderr, "paste: [-s] [-d delimiters] file ...\n"); 224 exit(1); 225 } 226