diff options
| -rw-r--r-- | Changelog | 2 | ||||
| -rw-r--r-- | editors/sed.c | 61 | ||||
| -rw-r--r-- | sed.c | 61 |
3 files changed, 98 insertions, 26 deletions
| @@ -13,6 +13,8 @@ | |||
| 13 | 13 | ||
| 14 | * Rodney Brown <RDBrown@mira.net> | 14 | * Rodney Brown <RDBrown@mira.net> |
| 15 | -- Optimized gzip.c, shrinking it be ~1.5k | 15 | -- Optimized gzip.c, shrinking it be ~1.5k |
| 16 | * Shu-Hao Chang <shuhao_chang@trend.com.tw> | ||
| 17 | -- Fixed sed handling of multiple -e commands | ||
| 16 | 18 | ||
| 17 | -Erik Andersen, --not yet released-- | 19 | -Erik Andersen, --not yet released-- |
| 18 | 20 | ||
diff --git a/editors/sed.c b/editors/sed.c index 352c5c94f..4fe882d20 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
| @@ -490,8 +490,23 @@ static void load_cmd_file(char *filename) | |||
| 490 | } | 490 | } |
| 491 | } | 491 | } |
| 492 | 492 | ||
| 493 | static void print_subst_w_backrefs(const char *line, const char *replace, regmatch_t *regmatch, int matches) | 493 | #define PIPE_MAGIC 0x7f |
| 494 | #define PIPE_GROW 64 | ||
| 495 | #define pipeputc(c) \ | ||
| 496 | { if (pipeline[pipeline_idx] == PIPE_MAGIC) { \ | ||
| 497 | pipeline = xrealloc(pipeline, pipeline_len+PIPE_GROW); \ | ||
| 498 | memset(pipeline+pipeline_len, 0, PIPE_GROW); \ | ||
| 499 | pipeline_len += PIPE_GROW; \ | ||
| 500 | pipeline[pipeline_len-1] = PIPE_MAGIC; } \ | ||
| 501 | pipeline[pipeline_idx++] = (c); } | ||
| 502 | |||
| 503 | static void print_subst_w_backrefs(const char *line, const char *replace, | ||
| 504 | regmatch_t *regmatch, char **pipeline_p, int *pipeline_idx_p, | ||
| 505 | int *pipeline_len_p, int matches) | ||
| 494 | { | 506 | { |
| 507 | char *pipeline = *pipeline_p; | ||
| 508 | int pipeline_idx = *pipeline_idx_p; | ||
| 509 | int pipeline_len = *pipeline_len_p; | ||
| 495 | int i; | 510 | int i; |
| 496 | 511 | ||
| 497 | /* go through the replacement string */ | 512 | /* go through the replacement string */ |
| @@ -508,13 +523,13 @@ static void print_subst_w_backrefs(const char *line, const char *replace, regmat | |||
| 508 | /* print out the text held in regmatch[backref] */ | 523 | /* print out the text held in regmatch[backref] */ |
| 509 | if (backref <= matches && regmatch[backref].rm_so != -1) | 524 | if (backref <= matches && regmatch[backref].rm_so != -1) |
| 510 | for (j = regmatch[backref].rm_so; j < regmatch[backref].rm_eo; j++) | 525 | for (j = regmatch[backref].rm_so; j < regmatch[backref].rm_eo; j++) |
| 511 | fputc(line[j], stdout); | 526 | pipeputc(line[j]); |
| 512 | } | 527 | } |
| 513 | 528 | ||
| 514 | /* if we find a backslash escaped character, print the character */ | 529 | /* if we find a backslash escaped character, print the character */ |
| 515 | else if (replace[i] == '\\') { | 530 | else if (replace[i] == '\\') { |
| 516 | ++i; | 531 | ++i; |
| 517 | fputc(replace[i], stdout); | 532 | pipeputc(replace[i]); |
| 518 | } | 533 | } |
| 519 | 534 | ||
| 520 | /* if we find an unescaped '&' print out the whole matched text. | 535 | /* if we find an unescaped '&' print out the whole matched text. |
| @@ -524,27 +539,41 @@ static void print_subst_w_backrefs(const char *line, const char *replace, regmat | |||
| 524 | else if (replace[i] == '&' && replace[i-1] != '\\') { | 539 | else if (replace[i] == '&' && replace[i-1] != '\\') { |
| 525 | int j; | 540 | int j; |
| 526 | for (j = regmatch[0].rm_so; j < regmatch[0].rm_eo; j++) | 541 | for (j = regmatch[0].rm_so; j < regmatch[0].rm_eo; j++) |
| 527 | fputc(line[j], stdout); | 542 | pipeputc(line[j]); |
| 528 | } | 543 | } |
| 529 | /* nothing special, just print this char of the replacement string to stdout */ | 544 | /* nothing special, just print this char of the replacement string to stdout */ |
| 530 | else | 545 | else |
| 531 | fputc(replace[i], stdout); | 546 | pipeputc(replace[i]); |
| 532 | } | 547 | } |
| 548 | *pipeline_p = pipeline; | ||
| 549 | *pipeline_idx_p = pipeline_idx; | ||
| 550 | *pipeline_len_p = pipeline_len; | ||
| 533 | } | 551 | } |
| 534 | 552 | ||
| 535 | static int do_subst_command(const struct sed_cmd *sed_cmd, const char *line) | 553 | static int do_subst_command(const struct sed_cmd *sed_cmd, char **line) |
| 536 | { | 554 | { |
| 537 | char *hackline = (char *)line; | 555 | char *hackline = *line; |
| 556 | char *pipeline = 0; | ||
| 557 | int pipeline_idx = 0; | ||
| 558 | int pipeline_len = 0; | ||
| 538 | int altered = 0; | 559 | int altered = 0; |
| 539 | regmatch_t *regmatch = NULL; | 560 | regmatch_t *regmatch = NULL; |
| 540 | 561 | ||
| 541 | /* we only proceed if the substitution 'search' expression matches */ | 562 | /* we only proceed if the substitution 'search' expression matches */ |
| 542 | if (regexec(sed_cmd->sub_match, line, 0, NULL, 0) == REG_NOMATCH) | 563 | if (regexec(sed_cmd->sub_match, hackline, 0, NULL, 0) == REG_NOMATCH) |
| 543 | return 0; | 564 | return 0; |
| 544 | 565 | ||
| 545 | /* whaddaya know, it matched. get the number of back references */ | 566 | /* whaddaya know, it matched. get the number of back references */ |
| 546 | regmatch = xmalloc(sizeof(regmatch_t) * (sed_cmd->num_backrefs+1)); | 567 | regmatch = xmalloc(sizeof(regmatch_t) * (sed_cmd->num_backrefs+1)); |
| 547 | 568 | ||
| 569 | /* allocate more PIPE_GROW bytes | ||
| 570 | if replaced string is larger than original */ | ||
| 571 | pipeline_len = strlen(hackline)+PIPE_GROW; | ||
| 572 | pipeline = xmalloc(pipeline_len); | ||
| 573 | memset(pipeline, 0, pipeline_len); | ||
| 574 | /* buffer magic */ | ||
| 575 | pipeline[pipeline_len-1] = PIPE_MAGIC; | ||
| 576 | |||
| 548 | /* and now, as long as we've got a line to try matching and if we can match | 577 | /* and now, as long as we've got a line to try matching and if we can match |
| 549 | * the search string, we make substitutions */ | 578 | * the search string, we make substitutions */ |
| 550 | while (*hackline && (regexec(sed_cmd->sub_match, hackline, | 579 | while (*hackline && (regexec(sed_cmd->sub_match, hackline, |
| @@ -553,10 +582,11 @@ static int do_subst_command(const struct sed_cmd *sed_cmd, const char *line) | |||
| 553 | 582 | ||
| 554 | /* print everything before the match */ | 583 | /* print everything before the match */ |
| 555 | for (i = 0; i < regmatch[0].rm_so; i++) | 584 | for (i = 0; i < regmatch[0].rm_so; i++) |
| 556 | fputc(hackline[i], stdout); | 585 | pipeputc(hackline[i]); |
| 557 | 586 | ||
| 558 | /* then print the substitution string */ | 587 | /* then print the substitution string */ |
| 559 | print_subst_w_backrefs(hackline, sed_cmd->replace, regmatch, | 588 | print_subst_w_backrefs(hackline, sed_cmd->replace, regmatch, |
| 589 | &pipeline, &pipeline_idx, &pipeline_len, | ||
| 560 | sed_cmd->num_backrefs); | 590 | sed_cmd->num_backrefs); |
| 561 | 591 | ||
| 562 | /* advance past the match */ | 592 | /* advance past the match */ |
| @@ -569,11 +599,14 @@ static int do_subst_command(const struct sed_cmd *sed_cmd, const char *line) | |||
| 569 | break; | 599 | break; |
| 570 | } | 600 | } |
| 571 | 601 | ||
| 572 | puts(hackline); | 602 | for (; *hackline; hackline++) pipeputc(*hackline); |
| 603 | if (pipeline[pipeline_idx] == PIPE_MAGIC) pipeline[pipeline_idx] = 0; | ||
| 573 | 604 | ||
| 574 | /* cleanup */ | 605 | /* cleanup */ |
| 575 | free(regmatch); | 606 | free(regmatch); |
| 576 | 607 | ||
| 608 | free(*line); | ||
| 609 | *line = pipeline; | ||
| 577 | return altered; | 610 | return altered; |
| 578 | } | 611 | } |
| 579 | 612 | ||
| @@ -652,12 +685,14 @@ static void process_file(FILE *file) | |||
| 652 | 685 | ||
| 653 | /* we print the line once, unless we were told to be quiet */ | 686 | /* we print the line once, unless we were told to be quiet */ |
| 654 | if (!be_quiet) | 687 | if (!be_quiet) |
| 655 | altered |= do_subst_command(&sed_cmds[i], line); | 688 | altered |= do_subst_command(&sed_cmds[i], &line); |
| 656 | 689 | ||
| 657 | /* we also print the line if we were given the 'p' flag | 690 | /* we also print the line if we were given the 'p' flag |
| 658 | * (this is quite possibly the second printing) */ | 691 | * (this is quite possibly the second printing) */ |
| 659 | if (sed_cmds[i].sub_p) | 692 | if (sed_cmds[i].sub_p) |
| 660 | altered |= do_subst_command(&sed_cmds[i], line); | 693 | altered |= do_subst_command(&sed_cmds[i], &line); |
| 694 | if (altered && (i+1 >= ncmds || sed_cmds[i+1].cmd != 's')) | ||
| 695 | puts(line); | ||
| 661 | 696 | ||
| 662 | break; | 697 | break; |
| 663 | 698 | ||
| @@ -490,8 +490,23 @@ static void load_cmd_file(char *filename) | |||
| 490 | } | 490 | } |
| 491 | } | 491 | } |
| 492 | 492 | ||
| 493 | static void print_subst_w_backrefs(const char *line, const char *replace, regmatch_t *regmatch, int matches) | 493 | #define PIPE_MAGIC 0x7f |
| 494 | #define PIPE_GROW 64 | ||
| 495 | #define pipeputc(c) \ | ||
| 496 | { if (pipeline[pipeline_idx] == PIPE_MAGIC) { \ | ||
| 497 | pipeline = xrealloc(pipeline, pipeline_len+PIPE_GROW); \ | ||
| 498 | memset(pipeline+pipeline_len, 0, PIPE_GROW); \ | ||
| 499 | pipeline_len += PIPE_GROW; \ | ||
| 500 | pipeline[pipeline_len-1] = PIPE_MAGIC; } \ | ||
| 501 | pipeline[pipeline_idx++] = (c); } | ||
| 502 | |||
| 503 | static void print_subst_w_backrefs(const char *line, const char *replace, | ||
| 504 | regmatch_t *regmatch, char **pipeline_p, int *pipeline_idx_p, | ||
| 505 | int *pipeline_len_p, int matches) | ||
| 494 | { | 506 | { |
| 507 | char *pipeline = *pipeline_p; | ||
| 508 | int pipeline_idx = *pipeline_idx_p; | ||
| 509 | int pipeline_len = *pipeline_len_p; | ||
| 495 | int i; | 510 | int i; |
| 496 | 511 | ||
| 497 | /* go through the replacement string */ | 512 | /* go through the replacement string */ |
| @@ -508,13 +523,13 @@ static void print_subst_w_backrefs(const char *line, const char *replace, regmat | |||
| 508 | /* print out the text held in regmatch[backref] */ | 523 | /* print out the text held in regmatch[backref] */ |
| 509 | if (backref <= matches && regmatch[backref].rm_so != -1) | 524 | if (backref <= matches && regmatch[backref].rm_so != -1) |
| 510 | for (j = regmatch[backref].rm_so; j < regmatch[backref].rm_eo; j++) | 525 | for (j = regmatch[backref].rm_so; j < regmatch[backref].rm_eo; j++) |
| 511 | fputc(line[j], stdout); | 526 | pipeputc(line[j]); |
| 512 | } | 527 | } |
| 513 | 528 | ||
| 514 | /* if we find a backslash escaped character, print the character */ | 529 | /* if we find a backslash escaped character, print the character */ |
| 515 | else if (replace[i] == '\\') { | 530 | else if (replace[i] == '\\') { |
| 516 | ++i; | 531 | ++i; |
| 517 | fputc(replace[i], stdout); | 532 | pipeputc(replace[i]); |
| 518 | } | 533 | } |
| 519 | 534 | ||
| 520 | /* if we find an unescaped '&' print out the whole matched text. | 535 | /* if we find an unescaped '&' print out the whole matched text. |
| @@ -524,27 +539,41 @@ static void print_subst_w_backrefs(const char *line, const char *replace, regmat | |||
| 524 | else if (replace[i] == '&' && replace[i-1] != '\\') { | 539 | else if (replace[i] == '&' && replace[i-1] != '\\') { |
| 525 | int j; | 540 | int j; |
| 526 | for (j = regmatch[0].rm_so; j < regmatch[0].rm_eo; j++) | 541 | for (j = regmatch[0].rm_so; j < regmatch[0].rm_eo; j++) |
| 527 | fputc(line[j], stdout); | 542 | pipeputc(line[j]); |
| 528 | } | 543 | } |
| 529 | /* nothing special, just print this char of the replacement string to stdout */ | 544 | /* nothing special, just print this char of the replacement string to stdout */ |
| 530 | else | 545 | else |
| 531 | fputc(replace[i], stdout); | 546 | pipeputc(replace[i]); |
| 532 | } | 547 | } |
| 548 | *pipeline_p = pipeline; | ||
| 549 | *pipeline_idx_p = pipeline_idx; | ||
| 550 | *pipeline_len_p = pipeline_len; | ||
| 533 | } | 551 | } |
| 534 | 552 | ||
| 535 | static int do_subst_command(const struct sed_cmd *sed_cmd, const char *line) | 553 | static int do_subst_command(const struct sed_cmd *sed_cmd, char **line) |
| 536 | { | 554 | { |
| 537 | char *hackline = (char *)line; | 555 | char *hackline = *line; |
| 556 | char *pipeline = 0; | ||
| 557 | int pipeline_idx = 0; | ||
| 558 | int pipeline_len = 0; | ||
| 538 | int altered = 0; | 559 | int altered = 0; |
| 539 | regmatch_t *regmatch = NULL; | 560 | regmatch_t *regmatch = NULL; |
| 540 | 561 | ||
| 541 | /* we only proceed if the substitution 'search' expression matches */ | 562 | /* we only proceed if the substitution 'search' expression matches */ |
| 542 | if (regexec(sed_cmd->sub_match, line, 0, NULL, 0) == REG_NOMATCH) | 563 | if (regexec(sed_cmd->sub_match, hackline, 0, NULL, 0) == REG_NOMATCH) |
| 543 | return 0; | 564 | return 0; |
| 544 | 565 | ||
| 545 | /* whaddaya know, it matched. get the number of back references */ | 566 | /* whaddaya know, it matched. get the number of back references */ |
| 546 | regmatch = xmalloc(sizeof(regmatch_t) * (sed_cmd->num_backrefs+1)); | 567 | regmatch = xmalloc(sizeof(regmatch_t) * (sed_cmd->num_backrefs+1)); |
| 547 | 568 | ||
| 569 | /* allocate more PIPE_GROW bytes | ||
| 570 | if replaced string is larger than original */ | ||
| 571 | pipeline_len = strlen(hackline)+PIPE_GROW; | ||
| 572 | pipeline = xmalloc(pipeline_len); | ||
| 573 | memset(pipeline, 0, pipeline_len); | ||
| 574 | /* buffer magic */ | ||
| 575 | pipeline[pipeline_len-1] = PIPE_MAGIC; | ||
| 576 | |||
| 548 | /* and now, as long as we've got a line to try matching and if we can match | 577 | /* and now, as long as we've got a line to try matching and if we can match |
| 549 | * the search string, we make substitutions */ | 578 | * the search string, we make substitutions */ |
| 550 | while (*hackline && (regexec(sed_cmd->sub_match, hackline, | 579 | while (*hackline && (regexec(sed_cmd->sub_match, hackline, |
| @@ -553,10 +582,11 @@ static int do_subst_command(const struct sed_cmd *sed_cmd, const char *line) | |||
| 553 | 582 | ||
| 554 | /* print everything before the match */ | 583 | /* print everything before the match */ |
| 555 | for (i = 0; i < regmatch[0].rm_so; i++) | 584 | for (i = 0; i < regmatch[0].rm_so; i++) |
| 556 | fputc(hackline[i], stdout); | 585 | pipeputc(hackline[i]); |
| 557 | 586 | ||
| 558 | /* then print the substitution string */ | 587 | /* then print the substitution string */ |
| 559 | print_subst_w_backrefs(hackline, sed_cmd->replace, regmatch, | 588 | print_subst_w_backrefs(hackline, sed_cmd->replace, regmatch, |
| 589 | &pipeline, &pipeline_idx, &pipeline_len, | ||
| 560 | sed_cmd->num_backrefs); | 590 | sed_cmd->num_backrefs); |
| 561 | 591 | ||
| 562 | /* advance past the match */ | 592 | /* advance past the match */ |
| @@ -569,11 +599,14 @@ static int do_subst_command(const struct sed_cmd *sed_cmd, const char *line) | |||
| 569 | break; | 599 | break; |
| 570 | } | 600 | } |
| 571 | 601 | ||
| 572 | puts(hackline); | 602 | for (; *hackline; hackline++) pipeputc(*hackline); |
| 603 | if (pipeline[pipeline_idx] == PIPE_MAGIC) pipeline[pipeline_idx] = 0; | ||
| 573 | 604 | ||
| 574 | /* cleanup */ | 605 | /* cleanup */ |
| 575 | free(regmatch); | 606 | free(regmatch); |
| 576 | 607 | ||
| 608 | free(*line); | ||
| 609 | *line = pipeline; | ||
| 577 | return altered; | 610 | return altered; |
| 578 | } | 611 | } |
| 579 | 612 | ||
| @@ -652,12 +685,14 @@ static void process_file(FILE *file) | |||
| 652 | 685 | ||
| 653 | /* we print the line once, unless we were told to be quiet */ | 686 | /* we print the line once, unless we were told to be quiet */ |
| 654 | if (!be_quiet) | 687 | if (!be_quiet) |
| 655 | altered |= do_subst_command(&sed_cmds[i], line); | 688 | altered |= do_subst_command(&sed_cmds[i], &line); |
| 656 | 689 | ||
| 657 | /* we also print the line if we were given the 'p' flag | 690 | /* we also print the line if we were given the 'p' flag |
| 658 | * (this is quite possibly the second printing) */ | 691 | * (this is quite possibly the second printing) */ |
| 659 | if (sed_cmds[i].sub_p) | 692 | if (sed_cmds[i].sub_p) |
| 660 | altered |= do_subst_command(&sed_cmds[i], line); | 693 | altered |= do_subst_command(&sed_cmds[i], &line); |
| 694 | if (altered && (i+1 >= ncmds || sed_cmds[i+1].cmd != 's')) | ||
| 695 | puts(line); | ||
| 661 | 696 | ||
| 662 | break; | 697 | break; |
| 663 | 698 | ||
