cut.c revision 23693
181634Sbrian/* 281634Sbrian * Copyright (c) 1989, 1993 381634Sbrian * The Regents of the University of California. All rights reserved. 481634Sbrian * 581634Sbrian * This code is derived from software contributed to Berkeley by 681634Sbrian * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue. 781634Sbrian * 881634Sbrian * Redistribution and use in source and binary forms, with or without 981634Sbrian * modification, are permitted provided that the following conditions 1081634Sbrian * are met: 1181634Sbrian * 1. Redistributions of source code must retain the above copyright 1281634Sbrian * notice, this list of conditions and the following disclaimer. 1381634Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1481634Sbrian * notice, this list of conditions and the following disclaimer in the 1581634Sbrian * documentation and/or other materials provided with the distribution. 1681634Sbrian * 3. All advertising materials mentioning features or use of this software 1781634Sbrian * must display the following acknowledgement: 1881634Sbrian * This product includes software developed by the University of 1981634Sbrian * California, Berkeley and its contributors. 2081634Sbrian * 4. Neither the name of the University nor the names of its contributors 2181634Sbrian * may be used to endorse or promote products derived from this software 2281634Sbrian * without specific prior written permission. 2381634Sbrian * 2481634Sbrian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2581634Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2681634Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2781634Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2881634Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2981634Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3081634Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3181634Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3281634Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3381634Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3481634Sbrian * SUCH DAMAGE. 35102558Sbrian */ 36102558Sbrian 3781634Sbrian#ifndef lint 3881634Sbrianstatic char copyright[] = 3981634Sbrian"@(#) Copyright (c) 1989, 1993\n\ 4081634Sbrian The Regents of the University of California. All rights reserved.\n"; 4181634Sbrian#endif /* not lint */ 4281634Sbrian 4381634Sbrian#ifndef lint 4481634Sbrianstatic char sccsid[] = "@(#)cut.c 8.3 (Berkeley) 5/4/95"; 4581634Sbrian#endif /* not lint */ 46102558Sbrian 47102558Sbrian#include <ctype.h> 4881634Sbrian#include <errno.h> 4981634Sbrian#include <limits.h> 5081634Sbrian#include <stdio.h> 5181634Sbrian#include <stdlib.h> 5281634Sbrian#include <string.h> 5381634Sbrian#include <unistd.h> 5481634Sbrian 5581634Sbrianint cflag; 5681634Sbrianchar dchar; 5781634Sbrianint dflag; 5881634Sbrianint fflag; 5981634Sbrianint sflag; 6081634Sbrian 6181634Sbrianvoid c_cut __P((FILE *, char *)); 6281634Sbrianvoid err __P((const char *, ...)); 6381634Sbrianvoid f_cut __P((FILE *, char *)); 6481634Sbrianvoid get_list __P((char *)); 6581634Sbrianvoid usage __P((void)); 6681634Sbrian 6781634Sbrianint 6881634Sbrianmain(argc, argv) 6981634Sbrian int argc; 7081634Sbrian char *argv[]; 7181634Sbrian{ 7281634Sbrian FILE *fp; 7381634Sbrian void (*fcn) __P((FILE *, char *)); 7481634Sbrian int ch; 7581634Sbrian 7681634Sbrian dchar = '\t'; /* default delimiter is \t */ 7781634Sbrian 7881634Sbrian while ((ch = getopt(argc, argv, "c:d:f:s")) != EOF) 7981634Sbrian switch(ch) { 8081634Sbrian case 'c': 8181634Sbrian fcn = c_cut; 8281634Sbrian get_list(optarg); 8381634Sbrian cflag = 1; 84 break; 85 case 'd': 86 dchar = *optarg; 87 dflag = 1; 88 break; 89 case 'f': 90 get_list(optarg); 91 fcn = f_cut; 92 fflag = 1; 93 break; 94 case 's': 95 sflag = 1; 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 err("%s: %s\n", *argv, strerror(errno)); 114 fcn(fp, *argv); 115 (void)fclose(fp); 116 } 117 else 118 fcn(stdin, "stdin"); 119 exit(0); 120} 121 122int autostart, autostop, maxval; 123 124char positions[_POSIX2_LINE_MAX + 1]; 125 126void 127get_list(list) 128 char *list; 129{ 130 register int setautostart, start, stop; 131 register char *pos; 132 char *p; 133 134 /* 135 * set a byte in the positions array to indicate if a field or 136 * column is to be selected; use +1, it's 1-based, not 0-based. 137 * This parser is less restrictive than the Draft 9 POSIX spec. 138 * POSIX doesn't allow lists that aren't in increasing order or 139 * overlapping lists. We also handle "-3-5" although there's no 140 * real reason too. 141 */ 142 for (; p = strtok(list, ", \t"); list = NULL) { 143 setautostart = start = stop = 0; 144 if (*p == '-') { 145 ++p; 146 setautostart = 1; 147 } 148 if (isdigit(*p)) { 149 start = stop = strtol(p, &p, 10); 150 if (setautostart && start > autostart) 151 autostart = start; 152 } 153 if (*p == '-') { 154 if (isdigit(p[1])) 155 stop = strtol(p + 1, &p, 10); 156 if (*p == '-') { 157 ++p; 158 if (!autostop || autostop > stop) 159 autostop = stop; 160 } 161 } 162 if (*p) 163 err("[-cf] list: illegal list value\n"); 164 if (!stop || !start) 165 err("[-cf] list: values may not include zero\n"); 166 if (stop > _POSIX2_LINE_MAX) 167 err("[-cf] list: %d too large (max %d)\n", 168 stop, _POSIX2_LINE_MAX); 169 if (maxval < stop) 170 maxval = stop; 171 for (pos = positions + start; start++ <= stop; *pos++ = 1); 172 } 173 174 /* overlapping ranges */ 175 if (autostop && maxval > autostop) 176 maxval = autostop; 177 178 /* set autostart */ 179 if (autostart) 180 memset(positions + 1, '1', autostart); 181} 182 183/* ARGSUSED */ 184void 185c_cut(fp, fname) 186 FILE *fp; 187 char *fname; 188{ 189 register int ch, col; 190 register char *pos; 191 192 for (;;) { 193 pos = positions + 1; 194 for (col = maxval; col; --col) { 195 if ((ch = getc(fp)) == EOF) 196 return; 197 if (ch == '\n') 198 break; 199 if (*pos++) 200 (void)putchar(ch); 201 } 202 if (ch != '\n') 203 if (autostop) 204 while ((ch = getc(fp)) != EOF && ch != '\n') 205 (void)putchar(ch); 206 else 207 while ((ch = getc(fp)) != EOF && ch != '\n'); 208 (void)putchar('\n'); 209 } 210} 211 212void 213f_cut(fp, fname) 214 FILE *fp; 215 char *fname; 216{ 217 register int ch, field, isdelim; 218 register char *pos, *p, sep; 219 int output; 220 char lbuf[_POSIX2_LINE_MAX + 1]; 221 222 for (sep = dchar; fgets(lbuf, sizeof(lbuf), fp);) { 223 output = 0; 224 for (isdelim = 0, p = lbuf;; ++p) { 225 if (!(ch = *p)) 226 err("%s: line too long.\n", fname); 227 /* this should work if newline is delimiter */ 228 if (ch == sep) 229 isdelim = 1; 230 if (ch == '\n') { 231 if (!isdelim && !sflag) 232 (void)printf("%s", lbuf); 233 break; 234 } 235 } 236 if (!isdelim) 237 continue; 238 239 pos = positions + 1; 240 for (field = maxval, p = lbuf; field; --field, ++pos) { 241 if (*pos) { 242 if (output++) 243 (void)putchar(sep); 244 while ((ch = *p++) != '\n' && ch != sep) 245 (void)putchar(ch); 246 } else 247 while ((ch = *p++) != '\n' && ch != sep); 248 if (ch == '\n') 249 break; 250 } 251 if (ch != '\n') 252 if (autostop) { 253 if (output) 254 (void)putchar(sep); 255 for (; (ch = *p) != '\n'; ++p) 256 (void)putchar(ch); 257 } else 258 for (; (ch = *p) != '\n'; ++p); 259 (void)putchar('\n'); 260 } 261} 262 263void 264usage() 265{ 266 (void)fprintf(stderr, 267"usage:\tcut -c list [file1 ...]\n\tcut -f list [-s] [-d delim] [file ...]\n"); 268 exit(1); 269} 270 271#if __STDC__ 272#include <stdarg.h> 273#else 274#include <varargs.h> 275#endif 276 277void 278#if __STDC__ 279err(const char *fmt, ...) 280#else 281err(fmt, va_alist) 282 char *fmt; 283 va_dcl 284#endif 285{ 286 va_list ap; 287#if __STDC__ 288 va_start(ap, fmt); 289#else 290 va_start(ap); 291#endif 292 (void)fprintf(stderr, "cut: "); 293 (void)vfprintf(stderr, fmt, ap); 294 va_end(ap); 295 (void)fprintf(stderr, "\n"); 296 exit(1); 297 /* NOTREACHED */ 298} 299