unexpand: fix incorrect expansion, add test for it
[oweals/busybox.git] / coreutils / cut.c
index 1634fc8c8e080bb05c87bd5fd107118d55c17db1..9cc22be16ef1773c293023a699c87d5ae5f7fa65 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright (C) 1999,2000,2001 by Lineo, inc.
  * Written by Mark Whitley <markw@codepoet.org>
- * debloated by Bernhard Fischer
+ * debloated by Bernhard Reutner-Fischer
  *
  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  */
@@ -33,11 +33,6 @@ enum {
        NON_RANGE = -1
 };
 
-/* growable array holding a series of lists */
-static struct cut_list *cut_lists;
-static unsigned int nlists;    /* number of elements in above list */
-
-
 static int cmpfunc(const void *a, const void *b)
 {
        return (((struct cut_list *) a)->startpos -
@@ -45,18 +40,19 @@ static int cmpfunc(const void *a, const void *b)
 
 }
 
-static void cut_file(FILE *file, char delim)
+static void cut_file(FILE *file, char delim, const struct cut_list *cut_lists, unsigned nlists)
 {
-       char *line = NULL;
-       unsigned int linenum = 0;       /* keep these zero-based to be consistent */
+       char *line;
+       unsigned linenum = 0;   /* keep these zero-based to be consistent */
 
        /* go through every line in the file */
        while ((line = xmalloc_fgetline(file)) != NULL) {
 
                /* set up a list so we can keep track of what's been printed */
-               char * printed = xzalloc(strlen(line) * sizeof(char));
-               char * orig_line = line;
-               unsigned int cl_pos = 0;
+               int linelen = strlen(line);
+               char *printed = xzalloc(linelen + 1);
+               char *orig_line = line;
+               unsigned cl_pos = 0;
                int spos;
 
                /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */
@@ -64,15 +60,19 @@ static void cut_file(FILE *file, char delim)
                        /* print the chars specified in each cut list */
                        for (; cl_pos < nlists; cl_pos++) {
                                spos = cut_lists[cl_pos].startpos;
-                               while (spos < (int)strlen(line)) {
+                               while (spos < linelen) {
                                        if (!printed[spos]) {
                                                printed[spos] = 'X';
                                                putchar(line[spos]);
                                        }
                                        spos++;
                                        if (spos > cut_lists[cl_pos].endpos
-                                               || cut_lists[cl_pos].endpos == NON_RANGE)
+                                       /* NON_RANGE is -1, so if below is true,
+                                        * the above was true too (spos is >= 0) */
+                                       /* || cut_lists[cl_pos].endpos == NON_RANGE */
+                                       ) {
                                                break;
+                                       }
                                }
                        }
                } else if (delim == '\n') {     /* cut by lines */
@@ -89,7 +89,8 @@ static void cut_file(FILE *file, char delim)
                                spos++;
                                /* go to the next list if we're at the end of this one */
                                if (spos > cut_lists[cl_pos].endpos
-                                       || cut_lists[cl_pos].endpos == NON_RANGE) {
+                                || cut_lists[cl_pos].endpos == NON_RANGE
+                               ) {
                                        cl_pos++;
                                        /* get out if there's no more lists to process */
                                        if (cl_pos >= nlists)
@@ -148,7 +149,7 @@ static void cut_file(FILE *file, char delim)
                                         * this is a list, and we're not at the end of that
                                         * list */
                                } while (spos <= cut_lists[cl_pos].endpos && line
-                                                && cut_lists[cl_pos].endpos != NON_RANGE);
+                                               && cut_lists[cl_pos].endpos != NON_RANGE);
                        }
                }
                /* if we printed anything at all, we need to finish it with a
@@ -162,19 +163,23 @@ static void cut_file(FILE *file, char delim)
 }
 
 int cut_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int cut_main(int argc ATTRIBUTE_UNUSED, char **argv)
+int cut_main(int argc UNUSED_PARAM, char **argv)
 {
+       /* growable array holding a series of lists */
+       struct cut_list *cut_lists = NULL;
+       unsigned nlists = 0;    /* number of elements in above list */
        char delim = '\t';      /* delimiter, default is tab */
        char *sopt, *ltok;
+       unsigned opt;
 
        opt_complementary = "b--bcf:c--bcf:f--bcf";
-       getopt32(argv, optstring, &sopt, &sopt, &sopt, &ltok);
+       opt = getopt32(argv, optstring, &sopt, &sopt, &sopt, &ltok);
 //     argc -= optind;
        argv += optind;
-       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)))
                bb_error_msg_and_die("expected a list of bytes, characters, or fields");
 
-       if (option_mask32 & CUT_OPT_DELIM_FLGS) {
+       if (opt & CUT_OPT_DELIM_FLGS) {
                if (ltok[0] && ltok[1]) { /* more than 1 char? */
                        bb_error_msg_and_die("the delimiter must be a single character");
                }
@@ -182,10 +187,10 @@ int cut_main(int argc ATTRIBUTE_UNUSED, char **argv)
        }
 
        /*  non-field (char or byte) cutting has some special handling */
-       if (!(option_mask32 & CUT_OPT_FIELDS_FLGS)) {
+       if (!(opt & CUT_OPT_FIELDS_FLGS)) {
                static const char _op_on_field[] ALIGN1 = " only when operating on fields";
 
-               if (option_mask32 & CUT_OPT_SUPPRESS_FLGS) {
+               if (opt & CUT_OPT_SUPPRESS_FLGS) {
                        bb_error_msg_and_die
                                ("suppressing non-delimited lines makes sense%s",
                                 _op_on_field);
@@ -231,8 +236,8 @@ int cut_main(int argc ATTRIBUTE_UNUSED, char **argv)
                                e = EOL;
                        } else {
                                e = xatoi_u(ltok);
-                               /* if the user specified and end position of 0, that means "til the
-                                * end of the line */
+                               /* if the user specified and end position of 0,
+                                * that means "til the end of the line" */
                                if (e == 0)
                                        e = EOL;
                                e--;    /* again, arrays are zero based, lines are 1 based */
@@ -241,9 +246,12 @@ int cut_main(int argc ATTRIBUTE_UNUSED, char **argv)
                        }
 
                        /* add the new list */
-                       cut_lists = xrealloc(cut_lists, sizeof(struct cut_list) * (++nlists));
-                       cut_lists[nlists-1].startpos = s;
-                       cut_lists[nlists-1].endpos = e;
+                       cut_lists = xrealloc_vector(cut_lists, 4, nlists);
+                       /* NB: startpos is always >= 0,
+                        * while endpos may be = NON_RANGE (-1) */
+                       cut_lists[nlists].startpos = s;
+                       cut_lists[nlists].endpos = e;
+                       nlists++;
                }
 
                /* make sure we got some cut positions out of all that */
@@ -268,7 +276,7 @@ int cut_main(int argc ATTRIBUTE_UNUSED, char **argv)
                                retval = EXIT_FAILURE;
                                continue;
                        }
-                       cut_file(file, delim);
+                       cut_file(file, delim, cut_lists, nlists);
                        fclose_if_not_stdin(file);
                } while (*++argv);