diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-12-10 02:09:12 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-12-10 02:09:12 +0000 |
| commit | 2f8f71b20dbce1328a5175bb75ae15564f7e9489 (patch) | |
| tree | b806ee9d337d89ec3bc4f57eaaed1626560b68c8 | |
| parent | b15b7f7a4a06733fde996737110524d119b69106 (diff) | |
| download | busybox-w32-2f8f71b20dbce1328a5175bb75ae15564f7e9489.tar.gz busybox-w32-2f8f71b20dbce1328a5175bb75ae15564f7e9489.tar.bz2 busybox-w32-2f8f71b20dbce1328a5175bb75ae15564f7e9489.zip | |
sed: style fixes
| -rw-r--r-- | editors/sed.c | 666 |
1 files changed, 338 insertions, 328 deletions
diff --git a/editors/sed.c b/editors/sed.c index 94368aa68..877d1c420 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
| @@ -91,15 +91,14 @@ typedef struct sed_cmd_s { | |||
| 91 | 91 | ||
| 92 | static const char *const semicolon_whitespace = "; \n\r\t\v"; | 92 | static const char *const semicolon_whitespace = "; \n\r\t\v"; |
| 93 | 93 | ||
| 94 | struct sed_globals | 94 | struct sed_globals { |
| 95 | { | ||
| 96 | /* options */ | 95 | /* options */ |
| 97 | int be_quiet, in_place, regex_type; | 96 | int be_quiet, regex_type; |
| 98 | FILE *nonstdout; | 97 | FILE *nonstdout; |
| 99 | char *outname, *hold_space; | 98 | char *outname, *hold_space; |
| 100 | 99 | ||
| 101 | /* List of input files */ | 100 | /* List of input files */ |
| 102 | int input_file_count,current_input_file; | 101 | int input_file_count, current_input_file; |
| 103 | FILE **input_file_list; | 102 | FILE **input_file_list; |
| 104 | 103 | ||
| 105 | regmatch_t regmatch[10]; | 104 | regmatch_t regmatch[10]; |
| @@ -123,7 +122,7 @@ struct sed_globals | |||
| 123 | 122 | ||
| 124 | void sed_free_and_close_stuff(void); | 123 | void sed_free_and_close_stuff(void); |
| 125 | #if ENABLE_FEATURE_CLEAN_UP | 124 | #if ENABLE_FEATURE_CLEAN_UP |
| 126 | void sed_free_and_close_stuff(void) | 125 | static void sed_free_and_close_stuff(void) |
| 127 | { | 126 | { |
| 128 | sed_cmd_t *sed_cmd = bbg.sed_cmd_head.next; | 127 | sed_cmd_t *sed_cmd = bbg.sed_cmd_head.next; |
| 129 | 128 | ||
| @@ -187,9 +186,9 @@ static void parse_escapes(char *dest, char *string, int len, char from, char to) | |||
| 187 | 186 | ||
| 188 | static char *copy_parsing_escapes(char *string, int len) | 187 | static char *copy_parsing_escapes(char *string, int len) |
| 189 | { | 188 | { |
| 190 | char *dest = xmalloc(len+1); | 189 | char *dest = xmalloc(len + 1); |
| 191 | 190 | ||
| 192 | parse_escapes(dest,string,len,'n','\n'); | 191 | parse_escapes(dest, string, len, 'n', '\n'); |
| 193 | return dest; | 192 | return dest; |
| 194 | } | 193 | } |
| 195 | 194 | ||
| @@ -209,7 +208,7 @@ static int index_of_next_unescaped_regexp_delim(int delimiter, char *str) | |||
| 209 | 208 | ||
| 210 | if (delimiter < 0) { | 209 | if (delimiter < 0) { |
| 211 | bracket--; | 210 | bracket--; |
| 212 | delimiter *= -1; | 211 | delimiter = -delimiter; |
| 213 | } | 212 | } |
| 214 | 213 | ||
| 215 | for (; (ch = str[idx]); idx++) { | 214 | for (; (ch = str[idx]); idx++) { |
| @@ -228,7 +227,7 @@ static int index_of_next_unescaped_regexp_delim(int delimiter, char *str) | |||
| 228 | } | 227 | } |
| 229 | 228 | ||
| 230 | /* 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 */ |
| 231 | bb_error_msg_and_die("unmatched '%c'",delimiter); | 230 | bb_error_msg_and_die("unmatched '%c'", delimiter); |
| 232 | } | 231 | } |
| 233 | 232 | ||
| 234 | /* | 233 | /* |
| @@ -279,7 +278,7 @@ static int get_address(char *my_str, int *linenum, regex_t ** regex) | |||
| 279 | delimiter = '/'; | 278 | delimiter = '/'; |
| 280 | if (*my_str == '\\') delimiter = *++pos; | 279 | if (*my_str == '\\') delimiter = *++pos; |
| 281 | next = index_of_next_unescaped_regexp_delim(delimiter, ++pos); | 280 | next = index_of_next_unescaped_regexp_delim(delimiter, ++pos); |
| 282 | temp = copy_parsing_escapes(pos,next); | 281 | temp = copy_parsing_escapes(pos, next); |
| 283 | *regex = xmalloc(sizeof(regex_t)); | 282 | *regex = xmalloc(sizeof(regex_t)); |
| 284 | xregcomp(*regex, temp, bbg.regex_type|REG_NEWLINE); | 283 | xregcomp(*regex, temp, bbg.regex_type|REG_NEWLINE); |
| 285 | free(temp); | 284 | free(temp); |
| @@ -336,9 +335,10 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, char *substr) | |||
| 336 | if (isdigit(substr[idx])) { | 335 | if (isdigit(substr[idx])) { |
| 337 | if (match[0] != '^') { | 336 | if (match[0] != '^') { |
| 338 | /* Match 0 treated as all, multiple matches we take the last one. */ | 337 | /* Match 0 treated as all, multiple matches we take the last one. */ |
| 339 | char *pos = substr+idx; | 338 | char *pos = substr + idx; |
| 340 | sed_cmd->which_match = (unsigned short)strtol(substr+idx,&pos,10); | 339 | /* FIXME: error check? */ |
| 341 | idx = pos-substr; | 340 | sed_cmd->which_match = (unsigned short)strtol(substr+idx, &pos, 10); |
| 341 | idx = pos - substr; | ||
| 342 | } | 342 | } |
| 343 | continue; | 343 | continue; |
| 344 | } | 344 | } |
| @@ -358,7 +358,7 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, char *substr) | |||
| 358 | case 'w': | 358 | case 'w': |
| 359 | { | 359 | { |
| 360 | char *temp; | 360 | char *temp; |
| 361 | idx += parse_file_cmd(sed_cmd,substr+idx,&temp); | 361 | idx += parse_file_cmd(sed_cmd, substr+idx, &temp); |
| 362 | 362 | ||
| 363 | break; | 363 | break; |
| 364 | } | 364 | } |
| @@ -413,7 +413,7 @@ static char *parse_cmd_args(sed_cmd_t *sed_cmd, char *cmdstr) | |||
| 413 | break; | 413 | break; |
| 414 | } | 414 | } |
| 415 | sed_cmd->string = xstrdup(cmdstr); | 415 | sed_cmd->string = xstrdup(cmdstr); |
| 416 | parse_escapes(sed_cmd->string,sed_cmd->string,strlen(cmdstr),0,0); | 416 | parse_escapes(sed_cmd->string, sed_cmd->string, strlen(cmdstr), 0, 0); |
| 417 | cmdstr += strlen(cmdstr); | 417 | cmdstr += strlen(cmdstr); |
| 418 | /* handle file cmds: (r)ead */ | 418 | /* handle file cmds: (r)ead */ |
| 419 | } else if (strchr("rw", sed_cmd->cmd)) { | 419 | } else if (strchr("rw", sed_cmd->cmd)) { |
| @@ -421,7 +421,7 @@ static char *parse_cmd_args(sed_cmd_t *sed_cmd, char *cmdstr) | |||
| 421 | bb_error_msg_and_die("command only uses one address"); | 421 | bb_error_msg_and_die("command only uses one address"); |
| 422 | cmdstr += parse_file_cmd(sed_cmd, cmdstr, &sed_cmd->string); | 422 | cmdstr += parse_file_cmd(sed_cmd, cmdstr, &sed_cmd->string); |
| 423 | if (sed_cmd->cmd == 'w') | 423 | if (sed_cmd->cmd == 'w') |
| 424 | sed_cmd->file = xfopen(sed_cmd->string,"w"); | 424 | sed_cmd->file = xfopen(sed_cmd->string, "w"); |
| 425 | /* handle branch commands */ | 425 | /* handle branch commands */ |
| 426 | } else if (strchr(":btT", sed_cmd->cmd)) { | 426 | } else if (strchr(":btT", sed_cmd->cmd)) { |
| 427 | int length; | 427 | int length; |
| @@ -440,8 +440,8 @@ static char *parse_cmd_args(sed_cmd_t *sed_cmd, char *cmdstr) | |||
| 440 | 440 | ||
| 441 | cmdstr += parse_regex_delim(cmdstr, &match, &replace)+1; | 441 | cmdstr += parse_regex_delim(cmdstr, &match, &replace)+1; |
| 442 | /* \n already parsed, but \delimiter needs unescaping. */ | 442 | /* \n already parsed, but \delimiter needs unescaping. */ |
| 443 | parse_escapes(match,match,strlen(match),i,i); | 443 | parse_escapes(match, match, strlen(match), i, i); |
| 444 | parse_escapes(replace,replace,strlen(replace),i,i); | 444 | parse_escapes(replace, replace, strlen(replace), i, i); |
| 445 | 445 | ||
| 446 | sed_cmd->string = xzalloc((strlen(match) + 1) * 2); | 446 | sed_cmd->string = xzalloc((strlen(match) + 1) * 2); |
| 447 | for (i = 0; match[i] && replace[i]; i++) { | 447 | for (i = 0; match[i] && replace[i]; i++) { |
| @@ -641,7 +641,7 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line) | |||
| 641 | 641 | ||
| 642 | /* If we aren't interested in this match, output old line to | 642 | /* If we aren't interested in this match, output old line to |
| 643 | end of match and continue */ | 643 | end of match and continue */ |
| 644 | if (sed_cmd->which_match && sed_cmd->which_match!=match_count) { | 644 | if (sed_cmd->which_match && sed_cmd->which_match != match_count) { |
| 645 | for (i = 0; i < bbg.regmatch[0].rm_eo; i++) | 645 | for (i = 0; i < bbg.regmatch[0].rm_eo; i++) |
| 646 | pipe_putc(*oldline++); | 646 | pipe_putc(*oldline++); |
| 647 | continue; | 647 | continue; |
| @@ -698,7 +698,7 @@ static void flush_append(void) | |||
| 698 | 698 | ||
| 699 | /* Output appended lines. */ | 699 | /* Output appended lines. */ |
| 700 | while ((data = (char *)llist_pop(&bbg.append_head))) { | 700 | while ((data = (char *)llist_pop(&bbg.append_head))) { |
| 701 | fprintf(bbg.nonstdout,"%s\n",data); | 701 | fprintf(bbg.nonstdout, "%s\n", data); |
| 702 | free(data); | 702 | free(data); |
| 703 | } | 703 | } |
| 704 | } | 704 | } |
| @@ -801,325 +801,327 @@ static void process_files(void) | |||
| 801 | next_line = get_next_line(&next_last_char); | 801 | next_line = get_next_line(&next_last_char); |
| 802 | 802 | ||
| 803 | /* go through every line in each file */ | 803 | /* go through every line in each file */ |
| 804 | for (;;) { | 804 | again: |
| 805 | sed_cmd_t *sed_cmd; | ||
| 806 | int substituted = 0; | ||
| 807 | |||
| 808 | /* Advance to next line. Stop if out of lines. */ | ||
| 809 | pattern_space = next_line; | ||
| 810 | if (!pattern_space) break; | ||
| 811 | last_char = next_last_char; | ||
| 812 | |||
| 813 | /* Read one line in advance so we can act on the last line, | ||
| 814 | * the '$' address */ | ||
| 815 | next_line = get_next_line(&next_last_char); | ||
| 816 | linenum++; | ||
| 817 | restart: | ||
| 818 | /* for every line, go through all the commands */ | ||
| 819 | for (sed_cmd = bbg.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) { | ||
| 820 | int old_matched, matched; | ||
| 821 | |||
| 822 | old_matched = sed_cmd->in_match; | ||
| 823 | |||
| 824 | /* Determine if this command matches this line: */ | ||
| 825 | |||
| 826 | /* Are we continuing a previous multi-line match? */ | ||
| 827 | sed_cmd->in_match = sed_cmd->in_match | ||
| 828 | /* Or is no range necessary? */ | ||
| 829 | || (!sed_cmd->beg_line && !sed_cmd->end_line | ||
| 830 | && !sed_cmd->beg_match && !sed_cmd->end_match) | ||
| 831 | /* Or did we match the start of a numerical range? */ | ||
| 832 | || (sed_cmd->beg_line > 0 && (sed_cmd->beg_line == linenum)) | ||
| 833 | /* Or does this line match our begin address regex? */ | ||
| 834 | || (sed_cmd->beg_match && | ||
| 835 | !regexec(sed_cmd->beg_match, pattern_space, 0, NULL, 0)) | ||
| 836 | /* Or did we match last line of input? */ | ||
| 837 | || (sed_cmd->beg_line == -1 && next_line == NULL); | ||
| 838 | |||
| 839 | /* Snapshot the value */ | ||
| 840 | |||
| 841 | matched = sed_cmd->in_match; | ||
| 842 | |||
| 843 | /* Is this line the end of the current match? */ | ||
| 844 | |||
| 845 | if (matched) { | ||
| 846 | sed_cmd->in_match = !( | ||
| 847 | /* has the ending line come, or is this a single address command? */ | ||
| 848 | (sed_cmd->end_line ? | ||
| 849 | sed_cmd->end_line==-1 ? | ||
| 850 | !next_line | ||
| 851 | : sed_cmd->end_line<=linenum | ||
| 852 | : !sed_cmd->end_match) | ||
| 853 | /* or does this line matches our last address regex */ | ||
| 854 | || (sed_cmd->end_match && old_matched && (regexec(sed_cmd->end_match, pattern_space, 0, NULL, 0) == 0)) | ||
| 855 | ); | ||
| 856 | } | ||
| 857 | 805 | ||
| 858 | /* Skip blocks of commands we didn't match. */ | 806 | sed_cmd_t *sed_cmd; |
| 859 | if (sed_cmd->cmd == '{') { | 807 | int substituted = 0; |
| 860 | if (sed_cmd->invert ? matched : !matched) | ||
| 861 | while (sed_cmd && sed_cmd->cmd != '}') | ||
| 862 | sed_cmd = sed_cmd->next; | ||
| 863 | if (!sed_cmd) bb_error_msg_and_die("unterminated {"); | ||
| 864 | continue; | ||
| 865 | } | ||
| 866 | 808 | ||
| 867 | /* Okay, so did this line match? */ | 809 | /* Advance to next line. Stop if out of lines. */ |
| 868 | if (sed_cmd->invert ? !matched : matched) { | 810 | pattern_space = next_line; |
| 869 | /* Update last used regex in case a blank substitute BRE is found */ | 811 | if (!pattern_space) return; |
| 870 | if (sed_cmd->beg_match) { | 812 | last_char = next_last_char; |
| 871 | bbg.previous_regex_ptr = sed_cmd->beg_match; | ||
| 872 | } | ||
| 873 | 813 | ||
| 874 | /* actual sedding */ | 814 | /* Read one line in advance so we can act on the last line, |
| 875 | switch (sed_cmd->cmd) { | 815 | * the '$' address */ |
| 816 | next_line = get_next_line(&next_last_char); | ||
| 817 | linenum++; | ||
| 818 | restart: | ||
| 819 | /* for every line, go through all the commands */ | ||
| 820 | for (sed_cmd = bbg.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) { | ||
| 821 | int old_matched, matched; | ||
| 822 | |||
| 823 | old_matched = sed_cmd->in_match; | ||
| 824 | |||
| 825 | /* Determine if this command matches this line: */ | ||
| 826 | |||
| 827 | /* Are we continuing a previous multi-line match? */ | ||
| 828 | sed_cmd->in_match = sed_cmd->in_match | ||
| 829 | /* Or is no range necessary? */ | ||
| 830 | || (!sed_cmd->beg_line && !sed_cmd->end_line | ||
| 831 | && !sed_cmd->beg_match && !sed_cmd->end_match) | ||
| 832 | /* Or did we match the start of a numerical range? */ | ||
| 833 | || (sed_cmd->beg_line > 0 && (sed_cmd->beg_line == linenum)) | ||
| 834 | /* Or does this line match our begin address regex? */ | ||
| 835 | || (sed_cmd->beg_match && | ||
| 836 | !regexec(sed_cmd->beg_match, pattern_space, 0, NULL, 0)) | ||
| 837 | /* Or did we match last line of input? */ | ||
| 838 | || (sed_cmd->beg_line == -1 && next_line == NULL); | ||
| 839 | |||
| 840 | /* Snapshot the value */ | ||
| 841 | |||
| 842 | matched = sed_cmd->in_match; | ||
| 843 | |||
| 844 | /* Is this line the end of the current match? */ | ||
| 845 | |||
| 846 | if (matched) { | ||
| 847 | sed_cmd->in_match = !( | ||
| 848 | /* has the ending line come, or is this a single address command? */ | ||
| 849 | (sed_cmd->end_line ? | ||
| 850 | sed_cmd->end_line == -1 ? | ||
| 851 | !next_line | ||
| 852 | : (sed_cmd->end_line <= linenum) | ||
| 853 | : !sed_cmd->end_match | ||
| 854 | ) | ||
| 855 | /* or does this line matches our last address regex */ | ||
| 856 | || (sed_cmd->end_match && old_matched | ||
| 857 | && (regexec(sed_cmd->end_match, | ||
| 858 | pattern_space, 0, NULL, 0) == 0)) | ||
| 859 | ); | ||
| 860 | } | ||
| 876 | 861 | ||
| 877 | /* Print line number */ | 862 | /* Skip blocks of commands we didn't match. */ |
| 878 | case '=': | 863 | if (sed_cmd->cmd == '{') { |
| 879 | fprintf(bbg.nonstdout, "%d\n", linenum); | 864 | if (sed_cmd->invert ? matched : !matched) |
| 880 | break; | 865 | while (sed_cmd && sed_cmd->cmd != '}') |
| 866 | sed_cmd = sed_cmd->next; | ||
| 867 | if (!sed_cmd) bb_error_msg_and_die("unterminated {"); | ||
| 868 | continue; | ||
| 869 | } | ||
| 881 | 870 | ||
| 882 | /* Write the current pattern space up to the first newline */ | 871 | /* Okay, so did this line match? */ |
| 883 | case 'P': | 872 | if (sed_cmd->invert ? !matched : matched) { |
| 884 | { | 873 | /* Update last used regex in case a blank substitute BRE is found */ |
| 885 | char *tmp = strchr(pattern_space, '\n'); | 874 | if (sed_cmd->beg_match) { |
| 875 | bbg.previous_regex_ptr = sed_cmd->beg_match; | ||
| 876 | } | ||
| 886 | 877 | ||
| 887 | if (tmp) { | 878 | /* actual sedding */ |
| 888 | *tmp = '\0'; | 879 | switch (sed_cmd->cmd) { |
| 889 | sed_puts(pattern_space,1); | ||
| 890 | *tmp = '\n'; | ||
| 891 | break; | ||
| 892 | } | ||
| 893 | /* Fall Through */ | ||
| 894 | } | ||
| 895 | 880 | ||
| 896 | /* Write the current pattern space to output */ | 881 | /* Print line number */ |
| 897 | case 'p': | 882 | case '=': |
| 898 | sed_puts(pattern_space, last_char); | 883 | fprintf(bbg.nonstdout, "%d\n", linenum); |
| 884 | break; | ||
| 885 | |||
| 886 | /* Write the current pattern space up to the first newline */ | ||
| 887 | case 'P': | ||
| 888 | { | ||
| 889 | char *tmp = strchr(pattern_space, '\n'); | ||
| 890 | |||
| 891 | if (tmp) { | ||
| 892 | *tmp = '\0'; | ||
| 893 | sed_puts(pattern_space, 1); | ||
| 894 | *tmp = '\n'; | ||
| 899 | break; | 895 | break; |
| 900 | /* Delete up through first newline */ | ||
| 901 | case 'D': | ||
| 902 | { | ||
| 903 | char *tmp = strchr(pattern_space,'\n'); | ||
| 904 | |||
| 905 | if (tmp) { | ||
| 906 | tmp = xstrdup(tmp+1); | ||
| 907 | free(pattern_space); | ||
| 908 | pattern_space = tmp; | ||
| 909 | goto restart; | ||
| 910 | } | ||
| 911 | } | 896 | } |
| 912 | /* discard this line. */ | 897 | /* Fall Through */ |
| 913 | case 'd': | 898 | } |
| 914 | goto discard_line; | ||
| 915 | 899 | ||
| 916 | /* Substitute with regex */ | 900 | /* Write the current pattern space to output */ |
| 917 | case 's': | 901 | case 'p': |
| 918 | if (!do_subst_command(sed_cmd, &pattern_space)) | 902 | sed_puts(pattern_space, last_char); |
| 919 | break; | 903 | break; |
| 920 | substituted |= 1; | 904 | /* Delete up through first newline */ |
| 921 | 905 | case 'D': | |
| 922 | /* handle p option */ | 906 | { |
| 923 | if (sed_cmd->sub_p) | 907 | char *tmp = strchr(pattern_space, '\n'); |
| 924 | sed_puts(pattern_space, last_char); | ||
| 925 | /* handle w option */ | ||
| 926 | if (sed_cmd->file) | ||
| 927 | sed_cmd->last_char = puts_maybe_newline( | ||
| 928 | pattern_space, sed_cmd->file, | ||
| 929 | sed_cmd->last_char, last_char); | ||
| 930 | break; | ||
| 931 | 908 | ||
| 932 | /* Append line to linked list to be printed later */ | 909 | if (tmp) { |
| 933 | case 'a': | 910 | tmp = xstrdup(tmp+1); |
| 934 | append(sed_cmd->string); | 911 | free(pattern_space); |
| 935 | break; | 912 | pattern_space = tmp; |
| 913 | goto restart; | ||
| 914 | } | ||
| 915 | } | ||
| 916 | /* discard this line. */ | ||
| 917 | case 'd': | ||
| 918 | goto discard_line; | ||
| 936 | 919 | ||
| 937 | /* Insert text before this line */ | 920 | /* Substitute with regex */ |
| 938 | case 'i': | 921 | case 's': |
| 939 | sed_puts(sed_cmd->string,1); | 922 | if (!do_subst_command(sed_cmd, &pattern_space)) |
| 940 | break; | 923 | break; |
| 924 | substituted |= 1; | ||
| 941 | 925 | ||
| 942 | /* Cut and paste text (replace) */ | 926 | /* handle p option */ |
| 943 | case 'c': | 927 | if (sed_cmd->sub_p) |
| 944 | /* Only triggers on last line of a matching range. */ | 928 | sed_puts(pattern_space, last_char); |
| 945 | if (!sed_cmd->in_match) | 929 | /* handle w option */ |
| 946 | sed_puts(sed_cmd->string,0); | 930 | if (sed_cmd->file) |
| 947 | goto discard_line; | 931 | sed_cmd->last_char = puts_maybe_newline( |
| 948 | 932 | pattern_space, sed_cmd->file, | |
| 949 | /* Read file, append contents to output */ | 933 | sed_cmd->last_char, last_char); |
| 950 | case 'r': | 934 | break; |
| 951 | { | ||
| 952 | FILE *rfile; | ||
| 953 | 935 | ||
| 954 | rfile = fopen(sed_cmd->string, "r"); | 936 | /* Append line to linked list to be printed later */ |
| 955 | if (rfile) { | 937 | case 'a': |
| 956 | char *line; | 938 | append(sed_cmd->string); |
| 939 | break; | ||
| 957 | 940 | ||
| 958 | while ((line = xmalloc_getline(rfile)) | 941 | /* Insert text before this line */ |
| 959 | != NULL) | 942 | case 'i': |
| 960 | append(line); | 943 | sed_puts(sed_cmd->string, 1); |
| 961 | xprint_and_close_file(rfile); | 944 | break; |
| 962 | } | ||
| 963 | 945 | ||
| 964 | break; | 946 | /* Cut and paste text (replace) */ |
| 947 | case 'c': | ||
| 948 | /* Only triggers on last line of a matching range. */ | ||
| 949 | if (!sed_cmd->in_match) | ||
| 950 | sed_puts(sed_cmd->string, 0); | ||
| 951 | goto discard_line; | ||
| 952 | |||
| 953 | /* Read file, append contents to output */ | ||
| 954 | case 'r': | ||
| 955 | { | ||
| 956 | FILE *rfile; | ||
| 957 | |||
| 958 | rfile = fopen(sed_cmd->string, "r"); | ||
| 959 | if (rfile) { | ||
| 960 | char *line; | ||
| 961 | |||
| 962 | while ((line = xmalloc_getline(rfile)) | ||
| 963 | != NULL) | ||
| 964 | append(line); | ||
| 965 | xprint_and_close_file(rfile); | ||
| 965 | } | 966 | } |
| 966 | 967 | ||
| 967 | /* Write pattern space to file. */ | 968 | break; |
| 968 | case 'w': | 969 | } |
| 969 | sed_cmd->last_char = puts_maybe_newline( | ||
| 970 | pattern_space,sed_cmd->file, | ||
| 971 | sed_cmd->last_char, last_char); | ||
| 972 | break; | ||
| 973 | 970 | ||
| 974 | /* Read next line from input */ | 971 | /* Write pattern space to file. */ |
| 975 | case 'n': | 972 | case 'w': |
| 976 | if (!bbg.be_quiet) | 973 | sed_cmd->last_char = puts_maybe_newline( |
| 977 | sed_puts(pattern_space, last_char); | 974 | pattern_space, sed_cmd->file, |
| 978 | if (next_line) { | 975 | sed_cmd->last_char, last_char); |
| 979 | free(pattern_space); | 976 | break; |
| 980 | pattern_space = next_line; | ||
| 981 | last_char = next_last_char; | ||
| 982 | next_line = get_next_line(&next_last_char); | ||
| 983 | linenum++; | ||
| 984 | break; | ||
| 985 | } | ||
| 986 | /* fall through */ | ||
| 987 | 977 | ||
| 988 | /* Quit. End of script, end of input. */ | 978 | /* Read next line from input */ |
| 989 | case 'q': | 979 | case 'n': |
| 990 | /* Exit the outer while loop */ | 980 | if (!bbg.be_quiet) |
| 981 | sed_puts(pattern_space, last_char); | ||
| 982 | if (next_line) { | ||
| 983 | free(pattern_space); | ||
| 984 | pattern_space = next_line; | ||
| 985 | last_char = next_last_char; | ||
| 986 | next_line = get_next_line(&next_last_char); | ||
| 987 | linenum++; | ||
| 988 | break; | ||
| 989 | } | ||
| 990 | /* fall through */ | ||
| 991 | |||
| 992 | /* Quit. End of script, end of input. */ | ||
| 993 | case 'q': | ||
| 994 | /* Exit the outer while loop */ | ||
| 995 | free(next_line); | ||
| 996 | next_line = NULL; | ||
| 997 | goto discard_commands; | ||
| 998 | |||
| 999 | /* Append the next line to the current line */ | ||
| 1000 | case 'N': | ||
| 1001 | { | ||
| 1002 | int len; | ||
| 1003 | /* If no next line, jump to end of script and exit. */ | ||
| 1004 | if (next_line == NULL) { | ||
| 1005 | /* Jump to end of script and exit */ | ||
| 991 | free(next_line); | 1006 | free(next_line); |
| 992 | next_line = NULL; | 1007 | next_line = NULL; |
| 993 | goto discard_commands; | 1008 | goto discard_line; |
| 994 | 1009 | /* append next_line, read new next_line. */ | |
| 995 | /* Append the next line to the current line */ | ||
| 996 | case 'N': | ||
| 997 | { | ||
| 998 | /* If no next line, jump to end of script and exit. */ | ||
| 999 | if (next_line == NULL) { | ||
| 1000 | /* Jump to end of script and exit */ | ||
| 1001 | free(next_line); | ||
| 1002 | next_line = NULL; | ||
| 1003 | goto discard_line; | ||
| 1004 | /* append next_line, read new next_line. */ | ||
| 1005 | } else { | ||
| 1006 | int len = strlen(pattern_space); | ||
| 1007 | |||
| 1008 | pattern_space = realloc(pattern_space, len + strlen(next_line) + 2); | ||
| 1009 | pattern_space[len] = '\n'; | ||
| 1010 | strcpy(pattern_space + len+1, next_line); | ||
| 1011 | last_char = next_last_char; | ||
| 1012 | next_line = get_next_line(&next_last_char); | ||
| 1013 | linenum++; | ||
| 1014 | } | ||
| 1015 | break; | ||
| 1016 | } | 1010 | } |
| 1011 | len = strlen(pattern_space); | ||
| 1012 | pattern_space = realloc(pattern_space, len + strlen(next_line) + 2); | ||
| 1013 | pattern_space[len] = '\n'; | ||
| 1014 | strcpy(pattern_space + len+1, next_line); | ||
| 1015 | last_char = next_last_char; | ||
| 1016 | next_line = get_next_line(&next_last_char); | ||
| 1017 | linenum++; | ||
| 1018 | break; | ||
| 1019 | } | ||
| 1017 | 1020 | ||
| 1018 | /* Test/branch if substitution occurred */ | 1021 | /* Test/branch if substitution occurred */ |
| 1019 | case 't': | 1022 | case 't': |
| 1020 | if (!substituted) break; | 1023 | if (!substituted) break; |
| 1021 | substituted = 0; | 1024 | substituted = 0; |
| 1022 | /* Fall through */ | 1025 | /* Fall through */ |
| 1023 | /* Test/branch if substitution didn't occur */ | 1026 | /* Test/branch if substitution didn't occur */ |
| 1024 | case 'T': | 1027 | case 'T': |
| 1025 | if (substituted) break; | 1028 | if (substituted) break; |
| 1026 | /* Fall through */ | 1029 | /* Fall through */ |
| 1027 | /* Branch to label */ | 1030 | /* Branch to label */ |
| 1028 | case 'b': | 1031 | case 'b': |
| 1029 | if (!sed_cmd->string) goto discard_commands; | 1032 | if (!sed_cmd->string) goto discard_commands; |
| 1030 | else sed_cmd = branch_to(sed_cmd->string); | 1033 | else sed_cmd = branch_to(sed_cmd->string); |
| 1031 | break; | 1034 | break; |
| 1032 | /* Transliterate characters */ | 1035 | /* Transliterate characters */ |
| 1033 | case 'y': | 1036 | case 'y': |
| 1034 | { | 1037 | { |
| 1035 | int i; | 1038 | int i, j; |
| 1036 | 1039 | ||
| 1037 | for (i = 0; pattern_space[i]; i++) { | 1040 | for (i = 0; pattern_space[i]; i++) { |
| 1038 | int j; | 1041 | for (j = 0; sed_cmd->string[j]; j += 2) { |
| 1039 | 1042 | if (pattern_space[i] == sed_cmd->string[j]) { | |
| 1040 | for (j = 0; sed_cmd->string[j]; j += 2) { | 1043 | pattern_space[i] = sed_cmd->string[j + 1]; |
| 1041 | if (pattern_space[i] == sed_cmd->string[j]) { | 1044 | break; |
| 1042 | pattern_space[i] = sed_cmd->string[j + 1]; | ||
| 1043 | break; | ||
| 1044 | } | ||
| 1045 | } | 1045 | } |
| 1046 | } | 1046 | } |
| 1047 | |||
| 1048 | break; | ||
| 1049 | } | 1047 | } |
| 1050 | case 'g': /* Replace pattern space with hold space */ | ||
| 1051 | free(pattern_space); | ||
| 1052 | pattern_space = xstrdup(bbg.hold_space ? bbg.hold_space : ""); | ||
| 1053 | break; | ||
| 1054 | case 'G': /* Append newline and hold space to pattern space */ | ||
| 1055 | { | ||
| 1056 | int pattern_space_size = 2; | ||
| 1057 | int hold_space_size = 0; | ||
| 1058 | |||
| 1059 | if (pattern_space) | ||
| 1060 | pattern_space_size += strlen(pattern_space); | ||
| 1061 | if (bbg.hold_space) | ||
| 1062 | hold_space_size = strlen(bbg.hold_space); | ||
| 1063 | pattern_space = xrealloc(pattern_space, | ||
| 1064 | pattern_space_size + hold_space_size); | ||
| 1065 | if (pattern_space_size == 2) | ||
| 1066 | pattern_space[0] = 0; | ||
| 1067 | strcat(pattern_space, "\n"); | ||
| 1068 | if (bbg.hold_space) | ||
| 1069 | strcat(pattern_space, bbg.hold_space); | ||
| 1070 | last_char = '\n'; | ||
| 1071 | 1048 | ||
| 1072 | break; | 1049 | break; |
| 1073 | } | 1050 | } |
| 1074 | case 'h': /* Replace hold space with pattern space */ | 1051 | case 'g': /* Replace pattern space with hold space */ |
| 1075 | free(bbg.hold_space); | 1052 | free(pattern_space); |
| 1076 | bbg.hold_space = xstrdup(pattern_space); | 1053 | pattern_space = xstrdup(bbg.hold_space ? bbg.hold_space : ""); |
| 1077 | break; | 1054 | break; |
| 1078 | case 'H': /* Append newline and pattern space to hold space */ | 1055 | case 'G': /* Append newline and hold space to pattern space */ |
| 1079 | { | 1056 | { |
| 1080 | int hold_space_size = 2; | 1057 | int pattern_space_size = 2; |
| 1081 | int pattern_space_size = 0; | 1058 | int hold_space_size = 0; |
| 1082 | 1059 | ||
| 1083 | if (bbg.hold_space) | 1060 | if (pattern_space) |
| 1084 | hold_space_size += strlen(bbg.hold_space); | 1061 | pattern_space_size += strlen(pattern_space); |
| 1085 | if (pattern_space) | 1062 | if (bbg.hold_space) |
| 1086 | pattern_space_size = strlen(pattern_space); | 1063 | hold_space_size = strlen(bbg.hold_space); |
| 1087 | bbg.hold_space = xrealloc(bbg.hold_space, | 1064 | pattern_space = xrealloc(pattern_space, |
| 1088 | hold_space_size + pattern_space_size); | 1065 | pattern_space_size + hold_space_size); |
| 1089 | 1066 | if (pattern_space_size == 2) | |
| 1090 | if (hold_space_size == 2) | 1067 | pattern_space[0] = 0; |
| 1091 | *bbg.hold_space = 0; | 1068 | strcat(pattern_space, "\n"); |
| 1092 | strcat(bbg.hold_space, "\n"); | 1069 | if (bbg.hold_space) |
| 1093 | if (pattern_space) | 1070 | strcat(pattern_space, bbg.hold_space); |
| 1094 | strcat(bbg.hold_space, pattern_space); | 1071 | last_char = '\n'; |
| 1095 | 1072 | ||
| 1096 | break; | 1073 | break; |
| 1097 | } | 1074 | } |
| 1098 | case 'x': /* Exchange hold and pattern space */ | 1075 | case 'h': /* Replace hold space with pattern space */ |
| 1099 | { | 1076 | free(bbg.hold_space); |
| 1100 | char *tmp = pattern_space; | 1077 | bbg.hold_space = xstrdup(pattern_space); |
| 1101 | pattern_space = bbg.hold_space ? : xzalloc(1); | 1078 | break; |
| 1102 | last_char = '\n'; | 1079 | case 'H': /* Append newline and pattern space to hold space */ |
| 1103 | bbg.hold_space = tmp; | 1080 | { |
| 1104 | break; | 1081 | int hold_space_size = 2; |
| 1105 | } | 1082 | int pattern_space_size = 0; |
| 1106 | } | 1083 | |
| 1084 | if (bbg.hold_space) | ||
| 1085 | hold_space_size += strlen(bbg.hold_space); | ||
| 1086 | if (pattern_space) | ||
| 1087 | pattern_space_size = strlen(pattern_space); | ||
| 1088 | bbg.hold_space = xrealloc(bbg.hold_space, | ||
| 1089 | hold_space_size + pattern_space_size); | ||
| 1090 | |||
| 1091 | if (hold_space_size == 2) | ||
| 1092 | *bbg.hold_space = 0; | ||
| 1093 | strcat(bbg.hold_space, "\n"); | ||
| 1094 | if (pattern_space) | ||
| 1095 | strcat(bbg.hold_space, pattern_space); | ||
| 1096 | |||
| 1097 | break; | ||
| 1098 | } | ||
| 1099 | case 'x': /* Exchange hold and pattern space */ | ||
| 1100 | { | ||
| 1101 | char *tmp = pattern_space; | ||
| 1102 | pattern_space = bbg.hold_space ? : xzalloc(1); | ||
| 1103 | last_char = '\n'; | ||
| 1104 | bbg.hold_space = tmp; | ||
| 1105 | break; | ||
| 1106 | } | ||
| 1107 | } | 1107 | } |
| 1108 | } | 1108 | } |
| 1109 | } | ||
| 1109 | 1110 | ||
| 1110 | /* | 1111 | /* |
| 1111 | * exit point from sedding... | 1112 | * exit point from sedding... |
| 1112 | */ | 1113 | */ |
| 1113 | discard_commands: | 1114 | discard_commands: |
| 1114 | /* we will print the line unless we were told to be quiet ('-n') | 1115 | /* we will print the line unless we were told to be quiet ('-n') |
| 1115 | or if the line was suppressed (ala 'd'elete) */ | 1116 | or if the line was suppressed (ala 'd'elete) */ |
| 1116 | if (!bbg.be_quiet) sed_puts(pattern_space, last_char); | 1117 | if (!bbg.be_quiet) sed_puts(pattern_space, last_char); |
| 1117 | 1118 | ||
| 1118 | /* Delete and such jump here. */ | 1119 | /* Delete and such jump here. */ |
| 1119 | discard_line: | 1120 | discard_line: |
| 1120 | flush_append(); | 1121 | flush_append(); |
| 1121 | free(pattern_space); | 1122 | free(pattern_space); |
| 1122 | } | 1123 | |
| 1124 | goto again; | ||
| 1123 | } | 1125 | } |
| 1124 | 1126 | ||
| 1125 | /* It is possible to have a command line argument with embedded | 1127 | /* It is possible to have a command line argument with embedded |
| @@ -1131,7 +1133,7 @@ static void add_cmd_block(char *cmdstr) | |||
| 1131 | char *temp = xstrdup(cmdstr), *temp2 = temp; | 1133 | char *temp = xstrdup(cmdstr), *temp2 = temp; |
| 1132 | 1134 | ||
| 1133 | while (go) { | 1135 | while (go) { |
| 1134 | int len = strcspn(temp2,"\n"); | 1136 | int len = strcspn(temp2, "\n"); |
| 1135 | if (!temp2[len]) go = 0; | 1137 | if (!temp2[len]) go = 0; |
| 1136 | else temp2[len] = 0; | 1138 | else temp2[len] = 0; |
| 1137 | add_cmd(temp2); | 1139 | add_cmd(temp2); |
| @@ -1165,31 +1167,37 @@ static void add_files_link(llist_t *opt_f) | |||
| 1165 | 1167 | ||
| 1166 | int sed_main(int argc, char **argv) | 1168 | int sed_main(int argc, char **argv) |
| 1167 | { | 1169 | { |
| 1170 | enum { | ||
| 1171 | OPT_in_place = 1 << 0, | ||
| 1172 | }; | ||
| 1168 | unsigned opt; | 1173 | unsigned opt; |
| 1169 | llist_t *opt_e, *opt_f; | 1174 | llist_t *opt_e, *opt_f; |
| 1170 | int status = EXIT_SUCCESS; | 1175 | int status = EXIT_SUCCESS; |
| 1171 | 1176 | ||
| 1172 | bbg.sed_cmd_tail=&bbg.sed_cmd_head; | 1177 | bbg.sed_cmd_tail = &bbg.sed_cmd_head; |
| 1173 | 1178 | ||
| 1174 | /* destroy command strings on exit */ | 1179 | /* destroy command strings on exit */ |
| 1175 | if (ENABLE_FEATURE_CLEAN_UP) atexit(sed_free_and_close_stuff); | 1180 | if (ENABLE_FEATURE_CLEAN_UP) atexit(sed_free_and_close_stuff); |
| 1176 | 1181 | ||
| 1177 | /* Lie to autoconf when it starts asking stupid questions. */ | 1182 | /* Lie to autoconf when it starts asking stupid questions. */ |
| 1178 | if (argc==2 && !strcmp(argv[1],"--version")) { | 1183 | if (argc == 2 && !strcmp(argv[1], "--version")) { |
| 1179 | printf("This is not GNU sed version 4.0\n"); | 1184 | puts("This is not GNU sed version 4.0"); |
| 1180 | exit(0); | 1185 | return 0; |
| 1181 | } | 1186 | } |
| 1182 | 1187 | ||
| 1183 | /* do normal option parsing */ | 1188 | /* do normal option parsing */ |
| 1184 | opt_e = opt_f = NULL; | 1189 | opt_e = opt_f = NULL; |
| 1185 | opt_complementary = "e::f::"; /* can occur multiple times */ | 1190 | opt_complementary = "e::f::" /* can occur multiple times */ |
| 1186 | opt = getopt32(argc, argv, "irne:f:", &opt_e, &opt_f); | 1191 | "nn"; /* count -n */ |
| 1187 | if (opt & 0x1) { // -i | 1192 | opt = getopt32(argc, argv, "irne:f:", &opt_e, &opt_f, |
| 1188 | bbg.in_place++; | 1193 | &bbg.be_quiet); /* counter for -n */ |
| 1194 | argc -= optind; | ||
| 1195 | argv += optind; | ||
| 1196 | if (opt & OPT_in_place) { // -i | ||
| 1189 | atexit(cleanup_outname); | 1197 | atexit(cleanup_outname); |
| 1190 | } | 1198 | } |
| 1191 | if (opt & 0x2) bbg.regex_type|=REG_EXTENDED; // -r | 1199 | if (opt & 0x2) bbg.regex_type |= REG_EXTENDED; // -r |
| 1192 | if (opt & 0x4) bbg.be_quiet++; // -n | 1200 | //if (opt & 0x4) bbg.be_quiet++; // -n |
| 1193 | if (opt & 0x8) { // -e | 1201 | if (opt & 0x8) { // -e |
| 1194 | /* getopt32 reverses order of arguments, handle it */ | 1202 | /* getopt32 reverses order of arguments, handle it */ |
| 1195 | add_cmds_link(opt_e); | 1203 | add_cmds_link(opt_e); |
| @@ -1198,12 +1206,12 @@ int sed_main(int argc, char **argv) | |||
| 1198 | /* getopt32 reverses order of arguments, handle it */ | 1206 | /* getopt32 reverses order of arguments, handle it */ |
| 1199 | add_files_link(opt_f); | 1207 | add_files_link(opt_f); |
| 1200 | } | 1208 | } |
| 1201 | /* if we didn't get a pattern from -e or -f, use argv[optind] */ | 1209 | /* if we didn't get a pattern from -e or -f, use argv[0] */ |
| 1202 | if (!(opt & 0x18)) { | 1210 | if (!(opt & 0x18)) { |
| 1203 | if (argv[optind] == NULL) | 1211 | if (!argc) |
| 1204 | bb_show_usage(); | 1212 | bb_show_usage(); |
| 1205 | else | 1213 | add_cmd_block(*argv++); |
| 1206 | add_cmd_block(argv[optind++]); | 1214 | argc--; |
| 1207 | } | 1215 | } |
| 1208 | /* Flush any unfinished commands. */ | 1216 | /* Flush any unfinished commands. */ |
| 1209 | add_cmd(""); | 1217 | add_cmd(""); |
| @@ -1211,11 +1219,11 @@ int sed_main(int argc, char **argv) | |||
| 1211 | /* By default, we write to stdout */ | 1219 | /* By default, we write to stdout */ |
| 1212 | bbg.nonstdout = stdout; | 1220 | bbg.nonstdout = stdout; |
| 1213 | 1221 | ||
| 1214 | /* argv[(optind)..(argc-1)] should be names of file to process. If no | 1222 | /* argv[0..(argc-1)] should be names of file to process. If no |
| 1215 | * files were specified or '-' was specified, take input from stdin. | 1223 | * files were specified or '-' was specified, take input from stdin. |
| 1216 | * Otherwise, we process all the files specified. */ | 1224 | * Otherwise, we process all the files specified. */ |
| 1217 | if (argv[optind] == NULL) { | 1225 | if (argv[0] == NULL) { |
| 1218 | if (bbg.in_place) | 1226 | if (opt & OPT_in_place) |
| 1219 | bb_error_msg_and_die(bb_msg_requires_arg, "-i"); | 1227 | bb_error_msg_and_die(bb_msg_requires_arg, "-i"); |
| 1220 | add_input_file(stdin); | 1228 | add_input_file(stdin); |
| 1221 | process_files(); | 1229 | process_files(); |
| @@ -1223,11 +1231,13 @@ int sed_main(int argc, char **argv) | |||
| 1223 | int i; | 1231 | int i; |
| 1224 | FILE *file; | 1232 | FILE *file; |
| 1225 | 1233 | ||
| 1226 | for (i = optind; i < argc; i++) { | 1234 | for (i = 0; i < argc; i++) { |
| 1227 | struct stat statbuf; | 1235 | struct stat statbuf; |
| 1228 | int nonstdoutfd; | 1236 | int nonstdoutfd; |
| 1229 | 1237 | ||
| 1230 | if (!strcmp(argv[i], "-") && !bbg.in_place) { | 1238 | if (argv[i][0] == '-' && !argv[i][1] |
| 1239 | && !(opt & OPT_in_place) | ||
| 1240 | ) { | ||
| 1231 | add_input_file(stdin); | 1241 | add_input_file(stdin); |
| 1232 | process_files(); | 1242 | process_files(); |
| 1233 | continue; | 1243 | continue; |
| @@ -1237,7 +1247,7 @@ int sed_main(int argc, char **argv) | |||
| 1237 | status = EXIT_FAILURE; | 1247 | status = EXIT_FAILURE; |
| 1238 | continue; | 1248 | continue; |
| 1239 | } | 1249 | } |
| 1240 | if (!bbg.in_place) { | 1250 | if (!(opt & OPT_in_place)) { |
| 1241 | add_input_file(file); | 1251 | add_input_file(file); |
| 1242 | continue; | 1252 | continue; |
| 1243 | } | 1253 | } |
| @@ -1246,12 +1256,12 @@ int sed_main(int argc, char **argv) | |||
| 1246 | nonstdoutfd = mkstemp(bbg.outname); | 1256 | nonstdoutfd = mkstemp(bbg.outname); |
| 1247 | if (-1 == nonstdoutfd) | 1257 | if (-1 == nonstdoutfd) |
| 1248 | bb_error_msg_and_die("no temp file"); | 1258 | bb_error_msg_and_die("no temp file"); |
| 1249 | bbg.nonstdout = fdopen(nonstdoutfd,"w"); | 1259 | bbg.nonstdout = fdopen(nonstdoutfd, "w"); |
| 1250 | 1260 | ||
| 1251 | /* Set permissions of output file */ | 1261 | /* Set permissions of output file */ |
| 1252 | 1262 | ||
| 1253 | fstat(fileno(file),&statbuf); | 1263 | fstat(fileno(file), &statbuf); |
| 1254 | fchmod(nonstdoutfd,statbuf.st_mode); | 1264 | fchmod(nonstdoutfd, statbuf.st_mode); |
| 1255 | add_input_file(file); | 1265 | add_input_file(file); |
| 1256 | process_files(); | 1266 | process_files(); |
| 1257 | fclose(bbg.nonstdout); | 1267 | fclose(bbg.nonstdout); |
| @@ -1259,7 +1269,7 @@ int sed_main(int argc, char **argv) | |||
| 1259 | bbg.nonstdout = stdout; | 1269 | bbg.nonstdout = stdout; |
| 1260 | /* unlink(argv[i]); */ | 1270 | /* unlink(argv[i]); */ |
| 1261 | // FIXME: error check / message? | 1271 | // FIXME: error check / message? |
| 1262 | rename(bbg.outname,argv[i]); | 1272 | rename(bbg.outname, argv[i]); |
| 1263 | free(bbg.outname); | 1273 | free(bbg.outname); |
| 1264 | bbg.outname = 0; | 1274 | bbg.outname = 0; |
| 1265 | } | 1275 | } |
