cut.c revision 1591
1126756Smlaier/* 2126756Smlaier * Copyright (c) 1989, 1993 3126756Smlaier * The Regents of the University of California. All rights reserved. 4126756Smlaier * 5126756Smlaier * This code is derived from software contributed to Berkeley by 6126756Smlaier * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue. 7126756Smlaier * 8126756Smlaier * Redistribution and use in source and binary forms, with or without 9126756Smlaier * modification, are permitted provided that the following conditions 10126756Smlaier * are met: 11126756Smlaier * 1. Redistributions of source code must retain the above copyright 12126756Smlaier * notice, this list of conditions and the following disclaimer. 13126756Smlaier * 2. Redistributions in binary form must reproduce the above copyright 14126756Smlaier * notice, this list of conditions and the following disclaimer in the 15126756Smlaier * documentation and/or other materials provided with the distribution. 16126756Smlaier * 3. All advertising materials mentioning features or use of this software 17126756Smlaier * must display the following acknowledgement: 18126756Smlaier * This product includes software developed by the University of 19126756Smlaier * California, Berkeley and its contributors. 20126756Smlaier * 4. Neither the name of the University nor the names of its contributors 21126756Smlaier * may be used to endorse or promote products derived from this software 22126756Smlaier * without specific prior written permission. 23126756Smlaier * 24126756Smlaier * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25126756Smlaier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26126756Smlaier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27126756Smlaier * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28126756Smlaier * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29126756Smlaier * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30126756Smlaier * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31126756Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32126756Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33126756Smlaier * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34126756Smlaier * SUCH DAMAGE. 35126756Smlaier */ 36126756Smlaier 37126756Smlaier#ifndef lint 38126756Smlaierstatic char copyright[] = 39126756Smlaier"@(#) Copyright (c) 1989, 1993\n\ 40126756Smlaier The Regents of the University of California. All rights reserved.\n"; 41126756Smlaier#endif /* not lint */ 42126756Smlaier 43126756Smlaier#ifndef lint 44126756Smlaierstatic char sccsid[] = "@(#)cut.c 8.1 (Berkeley) 6/6/93"; 45126756Smlaier#endif /* not lint */ 46126756Smlaier 47126756Smlaier#include <ctype.h> 48126756Smlaier#include <errno.h> 49126756Smlaier#include <limits.h> 50126756Smlaier#include <stdio.h> 51126756Smlaier#include <stdlib.h> 52126756Smlaier#include <string.h> 53126756Smlaier 54126756Smlaierint cflag; 55126756Smlaierchar dchar; 56126756Smlaierint dflag; 57126756Smlaierint fflag; 58126756Smlaierint sflag; 59126756Smlaier 60126756Smlaiervoid c_cut __P((FILE *, char *)); 61126756Smlaiervoid err __P((const char *, ...)); 62126756Smlaiervoid f_cut __P((FILE *, char *)); 63126756Smlaiervoid get_list __P((char *)); 64126756Smlaiervoid usage __P((void)); 65126756Smlaier 66126756Smlaierint 67126756Smlaiermain(argc, argv) 68126756Smlaier int argc; 69126756Smlaier char *argv[]; 70126756Smlaier{ 71126756Smlaier FILE *fp; 72126756Smlaier void (*fcn) __P((FILE *, char *)); 73126756Smlaier int ch; 74126756Smlaier 75126756Smlaier dchar = '\t'; /* default delimiter is \t */ 76126756Smlaier 77126756Smlaier while ((ch = getopt(argc, argv, "c:d:f:s")) != EOF) 78126756Smlaier switch(ch) { 79126756Smlaier case 'c': 80126756Smlaier fcn = c_cut; 81126756Smlaier get_list(optarg); 82126756Smlaier cflag = 1; 83126756Smlaier break; 84126756Smlaier case 'd': 85126756Smlaier dchar = *optarg; 86126756Smlaier dflag = 1; 87126756Smlaier break; 88126756Smlaier case 'f': 89126756Smlaier get_list(optarg); 90126756Smlaier fcn = f_cut; 91126756Smlaier fflag = 1; 92126756Smlaier break; 93126756Smlaier case 's': 94126756Smlaier sflag = 1; 95126756Smlaier break; 96126756Smlaier case '?': 97126756Smlaier default: 98126756Smlaier usage(); 99126756Smlaier } 100126756Smlaier argc -= optind; 101126756Smlaier argv += optind; 102126756Smlaier 103126756Smlaier if (fflag) { 104126756Smlaier if (cflag) 105126756Smlaier usage(); 106126756Smlaier } else if (!cflag || dflag || sflag) 107126756Smlaier usage(); 108126756Smlaier 109126756Smlaier if (*argv) 110126756Smlaier for (; *argv; ++argv) { 111126756Smlaier if (!(fp = fopen(*argv, "r"))) 112126756Smlaier err("%s: %s\n", *argv, strerror(errno)); 113126756Smlaier fcn(fp, *argv); 114126756Smlaier (void)fclose(fp); 115126756Smlaier } 116126756Smlaier else 117126756Smlaier fcn(stdin, "stdin"); 118126756Smlaier exit(0); 119126756Smlaier} 120126756Smlaier 121126756Smlaierint autostart, autostop, maxval; 122126756Smlaier 123126756Smlaierchar positions[_POSIX2_LINE_MAX + 1]; 124126756Smlaier 125126756Smlaiervoid 126126756Smlaierget_list(list) 127126756Smlaier char *list; 128126756Smlaier{ 129126756Smlaier register int setautostart, start, stop; 130126756Smlaier register char *pos; 131126756Smlaier char *p; 132126756Smlaier 133126756Smlaier /* 134126756Smlaier * set a byte in the positions array to indicate if a field or 135126756Smlaier * column is to be selected; use +1, it's 1-based, not 0-based. 136126756Smlaier * This parser is less restrictive than the Draft 9 POSIX spec. 137126756Smlaier * POSIX doesn't allow lists that aren't in increasing order or 138126756Smlaier * overlapping lists. We also handle "-3-5" although there's no 139126756Smlaier * real reason too. 140126756Smlaier */ 141126756Smlaier for (; p = strtok(list, ", \t"); list = NULL) { 142126756Smlaier setautostart = start = stop = 0; 143126756Smlaier if (*p == '-') { 144126756Smlaier ++p; 145126756Smlaier setautostart = 1; 146126756Smlaier } 147126756Smlaier if (isdigit(*p)) { 148126756Smlaier start = stop = strtol(p, &p, 10); 149126756Smlaier if (setautostart && start > autostart) 150126756Smlaier autostart = start; 151126756Smlaier } 152126756Smlaier if (*p == '-') { 153126756Smlaier if (isdigit(p[1])) 154126756Smlaier stop = strtol(p + 1, &p, 10); 155126756Smlaier if (*p == '-') { 156126756Smlaier ++p; 157126756Smlaier if (!autostop || autostop > stop) 158126756Smlaier autostop = stop; 159126756Smlaier } 160126756Smlaier } 161126756Smlaier if (*p) 162126756Smlaier err("[-cf] list: illegal list value\n"); 163126756Smlaier if (!stop || !start) 164126756Smlaier err("[-cf] list: values may not include zero\n"); 165126756Smlaier if (stop > _POSIX2_LINE_MAX) 166126756Smlaier err("[-cf] list: %d too large (max %d)\n", 167126756Smlaier stop, _POSIX2_LINE_MAX); 168126756Smlaier if (maxval < stop) 169126756Smlaier maxval = stop; 170126756Smlaier for (pos = positions + start; start++ <= stop; *pos++ = 1); 171126756Smlaier } 172126756Smlaier 173126756Smlaier /* overlapping ranges */ 174126756Smlaier if (autostop && maxval > autostop) 175126756Smlaier maxval = autostop; 176126756Smlaier 177126756Smlaier /* set autostart */ 178126756Smlaier if (autostart) 179126756Smlaier memset(positions + 1, '1', autostart); 180126756Smlaier} 181126756Smlaier 182126756Smlaier/* ARGSUSED */ 183126756Smlaiervoid 184126756Smlaierc_cut(fp, fname) 185126756Smlaier FILE *fp; 186126756Smlaier char *fname; 187126756Smlaier{ 188126756Smlaier register int ch, col; 189126756Smlaier register char *pos; 190126756Smlaier 191126756Smlaier for (;;) { 192126756Smlaier pos = positions + 1; 193126756Smlaier for (col = maxval; col; --col) { 194126756Smlaier if ((ch = getc(fp)) == EOF) 195126756Smlaier return; 196126756Smlaier if (ch == '\n') 197126756Smlaier break; 198126756Smlaier if (*pos++) 199126756Smlaier (void)putchar(ch); 200126756Smlaier } 201126756Smlaier if (ch != '\n') 202126756Smlaier if (autostop) 203126756Smlaier while ((ch = getc(fp)) != EOF && ch != '\n') 204126756Smlaier (void)putchar(ch); 205126756Smlaier else 206126756Smlaier while ((ch = getc(fp)) != EOF && ch != '\n'); 207126756Smlaier (void)putchar('\n'); 208126756Smlaier } 209126756Smlaier} 210126756Smlaier 211126756Smlaiervoid 212126756Smlaierf_cut(fp, fname) 213126756Smlaier FILE *fp; 214126756Smlaier char *fname; 215126756Smlaier{ 216126756Smlaier register int ch, field, isdelim; 217126756Smlaier register char *pos, *p, sep; 218126756Smlaier int output; 219126756Smlaier char lbuf[_POSIX2_LINE_MAX + 1]; 220126756Smlaier 221126756Smlaier for (sep = dchar, output = 0; fgets(lbuf, sizeof(lbuf), fp);) { 222126756Smlaier for (isdelim = 0, p = lbuf;; ++p) { 223126756Smlaier if (!(ch = *p)) 224126756Smlaier err("%s: line too long.\n", fname); 225126756Smlaier /* this should work if newline is delimiter */ 226126756Smlaier if (ch == sep) 227126756Smlaier isdelim = 1; 228126756Smlaier if (ch == '\n') { 229126756Smlaier if (!isdelim && !sflag) 230126756Smlaier (void)printf("%s", lbuf); 231126756Smlaier break; 232126756Smlaier } 233126756Smlaier } 234126756Smlaier if (!isdelim) 235126756Smlaier continue; 236126756Smlaier 237126756Smlaier pos = positions + 1; 238126756Smlaier for (field = maxval, p = lbuf; field; --field, ++pos) { 239126756Smlaier if (*pos) { 240126756Smlaier if (output++) 241126756Smlaier (void)putchar(sep); 242126756Smlaier while ((ch = *p++) != '\n' && ch != sep) 243126756Smlaier (void)putchar(ch); 244126756Smlaier } else 245126756Smlaier while ((ch = *p++) != '\n' && ch != sep); 246126756Smlaier if (ch == '\n') 247126756Smlaier break; 248126756Smlaier } 249126756Smlaier if (ch != '\n') 250126756Smlaier if (autostop) { 251126756Smlaier if (output) 252126756Smlaier (void)putchar(sep); 253126756Smlaier for (; (ch = *p) != '\n'; ++p) 254126756Smlaier (void)putchar(ch); 255126756Smlaier } else 256126756Smlaier for (; (ch = *p) != '\n'; ++p); 257126756Smlaier (void)putchar('\n'); 258126756Smlaier } 259126756Smlaier} 260126756Smlaier 261126756Smlaiervoid 262126756Smlaierusage() 263126756Smlaier{ 264126756Smlaier (void)fprintf(stderr, 265126756Smlaier"usage:\tcut -c list [file1 ...]\n\tcut -f list [-s] [-d delim] [file ...]\n"); 266126756Smlaier exit(1); 267126756Smlaier} 268126756Smlaier 269126756Smlaier#if __STDC__ 270126756Smlaier#include <stdarg.h> 271126756Smlaier#else 272126756Smlaier#include <varargs.h> 273126756Smlaier#endif 274126756Smlaier 275126756Smlaiervoid 276126756Smlaier#if __STDC__ 277126756Smlaiererr(const char *fmt, ...) 278126756Smlaier#else 279126756Smlaiererr(fmt, va_alist) 280126756Smlaier char *fmt; 281126756Smlaier va_dcl 282126756Smlaier#endif 283126756Smlaier{ 284126756Smlaier va_list ap; 285126756Smlaier#if __STDC__ 286126756Smlaier va_start(ap, fmt); 287126756Smlaier#else 288126756Smlaier va_start(ap); 289126756Smlaier#endif 290126756Smlaier (void)fprintf(stderr, "cut: "); 291126756Smlaier (void)vfprintf(stderr, fmt, ap); 292126756Smlaier va_end(ap); 293126756Smlaier (void)fprintf(stderr, "\n"); 294126756Smlaier exit(1); 295126756Smlaier /* NOTREACHED */ 296126756Smlaier} 297126756Smlaier