Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 815 by niro, Sat Sep 1 22:45:15 2007 UTC revision 816 by niro, Fri Apr 24 18:33:46 2009 UTC
# Line 4  Line 4 
4   *   *
5   * Copyright (C) 1999,2000,2001 by Lineo, inc.   * Copyright (C) 1999,2000,2001 by Lineo, inc.
6   * Written by Mark Whitley <markw@codepoet.org>   * Written by Mark Whitley <markw@codepoet.org>
7   * debloated by Bernhard Fischer   * debloated by Bernhard Reutner-Fischer
8   *   *
9   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
10   */   */
11    
12  #include "busybox.h"  #include "libbb.h"
13    
14    /* This is a NOEXEC applet. Be very careful! */
15    
 /* option vars */  
 static const char optstring[] = "b:c:f:d:sn";  
 #define CUT_OPT_BYTE_FLGS (1<<0)  
 #define CUT_OPT_CHAR_FLGS (1<<1)  
 #define CUT_OPT_FIELDS_FLGS (1<<2)  
 #define CUT_OPT_DELIM_FLGS (1<<3)  
 #define CUT_OPT_SUPPRESS_FLGS (1<<4)  
16    
17  static char delim = '\t'; /* delimiter, default is tab */  /* option vars */
18    static const char optstring[] ALIGN1 = "b:c:f:d:sn";
19    #define CUT_OPT_BYTE_FLGS     (1 << 0)
20    #define CUT_OPT_CHAR_FLGS     (1 << 1)
21    #define CUT_OPT_FIELDS_FLGS   (1 << 2)
22    #define CUT_OPT_DELIM_FLGS    (1 << 3)
23    #define CUT_OPT_SUPPRESS_FLGS (1 << 4)
24    
25  struct cut_list {  struct cut_list {
26   int startpos;   int startpos;
# Line 32  enum { Line 33  enum {
33   NON_RANGE = -1   NON_RANGE = -1
34  };  };
35    
 /* growable array holding a series of lists */  
 static struct cut_list *cut_lists;  
 static unsigned int nlists; /* number of elements in above list */  
   
   
