fixed regex initialization
added more support for BACKWARDS option
This commit is contained in:
parent
11169abb0d
commit
eca46021bb
@ -1,5 +1,5 @@
|
||||
PROG= ed
|
||||
CFLAGS+=-DVI_BANG -DDES -DGNU_REGEX
|
||||
CFLAGS+=-DVI_BANG -DDES -DGNU_REGEX -DBACKWARDS
|
||||
SRCS= ed.c re.c buf.c cbc.c
|
||||
LDADD= -lgnuregex -lcrypt
|
||||
LINKS= ${BINDIR}/ed ${BINDIR}/red
|
||||
|
10
bin/ed/POSIX
10
bin/ed/POSIX
@ -41,6 +41,10 @@ If ed is invoked with a name argument prefixed by a bang, then the
|
||||
remainder of the argument is interpreted as a shell command. To invoke
|
||||
ed on a file whose name starts with bang, prefix the name with a backslash.
|
||||
|
||||
A restricted version of ed is supported when invoked as red. This limits
|
||||
editing of files in the local directory only and prohibits !<shell-cmd>
|
||||
commands.
|
||||
ed runs in restricted mode if invoked as red. This limits editing of
|
||||
files in the local directory only and prohibits !<shell-cmd> commands.
|
||||
|
||||
Though ed is not a binary editor, it can be used (if painfully) to edit
|
||||
binary files. To assist in binary editing, when a file containing at
|
||||
least one ASCII NUL character is written, a newline is not appended
|
||||
if it did not already contain one upon reading.
|
||||
|
@ -2,6 +2,10 @@ ed is an 8-bit-clean, POSIX-compliant line editor. It should work with
|
||||
any regular expression package that conforms to the POSIX interface
|
||||
standard, such as GNU regex(3).
|
||||
|
||||
If reliable signals are supported (e.g., POSIX sigaction(2)), it should
|
||||
compile with little trouble. Otherwise, the macros spl1() and spl0()
|
||||
should be redefined to disable interrupts.
|
||||
|
||||
The following compiler directives are recognized:
|
||||
GNU_REGEX - use with GNU regex(3)
|
||||
DES - use to add encryption support (requires crypt(3))
|
||||
|
111
bin/ed/ed.1
111
bin/ed/ed.1
@ -11,9 +11,9 @@ is a line-oriented text editor.
|
||||
It is used to create, display, modify and otherwise manipulate text
|
||||
files.
|
||||
.B red
|
||||
is a restricted
|
||||
is a restricted
|
||||
.BR ed :
|
||||
it can edit files only in the current
|
||||
it can only edit files in the current
|
||||
directory and cannot execute shell commands.
|
||||
|
||||
If invoked with a
|
||||
@ -37,7 +37,7 @@ and
|
||||
When first invoked,
|
||||
.B ed
|
||||
is in command mode.
|
||||
In this mode editing commands are read from the standard input and
|
||||
In this mode commands are read from the standard input and
|
||||
executed to manipulate the contents of the editor buffer.
|
||||
A typical command might look like:
|
||||
.sp
|
||||
@ -62,9 +62,10 @@ enters input mode. This is the primary means
|
||||
of adding text to a file.
|
||||
In this mode, no commands are available;
|
||||
instead, the standard input is written
|
||||
directly to the editor buffer. Lines must end with a
|
||||
directly to the editor buffer. Lines consist of text up to and
|
||||
including a
|
||||
.IR newline
|
||||
character (entered by hitting the RETURN key).
|
||||
character.
|
||||
Input mode is terminated by
|
||||
entering a single period (\fI.\fR) on a line.
|
||||
|
||||
@ -333,13 +334,13 @@ of the range with a `-', e.g., `a-z' specifies the lower case characters.
|
||||
The following literal expressions can also be used in
|
||||
.I char-class
|
||||
to specify sets of characters:
|
||||
|
||||
.sp
|
||||
\ \ [:alnum:]\ \ [:cntrl:]\ \ [:lower:]\ \ [:space:]
|
||||
.PD 0
|
||||
\ \ [:alpha:]\ \ [:digit:]\ \ [:print:]\ \ [:upper:]
|
||||
.PD 0
|
||||
\ \ [:blank:]\ \ [:graph:]\ \ [:punct:]\ \ [:xdigit:]
|
||||
|
||||
.sp
|
||||
If `-' appears as the first or last
|
||||
character of
|
||||
.IR char-class ,
|
||||
@ -347,15 +348,15 @@ then it matches itself.
|
||||
All other characters in
|
||||
.I char-class
|
||||
match themselves.
|
||||
|
||||
.sp
|
||||
Patterns in
|
||||
.I char-class
|
||||
of the form:
|
||||
|
||||
of the form:
|
||||
.sp
|
||||
\ \ [.\fIcol-elm\fR.] or,
|
||||
.PD 0
|
||||
\ \ [=\fIcol-elm\fR=]
|
||||
|
||||
.sp
|
||||
where
|
||||
.I col-elm
|
||||
is a
|
||||
@ -367,7 +368,6 @@ See
|
||||
.IR regex (3)
|
||||
for an explanation of these constructs.
|
||||
|
||||
|
||||
.TP 8
|
||||
[^\fIchar-class\fR]
|
||||
Matches any single character, other than newline, not in
|
||||
@ -510,7 +510,7 @@ The current address is set to the last line read.
|
||||
.TP 8
|
||||
.RI e \ !command
|
||||
Edits the standard output of
|
||||
.I !command
|
||||
.IR `!command' ,
|
||||
executed as described below.
|
||||
The default filename is unchanged.
|
||||
Any lines in the buffer are deleted before the output of
|
||||
@ -519,9 +519,9 @@ is read.
|
||||
The current address is set to the last line read.
|
||||
|
||||
.TP 8
|
||||
.RI E \ name
|
||||
.RI E \ file
|
||||
Edits
|
||||
.I name
|
||||
.I file
|
||||
unconditionally.
|
||||
This is similar to the
|
||||
.I e
|
||||
@ -530,18 +530,12 @@ except that unwritten changes are discarded without warning.
|
||||
The current address is set to the last line read.
|
||||
|
||||
.TP 8
|
||||
.RI f \ name
|
||||
.RI f \ file
|
||||
Sets the default filename to
|
||||
.IR name .
|
||||
.IR file .
|
||||
If
|
||||
.I name
|
||||
.I file
|
||||
is not specified, then the default unescaped filename is printed.
|
||||
If
|
||||
.I name
|
||||
is prefixed with a bang (!), then
|
||||
it is executed as a command via
|
||||
.IR sh (1),
|
||||
in subsequent reads and writes.
|
||||
|
||||
.TP 8
|
||||
.RI (1,$)g /re/command-list
|
||||
@ -569,6 +563,11 @@ Any commands are allowed, except for
|
||||
.IR `v' ,
|
||||
and
|
||||
.IR `V' .
|
||||
A newline alone in
|
||||
.I command-list
|
||||
is equivalent to a
|
||||
.I `p'
|
||||
command.
|
||||
|
||||
.TP 8
|
||||
.RI (1,$)G /re/
|
||||
@ -577,14 +576,17 @@ Interactively edits the addressed lines matching a regular expression
|
||||
For each matching line,
|
||||
the line is printed,
|
||||
the current address is set,
|
||||
and the user is prompted to enter a command list.
|
||||
and the user is prompted to enter a
|
||||
.IR command-list .
|
||||
At the end of the
|
||||
.I `G'
|
||||
command, the current address
|
||||
is set to the last line affected by the command
|
||||
list.
|
||||
is set to the last line affected by (the last)
|
||||
.IR command-list .
|
||||
|
||||
The format of the command list is the same as that of the
|
||||
The format of
|
||||
.I command-list
|
||||
is the same as that of the
|
||||
.I `g'
|
||||
command. A newline alone acts as a null command list.
|
||||
A single `&' repeats the last non-null command list.
|
||||
@ -683,15 +685,22 @@ The current address is set to the last line read.
|
||||
|
||||
.TP 8
|
||||
.RI ($)r \ !command
|
||||
Reads the standard output of
|
||||
.I !command
|
||||
Reads
|
||||
to after the addressed line
|
||||
the standard output of
|
||||
.IR `!command' ,
|
||||
executed as described below.
|
||||
to after the addressed line.
|
||||
The default filename is unchanged.
|
||||
The current address is set to the last line read.
|
||||
|
||||
.TP 8
|
||||
.RI (.,.)s /re/replacement/[gn]
|
||||
.HP
|
||||
.RI (.,.)s /re/replacement/
|
||||
.PD 0
|
||||
.HP
|
||||
.RI (.,.)s /re/replacement/\fRg\fR
|
||||
.HP
|
||||
.RI (.,.)s /re/replacement/n
|
||||
.br
|
||||
Replaces text in the addressed lines
|
||||
matching a regular expression
|
||||
.I re
|
||||
@ -708,6 +717,8 @@ suffix, where
|
||||
is a postive number, causes only the
|
||||
.IR n th
|
||||
match to be replaced.
|
||||
It is an error if no substitutions are performed on any of the addressed
|
||||
lines.
|
||||
The current address is set the last line affected.
|
||||
|
||||
.I re
|
||||
@ -735,12 +746,12 @@ If
|
||||
consists of a single `%', then
|
||||
.I replacement
|
||||
from the last substitution is used.
|
||||
Newlines may be included in
|
||||
Newlines may be embedded in
|
||||
.I replacement
|
||||
if they are escaped with a backslash (\\).
|
||||
|
||||
.TP 8
|
||||
.RI (.,.)s [rgp]*
|
||||
(.,.)s
|
||||
Repeats the last substitution.
|
||||
This form of the
|
||||
.I `s'
|
||||
@ -828,7 +839,7 @@ command.
|
||||
.TP 8
|
||||
.RI (1,$)w \ !command
|
||||
Writes the addressed lines to the standard input of
|
||||
.I !command
|
||||
.IR `!command' ,
|
||||
executed as described below.
|
||||
The default filename and current address are unchanged.
|
||||
|
||||
@ -867,14 +878,14 @@ If the first character of
|
||||
.I command
|
||||
is `!', then it is replaced by text of the
|
||||
previous
|
||||
.IR !command .
|
||||
.IR `!command' .
|
||||
.B ed
|
||||
does not process
|
||||
.I command
|
||||
for backslash (\\) escapes.
|
||||
However, an unescaped
|
||||
.I `%'
|
||||
is replaced by the default file name.
|
||||
is replaced by the default filename.
|
||||
When the shell returns from execution, a `!'
|
||||
is printed to the standard output.
|
||||
The current line is unchanged.
|
||||
@ -882,7 +893,7 @@ The current line is unchanged.
|
||||
.TP 8
|
||||
.RI (.,.)! command
|
||||
Replaces the addressed lines with the output of
|
||||
.I !command
|
||||
.I `!command'
|
||||
as described above.
|
||||
The current address is set to the last line read.
|
||||
|
||||
@ -931,9 +942,9 @@ interpreted literally.
|
||||
If a text (non-binary) file is not terminated by a newline character,
|
||||
then
|
||||
.B ed
|
||||
appends one on writing it. In the case of a binary file,
|
||||
appends one on reading/writing it. In the case of a binary file,
|
||||
.B ed
|
||||
does not append a newline on writing.
|
||||
does not append a newline on reading/writing.
|
||||
|
||||
per line overhead: 4 ints
|
||||
|
||||
@ -945,9 +956,23 @@ or exits if its input is from a script.
|
||||
An explanation of the last error can be
|
||||
printed with the
|
||||
.I `h'
|
||||
command.
|
||||
(help) command.
|
||||
|
||||
Attempting to quit
|
||||
Since the
|
||||
.I `g'
|
||||
(global) command masks any errors from failed searches and substitutions,
|
||||
it can be used to perform conditional operations in scripts; e.g.,
|
||||
.sp
|
||||
.RS
|
||||
g/\fIold\fR/s//\fInew\fR/
|
||||
.RE
|
||||
.sp
|
||||
replaces any occurrences of
|
||||
.I old
|
||||
with
|
||||
.IR new .
|
||||
|
||||
If diagnostics are not disabled, attempting to quit
|
||||
.B ed
|
||||
or edit another file before writing a modified buffer
|
||||
results in an error.
|
||||
|
61
bin/ed/ed.c
61
bin/ed/ed.c
@ -138,6 +138,7 @@ main(argc, argv)
|
||||
long status = 0;
|
||||
|
||||
red = (n = strlen(argv[0])) > 2 && argv[0][n - 3] == 'r';
|
||||
top:
|
||||
while ((c = getopt(argc, argv, "p:sx")) != EOF)
|
||||
switch(c) {
|
||||
case 'p': /* set prompt */
|
||||
@ -162,8 +163,12 @@ main(argc, argv)
|
||||
argc -= optind;
|
||||
if (argc && **argv == '-') {
|
||||
scripted = 1;
|
||||
argc--;
|
||||
if (argc > 1) {
|
||||
optind = 1;
|
||||
goto top;
|
||||
}
|
||||
argv++;
|
||||
argc--;
|
||||
}
|
||||
/* assert: reliable signals! */
|
||||
#ifdef SIGWINCH
|
||||
@ -474,8 +479,16 @@ doglob(gflag)
|
||||
int interact = gflag & ~GSG; /* GLB & gflag ? */
|
||||
char *cmd = NULL;
|
||||
|
||||
#ifdef BACKWARDS
|
||||
if (!interact)
|
||||
if (!strcmp(ibufp, "\n"))
|
||||
cmd = "p\n"; /* null cmd-list == `p' */
|
||||
else if ((cmd = getcmdv(&n, 0)) == NULL)
|
||||
return ERR;
|
||||
#else
|
||||
if (!interact && (cmd = getcmdv(&n, 0)) == NULL)
|
||||
return ERR;
|
||||
#endif
|
||||
ureset();
|
||||
for (;;) {
|
||||
for (lp = getlp(lc = 1); lc <= lastln; lc++, lp = lp->next)
|
||||
@ -525,6 +538,26 @@ doglob(gflag)
|
||||
}
|
||||
|
||||
|
||||
#ifdef BACKWARDS
|
||||
/* GETLINE3: get a legal address from the command buffer */
|
||||
#define GETLINE3(num) \
|
||||
{ \
|
||||
long ol1, ol2; \
|
||||
\
|
||||
ol1 = line1, ol2 = line2; \
|
||||
if (getlist() < 0) \
|
||||
return ERR; \
|
||||
else if (nlines == 0) { \
|
||||
sprintf(errmsg, "destination expected"); \
|
||||
return ERR; \
|
||||
} else if (line2 < 0 || lastln < line2) { \
|
||||
sprintf(errmsg, "invalid address"); \
|
||||
return ERR; \
|
||||
} \
|
||||
num = line2; \
|
||||
line1 = ol1, line2 = ol2; \
|
||||
}
|
||||
#else /* BACKWARDS */
|
||||
/* GETLINE3: get a legal address from the command buffer */
|
||||
#define GETLINE3(num) \
|
||||
{ \
|
||||
@ -540,6 +573,7 @@ doglob(gflag)
|
||||
num = line2; \
|
||||
line1 = ol1, line2 = ol2; \
|
||||
}
|
||||
#endif
|
||||
|
||||
/* sgflags */
|
||||
#define SGG 001 /* complement previous global substitute suffix */
|
||||
@ -598,7 +632,7 @@ docmd(glob)
|
||||
modified = 1;
|
||||
break;
|
||||
case 'e':
|
||||
if (modified)
|
||||
if (modified && !scripted)
|
||||
return EMOD;
|
||||
/* fall through */
|
||||
case 'E':
|
||||
@ -756,7 +790,7 @@ docmd(glob)
|
||||
return ERR;
|
||||
}
|
||||
VRFYCMD();
|
||||
gflag = (modified && !scripted && c != 'Q') ? EMOD : EOF;
|
||||
gflag = (modified && !scripted && c == 'q') ? EMOD : EOF;
|
||||
break;
|
||||
case 'r':
|
||||
if (!isspace(*ibufp)) {
|
||||
@ -912,7 +946,7 @@ docmd(glob)
|
||||
return ERR;
|
||||
else if (num == lastln)
|
||||
modified = 0;
|
||||
else if (n == 'q' && modified)
|
||||
else if (modified && !scripted && n == 'q')
|
||||
gflag = EMOD;
|
||||
break;
|
||||
case 'x':
|
||||
@ -929,7 +963,11 @@ docmd(glob)
|
||||
#endif
|
||||
break;
|
||||
case 'z':
|
||||
#ifdef BACKWARDS
|
||||
if (ckrange(line1 = 1, curln + 1) < 0)
|
||||
#else
|
||||
if (ckrange(line1 = 1, curln + !glob) < 0)
|
||||
#endif
|
||||
return ERR;
|
||||
else if ('0' < *ibufp && *ibufp <= '9')
|
||||
rows = strtol(ibufp, &ibufp, 10);
|
||||
@ -979,7 +1017,11 @@ docmd(glob)
|
||||
break;
|
||||
#endif
|
||||
case '\n':
|
||||
#ifdef BACKWARDS
|
||||
if (ckrange(line1 = 1, curln + 1) < 0
|
||||
#else
|
||||
if (ckrange(line1 = 1, curln + !glob) < 0
|
||||
#endif
|
||||
|| doprint(line2, line2, 0) < 0)
|
||||
return ERR;
|
||||
break;
|
||||
@ -1689,7 +1731,7 @@ putstr(s, l, n, gflag)
|
||||
}
|
||||
|
||||
|
||||
int newline_added; /* long record split across lines */
|
||||
int newline_added; /* set if newline appended to input file */
|
||||
|
||||
/* doread: read a text file into the editor buffer; return line count */
|
||||
long
|
||||
@ -2008,7 +2050,7 @@ getcmdv(sizep, nonl)
|
||||
while (*t++ != '\n')
|
||||
;
|
||||
if ((l = t - ibufp) < 2 || !oddesc(ibufp, ibufp + l - 1)) {
|
||||
*sizep = l;
|
||||
*sizep = l;
|
||||
return ibufp;
|
||||
}
|
||||
*sizep = -1;
|
||||
@ -2025,7 +2067,8 @@ getcmdv(sizep, nonl)
|
||||
}
|
||||
CKBUF(cvbuf, cvbufsz, l + n, NULL);
|
||||
memcpy(cvbuf + l, ibuf, n);
|
||||
if (n < 2 || !oddesc(cvbuf, cvbuf + (l += n) - 1))
|
||||
l += n;
|
||||
if (n < 2 || !oddesc(cvbuf, cvbuf + l - 1))
|
||||
break;
|
||||
*(cvbuf + --l - 1) = '\n'; /* strip trailing esc */
|
||||
if (nonl) l--; /* strip newline */
|
||||
@ -2112,7 +2155,7 @@ dohup(signo)
|
||||
char *s;
|
||||
int n;
|
||||
|
||||
if (!sigactive)
|
||||
if (!sigactive)
|
||||
quit(1);
|
||||
sigflags &= ~(1 << signo);
|
||||
if (lastln && dowrite(1, lastln, "ed.hup", "w") < 0
|
||||
@ -2133,7 +2176,7 @@ void
|
||||
dointr(signo)
|
||||
int signo;
|
||||
{
|
||||
if (!sigactive)
|
||||
if (!sigactive)
|
||||
quit(1);
|
||||
sigflags &= ~(1 << signo);
|
||||
#ifdef _POSIX_SOURCE
|
||||
|
@ -66,10 +66,6 @@
|
||||
|
||||
typedef regex_t pattern_t;
|
||||
|
||||
#ifdef GNU_REGEX
|
||||
# define FASTMAP_SIZE 256 /* size of fasmap for 8 bit character set */
|
||||
#endif
|
||||
|
||||
/* Line node */
|
||||
typedef struct line {
|
||||
struct line *next;
|
||||
|
@ -88,7 +88,7 @@ optpat()
|
||||
/* initialize pattern buffer */
|
||||
exp->buffer = NULL;
|
||||
exp->allocated = 0L;
|
||||
exp->fastmap = (char *) malloc(FASTMAP_SIZE);
|
||||
exp->fastmap = 0; /* not used by GNU regex after 0.12 */
|
||||
exp->translate = 0;
|
||||
#endif
|
||||
if (n = regcomp(exp, exps, 0)) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
ED= ../ed
|
||||
ED= ../obj/ed
|
||||
|
||||
all: build test
|
||||
@echo done
|
||||
|
@ -11,3 +11,5 @@ Some missing tests:
|
||||
6) ed -x - verify: 8-bit clean
|
||||
7) ed - verify: long-line support
|
||||
8) ed - verify: interactive/help mode
|
||||
9) G/pat/ - verify: global interactive command
|
||||
10) V/pat/ - verify: global interactive command
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
PATH="/bin:/usr/bin:/usr/local/bin/:."
|
||||
ED=$1
|
||||
[ X"$ED" = X ] && ED="../ed"
|
||||
[ X"$ED" = X -o ! -x $ED ] && ED="../ed"
|
||||
[ ! -x $ED ] && { echo "$ED: cannot execute"; exit 1; }
|
||||
|
||||
# Run the *-err.ed scripts first, since these don't generate output;
|
||||
|
1
bin/ed/test/e4.d
Normal file
1
bin/ed/test/e4.d
Normal file
@ -0,0 +1 @@
|
||||
E !echo hello world-
|
1
bin/ed/test/e4.r
Normal file
1
bin/ed/test/e4.r
Normal file
@ -0,0 +1 @@
|
||||
E !echo hello world-
|
1
bin/ed/test/e4.t
Normal file
1
bin/ed/test/e4.t
Normal file
@ -0,0 +1 @@
|
||||
e
|
@ -3,7 +3,7 @@
|
||||
|
||||
PATH="/bin:/usr/bin:/usr/local/bin/:."
|
||||
ED=$1
|
||||
[ X"$ED" = X ] && ED="../ed"
|
||||
[ X"$ED" = X -o ! -x $ED ] && ED="../ed"
|
||||
[ ! -x $ED ] && { echo "$ED: cannot execute"; exit 1; }
|
||||
|
||||
for i in *.t; do
|
||||
|
Loading…
Reference in New Issue
Block a user