[Toybox] [PATCH 1/2] Cleanup pass on cut.

Daniel K. Levy alliedenvy at gmail.com
Sat Aug 29 18:09:59 PDT 2015


Cleanup pass on cut.

Move -sbc and -dbc exclusivity checks into args parsing.
Use loopfiles instead of get_data reimplementation.
Behavioral change: parse_list now doesn't allow empty specifiers,
a zero start, or end less than start.
Minor additional cleanups.
---
 toys/posix/cut.c | 142 +++++++++++++++----------------------------------------
 1 file changed, 38 insertions(+), 104 deletions(-)

diff --git a/toys/posix/cut.c b/toys/posix/cut.c
index bb2b22d..934e27f 100644
--- a/toys/posix/cut.c
+++ b/toys/posix/cut.c
@@ -7,7 +7,7 @@
  *
  * TODO: cleanup
 
-USE_CUT(NEWTOY(cut, "b:|c:|f:|d:sn[!cbf]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_CUT(NEWTOY(cut, "b:|c:|f:|d:sn[!cbf][!dbc][!sbc]", TOYFLAG_USR|TOYFLAG_BIN))
 
 config CUT
   bool "cut"
@@ -21,7 +21,7 @@ config CUT
     -c LIST	select only these characters from LIST.
     -f LIST	select only these fields.
     -d DELIM	use DELIM instead of TAB for field delimiter.
-    -s	do not print lines not containing delimiters.
+    -s	only print lines containing delimiters.
     -n	don't split multibyte characters (Ignored).
 */
 #define FOR_cut
@@ -35,7 +35,7 @@ GLOBALS(
 
   void *slist_head;
   unsigned nelem;
-  void (*do_cut)(int fd);
+  void (*do_cut)(int, char *);
 )
 
 struct slist {
@@ -45,26 +45,24 @@ struct slist {
 
 static void add_to_list(int start, int end)
 {
-  struct slist *current, *head_ref, *temp1_node;
+  struct slist *current, *temp1_node;
 
-  head_ref = TT.slist_head;
   temp1_node = xzalloc(sizeof(struct slist));
   temp1_node->start = start;
   temp1_node->end = end;
 
   /* Special case for the head end */
-  if (!head_ref || head_ref->start >= start) { 
-      temp1_node->next = head_ref; 
-      head_ref = temp1_node;
+  if (!TT.slist_head || ((struct slist*)TT.slist_head)->start >= start) {
+    temp1_node->next = TT.slist_head;
+    TT.slist_head = temp1_node;
   } else { 
     /* Locate the node before the point of insertion */   
-    current = head_ref;   
+    current = TT.slist_head;
     while (current->next && current->next->start < temp1_node->start)
         current = current->next;
     temp1_node->next = current->next;   
     current->next = temp1_node;
   }
-  TT.slist_head = head_ref;
 }
 
 // parse list and add to slist.
@@ -75,22 +73,20 @@ static void parse_list(char *list)
     int start = 0, end = INT_MAX;
 
     if (!ctoken) break;
-    if (!*ctoken) continue;
+    if (!*ctoken) error_exit("empty position specifier");
 
     //Get start position.
-    if (*(dtoken = strsep(&ctoken, "-"))) {
-      start = atolx_range(dtoken, 0, INT_MAX);
-      start = (start?(start-1):start);
-    }
+    if (*(dtoken = strsep(&ctoken, "-")))
+      start = atolx_range(dtoken, 1, INT_MAX)-1;
 
     //Get end position.
     if (!ctoken) end = -1; //case e.g. 1,2,3
     else if (*ctoken) {//case e.g. N-M
-      end = atolx_range(ctoken, 0, INT_MAX);
-      if (!end) end = INT_MAX;
-      end--;
+      end = atolx_range(ctoken, start+1, INT_MAX)-1;
       if(end == start) end = -1;
-    }
+    } else if (!*dtoken)
+      error_exit("empty position specifier");
+
     add_to_list(start, end);
     TT.nelem++;
   }
@@ -98,49 +94,18 @@ static void parse_list(char *list)
   if (!TT.nelem) error_exit("missing positions list");
 }
 
-/*
- * retrive data from the file/s.
- */
-static void get_data(void)
-{
-  char **argv = toys.optargs; //file name.
-  toys.exitval = EXIT_SUCCESS;
-
-  if(!*argv) TT.do_cut(0); //for stdin
-  else {
-    for(; *argv; ++argv) {
-      if(strcmp(*argv, "-") == 0) TT.do_cut(0); //for stdin
-      else {
-        int fd = open(*argv, O_RDONLY, 0);
-        if(fd < 0) {//if file not present then continue with other files.
-          perror_msg("%s", *argv);
-          continue;
-        }
-        TT.do_cut(fd);
-        xclose(fd);
-      }
-    }
-  }
-}
-
 // perform cut operation on the given delimiter.
-static void do_fcut(int fd)
+static void do_fcut(int fd, char *name)
 {
-  char *buff, *pfield = 0, *delimiter = TT.delim;
+  char *buff, *pfield;
 
-  for (;;) {
-    unsigned cpos = 0;
-    int start, ndelimiters = -1;
-    int  nprinted_fields = 0;
+  while ((buff = get_line(fd))) {
+    unsigned cpos;
+    int start, ndelimiters = -1, nprinted_fields = 0;
     struct slist *temp_node = TT.slist_head;
 
-    free(pfield);
-    pfield = 0;
-
-    if (!(buff = get_line(fd))) break;
-
     //does line have any delimiter?.
-    if (strrchr(buff, (int)delimiter[0]) == NULL) {
+    if (!strchr(buff, *TT.delim)) {
       //if not then print whole line and move to next line.
       if (!(toys.optflags & FLAG_s)) xputs(buff);
       continue;
@@ -148,58 +113,49 @@ static void do_fcut(int fd)
 
     pfield = xzalloc(strlen(buff) + 1);
 
-    if (temp_node) {
       //process list on each line.
-      while (cpos < TT.nelem && buff) {
-        if (!temp_node) break;
+      for (cpos = 0; temp_node && cpos < TT.nelem && buff; cpos++) {
         start = temp_node->start;
         do {
           char *field = 0;
 
           //count number of delimeters per line.
-          while (buff) {
-            if (ndelimiters < start) {
+          while (buff && ndelimiters < start) {
               ndelimiters++;
-              field = strsep(&buff, delimiter);
-            } else break;
+              field = strsep(&buff, TT.delim);
           }
           //print field (if not yet printed).
-          if (!pfield[ndelimiters]) {
-            if (ndelimiters == start) {
+          if (!pfield[ndelimiters] && ndelimiters == start) {
               //put delimiter.
-              if (nprinted_fields++ > 0) xputc(delimiter[0]);
+              if (nprinted_fields++ > 0) xputc(*TT.delim);
               if (field) fputs(field, stdout);
               //make sure this field won't print again.
               pfield[ndelimiters] = (char) 0x23; //put some char at this position.
-            }
           }
           start++;
           if ((temp_node->end < 0) || !buff) break;          
         } while(start <= temp_node->end);
         temp_node = temp_node->next;
-        cpos++;
       }
-    }
     xputc('\n');
+    free(pfield);
   }
 }
 
 // perform cut operation char or byte.
-static void do_bccut(int fd)
+static void do_bccut(int fd, char *name)
 {
   char *buff;
 
-  while ((buff = get_line(fd)) != NULL) {
-    unsigned cpos = 0;
-    int buffln = strlen(buff);
+  while ((buff = get_line(fd))) {
+    unsigned cpos;
+    size_t buffln = strlen(buff);
     char *pfield = xzalloc(buffln + 1);
     struct slist *temp_node = TT.slist_head;
 
-    if (temp_node != NULL) {
-      while (cpos < TT.nelem) {
+      for (cpos = 0; temp_node && cpos < TT.nelem; cpos++) {
         int start;
 
-        if (!temp_node) break;
         start = temp_node->start;
         while (start < buffln) {
           //to avoid duplicate field printing.
@@ -217,24 +173,19 @@ static void do_bccut(int fd)
             break;
           }
         }
-        cpos++;
       }
       xputc('\n');
-    }
     free(pfield);
-    pfield = NULL;
   }
 }
 
 void cut_main(void)
 {
-  char delimiter = '\t'; //default delimiter.
   char *list;
 
   TT.nelem = 0;
   TT.slist_head = NULL;
 
-  //Get list and assign the function.
   if (toys.optflags & FLAG_f) {
     list = TT.flist;
     TT.do_cut = do_fcut;
@@ -247,30 +198,13 @@ void cut_main(void)
   }
 
   if (toys.optflags & FLAG_d) {
-    //delimiter must be 1 char.
-    if(TT.delim[0] && TT.delim[1])
-      perror_exit("the delimiter must be a single character");
-    delimiter = TT.delim[0];
-  }
+    if (TT.delim[0] && TT.delim[1]) perror_exit("bad -d: need one character");
+  } else TT.delim = "\t";
 
-  if(!(toys.optflags & FLAG_d) && (toys.optflags & FLAG_f)) {
-    TT.delim = xzalloc(2);
-    TT.delim[0] = delimiter;
-  }
-  
-  //when field is not specified, cutting has some special handling.
-  if (!(toys.optflags & FLAG_f)) {
-    if (toys.optflags & FLAG_s)
-      perror_exit("suppressing non-delimited lines operating on fields");
-    if (delimiter != '\t')
-      perror_exit("an input delimiter may be specified only when operating on fields");
-  }
+  if (!(toys.optflags & FLAG_f) && toys.optflags & FLAG_s)
+    perror_exit("-s needs -f");
 
   parse_list(list);
-  get_data();
-  if (!(toys.optflags & FLAG_d) && (toys.optflags & FLAG_f)) {
-    free(TT.delim);
-    TT.delim = NULL;
-  }
-  llist_traverse(TT.slist_head, free);
+  loopfiles(toys.optargs, TT.do_cut);
+  if (CFG_TOYBOX_FREE) llist_traverse(TT.slist_head, free);
 }
---




More information about the Toybox mailing list