A missing securetty file is not an error.
[oweals/busybox.git] / editors / sed.c
index 31b9de0556046a954cab688db5891dc8aee97273..23e9d545bd47dfe48b16e96a384c1b79658036b1 100644 (file)
@@ -96,6 +96,9 @@ struct sed_cmd {
 
        /* the command */
        char cmd; /* p,d,s (add more at your leisure :-) */
+
+       /* inversion flag */
+       int invert;         /* the '!' after the address */ 
 };
 
 /* globals */
@@ -175,7 +178,7 @@ static int index_of_next_unescaped_regexp_delim(const struct sed_cmd * const sed
 static int get_address(struct sed_cmd *sed_cmd, const char *str, int *linenum, regex_t **regex)
 {
        char *my_str = xstrdup(str);
-       int idx = 0;
+       int idx = 0, idx_start = 1;
        char olddelimiter;
        olddelimiter = sed_cmd->delimiter;
        sed_cmd->delimiter = '/';
@@ -191,13 +194,17 @@ static int get_address(struct sed_cmd *sed_cmd, const char *str, int *linenum, r
                *linenum = -1;
                idx++;
        }
-       else if (my_str[idx] == '/') {
+       else if (my_str[idx] == '/' || my_str[idx] == '\\') {
+               if (my_str[idx] == '\\') {
+                       idx_start++;
+                       sed_cmd-> delimiter = my_str[++idx];
+               }
                idx = index_of_next_unescaped_regexp_delim(sed_cmd, my_str, ++idx);
                if (idx == -1)
                        error_msg_and_die("unterminated match expression");
                my_str[idx] = '\0';
                *regex = (regex_t *)xmalloc(sizeof(regex_t));
-               xregcomp(*regex, my_str+1, REG_NEWLINE);
+               xregcomp(*regex, my_str+idx_start, REG_NEWLINE);
                idx++; /* so it points to the next character after the last '/' */
        }
        else {
@@ -394,17 +401,30 @@ static char *parse_cmd_str(struct sed_cmd * const sed_cmd, const char *const cmd
         */
 
        /* first part (if present) is an address: either a number or a /regex/ */
-       if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/')
+       if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/' || ( cmdstr[idx] == '\\' && cmdstr[idx+1] != '\\'))
                idx = get_address(sed_cmd, cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match);
 
        /* second part (if present) will begin with a comma */
-       if (cmdstr[idx] == ',')
-               idx += get_address(sed_cmd, &cmdstr[++idx], &sed_cmd->end_line, &sed_cmd->end_match);
+       if (cmdstr[idx] == ',') {
+               idx++;
+               idx += get_address(sed_cmd, &cmdstr[idx], &sed_cmd->end_line, &sed_cmd->end_match);
+       }
 
        /* skip whitespace before the command */
        while (isspace(cmdstr[idx]))
                idx++;
 
+       /* there my be the inversion flag between part2 and part3 */
+       sed_cmd->invert = 0;
+       if (cmdstr[idx] == '!') {
+               sed_cmd->invert = 1;
+               idx++;
+
+               /* skip whitespace before the command */
+               while (isspace(cmdstr[idx]))
+                       idx++;
+       }
+
        /* last part (mandatory) will be a command */
        if (cmdstr[idx] == '\0')
                error_msg_and_die("missing command");
@@ -642,12 +662,12 @@ static void process_file(FILE *file)
                /* for every line, go through all the commands */
                for (i = 0; i < ncmds; i++) {
                        struct sed_cmd *sed_cmd = &sed_cmds[i];
-
+                       int deleted = 0;
 
                        /*
                         * entry point into sedding...
                         */
-                       if (
+                       int matched = (
                                        /* no range necessary */
                                        (sed_cmd->beg_line == 0 && sed_cmd->end_line == 0 &&
                                         sed_cmd->beg_match == NULL &&
@@ -658,7 +678,9 @@ static void process_file(FILE *file)
                                        (sed_cmd->beg_match && (regexec(sed_cmd->beg_match, line, 0, NULL, 0) == 0)) ||
                                        /* we are currently within the beginning & ending address range */
                                        still_in_range
-                          ) {
+                          );
+
+                       if (sed_cmd->invert ^ matched) {
 
                                /*
                                 * actual sedding
@@ -671,6 +693,7 @@ static void process_file(FILE *file)
 
                                        case 'd':
                                                altered++;
+                                               deleted = 1;
                                                break;
 
                                        case 's':
@@ -744,13 +767,15 @@ static void process_file(FILE *file)
                                                                  /* else if we couldn't open the output file,
                                                                   * no biggie, just don't print anything */
                                                                  altered++;
-                                                         }
+                                                 }
                                                          break;
                                }
+                       }
 
-                               /*
-                                * exit point from sedding...
-                                */
+                       /*
+                        * exit point from sedding...
+                        */
+                       if (matched) {
                                if (
                                        /* this is a single-address command or... */
                                        (sed_cmd->end_line == 0 && sed_cmd->end_match == NULL) || (
@@ -773,6 +798,9 @@ static void process_file(FILE *file)
                                        still_in_range = 1;
                                }
                        }
+
+                       if (deleted)
+                               break;
                }
 
                /* we will print the line unless we were told to be quiet or if the