diff options
| author | Rob Landley <rob@landley.net> | 2006-07-26 17:25:08 +0000 |
|---|---|---|
| committer | Rob Landley <rob@landley.net> | 2006-07-26 17:25:08 +0000 |
| commit | 4795e4e011f1a146a2a4aa06a006fff5641befb5 (patch) | |
| tree | 6185ef8c9dfc1f24c094d5262b745119f6400402 | |
| parent | 7cc6b69bb09d2242493b7c4d882af958254e0cc7 (diff) | |
| download | busybox-w32-4795e4e011f1a146a2a4aa06a006fff5641befb5.tar.gz busybox-w32-4795e4e011f1a146a2a4aa06a006fff5641befb5.tar.bz2 busybox-w32-4795e4e011f1a146a2a4aa06a006fff5641befb5.zip | |
Rich Filker spotted that sed -e 's/xxx/[/' didn't work right. Did a smaller
fix than his, and shrank the code a bit on top of that so the net size is
smaller, and added a test to the test suite for this case. Plus I cleaned up
the #includes and removed unnecessary "const"s while I was there.
| -rw-r--r-- | editors/sed.c | 58 | ||||
| -rwxr-xr-x | testsuite/sed.tests | 2 |
2 files changed, 25 insertions, 35 deletions
diff --git a/editors/sed.c b/editors/sed.c index ed584e5df..89b8dd72c 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
| @@ -58,12 +58,6 @@ | |||
| 58 | Reference http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html | 58 | Reference http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html |
| 59 | */ | 59 | */ |
| 60 | 60 | ||
| 61 | #include <stdio.h> | ||
| 62 | #include <unistd.h> /* for getopt() */ | ||
| 63 | #include <errno.h> | ||
| 64 | #include <ctype.h> /* for isspace() */ | ||
| 65 | #include <stdlib.h> | ||
| 66 | #include <string.h> | ||
| 67 | #include "busybox.h" | 61 | #include "busybox.h" |
| 68 | #include "xregex.h" | 62 | #include "xregex.h" |
| 69 | 63 | ||
| @@ -94,8 +88,6 @@ typedef struct sed_cmd_s { | |||
| 94 | struct sed_cmd_s *next; /* Next command (linked list, NULL terminated) */ | 88 | struct sed_cmd_s *next; /* Next command (linked list, NULL terminated) */ |
| 95 | } sed_cmd_t; | 89 | } sed_cmd_t; |
| 96 | 90 | ||
| 97 | static const char bad_format_in_subst[] = | ||
| 98 | "bad format in substitution expression"; | ||
| 99 | static const char *const semicolon_whitespace = "; \n\r\t\v"; | 91 | static const char *const semicolon_whitespace = "; \n\r\t\v"; |
| 100 | 92 | ||
| 101 | struct sed_globals | 93 | struct sed_globals |
| @@ -175,7 +167,7 @@ static void cleanup_outname(void) | |||
| 175 | 167 | ||
| 176 | /* strdup, replacing "\n" with '\n', and "\delimiter" with 'delimiter' */ | 168 | /* strdup, replacing "\n" with '\n', and "\delimiter" with 'delimiter' */ |
| 177 | 169 | ||
| 178 | static void parse_escapes(char *dest, const char *string, int len, char from, char to) | 170 | static void parse_escapes(char *dest, char *string, int len, char from, char to) |
| 179 | { | 171 | { |
| 180 | int i=0; | 172 | int i=0; |
| 181 | 173 | ||
| @@ -192,7 +184,7 @@ static void parse_escapes(char *dest, const char *string, int len, char from, ch | |||
| 192 | *dest=0; | 184 | *dest=0; |
| 193 | } | 185 | } |
| 194 | 186 | ||
| 195 | static char *copy_parsing_escapes(const char *string, int len) | 187 | static char *copy_parsing_escapes(char *string, int len) |
| 196 | { | 188 | { |
| 197 | char *dest=xmalloc(len+1); | 189 | char *dest=xmalloc(len+1); |
| 198 | 190 | ||
| @@ -205,18 +197,22 @@ static char *copy_parsing_escapes(const char *string, int len) | |||
| 205 | * index_of_next_unescaped_regexp_delim - walks left to right through a string | 197 | * index_of_next_unescaped_regexp_delim - walks left to right through a string |
| 206 | * beginning at a specified index and returns the index of the next regular | 198 | * beginning at a specified index and returns the index of the next regular |
| 207 | * expression delimiter (typically a forward * slash ('/')) not preceded by | 199 | * expression delimiter (typically a forward * slash ('/')) not preceded by |
| 208 | * a backslash ('\'). | 200 | * a backslash ('\'). A negative delimiter disables square bracket checking. |
| 209 | */ | 201 | */ |
| 210 | static int index_of_next_unescaped_regexp_delim(const char delimiter, | 202 | static int index_of_next_unescaped_regexp_delim(int delimiter, char *str) |
| 211 | const char *str) | ||
| 212 | { | 203 | { |
| 213 | int bracket = -1; | 204 | int bracket = -1; |
| 214 | int escaped = 0; | 205 | int escaped = 0; |
| 215 | int idx = 0; | 206 | int idx = 0; |
| 216 | char ch; | 207 | char ch; |
| 217 | 208 | ||
| 209 | if (delimiter < 0) { | ||
| 210 | bracket--; | ||
| 211 | delimiter *= -1; | ||
| 212 | } | ||
| 213 | |||
| 218 | for (; (ch = str[idx]); idx++) { | 214 | for (; (ch = str[idx]); idx++) { |
| 219 | if (bracket != -1) { | 215 | if (bracket >= 0) { |
| 220 | if (ch == ']' && !(bracket == idx - 1 || (bracket == idx - 2 | 216 | if (ch == ']' && !(bracket == idx - 1 || (bracket == idx - 2 |
| 221 | && str[idx - 1] == '^'))) | 217 | && str[idx - 1] == '^'))) |
| 222 | bracket = -1; | 218 | bracket = -1; |
| @@ -224,43 +220,38 @@ static int index_of_next_unescaped_regexp_delim(const char delimiter, | |||
| 224 | escaped = 0; | 220 | escaped = 0; |
| 225 | else if (ch == '\\') | 221 | else if (ch == '\\') |
| 226 | escaped = 1; | 222 | escaped = 1; |
| 227 | else if (ch == '[') | 223 | else if (bracket == -1 && ch == '[') |
| 228 | bracket = idx; | 224 | bracket = idx; |
| 229 | else if (ch == delimiter) | 225 | else if (ch == delimiter) |
| 230 | return idx; | 226 | return idx; |
| 231 | } | 227 | } |
| 232 | 228 | ||
| 233 | /* if we make it to here, we've hit the end of the string */ | 229 | /* if we make it to here, we've hit the end of the string */ |
| 234 | return -1; | 230 | bb_error_msg_and_die("unmatched '%c'",delimiter); |
| 235 | } | 231 | } |
| 236 | 232 | ||
| 237 | /* | 233 | /* |
| 238 | * Returns the index of the third delimiter | 234 | * Returns the index of the third delimiter |
| 239 | */ | 235 | */ |
| 240 | static int parse_regex_delim(const char *cmdstr, char **match, char **replace) | 236 | static int parse_regex_delim(char *cmdstr, char **match, char **replace) |
| 241 | { | 237 | { |
| 242 | const char *cmdstr_ptr = cmdstr; | 238 | char *cmdstr_ptr = cmdstr; |
| 243 | char delimiter; | 239 | char delimiter; |
| 244 | int idx = 0; | 240 | int idx = 0; |
| 245 | 241 | ||
| 246 | /* verify that the 's' or 'y' is followed by something. That something | 242 | /* verify that the 's' or 'y' is followed by something. That something |
| 247 | * (typically a 'slash') is now our regexp delimiter... */ | 243 | * (typically a 'slash') is now our regexp delimiter... */ |
| 248 | if (*cmdstr == '\0') bb_error_msg_and_die(bad_format_in_subst); | 244 | if (*cmdstr == '\0') |
| 245 | bb_error_msg_and_die("bad format in substitution expression"); | ||
| 249 | delimiter = *(cmdstr_ptr++); | 246 | delimiter = *(cmdstr_ptr++); |
| 250 | 247 | ||
| 251 | /* save the match string */ | 248 | /* save the match string */ |
| 252 | idx = index_of_next_unescaped_regexp_delim(delimiter, cmdstr_ptr); | 249 | idx = index_of_next_unescaped_regexp_delim(delimiter, cmdstr_ptr); |
| 253 | if (idx == -1) { | ||
| 254 | bb_error_msg_and_die(bad_format_in_subst); | ||
| 255 | } | ||
| 256 | *match = copy_parsing_escapes(cmdstr_ptr, idx); | 250 | *match = copy_parsing_escapes(cmdstr_ptr, idx); |
| 257 | 251 | ||
| 258 | /* save the replacement string */ | 252 | /* save the replacement string */ |
| 259 | cmdstr_ptr += idx + 1; | 253 | cmdstr_ptr += idx + 1; |
| 260 | idx = index_of_next_unescaped_regexp_delim(delimiter, cmdstr_ptr); | 254 | idx = index_of_next_unescaped_regexp_delim(-delimiter, cmdstr_ptr); |
| 261 | if (idx == -1) { | ||
| 262 | bb_error_msg_and_die(bad_format_in_subst); | ||
| 263 | } | ||
| 264 | *replace = copy_parsing_escapes(cmdstr_ptr, idx); | 255 | *replace = copy_parsing_escapes(cmdstr_ptr, idx); |
| 265 | 256 | ||
| 266 | return ((cmdstr_ptr - cmdstr) + idx); | 257 | return ((cmdstr_ptr - cmdstr) + idx); |
| @@ -287,21 +278,18 @@ static int get_address(char *my_str, int *linenum, regex_t ** regex) | |||
| 287 | if (*my_str == '\\') delimiter = *(++pos); | 278 | if (*my_str == '\\') delimiter = *(++pos); |
| 288 | else delimiter = '/'; | 279 | else delimiter = '/'; |
| 289 | next = index_of_next_unescaped_regexp_delim(delimiter, ++pos); | 280 | next = index_of_next_unescaped_regexp_delim(delimiter, ++pos); |
| 290 | if (next == -1) | 281 | temp = copy_parsing_escapes(pos,next); |
| 291 | bb_error_msg_and_die("unterminated match expression"); | ||
| 292 | |||
| 293 | temp=copy_parsing_escapes(pos,next); | ||
| 294 | *regex = (regex_t *) xmalloc(sizeof(regex_t)); | 282 | *regex = (regex_t *) xmalloc(sizeof(regex_t)); |
| 295 | xregcomp(*regex, temp, bbg.regex_type|REG_NEWLINE); | 283 | xregcomp(*regex, temp, bbg.regex_type|REG_NEWLINE); |
| 296 | free(temp); | 284 | free(temp); |
| 297 | /* Move position to next character after last delimiter */ | 285 | /* Move position to next character after last delimiter */ |
| 298 | pos+=(next+1); | 286 | pos += (next+1); |
| 299 | } | 287 | } |
| 300 | return pos - my_str; | 288 | return pos - my_str; |
| 301 | } | 289 | } |
| 302 | 290 | ||
| 303 | /* Grab a filename. Whitespace at start is skipped, then goes to EOL. */ | 291 | /* Grab a filename. Whitespace at start is skipped, then goes to EOL. */ |
| 304 | static int parse_file_cmd(sed_cmd_t *sed_cmd, const char *filecmdstr, char **retval) | 292 | static int parse_file_cmd(sed_cmd_t *sed_cmd, char *filecmdstr, char **retval) |
| 305 | { | 293 | { |
| 306 | int start = 0, idx, hack=0; | 294 | int start = 0, idx, hack=0; |
| 307 | 295 | ||
| @@ -318,7 +306,7 @@ static int parse_file_cmd(sed_cmd_t *sed_cmd, const char *filecmdstr, char **ret | |||
| 318 | return idx; | 306 | return idx; |
| 319 | } | 307 | } |
| 320 | 308 | ||
| 321 | static int parse_subst_cmd(sed_cmd_t *const sed_cmd, char *substr) | 309 | static int parse_subst_cmd(sed_cmd_t *sed_cmd, char *substr) |
| 322 | { | 310 | { |
| 323 | int cflags = bbg.regex_type; | 311 | int cflags = bbg.regex_type; |
| 324 | char *match; | 312 | char *match; |
| @@ -569,7 +557,7 @@ static void pipe_putc(char c) | |||
| 569 | bbg.pipeline.buf[bbg.pipeline.idx++] = c; | 557 | bbg.pipeline.buf[bbg.pipeline.idx++] = c; |
| 570 | } | 558 | } |
| 571 | 559 | ||
| 572 | static void do_subst_w_backrefs(const char *line, const char *replace) | 560 | static void do_subst_w_backrefs(char *line, char *replace) |
| 573 | { | 561 | { |
| 574 | int i,j; | 562 | int i,j; |
| 575 | 563 | ||
| @@ -669,7 +657,7 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line) | |||
| 669 | } | 657 | } |
| 670 | 658 | ||
| 671 | /* Set command pointer to point to this label. (Does not handle null label.) */ | 659 | /* Set command pointer to point to this label. (Does not handle null label.) */ |
| 672 | static sed_cmd_t *branch_to(const char *label) | 660 | static sed_cmd_t *branch_to(char *label) |
| 673 | { | 661 | { |
| 674 | sed_cmd_t *sed_cmd; | 662 | sed_cmd_t *sed_cmd; |
| 675 | 663 | ||
diff --git a/testsuite/sed.tests b/testsuite/sed.tests index 4d6e2e67e..9d2be5570 100755 --- a/testsuite/sed.tests +++ b/testsuite/sed.tests | |||
| @@ -174,6 +174,8 @@ testing "sed -i with no arg [GNUFAIL]" "sed -e '' -i 2> /dev/null || echo yes" \ | |||
| 174 | "yes\n" "" "" | 174 | "yes\n" "" "" |
| 175 | rm ./- # Clean up | 175 | rm ./- # Clean up |
| 176 | 176 | ||
| 177 | testing "sed s/xxx/[/" "sed -e 's/xxx/[/'" "[\n" "" "xxx\n" | ||
| 178 | |||
| 177 | # Ponder this a bit more, why "woo not found" from gnu version? | 179 | # Ponder this a bit more, why "woo not found" from gnu version? |
| 178 | #testing "sed doesn't substitute in deleted line" \ | 180 | #testing "sed doesn't substitute in deleted line" \ |
| 179 | # "sed -e '/ook/d;s/ook//;t woo;a bang;'" "bang" "" "ook\n" | 181 | # "sed -e '/ook/d;s/ook//;t woo;a bang;'" "bang" "" "ook\n" |
