[BusyBox] Sed -i support.

Rob Landley rob at landley.net
Tue Feb 17 10:04:20 UTC 2004


Well, there's bound to be something wrong with it since it debugged way
too easy, but here's the patch adding -i support to sed.

Notice that -i is a global option, applying to every file listed even if
there are more than one.

Bugs in gnu sed's -i option:
  If you fill up the disk, the temp file isn't deleted.
Differences between gnu sed -i and busybox sed -i:
  "sed -i -" creates an empty - file.
  "busybox sed -i -" complains "-: no such file or directory"

I know I should use a better error message function on line 1161,
but I don't know what it is.

Rob

--- busybox/editors/sed.c	2004-02-04 04:57:46.000000000 -0600
+++ busybox.sed/editors/sed.c	2004-02-17 03:53:54.616241168 -0600
@@ -111,7 +111,10 @@
 
 /* globals */
 /* options */
-static int be_quiet = 0;
+static int be_quiet = 0, in_place=0;
+FILE *nonstdout;
+char *outname;
+
 
 static const char bad_format_in_subst[] =
 	"bad format in substitution expression";
@@ -168,6 +171,13 @@
 }
 #endif
 
+/* If something bad happens during -i operation, delete temp file */
+
+static void cleanup_outname(void)
+{
+  if(outname) unlink(outname);
+}
+
 /* strdup, replacing "\n" with '\n', and "\delimiter" with 'delimiter' */
 
 static void parse_escapes(char *dest, const char *string, int len, char from, char to)
@@ -690,7 +700,7 @@
 {
 	/* Output appended lines. */
 	while(append_head) {
-		puts(append_head->string);
+		fprintf(nonstdout,"%s\n",append_head->string);
 		append_tail=append_head->next;
 		free(append_head->string);
 		free(append_head);
@@ -728,12 +738,17 @@
 	fputs(s,file);
 	if(!no_newline) fputc('\n',file);
 
+    if(ferror(file)) {
+		fprintf(stderr,"Write failed.\n");
+		exit(4);  /* It's what gnu sed exits with... */
+	}
+
 	return no_newline;
 }
 
-#define sed_puts(s,n) missing_newline=puts_maybe_newline(s,stdout,missing_newline,n)
+#define sed_puts(s,n) missing_newline=puts_maybe_newline(s,nonstdout,missing_newline,n)
 
-static void process_file(FILE * file)
+static void process_file(FILE *file)
 {
 	char *pattern_space, *next_line, *hold_space=NULL;
 	static int linenum = 0, missing_newline=0;
@@ -819,7 +834,7 @@
 
 					/* Print line number */
 					case '=':
-						printf("%d\n", linenum);
+						fprintf(nonstdout,"%d\n", linenum);
 						break;
 
 					/* Write the current pattern space up to the first newline */
@@ -1091,8 +1106,12 @@
 #endif
 
 	/* do normal option parsing */
-	while ((opt = getopt(argc, argv, "ne:f:")) > 0) {
+	while ((opt = getopt(argc, argv, "ine:f:")) > 0) {
 		switch (opt) {
+		case 'i':
+			in_place++;
+			atexit(cleanup_outname);
+			break;
 		case 'n':
 			be_quiet++;
 			break;
@@ -1131,23 +1150,51 @@
 	/* Flush any unfinished commands. */
 	add_cmd("");
 
+	/* By default, we write to stdout */
+	nonstdout=stdout;
+
 	/* argv[(optind)..(argc-1)] should be names of file to process. If no
 	 * files were specified or '-' was specified, take input from stdin.
 	 * Otherwise, we process all the files specified. */
 	if (argv[optind] == NULL) {
+		if(in_place) {
+			fprintf(stderr,"sed: Filename required for -i\n");
+			exit(1);
+		}
 		process_file(stdin);
 	} else {
 		int i;
 		FILE *file;
 
 		for (i = optind; i < argc; i++) {
-			if(!strcmp(argv[i], "-")) {
+			if(!strcmp(argv[i], "-") && !in_place) {
 				process_file(stdin);
 			} else {
 				file = bb_wfopen(argv[i], "r");
 				if (file) {
+					if(in_place) {
+						struct stat statbuf;
+						outname=bb_xstrndup(argv[i],strlen(argv[i])+6);
+						strcat(outname,"XXXXXX");
+						/* Set permissions of output file */
+						fstat(fileno(file),&statbuf);
+						mkstemp(outname);
+						nonstdout=bb_wfopen(outname,"w");
+						/* Set permissions of output file */
+						fstat(fileno(file),&statbuf);
+						fchmod(fileno(file),statbuf.st_mode);
+						atexit(cleanup_outname);
+					}
 					process_file(file);
 					fclose(file);
+					if(in_place) {
+						fclose(nonstdout);
+						nonstdout=stdout;
+						unlink(argv[i]);
+						rename(outname,argv[i]);
+						free(outname);
+						outname=0;
+					}
 				} else {
 					status = EXIT_FAILURE;
 				}




More information about the busybox mailing list