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.

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
> 

Reply via email to