diff options
-rw-r--r-- | editors/sed.c | 90 |
1 files changed, 63 insertions, 27 deletions
diff --git a/editors/sed.c b/editors/sed.c index 1673ee2d4..1e2191864 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -119,8 +119,11 @@ typedef struct sed_cmd_s { /* linked list of sed commands */ static sed_cmd_t sed_cmd_head; static sed_cmd_t *sed_cmd_tail = &sed_cmd_head; +static sed_cmd_t *block_cmd; +static int in_block = 0; const char * const semicolon_whitespace = "; \n\r\t\v\0"; +static regex_t *previous_regex_ptr = NULL; #ifdef CONFIG_FEATURE_CLEAN_UP static void destroy_cmd_strs(void) @@ -245,6 +248,7 @@ static int get_address(char *my_str, int *linenum, regex_t **regex) bb_error_msg_and_die("unterminated match expression"); } my_str[idx] = '\0'; + *regex = (regex_t *)xmalloc(sizeof(regex_t)); xregcomp(*regex, my_str+idx_start, REG_NEWLINE); idx++; /* so it points to the next character after the last '/' */ @@ -305,8 +309,11 @@ static int parse_subst_cmd(sed_cmd_t * const sed_cmd, const char *substr) out: /* compile the match string into a regex */ - sed_cmd->sub_match = (regex_t *)xmalloc(sizeof(regex_t)); - xregcomp(sed_cmd->sub_match, match, cflags); + if (*match != '\0') { + /* If match is empty, we use last regex used at runtime */ + sed_cmd->sub_match = (regex_t *)xmalloc(sizeof(regex_t)); + xregcomp(sed_cmd->sub_match, match, cflags); + } free(match); return idx; @@ -493,8 +500,19 @@ static char *add_cmd(sed_cmd_t *sed_cmd, char *cmdstr) /* if this is a comment, jump past it and keep going */ if (*cmdstr == '#') { + /* "#n" is the same as using -n on the command line */ + if (cmdstr[1] == 'n') { + be_quiet++; + } return(strpbrk(cmdstr, "\n\r")); } + + /* Test for end of block */ + if (*cmdstr == '}') { + in_block = 0; + cmdstr++; + return(cmdstr); + } /* parse the command * format is: [addr][,addr]cmd @@ -548,32 +566,34 @@ static char *add_cmd(sed_cmd_t *sed_cmd, char *cmdstr) if (*cmdstr == '\0') bb_error_msg_and_die("missing command"); + /* This is the start of a block of commands */ + if (*cmdstr == '{') { + if (in_block != 0) { + bb_error_msg_and_die("cant handle sub-blocks"); + } + in_block = 1; + block_cmd = sed_cmd; + + return(cmdstr + 1); + } + sed_cmd->cmd = *cmdstr; cmdstr++; - if (sed_cmd->cmd == '{') { - do { - sed_cmd_t *sed_cmd_new; - char *end_ptr = strpbrk(cmdstr, ";}"); - - *end_ptr = '\0'; - sed_cmd_new = xcalloc(1, sizeof(sed_cmd_t)); - sed_cmd_new->beg_match = sed_cmd->beg_match; - sed_cmd_new->end_match = sed_cmd->end_match; - sed_cmd_new->beg_line = sed_cmd->beg_line; - sed_cmd_new->end_line = sed_cmd->end_line; - sed_cmd_new->invert = sed_cmd->invert; - - add_cmd(sed_cmd_new, cmdstr); - cmdstr = end_ptr + 1; - } while (*cmdstr != '\0'); - } else { - cmdstr = parse_cmd_str(sed_cmd, cmdstr); - - /* Add the command to the command array */ - sed_cmd_tail->linear = sed_cmd; - sed_cmd_tail = sed_cmd_tail->linear; + if (in_block == 1) { + sed_cmd->beg_match = block_cmd->beg_match; + sed_cmd->end_match = block_cmd->end_match; + sed_cmd->beg_line = block_cmd->beg_line; + sed_cmd->end_line = block_cmd->end_line; + sed_cmd->invert = block_cmd->invert; } + + cmdstr = parse_cmd_str(sed_cmd, cmdstr); + + /* Add the command to the command array */ + sed_cmd_tail->linear = sed_cmd; + sed_cmd_tail = sed_cmd_tail->linear; + return(cmdstr); } @@ -700,17 +720,27 @@ static void print_subst_w_backrefs(const char *line, const char *replace, } } -static int do_subst_command(const sed_cmd_t *sed_cmd, char **line) +static int do_subst_command(sed_cmd_t *sed_cmd, char **line) { char *hackline = *line; struct pipeline thepipe = { NULL, 0 , 0}; struct pipeline *const pipeline = &thepipe; int altered = 0; + int result; regmatch_t *regmatch = NULL; + regex_t *current_regex; + + if (sed_cmd->sub_match == NULL) { + current_regex = previous_regex_ptr; + } else { + previous_regex_ptr = current_regex = sed_cmd->sub_match; + } + result = regexec(current_regex, hackline, 0, NULL, 0); /* we only proceed if the substitution 'search' expression matches */ - if (regexec(sed_cmd->sub_match, hackline, 0, NULL, 0) == REG_NOMATCH) + if (result == REG_NOMATCH) { return 0; + } /* whaddaya know, it matched. get the number of back references */ regmatch = xmalloc(sizeof(regmatch_t) * (sed_cmd->num_backrefs+1)); @@ -724,7 +754,7 @@ static int do_subst_command(const sed_cmd_t *sed_cmd, char **line) /* and now, as long as we've got a line to try matching and if we can match * the search string, we make substitutions */ - while ((*hackline || !altered) && (regexec(sed_cmd->sub_match, hackline, + while ((*hackline || !altered) && (regexec(current_regex, hackline, sed_cmd->num_backrefs+1, regmatch, 0) != REG_NOMATCH) ) { int i; @@ -818,6 +848,10 @@ static void process_file(FILE *file) ); if (sed_cmd->invert ^ matched) { + /* Update last used regex incase a blank substitute BRE is found */ + if (sed_cmd->beg_match) { + previous_regex_ptr = sed_cmd->beg_match; + } /* * actual sedding @@ -999,6 +1033,8 @@ static void process_file(FILE *file) if ( /* this is a single-address command or... */ (sed_cmd->end_line == 0 && sed_cmd->end_match == NULL) || ( + /* If only one address */ + /* we were in the middle of our address range (this * isn't the first time through) and.. */ (still_in_range == 1) && ( |