fixed regex initialization

added more support for BACKWARDS option
This commit is contained in:
alm 1993-06-16 07:36:51 +00:00
parent 11169abb0d
commit eca46021bb
14 changed files with 141 additions and 64 deletions

View File

@ -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

View File

@ -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.

View File

@ -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))

View File

@ -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.

View File

@ -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

View File

@ -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;

View File

@ -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)) {

View File

@ -1,4 +1,4 @@
ED= ../ed
ED= ../obj/ed
all: build test
@echo done

View File

@ -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

View File

@ -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
View File

@ -0,0 +1 @@
E !echo hello world-

1
bin/ed/test/e4.r Normal file
View File

@ -0,0 +1 @@
E !echo hello world-

1
bin/ed/test/e4.t Normal file
View File

@ -0,0 +1 @@
e

View File

@ -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