36  static int cmpfunc(const void *a, const void *b)  static int cmpfunc(const void *a, const void *b)
37  {  {
38   return (((struct cut_list *) a)->startpos -   return (((struct cut_list *) a)->startpos -
# Line 44  static int cmpfunc(const void *a, const Line 40  static int cmpfunc(const void *a, const
40    
41  }  }
42    
43  static void cut_file(FILE * file)  static void cut_file(FILE *file, char delim, const struct cut_list *cut_lists, unsigned nlists)
44  {  {
45   char *line = NULL;   char *line;
46   unsigned int linenum = 0; /* keep these zero-based to be consistent */   unsigned linenum = 0; /* keep these zero-based to be consistent */
47    
48   /* go through every line in the file */   /* go through every line in the file */
49   while ((line = xmalloc_getline(file)) != NULL) {   while ((line = xmalloc_fgetline(file)) != NULL) {
50    
51   /* set up a list so we can keep track of what's been printed */   /* set up a list so we can keep track of what's been printed */
52   char * printed = xzalloc(strlen(line) * sizeof(char));   int linelen = strlen(line);
53   char * orig_line = line;   char *printed = xzalloc(linelen + 1);
54   unsigned int cl_pos = 0;   char *orig_line = line;
55     unsigned cl_pos = 0;
56   int spos;   int spos;
57    
58   /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */   /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */
# Line 63  static void cut_file(FILE * file) Line 60  static void cut_file(FILE * file)
60   /* print the chars specified in each cut list */   /* print the chars specified in each cut list */
61   for (; cl_pos < nlists; cl_pos++) {   for (; cl_pos < nlists; cl_pos++) {
62   spos = cut_lists[cl_pos].startpos;   spos = cut_lists[cl_pos].startpos;
63   while (spos < strlen(line)) {   while (spos < linelen) {
64   if (!printed[spos]) {   if (!printed[spos]) {
65   printed[spos] = 'X';   printed[spos] = 'X';
66   putchar(line[spos]);   putchar(line[spos]);
67   }   }
68   spos++;   spos++;
69   if (spos > cut_lists[cl_pos].endpos   if (spos > cut_lists[cl_pos].endpos
70   || cut_lists[cl_pos].endpos == NON_RANGE)   /* NON_RANGE is -1, so if below is true,
71     * the above was true too (spos is >= 0) */
72     /* || cut_lists[cl_pos].endpos == NON_RANGE */
73     ) {
74   break;   break;
75     }
76   }   }
77   }   }
78   } else if (delim == '\n') { /* cut by lines */   } else if (delim == '\n') { /* cut by lines */
# Line 79  static void cut_file(FILE * file) Line 80  static void cut_file(FILE * file)
80    
81   /* get out if we have no more lists to process or if the lines   /* get out if we have no more lists to process or if the lines
82   * are lower than what we're interested in */   * are lower than what we're interested in */
83   if (linenum < spos || cl_pos >= nlists)   if (((int)linenum < spos) || (cl_pos >= nlists))
84   goto next_line;   goto next_line;
85    
86   /* if the line we're looking for is lower than the one we were   /* if the line we're looking for is lower than the one we were
87   * passed, it means we displayed it already, so move on */   * passed, it means we displayed it already, so move on */
88   while (spos < linenum) {   while (spos < (int)linenum) {
89   spos++;   spos++;
90   /* go to the next list if we're at the end of this one */   /* go to the next list if we're at the end of this one */
91   if (spos > cut_lists[cl_pos].endpos   if (spos > cut_lists[cl_pos].endpos
92   || cut_lists[cl_pos].endpos == NON_RANGE) {   || cut_lists[cl_pos].endpos == NON_RANGE
93     ) {
94   cl_pos++;   cl_pos++;
95   /* get out if there's no more lists to process */   /* get out if there's no more lists to process */
96   if (cl_pos >= nlists)   if (cl_pos >= nlists)
# Line 96  static void cut_file(FILE * file) Line 98  static void cut_file(FILE * file)
98   spos = cut_lists[cl_pos].startpos;   spos = cut_lists[cl_pos].startpos;
99   /* get out if the current line is lower than the one   /* get out if the current line is lower than the one
100   * we just became interested in */   * we just became interested in */
101   if (linenum < spos)   if ((int)linenum < spos)
102   goto next_line;   goto next_line;
103   }   }
104   }   }
# Line 147  static void cut_file(FILE * file) Line 149  static void cut_file(FILE * file)
149   * this is a list, and we're not at the end of that   * this is a list, and we're not at the end of that
150   * list */   * list */
151   } while (spos <= cut_lists[cl_pos].endpos && line   } while (spos <= cut_lists[cl_pos].endpos && line
152   && cut_lists[cl_pos].endpos != NON_RANGE);   && cut_lists[cl_pos].endpos != NON_RANGE);
153   }   }
154   }   }
155   /* if we printed anything at all, we need to finish it with a   /* if we printed anything at all, we need to finish it with a
# Line 160  static void cut_file(FILE * file) Line 162  static void cut_file(FILE * file)
162   }   }
163  }  }
164    
165  static const char _op_on_field[] = " only when operating on fields";  int cut_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
166    int cut_main(int argc UNUSED_PARAM, char **argv)
 int cut_main(int argc, char **argv)  
167  {  {
168     /* growable array holding a series of lists */
169     struct cut_list *cut_lists = NULL;
170     unsigned nlists = 0; /* number of elements in above list */
171     char delim = '\t'; /* delimiter, default is tab */
172   char *sopt, *ltok;   char *sopt, *ltok;
173     unsigned opt;
174    
175   opt_complementary = "b--bcf:c--bcf:f--bcf";   opt_complementary = "b--bcf:c--bcf:f--bcf";
176   getopt32(argc, argv, optstring, &sopt, &sopt, &sopt, &ltok);   opt = getopt32(argv, optstring, &sopt, &sopt, &sopt, &ltok);
177  // argc -= optind;  // argc -= optind;
178   argv += optind;   argv += optind;
179   if (!(option_mask32 & (CUT_OPT_BYTE_FLGS | CUT_OPT_CHAR_FLGS | CUT_OPT_FIELDS_FLGS)))   if (!(opt & (CUT_OPT_BYTE_FLGS | CUT_OPT_CHAR_FLGS | CUT_OPT_FIELDS_FLGS)))
180   bb_error_msg_and_die("expected a list of bytes, characters, or fields");   bb_error_msg_and_die("expected a list of bytes, characters, or fields");
  if (option_mask32 & BB_GETOPT_ERROR)  
  bb_error_msg_and_die("only one type of list may be specified");  
