summaryrefslogtreecommitdiffstats
path: root/usr.bin/sed
diff options
context:
space:
mode:
authorjmallett <jmallett@FreeBSD.org>2002-05-07 18:32:18 +0000
committerjmallett <jmallett@FreeBSD.org>2002-05-07 18:32:18 +0000
commitd3d209275896af223b3d3a62f2e9ae65b454dd1a (patch)
treefb0dd04f36f785df847fc030430b1e52614ecc5b /usr.bin/sed
parent95ebf4bebbc67d7cc3cc35968c894076a2e81651 (diff)
downloadFreeBSD-src-d3d209275896af223b3d3a62f2e9ae65b454dd1a.zip
FreeBSD-src-d3d209275896af223b3d3a62f2e9ae65b454dd1a.tar.gz
Add a -i option to sed(1) to do inplace editing, to give us an alternative to
Perl for such things. The key difference to Perl is that a backup extension *MUST* be specified, because on one hand it isn't recommended to have options which optionally take a parameter, and on the other hand, it'd be slightly unpleasent to implement proper handling for that. The difference between this and the version posted to developers@ is that it does handle multiple files in argv after the getopt(3) handling "correctly", in that the inplace editing-specific code has been moved out to a function, and that function is used beyond the first file in our linked list. This option has been documented as FreeBSD-specific in the manpage. Reviewed by: developers@ (got feedback from: des, fanf, sobomax, roberto, obrien) MFC after: 1 week
Diffstat (limited to 'usr.bin/sed')
-rw-r--r--usr.bin/sed/main.c68
-rw-r--r--usr.bin/sed/sed.112
2 files changed, 77 insertions, 3 deletions
diff --git a/usr.bin/sed/main.c b/usr.bin/sed/main.c
index 6e5b4b7..990e9aa 100644
--- a/usr.bin/sed/main.c
+++ b/usr.bin/sed/main.c
@@ -48,7 +48,8 @@ static const char copyright[] =
static const char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/3/94";
#endif
-#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
#include <err.h>
#include <errno.h>
@@ -101,11 +102,13 @@ int rflags = 0;
* units, but span across input files.
*/
const char *fname; /* File name. */
+const char *inplace; /* Inplace edit file extension. */
u_long linenum;
int lastline; /* TRUE on the last line of the last file */
static void add_compunit(enum e_cut, char *);
static void add_file(char *);
+static int inplace_edit(char **);
static void usage(void);
int
@@ -119,7 +122,9 @@ main(argc, argv)
(void) setlocale(LC_ALL, "");
fflag = 0;
- while ((c = getopt(argc, argv, "Eae:f:n")) != -1)
+ inplace = NULL;
+
+ while ((c = getopt(argc, argv, "Eae:f:i:n")) != -1)
switch (c) {
case 'E':
rflags = REG_EXTENDED;
@@ -139,6 +144,9 @@ main(argc, argv)
fflag = 1;
add_compunit(CU_FILE, optarg);
break;
+ case 'i':
+ inplace = optarg;
+ break;
case 'n':
nflag = 1;
break;
@@ -300,9 +308,15 @@ mf_fgets(sp, spflag)
return (0);
}
if (files->fname == NULL) {
+ if (inplace != NULL)
+ errx(1, "-i may not be used with stdin");
f = stdin;
fname = "stdin";
} else {
+ if (inplace != NULL) {
+ if (inplace_edit(&files->fname) == -1)
+ continue;
+ }
fname = files->fname;
if ((f = fopen(fname, "r")) == NULL)
err(1, "%s", fname);
@@ -340,9 +354,15 @@ mf_fgets(sp, spflag)
return (1);
}
if (files->fname == NULL) {
+ if (inplace != NULL)
+ errx(1, "-i may not be used with stdin");
f = stdin;
fname = "stdin";
} else {
+ if (inplace != NULL) {
+ if (inplace_edit(&files->fname) == -1)
+ continue;
+ }
fname = files->fname;
if ((f = fopen(fname, "r")) == NULL)
err(1, "%s", fname);
@@ -387,3 +407,47 @@ add_file(s)
fp->fname = s;
fl_nextp = &fp->next;
}
+
+/*
+ * Modify a pointer to a filename for inplace editing and reopen stdout
+ */
+static int
+inplace_edit(fname)
+ char **fname;
+{
+ struct stat orig;
+ int input, output;
+ char backup[MAXPATHLEN];
+ char *buffer;
+
+ if (lstat(*fname, &orig) == -1)
+ err(1, "lstat");
+ if ((orig.st_mode & S_IFREG) == 0) {
+ warnx("cannot inplace edit %s, not a regular file", fname);
+ return -1;
+ }
+
+ strlcpy(backup, *fname, MAXPATHLEN);
+ strlcat(backup, inplace, MAXPATHLEN);
+
+ input = open(*fname, O_RDONLY);
+ if (input == -1)
+ err(1, "open(%s)", fname);
+ output = open(backup, O_WRONLY|O_CREAT);
+ if (output == -1)
+ err(1, "open(%s)", backup);
+ if (fchmod(output, orig.st_mode & ~S_IFMT) == -1)
+ err(1, "chmod");
+ buffer = malloc(orig.st_size);
+ if (buffer == NULL)
+ errx(1, "malloc failed");
+ if (read(input, buffer, orig.st_size) == -1)
+ err(1, "read");
+ if (write(output, buffer, orig.st_size) == -1)
+ err(1, "write");
+ close(input);
+ close(output);
+ freopen(*fname, "w", stdout);
+ *fname = strdup(backup);
+ return 0;
+}
diff --git a/usr.bin/sed/sed.1 b/usr.bin/sed/sed.1
index f46201a..4005463 100644
--- a/usr.bin/sed/sed.1
+++ b/usr.bin/sed/sed.1
@@ -35,7 +35,7 @@
.\" @(#)sed.1 8.2 (Berkeley) 12/30/93
.\" $FreeBSD$
.\"
-.Dd December 30, 1993
+.Dd Mar 7, 2002
.Dt SED 1
.Os
.Sh NAME
@@ -50,6 +50,7 @@
.Op Fl Ean
.Op Fl e Ar command
.Op Fl f Ar command_file
+.Op Fl i Ar extension
.Op Ar
.Sh DESCRIPTION
The
@@ -98,6 +99,9 @@ Append the editing commands found in the file
.Ar command_file
to the list of commands.
The editing commands should each be listed on a separate line.
+.It Fl i Ar extension
+Edit files in-place, saving backups with the specified
+.Ar extension .
.It Fl n
By default, each line of input is echoed to the standard output after
all of the commands have been applied to it.
@@ -513,3 +517,9 @@ The
function is expected to be a superset of the
.St -p1003.2
specification.
+.Pp
+The
+.Fl i
+option is a non-standard
+.Fx
+extension and may not be available on other operating systems.
OpenPOWER on IntegriCloud