aboutsummaryrefslogtreecommitdiff
path: root/coreutils/cut.c
diff options
context:
space:
mode:
authoraldot <aldot@69ca8d6d-28ef-0310-b511-8ec308f3f277>2006-08-28 23:31:54 +0000
committeraldot <aldot@69ca8d6d-28ef-0310-b511-8ec308f3f277>2006-08-28 23:31:54 +0000
commitd52f45a484fc7fc049ab40db9adc6ead7ea9b122 (patch)
tree2a57564b8917a983365c765d4daa83032d9f0a17 /coreutils/cut.c
parent2803d256e9decd450b955c2846bf945db72bb79e (diff)
downloadbusybox-w32-d52f45a484fc7fc049ab40db9adc6ead7ea9b122.tar.gz
busybox-w32-d52f45a484fc7fc049ab40db9adc6ead7ea9b122.tar.bz2
busybox-w32-d52f45a484fc7fc049ab40db9adc6ead7ea9b122.zip
- pull from busybox_scratch: r15829:15850
Various fixes, cleanups and shrinkage: saves 952 Bytes: text data bss dec hex filename 1087742 15853 790632 1894227 1ce753 ../busybox/busybox.old 1086790 15853 790632 1893275 1ce39b busybox via: # scripts/bloat-o-meter ../busybox/busybox_unstripped.old busybox_unstripped function old new delta ipcrm_main 756 822 +66 getval - 61 +61 maybe_set_utc - 40 +40 udhcpc_main 2896 2912 +16 md5_hash_block 428 437 +9 opt 8 16 +8 qgravechar 106 110 +4 make_bitmap 292 295 +3 inflate_unzip 2056 2059 +3 add_partition 1412 1414 +2 __parsespent 156 158 +2 qrealloc 41 42 +1 format - 1 +1 catv_main 313 314 +1 watch_main 293 292 -1 varunset 81 80 -1 part 1 - -1 check_if_skip 837 836 -1 start_stop_daemon_main 840 837 -3 create_lost_and_found 175 172 -3 supress_non_delimited_lines 4 - -4 static.l 4 - -4 static.c 5 1 -4 bsd_sum_file 237 233 -4 eval2 338 332 -6 arithmetic_common 166 158 -8 cmpfunc 22 5 -17 cksum_main 294 275 -19 cmp_main 465 439 -26 dd_main 1535 1508 -27 rmmod_main 376 333 -43 cut_file 727 644 -83 ipcs_main 3809 3721 -88 cut_main 722 614 -108 date_main 1443 1263 -180 remove_ids 222 - -222 ------------------------------------------------------------------------------ (add/remove: 3/4 grow/shrink: 11/18 up/down: 217/-853) Total: -636 bytes git-svn-id: svn://busybox.net/trunk/busybox@16009 69ca8d6d-28ef-0310-b511-8ec308f3f277
Diffstat (limited to 'coreutils/cut.c')
-rw-r--r--coreutils/cut.c479
1 files changed, 224 insertions, 255 deletions
diff --git a/coreutils/cut.c b/coreutils/cut.c
index 1b80e7e73..d88a891b0 100644
--- a/coreutils/cut.c
+++ b/coreutils/cut.c
@@ -4,28 +4,24 @@
4 * 4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. 5 * Copyright (C) 1999,2000,2001 by Lineo, inc.
6 * Written by Mark Whitley <markw@codepoet.org> 6 * Written by Mark Whitley <markw@codepoet.org>
7 * debloated by Bernhard Fischer
7 * 8 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */ 10 */
10 11
11#include <stdio.h>
12#include <stdlib.h>
13#include <unistd.h>
14#include <string.h>
15#include <limits.h>
16#include "busybox.h" 12#include "busybox.h"
17 13
18
19/* option vars */ 14/* option vars */
20static const char optstring[] = "b:c:f:d:sn"; 15static const char *const optstring = "b:c:f:d:sn";
21#define OPT_BYTE_FLGS 1 16
22#define OPT_CHAR_FLGS 2 17#define CUT_OPT_BYTE_FLGS (1<<0)
23#define OPT_FIELDS_FLGS 4 18#define CUT_OPT_CHAR_FLGS (1<<1)
24#define OPT_DELIM_FLGS 8 19#define CUT_OPT_FIELDS_FLGS (1<<2)
25#define OPT_SUPRESS_FLGS 16 20#define CUT_OPT_DELIM_FLGS (1<<3)
26static char part; /* (b)yte, (c)har, (f)ields */ 21#define CUT_OPT_SUPPRESS_FLGS (1<<4)
27static unsigned int supress_non_delimited_lines; 22static unsigned long opt;
28static char delim = '\t'; /* delimiter, default is tab */ 23
24static char delim = '\t'; /* delimiter, default is tab */
29 25
30struct cut_list { 26struct cut_list {
31 int startpos; 27 int startpos;
@@ -38,295 +34,268 @@ enum {
38 NON_RANGE = -1 34 NON_RANGE = -1
39}; 35};
40 36
41static struct cut_list *cut_lists = NULL; /* growable array holding a series of lists */ 37/* growable array holding a series of lists */
42static unsigned int nlists = 0; /* number of elements in above list */ 38static struct cut_list *cut_lists;
39static unsigned int nlists; /* number of elements in above list */
43 40
44 41
45static int cmpfunc(const void *a, const void *b) 42static int cmpfunc(const void *a, const void *b)
46{ 43{
47 struct cut_list *la = (struct cut_list *)a; 44 return (((struct cut_list *) a)->startpos -
48 struct cut_list *lb = (struct cut_list *)b; 45 ((struct cut_list *) b)->startpos);
49
50 if (la->startpos > lb->startpos)
51 return 1;
52 if (la->startpos < lb->startpos)
53 return -1;
54 return 0;
55}
56 46
47}
57 48
58/* 49static void cut_file(FILE * file)
59 * parse_lists() - parses a list and puts values into startpos and endpos.
60 * valid list formats: N, N-, N-M, -M
61 * more than one list can be separated by commas
62 */
63static void parse_lists(char *lists)
64{ 50{
65 char *ltok = NULL; 51 char *line = NULL;
66 char *ntok = NULL; 52 unsigned int linenum = 0; /* keep these zero-based to be consistent */
67 char *junk;
68 int s = 0, e = 0;
69
70 /* take apart the lists, one by one (they are separated with commas */
71 while ((ltok = strsep(&lists, ",")) != NULL) {
72
73 /* it's actually legal to pass an empty list */
74 if (strlen(ltok) == 0)
75 continue;
76
77 /* get the start pos */
78 ntok = strsep(&ltok, "-");
79 if (ntok == NULL) {
80 fprintf(stderr, "Help ntok is null for starting position! What do I do?\n");
81 } else if (strlen(ntok) == 0) {
82 s = BOL;
83 } else {
84 s = strtoul(ntok, &junk, 10);
85 if(*junk != '\0' || s < 0)
86 bb_error_msg_and_die("invalid byte or field list");
87
88 /* account for the fact that arrays are zero based, while the user
89 * expects the first char on the line to be char # 1 */
90 if (s != 0)
91 s--;
92 }
93
94 /* get the end pos */
95 ntok = strsep(&ltok, "-");
96 if (ntok == NULL) {
97 e = NON_RANGE;
98 } else if (strlen(ntok) == 0) {
99 e = EOL;
100 } else {
101 e = strtoul(ntok, &junk, 10);
102 if(*junk != '\0' || e < 0)
103 bb_error_msg_and_die("invalid byte or field list");
104 /* if the user specified and end position of 0, that means "til the
105 * end of the line */
106 if (e == 0)
107 e = INT_MAX;
108 e--; /* again, arrays are zero based, lines are 1 based */
109 if (e == s)
110 e = NON_RANGE;
111 }
112
113 /* if there's something left to tokenize, the user past an invalid list */
114 if (ltok)
115 bb_error_msg_and_die("invalid byte or field list");
116
117 /* add the new list */
118 cut_lists = xrealloc(cut_lists, sizeof(struct cut_list) * (++nlists));
119 cut_lists[nlists-1].startpos = s;
120 cut_lists[nlists-1].endpos = e;
121 }
122
123 /* make sure we got some cut positions out of all that */
124 if (nlists == 0)
125 bb_error_msg_and_die("missing list of positions");
126
127 /* now that the lists are parsed, we need to sort them to make life easier
128 * on us when it comes time to print the chars / fields / lines */
129 qsort(cut_lists, nlists, sizeof(struct cut_list), cmpfunc);
130 53
131} 54 /* go through every line in the file */
55 while ((line = bb_get_chomped_line_from_file(file)) != NULL) {
132 56
57 /* set up a list so we can keep track of what's been printed */
58 char * printed = xzalloc(strlen(line) * sizeof(char));
59 char * orig_line = line;
60 unsigned int cl_pos = 0;
61 int spos;
133 62
134static void cut_line_by_chars(const char *line) 63 /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */
135{ 64 if ((opt & (CUT_OPT_CHAR_FLGS | CUT_OPT_BYTE_FLGS))) {
136 int c, l; 65 /* print the chars specified in each cut list */
137 /* set up a list so we can keep track of what's been printed */ 66 for (; cl_pos < nlists; cl_pos++) {
138 char *printed = xzalloc(strlen(line)); 67 spos = cut_lists[cl_pos].startpos;
139 68 while (spos < strlen(line)) {
140 /* print the chars specified in each cut list */ 69 if (!printed[spos]) {
141 for (c = 0; c < nlists; c++) { 70 printed[spos] = 'X';
142 l = cut_lists[c].startpos; 71 putchar(line[spos]);
143 while (l < strlen(line)) { 72 }
144 if (!printed[l]) { 73 spos++;
145 putchar(line[l]); 74 if (spos > cut_lists[cl_pos].endpos
146 printed[l] = 'X'; 75 || cut_lists[cl_pos].endpos == NON_RANGE)
76 break;
77 }
78 }
79 } else if (delim == '\n') { /* cut by lines */
80 spos = cut_lists[cl_pos].startpos;
81
82 /* get out if we have no more lists to process or if the lines
83 * are lower than what we're interested in */
84 if (linenum < spos || cl_pos >= nlists)
85 goto next_line;
86
87 /* if the line we're looking for is lower than the one we were
88 * passed, it means we displayed it already, so move on */
89 while (spos < linenum) {
90 spos++;
91 /* go to the next list if we're at the end of this one */
92 if (spos > cut_lists[cl_pos].endpos
93 || cut_lists[cl_pos].endpos == NON_RANGE) {
94 cl_pos++;
95 /* get out if there's no more lists to process */
96 if (cl_pos >= nlists)
97 goto next_line;
98 spos = cut_lists[cl_pos].startpos;
99 /* get out if the current line is lower than the one
100 * we just became interested in */
101 if (linenum < spos)
102 goto next_line;
103 }
147 } 104 }
148 l++;
149 if (cut_lists[c].endpos == NON_RANGE || l > cut_lists[c].endpos)
150 break;
151 }
152 }
153 putchar('\n'); /* cuz we were handed a chomped line */
154 free(printed);
155}
156
157 105
158static void cut_line_by_fields(char *line) 106 /* If we made it here, it means we've found the line we're
159{ 107 * looking for, so print it */
160 int c, f;
161 int ndelim = -1; /* zero-based / one-based problem */
162 int nfields_printed = 0;
163 char *field = NULL;
164 char d[2] = { delim, 0 };
165 char *printed;
166
167 /* test the easy case first: does this line contain any delimiters? */
168 if (strchr(line, delim) == NULL) {
169 if (!supress_non_delimited_lines)
170 puts(line); 108 puts(line);
171 return; 109 goto next_line;
172 } 110 } else { /* cut by fields */
173 111 int ndelim = -1; /* zero-based / one-based problem */
174 /* set up a list so we can keep track of what's been printed */ 112 int nfields_printed = 0;
175 printed = xzalloc(strlen(line)); 113 char *field = NULL;
176 114 const char delimiter[2] = { delim, 0 };
177 /* process each list on this line, for as long as we've got a line to process */ 115
178 for (c = 0; c < nlists && line; c++) { 116 /* does this line contain any delimiters? */
179 f = cut_lists[c].startpos; 117 if (strchr(line, delim) == NULL) {
180 do { 118 if (!(opt & CUT_OPT_SUPPRESS_FLGS))
181 119 puts(line);
182 /* find the field we're looking for */ 120 goto next_line;
183 while (line && ndelim < f) {
184 field = strsep(&line, d);
185 ndelim++;
186 } 121 }
187 122
188 /* we found it, and it hasn't been printed yet */ 123 /* process each list on this line, for as long as we've got
189 if (field && ndelim == f && !printed[ndelim]) { 124 * a line to process */
190 /* if this isn't our first time through, we need to print the 125 for (; cl_pos < nlists && line; cl_pos++) {
191 * delimiter after the last field that was printed */ 126 spos = cut_lists[cl_pos].startpos;
192 if (nfields_printed > 0) 127 do {
193 putchar(delim); 128
194 fputs(field, stdout); 129 /* find the field we're looking for */
195 printed[ndelim] = 'X'; 130 while (line && ndelim < spos) {
196 nfields_printed++; 131 field = strsep(&line, delimiter);
132 ndelim++;
133 }
134
135 /* we found it, and it hasn't been printed yet */
136 if (field && ndelim == spos && !printed[ndelim]) {
137 /* if this isn't our first time through, we need to
138 * print the delimiter after the last field that was
139 * printed */
140 if (nfields_printed > 0)
141 putchar(delim);
142 fputs(field, stdout);
143 printed[ndelim] = 'X';
144 nfields_printed++; /* shouldn't overflow.. */
145 }
146
147 spos++;
148
149 /* keep going as long as we have a line to work with,
150 * this is a list, and we're not at the end of that
151 * list */
152 } while (spos <= cut_lists[cl_pos].endpos && line
153 && cut_lists[cl_pos].endpos != NON_RANGE);
197 } 154 }
198
199 f++;
200
201 /* keep going as long as we have a line to work with, this is a
202 * list, and we're not at the end of that list */
203 } while (line && cut_lists[c].endpos != NON_RANGE && f <= cut_lists[c].endpos);
204 }
205
206 /* if we printed anything at all, we need to finish it with a newline cuz
207 * we were handed a chomped line */
208 putchar('\n');
209
210 free(printed);
211}
212
213
214static void cut_file_by_lines(const char *line, unsigned int linenum)
215{
216 static int c = 0;
217 static int l = -1;
218
219 /* I can't initialize this above cuz the "initializer isn't
220 * constant" *sigh* */
221 if (l == -1)
222 l = cut_lists[c].startpos;
223
224 /* get out if we have no more lists to process or if the lines are lower
225 * than what we're interested in */
226 if (c >= nlists || linenum < l)
227 return;
228
229 /* if the line we're looking for is lower than the one we were passed, it
230 * means we displayed it already, so move on */
231 while (l < linenum) {
232 l++;
233 /* move on to the next list if we're at the end of this one */
234 if (cut_lists[c].endpos == NON_RANGE || l > cut_lists[c].endpos) {
235 c++;
236 /* get out if there's no more lists to process */
237 if (c >= nlists)
238 return;
239 l = cut_lists[c].startpos;
240 /* get out if the current line is lower than the one we just became
241 * interested in */
242 if (linenum < l)
243 return;
244 } 155 }
156 /* if we printed anything at all, we need to finish it with a
157 * newline cuz we were handed a chomped line */
158 putchar('\n');
159 next_line:
160 linenum++;
161 free(printed);
162 free(orig_line);
245 } 163 }
246
247 /* If we made it here, it means we've found the line we're looking for, so print it */
248 puts(line);
249} 164}
250 165
251 166static int getval(char *ntok)
252/*
253 * snippy-snip
254 */
255static void cut_file(FILE *file)
256{ 167{
257 char *line = NULL; 168 char *junk;
258 unsigned int linenum = 0; /* keep these zero-based to be consistent */ 169 int i = strtoul(ntok, &junk, 10);
259
260 /* go through every line in the file */
261 while ((line = bb_get_chomped_line_from_file(file)) != NULL) {
262
263 /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */
264 if ((part & (OPT_CHAR_FLGS | OPT_BYTE_FLGS)))
265 cut_line_by_chars(line);
266
267 /* cut based on fields */
268 else {
269 if (delim == '\n')
270 cut_file_by_lines(line, linenum);
271 else
272 cut_line_by_fields(line);
273 }
274 170
275 linenum++; 171 if (*junk != '\0' || i < 0)
276 free(line); 172 bb_error_msg_and_die("invalid byte or field list");
277 } 173 return i;
278} 174}
279 175
176static const char * const _op_on_field = " only when operating on fields";
280 177
281int cut_main(int argc, char **argv) 178int cut_main(int argc, char **argv)
282{ 179{
283 unsigned long opt; 180 char *sopt, *ltok;
284 char *sopt, *sdopt;
285 181
286 bb_opt_complementally = "b--bcf:c--bcf:f--bcf"; 182 bb_opt_complementally = "b--bcf:c--bcf:f--bcf";
287 opt = bb_getopt_ulflags(argc, argv, optstring, &sopt, &sopt, &sopt, &sdopt); 183 opt =
288 part = opt & (OPT_BYTE_FLGS|OPT_CHAR_FLGS|OPT_FIELDS_FLGS); 184 bb_getopt_ulflags(argc, argv, optstring, &sopt, &sopt, &sopt, &ltok);
289 if(part == 0) 185 if (!(opt & (CUT_OPT_BYTE_FLGS | CUT_OPT_CHAR_FLGS | CUT_OPT_FIELDS_FLGS)))
290 bb_error_msg_and_die("you must specify a list of bytes, characters, or fields"); 186 bb_error_msg_and_die
291 if(opt & BB_GETOPT_ERROR) 187 ("expected a list of bytes, characters, or fields");
188 if (opt & BB_GETOPT_ERROR)
292 bb_error_msg_and_die("only one type of list may be specified"); 189 bb_error_msg_and_die("only one type of list may be specified");
293 parse_lists(sopt); 190
294 if((opt & (OPT_DELIM_FLGS))) { 191 if ((opt & (CUT_OPT_DELIM_FLGS))) {
295 if (strlen(sdopt) > 1) { 192 if (strlen(ltok) > 1) {
296 bb_error_msg_and_die("the delimiter must be a single character"); 193 bb_error_msg_and_die("the delimiter must be a single character");
297 } 194 }
298 delim = sdopt[0]; 195 delim = ltok[0];
299 } 196 }
300 supress_non_delimited_lines = opt & OPT_SUPRESS_FLGS;
301 197
302 /* non-field (char or byte) cutting has some special handling */ 198 /* non-field (char or byte) cutting has some special handling */
303 if (part != OPT_FIELDS_FLGS) { 199 if (!(opt & CUT_OPT_FIELDS_FLGS)) {
304 if (supress_non_delimited_lines) { 200 if (opt & CUT_OPT_SUPPRESS_FLGS) {
305 bb_error_msg_and_die("suppressing non-delimited lines makes sense" 201 bb_error_msg_and_die
306 " only when operating on fields"); 202 ("suppressing non-delimited lines makes sense%s",
203 _op_on_field);
307 } 204 }
308 if (delim != '\t') { 205 if (delim != '\t') {
309 bb_error_msg_and_die("a delimiter may be specified only when operating on fields"); 206 bb_error_msg_and_die
207 ("a delimiter may be specified%s", _op_on_field);
310 } 208 }
311 } 209 }
312 210
211 /*
212 * parse list and put values into startpos and endpos.
213 * valid list formats: N, N-, N-M, -M
214 * more than one list can be separated by commas
215 */
216 {
217 char *ntok;
218 int s = 0, e = 0;
219
220 /* take apart the lists, one by one (they are separated with commas */
221 while ((ltok = strsep(&sopt, ",")) != NULL) {
222
223 /* it's actually legal to pass an empty list */
224 if (strlen(ltok) == 0)
225 continue;
226
227 /* get the start pos */
228 ntok = strsep(&ltok, "-");
229 if (ntok == NULL) {
230 bb_error_msg
231 ("internal error: ntok is null for start pos!?\n");
232 } else if (strlen(ntok) == 0) {
233 s = BOL;
234 } else {
235 s = getval(ntok);
236 /* account for the fact that arrays are zero based, while
237 * the user expects the first char on the line to be char #1 */
238 if (s != 0)
239 s--;
240 }
241
242 /* get the end pos */
243 ntok = strsep(&ltok, "-");
244 if (ntok == NULL) {
245 e = NON_RANGE;
246 } else if (strlen(ntok) == 0) {
247 e = EOL;
248 } else {
249 e = getval(ntok);
250 /* if the user specified and end position of 0, that means "til the
251 * end of the line */
252 if (e == 0)
253 e = EOL;
254 e--; /* again, arrays are zero based, lines are 1 based */
255 if (e == s)
256 e = NON_RANGE;
257 }
258
259 /* if there's something left to tokenize, the user passed
260 * an invalid list */
261 if (ltok)
262 bb_error_msg_and_die("invalid byte or field list");
263
264 /* add the new list */
265 cut_lists =
266 xrealloc(cut_lists, sizeof(struct cut_list) * (++nlists));
267 cut_lists[nlists - 1].startpos = s;
268 cut_lists[nlists - 1].endpos = e;
269 }
270
271 /* make sure we got some cut positions out of all that */
272 if (nlists == 0)
273 bb_error_msg_and_die("missing list of positions");
274
275 /* now that the lists are parsed, we need to sort them to make life
276 * easier on us when it comes time to print the chars / fields / lines
277 */
278 qsort(cut_lists, nlists, sizeof(struct cut_list), cmpfunc);
279 }
280
313 /* argv[(optind)..(argc-1)] should be names of file to process. If no 281 /* argv[(optind)..(argc-1)] should be names of file to process. If no
314 * files were specified or '-' was specified, take input from stdin. 282 * files were specified or '-' was specified, take input from stdin.
315 * Otherwise, we process all the files specified. */ 283 * Otherwise, we process all the files specified. */
316 if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) { 284 if (argv[optind] == NULL
285 || (argv[optind][0] == '-' && argv[optind][1] == '\0')) {
317 cut_file(stdin); 286 cut_file(stdin);
318 } 287 } else {
319 else {
320 int i;
321 FILE *file; 288 FILE *file;
322 for (i = optind; i < argc; i++) { 289
323 file = bb_wfopen(argv[i], "r"); 290 for (; optind < argc; optind++) {
324 if(file) { 291 file = bb_wfopen(argv[optind], "r");
292 if (file) {
325 cut_file(file); 293 cut_file(file);
326 fclose(file); 294 fclose(file);
327 } 295 }
328 } 296 }
329 } 297 }
330 298 if (ENABLE_FEATURE_CLEAN_UP)
299 free(cut_lists);
331 return EXIT_SUCCESS; 300 return EXIT_SUCCESS;
332} 301}