sed: support GNU-like '\t' escape in substitutions
This commit is contained in:
parent
6df9e3c9a3
commit
40276648ab
@ -173,7 +173,7 @@ static void cleanup_outname(void)
|
|||||||
if (G.outname) unlink(G.outname);
|
if (G.outname) unlink(G.outname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* strdup, replacing "\n" with '\n', and "\delimiter" with 'delimiter' */
|
/* strcpy, replacing "\from" with 'to'. If to is NUL, replacing "\any" with 'any' */
|
||||||
|
|
||||||
static void parse_escapes(char *dest, const char *string, int len, char from, char to)
|
static void parse_escapes(char *dest, const char *string, int len, char from, char to)
|
||||||
{
|
{
|
||||||
@ -188,9 +188,10 @@ static void parse_escapes(char *dest, const char *string, int len, char from, ch
|
|||||||
}
|
}
|
||||||
*dest++ = string[i++];
|
*dest++ = string[i++];
|
||||||
}
|
}
|
||||||
|
/* TODO: is it safe wrt a string with trailing '\\' ? */
|
||||||
*dest++ = string[i++];
|
*dest++ = string[i++];
|
||||||
}
|
}
|
||||||
*dest = 0;
|
*dest = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *copy_parsing_escapes(const char *string, int len)
|
static char *copy_parsing_escapes(const char *string, int len)
|
||||||
@ -198,6 +199,8 @@ static char *copy_parsing_escapes(const char *string, int len)
|
|||||||
char *dest = xmalloc(len + 1);
|
char *dest = xmalloc(len + 1);
|
||||||
|
|
||||||
parse_escapes(dest, string, len, 'n', '\n');
|
parse_escapes(dest, string, len, 'n', '\n');
|
||||||
|
/* GNU sed also recognizes \t */
|
||||||
|
parse_escapes(dest, dest, strlen(dest), 't', '\t');
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +208,7 @@ static char *copy_parsing_escapes(const char *string, int len)
|
|||||||
/*
|
/*
|
||||||
* index_of_next_unescaped_regexp_delim - walks left to right through a string
|
* index_of_next_unescaped_regexp_delim - walks left to right through a string
|
||||||
* beginning at a specified index and returns the index of the next regular
|
* beginning at a specified index and returns the index of the next regular
|
||||||
* expression delimiter (typically a forward * slash ('/')) not preceded by
|
* expression delimiter (typically a forward slash ('/')) not preceded by
|
||||||
* a backslash ('\'). A negative delimiter disables square bracket checking.
|
* a backslash ('\'). A negative delimiter disables square bracket checking.
|
||||||
*/
|
*/
|
||||||
static int index_of_next_unescaped_regexp_delim(int delimiter, const char *str)
|
static int index_of_next_unescaped_regexp_delim(int delimiter, const char *str)
|
||||||
@ -425,7 +428,8 @@ static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sed_cmd->string = xstrdup(cmdstr);
|
sed_cmd->string = xstrdup(cmdstr);
|
||||||
parse_escapes(sed_cmd->string, sed_cmd->string, strlen(cmdstr), 0, 0);
|
/* "\anychar" -> "anychar" */
|
||||||
|
parse_escapes(sed_cmd->string, sed_cmd->string, strlen(cmdstr), '\0', '\0');
|
||||||
cmdstr += strlen(cmdstr);
|
cmdstr += strlen(cmdstr);
|
||||||
/* handle file cmds: (r)ead */
|
/* handle file cmds: (r)ead */
|
||||||
} else if (strchr("rw", sed_cmd->cmd)) {
|
} else if (strchr("rw", sed_cmd->cmd)) {
|
||||||
@ -1337,7 +1341,7 @@ int sed_main(int argc, char **argv)
|
|||||||
// FIXME: error check / message?
|
// FIXME: error check / message?
|
||||||
rename(G.outname, argv[i]);
|
rename(G.outname, argv[i]);
|
||||||
free(G.outname);
|
free(G.outname);
|
||||||
G.outname = 0;
|
G.outname = NULL;
|
||||||
}
|
}
|
||||||
if (G.input_file_count > G.current_input_file)
|
if (G.input_file_count > G.current_input_file)
|
||||||
process_files();
|
process_files();
|
||||||
|
@ -4,7 +4,9 @@ Update: doesn't work as described. Try "make check" from parent dir...
|
|||||||
To run the test suite, change to this directory and run "./runtest". It will
|
To run the test suite, change to this directory and run "./runtest". It will
|
||||||
run all of the test cases, and list those with unexpected outcomes. Adding the
|
run all of the test cases, and list those with unexpected outcomes. Adding the
|
||||||
-v option will cause it to show expected outcomes as well. To only run the test
|
-v option will cause it to show expected outcomes as well. To only run the test
|
||||||
cases for particular applets, specify them as parameters to runtest.
|
cases for particular applets:
|
||||||
|
|
||||||
|
./runtest <applet1> <applet2>...
|
||||||
|
|
||||||
The test cases for an applet reside in the subdirectory of the applet name. The
|
The test cases for an applet reside in the subdirectory of the applet name. The
|
||||||
name of the test case should be the assertion that is tested. The test case
|
name of the test case should be the assertion that is tested. The test case
|
||||||
|
@ -57,6 +57,7 @@ testing "sed s arbitrary delimiter" "sed -e 's woo boing '" "boing\n" "" "woo\n"
|
|||||||
testing "sed s chains" "sed -e s/foo/bar/ -e s/bar/baz/" "baz\n" "" "foo\n"
|
testing "sed s chains" "sed -e s/foo/bar/ -e s/bar/baz/" "baz\n" "" "foo\n"
|
||||||
testing "sed s chains2" "sed -e s/foo/bar/ -e s/baz/nee/" "bar\n" "" "foo\n"
|
testing "sed s chains2" "sed -e s/foo/bar/ -e s/baz/nee/" "bar\n" "" "foo\n"
|
||||||
testing "sed s [delimiter]" "sed -e 's@[@]@@'" "onetwo" "" "one@two"
|
testing "sed s [delimiter]" "sed -e 's@[@]@@'" "onetwo" "" "one@two"
|
||||||
|
testing "sed s with \\t (GNU ext)" "sed 's/\t/ /'" "one two" "" "one\ttwo"
|
||||||
|
|
||||||
# branch
|
# branch
|
||||||
testing "sed b (branch)" "sed -e 'b one;p;: one'" "foo\n" "" "foo\n"
|
testing "sed b (branch)" "sed -e 'b one;p;: one'" "foo\n" "" "foo\n"
|
||||||
|
Loading…
Reference in New Issue
Block a user