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