* 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 $
*/
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;
case NONSEL: /* ! */
p++;
EATSPACE();
- cmd->nonsel = ! cmd->nonsel;
+ cmd->nonsel = 1;
goto nonsel;
case GROUP: /* { */
p++;
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
icase = 0;
+ a->type = 0;
switch (*p) {
case '\\': /* Context address */
++p;
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:
* 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 $
*/
* 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 */
};
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 { */
} u;
char code; /* Command code */
u_int nonsel:1; /* True if ! */
- u_int inrange:1; /* True if in range */
};
/*
* 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 $
*/
* 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 $
*/
(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)
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;
* 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;
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.
static __inline int
regexec_e(regex_t *preg, const char *string, int eflags, int nomatch,
- size_t slen)
+ size_t slen)
{
int eval;
.\" 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
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
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
.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