On 07/17/15 13:51, Antoine Jacoutot wrote: > On Fri, Jul 17, 2015 at 12:57:12PM -0400, Brian Callahan wrote: >> >> >> On 07/17/15 12:10, Jasper Lievisse Adriaanse wrote: >>> Hi, >>> >>> Here's a diff to add the '-i' flag to sed to do inplace edits. It's mostly >>> from FreeBSD with some adjustments to prevent a race with unlink() and >>> fopen() >>> during the tempfile creation. >>> >>> It's been tested in a full ports bulk (thanks aja), and went through a build >>> of base and xenocara. >>> Regress tests will also be added for this. >>> >>> This diff is already OK millert@. Any more OKs? >>> >> >> Cool. This saves me having to install coreutils just to work on some >> school projects. > > You mean gsed right? >
Oh, heh. Yes. I mean gsed. Either way, it's one less package I have to remember. (and clearly I'm not so good at remembering them in the first place!) > >> ok bcallah@, fwiw. >> >>> Index: defs.h >>> =================================================================== >>> RCS file: /cvs/src/usr.bin/sed/defs.h,v >>> retrieving revision 1.5 >>> diff -u -p -r1.5 defs.h >>> --- defs.h 19 Jan 2015 15:30:52 -0000 1.5 >>> +++ defs.h 16 Jul 2015 18:45:58 -0000 >>> @@ -128,6 +128,7 @@ typedef struct { >>> char *space; /* Current space pointer. */ >>> size_t len; /* Current length. */ >>> int deleted; /* If deleted. */ >>> + int append_newline; /* If originally terminated by \n. */ >>> char *back; /* Backing memory. */ >>> size_t blen; /* Backing memory length. */ >>> } SPACE; >>> Index: extern.h >>> =================================================================== >>> RCS file: /cvs/src/usr.bin/sed/extern.h,v >>> retrieving revision 1.9 >>> diff -u -p -r1.9 extern.h >>> --- extern.h 13 Apr 2015 05:11:23 -0000 1.9 >>> +++ extern.h 16 Jul 2015 00:23:57 -0000 >>> @@ -40,17 +40,19 @@ extern regmatch_t *match; >>> extern size_t maxnsub; >>> extern u_long linenum; >>> extern size_t appendnum; >>> -extern int lastline; >>> extern int Eflag, aflag, eflag, nflag; >>> -extern char *fname; >>> +extern const char *fname, *outfname; >>> +extern FILE *infile, *outfile; >>> >>> void cfclose(struct s_command *, struct s_command *); >>> void compile(void); >>> -void cspace(SPACE *, char *, size_t, enum e_spflag); >>> +void cspace(SPACE *, const char *, size_t, enum e_spflag); >>> char *cu_fgets(char **, size_t *); >>> void err(int, const char *, ...); >>> int mf_fgets(SPACE *, enum e_spflag); >>> +int lastline(void); >>> void process(void); >>> +void resetranges(void); >>> char *strregerror(int, regex_t *); >>> void *xmalloc(size_t); >>> void *xreallocarray(void *, size_t, size_t); >>> Index: main.c >>> =================================================================== >>> RCS file: /cvs/src/usr.bin/sed/main.c,v >>> retrieving revision 1.18 >>> diff -u -p -r1.18 main.c >>> --- main.c 26 Nov 2014 18:34:51 -0000 1.18 >>> +++ main.c 16 Jul 2015 19:21:16 -0000 >>> @@ -34,6 +34,7 @@ >>> */ >>> >>> #include <sys/types.h> >>> +#include <sys/stat.h> >>> >>> #include <ctype.h> >>> #include <errno.h> >>> @@ -45,6 +46,7 @@ >>> #include <stdlib.h> >>> #include <string.h> >>> #include <unistd.h> >>> +#include <libgen.h> >>> >>> #include "defs.h" >>> #include "extern.h" >>> @@ -78,15 +80,23 @@ struct s_flist { >>> */ >>> static struct s_flist *files, **fl_nextp = &files; >>> >>> +FILE *infile; /* Current input file */ >>> +FILE *outfile; /* Current output file */ >>> + >>> int Eflag, aflag, eflag, nflag; >>> +static int rval; /* Exit status */ >>> >>> /* >>> * Current file and line number; line numbers restart across compilation >>> - * units, but span across input files. >>> + * units, but span across input files. The latter is optional if editing >>> + * in place. >>> */ >>> -char *fname; /* File name. */ >>> +const char *fname; /* File name. */ >>> +const char *outfname; /* Output file name */ >>> +static char oldfname[PATH_MAX]; /* Old file name (for in-place editing) >>> */ >>> +static char tmpfname[PATH_MAX]; /* Temporary file name (for in-place >>> editing) */ >>> +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 *); >>> @@ -97,7 +107,8 @@ main(int argc, char *argv[]) >>> int c, fflag; >>> >>> fflag = 0; >>> - while ((c = getopt(argc, argv, "Eae:f:nru")) != -1) >>> + inplace = NULL; >>> + while ((c = getopt(argc, argv, "Eae:f:i::nru")) != -1) >>> switch (c) { >>> case 'E': >>> case 'r': >>> @@ -114,6 +125,9 @@ main(int argc, char *argv[]) >>> fflag = 1; >>> add_compunit(CU_FILE, optarg); >>> break; >>> + case 'i': >>> + inplace = optarg ? optarg : ""; >>> + break; >>> case 'n': >>> nflag = 1; >>> break; >>> @@ -123,8 +137,8 @@ main(int argc, char *argv[]) >>> default: >>> case '?': >>> (void)fprintf(stderr, >>> - "usage: sed [-aEnru] command [file ...]\n" >>> - " sed [-aEnru] [-e command] [-f command_file] >>> [file ...]\n"); >>> + "usage: sed [-aEnru] [-i [extension]] command [file >>> ...]\n" >>> + " sed [-aEnru] [-i [extension]] [-e command] >>> [-f command_file] [file ...]\n"); >>> exit(1); >>> } >>> argc -= optind; >>> @@ -148,7 +162,7 @@ main(int argc, char *argv[]) >>> cfclose(prog, NULL); >>> if (fclose(stdout)) >>> err(FATAL, "stdout: %s", strerror(errno)); >>> - exit (0); >>> + exit (rval); >>> } >>> >>> /* >>> @@ -258,69 +272,128 @@ again: >>> int >>> mf_fgets(SPACE *sp, enum e_spflag spflag) >>> { >>> - static FILE *f; /* Current open file */ >>> + struct stat sb; >>> size_t len; >>> char *p; >>> - int c; >>> + int c, fd; >>> + static int firstfile; >>> >>> - if (f == NULL) >>> - /* Advance to first non-empty file */ >>> - for (;;) { >>> - if (files == NULL) { >>> - lastline = 1; >>> - return (0); >>> - } >>> - if (files->fname == NULL) { >>> - f = stdin; >>> - fname = "stdin"; >>> - } else { >>> - fname = files->fname; >>> - if ((f = fopen(fname, "r")) == NULL) >>> - err(FATAL, "%s: %s", >>> - fname, strerror(errno)); >>> + if (infile == NULL) { >>> + /* stdin? */ >>> + if (files->fname == NULL) { >>> + if (inplace != NULL) >>> + err(FATAL, "-i may not be used with stdin"); >>> + infile = stdin; >>> + fname = "stdin"; >>> + outfile = stdout; >>> + outfname = "stdout"; >>> + } >>> + >>> + firstfile = 1; >>> + } >>> + >>> + for (;;) { >>> + if (infile != NULL && (c = getc(infile)) != EOF) { >>> + (void)ungetc(c, infile); >>> + break; >>> + } >>> + /* If we are here then either eof or no files are open yet */ >>> + if (infile == stdin) { >>> + sp->len = 0; >>> + return (0); >>> + } >>> + if (infile != NULL) { >>> + fclose(infile); >>> + if (*oldfname != '\0') { >>> + if (rename(fname, oldfname) != 0) { >>> + err(WARNING, "rename()"); >>> + unlink(tmpfname); >>> + exit(1); >>> + } >>> + *oldfname = '\0'; >>> } >>> - if ((c = getc(f)) != EOF) { >>> - (void)ungetc(c, f); >>> - break; >>> + if (*tmpfname != '\0') { >>> + if (outfile != NULL && outfile != stdout) >>> + fclose(outfile); >>> + outfile = NULL; >>> + rename(tmpfname, fname); >>> + *tmpfname = '\0'; >>> } >>> - (void)fclose(f); >>> + outfname = NULL; >>> + } >>> + if (firstfile == 0) >>> files = files->next; >>> + else >>> + firstfile = 0; >>> + if (files == NULL) { >>> + sp->len = 0; >>> + return (0); >>> + } >>> + fname = files->fname; >>> + if (inplace != NULL) { >>> + if (lstat(fname, &sb) != 0) >>> + err(1, "%s", fname); >>> + if (!S_ISREG(sb.st_mode)) >>> + err(FATAL, "%s: %s %s", fname, >>> + "in-place editing only", >>> + "works for regular files"); >>> + if (*inplace != '\0') { >>> + strlcpy(oldfname, fname, >>> + sizeof(oldfname)); >>> + len = strlcat(oldfname, inplace, >>> + sizeof(oldfname)); >>> + if (len > sizeof(oldfname)) >>> + err(FATAL, "%s: name too long", fname); >>> + } >>> + len = snprintf(tmpfname, sizeof(tmpfname), >>> "%s/.%s.XXXXXXXXXX", >>> + dirname(fname), basename(fname)); >>> + if (len >= sizeof(tmpfname)) >>> + err(FATAL, "%s: name too long", fname); >>> + if ((fd = mkstemp(tmpfname)) == -1) >>> + err(FATAL, "%s", fname); >>> + if ((outfile = fdopen(fd, "w")) == NULL) { >>> + unlink(tmpfname); >>> + err(FATAL, "%s", fname); >>> + } >>> + fchown(fileno(outfile), sb.st_uid, sb.st_gid); >>> + fchmod(fileno(outfile), sb.st_mode & ALLPERMS); >>> + outfname = tmpfname; >>> + linenum = 0; >>> + resetranges(); >>> + } else { >>> + outfile = stdout; >>> + outfname = "stdout"; >>> + } >>> + if ((infile = fopen(fname, "r")) == NULL) { >>> + err(WARNING, "%s", fname); >>> + rval = 1; >>> + continue; >>> } >>> - >>> - if (lastline) { >>> - sp->len = 0; >>> - return (0); >>> } >>> >>> /* >>> + * We are here only when infile is open and we still have something >>> + * to read from it. >>> + * >>> * Use fgetln so that we can handle essentially infinite input data. >>> * Can't use the pointer into the stdio buffer as the process space >>> * because the ungetc() can cause it to move. >>> */ >>> - p = fgetln(f, &len); >>> - if (ferror(f)) >>> + p = fgetln(infile, &len); >>> + if (ferror(infile)) >>> err(FATAL, "%s: %s", fname, strerror(errno ? errno : EIO)); >>> + if (len != 0 && p[len - 1] == '\n') { >>> + sp->append_newline = 1; >>> + len--; >>> + } else if (!lastline()) { >>> + sp->append_newline = 1; >>> + } else { >>> + sp->append_newline = 0; >>> + } >>> cspace(sp, p, len, spflag); >>> >>> linenum++; >>> - /* Advance to next non-empty file */ >>> - while ((c = getc(f)) == EOF) { >>> - (void)fclose(f); >>> - files = files->next; >>> - if (files == NULL) { >>> - lastline = 1; >>> - return (1); >>> - } >>> - if (files->fname == NULL) { >>> - f = stdin; >>> - fname = "stdin"; >>> - } else { >>> - fname = files->fname; >>> - if ((f = fopen(fname, "r")) == NULL) >>> - err(FATAL, "%s: %s", fname, strerror(errno)); >>> - } >>> - } >>> - (void)ungetc(c, f); >>> + >>> return (1); >>> } >>> >>> @@ -353,4 +426,52 @@ add_file(char *s) >>> *fl_nextp = fp; >>> fp->fname = s; >>> fl_nextp = &fp->next; >>> +} >>> + >>> + >>> +static int >>> +next_files_have_lines() >>> +{ >>> + struct s_flist *file; >>> + FILE *file_fd; >>> + int ch; >>> + >>> + file = files; >>> + while ((file = file->next) != NULL) { >>> + if ((file_fd = fopen(file->fname, "r")) == NULL) >>> + continue; >>> + >>> + if ((ch = getc(file_fd)) != EOF) { >>> + /* >>> + * This next file has content, therefore current >>> + * file doesn't contains the last line. >>> + */ >>> + ungetc(ch, file_fd); >>> + fclose(file_fd); >>> + return (1); >>> + } >>> + >>> + fclose(file_fd); >>> + } >>> + >>> + return (0); >>> +} >>> + >>> +int >>> +lastline(void) >>> +{ >>> + int ch; >>> + >>> + if (feof(infile)) { >>> + return !( >>> + (inplace == NULL) && >>> + next_files_have_lines()); >>> + } >>> + if ((ch = getc(infile)) == EOF) { >>> + return !( >>> + (inplace == NULL) && >>> + next_files_have_lines()); >>> + } >>> + ungetc(ch, infile); >>> + return (0); >>> } >>> Index: process.c >>> =================================================================== >>> RCS file: /cvs/src/usr.bin/sed/process.c,v >>> retrieving revision 1.23 >>> diff -u -p -r1.23 process.c >>> --- process.c 18 Apr 2015 18:28:37 -0000 1.23 >>> +++ process.c 16 Jul 2015 18:50:40 -0000 >>> @@ -55,6 +55,7 @@ static SPACE HS, PS, SS; >>> #define pd PS.deleted >>> #define ps PS.space >>> #define psl PS.len >>> +#define psanl PS.append_newline >>> #define hs HS.space >>> #define hsl HS.len >>> >>> @@ -76,7 +77,10 @@ static regex_t *defpreg; >>> size_t maxnsub; >>> regmatch_t *match; >>> >>> -#define OUT(s) do { fwrite(s, sizeof(u_char), psl, stdout); } while (0) >>> +#define OUT() do {\ >>> + fwrite(ps, 1, psl, outfile);\ >>> + if (psanl) fputc('\n', outfile);\ >>> +} while (0) >>> >>> void >>> process(void) >>> @@ -85,6 +89,7 @@ process(void) >>> SPACE tspace; >>> size_t len, oldpsl; >>> char *p; >>> + int oldpsanl; >>> >>> for (linenum = 0; mf_fgets(&PS, REPLACE);) { >>> pd = 0; >>> @@ -118,8 +123,8 @@ redirect: >>> case 'c': >>> pd = 1; >>> psl = 0; >>> - if (cp->a2 == NULL || lastaddr) >>> - (void)printf("%s", cp->t); >>> + if (cp->a2 == NULL || lastaddr || lastline()) >>> + (void)fprintf(outfile, "%s", cp->t); >>> break; >>> case 'd': >>> pd = 1; >>> @@ -128,7 +133,7 @@ redirect: >>> if (pd) >>> goto new; >>> if (psl == 0 || >>> - (p = memchr(ps, '\n', psl - 1)) == NULL) { >>> + (p = memchr(ps, '\n', psl)) == NULL) { >>> pd = 1; >>> goto new; >>> } else { >>> @@ -140,25 +145,25 @@ redirect: >>> cspace(&PS, hs, hsl, REPLACE); >>> break; >>> case 'G': >>> - if (hs == NULL) >>> - cspace(&HS, "\n", 1, REPLACE); >>> + cspace(&PS, "\n", 1, 0); >>> cspace(&PS, hs, hsl, 0); >>> break; >>> case 'h': >>> cspace(&HS, ps, psl, REPLACE); >>> break; >>> case 'H': >>> + cspace(&HS, "\n", 1, 0); >>> cspace(&HS, ps, psl, 0); >>> break; >>> case 'i': >>> - (void)printf("%s", cp->t); >>> + (void)fprintf(outfile, "%s", cp->t); >>> break; >>> case 'l': >>> lputs(ps); >>> break; >>> case 'n': >>> if (!nflag && !pd) >>> - OUT(ps); >>> + OUT(); >>> flush_appends(); >>> if (!mf_fgets(&PS, REPLACE)) >>> exit(0); >>> @@ -166,33 +171,32 @@ redirect: >>> break; >>> case 'N': >>> flush_appends(); >>> - if (!mf_fgets(&PS, 0)) { >>> - if (!nflag && !pd) >>> - OUT(ps); >>> + cspace(&PS, "\n", 1, 0); >>> + if (!mf_fgets(&PS, 0)) >>> exit(0); >>> - } >>> break; >>> case 'p': >>> if (pd) >>> break; >>> - OUT(ps); >>> + OUT(); >>> break; >>> case 'P': >>> if (pd) >>> break; >>> - if (psl != 0 && >>> - (p = memchr(ps, '\n', psl - 1)) != NULL) { >>> + if ((p = memchr(ps, '\n', psl)) != NULL) { >>> oldpsl = psl; >>> - psl = (p + 1) - ps; >>> - OUT(ps); >>> + oldpsanl = psanl; >>> + psl = p - ps; >>> + psanl = 1; >>> + OUT(); >>> psl = oldpsl; >>> } else { >>> - OUT(ps); >>> + OUT(); >>> } >>> break; >>> case 'q': >>> if (!nflag && !pd) >>> - OUT(ps); >>> + OUT(); >>> flush_appends(); >>> exit(0); >>> case 'r': >>> @@ -225,34 +229,36 @@ redirect: >>> DEFFILEMODE)) == -1) >>> err(FATAL, "%s: %s", >>> cp->t, strerror(errno)); >>> - if (write(cp->u.fd, ps, psl) != psl) >>> + if (write(cp->u.fd, ps, psl) != psl || >>> + write(cp->u.fd, "\n", 1) != 1) >>> err(FATAL, "%s: %s", >>> cp->t, strerror(errno)); >>> break; >>> case 'x': >>> if (hs == NULL) >>> - cspace(&HS, "\n", 1, REPLACE); >>> + cspace(&HS, "", 0, REPLACE); >>> tspace = PS; >>> PS = HS; >>> + psanl = tspace.append_newline; >>> HS = tspace; >>> break; >>> case 'y': >>> if (pd || psl == 0) >>> break; >>> - for (p = ps, len = psl; --len; ++p) >>> + for (p = ps, len = psl; len--; ++p) >>> *p = cp->u.y[(unsigned char)*p]; >>> break; >>> case ':': >>> case '}': >>> break; >>> case '=': >>> - (void)printf("%lu\n", linenum); >>> + (void)fprintf(outfile, "%lu\n", linenum); >>> } >>> cp = cp->next; >>> } /* for all cp */ >>> >>> new: if (!nflag && !pd) >>> - OUT(ps); >>> + OUT(); >>> flush_appends(); >>> } /* for all lines */ >>> } >>> @@ -263,7 +269,7 @@ new: if (!nflag && !pd) >>> */ >>> #define MATCH(a) \ >>> (a)->type == AT_RE ? regexec_e((a)->u.r, ps, 0, 1, psl) : \ >>> - (a)->type == AT_LINE ? linenum == (a)->u.l : lastline >>> + (a)->type == AT_LINE ? linenum == (a)->u.l : lastline() >>> >>> /* >>> * Return TRUE if the command applies to the current line. Sets the >>> inrange >>> @@ -305,6 +311,19 @@ applies(struct s_command *cp) >>> } >>> >>> /* >>> + * Reset all inrange markers. >>> + */ >>> +void >>> +resetranges(void) >>> +{ >>> + struct s_command *cp; >>> + >>> + for (cp = prog; cp; cp = cp->code == '{' ? cp->u.c : cp->next) >>> + if (cp->a2) >>> + cp->inrange = 0; >>> +} >>> + >>> +/* >>> * substitute -- >>> * Do substitutions in the pattern space. Currently, we build a >>> * copy of the new pattern space in the substitute space structure >>> @@ -392,19 +411,21 @@ substitute(struct s_command *cp) >>> */ >>> tspace = PS; >>> PS = SS; >>> + psanl = tspace.append_newline; >>> SS = tspace; >>> SS.space = SS.back; >>> >>> /* Handle the 'p' flag. */ >>> if (cp->u.s->p) >>> - OUT(ps); >>> + OUT(); >>> >>> /* Handle the 'w' flag. */ >>> if (cp->u.s->wfile && !pd) { >>> if (cp->u.s->wfd == -1 && (cp->u.s->wfd = open(cp->u.s->wfile, >>> O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, DEFFILEMODE)) == -1) >>> err(FATAL, "%s: %s", cp->u.s->wfile, strerror(errno)); >>> - if (write(cp->u.s->wfd, ps, psl) != psl) >>> + if (write(cp->u.s->wfd, ps, psl) != psl || >>> + write(cp->u.s->wfd, "\n", 1) != 1) >>> err(FATAL, "%s: %s", cp->u.s->wfile, strerror(errno)); >>> } >>> return (1); >>> @@ -425,7 +446,7 @@ flush_appends(void) >>> switch (appends[i].type) { >>> case AP_STRING: >>> fwrite(appends[i].s, sizeof(char), appends[i].len, >>> - stdout); >>> + outfile); >>> break; >>> case AP_FILE: >>> /* >>> @@ -439,12 +460,12 @@ flush_appends(void) >>> if ((f = fopen(appends[i].s, "r")) == NULL) >>> break; >>> while ((count = fread(buf, sizeof(char), sizeof(buf), >>> f))) >>> - (void)fwrite(buf, sizeof(char), count, stdout); >>> + (void)fwrite(buf, sizeof(char), count, outfile); >>> (void)fclose(f); >>> break; >>> } >>> - if (ferror(stdout)) >>> - err(FATAL, "stdout: %s", strerror(errno ? errno : EIO)); >>> + if (ferror(outfile)) >>> + err(FATAL, "%s: %s", outfname, strerror(errno ? errno : EIO)); >>> appendx = sdone = 0; >>> } >>> >>> @@ -452,10 +473,14 @@ static void >>> lputs(char *s) >>> { >>> int count; >>> - char *escapes, *p; >>> + const char *escapes; >>> + char *p; >>> struct winsize win; >>> static int termwidth = -1; >>> >>> + if (outfile != stdout) >>> + termwidth = 60; >>> + >>> if (termwidth == -1) { >>> termwidth = 0; >>> if ((p = getenv("COLUMNS"))) >>> @@ -470,29 +495,33 @@ lputs(char *s) >>> >>> for (count = 0; *s; ++s) { >>> if (count >= termwidth) { >>> - (void)printf("\\\n"); >>> + (void)fprintf(outfile, "\\\n"); >>> count = 0; >>> } >>> if (isascii((unsigned char)*s) && isprint((unsigned char)*s) >>> && *s != '\\') { >>> - (void)putchar(*s); >>> + (void)fputc(*s, outfile); >>> count++; >>> - } else if (*s != '\n') { >>> + } else if (*s == '\n') { >>> + (void)fputc('$', outfile); >>> + (void)fputc('\n', outfile); >>> + count = 0; >>> + } else { >>> escapes = "\\\a\b\f\r\t\v"; >>> - (void)putchar('\\'); >>> + (void)fputc('\\', outfile); >>> if ((p = strchr(escapes, *s))) { >>> - (void)putchar("\\abfrtv"[p - escapes]); >>> + (void)fputc("\\abfrtv"[p - escapes], outfile); >>> count += 2; >>> } else { >>> - (void)printf("%03o", *(u_char *)s); >>> + (void)fprintf(outfile, "%03o", *(u_char *)s); >>> count += 4; >>> } >>> } >>> } >>> - (void)putchar('$'); >>> - (void)putchar('\n'); >>> - if (ferror(stdout)) >>> - err(FATAL, "stdout: %s", strerror(errno ? errno : EIO)); >>> + (void)fputc('$', outfile); >>> + (void)fputc('\n', outfile); >>> + if (ferror(outfile)) >>> + err(FATAL, "%s: %s", outfname, strerror(errno ? errno : EIO)); >>> } >>> >>> static inline int >>> @@ -507,9 +536,7 @@ regexec_e(regex_t *preg, const char *str >>> } else >>> defpreg = preg; >>> >>> - /* Set anchors, discounting trailing newline (if any). */ >>> - if (slen > 0 && string[slen - 1] == '\n') >>> - slen--; >>> + /* Set anchors */ >>> match[0].rm_so = 0; >>> match[0].rm_eo = slen; >>> >>> @@ -575,7 +602,7 @@ regsub(SPACE *sp, char *string, char *sr >>> * space as necessary. >>> */ >>> void >>> -cspace(SPACE *sp, char *p, size_t len, enum e_spflag spflag) >>> +cspace(SPACE *sp, const char *p, size_t len, enum e_spflag spflag) >>> { >>> size_t tlen; >>> >>> Index: sed.1 >>> =================================================================== >>> RCS file: /cvs/src/usr.bin/sed/sed.1,v >>> retrieving revision 1.44 >>> diff -u -p -r1.44 sed.1 >>> --- sed.1 22 Oct 2014 23:23:22 -0000 1.44 >>> +++ sed.1 16 Jul 2015 19:15:14 -0000 >>> @@ -47,6 +47,7 @@ >>> .Op Fl aEnru >>> .Op Fl e Ar command >>> .Op Fl f Ar command_file >>> +.Op Fl i Op Ar extension >>> .Op Ar >>> .Sh DESCRIPTION >>> The >>> @@ -94,6 +95,16 @@ Append the editing commands found in the >>> .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 . >>> +If a zero-length >>> +.Ar extension >>> +is given, no backup will be saved. >>> +It is not recommended to give a zero-length >>> +.Ar extension >>> +when in-place editing files, as you risk corruption or partial content >>> +in situations where disk space is exhausted, etc. >>> .It Fl r >>> An alias for >>> .Fl E , >>> @@ -510,6 +521,12 @@ command, >>> squeezing excess empty lines from standard input: >>> .Bd -literal -offset indent >>> $ sed -n ' >>> +.Pp >>> +The >>> +.Fl i >>> +option is a non-standard >>> +.Fx >>> +extension and may not be available on other operating systems. >>> # Write non-empty lines. >>> /./ { >>> p >>> @@ -543,7 +560,7 @@ utility is compliant with the >>> specification. >>> .Pp >>> The flags >>> -.Op Fl aEru >>> +.Op Fl aEiru >>> are extensions to that specification. >>> .Pp >>> The use of newlines to separate multiple commands on the command line >>> >> >