Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/editors/sed.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/editors/sed.c
r1765 r2725 6 6 * Copyright (C) 1999,2000,2001 by Mark Whitley <markw@codepoet.org> 7 7 * Copyright (C) 2002 Matt Kraai 8 * Copyright (C) 2003 by Glenn McGrath <bug1@iinet.net.au>8 * Copyright (C) 2003 by Glenn McGrath 9 9 * Copyright (C) 2003,2004 by Rob Landley <rob@landley.net> 10 10 * 11 11 * MAINTAINER: Rob Landley <rob@landley.net> 12 12 * 13 * Licensed under GPL version 2, see file LICENSE in this tarball for details.13 * Licensed under GPLv2, see file LICENSE in this source tree. 14 14 */ 15 15 … … 24 24 (G.sed_cmd_head/G.sed_cmd_tail). 25 25 26 add_input_file() adds a FILE 26 add_input_file() adds a FILE* to the list of input files. We need to 27 27 know all input sources ahead of time to find the last line for the $ match. 28 28 … … 62 62 #include "xregex.h" 63 63 64 enum { 65 OPT_in_place = 1 << 0, 66 }; 67 64 68 /* Each sed command turns into one of these structures. */ 65 69 typedef struct sed_cmd_s { … … 77 81 char *string; /* Data string for (saicytb) commands. */ 78 82 79 unsigned short which_match;/* (s) Which match to replace (0 for all) */83 unsigned which_match; /* (s) Which match to replace (0 for all) */ 80 84 81 85 /* Bitfields (gcc won't group them if we don't) */ … … 114 118 115 119 struct pipeline { 116 char *buf; 117 int idx; 118 int len; 120 char *buf; /* Space to hold string */ 121 int idx; /* Space used */ 122 int len; /* Space allocated */ 119 123 } pipeline; 124 } FIX_ALIASING; 125 #define G (*(struct globals*)&bb_common_bufsiz1) 126 struct BUG_G_too_big { 127 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; 120 128 }; 121 #define G (*(struct globals*)&bb_common_bufsiz1)122 void BUG_sed_globals_too_big(void);123 129 #define INIT_G() do { \ 124 if (sizeof(struct globals) > COMMON_BUFSIZE) \125 BUG_sed_globals_too_big(); \126 130 G.sed_cmd_tail = &G.sed_cmd_head; \ 127 131 } while (0) … … 158 162 } 159 163 160 if (G.hold_space)free(G.hold_space);164 free(G.hold_space); 161 165 162 166 while (G.current_input_file < G.input_file_count) … … 174 178 } 175 179 176 /* str dup, replacing "\n" with '\n', and "\delimiter" with 'delimiter' */180 /* strcpy, replacing "\from" with 'to'. If to is NUL, replacing "\any" with 'any' */ 177 181 178 182 static void parse_escapes(char *dest, const char *string, int len, char from, char to) … … 189 193 *dest++ = string[i++]; 190 194 } 195 /* TODO: is it safe wrt a string with trailing '\\' ? */ 191 196 *dest++ = string[i++]; 192 197 } 193 *dest = 0;198 *dest = '\0'; 194 199 } 195 200 … … 199 204 200 205 parse_escapes(dest, string, len, 'n', '\n'); 206 /* GNU sed also recognizes \t */ 207 parse_escapes(dest, dest, strlen(dest), 't', '\t'); 201 208 return dest; 202 209 } … … 206 213 * index_of_next_unescaped_regexp_delim - walks left to right through a string 207 214 * beginning at a specified index and returns the index of the next regular 208 * expression delimiter (typically a forward *slash ('/')) not preceded by215 * expression delimiter (typically a forward slash ('/')) not preceded by 209 216 * a backslash ('\'). A negative delimiter disables square bracket checking. 210 217 */ … … 299 306 300 307 /* Grab a filename. Whitespace at start is skipped, then goes to EOL. */ 301 static int parse_file_cmd( sed_cmd_t *sed_cmd,const char *filecmdstr, char **retval)308 static int parse_file_cmd(/*sed_cmd_t *sed_cmd,*/ const char *filecmdstr, char **retval) 302 309 { 303 310 int start = 0, idx, hack = 0; … … 351 358 const char *pos = substr + idx; 352 359 /* FIXME: error check? */ 353 sed_cmd->which_match = (unsigned short)strtol(substr+idx, (char**) &pos, 10);360 sed_cmd->which_match = (unsigned)strtol(substr+idx, (char**) &pos, 10); 354 361 idx = pos - substr; 355 362 } … … 357 364 } 358 365 /* Skip spaces */ 359 if (isspace(substr[idx])) continue; 366 if (isspace(substr[idx])) 367 continue; 360 368 361 369 switch (substr[idx]) { 362 370 /* Replace all occurrences */ 363 371 case 'g': 364 if (match[0] != '^') sed_cmd->which_match = 0; 372 if (match[0] != '^') 373 sed_cmd->which_match = 0; 365 374 break; 366 375 /* Print pattern space */ … … 372 381 { 373 382 char *temp; 374 idx += parse_file_cmd( sed_cmd,substr+idx, &temp);383 idx += parse_file_cmd(/*sed_cmd,*/ substr+idx, &temp); 375 384 break; 376 385 } … … 381 390 /* Comment */ 382 391 case '#': 383 while (substr[++idx]) /*skip all*/; 392 // while (substr[++idx]) continue; 393 idx += strlen(substr + idx); // same 384 394 /* Fall through */ 385 395 /* End of command */ … … 391 401 } 392 402 } 393 out:403 out: 394 404 /* compile the match string into a regex */ 395 405 if (*match != '\0') { … … 414 424 else if (strchr("aic", sed_cmd->cmd)) { 415 425 if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c') 416 bb_error_msg_and_die 417 ("only a beginning address can be specified for edit commands"); 426 bb_error_msg_and_die("only a beginning address can be specified for edit commands"); 418 427 for (;;) { 419 428 if (*cmdstr == '\n' || *cmdstr == '\\') { 420 429 cmdstr++; 421 430 break; 422 } else if (isspace(*cmdstr)) 423 cmdstr++; 424 else 431 } 432 if (!isspace(*cmdstr)) 425 433 break; 434 cmdstr++; 426 435 } 427 436 sed_cmd->string = xstrdup(cmdstr); 428 parse_escapes(sed_cmd->string, sed_cmd->string, strlen(cmdstr), 0, 0); 437 /* "\anychar" -> "anychar" */ 438 parse_escapes(sed_cmd->string, sed_cmd->string, strlen(cmdstr), '\0', '\0'); 429 439 cmdstr += strlen(cmdstr); 430 440 /* handle file cmds: (r)ead */ … … 432 442 if (sed_cmd->end_line || sed_cmd->end_match) 433 443 bb_error_msg_and_die("command only uses one address"); 434 cmdstr += parse_file_cmd( sed_cmd,cmdstr, &sed_cmd->string);444 cmdstr += parse_file_cmd(/*sed_cmd,*/ cmdstr, &sed_cmd->string); 435 445 if (sed_cmd->cmd == 'w') { 436 sed_cmd->sw_file = xfopen (sed_cmd->string, "w");446 sed_cmd->sw_file = xfopen_for_write(sed_cmd->string); 437 447 sed_cmd->sw_last_char = '\n'; 438 448 } … … 483 493 { 484 494 sed_cmd_t *sed_cmd; 485 int temp;495 unsigned len, n; 486 496 487 497 /* Append this line to any unfinished line from last time. */ … … 492 502 } 493 503 494 /* If this line ends with backslash, request next line. */ 495 temp = strlen(cmdstr); 496 if (temp && cmdstr[--temp] == '\\') { 504 /* If this line ends with unescaped backslash, request next line. */ 505 n = len = strlen(cmdstr); 506 while (n && cmdstr[n-1] == '\\') 507 n--; 508 if ((len - n) & 1) { /* if odd number of trailing backslashes */ 497 509 if (!G.add_cmd_line) 498 510 G.add_cmd_line = xstrdup(cmdstr); 499 G.add_cmd_line[ temp] = '\0';511 G.add_cmd_line[len-1] = '\0'; 500 512 return; 501 513 } … … 556 568 if (!*cmdstr) 557 569 bb_error_msg_and_die("missing command"); 558 sed_cmd->cmd = * (cmdstr++);570 sed_cmd->cmd = *cmdstr++; 559 571 cmdstr = parse_cmd_args(sed_cmd, cmdstr); 560 572 … … 585 597 static void do_subst_w_backrefs(char *line, char *replace) 586 598 { 587 int i, j;599 int i, j; 588 600 589 601 /* go through the replacement string */ … … 620 632 } 621 633 622 static int do_subst_command(sed_cmd_t *sed_cmd, char **line )623 { 624 char * oldline = *line;634 static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) 635 { 636 char *line = *line_p; 625 637 int altered = 0; 626 intmatch_count = 0;638 unsigned match_count = 0; 627 639 regex_t *current_regex; 628 640 641 current_regex = sed_cmd->sub_match; 629 642 /* Handle empty regex. */ 630 if ( sed_cmd->sub_match == NULL) {643 if (!current_regex) { 631 644 current_regex = G.previous_regex_ptr; 632 645 if (!current_regex) 633 646 bb_error_msg_and_die("no previous regexp"); 634 } else635 G.previous_regex_ptr = current_regex = sed_cmd->sub_match;647 } 648 G.previous_regex_ptr = current_regex; 636 649 637 650 /* Find the first match */ 638 if (REG_NOMATCH == regexec(current_regex, oldline, 10, G.regmatch, 0))651 if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0)) 639 652 return 0; 640 653 … … 653 666 echo "hi" | busybox sed 's/^/!/g' */ 654 667 if (!G.regmatch[0].rm_so && !G.regmatch[0].rm_eo && match_count) { 655 pipe_putc(* oldline++);668 pipe_putc(*line++); 656 669 continue; 657 670 } … … 661 674 /* If we aren't interested in this match, output old line to 662 675 end of match and continue */ 663 if (sed_cmd->which_match && sed_cmd->which_match != match_count) { 676 if (sed_cmd->which_match 677 && (sed_cmd->which_match != match_count) 678 ) { 664 679 for (i = 0; i < G.regmatch[0].rm_eo; i++) 665 pipe_putc(* oldline++);680 pipe_putc(*line++); 666 681 continue; 667 682 } … … 669 684 /* print everything before the match */ 670 685 for (i = 0; i < G.regmatch[0].rm_so; i++) 671 pipe_putc( oldline[i]);686 pipe_putc(line[i]); 672 687 673 688 /* then print the substitution string */ 674 do_subst_w_backrefs( oldline, sed_cmd->string);689 do_subst_w_backrefs(line, sed_cmd->string); 675 690 676 691 /* advance past the match */ 677 oldline += G.regmatch[0].rm_eo;692 line += G.regmatch[0].rm_eo; 678 693 /* flag that something has changed */ 679 694 altered++; 680 695 681 696 /* if we're not doing this globally, get out now */ 682 if (sed_cmd->which_match) break; 683 } while (*oldline && (regexec(current_regex, oldline, 10, G.regmatch, 0) != REG_NOMATCH)); 697 if (sed_cmd->which_match) 698 break; 699 700 //maybe (G.regmatch[0].rm_eo ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL? 701 } while (*line && regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH); 684 702 685 703 /* Copy rest of string into output pipeline */ 686 687 while (*oldline) 688 pipe_putc(*oldline++); 689 pipe_putc(0); 690 691 free(*line); 692 *line = G.pipeline.buf; 704 while (1) { 705 char c = *line++; 706 pipe_putc(c); 707 if (c == '\0') 708 break; 709 } 710 711 free(*line_p); 712 *line_p = G.pipeline.buf; 693 713 return altered; 694 714 } … … 725 745 static void add_input_file(FILE *file) 726 746 { 727 G.input_file_list = xrealloc(G.input_file_list, 728 (G.input_file_count + 1) * sizeof(FILE *)); 747 G.input_file_list = xrealloc_vector(G.input_file_list, 2, G.input_file_count); 729 748 G.input_file_list[G.input_file_count++] = file; 730 749 } … … 859 878 next_line = get_next_line(&next_gets_char); 860 879 861 /* go through every line in each file */862 again:880 /* Go through every line in each file */ 881 again: 863 882 substituted = 0; 864 883 865 884 /* Advance to next line. Stop if out of lines. */ 866 885 pattern_space = next_line; 867 if (!pattern_space) return; 886 if (!pattern_space) 887 return; 868 888 last_gets_char = next_gets_char; 869 889 … … 872 892 next_line = get_next_line(&next_gets_char); 873 893 linenum++; 874 restart: 875 /* for every line, go through all the commands */ 894 895 /* For every line, go through all the commands */ 896 restart: 876 897 for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) { 877 898 int old_matched, matched; … … 880 901 881 902 /* Determine if this command matches this line: */ 903 904 //bb_error_msg("match1:%d", sed_cmd->in_match); 905 //bb_error_msg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line 906 // && !sed_cmd->beg_match && !sed_cmd->end_match)); 907 //bb_error_msg("match3:%d", (sed_cmd->beg_line > 0 908 // && (sed_cmd->end_line || sed_cmd->end_match 909 // ? (sed_cmd->beg_line <= linenum) 910 // : (sed_cmd->beg_line == linenum) 911 // ) 912 // ) 913 //bb_error_msg("match4:%d", (beg_match(sed_cmd, pattern_space))); 914 //bb_error_msg("match5:%d", (sed_cmd->beg_line == -1 && next_line == NULL)); 882 915 883 916 /* Are we continuing a previous multi-line match? */ … … 887 920 && !sed_cmd->beg_match && !sed_cmd->end_match) 888 921 /* Or did we match the start of a numerical range? */ 889 || (sed_cmd->beg_line > 0 && (sed_cmd->beg_line == linenum)) 922 || (sed_cmd->beg_line > 0 923 && (sed_cmd->end_line || sed_cmd->end_match 924 /* note: even if end is numeric and is < linenum too, 925 * GNU sed matches! We match too */ 926 ? (sed_cmd->beg_line <= linenum) /* N,end */ 927 : (sed_cmd->beg_line == linenum) /* N */ 928 ) 929 ) 890 930 /* Or does this line match our begin address regex? */ 891 931 || (beg_match(sed_cmd, pattern_space)) … … 894 934 895 935 /* Snapshot the value */ 896 897 936 matched = sed_cmd->in_match; 898 937 938 //bb_error_msg("cmd:'%c' matched:%d beg_line:%d end_line:%d linenum:%d", 939 //sed_cmd->cmd, matched, sed_cmd->beg_line, sed_cmd->end_line, linenum); 940 899 941 /* Is this line the end of the current match? */ 900 942 901 943 if (matched) { 944 /* once matched, "n,xxx" range is dead, disabling it */ 945 if (sed_cmd->beg_line > 0 946 && !(option_mask32 & OPT_in_place) /* but not for -i */ 947 ) { 948 sed_cmd->beg_line = -2; 949 } 902 950 sed_cmd->in_match = !( 903 951 /* has the ending line come, or is this a single address command? */ … … 915 963 } 916 964 917 /* Skip blocks of commands we didn't match .*/965 /* Skip blocks of commands we didn't match */ 918 966 if (sed_cmd->cmd == '{') { 919 967 if (sed_cmd->invert ? matched : !matched) { 920 while (sed_cmd->cmd != '}') { 968 unsigned nest_cnt = 0; 969 while (1) { 970 if (sed_cmd->cmd == '{') 971 nest_cnt++; 972 if (sed_cmd->cmd == '}') { 973 nest_cnt--; 974 if (nest_cnt == 0) 975 break; 976 } 921 977 sed_cmd = sed_cmd->next; 922 978 if (!sed_cmd) … … 928 984 929 985 /* Okay, so did this line match? */ 930 if (sed_cmd->invert ? !matched : matched) { 931 /* Update last used regex in case a blank substitute BRE is found */ 932 if (sed_cmd->beg_match) { 933 G.previous_regex_ptr = sed_cmd->beg_match; 934 } 935 936 /* actual sedding */ 937 switch (sed_cmd->cmd) { 938 939 /* Print line number */ 940 case '=': 941 fprintf(G.nonstdout, "%d\n", linenum); 986 if (sed_cmd->invert ? matched : !matched) 987 continue; /* no */ 988 989 /* Update last used regex in case a blank substitute BRE is found */ 990 if (sed_cmd->beg_match) { 991 G.previous_regex_ptr = sed_cmd->beg_match; 992 } 993 994 /* actual sedding */ 995 //bb_error_msg("pattern_space:'%s' next_line:'%s' cmd:%c", 996 //pattern_space, next_line, sed_cmd->cmd); 997 switch (sed_cmd->cmd) { 998 999 /* Print line number */ 1000 case '=': 1001 fprintf(G.nonstdout, "%d\n", linenum); 1002 break; 1003 1004 /* Write the current pattern space up to the first newline */ 1005 case 'P': 1006 { 1007 char *tmp = strchr(pattern_space, '\n'); 1008 if (tmp) { 1009 *tmp = '\0'; 1010 /* TODO: explain why '\n' below */ 1011 sed_puts(pattern_space, '\n'); 1012 *tmp = '\n'; 942 1013 break; 943 944 /* Write the current pattern space up to the first newline */ 945 case 'P': 946 { 947 char *tmp = strchr(pattern_space, '\n'); 948 949 if (tmp) { 950 *tmp = '\0'; 951 /* TODO: explain why '\n' below */ 952 sed_puts(pattern_space, '\n'); 953 *tmp = '\n'; 954 break; 955 } 956 /* Fall Through */ 957 } 958 959 /* Write the current pattern space to output */ 960 case 'p': 961 /* NB: we print this _before_ the last line 962 * (of current file) is printed. Even if 963 * that line is nonterminated, we print 964 * '\n' here (gnu sed does the same) */ 965 sed_puts(pattern_space, '\n'); 1014 } 1015 /* Fall Through */ 1016 } 1017 1018 /* Write the current pattern space to output */ 1019 case 'p': 1020 /* NB: we print this _before_ the last line 1021 * (of current file) is printed. Even if 1022 * that line is nonterminated, we print 1023 * '\n' here (gnu sed does the same) */ 1024 sed_puts(pattern_space, '\n'); 1025 break; 1026 /* Delete up through first newline */ 1027 case 'D': 1028 { 1029 char *tmp = strchr(pattern_space, '\n'); 1030 if (tmp) { 1031 overlapping_strcpy(pattern_space, tmp + 1); 1032 goto restart; 1033 } 1034 } 1035 /* discard this line. */ 1036 case 'd': 1037 goto discard_line; 1038 1039 /* Substitute with regex */ 1040 case 's': 1041 if (!do_subst_command(sed_cmd, &pattern_space)) 966 1042 break; 967 /* Delete up through first newline */ 968 case 'D': 969 { 970 char *tmp = strchr(pattern_space, '\n'); 971 972 if (tmp) { 973 tmp = xstrdup(tmp+1); 974 free(pattern_space); 975 pattern_space = tmp; 976 goto restart; 977 } 978 } 979 /* discard this line. */ 980 case 'd': 981 goto discard_line; 982 983 /* Substitute with regex */ 984 case 's': 985 if (!do_subst_command(sed_cmd, &pattern_space)) 986 break; 987 substituted |= 1; 988 989 /* handle p option */ 990 if (sed_cmd->sub_p) 991 sed_puts(pattern_space, last_gets_char); 992 /* handle w option */ 993 if (sed_cmd->sw_file) 994 puts_maybe_newline( 995 pattern_space, sed_cmd->sw_file, 996 &sed_cmd->sw_last_char, last_gets_char); 997 break; 998 999 /* Append line to linked list to be printed later */ 1000 case 'a': 1001 append(sed_cmd->string); 1002 break; 1003 1004 /* Insert text before this line */ 1005 case 'i': 1006 sed_puts(sed_cmd->string, '\n'); 1007 break; 1008 1009 /* Cut and paste text (replace) */ 1010 case 'c': 1011 /* Only triggers on last line of a matching range. */ 1012 if (!sed_cmd->in_match) 1013 sed_puts(sed_cmd->string, NO_EOL_CHAR); 1014 goto discard_line; 1015 1016 /* Read file, append contents to output */ 1017 case 'r': 1018 { 1019 FILE *rfile; 1020 1021 rfile = fopen(sed_cmd->string, "r"); 1022 if (rfile) { 1023 char *line; 1024 1025 while ((line = xmalloc_getline(rfile)) 1026 != NULL) 1027 append(line); 1028 xprint_and_close_file(rfile); 1029 } 1030 1031 break; 1032 } 1033 1034 /* Write pattern space to file. */ 1035 case 'w': 1043 substituted |= 1; 1044 1045 /* handle p option */ 1046 if (sed_cmd->sub_p) 1047 sed_puts(pattern_space, last_gets_char); 1048 /* handle w option */ 1049 if (sed_cmd->sw_file) 1036 1050 puts_maybe_newline( 1037 1051 pattern_space, sed_cmd->sw_file, 1038 1052 &sed_cmd->sw_last_char, last_gets_char); 1039 break; 1040 1041 /* Read next line from input */ 1042 case 'n': 1043 if (!G.be_quiet) 1044 sed_puts(pattern_space, last_gets_char); 1045 if (next_line) { 1046 free(pattern_space); 1047 pattern_space = next_line; 1048 last_gets_char = next_gets_char; 1049 next_line = get_next_line(&next_gets_char); 1050 linenum++; 1051 break; 1052 } 1053 /* fall through */ 1054 1055 /* Quit. End of script, end of input. */ 1056 case 'q': 1057 /* Exit the outer while loop */ 1058 free(next_line); 1059 next_line = NULL; 1060 goto discard_commands; 1061 1062 /* Append the next line to the current line */ 1063 case 'N': 1064 { 1065 int len; 1066 /* If no next line, jump to end of script and exit. */ 1067 if (next_line == NULL) { 1068 /* Jump to end of script and exit */ 1069 free(next_line); 1070 next_line = NULL; 1071 goto discard_line; 1072 /* append next_line, read new next_line. */ 1073 } 1074 len = strlen(pattern_space); 1075 pattern_space = realloc(pattern_space, len + strlen(next_line) + 2); 1076 pattern_space[len] = '\n'; 1077 strcpy(pattern_space + len+1, next_line); 1053 break; 1054 1055 /* Append line to linked list to be printed later */ 1056 case 'a': 1057 append(sed_cmd->string); 1058 break; 1059 1060 /* Insert text before this line */ 1061 case 'i': 1062 sed_puts(sed_cmd->string, '\n'); 1063 break; 1064 1065 /* Cut and paste text (replace) */ 1066 case 'c': 1067 /* Only triggers on last line of a matching range. */ 1068 if (!sed_cmd->in_match) 1069 sed_puts(sed_cmd->string, '\n'); 1070 goto discard_line; 1071 1072 /* Read file, append contents to output */ 1073 case 'r': 1074 { 1075 FILE *rfile; 1076 rfile = fopen_for_read(sed_cmd->string); 1077 if (rfile) { 1078 char *line; 1079 1080 while ((line = xmalloc_fgetline(rfile)) 1081 != NULL) 1082 append(line); 1083 xprint_and_close_file(rfile); 1084 } 1085 1086 break; 1087 } 1088 1089 /* Write pattern space to file. */ 1090 case 'w': 1091 puts_maybe_newline( 1092 pattern_space, sed_cmd->sw_file, 1093 &sed_cmd->sw_last_char, last_gets_char); 1094 break; 1095 1096 /* Read next line from input */ 1097 case 'n': 1098 if (!G.be_quiet) 1099 sed_puts(pattern_space, last_gets_char); 1100 if (next_line) { 1101 free(pattern_space); 1102 pattern_space = next_line; 1078 1103 last_gets_char = next_gets_char; 1079 1104 next_line = get_next_line(&next_gets_char); 1105 substituted = 0; 1080 1106 linenum++; 1081 1107 break; 1082 1108 } 1083 1084 /* Test/branch if substitution occurred */ 1085 case 't': 1086 if (!substituted) break; 1087 substituted = 0; 1088 /* Fall through */ 1089 /* Test/branch if substitution didn't occur */ 1090 case 'T': 1091 if (substituted) break; 1092 /* Fall through */ 1093 /* Branch to label */ 1094 case 'b': 1095 if (!sed_cmd->string) goto discard_commands; 1096 else sed_cmd = branch_to(sed_cmd->string); 1097 break; 1098 /* Transliterate characters */ 1099 case 'y': 1100 { 1101 int i, j; 1102 1103 for (i = 0; pattern_space[i]; i++) { 1104 for (j = 0; sed_cmd->string[j]; j += 2) { 1105 if (pattern_space[i] == sed_cmd->string[j]) { 1106 pattern_space[i] = sed_cmd->string[j + 1]; 1107 break; 1108 } 1109 /* fall through */ 1110 1111 /* Quit. End of script, end of input. */ 1112 case 'q': 1113 /* Exit the outer while loop */ 1114 free(next_line); 1115 next_line = NULL; 1116 goto discard_commands; 1117 1118 /* Append the next line to the current line */ 1119 case 'N': 1120 { 1121 int len; 1122 /* If no next line, jump to end of script and exit. */ 1123 /* http://www.gnu.org/software/sed/manual/sed.html: 1124 * "Most versions of sed exit without printing anything 1125 * when the N command is issued on the last line of 1126 * a file. GNU sed prints pattern space before exiting 1127 * unless of course the -n command switch has been 1128 * specified. This choice is by design." 1129 */ 1130 if (next_line == NULL) { 1131 //goto discard_line; 1132 goto discard_commands; /* GNU behavior */ 1133 } 1134 /* Append next_line, read new next_line. */ 1135 len = strlen(pattern_space); 1136 pattern_space = xrealloc(pattern_space, len + strlen(next_line) + 2); 1137 pattern_space[len] = '\n'; 1138 strcpy(pattern_space + len+1, next_line); 1139 last_gets_char = next_gets_char; 1140 next_line = get_next_line(&next_gets_char); 1141 linenum++; 1142 break; 1143 } 1144 1145 /* Test/branch if substitution occurred */ 1146 case 't': 1147 if (!substituted) break; 1148 substituted = 0; 1149 /* Fall through */ 1150 /* Test/branch if substitution didn't occur */ 1151 case 'T': 1152 if (substituted) break; 1153 /* Fall through */ 1154 /* Branch to label */ 1155 case 'b': 1156 if (!sed_cmd->string) goto discard_commands; 1157 else sed_cmd = branch_to(sed_cmd->string); 1158 break; 1159 /* Transliterate characters */ 1160 case 'y': 1161 { 1162 int i, j; 1163 for (i = 0; pattern_space[i]; i++) { 1164 for (j = 0; sed_cmd->string[j]; j += 2) { 1165 if (pattern_space[i] == sed_cmd->string[j]) { 1166 pattern_space[i] = sed_cmd->string[j + 1]; 1167 break; 1109 1168 } 1110 1169 } 1111 1112 break; 1113 }1114 case 'g': /* Replace pattern space with hold space */1115 free(pattern_space);1116 pattern_space = xstrdup(G.hold_space ? G.hold_space : "");1117 break;1118 case 'G': /* Append newline and hold space to pattern space */1119 {1120 int pattern_space_size = 2;1121 int hold_space_size = 0;1122 1123 if (pattern_space) 1124 pattern_space_size += strlen(pattern_space);1125 if (G.hold_space)1126 hold_space_size = strlen(G.hold_space);1127 pattern_space = xrealloc(pattern_space,1128 pattern_space_size + hold_space_size);1129 if (pattern_space_size == 2)1130 pattern_space[0] = 0;1131 strcat(pattern_space, "\n");1132 if (G.hold_space)1133 strcat(pattern_space, G.hold_space);1134 last_gets_char = '\n';1135 1136 break; 1137 }1138 case 'h': /* Replace hold space with pattern space */1139 free(G.hold_space);1140 G.hold_space = xstrdup(pattern_space);1141 break;1142 case 'H': /* Append newline and pattern space to hold space */1143 {1144 int hold_space_size = 2;1145 int pattern_space_size = 0;1146 1147 if (G.hold_space) 1148 hold_space_size += strlen(G.hold_space);1149 if (pattern_space)1150 pattern_space_size = strlen(pattern_space);1151 G.hold_space = xrealloc(G.hold_space,1152 hold_space_size + pattern_space_size);1153 1154 if (hold_space_size == 2) 1155 *G.hold_space = 0;1156 strcat(G.hold_space, "\n");1157 if (pattern_space)1158 strcat(G.hold_space, pattern_space);1159 1160 break; 1161 }1162 case 'x': /* Exchange hold and pattern space */1163 {1164 char *tmp = pattern_space;1165 pattern_space = G.hold_space ? : xzalloc(1);1166 last_gets_char = '\n';1167 G.hold_space = tmp;1168 break;1169 }1170 1171 } 1172 } 1170 } 1171 1172 break; 1173 } 1174 case 'g': /* Replace pattern space with hold space */ 1175 free(pattern_space); 1176 pattern_space = xstrdup(G.hold_space ? G.hold_space : ""); 1177 break; 1178 case 'G': /* Append newline and hold space to pattern space */ 1179 { 1180 int pattern_space_size = 2; 1181 int hold_space_size = 0; 1182 1183 if (pattern_space) 1184 pattern_space_size += strlen(pattern_space); 1185 if (G.hold_space) 1186 hold_space_size = strlen(G.hold_space); 1187 pattern_space = xrealloc(pattern_space, 1188 pattern_space_size + hold_space_size); 1189 if (pattern_space_size == 2) 1190 pattern_space[0] = 0; 1191 strcat(pattern_space, "\n"); 1192 if (G.hold_space) 1193 strcat(pattern_space, G.hold_space); 1194 last_gets_char = '\n'; 1195 1196 break; 1197 } 1198 case 'h': /* Replace hold space with pattern space */ 1199 free(G.hold_space); 1200 G.hold_space = xstrdup(pattern_space); 1201 break; 1202 case 'H': /* Append newline and pattern space to hold space */ 1203 { 1204 int hold_space_size = 2; 1205 int pattern_space_size = 0; 1206 1207 if (G.hold_space) 1208 hold_space_size += strlen(G.hold_space); 1209 if (pattern_space) 1210 pattern_space_size = strlen(pattern_space); 1211 G.hold_space = xrealloc(G.hold_space, 1212 hold_space_size + pattern_space_size); 1213 1214 if (hold_space_size == 2) 1215 *G.hold_space = 0; 1216 strcat(G.hold_space, "\n"); 1217 if (pattern_space) 1218 strcat(G.hold_space, pattern_space); 1219 1220 break; 1221 } 1222 case 'x': /* Exchange hold and pattern space */ 1223 { 1224 char *tmp = pattern_space; 1225 pattern_space = G.hold_space ? G.hold_space : xzalloc(1); 1226 last_gets_char = '\n'; 1227 G.hold_space = tmp; 1228 break; 1229 } 1230 } /* switch */ 1231 } /* for each cmd */ 1173 1232 1174 1233 /* 1175 * exit point from sedding...1234 * Exit point from sedding... 1176 1235 */ 1177 1236 discard_commands: … … 1212 1271 /* Odd number of preceding slashes - newline is escaped */ 1213 1272 if (slashes & 1) { 1214 strcpy(eol-1, eol);1273 overlapping_strcpy(eol - 1, eol); 1215 1274 eol = strchr(eol, '\n'); 1216 1275 goto next; … … 1224 1283 } 1225 1284 1226 int sed_main(int argc, char **argv); 1227 int sed_main(int argc, char **argv) 1228 { 1229 enum { 1230 OPT_in_place = 1 << 0, 1231 }; 1285 int sed_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1286 int sed_main(int argc UNUSED_PARAM, char **argv) 1287 { 1232 1288 unsigned opt; 1233 1289 llist_t *opt_e, *opt_f; … … 1240 1296 1241 1297 /* Lie to autoconf when it starts asking stupid questions. */ 1242 if (arg c == 2&& !strcmp(argv[1], "--version")) {1298 if (argv[1] && !strcmp(argv[1], "--version")) { 1243 1299 puts("This is not GNU sed version 4.0"); 1244 1300 return 0; … … 1249 1305 opt_complementary = "e::f::" /* can occur multiple times */ 1250 1306 "nn"; /* count -n */ 1307 /* -i must be first, to match OPT_in_place definition */ 1251 1308 opt = getopt32(argv, "irne:f:", &opt_e, &opt_f, 1252 1309 &G.be_quiet); /* counter for -n */ 1253 argc -= optind;1310 //argc -= optind; 1254 1311 argv += optind; 1255 1312 if (opt & OPT_in_place) { // -i … … 1259 1316 //if (opt & 0x4) G.be_quiet++; // -n 1260 1317 while (opt_e) { // -e 1261 add_cmd_block(opt_e->data); 1262 opt_e = opt_e->link; 1263 /* we leak opt_e here... */ 1318 add_cmd_block(llist_pop(&opt_e)); 1264 1319 } 1265 1320 while (opt_f) { // -f 1266 1321 char *line; 1267 1322 FILE *cmdfile; 1268 cmdfile = xfopen (opt_f->data, "r");1269 while ((line = xmalloc_ getline(cmdfile)) != NULL) {1323 cmdfile = xfopen_for_read(llist_pop(&opt_f)); 1324 while ((line = xmalloc_fgetline(cmdfile)) != NULL) { 1270 1325 add_cmd(line); 1271 1326 free(line); 1272 1327 } 1273 1328 fclose(cmdfile); 1274 opt_f = opt_f->link;1275 /* we leak opt_f here... */1276 1329 } 1277 1330 /* if we didn't get a pattern from -e or -f, use argv[0] */ 1278 1331 if (!(opt & 0x18)) { 1279 if (! argc)1332 if (!*argv) 1280 1333 bb_show_usage(); 1281 1334 add_cmd_block(*argv++); 1282 argc--;1283 1335 } 1284 1336 /* Flush any unfinished commands. */ … … 1295 1347 bb_error_msg_and_die(bb_msg_requires_arg, "-i"); 1296 1348 add_input_file(stdin); 1297 process_files();1298 1349 } else { 1299 1350 int i; 1300 1351 FILE *file; 1301 1352 1302 for (i = 0; i < argc; i++) {1353 for (i = 0; argv[i]; i++) { 1303 1354 struct stat statbuf; 1304 1355 int nonstdoutfd; … … 1320 1371 1321 1372 G.outname = xasprintf("%sXXXXXX", argv[i]); 1322 nonstdoutfd = mkstemp(G.outname); 1323 if (-1 == nonstdoutfd) 1324 bb_perror_msg_and_die("cannot create temp file %s", G.outname); 1325 G.nonstdout = fdopen(nonstdoutfd, "w"); 1326 1327 /* Set permissions of output file */ 1328 1373 nonstdoutfd = xmkstemp(G.outname); 1374 G.nonstdout = xfdopen_for_write(nonstdoutfd); 1375 1376 /* Set permissions/owner of output file */ 1329 1377 fstat(fileno(file), &statbuf); 1378 /* chmod'ing AFTER chown would preserve suid/sgid bits, 1379 * but GNU sed 4.2.1 does not preserve them either */ 1330 1380 fchmod(nonstdoutfd, statbuf.st_mode); 1381 fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid); 1331 1382 add_input_file(file); 1332 1383 process_files(); … … 1335 1386 G.nonstdout = stdout; 1336 1387 /* unlink(argv[i]); */ 1337 // FIXME: error check / message? 1338 rename(G.outname, argv[i]); 1388 xrename(G.outname, argv[i]); 1339 1389 free(G.outname); 1340 G.outname = 0; 1341 } 1342 if (G.input_file_count > G.current_input_file) 1343 process_files(); 1344 } 1390 G.outname = NULL; 1391 } 1392 /* Here, to handle "sed 'cmds' nonexistent_file" case we did: 1393 * if (G.current_input_file >= G.input_file_count) 1394 * return status; 1395 * but it's not needed since process_files() works correctly 1396 * in this case too. */ 1397 } 1398 process_files(); 1345 1399 1346 1400 return status;
Note:
See TracChangeset
for help on using the changeset viewer.