sed: support GNU-like '\t' escape in substitutions
authorDenis Vlasenko <vda.linux@googlemail.com>
Tue, 13 Nov 2007 16:48:10 +0000 (16:48 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Tue, 13 Nov 2007 16:48:10 +0000 (16:48 -0000)
editors/sed.c
testsuite/README
testsuite/sed.tests

index f75fceea504ecf12363308da91a095e0bfd978e3..0f5cab2b7aea36cc7fd89a2d6318456b08044354 100644 (file)
@@ -173,7 +173,7 @@ static void cleanup_outname(void)
        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)
 {
@@ -188,9 +188,10 @@ static void parse_escapes(char *dest, const char *string, int len, char from, ch
                        }
                        *dest++ = string[i++];
                }
+               /* TODO: is it safe wrt a string with trailing '\\' ? */
                *dest++ = string[i++];
        }
-       *dest = 0;
+       *dest = '\0';
 }
 
 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);
 
        parse_escapes(dest, string, len, 'n', '\n');
+       /* GNU sed also recognizes \t */
+       parse_escapes(dest, dest, strlen(dest), 't', '\t');
        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
  * 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.
  */
 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;
                }
                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);
        /* handle file cmds: (r)ead */
        } else if (strchr("rw", sed_cmd->cmd)) {
@@ -1337,7 +1341,7 @@ int sed_main(int argc, char **argv)
                        // FIXME: error check / message?
                        rename(G.outname, argv[i]);
                        free(G.outname);
-                       G.outname = 0;
+                       G.outname = NULL;
                }
                if (G.input_file_count > G.current_input_file)
                        process_files();
index 377f20ef8ecf7eb2e9c626c96f1b3a01ef5ebdf9..a44846dbbd9f2501c25a9eaaaedc24f1f524db6b 100644 (file)
@@ -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
 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
-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
 name of the test case should be the assertion that is tested.  The test case
index a054de6d7f1d8557d464215e4c5bf3562d9242d7..7471ed5fc8286e7fbb991231298b4fb3626d4fcf 100755 (executable)
@@ -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 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 with \\t (GNU ext)" "sed 's/\t/ /'" "one two" "" "one\ttwo"
 
 # branch
 testing "sed b (branch)" "sed -e 'b one;p;: one'" "foo\n" "" "foo\n"