static void do_subst_w_backrefs(const char *line, const char *replace) { int i,j; /* go through the replacement string */ for (i = 0; replace[i]; i++) { /* if we find a backreference (\1, \2, etc.) print the backref'ed * text */ if (replace[i] == '\\' && replace[i+1]>'0' && replace[i+1]<='9') { int backref=replace[++i]-'0'; /* print out the text held in regmatch[backref] */ if(regmatch[backref].rm_so != -1) for (j = regmatch[backref].rm_so; j < regmatch[backref].rm_eo; j++) pipe_putc(line[j]); } /* if we find a backslash escaped character, print the character */ else if (replace[i] == '\\') pipe_putc(replace[++i]); /* if we find an unescaped '&' print out the whole matched text. */ else if (replace[i] == '&') for (j = regmatch[0].rm_so; j < regmatch[0].rm_eo; j++) pipe_putc(line[j]); /* Otherwise just output the character. */ else pipe_putc(replace[i]); } }
size_t pipe_write(struct robject *self, rp_t source, uint8_t *buffer, size_t size, off_t offset) { struct pipe *pipe; size_t i; pipe = robject_data(self, "pipe"); for (i = 0; i < size; i++) { pipe_putc(pipe, buffer[i]); } return size; }
static void do_subst_w_backrefs(char *line, char *replace) { int i, j; /* go through the replacement string */ for (i = 0; replace[i]; i++) { /* if we find a backreference (\1, \2, etc.) print the backref'ed text */ if (replace[i] == '\\') { unsigned backref = replace[++i] - '0'; if (backref <= 9) { /* print out the text held in G.regmatch[backref] */ if (G.regmatch[backref].rm_so != -1) { j = G.regmatch[backref].rm_so; while (j < G.regmatch[backref].rm_eo) pipe_putc(line[j++]); } continue; } /* I _think_ it is impossible to get '\' to be * the last char in replace string. Thus we don't check * for replace[i] == NUL. (counterexample anyone?) */ /* if we find a backslash escaped character, print the character */ pipe_putc(replace[i]); continue; } /* if we find an unescaped '&' print out the whole matched text. */ if (replace[i] == '&') { j = G.regmatch[0].rm_so; while (j < G.regmatch[0].rm_eo) pipe_putc(line[j++]); continue; } /* Otherwise just output the character. */ pipe_putc(replace[i]); } }
static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) { char *line = *line_p; unsigned match_count = 0; bool altered = 0; bool prev_match_empty = 1; bool tried_at_eol = 0; regex_t *current_regex; current_regex = sed_cmd->sub_match; /* Handle empty regex. */ if (!current_regex) { current_regex = G.previous_regex_ptr; if (!current_regex) bb_error_msg_and_die("no previous regexp"); } G.previous_regex_ptr = current_regex; /* Find the first match */ dbg("matching '%s'", line); if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0)) { dbg("no match"); return 0; } dbg("match"); /* Initialize temporary output buffer. */ G.pipeline.buf = xmalloc(PIPE_GROW); G.pipeline.len = PIPE_GROW; G.pipeline.idx = 0; /* Now loop through, substituting for matches */ do { int start = G.regmatch[0].rm_so; int end = G.regmatch[0].rm_eo; int i; match_count++; /* If we aren't interested in this match, output old line to * end of match and continue */ if (sed_cmd->which_match && (sed_cmd->which_match != match_count) ) { for (i = 0; i < end; i++) pipe_putc(*line++); /* Null match? Print one more char */ if (start == end && *line) pipe_putc(*line++); goto next; } /* Print everything before the match */ for (i = 0; i < start; i++) pipe_putc(line[i]); /* Then print the substitution string, * unless we just matched empty string after non-empty one. * Example: string "cccd", pattern "c*", repl "R": * result is "RdR", not "RRdR": first match "ccc", * second is "" before "d", third is "" after "d". * Second match is NOT replaced! */ if (prev_match_empty || start != 0 || start != end) { //dbg("%d %d %d", prev_match_empty, start, end); dbg("inserting replacement at %d in '%s'", start, line); do_subst_w_backrefs(line, sed_cmd->string); /* Flag that something has changed */ altered = 1; } else { dbg("NOT inserting replacement at %d in '%s'", start, line); } /* If matched string is empty (f.e. "c*" pattern), * copy verbatim one char after it before attempting more matches */ prev_match_empty = (start == end); if (prev_match_empty) { if (!line[end]) { tried_at_eol = 1; } else { pipe_putc(line[end]); end++; } } /* Advance past the match */ dbg("line += %d", end); line += end; /* if we're not doing this globally, get out now */ if (sed_cmd->which_match != 0) break; next: /* Exit if we are at EOL and already tried matching at it */ if (*line == '\0') { if (tried_at_eol) break; tried_at_eol = 1; } //maybe (end ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL? } while (regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH); /* Copy rest of string into output pipeline */ while (1) { char c = *line++; pipe_putc(c); if (c == '\0') break; } free(*line_p); *line_p = G.pipeline.buf; return altered; }
static int do_subst_command(sed_cmd_t *sed_cmd, char **line) { char *oldline = *line; int altered = 0; unsigned match_count = 0; regex_t *current_regex; /* Handle empty regex. */ if (sed_cmd->sub_match == NULL) { current_regex = G.previous_regex_ptr; if (!current_regex) bb_error_msg_and_die("no previous regexp"); } else G.previous_regex_ptr = current_regex = sed_cmd->sub_match; /* Find the first match */ if (REG_NOMATCH == regexec(current_regex, oldline, 10, G.regmatch, 0)) return 0; /* Initialize temporary output buffer. */ G.pipeline.buf = xmalloc(PIPE_GROW); G.pipeline.len = PIPE_GROW; G.pipeline.idx = 0; /* Now loop through, substituting for matches */ do { int i; /* Work around bug in glibc regexec, demonstrated by: echo " a.b" | busybox sed 's [^ .]* x g' The match_count check is so not to break echo "hi" | busybox sed 's/^/!/g' */ if (!G.regmatch[0].rm_so && !G.regmatch[0].rm_eo && match_count) { pipe_putc(*oldline++); continue; } match_count++; /* If we aren't interested in this match, output old line to end of match and continue */ if (sed_cmd->which_match && (sed_cmd->which_match != match_count) ) { for (i = 0; i < G.regmatch[0].rm_eo; i++) pipe_putc(*oldline++); continue; } /* print everything before the match */ for (i = 0; i < G.regmatch[0].rm_so; i++) pipe_putc(oldline[i]); /* then print the substitution string */ do_subst_w_backrefs(oldline, sed_cmd->string); /* advance past the match */ oldline += G.regmatch[0].rm_eo; /* flag that something has changed */ altered++; /* if we're not doing this globally, get out now */ if (sed_cmd->which_match) break; } while (*oldline && (regexec(current_regex, oldline, 10, G.regmatch, 0) != REG_NOMATCH)); /* Copy rest of string into output pipeline */ while (*oldline) pipe_putc(*oldline++); pipe_putc(0); free(*line); *line = G.pipeline.buf; return altered; }