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