181    
182   if (option_mask32 & CUT_OPT_DELIM_FLGS) {   if (opt & CUT_OPT_DELIM_FLGS) {
183   if (strlen(ltok) > 1) {   if (ltok[0] && ltok[1]) { /* more than 1 char? */
184   bb_error_msg_and_die("the delimiter must be a single character");   bb_error_msg_and_die("the delimiter must be a single character");
185   }   }
186   delim = ltok[0];   delim = ltok[0];
187   }   }
188    
189   /*  non-field (char or byte) cutting has some special handling */   /*  non-field (char or byte) cutting has some special handling */
190   if (!(option_mask32 & CUT_OPT_FIELDS_FLGS)) {   if (!(opt & CUT_OPT_FIELDS_FLGS)) {
191   if (option_mask32 & CUT_OPT_SUPPRESS_FLGS) {   static const char _op_on_field[] ALIGN1 = " only when operating on fields";
192    
193     if (opt & CUT_OPT_SUPPRESS_FLGS) {
194   bb_error_msg_and_die   bb_error_msg_and_die
195   ("suppressing non-delimited lines makes sense%s",   ("suppressing non-delimited lines makes sense%s",
196   _op_on_field);   _op_on_field);
# Line 204  int cut_main(int argc, char **argv) Line 210  int cut_main(int argc, char **argv)
210   char *ntok;   char *ntok;
211   int s = 0, e = 0;   int s = 0, e = 0;
212    
213   /* take apart the lists, one by one (they are separated with commas */   /* take apart the lists, one by one (they are separated with commas) */
214   while ((ltok = strsep(&sopt, ",")) != NULL) {   while ((ltok = strsep(&sopt, ",")) != NULL) {
215    
216   /* it's actually legal to pass an empty list */   /* it's actually legal to pass an empty list */
217   if (strlen(ltok) == 0)   if (!ltok[0])
218   continue;   continue;
219    
220   /* get the start pos */   /* get the start pos */
221   ntok = strsep(&ltok, "-");   ntok = strsep(&ltok, "-");
222   if (ntok == NULL) {   if (!ntok[0]) {
  bb_error_msg  
  ("internal error: ntok is null for start pos!?\n");  
  } else if (strlen(ntok) == 0) {  
223   s = BOL;   s = BOL;
224   } else {   } else {
225   s = xatoi_u(ntok);   s = xatoi_u(ntok);
# Line 227  int cut_main(int argc, char **argv) Line 230  int cut_main(int argc, char **argv)
230   }   }
231    
232   /* get the end pos */   /* get the end pos */
233   ntok = strsep(&ltok, "-");   if (ltok == NULL) {
  if (ntok == NULL) {  
234   e = NON_RANGE;   e = NON_RANGE;
235   } else if (strlen(ntok) == 0) {   } else if (!ltok[0]) {
236   e = EOL;   e = EOL;
237   } else {   } else {
238   e = xatoi_u(ntok);   e = xatoi_u(ltok);
239   /* if the user specified and end position of 0, that means "til the   /* if the user specified and end position of 0,
240   * end of the line */   * that means "til the end of the line" */
241   if (e == 0)   if (e == 0)
242   e = EOL;   e = EOL;
243   e--; /* again, arrays are zero based, lines are 1 based */   e--; /* again, arrays are zero based, lines are 1 based */
# Line 243  int cut_main(int argc, char **argv) Line 245  int cut_main(int argc, char **argv)
245   e = NON_RANGE;   e = NON_RANGE;
246   }   }
247    
  /* if there's something left to tokenize, the user passed  
  * an invalid list */  
  if (ltok)  
  bb_error_msg_and_die("invalid byte or field list");  
   
248   /* add the new list */   /* add the new list */
249   cut_lists = xrealloc(cut_lists, sizeof(struct cut_list) * (++nlists));   cut_lists = xrealloc_vector(cut_lists, 4, nlists);
250   cut_lists[nlists-1].startpos = s;   /* NB: startpos is always >= 0,
251   cut_lists[nlists-1].endpos = e;   * while endpos may be = NON_RANGE (-1) */
252     cut_lists[nlists].startpos = s;
253     cut_lists[nlists].endpos = e;
254     nlists++;
255   }   }
256    
257   /* make sure we got some cut positions out of all that */   /* make sure we got some cut positions out of all that */
# Line 264  int cut_main(int argc, char **argv) Line 264  int cut_main(int argc, char **argv)
264   qsort(cut_lists, nlists, sizeof(struct cut_list), cmpfunc);   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.   int retval = EXIT_SUCCESS;
269   * Otherwise, we process all the files specified. */  
270   if (argv[0] == NULL || LONE_DASH(argv[0])) {   if (!*argv)
271   cut_file(stdin);   *--argv = (char *)"-";
  } else {  
  FILE *file;  
272    
273   do {   do {
274   file = fopen_or_warn(argv[0], "r");   FILE *file = fopen_or_warn_stdin(*argv);
275   if (file) {   if (!file) {
276   cut_file(file);   retval = EXIT_FAILURE;
277   fclose(file);   continue;
278   }   }
279     cut_file(file, delim, cut_lists, nlists);
280     fclose_if_not_stdin(file);
281   } while (*++argv);   } while (*++argv);
282    
283     if (ENABLE_FEATURE_CLEAN_UP)
284     free(cut_lists);
285     fflush_stdout_and_exit(retval);
286   }   }
  if (ENABLE_FEATURE_CLEAN_UP)  
  free(cut_lists);  
  return EXIT_SUCCESS;  
287  }  }

Legend:
Removed from v.815  
changed lines
  Added in v.816