mirror of
https://github.com/sheumann/hush.git
synced 2024-12-21 23:29:34 +00:00
sed: fix handling of 1d;1,3p and 1d;1,REGEXp
function old new delta process_files 2084 2173 +89 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
f1fab09242
commit
8bca3e20b9
486
editors/sed.c
486
editors/sed.c
@ -865,63 +865,80 @@ static void process_files(void)
|
|||||||
/* Prime the pump */
|
/* Prime the pump */
|
||||||
next_line = get_next_line(&next_gets_char);
|
next_line = get_next_line(&next_gets_char);
|
||||||
|
|
||||||
/* go through every line in each file */
|
/* Go through every line in each file */
|
||||||
again:
|
again:
|
||||||
substituted = 0;
|
substituted = 0;
|
||||||
|
|
||||||
/* Advance to next line. Stop if out of lines. */
|
/* Advance to next line. Stop if out of lines. */
|
||||||
pattern_space = next_line;
|
pattern_space = next_line;
|
||||||
if (!pattern_space) return;
|
if (!pattern_space)
|
||||||
|
return;
|
||||||
last_gets_char = next_gets_char;
|
last_gets_char = next_gets_char;
|
||||||
|
|
||||||
/* Read one line in advance so we can act on the last line,
|
/* Read one line in advance so we can act on the last line,
|
||||||
* the '$' address */
|
* the '$' address */
|
||||||
next_line = get_next_line(&next_gets_char);
|
next_line = get_next_line(&next_gets_char);
|
||||||
linenum++;
|
linenum++;
|
||||||
|
|
||||||
|
/* For every line, go through all the commands */
|
||||||
restart:
|
restart:
|
||||||
/* for every line, go through all the commands */
|
|
||||||
for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) {
|
for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) {
|
||||||
int old_matched, matched;
|
int old_matched, matched;
|
||||||
|
|
||||||
old_matched = sed_cmd->in_match;
|
old_matched = sed_cmd->in_match;
|
||||||
|
|
||||||
/* Determine if this command matches this line: */
|
/* Determine if this command matches this line: */
|
||||||
|
/* Are we continuing a previous multi-line match? */
|
||||||
/* Are we continuing a previous multi-line match? */
|
|
||||||
sed_cmd->in_match = sed_cmd->in_match
|
sed_cmd->in_match = sed_cmd->in_match
|
||||||
/* Or is no range necessary? */
|
/* Or is no range necessary? */
|
||||||
|| (!sed_cmd->beg_line && !sed_cmd->end_line
|
|| (!sed_cmd->beg_line && !sed_cmd->end_line
|
||||||
&& !sed_cmd->beg_match && !sed_cmd->end_match)
|
&& !sed_cmd->beg_match && !sed_cmd->end_match)
|
||||||
/* Or did we match the start of a numerical range? */
|
/* Or did we match the start of a numerical range? */
|
||||||
|| (sed_cmd->beg_line > 0 && (sed_cmd->beg_line == linenum))
|
|| (sed_cmd->beg_line > 0 && (sed_cmd->beg_line == linenum
|
||||||
|
/* "shadowed beginning" case: "1d;1,ENDp" - p still matches at line 2
|
||||||
|
* even though 1d skipped line 1 which is a start line for p */
|
||||||
|
|| (sed_cmd->end_line && sed_cmd->beg_line < linenum && sed_cmd->end_line >= linenum)
|
||||||
|
|| (sed_cmd->end_match && sed_cmd->beg_line < linenum)
|
||||||
|
)
|
||||||
|
)
|
||||||
/* Or does this line match our begin address regex? */
|
/* Or does this line match our begin address regex? */
|
||||||
|| (beg_match(sed_cmd, pattern_space))
|
|| (beg_match(sed_cmd, pattern_space))
|
||||||
/* Or did we match last line of input? */
|
/* Or did we match last line of input? */
|
||||||
|| (sed_cmd->beg_line == -1 && next_line == NULL);
|
|| (sed_cmd->beg_line == -1 && next_line == NULL);
|
||||||
|
|
||||||
/* Snapshot the value */
|
|
||||||
|
|
||||||
matched = sed_cmd->in_match;
|
matched = sed_cmd->in_match;
|
||||||
|
|
||||||
/* Is this line the end of the current match? */
|
//bb_error_msg("cmd:'%c' matched:%d beg_line:%d end_line:%d linenum:%d",
|
||||||
|
//sed_cmd->cmd, matched, sed_cmd->beg_line, sed_cmd->end_line, linenum);
|
||||||
|
|
||||||
|
/* Is this line the end of the current match? */
|
||||||
if (matched) {
|
if (matched) {
|
||||||
sed_cmd->in_match = !(
|
int n = (
|
||||||
/* has the ending line come, or is this a single address command? */
|
/* has the ending line come, or is this a single address command? */
|
||||||
(sed_cmd->end_line ?
|
sed_cmd->end_line ?
|
||||||
sed_cmd->end_line == -1 ?
|
sed_cmd->end_line == -1 ?
|
||||||
!next_line
|
!next_line
|
||||||
: (sed_cmd->end_line <= linenum)
|
: (sed_cmd->end_line <= linenum)
|
||||||
: !sed_cmd->end_match
|
: !sed_cmd->end_match
|
||||||
)
|
);
|
||||||
|
if (!n) {
|
||||||
/* or does this line matches our last address regex */
|
/* or does this line matches our last address regex */
|
||||||
|| (sed_cmd->end_match && old_matched
|
n = (sed_cmd->end_match
|
||||||
|
&& old_matched
|
||||||
&& (regexec(sed_cmd->end_match,
|
&& (regexec(sed_cmd->end_match,
|
||||||
pattern_space, 0, NULL, 0) == 0))
|
pattern_space, 0, NULL, 0) == 0)
|
||||||
);
|
);
|
||||||
|
if (n && sed_cmd->beg_line > 0) {
|
||||||
|
/* Once matched, "n,regex" range is dead, disabling it */
|
||||||
|
regfree(sed_cmd->end_match);
|
||||||
|
free(sed_cmd->end_match);
|
||||||
|
sed_cmd->end_match = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sed_cmd->in_match = !n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip blocks of commands we didn't match. */
|
/* Skip blocks of commands we didn't match */
|
||||||
if (sed_cmd->cmd == '{') {
|
if (sed_cmd->cmd == '{') {
|
||||||
if (sed_cmd->invert ? matched : !matched) {
|
if (sed_cmd->invert ? matched : !matched) {
|
||||||
while (sed_cmd->cmd != '}') {
|
while (sed_cmd->cmd != '}') {
|
||||||
@ -934,253 +951,254 @@ static void process_files(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Okay, so did this line match? */
|
/* Okay, so did this line match? */
|
||||||
if (sed_cmd->invert ? !matched : matched) {
|
if (sed_cmd->invert ? matched : !matched)
|
||||||
/* Update last used regex in case a blank substitute BRE is found */
|
continue; /* no */
|
||||||
if (sed_cmd->beg_match) {
|
|
||||||
G.previous_regex_ptr = sed_cmd->beg_match;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* actual sedding */
|
/* Update last used regex in case a blank substitute BRE is found */
|
||||||
switch (sed_cmd->cmd) {
|
if (sed_cmd->beg_match) {
|
||||||
|
G.previous_regex_ptr = sed_cmd->beg_match;
|
||||||
|
}
|
||||||
|
|
||||||
/* Print line number */
|
/* actual sedding */
|
||||||
case '=':
|
switch (sed_cmd->cmd) {
|
||||||
fprintf(G.nonstdout, "%d\n", linenum);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Write the current pattern space up to the first newline */
|
/* Print line number */
|
||||||
case 'P':
|
case '=':
|
||||||
{
|
fprintf(G.nonstdout, "%d\n", linenum);
|
||||||
char *tmp = strchr(pattern_space, '\n');
|
break;
|
||||||
|
|
||||||
if (tmp) {
|
/* Write the current pattern space up to the first newline */
|
||||||
*tmp = '\0';
|
case 'P':
|
||||||
/* TODO: explain why '\n' below */
|
{
|
||||||
sed_puts(pattern_space, '\n');
|
char *tmp = strchr(pattern_space, '\n');
|
||||||
*tmp = '\n';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* Fall Through */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write the current pattern space to output */
|
if (tmp) {
|
||||||
case 'p':
|
*tmp = '\0';
|
||||||
/* NB: we print this _before_ the last line
|
/* TODO: explain why '\n' below */
|
||||||
* (of current file) is printed. Even if
|
|
||||||
* that line is nonterminated, we print
|
|
||||||
* '\n' here (gnu sed does the same) */
|
|
||||||
sed_puts(pattern_space, '\n');
|
sed_puts(pattern_space, '\n');
|
||||||
break;
|
*tmp = '\n';
|
||||||
/* Delete up through first newline */
|
|
||||||
case 'D':
|
|
||||||
{
|
|
||||||
char *tmp = strchr(pattern_space, '\n');
|
|
||||||
|
|
||||||
if (tmp) {
|
|
||||||
tmp = xstrdup(tmp+1);
|
|
||||||
free(pattern_space);
|
|
||||||
pattern_space = tmp;
|
|
||||||
goto restart;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* discard this line. */
|
|
||||||
case 'd':
|
|
||||||
goto discard_line;
|
|
||||||
|
|
||||||
/* Substitute with regex */
|
|
||||||
case 's':
|
|
||||||
if (!do_subst_command(sed_cmd, &pattern_space))
|
|
||||||
break;
|
|
||||||
substituted |= 1;
|
|
||||||
|
|
||||||
/* handle p option */
|
|
||||||
if (sed_cmd->sub_p)
|
|
||||||
sed_puts(pattern_space, last_gets_char);
|
|
||||||
/* handle w option */
|
|
||||||
if (sed_cmd->sw_file)
|
|
||||||
puts_maybe_newline(
|
|
||||||
pattern_space, sed_cmd->sw_file,
|
|
||||||
&sed_cmd->sw_last_char, last_gets_char);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Append line to linked list to be printed later */
|
|
||||||
case 'a':
|
|
||||||
append(sed_cmd->string);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Insert text before this line */
|
|
||||||
case 'i':
|
|
||||||
sed_puts(sed_cmd->string, '\n');
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Cut and paste text (replace) */
|
|
||||||
case 'c':
|
|
||||||
/* Only triggers on last line of a matching range. */
|
|
||||||
if (!sed_cmd->in_match)
|
|
||||||
sed_puts(sed_cmd->string, NO_EOL_CHAR);
|
|
||||||
goto discard_line;
|
|
||||||
|
|
||||||
/* Read file, append contents to output */
|
|
||||||
case 'r':
|
|
||||||
{
|
|
||||||
FILE *rfile;
|
|
||||||
|
|
||||||
rfile = fopen_for_read(sed_cmd->string);
|
|
||||||
if (rfile) {
|
|
||||||
char *line;
|
|
||||||
|
|
||||||
while ((line = xmalloc_fgetline(rfile))
|
|
||||||
!= NULL)
|
|
||||||
append(line);
|
|
||||||
xprint_and_close_file(rfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* Fall Through */
|
||||||
|
}
|
||||||
|
|
||||||
/* Write pattern space to file. */
|
/* Write the current pattern space to output */
|
||||||
case 'w':
|
case 'p':
|
||||||
|
/* NB: we print this _before_ the last line
|
||||||
|
* (of current file) is printed. Even if
|
||||||
|
* that line is nonterminated, we print
|
||||||
|
* '\n' here (gnu sed does the same) */
|
||||||
|
sed_puts(pattern_space, '\n');
|
||||||
|
break;
|
||||||
|
/* Delete up through first newline */
|
||||||
|
case 'D':
|
||||||
|
{
|
||||||
|
char *tmp = strchr(pattern_space, '\n');
|
||||||
|
|
||||||
|
if (tmp) {
|
||||||
|
tmp = xstrdup(tmp+1);
|
||||||
|
free(pattern_space);
|
||||||
|
pattern_space = tmp;
|
||||||
|
goto restart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* discard this line. */
|
||||||
|
case 'd':
|
||||||
|
goto discard_line;
|
||||||
|
|
||||||
|
/* Substitute with regex */
|
||||||
|
case 's':
|
||||||
|
if (!do_subst_command(sed_cmd, &pattern_space))
|
||||||
|
break;
|
||||||
|
substituted |= 1;
|
||||||
|
|
||||||
|
/* handle p option */
|
||||||
|
if (sed_cmd->sub_p)
|
||||||
|
sed_puts(pattern_space, last_gets_char);
|
||||||
|
/* handle w option */
|
||||||
|
if (sed_cmd->sw_file)
|
||||||
puts_maybe_newline(
|
puts_maybe_newline(
|
||||||
pattern_space, sed_cmd->sw_file,
|
pattern_space, sed_cmd->sw_file,
|
||||||
&sed_cmd->sw_last_char, last_gets_char);
|
&sed_cmd->sw_last_char, last_gets_char);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Read next line from input */
|
/* Append line to linked list to be printed later */
|
||||||
case 'n':
|
case 'a':
|
||||||
if (!G.be_quiet)
|
append(sed_cmd->string);
|
||||||
sed_puts(pattern_space, last_gets_char);
|
break;
|
||||||
if (next_line) {
|
|
||||||
free(pattern_space);
|
|
||||||
pattern_space = next_line;
|
|
||||||
last_gets_char = next_gets_char;
|
|
||||||
next_line = get_next_line(&next_gets_char);
|
|
||||||
substituted = 0;
|
|
||||||
linenum++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* fall through */
|
|
||||||
|
|
||||||
/* Quit. End of script, end of input. */
|
/* Insert text before this line */
|
||||||
case 'q':
|
case 'i':
|
||||||
/* Exit the outer while loop */
|
sed_puts(sed_cmd->string, '\n');
|
||||||
free(next_line);
|
break;
|
||||||
next_line = NULL;
|
|
||||||
goto discard_commands;
|
|
||||||
|
|
||||||
/* Append the next line to the current line */
|
/* Cut and paste text (replace) */
|
||||||
case 'N':
|
case 'c':
|
||||||
{
|
/* Only triggers on last line of a matching range. */
|
||||||
int len;
|
if (!sed_cmd->in_match)
|
||||||
/* If no next line, jump to end of script and exit. */
|
sed_puts(sed_cmd->string, NO_EOL_CHAR);
|
||||||
if (next_line == NULL) {
|
goto discard_line;
|
||||||
/* Jump to end of script and exit */
|
|
||||||
free(next_line);
|
/* Read file, append contents to output */
|
||||||
next_line = NULL;
|
case 'r':
|
||||||
goto discard_line;
|
{
|
||||||
/* append next_line, read new next_line. */
|
FILE *rfile;
|
||||||
}
|
|
||||||
len = strlen(pattern_space);
|
rfile = fopen_for_read(sed_cmd->string);
|
||||||
pattern_space = realloc(pattern_space, len + strlen(next_line) + 2);
|
if (rfile) {
|
||||||
pattern_space[len] = '\n';
|
char *line;
|
||||||
strcpy(pattern_space + len+1, next_line);
|
|
||||||
|
while ((line = xmalloc_fgetline(rfile))
|
||||||
|
!= NULL)
|
||||||
|
append(line);
|
||||||
|
xprint_and_close_file(rfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write pattern space to file. */
|
||||||
|
case 'w':
|
||||||
|
puts_maybe_newline(
|
||||||
|
pattern_space, sed_cmd->sw_file,
|
||||||
|
&sed_cmd->sw_last_char, last_gets_char);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Read next line from input */
|
||||||
|
case 'n':
|
||||||
|
if (!G.be_quiet)
|
||||||
|
sed_puts(pattern_space, last_gets_char);
|
||||||
|
if (next_line) {
|
||||||
|
free(pattern_space);
|
||||||
|
pattern_space = next_line;
|
||||||
last_gets_char = next_gets_char;
|
last_gets_char = next_gets_char;
|
||||||
next_line = get_next_line(&next_gets_char);
|
next_line = get_next_line(&next_gets_char);
|
||||||
|
substituted = 0;
|
||||||
linenum++;
|
linenum++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* fall through */
|
||||||
|
|
||||||
/* Test/branch if substitution occurred */
|
/* Quit. End of script, end of input. */
|
||||||
case 't':
|
case 'q':
|
||||||
if (!substituted) break;
|
/* Exit the outer while loop */
|
||||||
substituted = 0;
|
free(next_line);
|
||||||
/* Fall through */
|
next_line = NULL;
|
||||||
/* Test/branch if substitution didn't occur */
|
goto discard_commands;
|
||||||
case 'T':
|
|
||||||
if (substituted) break;
|
|
||||||
/* Fall through */
|
|
||||||
/* Branch to label */
|
|
||||||
case 'b':
|
|
||||||
if (!sed_cmd->string) goto discard_commands;
|
|
||||||
else sed_cmd = branch_to(sed_cmd->string);
|
|
||||||
break;
|
|
||||||
/* Transliterate characters */
|
|
||||||
case 'y':
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
for (i = 0; pattern_space[i]; i++) {
|
/* Append the next line to the current line */
|
||||||
for (j = 0; sed_cmd->string[j]; j += 2) {
|
case 'N':
|
||||||
if (pattern_space[i] == sed_cmd->string[j]) {
|
{
|
||||||
pattern_space[i] = sed_cmd->string[j + 1];
|
int len;
|
||||||
break;
|
/* If no next line, jump to end of script and exit. */
|
||||||
}
|
if (next_line == NULL) {
|
||||||
|
/* Jump to end of script and exit */
|
||||||
|
free(next_line);
|
||||||
|
next_line = NULL;
|
||||||
|
goto discard_line;
|
||||||
|
/* append next_line, read new next_line. */
|
||||||
|
}
|
||||||
|
len = strlen(pattern_space);
|
||||||
|
pattern_space = realloc(pattern_space, len + strlen(next_line) + 2);
|
||||||
|
pattern_space[len] = '\n';
|
||||||
|
strcpy(pattern_space + len+1, next_line);
|
||||||
|
last_gets_char = next_gets_char;
|
||||||
|
next_line = get_next_line(&next_gets_char);
|
||||||
|
linenum++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test/branch if substitution occurred */
|
||||||
|
case 't':
|
||||||
|
if (!substituted) break;
|
||||||
|
substituted = 0;
|
||||||
|
/* Fall through */
|
||||||
|
/* Test/branch if substitution didn't occur */
|
||||||
|
case 'T':
|
||||||
|
if (substituted) break;
|
||||||
|
/* Fall through */
|
||||||
|
/* Branch to label */
|
||||||
|
case 'b':
|
||||||
|
if (!sed_cmd->string) goto discard_commands;
|
||||||
|
else sed_cmd = branch_to(sed_cmd->string);
|
||||||
|
break;
|
||||||
|
/* Transliterate characters */
|
||||||
|
case 'y':
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i = 0; pattern_space[i]; i++) {
|
||||||
|
for (j = 0; sed_cmd->string[j]; j += 2) {
|
||||||
|
if (pattern_space[i] == sed_cmd->string[j]) {
|
||||||
|
pattern_space[i] = sed_cmd->string[j + 1];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case 'g': /* Replace pattern space with hold space */
|
|
||||||
free(pattern_space);
|
|
||||||
pattern_space = xstrdup(G.hold_space ? G.hold_space : "");
|
|
||||||
break;
|
|
||||||
case 'G': /* Append newline and hold space to pattern space */
|
|
||||||
{
|
|
||||||
int pattern_space_size = 2;
|
|
||||||
int hold_space_size = 0;
|
|
||||||
|
|
||||||
if (pattern_space)
|
break;
|
||||||
pattern_space_size += strlen(pattern_space);
|
|
||||||
if (G.hold_space)
|
|
||||||
hold_space_size = strlen(G.hold_space);
|
|
||||||
pattern_space = xrealloc(pattern_space,
|
|
||||||
pattern_space_size + hold_space_size);
|
|
||||||
if (pattern_space_size == 2)
|
|
||||||
pattern_space[0] = 0;
|
|
||||||
strcat(pattern_space, "\n");
|
|
||||||
if (G.hold_space)
|
|
||||||
strcat(pattern_space, G.hold_space);
|
|
||||||
last_gets_char = '\n';
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'h': /* Replace hold space with pattern space */
|
|
||||||
free(G.hold_space);
|
|
||||||
G.hold_space = xstrdup(pattern_space);
|
|
||||||
break;
|
|
||||||
case 'H': /* Append newline and pattern space to hold space */
|
|
||||||
{
|
|
||||||
int hold_space_size = 2;
|
|
||||||
int pattern_space_size = 0;
|
|
||||||
|
|
||||||
if (G.hold_space)
|
|
||||||
hold_space_size += strlen(G.hold_space);
|
|
||||||
if (pattern_space)
|
|
||||||
pattern_space_size = strlen(pattern_space);
|
|
||||||
G.hold_space = xrealloc(G.hold_space,
|
|
||||||
hold_space_size + pattern_space_size);
|
|
||||||
|
|
||||||
if (hold_space_size == 2)
|
|
||||||
*G.hold_space = 0;
|
|
||||||
strcat(G.hold_space, "\n");
|
|
||||||
if (pattern_space)
|
|
||||||
strcat(G.hold_space, pattern_space);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'x': /* Exchange hold and pattern space */
|
|
||||||
{
|
|
||||||
char *tmp = pattern_space;
|
|
||||||
pattern_space = G.hold_space ? : xzalloc(1);
|
|
||||||
last_gets_char = '\n';
|
|
||||||
G.hold_space = tmp;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
case 'g': /* Replace pattern space with hold space */
|
||||||
|
free(pattern_space);
|
||||||
|
pattern_space = xstrdup(G.hold_space ? G.hold_space : "");
|
||||||
|
break;
|
||||||
|
case 'G': /* Append newline and hold space to pattern space */
|
||||||
|
{
|
||||||
|
int pattern_space_size = 2;
|
||||||
|
int hold_space_size = 0;
|
||||||
|
|
||||||
|
if (pattern_space)
|
||||||
|
pattern_space_size += strlen(pattern_space);
|
||||||
|
if (G.hold_space)
|
||||||
|
hold_space_size = strlen(G.hold_space);
|
||||||
|
pattern_space = xrealloc(pattern_space,
|
||||||
|
pattern_space_size + hold_space_size);
|
||||||
|
if (pattern_space_size == 2)
|
||||||
|
pattern_space[0] = 0;
|
||||||
|
strcat(pattern_space, "\n");
|
||||||
|
if (G.hold_space)
|
||||||
|
strcat(pattern_space, G.hold_space);
|
||||||
|
last_gets_char = '\n';
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'h': /* Replace hold space with pattern space */
|
||||||
|
free(G.hold_space);
|
||||||
|
G.hold_space = xstrdup(pattern_space);
|
||||||
|
break;
|
||||||
|
case 'H': /* Append newline and pattern space to hold space */
|
||||||
|
{
|
||||||
|
int hold_space_size = 2;
|
||||||
|
int pattern_space_size = 0;
|
||||||
|
|
||||||
|
if (G.hold_space)
|
||||||
|
hold_space_size += strlen(G.hold_space);
|
||||||
|
if (pattern_space)
|
||||||
|
pattern_space_size = strlen(pattern_space);
|
||||||
|
G.hold_space = xrealloc(G.hold_space,
|
||||||
|
hold_space_size + pattern_space_size);
|
||||||
|
|
||||||
|
if (hold_space_size == 2)
|
||||||
|
*G.hold_space = 0;
|
||||||
|
strcat(G.hold_space, "\n");
|
||||||
|
if (pattern_space)
|
||||||
|
strcat(G.hold_space, pattern_space);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'x': /* Exchange hold and pattern space */
|
||||||
|
{
|
||||||
|
char *tmp = pattern_space;
|
||||||
|
pattern_space = G.hold_space ? : xzalloc(1);
|
||||||
|
last_gets_char = '\n';
|
||||||
|
G.hold_space = tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} /* switch */
|
||||||
|
} /* for each cmd */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* exit point from sedding...
|
* Exit point from sedding...
|
||||||
*/
|
*/
|
||||||
discard_commands:
|
discard_commands:
|
||||||
/* we will print the line unless we were told to be quiet ('-n')
|
/* we will print the line unless we were told to be quiet ('-n')
|
||||||
|
@ -207,4 +207,17 @@ testing "sed n command must reset 'substituted' bit" \
|
|||||||
"sed 's/1/x/;T;n;: next;s/3/y/;t quit;n;b next;: quit;q'" \
|
"sed 's/1/x/;T;n;: next;s/3/y/;t quit;n;b next;: quit;q'" \
|
||||||
"0\nx\n2\ny\n" "" "0\n1\n2\n3\n"
|
"0\nx\n2\ny\n" "" "0\n1\n2\n3\n"
|
||||||
|
|
||||||
|
testing "sed d does not break n,m matching" \
|
||||||
|
"sed -n '1d;1,3p'" \
|
||||||
|
"second\nthird\n" "" "first\nsecond\nthird\nfourth\n"
|
||||||
|
|
||||||
|
testing "sed d does not break n,regex matching" \
|
||||||
|
"sed -n '1d;1,/hir/p'" \
|
||||||
|
"second\nthird\n" "" "first\nsecond\nthird\nfourth\n"
|
||||||
|
|
||||||
|
testing "sed d does not break n,regex matching #2" \
|
||||||
|
"sed -n '1,5d;1,/hir/p'" \
|
||||||
|
"second2\nthird2\n" "" \
|
||||||
|
"first\nsecond\nthird\nfourth\n""first2\nsecond2\nthird2\nfourth2\n"
|
||||||
|
|
||||||
exit $FAILCOUNT
|
exit $FAILCOUNT
|
||||||
|
Loading…
Reference in New Issue
Block a user