1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue. 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 char copyright[] = 39 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 40 All rights reserved.\n"; 41 #endif /* not lint */ 42 43 #ifndef lint 44 static char sccsid[] = "@(#)cut.c 5.4 (Berkeley) 10/30/90"; 45 #endif /* not lint */ 46 47 #include <limits.h> 48 #include <stdio.h> 49 #include <ctype.h> 50 51 int cflag; 52 char dchar; 53 int dflag; 54 int fflag; 55 int sflag; 56 57 main(argc, argv) 58 int argc; 59 char **argv; 60 { 61 extern char *optarg; 62 extern int errno, optind; 63 FILE *fp; 64 int ch, (*fcn)(), c_cut(), f_cut(); 65 char *strerror(); 66 67 dchar = '\t'; /* default delimiter is \t */ 68 69 while ((ch = getopt(argc, argv, "c:d:f:s")) != EOF) 70 switch(ch) { 71 case 'c': 72 fcn = c_cut; 73 get_list(optarg); 74 cflag = 1; 75 break; 76 case 'd': 77 dchar = *optarg; 78 dflag = 1; 79 break; 80 case 'f': 81 get_list(optarg); 82 fcn = f_cut; 83 fflag = 1; 84 break; 85 case 's': 86 sflag = 1; 87 break; 88 case '?': 89 default: 90 usage(); 91 } 92 argc -= optind; 93 argv += optind; 94 95 if (fflag) { 96 if (cflag) 97 usage(); 98 } else if (!cflag || dflag || sflag) 99 usage(); 100 101 if (*argv) 102 for (; *argv; ++argv) { 103 if (!(fp = fopen(*argv, "r"))) { 104 (void)fprintf(stderr, 105 "cut: %s: %s\n", *argv, strerror(errno)); 106 exit(1); 107 } 108 fcn(fp, *argv); 109 } 110 else 111 fcn(stdin, "stdin"); 112 exit(0); 113 } 114 115 int autostart, autostop, maxval; 116 117 char positions[_POSIX2_LINE_MAX + 1]; 118 119 get_list(list) 120 char *list; 121 { 122 register char *pos; 123 register int setautostart, start, stop; 124 char *p, *strtok(); 125 126 /* 127 * set a byte in the positions array to indicate if a field or 128 * column is to be selected; use +1, it's 1-based, not 0-based. 129 * This parser is less restrictive than the Draft 9 POSIX spec. 130 * POSIX doesn't allow lists that aren't in increasing order or 131 * overlapping lists. We also handle "-3-5" although there's no 132 * real reason too. 133 */ 134 for (; p = strtok(list, ", \t"); list = NULL) { 135 setautostart = start = stop = 0; 136 if (*p == '-') { 137 ++p; 138 setautostart = 1; 139 } 140 if (isdigit(*p)) { 141 start = stop = strtol(p, &p, 10); 142 if (setautostart && start > autostart) 143 autostart = start; 144 } 145 if (*p == '-') { 146 if (isdigit(p[1])) 147 stop = strtol(p + 1, &p, 10); 148 if (*p == '-') { 149 ++p; 150 if (!autostop || autostop > stop) 151 autostop = stop; 152 } 153 } 154 if (*p) 155 badlist("illegal list value"); 156 if (!stop || !start) 157 badlist("values may not include zero"); 158 if (stop > _POSIX2_LINE_MAX) { 159 /* positions used rather than allocate a new buffer */ 160 (void)sprintf(positions, "%d too large (max %d)", 161 stop, _POSIX2_LINE_MAX); 162 badlist(positions); 163 } 164 if (maxval < stop) 165 maxval = stop; 166 for (pos = positions + start; start++ <= stop; *pos++ = 1); 167 } 168 169 /* overlapping ranges */ 170 if (autostop && maxval > autostop) 171 maxval = autostop; 172 173 /* set autostart */ 174 if (autostart) 175 memset(positions + 1, '1', autostart); 176 } 177 178 /* ARGSUSED */ 179 c_cut(fp, fname) 180 FILE *fp; 181 char *fname; 182 { 183 register int ch, col; 184 register char *pos; 185 186 for (;;) { 187 pos = positions + 1; 188 for (col = maxval; col; --col) { 189 if ((ch = getc(fp)) == EOF) 190 return; 191 if (ch == '\n') 192 break; 193 if (*pos++) 194 putchar(ch); 195 } 196 if (ch != '\n') 197 if (autostop) 198 while ((ch = getc(fp)) != EOF && ch != '\n') 199 putchar(ch); 200 else 201 while ((ch = getc(fp)) != EOF && ch != '\n'); 202 putchar('\n'); 203 } 204 } 205 206 f_cut(fp, fname) 207 FILE *fp; 208 char *fname; 209 { 210 register int ch, field, isdelim; 211 register char *pos, *p, sep; 212 int output; 213 char lbuf[_POSIX2_LINE_MAX + 1]; 214 215 for (sep = dchar, output = 0; fgets(lbuf, sizeof(lbuf), fp); output = 0) { 216 for (isdelim = 0, p = lbuf;; ++p) { 217 if (!(ch = *p)) { 218 (void)fprintf(stderr, 219 "cut: %s: line too long.\n", fname); 220 exit(1); 221 } 222 /* this should work if newline is delimiter */ 223 if (ch == sep) 224 isdelim = 1; 225 if (ch == '\n') { 226 if (!isdelim && !sflag) 227 (void)printf("%s", lbuf); 228 break; 229 } 230 } 231 if (!isdelim) 232 continue; 233 234 pos = positions + 1; 235 for (field = maxval, p = lbuf; field; --field, ++pos) { 236 if (*pos) { 237 if (output++) 238 putchar(sep); 239 while ((ch = *p++) != '\n' && ch != sep) 240 putchar(ch); 241 } else 242 while ((ch = *p++) != '\n' && ch != sep); 243 if (ch == '\n') 244 break; 245 } 246 if (ch != '\n') 247 if (autostop) { 248 if (output) 249 putchar(sep); 250 for (; (ch = *p) != '\n'; ++p) 251 putchar(ch); 252 } else 253 for (; (ch = *p) != '\n'; ++p); 254 putchar('\n'); 255 } 256 } 257 258 badlist(msg) 259 char *msg; 260 { 261 (void)fprintf(stderr, "cut: [-cf] list: %s.\n", msg); 262 exit(1); 263 } 264 265 usage() 266 { 267 (void)fprintf(stderr, 268 "usage:\tcut -c list [file1 ...]\n\tcut -f list [-s] [-d delim] [file ...]\n"); 269 exit(1); 270 } 271