aboutsummaryrefslogtreecommitdiff
path: root/busybox/editors/sed.c
diff options
context:
space:
mode:
Diffstat (limited to 'busybox/editors/sed.c')
-rw-r--r--busybox/editors/sed.c110
1 files changed, 62 insertions, 48 deletions
diff --git a/busybox/editors/sed.c b/busybox/editors/sed.c
index 3d6871621..992e5711d 100644
--- a/busybox/editors/sed.c
+++ b/busybox/editors/sed.c
@@ -34,7 +34,10 @@
34 resulting sed_cmd_t structures are appended to a linked list 34 resulting sed_cmd_t structures are appended to a linked list
35 (sed_cmd_head/sed_cmd_tail). 35 (sed_cmd_head/sed_cmd_tail).
36 36
37 process_file() does actual sedding, reading data lines from an input FILE * 37 add_input_file() adds a FILE * to the list of input files. We need to
38 know them all ahead of time to find the last line for the $ match.
39
40 process_files() does actual sedding, reading data lines from each input FILE *
38 (which could be stdin) and applying the sed command list (sed_cmd_head) to 41 (which could be stdin) and applying the sed command list (sed_cmd_head) to
39 each of the resulting lines. 42 each of the resulting lines.
40 43
@@ -112,17 +115,20 @@ typedef struct sed_cmd_s {
112 115
113/* globals */ 116/* globals */
114/* options */ 117/* options */
115static int be_quiet = 0, in_place=0, regex_type=0; 118static int be_quiet, in_place, regex_type;
116FILE *nonstdout; 119FILE *nonstdout;
117char *outname; 120char *outname,*hold_space;
118 121
122/* List of input files */
123int input_file_count,current_input_file;
124FILE **input_file_list;
119 125
120static const char bad_format_in_subst[] = 126static const char bad_format_in_subst[] =
121 "bad format in substitution expression"; 127 "bad format in substitution expression";
122const char *const semicolon_whitespace = "; \n\r\t\v"; 128const char *const semicolon_whitespace = "; \n\r\t\v";
123 129
124regmatch_t regmatch[10]; 130regmatch_t regmatch[10];
125static regex_t *previous_regex_ptr = NULL; 131static regex_t *previous_regex_ptr;
126 132
127/* linked list of sed commands */ 133/* linked list of sed commands */
128static sed_cmd_t sed_cmd_head; 134static sed_cmd_t sed_cmd_head;
@@ -169,6 +175,11 @@ static void free_and_close_stuff(void)
169 free(sed_cmd); 175 free(sed_cmd);
170 sed_cmd = sed_cmd_next; 176 sed_cmd = sed_cmd_next;
171 } 177 }
178
179 if(hold_space) free(hold_space);
180
181 while(current_input_file<input_file_count)
182 fclose(input_file_list[current_input_file++]);
172} 183}
173#endif 184#endif
174 185
@@ -563,6 +574,8 @@ void add_cmd(char *cmdstr)
563 } 574 }
564} 575}
565 576
577/* Append to a string, reallocating memory as necessary. */
578
566struct pipeline { 579struct pipeline {
567 char *buf; /* Space to hold string */ 580 char *buf; /* Space to hold string */
568 int idx; /* Space used */ 581 int idx; /* Space used */
@@ -716,20 +729,29 @@ static void flush_append(void)
716 append_head=append_tail=NULL; 729 append_head=append_tail=NULL;
717} 730}
718 731
719/* Get next line of input, flushing append buffer and noting if we hit EOF 732void add_input_file(FILE *file)
720 * without a newline on the last line. 733{
734 input_file_list=xrealloc(input_file_list,(input_file_count+1)*sizeof(FILE *));
735 input_file_list[input_file_count++]=file;
736}
737
738/* Get next line of input from input_file_list, flushing append buffer and
739 * noting if we ran out of files without a newline on the last line we read.
721 */ 740 */
722static char *get_next_line(FILE * file, int *no_newline) 741static char *get_next_line(int *no_newline)
723{ 742{
724 char *temp; 743 char *temp=NULL;
725 int len; 744 int len;
726 745
727 flush_append(); 746 flush_append();
728 temp=bb_get_line_from_file(file); 747 while(current_input_file<input_file_count) {
729 if(temp) { 748 temp=bb_get_line_from_file(input_file_list[current_input_file]);
730 len=strlen(temp); 749 if(temp) {
731 if(len && temp[len-1]=='\n') temp[len-1]=0; 750 len=strlen(temp);
732 else *no_newline=1; 751 *no_newline=!(len && temp[len-1]=='\n');
752 if(!*no_newline) temp[len-1]=0;
753 break;
754 } else fclose(input_file_list[current_input_file++]);
733 } 755 }
734 756
735 return temp; 757 return temp;
@@ -755,15 +777,15 @@ static int puts_maybe_newline(char *s, FILE *file, int missing_newline, int no_n
755 777
756#define sed_puts(s,n) missing_newline=puts_maybe_newline(s,nonstdout,missing_newline,n) 778#define sed_puts(s,n) missing_newline=puts_maybe_newline(s,nonstdout,missing_newline,n)
757 779
758static void process_file(FILE *file) 780static void process_files(void)
759{ 781{
760 char *pattern_space, *next_line, *hold_space=NULL; 782 char *pattern_space, *next_line;
761 static int linenum = 0, missing_newline=0; 783 int linenum = 0, missing_newline=0;
762 int no_newline,next_no_newline=0; 784 int no_newline,next_no_newline=0;
763 785
764 next_line = get_next_line(file,&next_no_newline); 786 next_line = get_next_line(&next_no_newline);
765 787
766 /* go through every line in the file */ 788 /* go through every line in each file */
767 for(;;) { 789 for(;;) {
768 sed_cmd_t *sed_cmd; 790 sed_cmd_t *sed_cmd;
769 int substituted=0; 791 int substituted=0;
@@ -773,7 +795,7 @@ static void process_file(FILE *file)
773 no_newline=next_no_newline; 795 no_newline=next_no_newline;
774 796
775 /* Read one line in advance so we can act on the last line, the '$' address */ 797 /* Read one line in advance so we can act on the last line, the '$' address */
776 next_line = get_next_line(file,&next_no_newline); 798 next_line = get_next_line(&next_no_newline);
777 linenum++; 799 linenum++;
778restart: 800restart:
779 /* for every line, go through all the commands */ 801 /* for every line, go through all the commands */
@@ -908,7 +930,7 @@ restart:
908 /* Cut and paste text (replace) */ 930 /* Cut and paste text (replace) */
909 case 'c': 931 case 'c':
910 /* Only triggers on last line of a matching range. */ 932 /* Only triggers on last line of a matching range. */
911 if (!sed_cmd->in_match) sed_puts(sed_cmd->string,1); 933 if (!sed_cmd->in_match) sed_puts(sed_cmd->string,0);
912 goto discard_line; 934 goto discard_line;
913 935
914 /* Read file, append contents to output */ 936 /* Read file, append contents to output */
@@ -942,7 +964,7 @@ restart:
942 free(pattern_space); 964 free(pattern_space);
943 pattern_space = next_line; 965 pattern_space = next_line;
944 no_newline=next_no_newline; 966 no_newline=next_no_newline;
945 next_line = get_next_line(file,&next_no_newline); 967 next_line = get_next_line(&next_no_newline);
946 linenum++; 968 linenum++;
947 break; 969 break;
948 } 970 }
@@ -972,7 +994,7 @@ restart:
972 pattern_space[len]='\n'; 994 pattern_space[len]='\n';
973 strcpy(pattern_space+len+1, next_line); 995 strcpy(pattern_space+len+1, next_line);
974 no_newline=next_no_newline; 996 no_newline=next_no_newline;
975 next_line = get_next_line(file,&next_no_newline); 997 next_line = get_next_line(&next_no_newline);
976 linenum++; 998 linenum++;
977 } 999 }
978 break; 1000 break;
@@ -1007,10 +1029,7 @@ restart:
1007 } 1029 }
1008 case 'g': /* Replace pattern space with hold space */ 1030 case 'g': /* Replace pattern space with hold space */
1009 free(pattern_space); 1031 free(pattern_space);
1010 if (hold_space) { 1032 pattern_space = strdup(hold_space ? hold_space : "");
1011 pattern_space = strdup(hold_space);
1012 no_newline=0;
1013 }
1014 break; 1033 break;
1015 case 'G': /* Append newline and hold space to pattern space */ 1034 case 'G': /* Append newline and hold space to pattern space */
1016 { 1035 {
@@ -1096,9 +1115,7 @@ static void add_cmd_block(char *cmdstr)
1096 1115
1097extern int sed_main(int argc, char **argv) 1116extern int sed_main(int argc, char **argv)
1098{ 1117{
1099 int status = EXIT_SUCCESS; 1118 int status = EXIT_SUCCESS, opt, getpat = 1;
1100 int opt;
1101 uint8_t getpat = 1;
1102 1119
1103#ifdef CONFIG_FEATURE_CLEAN_UP 1120#ifdef CONFIG_FEATURE_CLEAN_UP
1104 /* destroy command strings on exit */ 1121 /* destroy command strings on exit */
@@ -1153,8 +1170,7 @@ extern int sed_main(int argc, char **argv)
1153 } 1170 }
1154 } 1171 }
1155 1172
1156 /* if we didn't get a pattern from a -e and no command file was specified, 1173 /* if we didn't get a pattern from -e or -f, use argv[optind] */
1157 * argv[optind] should be the pattern. no pattern, no worky */
1158 if(getpat) { 1174 if(getpat) {
1159 if (argv[optind] == NULL) 1175 if (argv[optind] == NULL)
1160 bb_show_usage(); 1176 bb_show_usage();
@@ -1171,49 +1187,47 @@ extern int sed_main(int argc, char **argv)
1171 * files were specified or '-' was specified, take input from stdin. 1187 * files were specified or '-' was specified, take input from stdin.
1172 * Otherwise, we process all the files specified. */ 1188 * Otherwise, we process all the files specified. */
1173 if (argv[optind] == NULL) { 1189 if (argv[optind] == NULL) {
1174 if(in_place) { 1190 if(in_place) bb_error_msg_and_die("Filename required for -i");
1175 fprintf(stderr,"sed: Filename required for -i\n"); 1191 add_input_file(stdin);
1176 exit(1); 1192 process_files();
1177 }
1178 process_file(stdin);
1179 } else { 1193 } else {
1180 int i; 1194 int i;
1181 FILE *file; 1195 FILE *file;
1182 1196
1183 for (i = optind; i < argc; i++) { 1197 for (i = optind; i < argc; i++) {
1184 if(!strcmp(argv[i], "-") && !in_place) { 1198 if(!strcmp(argv[i], "-") && !in_place) {
1185 process_file(stdin); 1199 add_input_file(stdin);
1200 process_files();
1186 } else { 1201 } else {
1187 file = bb_wfopen(argv[i], "r"); 1202 file = bb_wfopen(argv[i], "r");
1188 if (file) { 1203 if (file) {
1189 if(in_place) { 1204 if(in_place) {
1190 struct stat statbuf; 1205 struct stat statbuf;
1206 int nonstdoutfd;
1207
1191 outname=bb_xstrndup(argv[i],strlen(argv[i])+6); 1208 outname=bb_xstrndup(argv[i],strlen(argv[i])+6);
1192 strcat(outname,"XXXXXX"); 1209 strcat(outname,"XXXXXX");
1210 if(-1==(nonstdoutfd=mkstemp(outname)))
1211 bb_error_msg_and_die("no temp file");
1212 nonstdout=fdopen(nonstdoutfd,"w");
1193 /* Set permissions of output file */ 1213 /* Set permissions of output file */
1194 fstat(fileno(file),&statbuf); 1214 fstat(fileno(file),&statbuf);
1195 mkstemp(outname); 1215 fchmod(nonstdoutfd,statbuf.st_mode);
1196 nonstdout=bb_wfopen(outname,"w"); 1216 add_input_file(file);
1197 /* Set permissions of output file */ 1217 process_files();
1198 fstat(fileno(file),&statbuf);
1199 fchmod(fileno(nonstdout),statbuf.st_mode);
1200 atexit(cleanup_outname);
1201 }
1202 process_file(file);
1203 fclose(file);
1204 if(in_place) {
1205 fclose(nonstdout); 1218 fclose(nonstdout);
1206 nonstdout=stdout; 1219 nonstdout=stdout;
1207 unlink(argv[i]); 1220 unlink(argv[i]);
1208 rename(outname,argv[i]); 1221 rename(outname,argv[i]);
1209 free(outname); 1222 free(outname);
1210 outname=0; 1223 outname=0;
1211 } 1224 } else add_input_file(file);
1212 } else { 1225 } else {
1213 status = EXIT_FAILURE; 1226 status = EXIT_FAILURE;
1214 } 1227 }
1215 } 1228 }
1216 } 1229 }
1230 if(input_file_count>current_input_file) process_files();
1217 } 1231 }
1218 1232
1219 return status; 1233 return status;