docs/cut
changeset 14:21ad1c1548c4
Code ausgewaehlter Implementierungen eingefuegt
Das Datum entspricht dem Dateiaenderungsdatum.
author | markus schnalke <meillo@marmaro.de> |
---|---|
date | Tue, 12 May 2015 06:46:59 +0200 |
parents | bf5e41260f89 |
children | 77d1f55bba08 |
files | code/cut.c__4.3bsd-reno.1990-06-25 code/cut.c__4.3bsd-uwisc.1986-11-07 code/cut.c__freebsd.1994-05-27 code/cut.c__freebsd.2012-11-24 code/cut.c__gnu.1992-11-08 code/cut.c__gnu.2015-05-01 code/cut.c__heirloom.2012-05-20 code/cut.c__netbsd.1993-03-21 code/cut.c__netbsd.2014-02-03 code/cut.c__openbsd.2008-06-27 code/cut.c__system_iii.1980-04-11 |
diffstat | 11 files changed, 3966 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/code/cut.c__4.3bsd-reno.1990-06-25 Tue May 12 06:46:59 2015 +0200 1.3 @@ -0,0 +1,256 @@ 1.4 +/* 1.5 + * Copyright (c) 1989 The Regents of the University of California. 1.6 + * All rights reserved. 1.7 + * 1.8 + * This code is derived from software contributed to Berkeley by 1.9 + * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue. 1.10 + * 1.11 + * Redistribution and use in source and binary forms are permitted provided 1.12 + * that: (1) source distributions retain this entire copyright notice and 1.13 + * comment, and (2) distributions including binaries display the following 1.14 + * acknowledgement: ``This product includes software developed by the 1.15 + * University of California, Berkeley and its contributors'' in the 1.16 + * documentation or other materials provided with the distribution and in 1.17 + * all advertising materials mentioning features or use of this software. 1.18 + * Neither the name of the University nor the names of its contributors may 1.19 + * be used to endorse or promote products derived from this software without 1.20 + * specific prior written permission. 1.21 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1.22 + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1.23 + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1.24 + */ 1.25 + 1.26 +#ifndef lint 1.27 +char copyright[] = 1.28 +"@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 1.29 + All rights reserved.\n"; 1.30 +#endif /* not lint */ 1.31 + 1.32 +#ifndef lint 1.33 +static char sccsid[] = "@(#)cut.c 5.3 (Berkeley) 6/24/90"; 1.34 +#endif /* not lint */ 1.35 + 1.36 +#include <limits.h> 1.37 +#include <stdio.h> 1.38 +#include <ctype.h> 1.39 + 1.40 +int cflag; 1.41 +char dchar; 1.42 +int dflag; 1.43 +int fflag; 1.44 +int sflag; 1.45 + 1.46 +main(argc, argv) 1.47 + int argc; 1.48 + char **argv; 1.49 +{ 1.50 + extern char *optarg; 1.51 + extern int errno, optind; 1.52 + FILE *fp; 1.53 + int ch, (*fcn)(), c_cut(), f_cut(); 1.54 + char *strerror(); 1.55 + 1.56 + dchar = '\t'; /* default delimiter is \t */ 1.57 + 1.58 + while ((ch = getopt(argc, argv, "c:d:f:s")) != EOF) 1.59 + switch(ch) { 1.60 + case 'c': 1.61 + fcn = c_cut; 1.62 + get_list(optarg); 1.63 + cflag = 1; 1.64 + break; 1.65 + case 'd': 1.66 + dchar = *optarg; 1.67 + dflag = 1; 1.68 + break; 1.69 + case 'f': 1.70 + get_list(optarg); 1.71 + fcn = f_cut; 1.72 + fflag = 1; 1.73 + break; 1.74 + case 's': 1.75 + sflag = 1; 1.76 + break; 1.77 + case '?': 1.78 + default: 1.79 + usage(); 1.80 + } 1.81 + argc -= optind; 1.82 + argv += optind; 1.83 + 1.84 + if (fflag) { 1.85 + if (cflag) 1.86 + usage(); 1.87 + } else if (!cflag || dflag || sflag) 1.88 + usage(); 1.89 + 1.90 + if (*argv) 1.91 + for (; *argv; ++argv) { 1.92 + if (!(fp = fopen(*argv, "r"))) { 1.93 + (void)fprintf(stderr, 1.94 + "cut: %s: %s\n", *argv, strerror(errno)); 1.95 + exit(1); 1.96 + } 1.97 + fcn(fp, *argv); 1.98 + } 1.99 + else 1.100 + fcn(stdin, "stdin"); 1.101 + exit(0); 1.102 +} 1.103 + 1.104 +int autostart, autostop, maxval; 1.105 + 1.106 +char positions[_BSD_LINE_MAX + 1]; 1.107 + 1.108 +get_list(list) 1.109 + char *list; 1.110 +{ 1.111 + register char *pos; 1.112 + register int setautostart, start, stop; 1.113 + char *p, *strtok(); 1.114 + 1.115 + /* 1.116 + * set a byte in the positions array to indicate if a field or 1.117 + * column is to be selected; use +1, it's 1-based, not 0-based. 1.118 + * This parser is less restrictive than the Draft 9 POSIX spec. 1.119 + * POSIX doesn't allow lists that aren't in increasing order or 1.120 + * overlapping lists. We also handle "-3-5" although there's no 1.121 + * real reason too. 1.122 + */ 1.123 + for (; p = strtok(list, ", \t"); list = NULL) { 1.124 + setautostart = start = stop = 0; 1.125 + if (*p == '-') { 1.126 + ++p; 1.127 + setautostart = 1; 1.128 + } 1.129 + if (isdigit(*p)) { 1.130 + start = stop = strtol(p, &p, 10); 1.131 + if (setautostart && start > autostart) 1.132 + autostart = start; 1.133 + } 1.134 + if (*p == '-') { 1.135 + if (isdigit(p[1])) 1.136 + stop = strtol(p + 1, &p, 10); 1.137 + if (*p == '-') { 1.138 + ++p; 1.139 + if (!autostop || autostop > stop) 1.140 + autostop = stop; 1.141 + } 1.142 + } 1.143 + if (*p) 1.144 + badlist("illegal list value"); 1.145 + if (!stop || !start) 1.146 + badlist("values may not include zero"); 1.147 + if (stop > _BSD_LINE_MAX) { 1.148 + /* positions used rather than allocate a new buffer */ 1.149 + (void)sprintf(positions, "%d too large (max %d)", 1.150 + stop, _BSD_LINE_MAX); 1.151 + badlist(positions); 1.152 + } 1.153 + if (maxval < stop) 1.154 + maxval = stop; 1.155 + for (pos = positions + start; start++ <= stop; *pos++ = 1); 1.156 + } 1.157 + 1.158 + /* overlapping ranges */ 1.159 + if (autostop && maxval > autostop) 1.160 + maxval = autostop; 1.161 + 1.162 + /* set autostart */ 1.163 + if (autostart) 1.164 + memset(positions + 1, '1', autostart); 1.165 +} 1.166 + 1.167 +/* ARGSUSED */ 1.168 +c_cut(fp, fname) 1.169 + FILE *fp; 1.170 + char *fname; 1.171 +{ 1.172 + register int ch, col; 1.173 + register char *pos; 1.174 + 1.175 + for (;;) { 1.176 + pos = positions + 1; 1.177 + for (col = maxval; col; --col) { 1.178 + if ((ch = getc(fp)) == EOF) 1.179 + return; 1.180 + if (ch == '\n') 1.181 + break; 1.182 + if (*pos++) 1.183 + putchar(ch); 1.184 + } 1.185 + if (ch != '\n') 1.186 + if (autostop) 1.187 + while ((ch = getc(fp)) != EOF && ch != '\n') 1.188 + putchar(ch); 1.189 + else 1.190 + while ((ch = getc(fp)) != EOF && ch != '\n'); 1.191 + putchar('\n'); 1.192 + } 1.193 +} 1.194 + 1.195 +f_cut(fp, fname) 1.196 + FILE *fp; 1.197 + char *fname; 1.198 +{ 1.199 + register int ch, field, isdelim; 1.200 + register char *pos, *p, sep; 1.201 + int output; 1.202 + char lbuf[_BSD_LINE_MAX + 1]; 1.203 + 1.204 + for (sep = dchar, output = 0; fgets(lbuf, sizeof(lbuf), fp);) { 1.205 + for (isdelim = 0, p = lbuf;; ++p) { 1.206 + if (!(ch = *p)) { 1.207 + (void)fprintf(stderr, 1.208 + "cut: %s: line too long.\n", fname); 1.209 + exit(1); 1.210 + } 1.211 + /* this should work if newline is delimiter */ 1.212 + if (ch == sep) 1.213 + isdelim = 1; 1.214 + if (ch == '\n') { 1.215 + if (!isdelim && !sflag) 1.216 + (void)printf("%s", lbuf); 1.217 + break; 1.218 + } 1.219 + } 1.220 + if (!isdelim) 1.221 + continue; 1.222 + 1.223 + pos = positions + 1; 1.224 + for (field = maxval, p = lbuf; field; --field, ++pos) { 1.225 + if (*pos) { 1.226 + if (output++) 1.227 + putchar(sep); 1.228 + while ((ch = *p++) != '\n' && ch != sep) 1.229 + putchar(ch); 1.230 + } else 1.231 + while ((ch = *p++) != '\n' && ch != sep); 1.232 + if (ch == '\n') 1.233 + break; 1.234 + } 1.235 + if (ch != '\n') 1.236 + if (autostop) { 1.237 + if (output) 1.238 + putchar(sep); 1.239 + for (; (ch = *p) != '\n'; ++p) 1.240 + putchar(ch); 1.241 + } else 1.242 + for (; (ch = *p) != '\n'; ++p); 1.243 + putchar('\n'); 1.244 + } 1.245 +} 1.246 + 1.247 +badlist(msg) 1.248 + char *msg; 1.249 +{ 1.250 + (void)fprintf(stderr, "cut: [-cf] list: %s.\n", msg); 1.251 + exit(1); 1.252 +} 1.253 + 1.254 +usage() 1.255 +{ 1.256 + (void)fprintf(stderr, 1.257 +"usage:\tcut -c list [file1 ...]\n\tcut -f list [-s] [-d delim] [file ...]\n"); 1.258 + exit(1); 1.259 +}
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/code/cut.c__4.3bsd-uwisc.1986-11-07 Tue May 12 06:46:59 2015 +0200 2.3 @@ -0,0 +1,125 @@ 2.4 +static char sccsid[] = "@(#)cut.c 1.3"; 2.5 +# 2.6 +/* cut : cut and paste columns of a table (projection of a relation) */ 2.7 +/* Release 1.5; handles single backspaces as produced by nroff */ 2.8 +# include <stdio.h> /* make: cc cut.c */ 2.9 +# define NFIELDS 512 /* max no of fields or resulting line length */ 2.10 +# define BACKSPACE 8 2.11 +main(argc, argv) 2.12 +int argc; char **argv; 2.13 +{ 2.14 + int del = '\t'; 2.15 + int i, j, count, poscnt, r, s, t; 2.16 + int endflag, supflag, cflag, fflag, backflag, filenr; 2.17 + int sel[NFIELDS]; 2.18 + register int c; 2.19 + register char *p1; 2.20 + char *p2, outbuf[NFIELDS]; 2.21 + FILE *inptr; 2.22 + endflag = supflag = cflag = fflag = 0; 2.23 + 2.24 + 2.25 +while (argc > 1 && argv[1][0] == '-'){ 2.26 + for (i = 1; (c = argv[1][i]) != '\0'; i++) { 2.27 + switch(c) { 2.28 + case 'd' : del = argv[1][++i]; 2.29 + if (del == '\0') diag("no delimiter\n"); 2.30 + break; 2.31 + case 's': supflag++ ; 2.32 + break; 2.33 + case 'c': cflag++ ; 2.34 + break; 2.35 + case 'f': fflag++ ; 2.36 + break; 2.37 + default : diag("Usage: cut [-s] [-d<char>] {-c<list> | -f<list>} file ...\n"); 2.38 + break; 2.39 + } 2.40 + if (!endflag && (cflag || fflag)) { 2.41 + endflag = 1; 2.42 + r = s = t = 0; 2.43 + do { c = argv[1][++i]; 2.44 + switch(c) { 2.45 + case '-' : if (r) diagl(); 2.46 + r = 1; 2.47 + if (t == 0) s = 1; 2.48 + else {s = t; t = 0;} 2.49 + continue; 2.50 + case '\0' : 2.51 + case ',' : if (t >= NFIELDS) diagl(); 2.52 + if (r) { if (t == 0) t = NFIELDS - 1; 2.53 + if (t<s) diagl(); 2.54 + for(j = s; j <= t; j++) sel[j] = 1; 2.55 + } 2.56 + else sel[t] = (t > 0 ? 1 : 0); 2.57 + r = s = t = 0; 2.58 + if (c == '\0') {i--; break;} 2.59 + continue; 2.60 + default : 2.61 + if (c< '0' || c> '9') diagl(); 2.62 + t = 10*t + c - '0'; 2.63 + continue; 2.64 + } 2.65 + for (j = t = 0; j < NFIELDS; j++) t += sel[j]; 2.66 + if (t == 0) diag("no fields\n"); 2.67 + } while (c != '\0'); 2.68 + } 2.69 + } 2.70 + --argc; 2.71 + ++argv; 2.72 +} /* end options */ 2.73 +if (!(cflag || fflag)) diagl(); 2.74 + 2.75 +--argc; 2.76 +filenr = 1; 2.77 +do { /* for all input files */ 2.78 + if (argc > 0) inptr = fopen(argv[filenr], "r"); 2.79 + else inptr = stdin; 2.80 + 2.81 + if (inptr == NULL) { 2.82 + write(2,"Cannot open :",14); 2.83 + diag(argv[filenr]); 2.84 + } 2.85 + endflag = 0; 2.86 + do { /* for all lines of a file */ 2.87 + count = poscnt = backflag = 0; 2.88 + p1 = &outbuf[0] - 1 ; 2.89 + p2 = p1; 2.90 + do { /* for all char of the line */ 2.91 + c = fgetc(inptr); 2.92 + if (c == EOF) { 2.93 + endflag = 1; 2.94 + break; 2.95 + } 2.96 + if (count == NFIELDS - 1) diag("line too long\n"); 2.97 + if (c != '\n') *++p1 = c; 2.98 + if (cflag && (c == BACKSPACE)) backflag++ ; else 2.99 + { if ( !backflag ) poscnt += 1 ; else backflag-- ;} 2.100 + if ( backflag > 1 ) diag("cannot handle multiple adjacent backspaces\n"); 2.101 + if ( ((c == '\n') && count > 0) || c == del || cflag) { 2.102 + count += 1; 2.103 + if (fflag) poscnt = count ; 2.104 + if (sel[poscnt]) p2 = p1; else p1 = p2; 2.105 + } 2.106 + }while (c != '\n'); 2.107 + if ( !endflag && (count > 0 || !supflag)) { 2.108 + if (*p1 == del) *p1 = '\0'; 2.109 + else *++p1 = '\0'; /*suppress trailing delimiter*/ 2.110 + puts(outbuf); 2.111 + } 2.112 + } while (!endflag) ; 2.113 +fclose(inptr); 2.114 +} while(++filenr <= argc); 2.115 +} 2.116 + 2.117 +diag(s) 2.118 +char *s; 2.119 +{ 2.120 + write(2, "cut : ", 6); 2.121 + while(*s) 2.122 + write(2,s++,1); 2.123 + exit(2); 2.124 +} 2.125 +diagl() 2.126 +{ 2.127 +diag("bad list for c/f option\n"); 2.128 +}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/code/cut.c__freebsd.1994-05-27 Tue May 12 06:46:59 2015 +0200 3.3 @@ -0,0 +1,296 @@ 3.4 +/* 3.5 + * Copyright (c) 1989, 1993 3.6 + * The Regents of the University of California. All rights reserved. 3.7 + * 3.8 + * This code is derived from software contributed to Berkeley by 3.9 + * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue. 3.10 + * 3.11 + * Redistribution and use in source and binary forms, with or without 3.12 + * modification, are permitted provided that the following conditions 3.13 + * are met: 3.14 + * 1. Redistributions of source code must retain the above copyright 3.15 + * notice, this list of conditions and the following disclaimer. 3.16 + * 2. Redistributions in binary form must reproduce the above copyright 3.17 + * notice, this list of conditions and the following disclaimer in the 3.18 + * documentation and/or other materials provided with the distribution. 3.19 + * 3. All advertising materials mentioning features or use of this software 3.20 + * must display the following acknowledgement: 3.21 + * This product includes software developed by the University of 3.22 + * California, Berkeley and its contributors. 3.23 + * 4. Neither the name of the University nor the names of its contributors 3.24 + * may be used to endorse or promote products derived from this software 3.25 + * without specific prior written permission. 3.26 + * 3.27 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 3.28 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3.29 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3.30 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3.31 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3.32 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3.33 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3.34 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3.35 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3.36 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3.37 + * SUCH DAMAGE. 3.38 + */ 3.39 + 3.40 +#ifndef lint 3.41 +static char copyright[] = 3.42 +"@(#) Copyright (c) 1989, 1993\n\ 3.43 + The Regents of the University of California. All rights reserved.\n"; 3.44 +#endif /* not lint */ 3.45 + 3.46 +#ifndef lint 3.47 +static char sccsid[] = "@(#)cut.c 8.1 (Berkeley) 6/6/93"; 3.48 +#endif /* not lint */ 3.49 + 3.50 +#include <ctype.h> 3.51 +#include <errno.h> 3.52 +#include <limits.h> 3.53 +#include <stdio.h> 3.54 +#include <stdlib.h> 3.55 +#include <string.h> 3.56 + 3.57 +int cflag; 3.58 +char dchar; 3.59 +int dflag; 3.60 +int fflag; 3.61 +int sflag; 3.62 + 3.63 +void c_cut __P((FILE *, char *)); 3.64 +void err __P((const char *, ...)); 3.65 +void f_cut __P((FILE *, char *)); 3.66 +void get_list __P((char *)); 3.67 +void usage __P((void)); 3.68 + 3.69 +int 3.70 +main(argc, argv) 3.71 + int argc; 3.72 + char *argv[]; 3.73 +{ 3.74 + FILE *fp; 3.75 + void (*fcn) __P((FILE *, char *)); 3.76 + int ch; 3.77 + 3.78 + dchar = '\t'; /* default delimiter is \t */ 3.79 + 3.80 + while ((ch = getopt(argc, argv, "c:d:f:s")) != EOF) 3.81 + switch(ch) { 3.82 + case 'c': 3.83 + fcn = c_cut; 3.84 + get_list(optarg); 3.85 + cflag = 1; 3.86 + break; 3.87 + case 'd': 3.88 + dchar = *optarg; 3.89 + dflag = 1; 3.90 + break; 3.91 + case 'f': 3.92 + get_list(optarg); 3.93 + fcn = f_cut; 3.94 + fflag = 1; 3.95 + break; 3.96 + case 's': 3.97 + sflag = 1; 3.98 + break; 3.99 + case '?': 3.100 + default: 3.101 + usage(); 3.102 + } 3.103 + argc -= optind; 3.104 + argv += optind; 3.105 + 3.106 + if (fflag) { 3.107 + if (cflag) 3.108 + usage(); 3.109 + } else if (!cflag || dflag || sflag) 3.110 + usage(); 3.111 + 3.112 + if (*argv) 3.113 + for (; *argv; ++argv) { 3.114 + if (!(fp = fopen(*argv, "r"))) 3.115 + err("%s: %s\n", *argv, strerror(errno)); 3.116 + fcn(fp, *argv); 3.117 + (void)fclose(fp); 3.118 + } 3.119 + else 3.120 + fcn(stdin, "stdin"); 3.121 + exit(0); 3.122 +} 3.123 + 3.124 +int autostart, autostop, maxval; 3.125 + 3.126 +char positions[_POSIX2_LINE_MAX + 1]; 3.127 + 3.128 +void 3.129 +get_list(list) 3.130 + char *list; 3.131 +{ 3.132 + register int setautostart, start, stop; 3.133 + register char *pos; 3.134 + char *p; 3.135 + 3.136 + /* 3.137 + * set a byte in the positions array to indicate if a field or 3.138 + * column is to be selected; use +1, it's 1-based, not 0-based. 3.139 + * This parser is less restrictive than the Draft 9 POSIX spec. 3.140 + * POSIX doesn't allow lists that aren't in increasing order or 3.141 + * overlapping lists. We also handle "-3-5" although there's no 3.142 + * real reason too. 3.143 + */ 3.144 + for (; p = strtok(list, ", \t"); list = NULL) { 3.145 + setautostart = start = stop = 0; 3.146 + if (*p == '-') { 3.147 + ++p; 3.148 + setautostart = 1; 3.149 + } 3.150 + if (isdigit(*p)) { 3.151 + start = stop = strtol(p, &p, 10); 3.152 + if (setautostart && start > autostart) 3.153 + autostart = start; 3.154 + } 3.155 + if (*p == '-') { 3.156 + if (isdigit(p[1])) 3.157 + stop = strtol(p + 1, &p, 10); 3.158 + if (*p == '-') { 3.159 + ++p; 3.160 + if (!autostop || autostop > stop) 3.161 + autostop = stop; 3.162 + } 3.163 + } 3.164 + if (*p) 3.165 + err("[-cf] list: illegal list value\n"); 3.166 + if (!stop || !start) 3.167 + err("[-cf] list: values may not include zero\n"); 3.168 + if (stop > _POSIX2_LINE_MAX) 3.169 + err("[-cf] list: %d too large (max %d)\n", 3.170 + stop, _POSIX2_LINE_MAX); 3.171 + if (maxval < stop) 3.172 + maxval = stop; 3.173 + for (pos = positions + start; start++ <= stop; *pos++ = 1); 3.174 + } 3.175 + 3.176 + /* overlapping ranges */ 3.177 + if (autostop && maxval > autostop) 3.178 + maxval = autostop; 3.179 + 3.180 + /* set autostart */ 3.181 + if (autostart) 3.182 + memset(positions + 1, '1', autostart); 3.183 +} 3.184 + 3.185 +/* ARGSUSED */ 3.186 +void 3.187 +c_cut(fp, fname) 3.188 + FILE *fp; 3.189 + char *fname; 3.190 +{ 3.191 + register int ch, col; 3.192 + register char *pos; 3.193 + 3.194 + for (;;) { 3.195 + pos = positions + 1; 3.196 + for (col = maxval; col; --col) { 3.197 + if ((ch = getc(fp)) == EOF) 3.198 + return; 3.199 + if (ch == '\n') 3.200 + break; 3.201 + if (*pos++) 3.202 + (void)putchar(ch); 3.203 + } 3.204 + if (ch != '\n') 3.205 + if (autostop) 3.206 + while ((ch = getc(fp)) != EOF && ch != '\n') 3.207 + (void)putchar(ch); 3.208 + else 3.209 + while ((ch = getc(fp)) != EOF && ch != '\n'); 3.210 + (void)putchar('\n'); 3.211 + } 3.212 +} 3.213 + 3.214 +void 3.215 +f_cut(fp, fname) 3.216 + FILE *fp; 3.217 + char *fname; 3.218 +{ 3.219 + register int ch, field, isdelim; 3.220 + register char *pos, *p, sep; 3.221 + int output; 3.222 + char lbuf[_POSIX2_LINE_MAX + 1]; 3.223 + 3.224 + for (sep = dchar, output = 0; fgets(lbuf, sizeof(lbuf), fp);) { 3.225 + for (isdelim = 0, p = lbuf;; ++p) { 3.226 + if (!(ch = *p)) 3.227 + err("%s: line too long.\n", fname); 3.228 + /* this should work if newline is delimiter */ 3.229 + if (ch == sep) 3.230 + isdelim = 1; 3.231 + if (ch == '\n') { 3.232 + if (!isdelim && !sflag) 3.233 + (void)printf("%s", lbuf); 3.234 + break; 3.235 + } 3.236 + } 3.237 + if (!isdelim) 3.238 + continue; 3.239 + 3.240 + pos = positions + 1; 3.241 + for (field = maxval, p = lbuf; field; --field, ++pos) { 3.242 + if (*pos) { 3.243 + if (output++) 3.244 + (void)putchar(sep); 3.245 + while ((ch = *p++) != '\n' && ch != sep) 3.246 + (void)putchar(ch); 3.247 + } else 3.248 + while ((ch = *p++) != '\n' && ch != sep); 3.249 + if (ch == '\n') 3.250 + break; 3.251 + } 3.252 + if (ch != '\n') 3.253 + if (autostop) { 3.254 + if (output) 3.255 + (void)putchar(sep); 3.256 + for (; (ch = *p) != '\n'; ++p) 3.257 + (void)putchar(ch); 3.258 + } else 3.259 + for (; (ch = *p) != '\n'; ++p); 3.260 + (void)putchar('\n'); 3.261 + } 3.262 +} 3.263 + 3.264 +void 3.265 +usage() 3.266 +{ 3.267 + (void)fprintf(stderr, 3.268 +"usage:\tcut -c list [file1 ...]\n\tcut -f list [-s] [-d delim] [file ...]\n"); 3.269 + exit(1); 3.270 +} 3.271 + 3.272 +#if __STDC__ 3.273 +#include <stdarg.h> 3.274 +#else 3.275 +#include <varargs.h> 3.276 +#endif 3.277 + 3.278 +void 3.279 +#if __STDC__ 3.280 +err(const char *fmt, ...) 3.281 +#else 3.282 +err(fmt, va_alist) 3.283 + char *fmt; 3.284 + va_dcl 3.285 +#endif 3.286 +{ 3.287 + va_list ap; 3.288 +#if __STDC__ 3.289 + va_start(ap, fmt); 3.290 +#else 3.291 + va_start(ap); 3.292 +#endif 3.293 + (void)fprintf(stderr, "cut: "); 3.294 + (void)vfprintf(stderr, fmt, ap); 3.295 + va_end(ap); 3.296 + (void)fprintf(stderr, "\n"); 3.297 + exit(1); 3.298 + /* NOTREACHED */ 3.299 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/code/cut.c__freebsd.2012-11-24 Tue May 12 06:46:59 2015 +0200 4.3 @@ -0,0 +1,479 @@ 4.4 +/* 4.5 + * Copyright (c) 1989, 1993 4.6 + * The Regents of the University of California. All rights reserved. 4.7 + * 4.8 + * This code is derived from software contributed to Berkeley by 4.9 + * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue. 4.10 + * 4.11 + * Redistribution and use in source and binary forms, with or without 4.12 + * modification, are permitted provided that the following conditions 4.13 + * are met: 4.14 + * 1. Redistributions of source code must retain the above copyright 4.15 + * notice, this list of conditions and the following disclaimer. 4.16 + * 2. Redistributions in binary form must reproduce the above copyright 4.17 + * notice, this list of conditions and the following disclaimer in the 4.18 + * documentation and/or other materials provided with the distribution. 4.19 + * 4. Neither the name of the University nor the names of its contributors 4.20 + * may be used to endorse or promote products derived from this software 4.21 + * without specific prior written permission. 4.22 + * 4.23 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 4.24 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4.25 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4.26 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 4.27 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4.28 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4.29 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4.30 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4.31 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 4.32 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 4.33 + * SUCH DAMAGE. 4.34 + */ 4.35 + 4.36 +#ifndef lint 4.37 +static const char copyright[] = 4.38 +"@(#) Copyright (c) 1989, 1993\n\ 4.39 + The Regents of the University of California. All rights reserved.\n"; 4.40 +static const char sccsid[] = "@(#)cut.c 8.3 (Berkeley) 5/4/95"; 4.41 +#endif /* not lint */ 4.42 +#include <sys/cdefs.h> 4.43 +__FBSDID("$FreeBSD$"); 4.44 + 4.45 +#include <ctype.h> 4.46 +#include <err.h> 4.47 +#include <errno.h> 4.48 +#include <limits.h> 4.49 +#include <locale.h> 4.50 +#include <stdio.h> 4.51 +#include <stdlib.h> 4.52 +#include <string.h> 4.53 +#include <unistd.h> 4.54 +#include <wchar.h> 4.55 + 4.56 +static int bflag; 4.57 +static int cflag; 4.58 +static wchar_t dchar; 4.59 +static char dcharmb[MB_LEN_MAX + 1]; 4.60 +static int dflag; 4.61 +static int fflag; 4.62 +static int nflag; 4.63 +static int sflag; 4.64 +static int wflag; 4.65 + 4.66 +static size_t autostart, autostop, maxval; 4.67 +static char * positions; 4.68 + 4.69 +static int b_cut(FILE *, const char *); 4.70 +static int b_n_cut(FILE *, const char *); 4.71 +static int c_cut(FILE *, const char *); 4.72 +static int f_cut(FILE *, const char *); 4.73 +static void get_list(char *); 4.74 +static int is_delim(wchar_t); 4.75 +static void needpos(size_t); 4.76 +static void usage(void); 4.77 + 4.78 +int 4.79 +main(int argc, char *argv[]) 4.80 +{ 4.81 + FILE *fp; 4.82 + int (*fcn)(FILE *, const char *); 4.83 + int ch, rval; 4.84 + size_t n; 4.85 + 4.86 + setlocale(LC_ALL, ""); 4.87 + 4.88 + fcn = NULL; 4.89 + dchar = '\t'; /* default delimiter is \t */ 4.90 + strcpy(dcharmb, "\t"); 4.91 + 4.92 + while ((ch = getopt(argc, argv, "b:c:d:f:snw")) != -1) 4.93 + switch(ch) { 4.94 + case 'b': 4.95 + get_list(optarg); 4.96 + bflag = 1; 4.97 + break; 4.98 + case 'c': 4.99 + get_list(optarg); 4.100 + cflag = 1; 4.101 + break; 4.102 + case 'd': 4.103 + n = mbrtowc(&dchar, optarg, MB_LEN_MAX, NULL); 4.104 + if (dchar == '\0' || n != strlen(optarg)) 4.105 + errx(1, "bad delimiter"); 4.106 + strcpy(dcharmb, optarg); 4.107 + dflag = 1; 4.108 + break; 4.109 + case 'f': 4.110 + get_list(optarg); 4.111 + fflag = 1; 4.112 + break; 4.113 + case 's': 4.114 + sflag = 1; 4.115 + break; 4.116 + case 'n': 4.117 + nflag = 1; 4.118 + break; 4.119 + case 'w': 4.120 + wflag = 1; 4.121 + break; 4.122 + case '?': 4.123 + default: 4.124 + usage(); 4.125 + } 4.126 + argc -= optind; 4.127 + argv += optind; 4.128 + 4.129 + if (fflag) { 4.130 + if (bflag || cflag || nflag || (wflag && dflag)) 4.131 + usage(); 4.132 + } else if (!(bflag || cflag) || dflag || sflag || wflag) 4.133 + usage(); 4.134 + else if (!bflag && nflag) 4.135 + usage(); 4.136 + 4.137 + if (fflag) 4.138 + fcn = f_cut; 4.139 + else if (cflag) 4.140 + fcn = MB_CUR_MAX > 1 ? c_cut : b_cut; 4.141 + else if (bflag) 4.142 + fcn = nflag && MB_CUR_MAX > 1 ? b_n_cut : b_cut; 4.143 + 4.144 + rval = 0; 4.145 + if (*argv) 4.146 + for (; *argv; ++argv) { 4.147 + if (strcmp(*argv, "-") == 0) 4.148 + rval |= fcn(stdin, "stdin"); 4.149 + else { 4.150 + if (!(fp = fopen(*argv, "r"))) { 4.151 + warn("%s", *argv); 4.152 + rval = 1; 4.153 + continue; 4.154 + } 4.155 + fcn(fp, *argv); 4.156 + (void)fclose(fp); 4.157 + } 4.158 + } 4.159 + else 4.160 + rval = fcn(stdin, "stdin"); 4.161 + exit(rval); 4.162 +} 4.163 + 4.164 +static void 4.165 +get_list(char *list) 4.166 +{ 4.167 + size_t setautostart, start, stop; 4.168 + char *pos; 4.169 + char *p; 4.170 + 4.171 + /* 4.172 + * set a byte in the positions array to indicate if a field or 4.173 + * column is to be selected; use +1, it's 1-based, not 0-based. 4.174 + * Numbers and number ranges may be overlapping, repeated, and in 4.175 + * any order. We handle "-3-5" although there's no real reason to. 4.176 + */ 4.177 + for (; (p = strsep(&list, ", \t")) != NULL;) { 4.178 + setautostart = start = stop = 0; 4.179 + if (*p == '-') { 4.180 + ++p; 4.181 + setautostart = 1; 4.182 + } 4.183 + if (isdigit((unsigned char)*p)) { 4.184 + start = stop = strtol(p, &p, 10); 4.185 + if (setautostart && start > autostart) 4.186 + autostart = start; 4.187 + } 4.188 + if (*p == '-') { 4.189 + if (isdigit((unsigned char)p[1])) 4.190 + stop = strtol(p + 1, &p, 10); 4.191 + if (*p == '-') { 4.192 + ++p; 4.193 + if (!autostop || autostop > stop) 4.194 + autostop = stop; 4.195 + } 4.196 + } 4.197 + if (*p) 4.198 + errx(1, "[-bcf] list: illegal list value"); 4.199 + if (!stop || !start) 4.200 + errx(1, "[-bcf] list: values may not include zero"); 4.201 + if (maxval < stop) { 4.202 + maxval = stop; 4.203 + needpos(maxval + 1); 4.204 + } 4.205 + for (pos = positions + start; start++ <= stop; *pos++ = 1); 4.206 + } 4.207 + 4.208 + /* overlapping ranges */ 4.209 + if (autostop && maxval > autostop) { 4.210 + maxval = autostop; 4.211 + needpos(maxval + 1); 4.212 + } 4.213 + 4.214 + /* set autostart */ 4.215 + if (autostart) 4.216 + memset(positions + 1, '1', autostart); 4.217 +} 4.218 + 4.219 +static void 4.220 +needpos(size_t n) 4.221 +{ 4.222 + static size_t npos; 4.223 + size_t oldnpos; 4.224 + 4.225 + /* Grow the positions array to at least the specified size. */ 4.226 + if (n > npos) { 4.227 + oldnpos = npos; 4.228 + if (npos == 0) 4.229 + npos = n; 4.230 + while (n > npos) 4.231 + npos *= 2; 4.232 + if ((positions = realloc(positions, npos)) == NULL) 4.233 + err(1, "realloc"); 4.234 + memset((char *)positions + oldnpos, 0, npos - oldnpos); 4.235 + } 4.236 +} 4.237 + 4.238 +static int 4.239 +b_cut(FILE *fp, const char *fname __unused) 4.240 +{ 4.241 + int ch, col; 4.242 + char *pos; 4.243 + 4.244 + ch = 0; 4.245 + for (;;) { 4.246 + pos = positions + 1; 4.247 + for (col = maxval; col; --col) { 4.248 + if ((ch = getc(fp)) == EOF) 4.249 + return (0); 4.250 + if (ch == '\n') 4.251 + break; 4.252 + if (*pos++) 4.253 + (void)putchar(ch); 4.254 + } 4.255 + if (ch != '\n') { 4.256 + if (autostop) 4.257 + while ((ch = getc(fp)) != EOF && ch != '\n') 4.258 + (void)putchar(ch); 4.259 + else 4.260 + while ((ch = getc(fp)) != EOF && ch != '\n'); 4.261 + } 4.262 + (void)putchar('\n'); 4.263 + } 4.264 + return (0); 4.265 +} 4.266 + 4.267 +/* 4.268 + * Cut based on byte positions, taking care not to split multibyte characters. 4.269 + * Although this function also handles the case where -n is not specified, 4.270 + * b_cut() ought to be much faster. 4.271 + */ 4.272 +static int 4.273 +b_n_cut(FILE *fp, const char *fname) 4.274 +{ 4.275 + size_t col, i, lbuflen; 4.276 + char *lbuf; 4.277 + int canwrite, clen, warned; 4.278 + mbstate_t mbs; 4.279 + 4.280 + memset(&mbs, 0, sizeof(mbs)); 4.281 + warned = 0; 4.282 + while ((lbuf = fgetln(fp, &lbuflen)) != NULL) { 4.283 + for (col = 0; lbuflen > 0; col += clen) { 4.284 + if ((clen = mbrlen(lbuf, lbuflen, &mbs)) < 0) { 4.285 + if (!warned) { 4.286 + warn("%s", fname); 4.287 + warned = 1; 4.288 + } 4.289 + memset(&mbs, 0, sizeof(mbs)); 4.290 + clen = 1; 4.291 + } 4.292 + if (clen == 0 || *lbuf == '\n') 4.293 + break; 4.294 + if (col < maxval && !positions[1 + col]) { 4.295 + /* 4.296 + * Print the character if (1) after an initial 4.297 + * segment of un-selected bytes, the rest of 4.298 + * it is selected, and (2) the last byte is 4.299 + * selected. 4.300 + */ 4.301 + i = col; 4.302 + while (i < col + clen && i < maxval && 4.303 + !positions[1 + i]) 4.304 + i++; 4.305 + canwrite = i < col + clen; 4.306 + for (; i < col + clen && i < maxval; i++) 4.307 + canwrite &= positions[1 + i]; 4.308 + if (canwrite) 4.309 + fwrite(lbuf, 1, clen, stdout); 4.310 + } else { 4.311 + /* 4.312 + * Print the character if all of it has 4.313 + * been selected. 4.314 + */ 4.315 + canwrite = 1; 4.316 + for (i = col; i < col + clen; i++) 4.317 + if ((i >= maxval && !autostop) || 4.318 + (i < maxval && !positions[1 + i])) { 4.319 + canwrite = 0; 4.320 + break; 4.321 + } 4.322 + if (canwrite) 4.323 + fwrite(lbuf, 1, clen, stdout); 4.324 + } 4.325 + lbuf += clen; 4.326 + lbuflen -= clen; 4.327 + } 4.328 + if (lbuflen > 0) 4.329 + putchar('\n'); 4.330 + } 4.331 + return (warned); 4.332 +} 4.333 + 4.334 +static int 4.335 +c_cut(FILE *fp, const char *fname) 4.336 +{ 4.337 + wint_t ch; 4.338 + int col; 4.339 + char *pos; 4.340 + 4.341 + ch = 0; 4.342 + for (;;) { 4.343 + pos = positions + 1; 4.344 + for (col = maxval; col; --col) { 4.345 + if ((ch = getwc(fp)) == WEOF) 4.346 + goto out; 4.347 + if (ch == '\n') 4.348 + break; 4.349 + if (*pos++) 4.350 + (void)putwchar(ch); 4.351 + } 4.352 + if (ch != '\n') { 4.353 + if (autostop) 4.354 + while ((ch = getwc(fp)) != WEOF && ch != '\n') 4.355 + (void)putwchar(ch); 4.356 + else 4.357 + while ((ch = getwc(fp)) != WEOF && ch != '\n'); 4.358 + } 4.359 + (void)putwchar('\n'); 4.360 + } 4.361 +out: 4.362 + if (ferror(fp)) { 4.363 + warn("%s", fname); 4.364 + return (1); 4.365 + } 4.366 + return (0); 4.367 +} 4.368 + 4.369 +static int 4.370 +is_delim(wchar_t ch) 4.371 +{ 4.372 + if (wflag) { 4.373 + if (ch == ' ' || ch == '\t') 4.374 + return 1; 4.375 + } else { 4.376 + if (ch == dchar) 4.377 + return 1; 4.378 + } 4.379 + return 0; 4.380 +} 4.381 + 4.382 +static int 4.383 +f_cut(FILE *fp, const char *fname) 4.384 +{ 4.385 + wchar_t ch; 4.386 + int field, i, isdelim; 4.387 + char *pos, *p; 4.388 + int output; 4.389 + char *lbuf, *mlbuf; 4.390 + size_t clen, lbuflen, reallen; 4.391 + 4.392 + mlbuf = NULL; 4.393 + while ((lbuf = fgetln(fp, &lbuflen)) != NULL) { 4.394 + reallen = lbuflen; 4.395 + /* Assert EOL has a newline. */ 4.396 + if (*(lbuf + lbuflen - 1) != '\n') { 4.397 + /* Can't have > 1 line with no trailing newline. */ 4.398 + mlbuf = malloc(lbuflen + 1); 4.399 + if (mlbuf == NULL) 4.400 + err(1, "malloc"); 4.401 + memcpy(mlbuf, lbuf, lbuflen); 4.402 + *(mlbuf + lbuflen) = '\n'; 4.403 + lbuf = mlbuf; 4.404 + reallen++; 4.405 + } 4.406 + output = 0; 4.407 + for (isdelim = 0, p = lbuf;; p += clen) { 4.408 + clen = mbrtowc(&ch, p, lbuf + reallen - p, NULL); 4.409 + if (clen == (size_t)-1 || clen == (size_t)-2) { 4.410 + warnc(EILSEQ, "%s", fname); 4.411 + free(mlbuf); 4.412 + return (1); 4.413 + } 4.414 + if (clen == 0) 4.415 + clen = 1; 4.416 + /* this should work if newline is delimiter */ 4.417 + if (is_delim(ch)) 4.418 + isdelim = 1; 4.419 + if (ch == '\n') { 4.420 + if (!isdelim && !sflag) 4.421 + (void)fwrite(lbuf, lbuflen, 1, stdout); 4.422 + break; 4.423 + } 4.424 + } 4.425 + if (!isdelim) 4.426 + continue; 4.427 + 4.428 + pos = positions + 1; 4.429 + for (field = maxval, p = lbuf; field; --field, ++pos) { 4.430 + if (*pos && output++) 4.431 + for (i = 0; dcharmb[i] != '\0'; i++) 4.432 + putchar(dcharmb[i]); 4.433 + for (;;) { 4.434 + clen = mbrtowc(&ch, p, lbuf + reallen - p, 4.435 + NULL); 4.436 + if (clen == (size_t)-1 || clen == (size_t)-2) { 4.437 + warnc(EILSEQ, "%s", fname); 4.438 + free(mlbuf); 4.439 + return (1); 4.440 + } 4.441 + if (clen == 0) 4.442 + clen = 1; 4.443 + p += clen; 4.444 + if (ch == '\n' || is_delim(ch)) { 4.445 + /* compress whitespace */ 4.446 + if (wflag && ch != '\n') 4.447 + while (is_delim(*p)) 4.448 + p++; 4.449 + break; 4.450 + } 4.451 + if (*pos) 4.452 + for (i = 0; i < (int)clen; i++) 4.453 + putchar(p[i - clen]); 4.454 + } 4.455 + if (ch == '\n') 4.456 + break; 4.457 + } 4.458 + if (ch != '\n') { 4.459 + if (autostop) { 4.460 + if (output) 4.461 + for (i = 0; dcharmb[i] != '\0'; i++) 4.462 + putchar(dcharmb[i]); 4.463 + for (; (ch = *p) != '\n'; ++p) 4.464 + (void)putchar(ch); 4.465 + } else 4.466 + for (; (ch = *p) != '\n'; ++p); 4.467 + } 4.468 + (void)putchar('\n'); 4.469 + } 4.470 + free(mlbuf); 4.471 + return (0); 4.472 +} 4.473 + 4.474 +static void 4.475 +usage(void) 4.476 +{ 4.477 + (void)fprintf(stderr, "%s\n%s\n%s\n", 4.478 + "usage: cut -b list [-n] [file ...]", 4.479 + " cut -c list [file ...]", 4.480 + " cut -f list [-s] [-w | -d delim] [file ...]"); 4.481 + exit(1); 4.482 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/code/cut.c__gnu.1992-11-08 Tue May 12 06:46:59 2015 +0200 5.3 @@ -0,0 +1,586 @@ 5.4 +/* cut - remove parts of lines of files 5.5 + Copyright (C) 1984 by David M. Ihnat 5.6 + 5.7 + This program is a total rewrite of the Bell Laboratories Unix(Tm) 5.8 + command of the same name, as of System V. It contains no proprietary 5.9 + code, and therefore may be used without violation of any proprietary 5.10 + agreements whatsoever. However, you will notice that the program is 5.11 + copyrighted by me. This is to assure the program does *not* fall 5.12 + into the public domain. Thus, I may specify just what I am now: 5.13 + This program may be freely copied and distributed, provided this notice 5.14 + remains; it may not be sold for profit without express written consent of 5.15 + the author. 5.16 + Please note that I recreated the behavior of the Unix(Tm) 'cut' command 5.17 + as faithfully as possible; however, I haven't run a full set of regression 5.18 + tests. Thus, the user of this program accepts full responsibility for any 5.19 + effects or loss; in particular, the author is not responsible for any losses, 5.20 + explicit or incidental, that may be incurred through use of this program. 5.21 + 5.22 + I ask that any bugs (and, if possible, fixes) be reported to me when 5.23 + possible. -David Ihnat (312) 784-4544 ignatz@homebru.chi.il.us 5.24 + 5.25 + POSIX changes, bug fixes, long-named options, and cleanup 5.26 + by David MacKenzie <djm@ai.mit.edu>. 5.27 + 5.28 + Options: 5.29 + --bytes=byte-list 5.30 + -b byte-list Print only the bytes in positions listed 5.31 + in BYTE-LIST. 5.32 + Tabs and backspaces are treated like any 5.33 + other character; they take up 1 byte. 5.34 + 5.35 + --characters=character-list 5.36 + -c character-list Print only characters in positions listed 5.37 + in CHARACTER-LIST. 5.38 + The same as -b for now, but 5.39 + internationalization will change that. 5.40 + Tabs and backspaces are treated like any 5.41 + other character; they take up 1 character. 5.42 + 5.43 + --fields=field-list 5.44 + -f field-list Print only the fields listed in FIELD-LIST. 5.45 + Fields are separated by a TAB by default. 5.46 + 5.47 + --delimiter=delim 5.48 + -d delim For -f, fields are separated by the first 5.49 + character in DELIM instead of TAB. 5.50 + 5.51 + -n Do not split multibyte chars (no-op for now). 5.52 + 5.53 + --only-delimited 5.54 + -s For -f, do not print lines that do not contain 5.55 + the field separator character. 5.56 + 5.57 + The BYTE-LIST, CHARACTER-LIST, and FIELD-LIST are one or more numbers 5.58 + or ranges separated by commas. The first byte, character, and field 5.59 + are numbered 1. 5.60 + 5.61 + A FILE of `-' means standard input. */ 5.62 + 5.63 +#define _GNU_SOURCE 5.64 +#include <ctype.h> 5.65 +#ifndef isblank 5.66 +#define isblank(c) ((c) == ' ' || (c) == '\t') 5.67 +#endif 5.68 +#include <stdio.h> 5.69 +#include <getopt.h> 5.70 +#include <sys/types.h> 5.71 +#include "system.h" 5.72 + 5.73 +#ifdef isascii 5.74 +#define ISDIGIT(c) (isascii ((c)) && isdigit ((c))) 5.75 +#else 5.76 +#define ISDIGIT(c) (isdigit ((c))) 5.77 +#endif 5.78 + 5.79 +char *xmalloc (); 5.80 +char *xrealloc (); 5.81 +int set_fields (); 5.82 +int cut_file (); 5.83 +void cut_stream (); 5.84 +void cut_bytes (); 5.85 +void cut_fields (); 5.86 +void enlarge_line (); 5.87 +void error (); 5.88 +void invalid_list (); 5.89 +void usage (); 5.90 + 5.91 +/* The number of elements allocated for the input line 5.92 + and the byte or field number. 5.93 + Enlarged as necessary. */ 5.94 +int line_size; 5.95 + 5.96 +/* Processed output buffer. */ 5.97 +char *outbuf; 5.98 + 5.99 +/* Where to save next char to output. */ 5.100 +char *outbufptr; 5.101 + 5.102 +/* Raw line buffer for field mode. */ 5.103 +char *inbuf; 5.104 + 5.105 +/* Where to save next input char. */ 5.106 +char *inbufptr; 5.107 + 5.108 +/* What can be done about a byte or field. */ 5.109 +enum field_action 5.110 +{ 5.111 + field_omit, 5.112 + field_output 5.113 +}; 5.114 + 5.115 +/* In byte mode, which bytes to output. 5.116 + In field mode, which `delim'-separated fields to output. 5.117 + Both bytes and fields are numbered starting with 1, 5.118 + so the first element of `fields' is unused. */ 5.119 +enum field_action *fields; 5.120 + 5.121 +enum operating_mode 5.122 +{ 5.123 + undefined_mode, 5.124 + 5.125 + /* Output characters that are in the given bytes. */ 5.126 + byte_mode, 5.127 + 5.128 + /* Output the given delimeter-separated fields. */ 5.129 + field_mode 5.130 +}; 5.131 + 5.132 +enum operating_mode operating_mode; 5.133 + 5.134 +/* If nonzero, 5.135 + for field mode, do not output lines containing no delimeter characters. */ 5.136 +int delimited_lines_only; 5.137 + 5.138 +/* The delimeter character for field mode. */ 5.139 +unsigned char delim; 5.140 + 5.141 +/* Nonzero if we have ever read standard input. */ 5.142 +int have_read_stdin; 5.143 + 5.144 +/* The name this program was run with. */ 5.145 +char *program_name; 5.146 + 5.147 +struct option longopts[] = 5.148 +{ 5.149 + {"bytes", 1, 0, 'b'}, 5.150 + {"characters", 1, 0, 'c'}, 5.151 + {"fields", 1, 0, 'f'}, 5.152 + {"delimiter", 1, 0, 'd'}, 5.153 + {"only-delimited", 0, 0, 's'}, 5.154 + {0, 0, 0, 0} 5.155 +}; 5.156 + 5.157 +void 5.158 +main (argc, argv) 5.159 + int argc; 5.160 + char **argv; 5.161 +{ 5.162 + int optc, exit_status = 0; 5.163 + 5.164 + program_name = argv[0]; 5.165 + 5.166 + line_size = 512; 5.167 + operating_mode = undefined_mode; 5.168 + delimited_lines_only = 0; 5.169 + delim = '\0'; 5.170 + have_read_stdin = 0; 5.171 + 5.172 + fields = (enum field_action *) 5.173 + xmalloc (line_size * sizeof (enum field_action)); 5.174 + outbuf = (char *) xmalloc (line_size); 5.175 + inbuf = (char *) xmalloc (line_size); 5.176 + 5.177 + for (optc = 0; optc < line_size; optc++) 5.178 + fields[optc] = field_omit; 5.179 + 5.180 + while ((optc = getopt_long (argc, argv, "b:c:d:f:ns", longopts, (int *) 0)) 5.181 + != EOF) 5.182 + { 5.183 + switch (optc) 5.184 + { 5.185 + case 'b': 5.186 + case 'c': 5.187 + /* Build the byte list. */ 5.188 + if (operating_mode != undefined_mode) 5.189 + usage (); 5.190 + operating_mode = byte_mode; 5.191 + if (set_fields (optarg) == 0) 5.192 + error (2, 0, "no fields given"); 5.193 + break; 5.194 + 5.195 + case 'f': 5.196 + /* Build the field list. */ 5.197 + if (operating_mode != undefined_mode) 5.198 + usage (); 5.199 + operating_mode = field_mode; 5.200 + if (set_fields (optarg) == 0) 5.201 + error (2, 0, "no fields given"); 5.202 + break; 5.203 + 5.204 + case 'd': 5.205 + /* New delimiter. */ 5.206 + if (optarg[0] == '\0') 5.207 + error (2, 0, "no delimiter given"); 5.208 + if (optarg[1] != '\0') 5.209 + error (2, 0, "delimiter must be a single character"); 5.210 + delim = optarg[0]; 5.211 + break; 5.212 + 5.213 + case 'n': 5.214 + break; 5.215 + 5.216 + case 's': 5.217 + delimited_lines_only++; 5.218 + break; 5.219 + 5.220 + default: 5.221 + usage (); 5.222 + } 5.223 + } 5.224 + 5.225 + if (operating_mode == undefined_mode) 5.226 + usage (); 5.227 + 5.228 + if ((delimited_lines_only || delim != '\0') && operating_mode != field_mode) 5.229 + usage (); 5.230 + 5.231 + if (delim == '\0') 5.232 + delim = '\t'; 5.233 + 5.234 + if (optind == argc) 5.235 + exit_status |= cut_file ("-"); 5.236 + else 5.237 + for (; optind < argc; optind++) 5.238 + exit_status |= cut_file (argv[optind]); 5.239 + 5.240 + if (have_read_stdin && fclose (stdin) == EOF) 5.241 + { 5.242 + error (0, errno, "-"); 5.243 + exit_status = 1; 5.244 + } 5.245 + if (ferror (stdout) || fclose (stdout) == EOF) 5.246 + error (1, 0, "write error"); 5.247 + 5.248 + exit (exit_status); 5.249 +} 5.250 + 5.251 +/* Select for printing the positions in `fields' that are listed in 5.252 + byte or field specification FIELDSTR. FIELDSTR should be 5.253 + composed of one or more numbers or ranges of numbers, separated by 5.254 + blanks or commas. Incomplete ranges may be given: `-m' means 5.255 + `1-m'; `n-' means `n' through end of line or last field. 5.256 + 5.257 + Return the number of fields selected. */ 5.258 + 5.259 +int 5.260 +set_fields (fieldstr) 5.261 + char *fieldstr; 5.262 +{ 5.263 + int initial = 1; /* Value of first number in a range. */ 5.264 + int dash_found = 0; /* Nonzero if a '-' is found in this field. */ 5.265 + int value = 0; /* If nonzero, a number being accumulated. */ 5.266 + int fields_selected = 0; /* Number of fields selected so far. */ 5.267 + /* If nonzero, index of first field in a range that goes to end of line. */ 5.268 + int eol_range_start = 0; 5.269 + 5.270 + for (;;) 5.271 + { 5.272 + if (*fieldstr == '-') 5.273 + { 5.274 + /* Starting a range. */ 5.275 + if (dash_found) 5.276 + invalid_list (); 5.277 + dash_found++; 5.278 + fieldstr++; 5.279 + 5.280 + if (value) 5.281 + { 5.282 + if (value >= line_size) 5.283 + enlarge_line (value); 5.284 + initial = value; 5.285 + value = 0; 5.286 + } 5.287 + else 5.288 + initial = 1; 5.289 + } 5.290 + else if (*fieldstr == ',' || isblank (*fieldstr) || *fieldstr == '\0') 5.291 + { 5.292 + /* Ending the string, or this field/byte sublist. */ 5.293 + if (dash_found) 5.294 + { 5.295 + dash_found = 0; 5.296 + 5.297 + /* A range. Possibilites: -n, m-n, n-. 5.298 + In any case, `initial' contains the start of the range. */ 5.299 + if (value == 0) 5.300 + { 5.301 + /* `n-'. From `initial' to end of line. */ 5.302 + eol_range_start = initial; 5.303 + fields_selected++; 5.304 + } 5.305 + else 5.306 + { 5.307 + /* `m-n' or `-n' (1-n). */ 5.308 + if (value < initial) 5.309 + invalid_list (); 5.310 + 5.311 + if (value >= line_size) 5.312 + enlarge_line (value); 5.313 + 5.314 + /* Is there already a range going to end of line? */ 5.315 + if (eol_range_start != 0) 5.316 + { 5.317 + /* Yes. Is the new sequence already contained 5.318 + in the old one? If so, no processing is 5.319 + necessary. */ 5.320 + if (initial < eol_range_start) 5.321 + { 5.322 + /* No, the new sequence starts before the 5.323 + old. Does the old range going to end of line 5.324 + extend into the new range? */ 5.325 + if (eol_range_start < value) 5.326 + /* Yes. Simply move the end of line marker. */ 5.327 + eol_range_start = initial; 5.328 + else 5.329 + { 5.330 + /* No. A simple range, before and disjoint from 5.331 + the range going to end of line. Fill it. */ 5.332 + for (; initial <= value; initial++) 5.333 + fields[initial] = field_output; 5.334 + } 5.335 + 5.336 + /* In any case, some fields were selected. */ 5.337 + fields_selected++; 5.338 + } 5.339 + } 5.340 + else 5.341 + { 5.342 + /* There is no range going to end of line. */ 5.343 + for (; initial <= value; initial++) 5.344 + fields[initial] = field_output; 5.345 + fields_selected++; 5.346 + } 5.347 + value = 0; 5.348 + } 5.349 + } 5.350 + else if (value != 0) 5.351 + { 5.352 + /* A simple field number, not a range. */ 5.353 + if (value >= line_size) 5.354 + enlarge_line (value); 5.355 + 5.356 + fields[value] = field_output; 5.357 + value = 0; 5.358 + fields_selected++; 5.359 + } 5.360 + 5.361 + if (*fieldstr == '\0') 5.362 + { 5.363 + /* If there was a range going to end of line, fill the 5.364 + array from the end of line point. */ 5.365 + if (eol_range_start) 5.366 + for (initial = eol_range_start; initial < line_size; initial++) 5.367 + fields[initial] = field_output; 5.368 + 5.369 + return fields_selected; 5.370 + } 5.371 + 5.372 + fieldstr++; 5.373 + } 5.374 + else if (ISDIGIT (*fieldstr)) 5.375 + { 5.376 + value = 10 * value + *fieldstr - '0'; 5.377 + fieldstr++; 5.378 + } 5.379 + else 5.380 + invalid_list (); 5.381 + } 5.382 +} 5.383 + 5.384 +/* Process file FILE to standard output. 5.385 + Return 0 if successful, 1 if not. */ 5.386 + 5.387 +int 5.388 +cut_file (file) 5.389 + char *file; 5.390 +{ 5.391 + FILE *stream; 5.392 + 5.393 + if (!strcmp (file, "-")) 5.394 + { 5.395 + have_read_stdin = 1; 5.396 + stream = stdin; 5.397 + } 5.398 + else 5.399 + { 5.400 + stream = fopen (file, "r"); 5.401 + if (stream == NULL) 5.402 + { 5.403 + error (0, errno, "%s", file); 5.404 + return 1; 5.405 + } 5.406 + } 5.407 + 5.408 + cut_stream (stream); 5.409 + 5.410 + if (ferror (stream)) 5.411 + { 5.412 + error (0, errno, "%s", file); 5.413 + return 1; 5.414 + } 5.415 + if (!strcmp (file, "-")) 5.416 + clearerr (stream); /* Also clear EOF. */ 5.417 + else if (fclose (stream) == EOF) 5.418 + { 5.419 + error (0, errno, "%s", file); 5.420 + return 1; 5.421 + } 5.422 + return 0; 5.423 +} 5.424 + 5.425 +void 5.426 +cut_stream (stream) 5.427 + FILE *stream; 5.428 +{ 5.429 + if (operating_mode == byte_mode) 5.430 + cut_bytes (stream); 5.431 + else 5.432 + cut_fields (stream); 5.433 +} 5.434 + 5.435 +/* Print the file open for reading on stream STREAM 5.436 + with the bytes marked `field_omit' in `fields' removed from each line. */ 5.437 + 5.438 +void 5.439 +cut_bytes (stream) 5.440 + FILE *stream; 5.441 +{ 5.442 + register int c; /* Each character from the file. */ 5.443 + int doneflag = 0; /* Nonzero if EOF reached. */ 5.444 + int char_count; /* Number of chars in the line so far. */ 5.445 + 5.446 + while (doneflag == 0) 5.447 + { 5.448 + /* Start processing a line. */ 5.449 + outbufptr = outbuf; 5.450 + char_count = 0; 5.451 + 5.452 + do 5.453 + { 5.454 + c = getc (stream); 5.455 + if (c == EOF) 5.456 + { 5.457 + doneflag++; 5.458 + break; 5.459 + } 5.460 + 5.461 + /* If this character is to be sent, stow it in the outbuffer. */ 5.462 + 5.463 + if (++char_count == line_size - 1) 5.464 + enlarge_line (char_count); 5.465 + 5.466 + if (fields[char_count] == field_output || c == '\n') 5.467 + *outbufptr++ = c; 5.468 + } 5.469 + while (c != '\n'); 5.470 + 5.471 + if (char_count) 5.472 + fwrite (outbuf, sizeof (char), outbufptr - outbuf, stdout); 5.473 + } 5.474 +} 5.475 + 5.476 +/* Print the file open for reading on stream STREAM 5.477 + with the fields marked `field_omit' in `fields' removed from each line. 5.478 + All characters are initially stowed in the raw input buffer, until 5.479 + at least one field has been found. */ 5.480 + 5.481 +void 5.482 +cut_fields (stream) 5.483 + FILE *stream; 5.484 +{ 5.485 + register int c; /* Each character from the file. */ 5.486 + int doneflag = 0; /* Nonzero if EOF reached. */ 5.487 + int char_count; /* Number of chars in line before any delim. */ 5.488 + int fieldfound; /* Nonzero if any fields to print found. */ 5.489 + int curr_field; /* Current index in `fields'. */ 5.490 + 5.491 + while (doneflag == 0) 5.492 + { 5.493 + char_count = 0; 5.494 + fieldfound = 0; 5.495 + curr_field = 1; 5.496 + outbufptr = outbuf; 5.497 + inbufptr = inbuf; 5.498 + 5.499 + do 5.500 + { 5.501 + c = getc (stream); 5.502 + if (c == EOF) 5.503 + { 5.504 + doneflag++; 5.505 + break; 5.506 + } 5.507 + 5.508 + if (fields[curr_field] == field_output && c != '\n') 5.509 + { 5.510 + /* Working on a field. It, and its terminating 5.511 + delimiter, go only into the processed buffer. */ 5.512 + fieldfound = 1; 5.513 + if (outbufptr - outbuf == line_size - 2) 5.514 + enlarge_line (outbufptr - outbuf); 5.515 + *outbufptr++ = c; 5.516 + } 5.517 + else if (fieldfound == 0) 5.518 + { 5.519 + if (++char_count == line_size - 1) 5.520 + enlarge_line (char_count); 5.521 + *inbufptr++ = c; 5.522 + } 5.523 + 5.524 + if (c == delim && ++curr_field == line_size - 1) 5.525 + enlarge_line (curr_field); 5.526 + } 5.527 + while (c != '\n'); 5.528 + 5.529 + if (fieldfound) 5.530 + { 5.531 + /* Something was found. Print it. */ 5.532 + if (outbufptr[-1] == delim) 5.533 + --outbufptr; /* Suppress trailing delimiter. */ 5.534 + 5.535 + fwrite (outbuf, sizeof (char), outbufptr - outbuf, stdout); 5.536 + if (c == '\n') 5.537 + putc (c, stdout); 5.538 + } 5.539 + else if (!delimited_lines_only && char_count) 5.540 + /* A line with some characters, no delimiters, and no 5.541 + suppression. Print it. */ 5.542 + fwrite (inbuf, sizeof (char), inbufptr - inbuf, stdout); 5.543 + } 5.544 +} 5.545 + 5.546 +/* Extend the buffers to accomodate at least NEW_SIZE characters. */ 5.547 + 5.548 +void 5.549 +enlarge_line (new_size) 5.550 + int new_size; 5.551 +{ 5.552 + char *newp; 5.553 + int i; 5.554 + 5.555 + new_size += 256; /* Leave some room to grow. */ 5.556 + 5.557 + fields = (enum field_action *) 5.558 + xrealloc (fields, new_size * sizeof (enum field_action)); 5.559 + 5.560 + newp = (char *) xrealloc (outbuf, new_size); 5.561 + outbufptr += newp - outbuf; 5.562 + outbuf = newp; 5.563 + 5.564 + newp = (char *) xrealloc (inbuf, new_size); 5.565 + inbufptr += newp - inbuf; 5.566 + inbuf = newp; 5.567 + 5.568 + for (i = line_size; i < new_size; i++) 5.569 + fields[i] = field_omit; 5.570 + line_size = new_size; 5.571 +} 5.572 + 5.573 +void 5.574 +invalid_list () 5.575 +{ 5.576 + error (2, 0, "invalid byte or field list"); 5.577 +} 5.578 + 5.579 +void 5.580 +usage () 5.581 +{ 5.582 + fprintf (stderr, "\ 5.583 +Usage: %s {-b byte-list,--bytes=byte-list} [-n] [file...]\n\ 5.584 + %s {-c character-list,--characters=character-list} [file...]\n\ 5.585 + %s {-f field-list,--fields=field-list} [-d delim] [-s]\n\ 5.586 + [--delimiter=delim] [--only-delimited] [file...]\n", 5.587 + program_name, program_name, program_name); 5.588 + exit (2); 5.589 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/code/cut.c__gnu.2015-05-01 Tue May 12 06:46:59 2015 +0200 6.3 @@ -0,0 +1,830 @@ 6.4 +/* cut - remove parts of lines of files 6.5 + Copyright (C) 1997-2015 Free Software Foundation, Inc. 6.6 + Copyright (C) 1984 David M. Ihnat 6.7 + 6.8 + This program is free software: you can redistribute it and/or modify 6.9 + it under the terms of the GNU General Public License as published by 6.10 + the Free Software Foundation, either version 3 of the License, or 6.11 + (at your option) any later version. 6.12 + 6.13 + This program is distributed in the hope that it will be useful, 6.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of 6.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 6.16 + GNU General Public License for more details. 6.17 + 6.18 + You should have received a copy of the GNU General Public License 6.19 + along with this program. If not, see <http://www.gnu.org/licenses/>. */ 6.20 + 6.21 +/* Written by David Ihnat. */ 6.22 + 6.23 +/* POSIX changes, bug fixes, long-named options, and cleanup 6.24 + by David MacKenzie <djm@gnu.ai.mit.edu>. 6.25 + 6.26 + Rewrite cut_fields and cut_bytes -- Jim Meyering. */ 6.27 + 6.28 +#include <config.h> 6.29 + 6.30 +#include <stdio.h> 6.31 +#include <assert.h> 6.32 +#include <getopt.h> 6.33 +#include <sys/types.h> 6.34 +#include "system.h" 6.35 + 6.36 +#include "error.h" 6.37 +#include "fadvise.h" 6.38 +#include "getndelim2.h" 6.39 +#include "hash.h" 6.40 +#include "quote.h" 6.41 +#include "xstrndup.h" 6.42 + 6.43 +/* The official name of this program (e.g., no 'g' prefix). */ 6.44 +#define PROGRAM_NAME "cut" 6.45 + 6.46 +#define AUTHORS \ 6.47 + proper_name ("David M. Ihnat"), \ 6.48 + proper_name ("David MacKenzie"), \ 6.49 + proper_name ("Jim Meyering") 6.50 + 6.51 +#define FATAL_ERROR(Message) \ 6.52 + do \ 6.53 + { \ 6.54 + error (0, 0, (Message)); \ 6.55 + usage (EXIT_FAILURE); \ 6.56 + } \ 6.57 + while (0) 6.58 + 6.59 + 6.60 +struct range_pair 6.61 + { 6.62 + size_t lo; 6.63 + size_t hi; 6.64 + }; 6.65 + 6.66 +/* Array of `struct range_pair' holding all the finite ranges. */ 6.67 +static struct range_pair *rp; 6.68 + 6.69 +/* Pointer inside RP. When checking if a byte or field is selected 6.70 + by a finite range, we check if it is between CURRENT_RP.LO 6.71 + and CURRENT_RP.HI. If the byte or field index is greater than 6.72 + CURRENT_RP.HI then we make CURRENT_RP to point to the next range pair. */ 6.73 +static struct range_pair *current_rp; 6.74 + 6.75 +/* Number of finite ranges specified by the user. */ 6.76 +static size_t n_rp; 6.77 + 6.78 +/* Number of `struct range_pair's allocated. */ 6.79 +static size_t n_rp_allocated; 6.80 + 6.81 + 6.82 +/* Append LOW, HIGH to the list RP of range pairs, allocating additional 6.83 + space if necessary. Update global variable N_RP. When allocating, 6.84 + update global variable N_RP_ALLOCATED. */ 6.85 + 6.86 +static void 6.87 +add_range_pair (size_t lo, size_t hi) 6.88 +{ 6.89 + if (n_rp == n_rp_allocated) 6.90 + rp = X2NREALLOC (rp, &n_rp_allocated); 6.91 + rp[n_rp].lo = lo; 6.92 + rp[n_rp].hi = hi; 6.93 + ++n_rp; 6.94 +} 6.95 + 6.96 +/* This buffer is used to support the semantics of the -s option 6.97 + (or lack of same) when the specified field list includes (does 6.98 + not include) the first field. In both of those cases, the entire 6.99 + first field must be read into this buffer to determine whether it 6.100 + is followed by a delimiter or a newline before any of it may be 6.101 + output. Otherwise, cut_fields can do the job without using this 6.102 + buffer. */ 6.103 +static char *field_1_buffer; 6.104 + 6.105 +/* The number of bytes allocated for FIELD_1_BUFFER. */ 6.106 +static size_t field_1_bufsize; 6.107 + 6.108 +enum operating_mode 6.109 + { 6.110 + undefined_mode, 6.111 + 6.112 + /* Output characters that are in the given bytes. */ 6.113 + byte_mode, 6.114 + 6.115 + /* Output the given delimiter-separated fields. */ 6.116 + field_mode 6.117 + }; 6.118 + 6.119 +static enum operating_mode operating_mode; 6.120 + 6.121 +/* If true do not output lines containing no delimiter characters. 6.122 + Otherwise, all such lines are printed. This option is valid only 6.123 + with field mode. */ 6.124 +static bool suppress_non_delimited; 6.125 + 6.126 +/* If true, print all bytes, characters, or fields _except_ 6.127 + those that were specified. */ 6.128 +static bool complement; 6.129 + 6.130 +/* The delimiter character for field mode. */ 6.131 +static unsigned char delim; 6.132 + 6.133 +/* True if the --output-delimiter=STRING option was specified. */ 6.134 +static bool output_delimiter_specified; 6.135 + 6.136 +/* The length of output_delimiter_string. */ 6.137 +static size_t output_delimiter_length; 6.138 + 6.139 +/* The output field separator string. Defaults to the 1-character 6.140 + string consisting of the input delimiter. */ 6.141 +static char *output_delimiter_string; 6.142 + 6.143 +/* True if we have ever read standard input. */ 6.144 +static bool have_read_stdin; 6.145 + 6.146 +/* For long options that have no equivalent short option, use a 6.147 + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ 6.148 +enum 6.149 +{ 6.150 + OUTPUT_DELIMITER_OPTION = CHAR_MAX + 1, 6.151 + COMPLEMENT_OPTION 6.152 +}; 6.153 + 6.154 +static struct option const longopts[] = 6.155 +{ 6.156 + {"bytes", required_argument, NULL, 'b'}, 6.157 + {"characters", required_argument, NULL, 'c'}, 6.158 + {"fields", required_argument, NULL, 'f'}, 6.159 + {"delimiter", required_argument, NULL, 'd'}, 6.160 + {"only-delimited", no_argument, NULL, 's'}, 6.161 + {"output-delimiter", required_argument, NULL, OUTPUT_DELIMITER_OPTION}, 6.162 + {"complement", no_argument, NULL, COMPLEMENT_OPTION}, 6.163 + {GETOPT_HELP_OPTION_DECL}, 6.164 + {GETOPT_VERSION_OPTION_DECL}, 6.165 + {NULL, 0, NULL, 0} 6.166 +}; 6.167 + 6.168 +void 6.169 +usage (int status) 6.170 +{ 6.171 + if (status != EXIT_SUCCESS) 6.172 + emit_try_help (); 6.173 + else 6.174 + { 6.175 + printf (_("\ 6.176 +Usage: %s OPTION... [FILE]...\n\ 6.177 +"), 6.178 + program_name); 6.179 + fputs (_("\ 6.180 +Print selected parts of lines from each FILE to standard output.\n\ 6.181 +"), stdout); 6.182 + 6.183 + emit_stdin_note (); 6.184 + emit_mandatory_arg_note (); 6.185 + 6.186 + fputs (_("\ 6.187 + -b, --bytes=LIST select only these bytes\n\ 6.188 + -c, --characters=LIST select only these characters\n\ 6.189 + -d, --delimiter=DELIM use DELIM instead of TAB for field delimiter\n\ 6.190 +"), stdout); 6.191 + fputs (_("\ 6.192 + -f, --fields=LIST select only these fields; also print any line\n\ 6.193 + that contains no delimiter character, unless\n\ 6.194 + the -s option is specified\n\ 6.195 + -n (ignored)\n\ 6.196 +"), stdout); 6.197 + fputs (_("\ 6.198 + --complement complement the set of selected bytes, characters\n\ 6.199 + or fields\n\ 6.200 +"), stdout); 6.201 + fputs (_("\ 6.202 + -s, --only-delimited do not print lines not containing delimiters\n\ 6.203 + --output-delimiter=STRING use STRING as the output delimiter\n\ 6.204 + the default is to use the input delimiter\n\ 6.205 +"), stdout); 6.206 + fputs (HELP_OPTION_DESCRIPTION, stdout); 6.207 + fputs (VERSION_OPTION_DESCRIPTION, stdout); 6.208 + fputs (_("\ 6.209 +\n\ 6.210 +Use one, and only one of -b, -c or -f. Each LIST is made up of one\n\ 6.211 +range, or many ranges separated by commas. Selected input is written\n\ 6.212 +in the same order that it is read, and is written exactly once.\n\ 6.213 +"), stdout); 6.214 + fputs (_("\ 6.215 +Each range is one of:\n\ 6.216 +\n\ 6.217 + N N'th byte, character or field, counted from 1\n\ 6.218 + N- from N'th byte, character or field, to end of line\n\ 6.219 + N-M from N'th to M'th (included) byte, character or field\n\ 6.220 + -M from first to M'th (included) byte, character or field\n\ 6.221 +"), stdout); 6.222 + emit_ancillary_info (PROGRAM_NAME); 6.223 + } 6.224 + exit (status); 6.225 +} 6.226 + 6.227 +/* Comparison function for qsort to order the list of 6.228 + struct range_pairs. */ 6.229 +static int 6.230 +compare_ranges (const void *a, const void *b) 6.231 +{ 6.232 + int a_start = ((const struct range_pair *) a)->lo; 6.233 + int b_start = ((const struct range_pair *) b)->lo; 6.234 + return a_start < b_start ? -1 : a_start > b_start; 6.235 +} 6.236 + 6.237 +/* Reallocate Range Pair entries, with corresponding 6.238 + entries outside the range of each specified entry. */ 6.239 + 6.240 +static void 6.241 +complement_rp (void) 6.242 +{ 6.243 + if (complement) 6.244 + { 6.245 + struct range_pair *c = rp; 6.246 + size_t n = n_rp; 6.247 + size_t i; 6.248 + 6.249 + rp = NULL; 6.250 + n_rp = 0; 6.251 + n_rp_allocated = 0; 6.252 + 6.253 + if (c[0].lo > 1) 6.254 + add_range_pair (1, c[0].lo - 1); 6.255 + 6.256 + for (i = 1; i < n; ++i) 6.257 + { 6.258 + if (c[i-1].hi + 1 == c[i].lo) 6.259 + continue; 6.260 + 6.261 + add_range_pair (c[i-1].hi + 1, c[i].lo - 1); 6.262 + } 6.263 + 6.264 + if (c[n-1].hi < SIZE_MAX) 6.265 + add_range_pair (c[n-1].hi + 1, SIZE_MAX); 6.266 + 6.267 + free (c); 6.268 + } 6.269 +} 6.270 + 6.271 +/* Given the list of field or byte range specifications FIELDSTR, 6.272 + allocate and initialize the RP array. FIELDSTR should 6.273 + be composed of one or more numbers or ranges of numbers, separated 6.274 + by blanks or commas. Incomplete ranges may be given: '-m' means '1-m'; 6.275 + 'n-' means 'n' through end of line. 6.276 + Return true if FIELDSTR contains at least one field specification, 6.277 + false otherwise. */ 6.278 + 6.279 +static bool 6.280 +set_fields (const char *fieldstr) 6.281 +{ 6.282 + size_t initial = 1; /* Value of first number in a range. */ 6.283 + size_t value = 0; /* If nonzero, a number being accumulated. */ 6.284 + bool lhs_specified = false; 6.285 + bool rhs_specified = false; 6.286 + bool dash_found = false; /* True if a '-' is found in this field. */ 6.287 + bool field_found = false; /* True if at least one field spec 6.288 + has been processed. */ 6.289 + 6.290 + size_t i; 6.291 + bool in_digits = false; 6.292 + 6.293 + /* Collect and store in RP the range end points. */ 6.294 + 6.295 + while (true) 6.296 + { 6.297 + if (*fieldstr == '-') 6.298 + { 6.299 + in_digits = false; 6.300 + /* Starting a range. */ 6.301 + if (dash_found) 6.302 + FATAL_ERROR (_("invalid byte, character or field list")); 6.303 + dash_found = true; 6.304 + fieldstr++; 6.305 + 6.306 + if (lhs_specified && !value) 6.307 + FATAL_ERROR (_("fields and positions are numbered from 1")); 6.308 + 6.309 + initial = (lhs_specified ? value : 1); 6.310 + value = 0; 6.311 + } 6.312 + else if (*fieldstr == ',' 6.313 + || isblank (to_uchar (*fieldstr)) || *fieldstr == '\0') 6.314 + { 6.315 + in_digits = false; 6.316 + /* Ending the string, or this field/byte sublist. */ 6.317 + if (dash_found) 6.318 + { 6.319 + dash_found = false; 6.320 + 6.321 + if (!lhs_specified && !rhs_specified) 6.322 + FATAL_ERROR (_("invalid range with no endpoint: -")); 6.323 + 6.324 + /* A range. Possibilities: -n, m-n, n-. 6.325 + In any case, 'initial' contains the start of the range. */ 6.326 + if (!rhs_specified) 6.327 + { 6.328 + /* 'n-'. From 'initial' to end of line. */ 6.329 + add_range_pair (initial, SIZE_MAX); 6.330 + field_found = true; 6.331 + } 6.332 + else 6.333 + { 6.334 + /* 'm-n' or '-n' (1-n). */ 6.335 + if (value < initial) 6.336 + FATAL_ERROR (_("invalid decreasing range")); 6.337 + 6.338 + add_range_pair (initial, value); 6.339 + field_found = true; 6.340 + } 6.341 + value = 0; 6.342 + } 6.343 + else 6.344 + { 6.345 + /* A simple field number, not a range. */ 6.346 + if (value == 0) 6.347 + FATAL_ERROR (_("fields and positions are numbered from 1")); 6.348 + add_range_pair (value, value); 6.349 + value = 0; 6.350 + field_found = true; 6.351 + } 6.352 + 6.353 + if (*fieldstr == '\0') 6.354 + break; 6.355 + 6.356 + fieldstr++; 6.357 + lhs_specified = false; 6.358 + rhs_specified = false; 6.359 + } 6.360 + else if (ISDIGIT (*fieldstr)) 6.361 + { 6.362 + /* Record beginning of digit string, in case we have to 6.363 + complain about it. */ 6.364 + static char const *num_start; 6.365 + if (!in_digits || !num_start) 6.366 + num_start = fieldstr; 6.367 + in_digits = true; 6.368 + 6.369 + if (dash_found) 6.370 + rhs_specified = 1; 6.371 + else 6.372 + lhs_specified = 1; 6.373 + 6.374 + /* Detect overflow. */ 6.375 + if (!DECIMAL_DIGIT_ACCUMULATE (value, *fieldstr - '0', size_t) 6.376 + || value == SIZE_MAX) 6.377 + { 6.378 + /* In case the user specified -c$(echo 2^64|bc),22, 6.379 + complain only about the first number. */ 6.380 + /* Determine the length of the offending number. */ 6.381 + size_t len = strspn (num_start, "0123456789"); 6.382 + char *bad_num = xstrndup (num_start, len); 6.383 + if (operating_mode == byte_mode) 6.384 + error (0, 0, 6.385 + _("byte offset %s is too large"), quote (bad_num)); 6.386 + else 6.387 + error (0, 0, 6.388 + _("field number %s is too large"), quote (bad_num)); 6.389 + free (bad_num); 6.390 + exit (EXIT_FAILURE); 6.391 + } 6.392 + 6.393 + fieldstr++; 6.394 + } 6.395 + else 6.396 + FATAL_ERROR (_("invalid byte, character or field list")); 6.397 + } 6.398 + 6.399 + qsort (rp, n_rp, sizeof (rp[0]), compare_ranges); 6.400 + 6.401 + /* Merge range pairs (e.g. `2-5,3-4' becomes `2-5'). */ 6.402 + for (i = 0; i < n_rp; ++i) 6.403 + { 6.404 + for (size_t j = i + 1; j < n_rp; ++j) 6.405 + { 6.406 + if (rp[j].lo <= rp[i].hi) 6.407 + { 6.408 + rp[i].hi = MAX (rp[j].hi, rp[i].hi); 6.409 + memmove (rp + j, rp + j + 1, (n_rp - j - 1) * sizeof *rp); 6.410 + n_rp--; 6.411 + j--; 6.412 + } 6.413 + else 6.414 + break; 6.415 + } 6.416 + } 6.417 + 6.418 + complement_rp (); 6.419 + 6.420 + /* After merging, reallocate RP so we release memory to the system. 6.421 + Also add a sentinel at the end of RP, to avoid out of bounds access 6.422 + and for performance reasons. */ 6.423 + ++n_rp; 6.424 + rp = xrealloc (rp, n_rp * sizeof (struct range_pair)); 6.425 + rp[n_rp - 1].lo = rp[n_rp - 1].hi = SIZE_MAX; 6.426 + 6.427 + return field_found; 6.428 +} 6.429 + 6.430 +/* Increment *ITEM_IDX (i.e., a field or byte index), 6.431 + and if required CURRENT_RP. */ 6.432 + 6.433 +static inline void 6.434 +next_item (size_t *item_idx) 6.435 +{ 6.436 + (*item_idx)++; 6.437 + if ((*item_idx) > current_rp->hi) 6.438 + current_rp++; 6.439 +} 6.440 + 6.441 +/* Return nonzero if the K'th field or byte is printable. */ 6.442 + 6.443 +static inline bool 6.444 +print_kth (size_t k) 6.445 +{ 6.446 + return current_rp->lo <= k; 6.447 +} 6.448 + 6.449 +/* Return nonzero if K'th byte is the beginning of a range. */ 6.450 + 6.451 +static inline bool 6.452 +is_range_start_index (size_t k) 6.453 +{ 6.454 + return k == current_rp->lo; 6.455 +} 6.456 + 6.457 +/* Read from stream STREAM, printing to standard output any selected bytes. */ 6.458 + 6.459 +static void 6.460 +cut_bytes (FILE *stream) 6.461 +{ 6.462 + size_t byte_idx; /* Number of bytes in the line so far. */ 6.463 + /* Whether to begin printing delimiters between ranges for the current line. 6.464 + Set after we've begun printing data corresponding to the first range. */ 6.465 + bool print_delimiter; 6.466 + 6.467 + byte_idx = 0; 6.468 + print_delimiter = false; 6.469 + current_rp = rp; 6.470 + while (true) 6.471 + { 6.472 + int c; /* Each character from the file. */ 6.473 + 6.474 + c = getc (stream); 6.475 + 6.476 + if (c == '\n') 6.477 + { 6.478 + putchar ('\n'); 6.479 + byte_idx = 0; 6.480 + print_delimiter = false; 6.481 + current_rp = rp; 6.482 + } 6.483 + else if (c == EOF) 6.484 + { 6.485 + if (byte_idx > 0) 6.486 + putchar ('\n'); 6.487 + break; 6.488 + } 6.489 + else 6.490 + { 6.491 + next_item (&byte_idx); 6.492 + if (print_kth (byte_idx)) 6.493 + { 6.494 + if (output_delimiter_specified) 6.495 + { 6.496 + if (print_delimiter && is_range_start_index (byte_idx)) 6.497 + { 6.498 + fwrite (output_delimiter_string, sizeof (char), 6.499 + output_delimiter_length, stdout); 6.500 + } 6.501 + print_delimiter = true; 6.502 + } 6.503 + 6.504 + putchar (c); 6.505 + } 6.506 + } 6.507 + } 6.508 +} 6.509 + 6.510 +/* Read from stream STREAM, printing to standard output any selected fields. */ 6.511 + 6.512 +static void 6.513 +cut_fields (FILE *stream) 6.514 +{ 6.515 + int c; 6.516 + size_t field_idx = 1; 6.517 + bool found_any_selected_field = false; 6.518 + bool buffer_first_field; 6.519 + 6.520 + current_rp = rp; 6.521 + 6.522 + c = getc (stream); 6.523 + if (c == EOF) 6.524 + return; 6.525 + 6.526 + ungetc (c, stream); 6.527 + c = 0; 6.528 + 6.529 + /* To support the semantics of the -s flag, we may have to buffer 6.530 + all of the first field to determine whether it is 'delimited.' 6.531 + But that is unnecessary if all non-delimited lines must be printed 6.532 + and the first field has been selected, or if non-delimited lines 6.533 + must be suppressed and the first field has *not* been selected. 6.534 + That is because a non-delimited line has exactly one field. */ 6.535 + buffer_first_field = (suppress_non_delimited ^ !print_kth (1)); 6.536 + 6.537 + while (1) 6.538 + { 6.539 + if (field_idx == 1 && buffer_first_field) 6.540 + { 6.541 + ssize_t len; 6.542 + size_t n_bytes; 6.543 + 6.544 + len = getndelim2 (&field_1_buffer, &field_1_bufsize, 0, 6.545 + GETNLINE_NO_LIMIT, delim, '\n', stream); 6.546 + if (len < 0) 6.547 + { 6.548 + free (field_1_buffer); 6.549 + field_1_buffer = NULL; 6.550 + if (ferror (stream) || feof (stream)) 6.551 + break; 6.552 + xalloc_die (); 6.553 + } 6.554 + 6.555 + n_bytes = len; 6.556 + assert (n_bytes != 0); 6.557 + 6.558 + c = 0; 6.559 + 6.560 + /* If the first field extends to the end of line (it is not 6.561 + delimited) and we are printing all non-delimited lines, 6.562 + print this one. */ 6.563 + if (to_uchar (field_1_buffer[n_bytes - 1]) != delim) 6.564 + { 6.565 + if (suppress_non_delimited) 6.566 + { 6.567 + /* Empty. */ 6.568 + } 6.569 + else 6.570 + { 6.571 + fwrite (field_1_buffer, sizeof (char), n_bytes, stdout); 6.572 + /* Make sure the output line is newline terminated. */ 6.573 + if (field_1_buffer[n_bytes - 1] != '\n') 6.574 + putchar ('\n'); 6.575 + c = '\n'; 6.576 + } 6.577 + continue; 6.578 + } 6.579 + if (print_kth (1)) 6.580 + { 6.581 + /* Print the field, but not the trailing delimiter. */ 6.582 + fwrite (field_1_buffer, sizeof (char), n_bytes - 1, stdout); 6.583 + 6.584 + /* With -d$'\n' don't treat the last '\n' as a delimiter. */ 6.585 + if (delim == '\n') 6.586 + { 6.587 + int last_c = getc (stream); 6.588 + if (last_c != EOF) 6.589 + { 6.590 + ungetc (last_c, stream); 6.591 + found_any_selected_field = true; 6.592 + } 6.593 + } 6.594 + else 6.595 + found_any_selected_field = true; 6.596 + } 6.597 + next_item (&field_idx); 6.598 + } 6.599 + 6.600 + int prev_c = c; 6.601 + 6.602 + if (print_kth (field_idx)) 6.603 + { 6.604 + if (found_any_selected_field) 6.605 + { 6.606 + fwrite (output_delimiter_string, sizeof (char), 6.607 + output_delimiter_length, stdout); 6.608 + } 6.609 + found_any_selected_field = true; 6.610 + 6.611 + while ((c = getc (stream)) != delim && c != '\n' && c != EOF) 6.612 + { 6.613 + putchar (c); 6.614 + prev_c = c; 6.615 + } 6.616 + } 6.617 + else 6.618 + { 6.619 + while ((c = getc (stream)) != delim && c != '\n' && c != EOF) 6.620 + { 6.621 + prev_c = c; 6.622 + } 6.623 + } 6.624 + 6.625 + /* With -d$'\n' don't treat the last '\n' as a delimiter. */ 6.626 + if (delim == '\n' && c == delim) 6.627 + { 6.628 + int last_c = getc (stream); 6.629 + if (last_c != EOF) 6.630 + ungetc (last_c, stream); 6.631 + else 6.632 + c = last_c; 6.633 + } 6.634 + 6.635 + if (c == delim) 6.636 + next_item (&field_idx); 6.637 + else if (c == '\n' || c == EOF) 6.638 + { 6.639 + if (found_any_selected_field 6.640 + || !(suppress_non_delimited && field_idx == 1)) 6.641 + { 6.642 + if (c == '\n' || prev_c != '\n' || delim == '\n') 6.643 + putchar ('\n'); 6.644 + } 6.645 + if (c == EOF) 6.646 + break; 6.647 + field_idx = 1; 6.648 + current_rp = rp; 6.649 + found_any_selected_field = false; 6.650 + } 6.651 + } 6.652 +} 6.653 + 6.654 +static void 6.655 +cut_stream (FILE *stream) 6.656 +{ 6.657 + if (operating_mode == byte_mode) 6.658 + cut_bytes (stream); 6.659 + else 6.660 + cut_fields (stream); 6.661 +} 6.662 + 6.663 +/* Process file FILE to standard output. 6.664 + Return true if successful. */ 6.665 + 6.666 +static bool 6.667 +cut_file (char const *file) 6.668 +{ 6.669 + FILE *stream; 6.670 + 6.671 + if (STREQ (file, "-")) 6.672 + { 6.673 + have_read_stdin = true; 6.674 + stream = stdin; 6.675 + } 6.676 + else 6.677 + { 6.678 + stream = fopen (file, "r"); 6.679 + if (stream == NULL) 6.680 + { 6.681 + error (0, errno, "%s", file); 6.682 + return false; 6.683 + } 6.684 + } 6.685 + 6.686 + fadvise (stream, FADVISE_SEQUENTIAL); 6.687 + 6.688 + cut_stream (stream); 6.689 + 6.690 + if (ferror (stream)) 6.691 + { 6.692 + error (0, errno, "%s", file); 6.693 + return false; 6.694 + } 6.695 + if (STREQ (file, "-")) 6.696 + clearerr (stream); /* Also clear EOF. */ 6.697 + else if (fclose (stream) == EOF) 6.698 + { 6.699 + error (0, errno, "%s", file); 6.700 + return false; 6.701 + } 6.702 + return true; 6.703 +} 6.704 + 6.705 +int 6.706 +main (int argc, char **argv) 6.707 +{ 6.708 + int optc; 6.709 + bool ok; 6.710 + bool delim_specified = false; 6.711 + char *spec_list_string IF_LINT ( = NULL); 6.712 + 6.713 + initialize_main (&argc, &argv); 6.714 + set_program_name (argv[0]); 6.715 + setlocale (LC_ALL, ""); 6.716 + bindtextdomain (PACKAGE, LOCALEDIR); 6.717 + textdomain (PACKAGE); 6.718 + 6.719 + atexit (close_stdout); 6.720 + 6.721 + operating_mode = undefined_mode; 6.722 + 6.723 + /* By default, all non-delimited lines are printed. */ 6.724 + suppress_non_delimited = false; 6.725 + 6.726 + delim = '\0'; 6.727 + have_read_stdin = false; 6.728 + 6.729 + while ((optc = getopt_long (argc, argv, "b:c:d:f:ns", longopts, NULL)) != -1) 6.730 + { 6.731 + switch (optc) 6.732 + { 6.733 + case 'b': 6.734 + case 'c': 6.735 + /* Build the byte list. */ 6.736 + if (operating_mode != undefined_mode) 6.737 + FATAL_ERROR (_("only one type of list may be specified")); 6.738 + operating_mode = byte_mode; 6.739 + spec_list_string = optarg; 6.740 + break; 6.741 + 6.742 + case 'f': 6.743 + /* Build the field list. */ 6.744 + if (operating_mode != undefined_mode) 6.745 + FATAL_ERROR (_("only one type of list may be specified")); 6.746 + operating_mode = field_mode; 6.747 + spec_list_string = optarg; 6.748 + break; 6.749 + 6.750 + case 'd': 6.751 + /* New delimiter. */ 6.752 + /* Interpret -d '' to mean 'use the NUL byte as the delimiter.' */ 6.753 + if (optarg[0] != '\0' && optarg[1] != '\0') 6.754 + FATAL_ERROR (_("the delimiter must be a single character")); 6.755 + delim = optarg[0]; 6.756 + delim_specified = true; 6.757 + break; 6.758 + 6.759 + case OUTPUT_DELIMITER_OPTION: 6.760 + output_delimiter_specified = true; 6.761 + /* Interpret --output-delimiter='' to mean 6.762 + 'use the NUL byte as the delimiter.' */ 6.763 + output_delimiter_length = (optarg[0] == '\0' 6.764 + ? 1 : strlen (optarg)); 6.765 + output_delimiter_string = xstrdup (optarg); 6.766 + break; 6.767 + 6.768 + case 'n': 6.769 + break; 6.770 + 6.771 + case 's': 6.772 + suppress_non_delimited = true; 6.773 + break; 6.774 + 6.775 + case COMPLEMENT_OPTION: 6.776 + complement = true; 6.777 + break; 6.778 + 6.779 + case_GETOPT_HELP_CHAR; 6.780 + 6.781 + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); 6.782 + 6.783 + default: 6.784 + usage (EXIT_FAILURE); 6.785 + } 6.786 + } 6.787 + 6.788 + if (operating_mode == undefined_mode) 6.789 + FATAL_ERROR (_("you must specify a list of bytes, characters, or fields")); 6.790 + 6.791 + if (delim_specified && operating_mode != field_mode) 6.792 + FATAL_ERROR (_("an input delimiter may be specified only\ 6.793 + when operating on fields")); 6.794 + 6.795 + if (suppress_non_delimited && operating_mode != field_mode) 6.796 + FATAL_ERROR (_("suppressing non-delimited lines makes sense\n\ 6.797 +\tonly when operating on fields")); 6.798 + 6.799 + if (! set_fields (spec_list_string)) 6.800 + { 6.801 + if (operating_mode == field_mode) 6.802 + FATAL_ERROR (_("missing list of fields")); 6.803 + else 6.804 + FATAL_ERROR (_("missing list of positions")); 6.805 + } 6.806 + 6.807 + if (!delim_specified) 6.808 + delim = '\t'; 6.809 + 6.810 + if (output_delimiter_string == NULL) 6.811 + { 6.812 + static char dummy[2]; 6.813 + dummy[0] = delim; 6.814 + dummy[1] = '\0'; 6.815 + output_delimiter_string = dummy; 6.816 + output_delimiter_length = 1; 6.817 + } 6.818 + 6.819 + if (optind == argc) 6.820 + ok = cut_file ("-"); 6.821 + else 6.822 + for (ok = true; optind < argc; optind++) 6.823 + ok &= cut_file (argv[optind]); 6.824 + 6.825 + 6.826 + if (have_read_stdin && fclose (stdin) == EOF) 6.827 + { 6.828 + error (0, errno, "-"); 6.829 + ok = false; 6.830 + } 6.831 + 6.832 + return ok ? EXIT_SUCCESS : EXIT_FAILURE; 6.833 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/code/cut.c__heirloom.2012-05-20 Tue May 12 06:46:59 2015 +0200 7.3 @@ -0,0 +1,405 @@ 7.4 +/* 7.5 + * cut - cut out fields of lines of files 7.6 + * 7.7 + * Gunnar Ritter, Freiburg i. Br., Germany, December 2002. 7.8 + */ 7.9 +/* 7.10 + * Copyright (c) 2003 Gunnar Ritter 7.11 + * 7.12 + * This software is provided 'as-is', without any express or implied 7.13 + * warranty. In no event will the authors be held liable for any damages 7.14 + * arising from the use of this software. 7.15 + * 7.16 + * Permission is granted to anyone to use this software for any purpose, 7.17 + * including commercial applications, and to alter it and redistribute 7.18 + * it freely, subject to the following restrictions: 7.19 + * 7.20 + * 1. The origin of this software must not be misrepresented; you must not 7.21 + * claim that you wrote the original software. If you use this software 7.22 + * in a product, an acknowledgment in the product documentation would be 7.23 + * appreciated but is not required. 7.24 + * 7.25 + * 2. Altered source versions must be plainly marked as such, and must not be 7.26 + * misrepresented as being the original software. 7.27 + * 7.28 + * 3. This notice may not be removed or altered from any source distribution. 7.29 + */ 7.30 + 7.31 +#if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4 7.32 +#define USED __attribute__ ((used)) 7.33 +#elif defined __GNUC__ 7.34 +#define USED __attribute__ ((unused)) 7.35 +#else 7.36 +#define USED 7.37 +#endif 7.38 +static const char sccsid[] USED = "@(#)cut.sl 1.20 (gritter) 5/29/05"; 7.39 + 7.40 +#include <sys/types.h> 7.41 +#include <sys/stat.h> 7.42 +#include <fcntl.h> 7.43 +#include <unistd.h> 7.44 +#include <stdio.h> 7.45 +#include <string.h> 7.46 +#include <stdlib.h> 7.47 +#include <errno.h> 7.48 +#include <libgen.h> 7.49 +#include <limits.h> 7.50 +#include <wchar.h> 7.51 +#include <ctype.h> 7.52 +#include <locale.h> 7.53 + 7.54 +#include "iblok.h" 7.55 + 7.56 +#if defined (__GLIBC__) && defined (_IO_putc_unlocked) 7.57 +#undef putc 7.58 +#define putc(c, f) _IO_putc_unlocked(c, f) 7.59 +#endif 7.60 + 7.61 +struct range { 7.62 + struct range *r_nxt; 7.63 + long r_min; 7.64 + long r_max; 7.65 +}; 7.66 + 7.67 +static unsigned errcnt; /* count of errors */ 7.68 +static int method; /* one of b, c, f */ 7.69 +static int nflag; /* character boundary bytes */ 7.70 +static int sflag; /* suppress lines w/o delimiters */ 7.71 +static char *progname; /* argv[0] to main() */ 7.72 +static wchar_t wcdelim = '\t'; /* delimiter character */ 7.73 +static const char *mbdelim = "\t";/* delimiter character */ 7.74 +struct range *fields; /* range list */ 7.75 +static int multibyte; /* multibyte LC_CTYPE */ 7.76 + 7.77 +#define next(wc, s) (multibyte ? mbtowc(&(wc), s, MB_LEN_MAX) :\ 7.78 + ((wc) = *(s) & 0377, (wc) != 0)) 7.79 + 7.80 +void * 7.81 +lrealloc(void *vp, size_t nbytes) 7.82 +{ 7.83 + void *p; 7.84 + 7.85 + if ((p = realloc(vp, nbytes)) == NULL) { 7.86 + write(2, "line too long\n", 14); 7.87 + exit(076); 7.88 + } 7.89 + return p; 7.90 +} 7.91 + 7.92 +void * 7.93 +smalloc(size_t nbytes) 7.94 +{ 7.95 + void *p; 7.96 + 7.97 + if ((p = malloc(nbytes)) == NULL) { 7.98 + write(2, "no memory\n", 11); 7.99 + exit(077); 7.100 + } 7.101 + return p; 7.102 +} 7.103 + 7.104 +static void 7.105 +error(const char *s) 7.106 +{ 7.107 + fprintf(stderr, "%s: ERROR: %s\n", progname, s); 7.108 + exit(2); 7.109 +} 7.110 + 7.111 +static void 7.112 +usage(void) 7.113 +{ 7.114 + error("Usage: cut [-s] [-d<char>] {-c<list> | -f<list>} file ..."); 7.115 +} 7.116 + 7.117 +static void 7.118 +badlist(void) 7.119 +{ 7.120 + error(method == 'b' ? "bad list for b/c/f option" : 7.121 + "bad list for c/f option"); 7.122 +} 7.123 + 7.124 +static void 7.125 +setdelim(const char *s) 7.126 +{ 7.127 + int n; 7.128 + 7.129 + if ((n = next(wcdelim, s)) < 0 || (n > 0 && s[n] != '\0')) 7.130 + error("no delimiter"); 7.131 + mbdelim = s; 7.132 +} 7.133 + 7.134 +static void 7.135 +addrange(long m, long n) 7.136 +{ 7.137 + struct range *rp, *rq; 7.138 + 7.139 + rp = smalloc(sizeof *rp); 7.140 + rp->r_nxt = NULL; 7.141 + rp->r_min = m; 7.142 + rp->r_max = n ? n : m; 7.143 + if (fields) { 7.144 + for (rq = fields; rq->r_nxt; rq = rq->r_nxt); 7.145 + rq->r_nxt = rp; 7.146 + } else 7.147 + fields = rp; 7.148 +} 7.149 + 7.150 +static int 7.151 +have(long i) 7.152 +{ 7.153 + struct range *rp; 7.154 + 7.155 + for (rp = fields; rp; rp = rp->r_nxt) 7.156 + if (i >= rp->r_min && i <= rp->r_max) 7.157 + return 1; 7.158 + return 0; 7.159 +} 7.160 + 7.161 +#define mnreset() m = 0, n = 0, lp = &m 7.162 + 7.163 +static void 7.164 +setlist(const char *s) 7.165 +{ 7.166 + char *cbuf, *cp; 7.167 + long m, n; 7.168 + long *lp; 7.169 + 7.170 + fields = NULL; 7.171 + cbuf = smalloc(strlen(s) + 1); 7.172 + mnreset(); 7.173 + for (;;) { 7.174 + if (*s == '-') { 7.175 + if (m == 0) 7.176 + m = 1; 7.177 + n = LONG_MAX; 7.178 + lp = &n; 7.179 + s++; 7.180 + } else if (*s == ',' || *s == ' ' || *s == '\t' || *s == '\0') { 7.181 + if (m) 7.182 + addrange(m, n); 7.183 + mnreset(); 7.184 + if (*s == '\0') 7.185 + break; 7.186 + s++; 7.187 + } else if (isdigit(*s & 0377)) { 7.188 + cp = cbuf; 7.189 + do 7.190 + *cp++ = *s++; 7.191 + while (isdigit(*s & 0377)); 7.192 + *cp = '\0'; 7.193 + *lp = strtol(cbuf, NULL, 10); 7.194 + } else 7.195 + badlist(); 7.196 + } 7.197 + if (fields == NULL) 7.198 + error("no fields"); 7.199 + free(cbuf); 7.200 +} 7.201 + 7.202 +static void 7.203 +cutb(struct iblok *ip) 7.204 +{ 7.205 + int c, i; 7.206 + 7.207 + i = 1; 7.208 + while ((c = ib_get(ip)) != EOF) { 7.209 + if (c == '\n') { 7.210 + i = 1; 7.211 + putc(c, stdout); 7.212 + } else if (have(i++)) 7.213 + putc(c, stdout); 7.214 + } 7.215 +} 7.216 + 7.217 +static void 7.218 +cutbn(struct iblok *ip) 7.219 +{ 7.220 + char *cp; 7.221 + int i, m, n; 7.222 + wint_t wc; 7.223 + 7.224 + i = 1; 7.225 + while ((cp = ib_getw(ip, &wc, &n)) != NULL) { 7.226 + if (wc == '\n') { 7.227 + i = 1; 7.228 + putc('\n', stdout); 7.229 + } else { 7.230 + if (have(i + n - 1)) 7.231 + for (m = 0; m < n; m++) 7.232 + putc(cp[m], stdout); 7.233 + i += n; 7.234 + } 7.235 + } 7.236 +} 7.237 + 7.238 +static void 7.239 +cutc(struct iblok *ip) 7.240 +{ 7.241 + char *cp; 7.242 + int i, n, m; 7.243 + wint_t wc; 7.244 + 7.245 + i = 1; 7.246 + while ((cp = ib_getw(ip, &wc, &n)) != NULL) { 7.247 + if (wc == '\n') { 7.248 + i = 1; 7.249 + putc('\n', stdout); 7.250 + } else if (wc != WEOF && have(i++)) { 7.251 + for (m = 0; m < n; m++) 7.252 + putc(cp[m], stdout); 7.253 + } 7.254 + } 7.255 +} 7.256 + 7.257 +static void 7.258 +cutf(struct iblok *ip) 7.259 +{ 7.260 + static char *line; 7.261 + static size_t linesize; 7.262 + char *cp, *lp, *lq; 7.263 + int c, i, n, m, gotcha; 7.264 + char b; 7.265 + wint_t wc; 7.266 + const int incr = 128; 7.267 + 7.268 + if (linesize == 0) 7.269 + line = smalloc(linesize = incr); 7.270 + lp = line; 7.271 + gotcha = 0; 7.272 + i = 1; 7.273 + do { 7.274 + if (multibyte) 7.275 + cp = ib_getw(ip, &wc, &n); 7.276 + else { 7.277 + if ((c = ib_get(ip)) != EOF) { 7.278 + wc = c; 7.279 + b = (char)c; 7.280 + cp = &b; 7.281 + } else { 7.282 + wc = WEOF; 7.283 + cp = NULL; 7.284 + } 7.285 + n = 1; 7.286 + } 7.287 + if (cp == NULL || wc == '\n' || wc == wcdelim) { 7.288 + if (have(i) && (!sflag || gotcha || wc == wcdelim) || 7.289 + (!sflag && i == 1 && 7.290 + (cp == NULL || wc == '\n'))) { 7.291 + if (gotcha) 7.292 + for (m = 0; mbdelim[m]; m++) 7.293 + putc(mbdelim[m], stdout); 7.294 + for (lq = line; lq < lp; lq++) 7.295 + putc(*lq, stdout); 7.296 + gotcha = 1; 7.297 + } 7.298 + if (wc == '\n') { 7.299 + if (gotcha) 7.300 + putc('\n', stdout); 7.301 + i = 1; 7.302 + gotcha = 0; 7.303 + } else 7.304 + i++; 7.305 + lp = line; 7.306 + } else { 7.307 + for (m = 0; m < n; m++) { 7.308 + if (lp >= &line[linesize]) { 7.309 + size_t diff = lp - line; 7.310 + line = lrealloc(line, linesize += incr); 7.311 + lp = &line[diff]; 7.312 + } 7.313 + *lp++ = cp[m]; 7.314 + } 7.315 + } 7.316 + } while (cp != NULL); 7.317 +} 7.318 + 7.319 +static int 7.320 +fdcut(int fd) 7.321 +{ 7.322 + struct iblok *ip; 7.323 + 7.324 + ip = ib_alloc(fd, 0); 7.325 + switch (method) { 7.326 + case 'b': 7.327 + if (nflag && multibyte) 7.328 + cutbn(ip); 7.329 + else 7.330 + cutb(ip); 7.331 + break; 7.332 + case 'c': 7.333 + if (multibyte) 7.334 + cutc(ip); 7.335 + else 7.336 + cutb(ip); 7.337 + break; 7.338 + case 'f': 7.339 + cutf(ip); 7.340 + break; 7.341 + } 7.342 + ib_free(ip); 7.343 + return 0; 7.344 +} 7.345 + 7.346 +static int 7.347 +fncut(const char *fn) 7.348 +{ 7.349 + int fd, res; 7.350 + 7.351 + if (fn[0] == '-' && fn[1] == '\0') 7.352 + fd = 0; 7.353 + else if ((fd = open(fn, O_RDONLY)) < 0) { 7.354 + fprintf(stderr, "%s: WARNING: cannot open %s\n", progname, fn); 7.355 + return 1; 7.356 + } 7.357 + res = fdcut(fd); 7.358 + if (fd) 7.359 + close(fd); 7.360 + return res; 7.361 +} 7.362 + 7.363 +int 7.364 +main(int argc, char **argv) 7.365 +{ 7.366 + const char optstring[] = "b:c:d:f:ns"; 7.367 + int i; 7.368 + 7.369 + progname = basename(argv[0]); 7.370 + setlocale(LC_CTYPE, ""); 7.371 + multibyte = MB_CUR_MAX > 1; 7.372 +#ifdef __GLIBC__ 7.373 + putenv("POSIXLY_CORRECT=1"); 7.374 +#endif 7.375 + while ((i = getopt(argc, argv, optstring)) != EOF) { 7.376 + switch (i) { 7.377 + case 'b': 7.378 + case 'c': 7.379 + case 'f': 7.380 + if (method && method != i) 7.381 + usage(); 7.382 + method = i; 7.383 + setlist(optarg); 7.384 + break; 7.385 + case 'd': 7.386 + setdelim(optarg); 7.387 + break; 7.388 + case 'n': 7.389 + nflag = 1; 7.390 + break; 7.391 + case 's': 7.392 + sflag = 1; 7.393 + break; 7.394 + default: 7.395 + usage(); 7.396 + } 7.397 + } 7.398 + /*if ((sflag && method != 'f') || (nflag && method != 'b')) 7.399 + usage();*/ 7.400 + if (method == 0) 7.401 + badlist(); 7.402 + if (argv[optind]) { 7.403 + for (i = optind; argv[i]; i++) 7.404 + errcnt |= fncut(argv[i]); 7.405 + } else 7.406 + errcnt |= fdcut(0); 7.407 + return errcnt; 7.408 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/code/cut.c__netbsd.1993-03-21 Tue May 12 06:46:59 2015 +0200 8.3 @@ -0,0 +1,270 @@ 8.4 +/* 8.5 + * Copyright (c) 1989 The Regents of the University of California. 8.6 + * All rights reserved. 8.7 + * 8.8 + * This code is derived from software contributed to Berkeley by 8.9 + * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue. 8.10 + * 8.11 + * Redistribution and use in source and binary forms, with or without 8.12 + * modification, are permitted provided that the following conditions 8.13 + * are met: 8.14 + * 1. Redistributions of source code must retain the above copyright 8.15 + * notice, this list of conditions and the following disclaimer. 8.16 + * 2. Redistributions in binary form must reproduce the above copyright 8.17 + * notice, this list of conditions and the following disclaimer in the 8.18 + * documentation and/or other materials provided with the distribution. 8.19 + * 3. All advertising materials mentioning features or use of this software 8.20 + * must display the following acknowledgement: 8.21 + * This product includes software developed by the University of 8.22 + * California, Berkeley and its contributors. 8.23 + * 4. Neither the name of the University nor the names of its contributors 8.24 + * may be used to endorse or promote products derived from this software 8.25 + * without specific prior written permission. 8.26 + * 8.27 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 8.28 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8.29 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 8.30 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 8.31 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 8.32 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 8.33 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 8.34 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 8.35 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 8.36 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 8.37 + * SUCH DAMAGE. 8.38 + */ 8.39 + 8.40 +#ifndef lint 8.41 +char copyright[] = 8.42 +"@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 8.43 + All rights reserved.\n"; 8.44 +#endif /* not lint */ 8.45 + 8.46 +#ifndef lint 8.47 +static char sccsid[] = "@(#)cut.c 5.4 (Berkeley) 10/30/90"; 8.48 +#endif /* not lint */ 8.49 + 8.50 +#include <limits.h> 8.51 +#include <stdio.h> 8.52 +#include <ctype.h> 8.53 + 8.54 +int cflag; 8.55 +char dchar; 8.56 +int dflag; 8.57 +int fflag; 8.58 +int sflag; 8.59 + 8.60 +main(argc, argv) 8.61 + int argc; 8.62 + char **argv; 8.63 +{ 8.64 + extern char *optarg; 8.65 + extern int errno, optind; 8.66 + FILE *fp; 8.67 + int ch, (*fcn)(), c_cut(), f_cut(); 8.68 + char *strerror(); 8.69 + 8.70 + dchar = '\t'; /* default delimiter is \t */ 8.71 + 8.72 + while ((ch = getopt(argc, argv, "c:d:f:s")) != EOF) 8.73 + switch(ch) { 8.74 + case 'c': 8.75 + fcn = c_cut; 8.76 + get_list(optarg); 8.77 + cflag = 1; 8.78 + break; 8.79 + case 'd': 8.80 + dchar = *optarg; 8.81 + dflag = 1; 8.82 + break; 8.83 + case 'f': 8.84 + get_list(optarg); 8.85 + fcn = f_cut; 8.86 + fflag = 1; 8.87 + break; 8.88 + case 's': 8.89 + sflag = 1; 8.90 + break; 8.91 + case '?': 8.92 + default: 8.93 + usage(); 8.94 + } 8.95 + argc -= optind; 8.96 + argv += optind; 8.97 + 8.98 + if (fflag) { 8.99 + if (cflag) 8.100 + usage(); 8.101 + } else if (!cflag || dflag || sflag) 8.102 + usage(); 8.103 + 8.104 + if (*argv) 8.105 + for (; *argv; ++argv) { 8.106 + if (!(fp = fopen(*argv, "r"))) { 8.107 + (void)fprintf(stderr, 8.108 + "cut: %s: %s\n", *argv, strerror(errno)); 8.109 + exit(1); 8.110 + } 8.111 + fcn(fp, *argv); 8.112 + } 8.113 + else 8.114 + fcn(stdin, "stdin"); 8.115 + exit(0); 8.116 +} 8.117 + 8.118 +int autostart, autostop, maxval; 8.119 + 8.120 +char positions[_POSIX2_LINE_MAX + 1]; 8.121 + 8.122 +get_list(list) 8.123 + char *list; 8.124 +{ 8.125 + register char *pos; 8.126 + register int setautostart, start, stop; 8.127 + char *p, *strtok(); 8.128 + 8.129 + /* 8.130 + * set a byte in the positions array to indicate if a field or 8.131 + * column is to be selected; use +1, it's 1-based, not 0-based. 8.132 + * This parser is less restrictive than the Draft 9 POSIX spec. 8.133 + * POSIX doesn't allow lists that aren't in increasing order or 8.134 + * overlapping lists. We also handle "-3-5" although there's no 8.135 + * real reason too. 8.136 + */ 8.137 + for (; p = strtok(list, ", \t"); list = NULL) { 8.138 + setautostart = start = stop = 0; 8.139 + if (*p == '-') { 8.140 + ++p; 8.141 + setautostart = 1; 8.142 + } 8.143 + if (isdigit(*p)) { 8.144 + start = stop = strtol(p, &p, 10); 8.145 + if (setautostart && start > autostart) 8.146 + autostart = start; 8.147 + } 8.148 + if (*p == '-') { 8.149 + if (isdigit(p[1])) 8.150 + stop = strtol(p + 1, &p, 10); 8.151 + if (*p == '-') { 8.152 + ++p; 8.153 + if (!autostop || autostop > stop) 8.154 + autostop = stop; 8.155 + } 8.156 + } 8.157 + if (*p) 8.158 + badlist("illegal list value"); 8.159 + if (!stop || !start) 8.160 + badlist("values may not include zero"); 8.161 + if (stop > _POSIX2_LINE_MAX) { 8.162 + /* positions used rather than allocate a new buffer */ 8.163 + (void)sprintf(positions, "%d too large (max %d)", 8.164 + stop, _POSIX2_LINE_MAX); 8.165 + badlist(positions); 8.166 + } 8.167 + if (maxval < stop) 8.168 + maxval = stop; 8.169 + for (pos = positions + start; start++ <= stop; *pos++ = 1); 8.170 + } 8.171 + 8.172 + /* overlapping ranges */ 8.173 + if (autostop && maxval > autostop) 8.174 + maxval = autostop; 8.175 + 8.176 + /* set autostart */ 8.177 + if (autostart) 8.178 + memset(positions + 1, '1', autostart); 8.179 +} 8.180 + 8.181 +/* ARGSUSED */ 8.182 +c_cut(fp, fname) 8.183 + FILE *fp; 8.184 + char *fname; 8.185 +{ 8.186 + register int ch, col; 8.187 + register char *pos; 8.188 + 8.189 + for (;;) { 8.190 + pos = positions + 1; 8.191 + for (col = maxval; col; --col) { 8.192 + if ((ch = getc(fp)) == EOF) 8.193 + return; 8.194 + if (ch == '\n') 8.195 + break; 8.196 + if (*pos++) 8.197 + putchar(ch); 8.198 + } 8.199 + if (ch != '\n') 8.200 + if (autostop) 8.201 + while ((ch = getc(fp)) != EOF && ch != '\n') 8.202 + putchar(ch); 8.203 + else 8.204 + while ((ch = getc(fp)) != EOF && ch != '\n'); 8.205 + putchar('\n'); 8.206 + } 8.207 +} 8.208 + 8.209 +f_cut(fp, fname) 8.210 + FILE *fp; 8.211 + char *fname; 8.212 +{ 8.213 + register int ch, field, isdelim; 8.214 + register char *pos, *p, sep; 8.215 + int output; 8.216 + char lbuf[_POSIX2_LINE_MAX + 1]; 8.217 + 8.218 + for (sep = dchar, output = 0; fgets(lbuf, sizeof(lbuf), fp);) { 8.219 + for (isdelim = 0, p = lbuf;; ++p) { 8.220 + if (!(ch = *p)) { 8.221 + (void)fprintf(stderr, 8.222 + "cut: %s: line too long.\n", fname); 8.223 + exit(1); 8.224 + } 8.225 + /* this should work if newline is delimiter */ 8.226 + if (ch == sep) 8.227 + isdelim = 1; 8.228 + if (ch == '\n') { 8.229 + if (!isdelim && !sflag) 8.230 + (void)printf("%s", lbuf); 8.231 + break; 8.232 + } 8.233 + } 8.234 + if (!isdelim) 8.235 + continue; 8.236 + 8.237 + pos = positions + 1; 8.238 + for (field = maxval, p = lbuf; field; --field, ++pos) { 8.239 + if (*pos) { 8.240 + if (output++) 8.241 + putchar(sep); 8.242 + while ((ch = *p++) != '\n' && ch != sep) 8.243 + putchar(ch); 8.244 + } else 8.245 + while ((ch = *p++) != '\n' && ch != sep); 8.246 + if (ch == '\n') 8.247 + break; 8.248 + } 8.249 + if (ch != '\n') 8.250 + if (autostop) { 8.251 + if (output) 8.252 + putchar(sep); 8.253 + for (; (ch = *p) != '\n'; ++p) 8.254 + putchar(ch); 8.255 + } else 8.256 + for (; (ch = *p) != '\n'; ++p); 8.257 + putchar('\n'); 8.258 + } 8.259 +} 8.260 + 8.261 +badlist(msg) 8.262 + char *msg; 8.263 +{ 8.264 + (void)fprintf(stderr, "cut: [-cf] list: %s.\n", msg); 8.265 + exit(1); 8.266 +} 8.267 + 8.268 +usage() 8.269 +{ 8.270 + (void)fprintf(stderr, 8.271 +"usage:\tcut -c list [file1 ...]\n\tcut -f list [-s] [-d delim] [file ...]\n"); 8.272 + exit(1); 8.273 +}
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/code/cut.c__netbsd.2014-02-03 Tue May 12 06:46:59 2015 +0200 9.3 @@ -0,0 +1,306 @@ 9.4 +/* $NetBSD: cut.c,v 1.29 2014/02/03 20:22:19 wiz Exp $ */ 9.5 + 9.6 +/* 9.7 + * Copyright (c) 1989, 1993 9.8 + * The Regents of the University of California. All rights reserved. 9.9 + * 9.10 + * This code is derived from software contributed to Berkeley by 9.11 + * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue. 9.12 + * 9.13 + * Redistribution and use in source and binary forms, with or without 9.14 + * modification, are permitted provided that the following conditions 9.15 + * are met: 9.16 + * 1. Redistributions of source code must retain the above copyright 9.17 + * notice, this list of conditions and the following disclaimer. 9.18 + * 2. Redistributions in binary form must reproduce the above copyright 9.19 + * notice, this list of conditions and the following disclaimer in the 9.20 + * documentation and/or other materials provided with the distribution. 9.21 + * 3. Neither the name of the University nor the names of its contributors 9.22 + * may be used to endorse or promote products derived from this software 9.23 + * without specific prior written permission. 9.24 + * 9.25 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 9.26 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 9.27 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 9.28 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 9.29 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 9.30 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 9.31 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 9.32 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 9.33 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 9.34 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 9.35 + * SUCH DAMAGE. 9.36 + */ 9.37 + 9.38 +#include <sys/cdefs.h> 9.39 +#ifndef lint 9.40 +__COPYRIGHT("@(#) Copyright (c) 1989, 1993\ 9.41 + The Regents of the University of California. All rights reserved."); 9.42 +#endif /* not lint */ 9.43 + 9.44 +#ifndef lint 9.45 +#if 0 9.46 +static char sccsid[] = "@(#)cut.c 8.3 (Berkeley) 5/4/95"; 9.47 +#endif 9.48 +__RCSID("$NetBSD: cut.c,v 1.29 2014/02/03 20:22:19 wiz Exp $"); 9.49 +#endif /* not lint */ 9.50 + 9.51 +#include <ctype.h> 9.52 +#include <err.h> 9.53 +#include <errno.h> 9.54 +#include <limits.h> 9.55 +#include <locale.h> 9.56 +#include <stdio.h> 9.57 +#include <stdlib.h> 9.58 +#include <string.h> 9.59 +#include <unistd.h> 9.60 +#include <util.h> 9.61 +#include <wchar.h> 9.62 +#include <sys/param.h> 9.63 + 9.64 +static int bflag; 9.65 +static int cflag; 9.66 +static char dchar; 9.67 +static int dflag; 9.68 +static int fflag; 9.69 +static int sflag; 9.70 + 9.71 +static void b_cut(FILE *, const char *); 9.72 +static void c_cut(FILE *, const char *); 9.73 +static void f_cut(FILE *, const char *); 9.74 +static void get_list(char *); 9.75 +static void usage(void) __dead; 9.76 + 9.77 +int 9.78 +main(int argc, char *argv[]) 9.79 +{ 9.80 + FILE *fp; 9.81 + void (*fcn)(FILE *, const char *); 9.82 + int ch, rval; 9.83 + 9.84 + fcn = NULL; 9.85 + (void)setlocale(LC_ALL, ""); 9.86 + 9.87 + dchar = '\t'; /* default delimiter is \t */ 9.88 + 9.89 + /* Since we don't support multi-byte characters, the -c and -b 9.90 + options are equivalent, and the -n option is meaningless. */ 9.91 + while ((ch = getopt(argc, argv, "b:c:d:f:sn")) != -1) 9.92 + switch(ch) { 9.93 + case 'b': 9.94 + fcn = b_cut; 9.95 + get_list(optarg); 9.96 + bflag = 1; 9.97 + break; 9.98 + case 'c': 9.99 + fcn = c_cut; 9.100 + get_list(optarg); 9.101 + cflag = 1; 9.102 + break; 9.103 + case 'd': 9.104 + dchar = *optarg; 9.105 + dflag = 1; 9.106 + break; 9.107 + case 'f': 9.108 + get_list(optarg); 9.109 + fcn = f_cut; 9.110 + fflag = 1; 9.111 + break; 9.112 + case 's': 9.113 + sflag = 1; 9.114 + break; 9.115 + case 'n': 9.116 + break; 9.117 + case '?': 9.118 + default: 9.119 + usage(); 9.120 + } 9.121 + argc -= optind; 9.122 + argv += optind; 9.123 + 9.124 + if (fflag) { 9.125 + if (cflag || bflag) 9.126 + usage(); 9.127 + } else if ((!cflag && !bflag) || dflag || sflag) 9.128 + usage(); 9.129 + else if (bflag && cflag) 9.130 + usage(); 9.131 + 9.132 + rval = 0; 9.133 + if (*argv) 9.134 + for (; *argv; ++argv) { 9.135 + if (strcmp(*argv, "-") == 0) 9.136 + fcn(stdin, "stdin"); 9.137 + else { 9.138 + if ((fp = fopen(*argv, "r"))) { 9.139 + fcn(fp, *argv); 9.140 + (void)fclose(fp); 9.141 + } else { 9.142 + rval = 1; 9.143 + warn("%s", *argv); 9.144 + } 9.145 + } 9.146 + } 9.147 + else 9.148 + fcn(stdin, "stdin"); 9.149 + return(rval); 9.150 +} 9.151 + 9.152 +static size_t autostart, autostop, maxval; 9.153 + 9.154 +static char *positions = NULL; 9.155 +static size_t numpositions = 0; 9.156 +#define ALLOC_CHUNK _POSIX2_LINE_MAX /* malloc granularity */ 9.157 + 9.158 +static void 9.159 +get_list(char *list) 9.160 +{ 9.161 + size_t setautostart, start, stop; 9.162 + char *pos; 9.163 + char *p; 9.164 + 9.165 + if (positions == NULL) { 9.166 + numpositions = ALLOC_CHUNK; 9.167 + positions = ecalloc(numpositions, sizeof(*positions)); 9.168 + } 9.169 + 9.170 + /* 9.171 + * set a byte in the positions array to indicate if a field or 9.172 + * column is to be selected; use +1, it's 1-based, not 0-based. 9.173 + * This parser is less restrictive than the Draft 9 POSIX spec. 9.174 + * POSIX doesn't allow lists that aren't in increasing order or 9.175 + * overlapping lists. We also handle "-3-5" although there's no 9.176 + * real reason to. 9.177 + */ 9.178 + for (; (p = strtok(list, ", \t")) != NULL; list = NULL) { 9.179 + setautostart = start = stop = 0; 9.180 + if (*p == '-') { 9.181 + ++p; 9.182 + setautostart = 1; 9.183 + } 9.184 + if (isdigit((unsigned char)*p)) { 9.185 + start = stop = strtol(p, &p, 10); 9.186 + if (setautostart && start > autostart) 9.187 + autostart = start; 9.188 + } 9.189 + if (*p == '-') { 9.190 + if (isdigit((unsigned char)p[1])) 9.191 + stop = strtol(p + 1, &p, 10); 9.192 + if (*p == '-') { 9.193 + ++p; 9.194 + if (!autostop || autostop > stop) 9.195 + autostop = stop; 9.196 + } 9.197 + } 9.198 + if (*p) 9.199 + errx(1, "[-bcf] list: illegal list value"); 9.200 + if (!stop || !start) 9.201 + errx(1, "[-bcf] list: values may not include zero"); 9.202 + if (stop + 1 > numpositions) { 9.203 + size_t newsize; 9.204 + newsize = roundup(stop + 1, ALLOC_CHUNK); 9.205 + positions = erealloc(positions, newsize); 9.206 + (void)memset(positions + numpositions, 0, 9.207 + newsize - numpositions); 9.208 + numpositions = newsize; 9.209 + } 9.210 + if (maxval < stop) 9.211 + maxval = stop; 9.212 + for (pos = positions + start; start++ <= stop; pos++) 9.213 + *pos = 1; 9.214 + } 9.215 + 9.216 + /* overlapping ranges */ 9.217 + if (autostop && maxval > autostop) 9.218 + maxval = autostop; 9.219 + 9.220 + /* set autostart */ 9.221 + if (autostart) 9.222 + (void)memset(positions + 1, '1', autostart); 9.223 +} 9.224 + 9.225 +static void 9.226 +/*ARGSUSED*/ 9.227 +f_cut(FILE *fp, const char *fname __unused) 9.228 +{ 9.229 + int ch, field, isdelim; 9.230 + char *pos, *p, sep; 9.231 + int output; 9.232 + size_t len; 9.233 + char *lbuf, *tbuf; 9.234 + 9.235 + for (sep = dchar, tbuf = NULL; (lbuf = fgetln(fp, &len)) != NULL;) { 9.236 + output = 0; 9.237 + if (lbuf[len - 1] != '\n') { 9.238 + /* no newline at the end of the last line so add one */ 9.239 + if ((tbuf = (char *)malloc(len + 1)) == NULL) 9.240 + err(1, NULL); 9.241 + (void)memcpy(tbuf, lbuf, len); 9.242 + tbuf[len++] = '\n'; 9.243 + lbuf = tbuf; 9.244 + } 9.245 + for (isdelim = 0, p = lbuf;; ++p) { 9.246 + ch = *p; 9.247 + /* this should work if newline is delimiter */ 9.248 + if (ch == sep) 9.249 + isdelim = 1; 9.250 + if (ch == '\n') { 9.251 + if (!isdelim && !sflag) 9.252 + (void)fwrite(lbuf, len, 1, stdout); 9.253 + break; 9.254 + } 9.255 + } 9.256 + if (!isdelim) 9.257 + continue; 9.258 + 9.259 + pos = positions + 1; 9.260 + for (field = maxval, p = lbuf; field; --field, ++pos) { 9.261 + if (*pos) { 9.262 + if (output++) 9.263 + (void)putchar(sep); 9.264 + while ((ch = *p++) != '\n' && ch != sep) 9.265 + (void)putchar(ch); 9.266 + } else { 9.267 + while ((ch = *p++) != '\n' && ch != sep) 9.268 + continue; 9.269 + } 9.270 + if (ch == '\n') 9.271 + break; 9.272 + } 9.273 + if (ch != '\n') { 9.274 + if (autostop) { 9.275 + if (output) 9.276 + (void)putchar(sep); 9.277 + for (; (ch = *p) != '\n'; ++p) 9.278 + (void)putchar(ch); 9.279 + } else 9.280 + for (; (ch = *p) != '\n'; ++p); 9.281 + } 9.282 + (void)putchar('\n'); 9.283 + if (tbuf) { 9.284 + free(tbuf); 9.285 + tbuf = NULL; 9.286 + } 9.287 + } 9.288 + if (tbuf) 9.289 + free(tbuf); 9.290 +} 9.291 + 9.292 +static void 9.293 +usage(void) 9.294 +{ 9.295 + (void)fprintf(stderr, "usage:\tcut -b list [-n] [file ...]\n" 9.296 + "\tcut -c list [file ...]\n" 9.297 + "\tcut -f list [-d string] [-s] [file ...]\n"); 9.298 + exit(1); 9.299 +} 9.300 + 9.301 +/* make b_put(): */ 9.302 +#define CUT_BYTE 1 9.303 +#include "x_cut.c" 9.304 +#undef CUT_BYTE 9.305 + 9.306 +/* make c_put(): */ 9.307 +#define CUT_BYTE 0 9.308 +#include "x_cut.c" 9.309 +#undef CUT_BYTE
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/code/cut.c__openbsd.2008-06-27 Tue May 12 06:46:59 2015 +0200 10.3 @@ -0,0 +1,290 @@ 10.4 +/* $OpenBSD: cut.c,v 1.13 2008/06/27 08:02:13 sobrado Exp $ */ 10.5 +/* $NetBSD: cut.c,v 1.9 1995/09/02 05:59:23 jtc Exp $ */ 10.6 + 10.7 +/* 10.8 + * Copyright (c) 1989, 1993 10.9 + * The Regents of the University of California. All rights reserved. 10.10 + * 10.11 + * This code is derived from software contributed to Berkeley by 10.12 + * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue. 10.13 + * 10.14 + * Redistribution and use in source and binary forms, with or without 10.15 + * modification, are permitted provided that the following conditions 10.16 + * are met: 10.17 + * 1. Redistributions of source code must retain the above copyright 10.18 + * notice, this list of conditions and the following disclaimer. 10.19 + * 2. Redistributions in binary form must reproduce the above copyright 10.20 + * notice, this list of conditions and the following disclaimer in the 10.21 + * documentation and/or other materials provided with the distribution. 10.22 + * 3. Neither the name of the University nor the names of its contributors 10.23 + * may be used to endorse or promote products derived from this software 10.24 + * without specific prior written permission. 10.25 + * 10.26 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 10.27 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 10.28 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 10.29 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 10.30 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 10.31 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 10.32 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 10.33 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 10.34 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 10.35 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 10.36 + * SUCH DAMAGE. 10.37 + */ 10.38 + 10.39 +#ifndef lint 10.40 +static char copyright[] = 10.41 +"@(#) Copyright (c) 1989, 1993\n\ 10.42 + The Regents of the University of California. All rights reserved.\n"; 10.43 +#endif /* not lint */ 10.44 + 10.45 +#ifndef lint 10.46 +#if 0 10.47 +static char sccsid[] = "@(#)cut.c 8.3 (Berkeley) 5/4/95"; 10.48 +#endif 10.49 +static char rcsid[] = "$OpenBSD: cut.c,v 1.13 2008/06/27 08:02:13 sobrado Exp $"; 10.50 +#endif /* not lint */ 10.51 + 10.52 +#include <ctype.h> 10.53 +#include <err.h> 10.54 +#include <errno.h> 10.55 +#include <limits.h> 10.56 +#include <locale.h> 10.57 +#include <stdio.h> 10.58 +#include <stdlib.h> 10.59 +#include <string.h> 10.60 +#include <unistd.h> 10.61 + 10.62 +int cflag; 10.63 +char dchar; 10.64 +int dflag; 10.65 +int fflag; 10.66 +int sflag; 10.67 + 10.68 +void c_cut(FILE *, char *); 10.69 +void f_cut(FILE *, char *); 10.70 +void get_list(char *); 10.71 +void usage(void); 10.72 + 10.73 +int 10.74 +main(int argc, char *argv[]) 10.75 +{ 10.76 + FILE *fp; 10.77 + void (*fcn)(FILE *, char *); 10.78 + int ch; 10.79 + 10.80 + setlocale (LC_ALL, ""); 10.81 + 10.82 + dchar = '\t'; /* default delimiter is \t */ 10.83 + 10.84 + /* Since we don't support multi-byte characters, the -c and -b 10.85 + options are equivalent, and the -n option is meaningless. */ 10.86 + while ((ch = getopt(argc, argv, "b:c:d:f:sn")) != -1) 10.87 + switch(ch) { 10.88 + case 'b': 10.89 + case 'c': 10.90 + fcn = c_cut; 10.91 + get_list(optarg); 10.92 + cflag = 1; 10.93 + break; 10.94 + case 'd': 10.95 + dchar = *optarg; 10.96 + dflag = 1; 10.97 + break; 10.98 + case 'f': 10.99 + get_list(optarg); 10.100 + fcn = f_cut; 10.101 + fflag = 1; 10.102 + break; 10.103 + case 's': 10.104 + sflag = 1; 10.105 + break; 10.106 + case 'n': 10.107 + break; 10.108 + case '?': 10.109 + default: 10.110 + usage(); 10.111 + } 10.112 + argc -= optind; 10.113 + argv += optind; 10.114 + 10.115 + if (fflag) { 10.116 + if (cflag) 10.117 + usage(); 10.118 + } else if (!cflag || dflag || sflag) 10.119 + usage(); 10.120 + 10.121 + if (*argv) 10.122 + for (; *argv; ++argv) { 10.123 + if (!(fp = fopen(*argv, "r"))) 10.124 + err(1, "%s", *argv); 10.125 + fcn(fp, *argv); 10.126 + (void)fclose(fp); 10.127 + } 10.128 + else 10.129 + fcn(stdin, "stdin"); 10.130 + exit(0); 10.131 +} 10.132 + 10.133 +int autostart, autostop, maxval; 10.134 + 10.135 +char positions[_POSIX2_LINE_MAX + 1]; 10.136 + 10.137 +void 10.138 +get_list(char *list) 10.139 +{ 10.140 + int setautostart, start, stop; 10.141 + char *pos; 10.142 + char *p; 10.143 + 10.144 + /* 10.145 + * set a byte in the positions array to indicate if a field or 10.146 + * column is to be selected; use +1, it's 1-based, not 0-based. 10.147 + * This parser is less restrictive than the Draft 9 POSIX spec. 10.148 + * POSIX doesn't allow lists that aren't in increasing order or 10.149 + * overlapping lists. We also handle "-3-5" although there's no 10.150 + * real reason too. 10.151 + */ 10.152 + while ((p = strsep(&list, ", \t"))) { 10.153 + setautostart = start = stop = 0; 10.154 + if (*p == '-') { 10.155 + ++p; 10.156 + setautostart = 1; 10.157 + } 10.158 + if (isdigit(*p)) { 10.159 + start = stop = strtol(p, &p, 10); 10.160 + if (setautostart && start > autostart) 10.161 + autostart = start; 10.162 + } 10.163 + if (*p == '-') { 10.164 + if (isdigit(p[1])) 10.165 + stop = strtol(p + 1, &p, 10); 10.166 + if (*p == '-') { 10.167 + ++p; 10.168 + if (!autostop || autostop > stop) 10.169 + autostop = stop; 10.170 + } 10.171 + } 10.172 + if (*p) 10.173 + errx(1, "[-cf] list: illegal list value"); 10.174 + if (!stop || !start) 10.175 + errx(1, "[-cf] list: values may not include zero"); 10.176 + if (stop > _POSIX2_LINE_MAX) 10.177 + errx(1, "[-cf] list: %d too large (max %d)", 10.178 + stop, _POSIX2_LINE_MAX); 10.179 + if (maxval < stop) 10.180 + maxval = stop; 10.181 + for (pos = positions + start; start++ <= stop; *pos++ = 1) 10.182 + ; 10.183 + } 10.184 + 10.185 + /* overlapping ranges */ 10.186 + if (autostop && maxval > autostop) 10.187 + maxval = autostop; 10.188 + 10.189 + /* set autostart */ 10.190 + if (autostart) 10.191 + memset(positions + 1, '1', autostart); 10.192 +} 10.193 + 10.194 +/* ARGSUSED */ 10.195 +void 10.196 +c_cut(FILE *fp, char *fname) 10.197 +{ 10.198 + int ch, col; 10.199 + char *pos; 10.200 + 10.201 + for (;;) { 10.202 + pos = positions + 1; 10.203 + for (col = maxval; col; --col) { 10.204 + if ((ch = getc(fp)) == EOF) 10.205 + return; 10.206 + if (ch == '\n') 10.207 + break; 10.208 + if (*pos++) 10.209 + (void)putchar(ch); 10.210 + } 10.211 + if (ch != '\n') { 10.212 + if (autostop) 10.213 + while ((ch = getc(fp)) != EOF && ch != '\n') 10.214 + (void)putchar(ch); 10.215 + else 10.216 + while ((ch = getc(fp)) != EOF && ch != '\n') 10.217 + ; 10.218 + } 10.219 + (void)putchar('\n'); 10.220 + } 10.221 +} 10.222 + 10.223 +void 10.224 +f_cut(FILE *fp, char *fname) 10.225 +{ 10.226 + int ch, field, isdelim; 10.227 + char *pos, *p, sep; 10.228 + int output; 10.229 + size_t len; 10.230 + char *lbuf, *tbuf; 10.231 + 10.232 + for (sep = dchar, tbuf = NULL; (lbuf = fgetln(fp, &len));) { 10.233 + output = 0; 10.234 + if (lbuf[len - 1] != '\n') { 10.235 + /* no newline at the end of the last line so add one */ 10.236 + if ((tbuf = (char *)malloc(len + 1)) == NULL) 10.237 + err(1, NULL); 10.238 + memcpy(tbuf, lbuf, len); 10.239 + tbuf[len] = '\n'; 10.240 + lbuf = tbuf; 10.241 + } 10.242 + for (isdelim = 0, p = lbuf;; ++p) { 10.243 + ch = *p; 10.244 + /* this should work if newline is delimiter */ 10.245 + if (ch == sep) 10.246 + isdelim = 1; 10.247 + if (ch == '\n') { 10.248 + if (!isdelim && !sflag) 10.249 + (void)fwrite(lbuf, len, 1, stdout); 10.250 + break; 10.251 + } 10.252 + } 10.253 + if (!isdelim) 10.254 + continue; 10.255 + 10.256 + pos = positions + 1; 10.257 + for (field = maxval, p = lbuf; field; --field, ++pos) { 10.258 + if (*pos) { 10.259 + if (output++) 10.260 + (void)putchar(sep); 10.261 + while ((ch = *p++) != '\n' && ch != sep) 10.262 + (void)putchar(ch); 10.263 + } else 10.264 + while ((ch = *p++) != '\n' && ch != sep) 10.265 + ; 10.266 + if (ch == '\n') 10.267 + break; 10.268 + } 10.269 + if (ch != '\n') { 10.270 + if (autostop) { 10.271 + if (output) 10.272 + (void)putchar(sep); 10.273 + for (; (ch = *p) != '\n'; ++p) 10.274 + (void)putchar(ch); 10.275 + } else 10.276 + for (; (ch = *p) != '\n'; ++p) 10.277 + ; 10.278 + } 10.279 + (void)putchar('\n'); 10.280 + } 10.281 + if (tbuf) 10.282 + free(tbuf); 10.283 +} 10.284 + 10.285 +void 10.286 +usage(void) 10.287 +{ 10.288 + (void)fprintf(stderr, 10.289 + "usage: cut -b list [-n] [file ...]\n" 10.290 + " cut -c list [file ...]\n" 10.291 + " cut -f list [-s] [-d delim] [file ...]\n"); 10.292 + exit(1); 10.293 +}
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/code/cut.c__system_iii.1980-04-11 Tue May 12 06:46:59 2015 +0200 11.3 @@ -0,0 +1,123 @@ 11.4 +# 11.5 +/* cut : cut and paste columns of a table (projection of a relation) (GWRL) */ 11.6 +/* Release 1.5; handles single backspaces as produced by nroff */ 11.7 +# include <stdio.h> /* make: cc cut.c */ 11.8 +# define NFIELDS 512 /* max no of fields or resulting line length */ 11.9 +# define BACKSPACE 8 11.10 +main(argc, argv) 11.11 +int argc; char **argv; 11.12 +{ 11.13 + int del = '\t'; 11.14 + int i, j, count, poscnt, r, s, t; 11.15 + int endflag, supflag, cflag, fflag, backflag, filenr; 11.16 + int sel[NFIELDS]; 11.17 + register int c; 11.18 + register char *p1; 11.19 + char *p2, outbuf[NFIELDS]; 11.20 + FILE *inptr; 11.21 + 11.22 + 11.23 +while (argc > 1 && argv[1][0] == '-'){ 11.24 + for (i = 1; (c = argv[1][i]) != '\0'; i++) { 11.25 + switch(c) { 11.26 + case 'd' : del = argv[1][++i]; 11.27 + if (del == '\0') diag("no delimiter\n"); 11.28 + break; 11.29 + case 's': supflag++ ; 11.30 + break; 11.31 + case 'c': cflag++ ; 11.32 + break; 11.33 + case 'f': fflag++ ; 11.34 + break; 11.35 + default : diag("Usage: cut [-s] [-d<char>] {-c<list> | -f<list>} file ...\n"); 11.36 + break; 11.37 + } 11.38 + if (!endflag && (cflag || fflag)) { 11.39 + endflag = 1; 11.40 + r = s = t = 0; 11.41 + do { c = argv[1][++i]; 11.42 + switch(c) { 11.43 + case '-' : if (r) diagl(); 11.44 + r = 1; 11.45 + if (t == 0) s = 1; 11.46 + else {s = t; t = 0;} 11.47 + continue; 11.48 + case '\0' : 11.49 + case ',' : if (t >= NFIELDS) diagl(); 11.50 + if (r) { if (t == 0) t = NFIELDS - 1; 11.51 + if (t<s) diagl(); 11.52 + for(j = s; j <= t; j++) sel[j] = 1; 11.53 + } 11.54 + else sel[t] = (t > 0 ? 1 : 0); 11.55 + r = s = t = 0; 11.56 + if (c == '\0') {i--; break;} 11.57 + continue; 11.58 + default : 11.59 + if (c< '0' || c> '9') diagl(); 11.60 + t = 10*t + c - '0'; 11.61 + continue; 11.62 + } 11.63 + for (j = t = 0; j < NFIELDS; j++) t += sel[j]; 11.64 + if (t == 0) diag("no fields\n"); 11.65 + } while (c != '\0'); 11.66 + } 11.67 + } 11.68 + --argc; 11.69 + ++argv; 11.70 +} /* end options */ 11.71 +if (!(cflag || fflag)) diagl(); 11.72 + 11.73 +--argc; 11.74 +filenr = 1; 11.75 +do { /* for all input files */ 11.76 + if (argc > 0) inptr = fopen(argv[filenr], "r"); 11.77 + else inptr = stdin; 11.78 + 11.79 + if (inptr == NULL) { 11.80 + write(2,"Cannot open :",14); 11.81 + diag(argv[filenr]); 11.82 + } 11.83 + endflag = 0; 11.84 + do { /* for all lines of a file */ 11.85 + count = poscnt = backflag = 0; 11.86 + p1 = &outbuf[0] - 1 ; 11.87 + p2 = p1; 11.88 + do { /* for all char of the line */ 11.89 + c = fgetc(inptr); 11.90 + if (c == EOF) { 11.91 + endflag = 1; 11.92 + break; 11.93 + } 11.94 + if (count == NFIELDS - 1) diag("line too long\n"); 11.95 + if (c != '\n') *++p1 = c; 11.96 + if (cflag && (c == BACKSPACE)) backflag++ ; else 11.97 + { if ( !backflag ) poscnt += 1 ; else backflag-- ;} 11.98 + if ( backflag > 1 ) diag("cannot handle multiple adjacent backspaces\n"); 11.99 + if ( ((c == '\n') && count > 0) || c == del || cflag) { 11.100 + count += 1; 11.101 + if (fflag) poscnt = count ; 11.102 + if (sel[poscnt]) p2 = p1; else p1 = p2; 11.103 + } 11.104 + }while (c != '\n'); 11.105 + if ( !endflag && (count > 0 || !supflag)) { 11.106 + if (*p1 == del) *p1 = '\0'; 11.107 + else *++p1 = '\0'; /*suppress trailing delimiter*/ 11.108 + puts(outbuf); 11.109 + } 11.110 + } while (!endflag) ; 11.111 +fclose(inptr); 11.112 +} while(++filenr <= argc); 11.113 +} 11.114 + 11.115 +diag(s) 11.116 +char *s; 11.117 +{ 11.118 + write(2, "cut : ", 6); 11.119 + while(*s) 11.120 + write(2,s++,1); 11.121 + exit(2); 11.122 +} 11.123 +diagl() 11.124 +{ 11.125 +diag("bad list for c/f option\n"); 11.126 +}