Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/coreutils/cut.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (hide annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 7978 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

1 niro 532 /* vi: set sw=4 ts=4: */
2     /*
3     * cut.c - minimalist version of cut
4     *
5     * Copyright (C) 1999,2000,2001 by Lineo, inc.
6     * Written by Mark Whitley <markw@codepoet.org>
7     * debloated by Bernhard Fischer
8     *
9     * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
10     */
11    
12     #include "busybox.h"
13    
14     /* option vars */
15     static const char optstring[] = "b:c:f:d:sn";
16     #define CUT_OPT_BYTE_FLGS (1<<0)
17     #define CUT_OPT_CHAR_FLGS (1<<1)
18     #define CUT_OPT_FIELDS_FLGS (1<<2)
19     #define CUT_OPT_DELIM_FLGS (1<<3)
20     #define CUT_OPT_SUPPRESS_FLGS (1<<4)
21    
22     static char delim = '\t'; /* delimiter, default is tab */
23    
24     struct cut_list {
25     int startpos;
26     int endpos;
27     };
28    
29     enum {
30     BOL = 0,
31     EOL = INT_MAX,
32     NON_RANGE = -1
33     };
34    
35     /* growable array holding a series of lists */
36     static struct cut_list *cut_lists;
37     static unsigned int nlists; /* number of elements in above list */
38    
39    
40     static int cmpfunc(const void *a, const void *b)
41     {
42     return (((struct cut_list *) a)->startpos -
43     ((struct cut_list *) b)->startpos);
44    
45     }
46    
47     static void cut_file(FILE * file)
48     {
49     char *line = NULL;
50     unsigned int linenum = 0; /* keep these zero-based to be consistent */
51    
52     /* go through every line in the file */
53     while ((line = xmalloc_getline(file)) != NULL) {
54    
55     /* set up a list so we can keep track of what's been printed */
56     char * printed = xzalloc(strlen(line) * sizeof(char));
57     char * orig_line = line;
58     unsigned int cl_pos = 0;
59     int spos;
60    
61     /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */
62     if (option_mask32 & (CUT_OPT_CHAR_FLGS | CUT_OPT_BYTE_FLGS)) {
63     /* print the chars specified in each cut list */
64     for (; cl_pos < nlists; cl_pos++) {
65     spos = cut_lists[cl_pos].startpos;
66     while (spos < strlen(line)) {
67     if (!printed[spos]) {
68     printed[spos] = 'X';
69     putchar(line[spos]);
70     }
71     spos++;
72     if (spos > cut_lists[cl_pos].endpos
73     || cut_lists[cl_pos].endpos == NON_RANGE)
74     break;
75     }
76     }
77     } else if (delim == '\n') { /* cut by lines */
78     spos = cut_lists[cl_pos].startpos;
79    
80     /* get out if we have no more lists to process or if the lines
81     * are lower than what we're interested in */
82     if (linenum < spos || cl_pos >= nlists)
83     goto next_line;
84    
85     /* if the line we're looking for is lower than the one we were
86     * passed, it means we displayed it already, so move on */
87     while (spos < linenum) {
88     spos++;
89     /* go to the next list if we're at the end of this one */
90     if (spos > cut_lists[cl_pos].endpos
91     || cut_lists[cl_pos].endpos == NON_RANGE) {
92     cl_pos++;
93     /* get out if there's no more lists to process */
94     if (cl_pos >= nlists)
95     goto next_line;
96     spos = cut_lists[cl_pos].startpos;
97     /* get out if the current line is lower than the one
98     * we just became interested in */
99     if (linenum < spos)
100     goto next_line;
101     }
102     }
103    
104     /* If we made it here, it means we've found the line we're
105     * looking for, so print it */
106     puts(line);
107     goto next_line;
108     } else { /* cut by fields */
109     int ndelim = -1; /* zero-based / one-based problem */
110     int nfields_printed = 0;
111     char *field = NULL;
112     const char delimiter[2] = { delim, 0 };
113    
114     /* does this line contain any delimiters? */
115     if (strchr(line, delim) == NULL) {
116     if (!(option_mask32 & CUT_OPT_SUPPRESS_FLGS))
117     puts(line);
118     goto next_line;
119     }
120    
121     /* process each list on this line, for as long as we've got
122     * a line to process */
123     for (; cl_pos < nlists && line; cl_pos++) {
124     spos = cut_lists[cl_pos].startpos;
125     do {
126     /* find the field we're looking for */
127     while (line && ndelim < spos) {
128     field = strsep(&line, delimiter);
129     ndelim++;
130     }
131    
132     /* we found it, and it hasn't been printed yet */
133     if (field && ndelim == spos && !printed[ndelim]) {
134     /* if this isn't our first time through, we need to
135     * print the delimiter after the last field that was
136     * printed */
137     if (nfields_printed > 0)
138     putchar(delim);
139     fputs(field, stdout);
140     printed[ndelim] = 'X';
141     nfields_printed++; /* shouldn't overflow.. */
142     }
143    
144     spos++;
145    
146     /* keep going as long as we have a line to work with,
147     * this is a list, and we're not at the end of that
148     * list */
149     } while (spos <= cut_lists[cl_pos].endpos && line
150     && cut_lists[cl_pos].endpos != NON_RANGE);
151     }
152     }
153     /* if we printed anything at all, we need to finish it with a
154     * newline cuz we were handed a chomped line */
155     putchar('\n');
156     next_line:
157     linenum++;
158     free(printed);
159     free(orig_line);
160     }
161     }
162    
163     static const char _op_on_field[] = " only when operating on fields";
164    
165     int cut_main(int argc, char **argv)
166     {
167     char *sopt, *ltok;
168    
169     opt_complementary = "b--bcf:c--bcf:f--bcf";
170     getopt32(argc, argv, optstring, &sopt, &sopt, &sopt, &ltok);
171     // argc -= optind;
172     argv += optind;
173     if (!(option_mask32 & (CUT_OPT_BYTE_FLGS | CUT_OPT_CHAR_FLGS | CUT_OPT_FIELDS_FLGS)))
174     bb_error_msg_and_die("expected a list of bytes, characters, or fields");
175     if (option_mask32 & BB_GETOPT_ERROR)
176     bb_error_msg_and_die("only one type of list may be specified");
177    
178     if (option_mask32 & CUT_OPT_DELIM_FLGS) {
179     if (strlen(ltok) > 1) {
180     bb_error_msg_and_die("the delimiter must be a single character");
181     }
182     delim = ltok[0];
183     }
184    
185     /* non-field (char or byte) cutting has some special handling */
186     if (!(option_mask32 & CUT_OPT_FIELDS_FLGS)) {
187     if (option_mask32 & CUT_OPT_SUPPRESS_FLGS) {
188     bb_error_msg_and_die
189     ("suppressing non-delimited lines makes sense%s",
190     _op_on_field);
191     }
192     if (delim != '\t') {
193     bb_error_msg_and_die
194     ("a delimiter may be specified%s", _op_on_field);
195     }
196     }
197    
198     /*
199     * parse list and put values into startpos and endpos.
200     * valid list formats: N, N-, N-M, -M
201     * more than one list can be separated by commas
202     */
203     {
204     char *ntok;
205     int s = 0, e = 0;
206    
207     /* take apart the lists, one by one (they are separated with commas */
208     while ((ltok = strsep(&sopt, ",")) != NULL) {
209    
210     /* it's actually legal to pass an empty list */
211     if (strlen(ltok) == 0)
212     continue;
213    
214     /* get the start pos */
215     ntok = strsep(&ltok, "-");
216     if (ntok == NULL) {
217     bb_error_msg
218     ("internal error: ntok is null for start pos!?\n");
219     } else if (strlen(ntok) == 0) {
220     s = BOL;
221     } else {
222     s = xatoi_u(ntok);
223     /* account for the fact that arrays are zero based, while
224     * the user expects the first char on the line to be char #1 */
225     if (s != 0)
226     s--;
227     }
228    
229     /* get the end pos */
230     ntok = strsep(&ltok, "-");
231     if (ntok == NULL) {
232     e = NON_RANGE;
233     } else if (strlen(ntok) == 0) {
234     e = EOL;
235     } else {
236     e = xatoi_u(ntok);
237     /* if the user specified and end position of 0, that means "til the
238     * end of the line */
239     if (e == 0)
240     e = EOL;
241     e--; /* again, arrays are zero based, lines are 1 based */
242     if (e == s)
243     e = NON_RANGE;
244     }
245    
246     /* if there's something left to tokenize, the user passed
247     * an invalid list */
248     if (ltok)
249     bb_error_msg_and_die("invalid byte or field list");
250    
251     /* add the new list */
252     cut_lists = xrealloc(cut_lists, sizeof(struct cut_list) * (++nlists));
253     cut_lists[nlists-1].startpos = s;
254     cut_lists[nlists-1].endpos = e;
255     }
256    
257     /* make sure we got some cut positions out of all that */
258     if (nlists == 0)
259     bb_error_msg_and_die("missing list of positions");
260    
261     /* now that the lists are parsed, we need to sort them to make life
262     * easier on us when it comes time to print the chars / fields / lines
263     */
264     qsort(cut_lists, nlists, sizeof(struct cut_list), cmpfunc);
265     }
266    
267     /* argv[0..argc-1] should be names of file to process. If no
268     * files were specified or '-' was specified, take input from stdin.
269     * Otherwise, we process all the files specified. */
270     if (argv[0] == NULL || LONE_DASH(argv[0])) {
271     cut_file(stdin);
272     } else {
273     FILE *file;
274    
275     do {
276     file = fopen_or_warn(argv[0], "r");
277     if (file) {
278     cut_file(file);
279     fclose(file);
280     }
281     } while (*++argv);
282     }
283     if (ENABLE_FEATURE_CLEAN_UP)
284     free(cut_lists);
285     return EXIT_SUCCESS;
286     }