sed(1): Sync with FreeBSD.
authorSascha Wildner <saw@online.de>
Sat, 13 Jun 2009 11:39:15 +0000 (13:39 +0200)
committerSascha Wildner <saw@online.de>
Sat, 13 Jun 2009 11:39:51 +0000 (13:39 +0200)
* Add workaround for a back reference when no corresponding parenthesized
  subexpression is defined. For example, the following command line caused
  unexpected behavior like segmentation fault:

  % echo test | sed -e 's/test/\1/'

* Fix the code to conform to the "or more" part of the following POSIX
  specification.

  "A function can be preceded by one or more '!' characters, in which
  case the function shall be applied if the addresses do not select
  the pattern space."

* Implement "addr1,+N" ranges - not dissimilar to grep's -A switch.

usr.bin/sed/compile.c
usr.bin/sed/defs.h
usr.bin/sed/misc.c
usr.bin/sed/process.c
usr.bin/sed/sed.1

index 819ef40..a06df77 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  * @(#)compile.c       8.1 (Berkeley) 6/6/93
- * $FreeBSD: src/usr.bin/sed/compile.c,v 1.31 2008/02/09 09:12:02 dwmalone Exp $
+ * $FreeBSD: src/usr.bin/sed/compile.c,v 1.34 2009/05/25 06:45:33 brian Exp $
  * $DragonFly: src/usr.bin/sed/compile.c,v 1.4 2008/04/08 13:23:38 swildner Exp $
  */
 
@@ -178,7 +178,7 @@ semicolon:  EATSPACE();
                if ((*link = cmd = malloc(sizeof(struct s_command))) == NULL)
                        err(1, "malloc");
                link = &cmd->next;
-               cmd->nonsel = cmd->inrange = 0;
+               cmd->startline = cmd->nonsel = 0;
                /* First parse the addresses */
                naddr = 0;
 
@@ -221,7 +221,7 @@ nonsel:             /* Now parse the command */
                case NONSEL:                    /* ! */
                        p++;
                        EATSPACE();
-                       cmd->nonsel = ! cmd->nonsel;
+                       cmd->nonsel = 1;
                        goto nonsel;
                case GROUP:                     /* { */
                        p++;
@@ -321,9 +321,17 @@ nonsel:            /* Now parse the command */
                        if (p == NULL)
                                errx(1,
                                "%lu: %s: unterminated substitute pattern", linenum, fname);
+
+                       /* Compile RE with no case sensitivity temporarily */
+                       if (*re == '\0')
+                               cmd->u.s->re = NULL;
+                       else
+                               cmd->u.s->re = compile_re(re, 0);
                        --p;
                        p = compile_subst(p, cmd->u.s);
                        p = compile_flags(p, cmd->u.s);
+
+                       /* Recompile RE with case sensitivity from "I" flag if any */
                        if (*re == '\0')
                                cmd->u.s->re = NULL;
                        else
@@ -764,6 +772,7 @@ compile_addr(char *p, struct s_addr *a)
 
        icase = 0;
 
+       a->type = 0;
        switch (*p) {
        case '\\':                              /* Context address */
                ++p;
@@ -787,10 +796,16 @@ compile_addr(char *p, struct s_addr *a)
        case '$':                               /* Last line */
                a->type = AT_LAST;
                return (p + 1);
+
+       case '+':                               /* Relative line number */
+               a->type = AT_RELLINE;
+               p++;
+               /* FALLTHROUGH */
                                                /* Line number */
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':
-               a->type = AT_LINE;
+               if (a->type == 0)
+                       a->type = AT_LINE;
                a->u.l = strtol(p, &end, 10);
                return (end);
        default:
index d44b33a..73dff7e 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     @(#)defs.h      8.1 (Berkeley) 6/6/93
- * $FreeBSD: src/usr.bin/sed/defs.h,v 1.7 2008/02/09 09:12:02 dwmalone Exp $
+ * $FreeBSD: src/usr.bin/sed/defs.h,v 1.8 2009/05/25 06:45:33 brian Exp $
  * $DragonFly: src/usr.bin/sed/defs.h,v 1.2 2008/04/08 13:23:38 swildner Exp $
  */
 
@@ -39,8 +39,9 @@
  * Types of address specifications
  */
 enum e_atype {
-       AT_RE,                                  /* Line that match RE */
+       AT_RE       = 1,                        /* Line that match RE */
        AT_LINE,                                /* Specific line */
+       AT_RELLINE,                             /* Relative line */
        AT_LAST,                                /* Last line */
 };
 
@@ -92,6 +93,7 @@ struct s_tr {
 struct s_command {
        struct s_command *next;                 /* Pointer to next command */
        struct s_addr *a1, *a2;                 /* Start and end address */
+       u_long startline;                       /* Start line number or zero */
        char *t;                                /* Text for : a c i r w */
        union {
                struct s_command *c;            /* Command(s) for b t { */
@@ -101,7 +103,6 @@ struct s_command {
        } u;
        char code;                              /* Command code */
        u_int nonsel:1;                         /* True if ! */
-       u_int inrange:1;                        /* True if in range */
 };
 
 /*
index 3961b72..2949402 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  * @(#)misc.c  8.1 (Berkeley) 6/6/93
- * $FreeBSD: src/usr.bin/sed/misc.c,v 1.9 2004/07/14 10:06:22 tjr Exp $
+ * $FreeBSD: src/usr.bin/sed/misc.c,v 1.10 2004/08/09 15:29:41 dds Exp $
  * $DragonFly: src/usr.bin/sed/misc.c,v 1.4 2008/04/08 13:23:38 swildner Exp $
  */
 
index b389aae..9e13145 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  * @(#)process.c       8.6 (Berkeley) 4/20/94
- * $FreeBSD: src/usr.bin/sed/process.c,v 1.49 2008/02/09 09:12:02 dwmalone Exp $
+ * $FreeBSD: src/usr.bin/sed/process.c,v 1.50 2009/05/25 06:45:33 brian Exp $
  * $DragonFly: src/usr.bin/sed/process.c,v 1.6 2008/04/08 13:23:38 swildner Exp $
  */
 
@@ -272,8 +272,8 @@ new:                if (!nflag && !pd)
            (a)->type == AT_LINE ? linenum == (a)->u.l : lastline())
 
 /*
- * Return TRUE if the command applies to the current line.  Sets the inrange
- * flag to process ranges.  Interprets the non-select (``!'') flag.
+ * Return TRUE if the command applies to the current line.  Sets the start
+ * line for process ranges.  Interprets the non-select (``!'') flag.
  */
 static __inline int
 applies(struct s_command *cp)
@@ -284,18 +284,22 @@ applies(struct s_command *cp)
        if (cp->a1 == NULL && cp->a2 == NULL)
                r = 1;
        else if (cp->a2)
-               if (cp->inrange) {
+               if (cp->startline > 0) {
                        if (MATCH(cp->a2)) {
-                               cp->inrange = 0;
+                               cp->startline = 0;
                                lastaddr = 1;
                                r = 1;
-                       } else if (cp->a2->type == AT_LINE &&
-                                  linenum > cp->a2->u.l) {
+                       } else if (linenum - cp->startline <= cp->a2->u.l)
+                               r = 1;
+                       else if ((cp->a2->type == AT_LINE &&
+                                  linenum > cp->a2->u.l) ||
+                                  (cp->a2->type == AT_RELLINE &&
+                                  linenum - cp->startline > cp->a2->u.l)) {
                                /*
                                 * We missed the 2nd address due to a branch,
                                 * so just close the range and return false.
                                 */
-                               cp->inrange = 0;
+                               cp->startline = 0;
                                r = 0;
                        } else
                                r = 1;
@@ -305,12 +309,15 @@ applies(struct s_command *cp)
                         * equal to the line number first selected, only
                         * one line shall be selected.
                         *      -- POSIX 1003.2
+                        * Likewise if the relative second line address is zero.
                         */
-                       if (cp->a2->type == AT_LINE &&
-                           linenum >= cp->a2->u.l)
+                       if ((cp->a2->type == AT_LINE &&
+                           linenum >= cp->a2->u.l) ||
+                           (cp->a2->type == AT_RELLINE && cp->a2->u.l == 0))
                                lastaddr = 1;
-                       else
-                               cp->inrange = 1;
+                       else {
+                               cp->startline = linenum;
+                       }
                        r = 1;
                } else
                        r = 0;
@@ -328,11 +335,11 @@ resetstate(void)
        struct s_command *cp;
 
        /*
-        * Reset all inrange markers.
+        * Reset all in-range markers.
         */
        for (cp = prog; cp; cp = cp->code == '{' ? cp->u.c : cp->next)
                if (cp->a2)
-                       cp->inrange = 0;
+                       cp->startline = 0;
 
        /*
         * Clear out the hold space.
@@ -628,7 +635,7 @@ lputs(char *s, size_t len)
 
 static __inline int
 regexec_e(regex_t *preg, const char *string, int eflags, int nomatch,
-         size_t slen)
+       size_t slen)
 {
        int eval;
 
index c630116..4b1394f 100644 (file)
 .\" SUCH DAMAGE.
 .\"
 .\"    @(#)sed.1       8.2 (Berkeley) 12/30/93
-.\" $FreeBSD: src/usr.bin/sed/sed.1,v 1.46 2007/07/04 16:42:41 ssouhlal Exp $
+.\" $FreeBSD: src/usr.bin/sed/sed.1,v 1.50 2009/05/25 21:29:06 brian Exp $
 .\" $DragonFly: src/usr.bin/sed/sed.1,v 1.6 2008/09/06 09:38:33 thomas Exp $
 .\"
-.Dd April 8, 2008
+.Dd June 13, 2009
 .Dt SED 1
 .Os
 .Sh NAME
@@ -213,6 +213,9 @@ that matches the second address.
 If the second address is a number
 less than or equal to the line number first selected, only that
 line is selected.
+The number in the second address may be prefixed with a
+.Pq Dq \&+
+to specify the number of lines to match after the first pattern.
 In the case when the second address is a context
 address,
 .Nm
@@ -245,20 +248,17 @@ has the following two additions to regular expressions:
 In a context address, any character other than a backslash
 .Pq Dq \e
 or newline character may be used to delimit the regular expression.
-The opening delimiter need to be preceede by a backslash
-unless it is a slash
-.Pq Dq / .
-For example the context address
-.Dq \exabcx
+The opening delimiter needs to be preceded by a backslash
+unless it is a slash.
+For example, the context address
+.Li \exabcx
 is equivalent to
-.Dq /abc/ .
+.Li /abc/ .
 Also, putting a backslash character before the delimiting character
-within the regular expression
-causes the character to be treated literally.
+within the regular expression causes the character to be treated literally.
 For example, in the context address
-.Dq \exabc\exdefx ,
-the RE delimiter
-is an
+.Li \exabc\exdefx ,
+the RE delimiter is an
 .Dq x
 and the second
 .Dq x
@@ -599,7 +599,10 @@ The
 .Fl E , I , a
 and
 .Fl i
-options, as well as the
+options, the prefixing
+.Dq \&+
+in the second member of an address range,
+as well as the
 .Dq I
 flag to the address regular expression and substitution command are
 non-standard