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:
parent
e6e23ffecb
commit
f879e8d923
@ -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:
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user