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

PR:		134856
Submitted by:	Jeremie Le Hen - jeremie at le-hen dot org
This commit is contained in:
Brian Somers 2009-05-25 06:45:33 +00:00
parent e6e23ffecb
commit f879e8d923
4 changed files with 39 additions and 18 deletions

View File

@ -181,7 +181,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;
@ -775,6 +775,7 @@ compile_addr(char *p, struct s_addr *a)
icase = 0;
a->type = 0;
switch (*p) {
case '\\': /* Context address */
++p;
@ -798,10 +799,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:

View File

@ -38,8 +38,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 */
};
@ -91,6 +92,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 { */
@ -100,7 +102,6 @@ struct s_command {
} u;
char code; /* Command code */
u_int nonsel:1; /* True if ! */
u_int inrange:1; /* True if in range */
};
/*

View File

@ -275,8 +275,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)
@ -287,18 +287,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;
@ -308,12 +312,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;
@ -331,11 +338,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.

View File

@ -211,6 +211,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
@ -594,7 +597,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