diff options
author | Glenn L McGrath <bug1@ihug.co.nz> | 2003-09-14 04:06:12 +0000 |
---|---|---|
committer | Glenn L McGrath <bug1@ihug.co.nz> | 2003-09-14 04:06:12 +0000 |
commit | 8aac05bfe5ffdbc4c9591d7d5b486c0af0769a7a (patch) | |
tree | 19d33618ba3c558cd34ab743fea1a2a52f6949d0 | |
parent | 7c59a83a779fa9cb92b9d37e462a130c380d14d4 (diff) | |
download | busybox-w32-8aac05bfe5ffdbc4c9591d7d5b486c0af0769a7a.tar.gz busybox-w32-8aac05bfe5ffdbc4c9591d7d5b486c0af0769a7a.tar.bz2 busybox-w32-8aac05bfe5ffdbc4c9591d7d5b486c0af0769a7a.zip |
Patch from Rob Landley
Fixed a memory leak in add_cmd/add_cmd_str by moving the allocation
of sed_cmd down to where it's actually first needed.
In get_address, if index_of_next_unescaped_regexp_delim ever failed, we
wouldn't notice because the return value was added to idx, which was
already guaranteed to be > 0. (This is buried in the changes made when
I redid get_address to be based on pointer arithmetic, because all the tests
were gratuitously dereferencing with a constant zero, which wasn't obvious.)
Comment in parse_regex_delim was wrong: 's' and 'y' both call it.
The reason "sed_cmd->num_backrefs = 0;" isn't needed is that sed_cmd was
allocated with cmalloc, which zeroes memory.
Different handling of space after \ in i...
Different handling of pattern "s/a/b s/c/d"
Cool, resursive reads don't cause a crash. :)
Fixed "sed -f blah filename - < filename" since GNU sed was handling
both - and filenames on the same line. (You can even list - more than
once, although it's immediate EOF...)
-rw-r--r-- | editors/sed.c | 107 |
1 files changed, 47 insertions, 60 deletions
diff --git a/editors/sed.c b/editors/sed.c index f297db83b..7174288a2 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
@@ -73,7 +73,6 @@ typedef struct sed_cmd_s { | |||
73 | 73 | ||
74 | /* inversion flag */ | 74 | /* inversion flag */ |
75 | int invert; /* the '!' after the address */ | 75 | int invert; /* the '!' after the address */ |
76 | // int block_cmd; /* This command is part of a group that has a command address */ | ||
77 | 76 | ||
78 | /* Runtime flag no not if the current command match's */ | 77 | /* Runtime flag no not if the current command match's */ |
79 | int still_in_range; | 78 | int still_in_range; |
@@ -193,13 +192,16 @@ static int index_of_next_unescaped_regexp_delim(const char delimiter, | |||
193 | return -1; | 192 | return -1; |
194 | } | 193 | } |
195 | 194 | ||
195 | /* | ||
196 | * Returns the index of the third delimiter | ||
197 | */ | ||
196 | static int parse_regex_delim(const char *cmdstr, char **match, char **replace) | 198 | static int parse_regex_delim(const char *cmdstr, char **match, char **replace) |
197 | { | 199 | { |
198 | const char *cmdstr_ptr = cmdstr; | 200 | const char *cmdstr_ptr = cmdstr; |
199 | char delimiter; | 201 | char delimiter; |
200 | int idx = 0; | 202 | int idx = 0; |
201 | 203 | ||
202 | /* verify that the 's' is followed by something. That something | 204 | /* verify that the 's' or 'y' is followed by something. That something |
203 | * (typically a 'slash') is now our regexp delimiter... */ | 205 | * (typically a 'slash') is now our regexp delimiter... */ |
204 | if (*cmdstr == '\0') | 206 | if (*cmdstr == '\0') |
205 | bb_error_msg_and_die(bad_format_in_subst); | 207 | bb_error_msg_and_die(bad_format_in_subst); |
@@ -231,38 +233,35 @@ static int parse_regex_delim(const char *cmdstr, char **match, char **replace) | |||
231 | */ | 233 | */ |
232 | static int get_address(char *my_str, int *linenum, regex_t ** regex) | 234 | static int get_address(char *my_str, int *linenum, regex_t ** regex) |
233 | { | 235 | { |
234 | int idx = 0; | 236 | char *pos=my_str; |
235 | 237 | ||
236 | if (isdigit(my_str[idx])) { | 238 | if (isdigit(*my_str)) { |
237 | char *endstr; | 239 | *linenum = strtol(my_str, &pos, 10); |
238 | |||
239 | *linenum = strtol(my_str, &endstr, 10); | ||
240 | /* endstr shouldnt ever equal NULL */ | 240 | /* endstr shouldnt ever equal NULL */ |
241 | idx = endstr - my_str; | 241 | } else if (*my_str == '$') { |
242 | } else if (my_str[idx] == '$') { | ||
243 | *linenum = -1; | 242 | *linenum = -1; |
244 | idx++; | 243 | pos++; |
245 | } else if (my_str[idx] == '/' || my_str[idx] == '\\') { | 244 | } else if (*my_str == '/' || *my_str == '\\') { |
246 | int idx_start = 1; | 245 | int next, idx_start = 1; |
247 | char delimiter; | 246 | char delimiter; |
248 | 247 | ||
249 | delimiter = '/'; | 248 | delimiter = '/'; |
250 | if (my_str[idx] == '\\') { | 249 | if (*my_str == '\\') { |
251 | idx_start++; | 250 | idx_start++; |
252 | delimiter = my_str[++idx]; | 251 | delimiter = *(++pos); |
253 | } | 252 | } |
254 | idx++; | 253 | next = index_of_next_unescaped_regexp_delim(delimiter, ++pos); |
255 | idx += index_of_next_unescaped_regexp_delim(delimiter, my_str + idx); | 254 | if (next == -1) { |
256 | if (idx == -1) { | ||
257 | bb_error_msg_and_die("unterminated match expression"); | 255 | bb_error_msg_and_die("unterminated match expression"); |
258 | } | 256 | } |
259 | my_str[idx] = '\0'; | 257 | pos += next; |
258 | *pos = '\0'; | ||
260 | 259 | ||
261 | *regex = (regex_t *) xmalloc(sizeof(regex_t)); | 260 | *regex = (regex_t *) xmalloc(sizeof(regex_t)); |
262 | xregcomp(*regex, my_str + idx_start, REG_NEWLINE); | 261 | xregcomp(*regex, my_str + idx_start, REG_NEWLINE); |
263 | idx++; /* so it points to the next character after the last '/' */ | 262 | pos++; /* so it points to the next character after the last '/' */ |
264 | } | 263 | } |
265 | return idx; | 264 | return pos - my_str; |
266 | } | 265 | } |
267 | 266 | ||
268 | static int parse_subst_cmd(sed_cmd_t * const sed_cmd, const char *substr) | 267 | static int parse_subst_cmd(sed_cmd_t * const sed_cmd, const char *substr) |
@@ -287,7 +286,6 @@ static int parse_subst_cmd(sed_cmd_t * const sed_cmd, const char *substr) | |||
287 | * function to save processor time, at the expense of a little more memory | 286 | * function to save processor time, at the expense of a little more memory |
288 | * (4 bits) per sed_cmd */ | 287 | * (4 bits) per sed_cmd */ |
289 | 288 | ||
290 | /* sed_cmd->num_backrefs = 0; *//* XXX: not needed? --apparently not */ | ||
291 | for (j = 0; match[j]; j++) { | 289 | for (j = 0; match[j]; j++) { |
292 | /* GNU/POSIX sed does not save more than nine backrefs */ | 290 | /* GNU/POSIX sed does not save more than nine backrefs */ |
293 | if (match[j] == '\\' && match[j + 1] == '(' | 291 | if (match[j] == '\\' && match[j + 1] == '(' |
@@ -333,17 +331,17 @@ static int parse_subst_cmd(sed_cmd_t * const sed_cmd, const char *substr) | |||
333 | 331 | ||
334 | static void replace_slash_n(char *string) | 332 | static void replace_slash_n(char *string) |
335 | { | 333 | { |
336 | int i; | 334 | char *dest; |
337 | int remaining = strlen(string); | ||
338 | 335 | ||
339 | for (i = 0; string[i]; i++) { | 336 | for (dest = string; *string; string++, dest++) { |
340 | if ((string[i] == '\\') && (string[i + 1] == 'n')) { | 337 | if ((string[0] == '\\') && (string[1] == 'n')) { |
341 | string[i] = '\n'; | 338 | *dest = '\n'; |
342 | memmove(string + i + 1, string + i + 1, remaining - 1); | 339 | string++; |
343 | } else { | 340 | } else { |
344 | remaining--; | 341 | *dest = *string; |
345 | } | 342 | } |
346 | } | 343 | } |
344 | *dest=0; | ||
347 | } | 345 | } |
348 | 346 | ||
349 | static int parse_translate_cmd(sed_cmd_t * const sed_cmd, const char *cmdstr) | 347 | static int parse_translate_cmd(sed_cmd_t * const sed_cmd, const char *cmdstr) |
@@ -431,7 +429,7 @@ static int parse_file_cmd(sed_cmd_t * sed_cmd, const char *filecmdstr) | |||
431 | * re: the file to be read, the GNU manual says the following: "Note that | 429 | * re: the file to be read, the GNU manual says the following: "Note that |
432 | * if filename cannot be read, it is treated as if it were an empty file, | 430 | * if filename cannot be read, it is treated as if it were an empty file, |
433 | * without any error indication." Thus, all of the following commands are | 431 | * without any error indication." Thus, all of the following commands are |
434 | * perfectly leagal: | 432 | * perfectly legal: |
435 | * | 433 | * |
436 | * sed -e '1r noexist' | 434 | * sed -e '1r noexist' |
437 | * sed -e '1r ;' | 435 | * sed -e '1r ;' |
@@ -496,8 +494,10 @@ static char *parse_cmd_str(sed_cmd_t * sed_cmd, char *cmdstr) | |||
496 | return (cmdstr); | 494 | return (cmdstr); |
497 | } | 495 | } |
498 | 496 | ||
499 | static char *add_cmd(sed_cmd_t *sed_cmd, char *cmdstr) | 497 | static char *add_cmd(char *cmdstr) |
500 | { | 498 | { |
499 | sed_cmd_t *sed_cmd; | ||
500 | |||
501 | /* Skip over leading whitespace and semicolons */ | 501 | /* Skip over leading whitespace and semicolons */ |
502 | cmdstr += strspn(cmdstr, semicolon_whitespace); | 502 | cmdstr += strspn(cmdstr, semicolon_whitespace); |
503 | 503 | ||
@@ -522,6 +522,8 @@ static char *add_cmd(sed_cmd_t *sed_cmd, char *cmdstr) | |||
522 | * part1 part2 part3 | 522 | * part1 part2 part3 |
523 | */ | 523 | */ |
524 | 524 | ||
525 | sed_cmd = xcalloc(1, sizeof(sed_cmd_t)); | ||
526 | |||
525 | /* first part (if present) is an address: either a '$', a number or a /regex/ */ | 527 | /* first part (if present) is an address: either a '$', a number or a /regex/ */ |
526 | cmdstr += get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); | 528 | cmdstr += get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); |
527 | 529 | ||
@@ -595,10 +597,7 @@ static void add_cmd_str(char *cmdstr) | |||
595 | } | 597 | } |
596 | #endif | 598 | #endif |
597 | do { | 599 | do { |
598 | sed_cmd_t *sed_cmd; | 600 | cmdstr = add_cmd(cmdstr); |
599 | |||
600 | sed_cmd = xcalloc(1, sizeof(sed_cmd_t)); | ||
601 | cmdstr = add_cmd(sed_cmd, cmdstr); | ||
602 | } while (cmdstr && strlen(cmdstr)); | 601 | } while (cmdstr && strlen(cmdstr)); |
603 | } | 602 | } |
604 | 603 | ||
@@ -651,18 +650,6 @@ void pipe_putc(struct pipeline *const pipeline, char c) | |||
651 | 650 | ||
652 | #define pipeputc(c) pipe_putc(pipeline, c) | 651 | #define pipeputc(c) pipe_putc(pipeline, c) |
653 | 652 | ||
654 | #if 0 | ||
655 | { | ||
656 | if (pipeline[pipeline_idx] == PIPE_MAGIC) { | ||
657 | pipeline = xrealloc(pipeline, pipeline_len + PIPE_GROW); | ||
658 | memset(pipeline + pipeline_len, 0, PIPE_GROW); | ||
659 | pipeline_len += PIPE_GROW; | ||
660 | pipeline[pipeline_len - 1] = PIPE_MAGIC; | ||
661 | } | ||
662 | pipeline[pipeline_idx++] = (c); | ||
663 | } | ||
664 | #endif | ||
665 | |||
666 | static void print_subst_w_backrefs(const char *line, const char *replace, | 653 | static void print_subst_w_backrefs(const char *line, const char *replace, |
667 | regmatch_t * regmatch, struct pipeline *const pipeline, int matches) | 654 | regmatch_t * regmatch, struct pipeline *const pipeline, int matches) |
668 | { | 655 | { |
@@ -1157,31 +1144,31 @@ extern int sed_main(int argc, char **argv) | |||
1157 | if (sed_cmd_head.next == NULL) { | 1144 | if (sed_cmd_head.next == NULL) { |
1158 | if (argv[optind] == NULL) | 1145 | if (argv[optind] == NULL) |
1159 | bb_show_usage(); | 1146 | bb_show_usage(); |
1160 | else { | 1147 | else |
1161 | char *str_cmd = strdup(argv[optind]); | 1148 | add_cmd_str(strdup(argv[optind++])); |
1162 | |||
1163 | add_cmd_str(str_cmd); | ||
1164 | free(str_cmd); | ||
1165 | optind++; | ||
1166 | } | ||
1167 | } | 1149 | } |
1168 | 1150 | ||
1169 | /* argv[(optind)..(argc-1)] should be names of file to process. If no | 1151 | /* argv[(optind)..(argc-1)] should be names of file to process. If no |
1170 | * files were specified or '-' was specified, take input from stdin. | 1152 | * files were specified or '-' was specified, take input from stdin. |
1171 | * Otherwise, we process all the files specified. */ | 1153 | * Otherwise, we process all the files specified. */ |
1172 | if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) { | 1154 | if (argv[optind] == NULL) { |
1173 | process_file(stdin); | 1155 | process_file(stdin); |
1174 | } else { | 1156 | } else { |
1175 | int i; | 1157 | int i; |
1176 | FILE *file; | 1158 | FILE *file; |
1177 | 1159 | ||
1178 | for (i = optind; i < argc; i++) { | 1160 | for (i = optind; i < argc; i++) { |
1179 | file = bb_wfopen(argv[i], "r"); | 1161 | if(!strcmp(argv[i], "-")) { |
1180 | if (file) { | 1162 | process_file(stdin); |
1181 | process_file(file); | 1163 | } else { |
1182 | fclose(file); | 1164 | file = bb_wfopen(argv[i], "r"); |
1183 | } else | 1165 | if (file) { |
1184 | status = EXIT_FAILURE; | 1166 | process_file(file); |
1167 | fclose(file); | ||
1168 | } else { | ||
1169 | status = EXIT_FAILURE; | ||
1170 | } | ||
1171 | } | ||
1185 | } | 1172 | } |
1186 | } | 1173 | } |
1187 | 1174 | ||