diff options
author | Mark Whitley <markw@lineo.com> | 2000-11-03 19:47:00 +0000 |
---|---|---|
committer | Mark Whitley <markw@lineo.com> | 2000-11-03 19:47:00 +0000 |
commit | 2dc192fd991ff24a2e1e469b988391d7830ad4b6 (patch) | |
tree | f093280113a03e33ad105928373a4bb2546f0d2c | |
parent | a75466e9819a7172ba48b06958a868022f4510a9 (diff) | |
download | busybox-w32-2dc192fd991ff24a2e1e469b988391d7830ad4b6.tar.gz busybox-w32-2dc192fd991ff24a2e1e469b988391d7830ad4b6.tar.bz2 busybox-w32-2dc192fd991ff24a2e1e469b988391d7830ad4b6.zip |
Re-worked the support for s///p, fixed a backref limit buglet, and cleaned up
a few other ugly places (do_subst_command got a much-needed overhaul). Also
took out BB_FEATURE_SED_PATTERN_SPACE from Config.h[.Hurd] as the 'p' is now a
standard feature (adds almost no bloat).
-rw-r--r-- | Config.h | 3 | ||||
-rw-r--r-- | Config.h.Hurd | 3 | ||||
-rw-r--r-- | editors/sed.c | 157 | ||||
-rw-r--r-- | sed.c | 157 |
4 files changed, 172 insertions, 148 deletions
@@ -223,9 +223,6 @@ | |||
223 | // Enable support for "--exclude" for excluding files | 223 | // Enable support for "--exclude" for excluding files |
224 | #define BB_FEATURE_TAR_EXCLUDE | 224 | #define BB_FEATURE_TAR_EXCLUDE |
225 | // | 225 | // |
226 | // Enable support for s///p pattern matching | ||
227 | #define BB_FEATURE_SED_PATTERN_SPACE | ||
228 | // | ||
229 | //// Enable reverse sort | 226 | //// Enable reverse sort |
230 | #define BB_FEATURE_SORT_REVERSE | 227 | #define BB_FEATURE_SORT_REVERSE |
231 | // | 228 | // |
diff --git a/Config.h.Hurd b/Config.h.Hurd index 79fdff6ad..9238761a2 100644 --- a/Config.h.Hurd +++ b/Config.h.Hurd | |||
@@ -218,9 +218,6 @@ | |||
218 | // Enable support for "--exclude" for excluding files | 218 | // Enable support for "--exclude" for excluding files |
219 | #define BB_FEATURE_TAR_EXCLUDE | 219 | #define BB_FEATURE_TAR_EXCLUDE |
220 | // | 220 | // |
221 | // Enable support for s///p pattern matching | ||
222 | #define BB_FEATURE_SED_PATTERN_SPACE | ||
223 | // | ||
224 | //// Enable reverse sort | 221 | //// Enable reverse sort |
225 | #define BB_FEATURE_SORT_REVERSE | 222 | #define BB_FEATURE_SORT_REVERSE |
226 | // | 223 | // |
diff --git a/editors/sed.c b/editors/sed.c index 75435f67a..eaca9ada5 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
@@ -62,13 +62,12 @@ extern char *optarg; /* ditto */ | |||
62 | /* options */ | 62 | /* options */ |
63 | static int be_quiet = 0; | 63 | static int be_quiet = 0; |
64 | 64 | ||
65 | static const int SUB_G = 1 << 0; | ||
66 | #ifdef BB_FEATURE_SED_PATTERN_SPACE | ||
67 | static const int SUB_P = 1 << 1; | ||
68 | #endif | ||
69 | 65 | ||
70 | struct sed_cmd { | 66 | struct sed_cmd { |
71 | 67 | ||
68 | |||
69 | /* GENERAL FIELDS */ | ||
70 | |||
72 | /* address storage */ | 71 | /* address storage */ |
73 | int beg_line; /* 'sed 1p' 0 == no begining line, apply commands to all lines */ | 72 | int beg_line; /* 'sed 1p' 0 == no begining line, apply commands to all lines */ |
74 | int end_line; /* 'sed 1,3p' 0 == no end line, use only beginning. -1 == $ */ | 73 | int end_line; /* 'sed 1,3p' 0 == no end line, use only beginning. -1 == $ */ |
@@ -78,19 +77,21 @@ struct sed_cmd { | |||
78 | /* the command */ | 77 | /* the command */ |
79 | char cmd; /* p,d,s (add more at your leisure :-) */ | 78 | char cmd; /* p,d,s (add more at your leisure :-) */ |
80 | 79 | ||
81 | /* substitution command specific fields */ | 80 | |
82 | regex_t *sub_match; /* sed -e 's/sub_match/replace/' */ | 81 | /* SUBSTITUTION COMMAND SPECIFIC FIELDS */ |
83 | char *replace; /* sed -e 's/sub_match/replace/' XXX: who will hold the \1 \2 \3s? */ | 82 | |
83 | /* sed -e 's/sub_match/replace/' */ | ||
84 | regex_t *sub_match; | ||
85 | char *replace; | ||
84 | unsigned int num_backrefs:4; /* how many back references (\1..\9) */ | 86 | unsigned int num_backrefs:4; /* how many back references (\1..\9) */ |
85 | /* Note: GNU/POSIX sed does not save more than nine backrefs, so | 87 | /* Note: GNU/POSIX sed does not save more than nine backrefs, so |
86 | * we only use 4 bits to hold the number */ | 88 | * we only use 4 bits to hold the number */ |
87 | #ifndef BB_FEATURE_SED_PATTERN_SPACE | 89 | unsigned int sub_g:1; /* sed -e 's/foo/bar/g' (global) */ |
88 | unsigned int sub_flags:1; /* sed -e 's/foo/bar/g' (global) */ | 90 | unsigned int sub_p:2; /* sed -e 's/foo/bar/p' (print substitution) */ |
89 | #else | 91 | |
90 | unsigned int sub_flags:2; /* sed -e 's/foo/bar/gp' (global/pattern) */ | 92 | |
91 | #endif | 93 | /* EDIT COMMAND (a,i,c) SPEICIFIC FIELDS */ |
92 | 94 | ||
93 | /* edit command (a,i,c) speicific field */ | ||
94 | char *editline; | 95 | char *editline; |
95 | }; | 96 | }; |
96 | 97 | ||
@@ -278,7 +279,7 @@ static int parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr) | |||
278 | /* sed_cmd->num_backrefs = 0; */ /* XXX: not needed? --apparently not */ | 279 | /* sed_cmd->num_backrefs = 0; */ /* XXX: not needed? --apparently not */ |
279 | for (j = 0; match[j]; j++) { | 280 | for (j = 0; match[j]; j++) { |
280 | /* GNU/POSIX sed does not save more than nine backrefs */ | 281 | /* GNU/POSIX sed does not save more than nine backrefs */ |
281 | if (match[j] == '\\' && match[j+1] == '(' && sed_cmd->num_backrefs < 9) | 282 | if (match[j] == '\\' && match[j+1] == '(' && sed_cmd->num_backrefs <= 9) |
282 | sed_cmd->num_backrefs++; | 283 | sed_cmd->num_backrefs++; |
283 | } | 284 | } |
284 | 285 | ||
@@ -293,16 +294,14 @@ static int parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr) | |||
293 | while (substr[++idx]) { | 294 | while (substr[++idx]) { |
294 | switch (substr[idx]) { | 295 | switch (substr[idx]) { |
295 | case 'g': | 296 | case 'g': |
296 | sed_cmd->sub_flags = SUB_G; | 297 | sed_cmd->sub_g = 1; |
297 | break; | 298 | break; |
298 | case 'I': | 299 | case 'I': |
299 | cflags |= REG_ICASE; | 300 | cflags |= REG_ICASE; |
300 | break; | 301 | break; |
301 | #ifdef BB_FEATURE_SED_PATTERN_SPACE | ||
302 | case 'p': | 302 | case 'p': |
303 | sed_cmd->sub_flags = SUB_P; | 303 | sed_cmd->sub_p = 1; |
304 | break; | 304 | break; |
305 | #endif | ||
306 | default: | 305 | default: |
307 | /* any whitespace or semicolon trailing after a s/// is ok */ | 306 | /* any whitespace or semicolon trailing after a s/// is ok */ |
308 | if (strchr("; \t\v\n\r", substr[idx])) | 307 | if (strchr("; \t\v\n\r", substr[idx])) |
@@ -534,59 +533,53 @@ static void print_subst_w_backrefs(const char *line, const char *replace, regmat | |||
534 | 533 | ||
535 | static int do_subst_command(const struct sed_cmd *sed_cmd, const char *line) | 534 | static int do_subst_command(const struct sed_cmd *sed_cmd, const char *line) |
536 | { | 535 | { |
536 | char *hackline = (char *)line; | ||
537 | int altered = 0; | 537 | int altered = 0; |
538 | regmatch_t *regmatch = NULL; | ||
538 | 539 | ||
539 | /* we only substitute if the substitution 'search' expression matches */ | 540 | /* if the user specified that they didn't want anything printed (i.e. a -n |
540 | if (regexec(sed_cmd->sub_match, line, 0, NULL, 0) == 0) { | 541 | * flag and no 'p' flag after the s///), then there's really no point doing |
541 | regmatch_t *regmatch = xmalloc(sizeof(regmatch_t) * (sed_cmd->num_backrefs+1)); | 542 | * anything here. */ |
542 | int i; | 543 | if (be_quiet && !sed_cmd->sub_p) |
543 | char *ptr = (char *)line; | 544 | return 0; |
544 | |||
545 | while (*ptr) { | ||
546 | /* if we can match the search string... */ | ||
547 | if (regexec(sed_cmd->sub_match, ptr, sed_cmd->num_backrefs+1, regmatch, 0) == 0) { | ||
548 | /* print everything before the match, */ | ||
549 | for (i = 0; i < regmatch[0].rm_so; i++) { | ||
550 | #ifdef BB_FEATURE_SED_PATTERN_SPACE | ||
551 | if(!be_quiet || (sed_cmd->sub_flags & SUB_P)) | ||
552 | #endif | ||
553 | fputc(ptr[i], stdout); | ||
554 | } | ||
555 | 545 | ||
556 | /* then print the substitution in its place */ | 546 | /* we only proceed if the substitution 'search' expression matches */ |
557 | #ifdef BB_FEATURE_SED_PATTERN_SPACE | 547 | if (regexec(sed_cmd->sub_match, line, 0, NULL, 0) == REG_NOMATCH) |
558 | if(!be_quiet || (sed_cmd->sub_flags & SUB_P)) | 548 | return 0; |
559 | #endif | ||
560 | print_subst_w_backrefs(ptr, sed_cmd->replace, regmatch); | ||
561 | 549 | ||
562 | /* then advance past the match */ | 550 | /* whaddaya know, it matched. get the number of back references */ |
563 | ptr += regmatch[0].rm_eo; | 551 | regmatch = xmalloc(sizeof(regmatch_t) * (sed_cmd->num_backrefs+1)); |
564 | 552 | ||
565 | /* and flag that something has changed */ | 553 | /* and now, as long as we've got a line to try matching and if we can match |
566 | altered++; | 554 | * the search string, we make substitutions */ |
555 | while (*hackline && (regexec(sed_cmd->sub_match, hackline, | ||
556 | sed_cmd->num_backrefs+1, regmatch, 0) == 0) ) { | ||
557 | int i; | ||
567 | 558 | ||
568 | /* if we're not doing this globally... */ | 559 | /* print everything before the match */ |
569 | if (!sed_cmd->sub_flags & SUB_G) | 560 | for (i = 0; i < regmatch[0].rm_so; i++) |
570 | break; | 561 | fputc(hackline[i], stdout); |
571 | } | ||
572 | /* if we COULD NOT match the search string (meaning we've gone past | ||
573 | * all previous instances), get out */ | ||
574 | else | ||
575 | break; | ||
576 | } | ||
577 | 562 | ||
578 | /* is there anything left to print? */ | 563 | /* then print the substitution string */ |
579 | #ifdef BB_FEATURE_SED_PATTERN_SPACE | 564 | print_subst_w_backrefs(hackline, sed_cmd->replace, regmatch); |
580 | if (*ptr && (!be_quiet || sed_cmds->sub_flags & SUB_P)) | 565 | |
581 | #else | 566 | /* advance past the match */ |
582 | if (*ptr) | 567 | hackline += regmatch[0].rm_eo; |
583 | #endif | 568 | /* flag that something has changed */ |
584 | fputs(ptr, stdout); | 569 | altered++; |
585 | 570 | ||
586 | /* cleanup */ | 571 | /* if we're not doing this globally, get out now */ |
587 | free(regmatch); | 572 | if (!sed_cmd->sub_g) |
573 | break; | ||
588 | } | 574 | } |
589 | 575 | ||
576 | /* if there's anything left of the line, print it */ | ||
577 | if (*hackline) | ||
578 | fputs(hackline, stdout); | ||
579 | |||
580 | /* cleanup */ | ||
581 | free(regmatch); | ||
582 | |||
590 | return altered; | 583 | return altered; |
591 | } | 584 | } |
592 | 585 | ||
@@ -605,7 +598,32 @@ static int do_sed_command(const struct sed_cmd *sed_cmd, const char *line) | |||
605 | break; | 598 | break; |
606 | 599 | ||
607 | case 's': | 600 | case 's': |
608 | altered = do_subst_command(sed_cmd, line); | 601 | |
602 | /* | ||
603 | * Some special cases for 's' printing to make it compliant with | ||
604 | * GNU sed printing behavior (aka "The -n | s///p Matrix"): | ||
605 | * | ||
606 | * -n ONLY = never print anything regardless of any successful | ||
607 | * substitution | ||
608 | * | ||
609 | * s///p ONLY = always print successful substitutions, even if | ||
610 | * the line is going to be printed anyway (line will be printed | ||
611 | * twice). | ||
612 | * | ||
613 | * -n AND s///p = print ONLY a successful substitution ONE TIME; | ||
614 | * no other lines are printed - this is the reason why the 'p' | ||
615 | * flag exists in the first place. | ||
616 | */ | ||
617 | |||
618 | /* we print the line once, unless we were told to be quiet */ | ||
619 | if (!be_quiet) | ||
620 | altered = do_subst_command(sed_cmd, line); | ||
621 | |||
622 | /* we also print the line if we were given the 'p' flag | ||
623 | * (this is quite possibly the second printing) */ | ||
624 | if (sed_cmd->sub_p) | ||
625 | altered = do_subst_command(sed_cmd, line); | ||
626 | |||
609 | break; | 627 | break; |
610 | 628 | ||
611 | case 'a': | 629 | case 'a': |
@@ -662,7 +680,8 @@ static void process_file(FILE *file) | |||
662 | 680 | ||
663 | /* are we acting on a range of line numbers? */ | 681 | /* are we acting on a range of line numbers? */ |
664 | else if (sed_cmds[i].beg_line > 0 && sed_cmds[i].end_line != 0) { | 682 | else if (sed_cmds[i].beg_line > 0 && sed_cmds[i].end_line != 0) { |
665 | if (linenum >= sed_cmds[i].beg_line && (sed_cmds[i].end_line == -1 || linenum <= sed_cmds[i].end_line)) | 683 | if (linenum >= sed_cmds[i].beg_line && |
684 | (sed_cmds[i].end_line == -1 || linenum <= sed_cmds[i].end_line)) | ||
666 | line_altered += do_sed_command(&sed_cmds[i], line); | 685 | line_altered += do_sed_command(&sed_cmds[i], line); |
667 | } | 686 | } |
668 | 687 | ||
@@ -678,14 +697,10 @@ static void process_file(FILE *file) | |||
678 | 697 | ||
679 | } | 698 | } |
680 | 699 | ||
681 | /* we will print the line unless we were told to be quiet or if | 700 | /* we will print the line unless we were told to be quiet or if the |
682 | * the line was altered (via a 'd'elete or 's'ubstitution) */ | 701 | * line was altered (via a 'd'elete or 's'ubstitution), in which case |
683 | #ifndef BB_FEATURE_SED_PATTERN_SPACE | 702 | * the altered line was already printed */ |
684 | if (!be_quiet &&!line_altered) | 703 | if (!be_quiet && !line_altered) |
685 | #else | ||
686 | /* we where specificly requested to print the output */ | ||
687 | if ((!be_quiet || (sed_cmds[i].sub_flags & SUB_P)) && !line_altered) | ||
688 | #endif | ||
689 | fputs(line, stdout); | 704 | fputs(line, stdout); |
690 | 705 | ||
691 | free(line); | 706 | free(line); |
@@ -62,13 +62,12 @@ extern char *optarg; /* ditto */ | |||
62 | /* options */ | 62 | /* options */ |
63 | static int be_quiet = 0; | 63 | static int be_quiet = 0; |
64 | 64 | ||
65 | static const int SUB_G = 1 << 0; | ||
66 | #ifdef BB_FEATURE_SED_PATTERN_SPACE | ||
67 | static const int SUB_P = 1 << 1; | ||
68 | #endif | ||
69 | 65 | ||
70 | struct sed_cmd { | 66 | struct sed_cmd { |
71 | 67 | ||
68 | |||
69 | /* GENERAL FIELDS */ | ||
70 | |||
72 | /* address storage */ | 71 | /* address storage */ |
73 | int beg_line; /* 'sed 1p' 0 == no begining line, apply commands to all lines */ | 72 | int beg_line; /* 'sed 1p' 0 == no begining line, apply commands to all lines */ |
74 | int end_line; /* 'sed 1,3p' 0 == no end line, use only beginning. -1 == $ */ | 73 | int end_line; /* 'sed 1,3p' 0 == no end line, use only beginning. -1 == $ */ |
@@ -78,19 +77,21 @@ struct sed_cmd { | |||
78 | /* the command */ | 77 | /* the command */ |
79 | char cmd; /* p,d,s (add more at your leisure :-) */ | 78 | char cmd; /* p,d,s (add more at your leisure :-) */ |
80 | 79 | ||
81 | /* substitution command specific fields */ | 80 | |
82 | regex_t *sub_match; /* sed -e 's/sub_match/replace/' */ | 81 | /* SUBSTITUTION COMMAND SPECIFIC FIELDS */ |
83 | char *replace; /* sed -e 's/sub_match/replace/' XXX: who will hold the \1 \2 \3s? */ | 82 | |
83 | /* sed -e 's/sub_match/replace/' */ | ||
84 | regex_t *sub_match; | ||
85 | char *replace; | ||
84 | unsigned int num_backrefs:4; /* how many back references (\1..\9) */ | 86 | unsigned int num_backrefs:4; /* how many back references (\1..\9) */ |
85 | /* Note: GNU/POSIX sed does not save more than nine backrefs, so | 87 | /* Note: GNU/POSIX sed does not save more than nine backrefs, so |
86 | * we only use 4 bits to hold the number */ | 88 | * we only use 4 bits to hold the number */ |
87 | #ifndef BB_FEATURE_SED_PATTERN_SPACE | 89 | unsigned int sub_g:1; /* sed -e 's/foo/bar/g' (global) */ |
88 | unsigned int sub_flags:1; /* sed -e 's/foo/bar/g' (global) */ | 90 | unsigned int sub_p:2; /* sed -e 's/foo/bar/p' (print substitution) */ |
89 | #else | 91 | |
90 | unsigned int sub_flags:2; /* sed -e 's/foo/bar/gp' (global/pattern) */ | 92 | |
91 | #endif | 93 | /* EDIT COMMAND (a,i,c) SPEICIFIC FIELDS */ |
92 | 94 | ||
93 | /* edit command (a,i,c) speicific field */ | ||
94 | char *editline; | 95 | char *editline; |
95 | }; | 96 | }; |
96 | 97 | ||
@@ -278,7 +279,7 @@ static int parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr) | |||
278 | /* sed_cmd->num_backrefs = 0; */ /* XXX: not needed? --apparently not */ | 279 | /* sed_cmd->num_backrefs = 0; */ /* XXX: not needed? --apparently not */ |
279 | for (j = 0; match[j]; j++) { | 280 | for (j = 0; match[j]; j++) { |
280 | /* GNU/POSIX sed does not save more than nine backrefs */ | 281 | /* GNU/POSIX sed does not save more than nine backrefs */ |
281 | if (match[j] == '\\' && match[j+1] == '(' && sed_cmd->num_backrefs < 9) | 282 | if (match[j] == '\\' && match[j+1] == '(' && sed_cmd->num_backrefs <= 9) |
282 | sed_cmd->num_backrefs++; | 283 | sed_cmd->num_backrefs++; |
283 | } | 284 | } |
284 | 285 | ||
@@ -293,16 +294,14 @@ static int parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr) | |||
293 | while (substr[++idx]) { | 294 | while (substr[++idx]) { |
294 | switch (substr[idx]) { | 295 | switch (substr[idx]) { |
295 | case 'g': | 296 | case 'g': |
296 | sed_cmd->sub_flags = SUB_G; | 297 | sed_cmd->sub_g = 1; |
297 | break; | 298 | break; |
298 | case 'I': | 299 | case 'I': |
299 | cflags |= REG_ICASE; | 300 | cflags |= REG_ICASE; |
300 | break; | 301 | break; |
301 | #ifdef BB_FEATURE_SED_PATTERN_SPACE | ||
302 | case 'p': | 302 | case 'p': |
303 | sed_cmd->sub_flags = SUB_P; | 303 | sed_cmd->sub_p = 1; |
304 | break; | 304 | break; |
305 | #endif | ||
306 | default: | 305 | default: |
307 | /* any whitespace or semicolon trailing after a s/// is ok */ | 306 | /* any whitespace or semicolon trailing after a s/// is ok */ |
308 | if (strchr("; \t\v\n\r", substr[idx])) | 307 | if (strchr("; \t\v\n\r", substr[idx])) |
@@ -534,59 +533,53 @@ static void print_subst_w_backrefs(const char *line, const char *replace, regmat | |||
534 | 533 | ||
535 | static int do_subst_command(const struct sed_cmd *sed_cmd, const char *line) | 534 | static int do_subst_command(const struct sed_cmd *sed_cmd, const char *line) |
536 | { | 535 | { |
536 | char *hackline = (char *)line; | ||
537 | int altered = 0; | 537 | int altered = 0; |
538 | regmatch_t *regmatch = NULL; | ||
538 | 539 | ||
539 | /* we only substitute if the substitution 'search' expression matches */ | 540 | /* if the user specified that they didn't want anything printed (i.e. a -n |
540 | if (regexec(sed_cmd->sub_match, line, 0, NULL, 0) == 0) { | 541 | * flag and no 'p' flag after the s///), then there's really no point doing |
541 | regmatch_t *regmatch = xmalloc(sizeof(regmatch_t) * (sed_cmd->num_backrefs+1)); | 542 | * anything here. */ |
542 | int i; | 543 | if (be_quiet && !sed_cmd->sub_p) |
543 | char *ptr = (char *)line; | 544 | return 0; |
544 | |||
545 | while (*ptr) { | ||
546 | /* if we can match the search string... */ | ||
547 | if (regexec(sed_cmd->sub_match, ptr, sed_cmd->num_backrefs+1, regmatch, 0) == 0) { | ||
548 | /* print everything before the match, */ | ||
549 | for (i = 0; i < regmatch[0].rm_so; i++) { | ||
550 | #ifdef BB_FEATURE_SED_PATTERN_SPACE | ||
551 | if(!be_quiet || (sed_cmd->sub_flags & SUB_P)) | ||
552 | #endif | ||
553 | fputc(ptr[i], stdout); | ||
554 | } | ||
555 | 545 | ||
556 | /* then print the substitution in its place */ | 546 | /* we only proceed if the substitution 'search' expression matches */ |
557 | #ifdef BB_FEATURE_SED_PATTERN_SPACE | 547 | if (regexec(sed_cmd->sub_match, line, 0, NULL, 0) == REG_NOMATCH) |
558 | if(!be_quiet || (sed_cmd->sub_flags & SUB_P)) | 548 | return 0; |
559 | #endif | ||
560 | print_subst_w_backrefs(ptr, sed_cmd->replace, regmatch); | ||
561 | 549 | ||
562 | /* then advance past the match */ | 550 | /* whaddaya know, it matched. get the number of back references */ |
563 | ptr += regmatch[0].rm_eo; | 551 | regmatch = xmalloc(sizeof(regmatch_t) * (sed_cmd->num_backrefs+1)); |
564 | 552 | ||
565 | /* and flag that something has changed */ | 553 | /* and now, as long as we've got a line to try matching and if we can match |
566 | altered++; | 554 | * the search string, we make substitutions */ |
555 | while (*hackline && (regexec(sed_cmd->sub_match, hackline, | ||
556 | sed_cmd->num_backrefs+1, regmatch, 0) == 0) ) { | ||
557 | int i; | ||
567 | 558 | ||
568 | /* if we're not doing this globally... */ | 559 | /* print everything before the match */ |
569 | if (!sed_cmd->sub_flags & SUB_G) | 560 | for (i = 0; i < regmatch[0].rm_so; i++) |
570 | break; | 561 | fputc(hackline[i], stdout); |
571 | } | ||
572 | /* if we COULD NOT match the search string (meaning we've gone past | ||
573 | * all previous instances), get out */ | ||
574 | else | ||
575 | break; | ||
576 | } | ||
577 | 562 | ||
578 | /* is there anything left to print? */ | 563 | /* then print the substitution string */ |
579 | #ifdef BB_FEATURE_SED_PATTERN_SPACE | 564 | print_subst_w_backrefs(hackline, sed_cmd->replace, regmatch); |
580 | if (*ptr && (!be_quiet || sed_cmds->sub_flags & SUB_P)) | 565 | |
581 | #else | 566 | /* advance past the match */ |
582 | if (*ptr) | 567 | hackline += regmatch[0].rm_eo; |
583 | #endif | 568 | /* flag that something has changed */ |
584 | fputs(ptr, stdout); | 569 | altered++; |
585 | 570 | ||
586 | /* cleanup */ | 571 | /* if we're not doing this globally, get out now */ |
587 | free(regmatch); | 572 | if (!sed_cmd->sub_g) |
573 | break; | ||
588 | } | 574 | } |
589 | 575 | ||
576 | /* if there's anything left of the line, print it */ | ||
577 | if (*hackline) | ||
578 | fputs(hackline, stdout); | ||
579 | |||
580 | /* cleanup */ | ||
581 | free(regmatch); | ||
582 | |||
590 | return altered; | 583 | return altered; |
591 | } | 584 | } |
592 | 585 | ||
@@ -605,7 +598,32 @@ static int do_sed_command(const struct sed_cmd *sed_cmd, const char *line) | |||
605 | break; | 598 | break; |
606 | 599 | ||
607 | case 's': | 600 | case 's': |
608 | altered = do_subst_command(sed_cmd, line); | 601 | |
602 | /* | ||
603 | * Some special cases for 's' printing to make it compliant with | ||
604 | * GNU sed printing behavior (aka "The -n | s///p Matrix"): | ||
605 | * | ||
606 | * -n ONLY = never print anything regardless of any successful | ||
607 | * substitution | ||
608 | * | ||
609 | * s///p ONLY = always print successful substitutions, even if | ||
610 | * the line is going to be printed anyway (line will be printed | ||
611 | * twice). | ||
612 | * | ||
613 | * -n AND s///p = print ONLY a successful substitution ONE TIME; | ||
614 | * no other lines are printed - this is the reason why the 'p' | ||
615 | * flag exists in the first place. | ||
616 | */ | ||
617 | |||
618 | /* we print the line once, unless we were told to be quiet */ | ||
619 | if (!be_quiet) | ||
620 | altered = do_subst_command(sed_cmd, line); | ||
621 | |||
622 | /* we also print the line if we were given the 'p' flag | ||
623 | * (this is quite possibly the second printing) */ | ||
624 | if (sed_cmd->sub_p) | ||
625 | altered = do_subst_command(sed_cmd, line); | ||
626 | |||
609 | break; | 627 | break; |
610 | 628 | ||
611 | case 'a': | 629 | case 'a': |
@@ -662,7 +680,8 @@ static void process_file(FILE *file) | |||
662 | 680 | ||
663 | /* are we acting on a range of line numbers? */ | 681 | /* are we acting on a range of line numbers? */ |
664 | else if (sed_cmds[i].beg_line > 0 && sed_cmds[i].end_line != 0) { | 682 | else if (sed_cmds[i].beg_line > 0 && sed_cmds[i].end_line != 0) { |
665 | if (linenum >= sed_cmds[i].beg_line && (sed_cmds[i].end_line == -1 || linenum <= sed_cmds[i].end_line)) | 683 | if (linenum >= sed_cmds[i].beg_line && |
684 | (sed_cmds[i].end_line == -1 || linenum <= sed_cmds[i].end_line)) | ||
666 | line_altered += do_sed_command(&sed_cmds[i], line); | 685 | line_altered += do_sed_command(&sed_cmds[i], line); |
667 | } | 686 | } |
668 | 687 | ||
@@ -678,14 +697,10 @@ static void process_file(FILE *file) | |||
678 | 697 | ||
679 | } | 698 | } |
680 | 699 | ||
681 | /* we will print the line unless we were told to be quiet or if | 700 | /* we will print the line unless we were told to be quiet or if the |
682 | * the line was altered (via a 'd'elete or 's'ubstitution) */ | 701 | * line was altered (via a 'd'elete or 's'ubstitution), in which case |
683 | #ifndef BB_FEATURE_SED_PATTERN_SPACE | 702 | * the altered line was already printed */ |
684 | if (!be_quiet &&!line_altered) | 703 | if (!be_quiet && !line_altered) |
685 | #else | ||
686 | /* we where specificly requested to print the output */ | ||
687 | if ((!be_quiet || (sed_cmds[i].sub_flags & SUB_P)) && !line_altered) | ||
688 | #endif | ||
689 | fputs(line, stdout); | 704 | fputs(line, stdout); |
690 | 705 | ||
691 | free(line); | 706 | free(line); |