Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
}