diff options
author | jmallett <jmallett@FreeBSD.org> | 2002-05-07 18:32:18 +0000 |
---|---|---|
committer | jmallett <jmallett@FreeBSD.org> | 2002-05-07 18:32:18 +0000 |
commit | d3d209275896af223b3d3a62f2e9ae65b454dd1a (patch) | |
tree | fb0dd04f36f785df847fc030430b1e52614ecc5b /usr.bin/sed | |
parent | 95ebf4bebbc67d7cc3cc35968c894076a2e81651 (diff) | |
download | FreeBSD-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.c | 68 | ||||
-rw-r--r-- | usr.bin/sed/sed.1 | 12 |
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. |