diff options
-rw-r--r-- | tools/regression/usr.bin/sed/regress.sh | 36 | ||||
-rw-r--r-- | usr.bin/sed/extern.h | 1 | ||||
-rw-r--r-- | usr.bin/sed/main.c | 20 | ||||
-rw-r--r-- | usr.bin/sed/process.c | 13 | ||||
-rw-r--r-- | usr.bin/sed/sed.1 | 60 |
5 files changed, 118 insertions, 12 deletions
diff --git a/tools/regression/usr.bin/sed/regress.sh b/tools/regression/usr.bin/sed/regress.sh index a99e7ba..2820a25 100644 --- a/tools/regression/usr.bin/sed/regress.sh +++ b/tools/regression/usr.bin/sed/regress.sh @@ -2,7 +2,7 @@ REGRESSION_START($1) -echo '1..16' +echo '1..20' REGRESSION_TEST(`G', `sed G < regress.in') REGRESSION_TEST(`P', `sed P < regress.in') @@ -28,6 +28,40 @@ foo REGRESSION_TEST(`b2a', `sed ''`2,3b 1,2d''` < regress.in') +` +inplace_test() +{ + expr="$1" + rc=0 + ns=$(jot 5) + ins= outs= _ins= + for n in $ns; do + jot -w "l${n}_%d" 9 | tee lines.in.$n lines._in.$n | \ + sed "$expr" > lines.out.$n + ins="$ins lines.in.$n" + outs="$outs lines.out.$n" + _ins="$_ins lines._in.$n" + done + sed "$expr" $_ins > lines.out + + sed -i "" "$expr" $ins + sed -I "" "$expr" $_ins + + for n in $ns; do + diff -u lines.out.$n lines.in.$n || rc=1 + done + cat $_ins | diff -u lines.out - || rc=1 + rm -f $ins $outs $_ins lines.out + + return $rc +} +' + +REGRESSION_TEST_FREEFORM(`inplace1', `inplace_test 3,6d') +REGRESSION_TEST_FREEFORM(`inplace2', `inplace_test 8,30d') +REGRESSION_TEST_FREEFORM(`inplace3', `inplace_test 20,99d') +REGRESSION_TEST_FREEFORM(`inplace4', `inplace_test "{;{;8,30d;};}"') + REGRESSION_TEST(`hanoi', `echo ":abcd: : :" | sed -f hanoi.sed') REGRESSION_TEST(`math', `echo "4+7*3+2^7/3" | sed -f math.sed') diff --git a/usr.bin/sed/extern.h b/usr.bin/sed/extern.h index 9d4b5bd..cb4ae16 100644 --- a/usr.bin/sed/extern.h +++ b/usr.bin/sed/extern.h @@ -52,4 +52,5 @@ char *cu_fgets(char *, int, int *); int mf_fgets(SPACE *, enum e_spflag); int lastline(void); void process(void); +void resetranges(void); char *strregerror(int, regex_t *); diff --git a/usr.bin/sed/main.c b/usr.bin/sed/main.c index 1b78f80..e4e426f 100644 --- a/usr.bin/sed/main.c +++ b/usr.bin/sed/main.c @@ -101,9 +101,12 @@ int aflag, eflag, nflag; int rflags = 0; static int rval; /* Exit status */ +static int ispan; /* Whether inplace editing spans across files */ + /* * 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. */ const char *fname; /* File name. */ const char *outfname; /* Output file name */ @@ -127,11 +130,15 @@ main(int argc, char *argv[]) fflag = 0; inplace = NULL; - while ((c = getopt(argc, argv, "Eae:f:i:ln")) != -1) + while ((c = getopt(argc, argv, "EI:ae:f:i:ln")) != -1) switch (c) { case 'E': rflags = REG_EXTENDED; break; + case 'I': + inplace = optarg; + ispan = 1; /* span across input files */ + break; case 'a': aflag = 1; break; @@ -149,6 +156,7 @@ main(int argc, char *argv[]) break; case 'i': inplace = optarg; + ispan = 0; /* don't span across input files */ break; case 'l': if(setlinebuf(stdout) != 0) @@ -307,7 +315,7 @@ mf_fgets(SPACE *sp, enum e_spflag spflag) /* stdin? */ if (files->fname == NULL) { if (inplace != NULL) - errx(1, "-i may not be used with stdin"); + errx(1, "-I or -i may not be used with stdin"); infile = stdin; fname = "stdin"; outfile = stdout; @@ -380,6 +388,10 @@ mf_fgets(SPACE *sp, enum e_spflag spflag) fchown(fileno(outfile), sb.st_uid, sb.st_gid); fchmod(fileno(outfile), sb.st_mode & ALLPERMS); outfname = tmpfname; + if (!ispan) { + linenum = 0; + resetranges(); + } } else { outfile = stdout; outfname = "stdout"; @@ -448,7 +460,7 @@ lastline(void) { int ch; - if (files->next != NULL) + if (files->next != NULL && (inplace == NULL || ispan)) return (0); if ((ch = getc(infile)) == EOF) return (1); diff --git a/usr.bin/sed/process.c b/usr.bin/sed/process.c index 44c75f6..9ed541f 100644 --- a/usr.bin/sed/process.c +++ b/usr.bin/sed/process.c @@ -317,6 +317,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 diff --git a/usr.bin/sed/sed.1 b/usr.bin/sed/sed.1 index f6a86d5..5e28f04 100644 --- a/usr.bin/sed/sed.1 +++ b/usr.bin/sed/sed.1 @@ -46,6 +46,7 @@ .Op Fl Ealn .Op Fl e Ar command .Op Fl f Ar command_file +.Op Fl I Ar extension .Op Fl i Ar extension .Op Ar .Sh DESCRIPTION @@ -95,7 +96,7 @@ 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 +.It Fl I Ar extension Edit files in-place, saving backups with the specified .Ar extension . If a zero-length @@ -105,6 +106,36 @@ 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. +.Pp +Note that in-place editing with +.Fl I +still takes place in a single continuous line address space covering +all files, although each file preserves its individuality instead of +forming one output stream. +The line counter is never reset between files, address ranges can span +file boundaries, and the +.Dq $ +address matches only the last line of the last file. +(See +.Sx "Sed Addresses" . ) +That can lead to unexpected results in many cases of in-place editing, +where using +.Fl i +is desired. +.It Fl i Ar extension +Edit files in-place similarly to +.Fl I , +but treat each file independently from other files. +In particular, line numbers in each file start at 1, +the +.Dq $ +address matches the last line of the current file, +and address ranges are limited to the current file. +(See +.Sx "Sed Addresses" . ) +The net result is as though each file were edited by a separate +.Nm +instance. .It Fl l Make output line buffered. .It Fl n @@ -140,13 +171,28 @@ Some of the functions use a .Em "hold space" to save all or part of the pattern space for subsequent retrieval. .Sh "Sed Addresses" -An address is not required, but if specified must be a number (that counts +An address is not required, but if specified must have one of the +following formats: +.Bl -bullet -offset indent +.It +a number that counts input lines -cumulatively across input files), a dollar +cumulatively across input files (or in each file independently +if a +.Fl i +option is in effect); +.It +a dollar .Pq Dq $ -character that addresses the last line of input, or a context address -(which consists of a regular expression preceded and followed by a -delimiter). +character that addresses the last line of input (or the last line +of the current file if a +.Fl i +option was specified); +.It +a context address +that consists of a regular expression preceded and followed by a +delimiter. +.El .Pp A command line with no addresses selects every pattern space. .Pp @@ -533,7 +579,7 @@ utility is expected to be a superset of the specification. .Pp The -.Fl E , a +.Fl E , I , a and .Fl i options are non-standard |