fixed undo within a global command (would corrupt the buffer)
This commit is contained in:
parent
fe8b331915
commit
aef94df1e8
|
@ -1,5 +1,5 @@
|
|||
PROG= ed
|
||||
CFLAGS+=-DVI_BANG -DDES -DGNU_REGEX -DBACKWARDS
|
||||
CFLAGS+=-DVI_BANG -DDES -DGNU_REGEX
|
||||
SRCS= ed.c re.c buf.c cbc.c
|
||||
LDADD= -lgnuregex -lcrypt
|
||||
LINKS= ${BINDIR}/ed ${BINDIR}/red
|
||||
|
|
12
bin/ed/POSIX
12
bin/ed/POSIX
|
@ -48,3 +48,15 @@ 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.
|
||||
|
||||
Since the behavior of `u' (undo) within a `g' (global) command list is
|
||||
not specified by POSIX D11/2, it follows the behavior of the SunOS ed
|
||||
(this is the best way, I think, in that the alternatives are either too
|
||||
complicated to implement or too confusing to use): undo forces a global
|
||||
command list to be executed only once, rather than for each line matching
|
||||
a global pattern. In addtion, each instance of `u' within a global command
|
||||
undoes all previous commands (including undo's) in the command list.
|
||||
|
||||
The `m' (move) command within a `g' command list also follows the SunOS
|
||||
ed implementation: any moved lines are removed from the global command's
|
||||
`active' list.
|
||||
|
|
46
bin/ed/buf.c
46
bin/ed/buf.c
|
@ -49,13 +49,13 @@ static char sccsid[] = "@(#)buf.c 5.5 (Berkeley) 3/28/93";
|
|||
#include "ed.h"
|
||||
|
||||
extern char errmsg[];
|
||||
extern line_t line0;
|
||||
|
||||
FILE *sfp; /* scratch file pointer */
|
||||
char *sfbuf = NULL; /* scratch file input buffer */
|
||||
int sfbufsz = 0; /* scratch file input buffer size */
|
||||
off_t sfseek; /* scratch file position */
|
||||
int seek_write; /* seek before writing */
|
||||
line_t line0; /* initial node of line queue */
|
||||
|
||||
/* gettxt: get a line of text from the scratch file; return pointer
|
||||
to the text */
|
||||
|
@ -165,7 +165,11 @@ getaddr(lp)
|
|||
|
||||
while (cp != lp && (cp = cp->next) != &line0)
|
||||
n++;
|
||||
return (cp != &line0) ? n : 0;
|
||||
if (n && cp == &line0) {
|
||||
sprintf(errmsg, "invalid address");
|
||||
return ERR;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
|
@ -244,3 +248,41 @@ quit(n)
|
|||
}
|
||||
exit(n);
|
||||
}
|
||||
|
||||
|
||||
unsigned char ctab[256]; /* character translation table */
|
||||
|
||||
/* init_buf: open scratch buffer; initialize line queue */
|
||||
void
|
||||
init_buf()
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (sbopen() < 0)
|
||||
quit(2);
|
||||
requeue(&line0, &line0);
|
||||
for (i = 0; i < 256; i++)
|
||||
ctab[i] = i;
|
||||
}
|
||||
|
||||
|
||||
/* translit: translate characters in a string */
|
||||
char *
|
||||
translit(s, len, from, to)
|
||||
char *s;
|
||||
int len;
|
||||
int from;
|
||||
int to;
|
||||
{
|
||||
static int i = 0;
|
||||
|
||||
unsigned char *us;
|
||||
|
||||
ctab[i] = i; /* restore table to initial state */
|
||||
ctab[i = from] = to;
|
||||
for (us = (unsigned char *) s; len-- > 0; us++)
|
||||
*us = ctab[*us];
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
|
30
bin/ed/ed.1
30
bin/ed/ed.1
|
@ -92,9 +92,9 @@ commands have the structure:
|
|||
.I [address [,address]]command[parameters]
|
||||
.RE
|
||||
.sp
|
||||
The address(es) indicate the line(s) to be affected by the command.
|
||||
If fewer addresses are given than the command accepts, then default
|
||||
addresses are supplied.
|
||||
The address(es) indicate the line or range of lines to be affected by the
|
||||
command. If fewer addresses are given than the command accepts, then
|
||||
default addresses are supplied.
|
||||
|
||||
.SS OPTIONS
|
||||
.TP 8
|
||||
|
@ -311,7 +311,7 @@ not listed below, including `{', '}', `(', `)', `<' and `>',
|
|||
matches itself.
|
||||
|
||||
.TP 8
|
||||
\fR\\\fIc\fR
|
||||
\fR\e\fIc\fR
|
||||
Any backslash-escaped character
|
||||
.IR c ,
|
||||
except for `{', '}', `(', `)', `<' and `>',
|
||||
|
@ -389,28 +389,28 @@ anchors the regular expression to the end of a line.
|
|||
Otherwise, it matches itself.
|
||||
|
||||
.TP 8
|
||||
\fR\\<\fR
|
||||
\fR\e<\fR
|
||||
Anchors the single character regular expression or subexpression
|
||||
immediately following it to the beginning of a word.
|
||||
(This may not be available)
|
||||
|
||||
.TP 8
|
||||
\fR\\>\fR
|
||||
\fR\e>\fR
|
||||
Anchors the single character regular expression or subexpression
|
||||
immediately following it to the end of a word.
|
||||
(This may not be available)
|
||||
|
||||
.TP 8
|
||||
\fR\\(\fIre\fR\\)\fR
|
||||
\fR\e(\fIre\fR\e)\fR
|
||||
Defines a subexpression
|
||||
.IR re .
|
||||
Subexpressions may be nested.
|
||||
A subsequent backreference of the form \fI`\\n'\fR, where
|
||||
A subsequent backreference of the form \fI`\en'\fR, where
|
||||
.I n
|
||||
is a number in the range [1,9], expands to the text matched by the
|
||||
.IR n th
|
||||
subexpression.
|
||||
For example, the regular expression `\\(.*\\)\\1' matches any string
|
||||
For example, the regular expression `\e(.*\e)\e1' matches any string
|
||||
consisting of identical adjacent substrings.
|
||||
Subexpressions are ordered relative to
|
||||
their left delimiter.
|
||||
|
@ -426,7 +426,7 @@ the string `abbb' (as opposed to the substring `bbb'), since a null match
|
|||
is the only left-most match.
|
||||
|
||||
.TP 8
|
||||
\fR\\{\fIn,m\fR\\}\fR or \fR\\{\fIn,\fR\\}\fR or \fR\\{\fIn\fR\\}\fR
|
||||
\fR\e{\fIn,m\fR\e}\fR or \fR\e{\fIn,\fR\e}\fR or \fR\e{\fIn\fR\e}\fR
|
||||
Matches the single character regular expression or subexpression
|
||||
immediately preceding it at least
|
||||
.I n
|
||||
|
@ -735,7 +735,7 @@ An unescaped `&' in
|
|||
.I replacement
|
||||
is replaced by the currently matched text.
|
||||
The character sequence
|
||||
\fI`\\m'\fR,
|
||||
\fI`\em'\fR,
|
||||
where
|
||||
.I m
|
||||
is a number in the range [1,9], is replaced by the
|
||||
|
@ -912,8 +912,8 @@ that line.
|
|||
Buffer file
|
||||
.PD 0
|
||||
.TP 20
|
||||
\fR./ed.hup\fR, $HOME/ed.hup
|
||||
First and second files to which
|
||||
ed.hup
|
||||
The file to which
|
||||
.B ed
|
||||
attempts to write the buffer if the terminal hangs up.
|
||||
|
||||
|
@ -971,6 +971,10 @@ replaces any occurrences of
|
|||
.I old
|
||||
with
|
||||
.IR new .
|
||||
If the
|
||||
.I `u'
|
||||
(undo) command occurs in a global command list, then
|
||||
the command list is executed only once.
|
||||
|
||||
If diagnostics are not disabled, attempting to quit
|
||||
.B ed
|
||||
|
|
255
bin/ed/ed.c
255
bin/ed/ed.c
|
@ -334,11 +334,6 @@ getone()
|
|||
}
|
||||
|
||||
|
||||
#define MAXMARK 26 /* max number of marks */
|
||||
|
||||
line_t *mark[MAXMARK]; /* line markers */
|
||||
int markno; /* line marker count */
|
||||
|
||||
/* getnum: return a relative line number from the command buffer */
|
||||
long
|
||||
getnum(first)
|
||||
|
@ -370,7 +365,7 @@ getnum(first)
|
|||
return first ? curln : 1;
|
||||
case '\'':
|
||||
ibufp++;
|
||||
return (first && islower(*ibufp)) ? getaddr(mark[*ibufp++ - 'a']) : ERR;
|
||||
return first ? getmark(*ibufp++) : ERR;
|
||||
case '%':
|
||||
case ',':
|
||||
case ';':
|
||||
|
@ -583,7 +578,6 @@ doglob(gflag)
|
|||
|
||||
long ucurln = -1; /* if >= 0, undo enabled */
|
||||
long ulastln = -1; /* if >= 0, undo enabled */
|
||||
int usw = 0; /* if set, undo last undo */
|
||||
int patlock = 0; /* if set, pattern not released by optpat() */
|
||||
|
||||
long rows = 22; /* scroll length: ws_row - 2 */
|
||||
|
@ -645,8 +639,8 @@ docmd(glob)
|
|||
} else if ((fnp = getfn()) == NULL)
|
||||
return ERR;
|
||||
VRFYCMD();
|
||||
memset(mark, 0, sizeof mark);
|
||||
lndelete(1, lastln);
|
||||
if (lndelete(1, lastln) < 0)
|
||||
return ERR;
|
||||
ureset();
|
||||
if (sbclose() < 0)
|
||||
return ERR;
|
||||
|
@ -726,13 +720,10 @@ docmd(glob)
|
|||
if (line2 == 0) {
|
||||
sprintf(errmsg, "invalid address");
|
||||
return ERR;
|
||||
} else if (!islower(c)) {
|
||||
sprintf(errmsg, "invalid mark character");
|
||||
return ERR;
|
||||
}
|
||||
VRFYCMD();
|
||||
if (!mark[c - 'a']) markno++;
|
||||
mark[c - 'a'] = getlp(line2);
|
||||
if (putmark(c, getlp(line2)) < 0)
|
||||
return ERR;
|
||||
break;
|
||||
case 'l':
|
||||
if (ckrange(curln, curln) < 0)
|
||||
|
@ -752,9 +743,7 @@ docmd(glob)
|
|||
}
|
||||
VRFYCMD();
|
||||
if (!glob) ureset();
|
||||
if (num == line1 - 1 || num == line2)
|
||||
curln = line2;
|
||||
else if (move(num) < 0)
|
||||
if (move(num, glob) < 0)
|
||||
return ERR;
|
||||
else
|
||||
modified = 1;
|
||||
|
@ -912,7 +901,7 @@ docmd(glob)
|
|||
return ERR;
|
||||
}
|
||||
VRFYCMD();
|
||||
if (undo() < 0)
|
||||
if (undo(glob) < 0)
|
||||
return ERR;
|
||||
break;
|
||||
case 'v':
|
||||
|
@ -1300,74 +1289,6 @@ append(n, glob)
|
|||
}
|
||||
|
||||
|
||||
#ifdef sun
|
||||
/* subst: change all text matching a pattern in a range of lines according to
|
||||
a substitution template; return status */
|
||||
subst(pat, gflag)
|
||||
pattern_t *pat;
|
||||
int gflag;
|
||||
{
|
||||
undo_t *up = NULL;
|
||||
char *txt;
|
||||
char *eot;
|
||||
line_t *bp, *ep, *np;
|
||||
long ocl;
|
||||
long nsubs = 0;
|
||||
int len;
|
||||
|
||||
ep = getlp(curln = line2);
|
||||
for (bp = getlp(line1); bp != ep->next; bp = bp->next)
|
||||
if ((len = regsub(pat, bp, gflag)) < 0)
|
||||
return ERR;
|
||||
else if (!len) {
|
||||
/* add copy of bp after current line - this avoids
|
||||
overloading the undo structure, since only two
|
||||
undo nodes are needed for the whole substitution;
|
||||
the cost is high, but the less than if undo is
|
||||
overloaded on a Sun evidently. XXX */
|
||||
if ((np = lpdup(bp)) == NULL)
|
||||
return ERR;
|
||||
spl1();
|
||||
lpqueue(np);
|
||||
if (up)
|
||||
up->t = getlp(curln);
|
||||
else if ((up = upush(UADD, curln, curln)) == NULL) {
|
||||
spl0();
|
||||
return ERR;
|
||||
}
|
||||
spl0();
|
||||
} else {
|
||||
txt = rbuf;
|
||||
eot = rbuf + len;
|
||||
spl1();
|
||||
do {
|
||||
if ((txt = puttxt(txt)) == NULL) {
|
||||
spl0();
|
||||
return ERR;
|
||||
} else if (up)
|
||||
up->t = getlp(curln);
|
||||
else if ((up = upush(UADD, curln, curln)) == NULL) {
|
||||
spl0();
|
||||
return ERR;
|
||||
}
|
||||
} while (txt != eot);
|
||||
spl0();
|
||||
nsubs++;
|
||||
}
|
||||
ocl = curln;
|
||||
lndelete(line1, line2);
|
||||
curln = ocl - (line2 - line1 + 1);
|
||||
if (nsubs == 0 && !(gflag & GLB)) {
|
||||
sprintf(errmsg, "no match");
|
||||
return ERR;
|
||||
} else if ((gflag & (GPR | GLS | GNP))
|
||||
&& doprint(curln, curln, gflag) < 0)
|
||||
return ERR;
|
||||
return 1;
|
||||
}
|
||||
#else /* sun */
|
||||
|
||||
|
||||
/* subst: change all text matching a pattern in a range of lines according to
|
||||
a substitution template; return status */
|
||||
subst(pat, gflag)
|
||||
|
@ -1389,7 +1310,8 @@ subst(pat, gflag)
|
|||
return ERR;
|
||||
else if (len) {
|
||||
up = NULL;
|
||||
lndelete(curln, curln);
|
||||
if (lndelete(curln, curln) < 0)
|
||||
return ERR;
|
||||
txt = rbuf;
|
||||
eot = rbuf + len;
|
||||
spl1();
|
||||
|
@ -1416,7 +1338,6 @@ subst(pat, gflag)
|
|||
return ERR;
|
||||
return 1;
|
||||
}
|
||||
#endif /* sun */
|
||||
|
||||
|
||||
/* regsub: replace text matched by a pattern according to a substitution
|
||||
|
@ -1498,7 +1419,8 @@ join(from, to)
|
|||
}
|
||||
CKBUF(buf, n, size + 2, ERR);
|
||||
memcpy(buf + size, "\n", 2);
|
||||
lndelete(from, to);
|
||||
if (lndelete(from, to) < 0)
|
||||
return ERR;
|
||||
curln = from - 1;
|
||||
spl1();
|
||||
if (puttxt(buf) == NULL
|
||||
|
@ -1513,19 +1435,25 @@ join(from, to)
|
|||
|
||||
|
||||
/* move: move a range of lines */
|
||||
move(num)
|
||||
move(num, glob)
|
||||
long num;
|
||||
int glob;
|
||||
{
|
||||
line_t *b1, *a1, *b2, *a2;
|
||||
line_t *b1, *a1, *b2, *a2, *lp;
|
||||
long n = nextln(line2, lastln);
|
||||
long p = prevln(line1, lastln);
|
||||
int done = (num == line1 - 1 || num == line2);
|
||||
|
||||
spl1();
|
||||
if (upush(UMOV, p, n) == NULL
|
||||
if (done) {
|
||||
a2 = getlp(n);
|
||||
b2 = getlp(p);
|
||||
curln = line2;
|
||||
} else if (upush(UMOV, p, n) == NULL
|
||||
|| upush(UMOV, num, nextln(num, lastln)) == NULL) {
|
||||
spl0();
|
||||
return ERR;
|
||||
}
|
||||
} else {
|
||||
a1 = getlp(n);
|
||||
if (num < line1)
|
||||
b1 = getlp(p), b2 = getlp(num); /* this getlp last! */
|
||||
|
@ -1535,6 +1463,10 @@ move(num)
|
|||
requeue(a1->prev, a2);
|
||||
requeue(b1, a1);
|
||||
curln = num + ((num < line1) ? line2 - line1 + 1 : 0);
|
||||
}
|
||||
if (glob)
|
||||
for (lp = b2->next; lp != a2; lp = lp->next)
|
||||
lp->len &= ~ACTV; /* zero ACTV bit */
|
||||
spl0();
|
||||
return 0;
|
||||
}
|
||||
|
@ -1857,7 +1789,6 @@ undo_t *ustack = NULL; /* undo stack */
|
|||
long usize = 0; /* stack size variable */
|
||||
long u_p = 0; /* undo stack pointer */
|
||||
|
||||
|
||||
/* upush: return pointer to intialized undo node */
|
||||
undo_t *
|
||||
upush(type, from, to)
|
||||
|
@ -1894,14 +1825,22 @@ upush(type, from, to)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* USWAP: swap undo nodes */
|
||||
#define USWAP(x,y) { \
|
||||
undo_t utmp; \
|
||||
utmp = x, x = y, y = utmp; \
|
||||
}
|
||||
|
||||
|
||||
/* undo: undo last change to the editor buffer */
|
||||
undo()
|
||||
undo(glob)
|
||||
int glob;
|
||||
{
|
||||
long n = usw ? 0 : u_p - 1;
|
||||
int i = usw ? 1 : -1;
|
||||
long j = u_p;
|
||||
long n;
|
||||
long ocurln = curln;
|
||||
long olastln = lastln;
|
||||
line_t *lp, *np;
|
||||
|
||||
if (ucurln == -1 || ulastln == -1) {
|
||||
sprintf(errmsg, "nothing to undo");
|
||||
|
@ -1910,8 +1849,8 @@ undo()
|
|||
modified = 1;
|
||||
getlp(0); /* this getlp last! */
|
||||
spl1();
|
||||
for (; j-- > 0; n += i)
|
||||
switch(ustack[n].type ^ usw) {
|
||||
for (n = u_p; n-- > 0;) {
|
||||
switch(ustack[n].type) {
|
||||
case UADD:
|
||||
requeue(ustack[n].h->prev, ustack[n].t->next);
|
||||
break;
|
||||
|
@ -1921,16 +1860,23 @@ undo()
|
|||
break;
|
||||
case UMOV:
|
||||
case VMOV:
|
||||
requeue(ustack[n + i].h, ustack[n].h->next);
|
||||
requeue(ustack[n].t->prev, ustack[n + i].t);
|
||||
requeue(ustack[n - 1].h, ustack[n].h->next);
|
||||
requeue(ustack[n].t->prev, ustack[n - 1].t);
|
||||
requeue(ustack[n].h, ustack[n].t);
|
||||
n += i, j--;
|
||||
n--;
|
||||
break;
|
||||
default:
|
||||
/*NOTREACHED*/
|
||||
;
|
||||
}
|
||||
usw = 1 - usw;
|
||||
ustack[n].type ^= 1;
|
||||
}
|
||||
/* reverse undo order */
|
||||
for (n = u_p; n-- > (u_p + 1)/ 2;)
|
||||
USWAP(ustack[n], ustack[u_p - 1 - n]);
|
||||
if (glob)
|
||||
for (lp = np = getlp(0); (lp = lp->next) != np;)
|
||||
lp->len &= ~ACTV; /* zero ACTV bit */
|
||||
curln = ucurln, ucurln = ocurln;
|
||||
lastln = ulastln, ulastln = olastln;
|
||||
spl0();
|
||||
|
@ -1943,29 +1889,71 @@ void
|
|||
ureset()
|
||||
{
|
||||
line_t *lp, *ep, *tl;
|
||||
int i;
|
||||
|
||||
while (u_p--)
|
||||
if ((ustack[u_p].type ^ usw) == UDEL) {
|
||||
if (ustack[u_p].type == UDEL) {
|
||||
ep = ustack[u_p].t->next;
|
||||
for (lp = ustack[u_p].h; lp != ep; lp = tl) {
|
||||
clrmark(lp);
|
||||
tl = lp->next;
|
||||
free(lp);
|
||||
}
|
||||
}
|
||||
u_p = 0;
|
||||
ucurln = curln;
|
||||
ulastln = lastln;
|
||||
}
|
||||
|
||||
|
||||
#define MAXMARK 26 /* max number of marks */
|
||||
|
||||
line_t *mark[MAXMARK]; /* line markers */
|
||||
int markno; /* line marker count */
|
||||
|
||||
/* getmark: return address of a marked line */
|
||||
int
|
||||
getmark(n)
|
||||
int n;
|
||||
{
|
||||
if (!islower(n)) {
|
||||
sprintf(errmsg, "invalid mark character");
|
||||
return ERR;
|
||||
}
|
||||
return getaddr(mark[n - 'a']);
|
||||
}
|
||||
|
||||
|
||||
/* putmark: set a line node mark */
|
||||
int
|
||||
putmark(n, lp)
|
||||
int n;
|
||||
line_t *lp;
|
||||
{
|
||||
if (!islower(n)) {
|
||||
sprintf(errmsg, "invalid mark character");
|
||||
return ERR;
|
||||
} else if (mark[n - 'a'] == NULL)
|
||||
markno++;
|
||||
mark[n - 'a'] = lp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* clrmark: clear line node marks */
|
||||
void
|
||||
clrmark(lp)
|
||||
line_t *lp;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (markno)
|
||||
for (i = 0; i < MAXMARK; i++)
|
||||
if (mark[i] == lp) {
|
||||
mark[i] = NULL;
|
||||
markno--;
|
||||
}
|
||||
tl = lp->next;
|
||||
free(lp);
|
||||
}
|
||||
}
|
||||
u_p = usw = 0;
|
||||
ucurln = curln;
|
||||
ulastln = lastln;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* sgetline: read a line of text up a maximum size from a file; return
|
||||
line length */
|
||||
sgetline(fp)
|
||||
|
@ -2146,7 +2134,6 @@ onintr(signo)
|
|||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
dohup(signo)
|
||||
int signo;
|
||||
|
@ -2201,44 +2188,6 @@ dowinch(signo)
|
|||
}
|
||||
|
||||
|
||||
unsigned char ctab[256]; /* character translation table */
|
||||
|
||||
/* translit: translate characters in a string */
|
||||
char *
|
||||
translit(s, len, from, to)
|
||||
char *s;
|
||||
int len;
|
||||
int from;
|
||||
int to;
|
||||
{
|
||||
static int i = 0;
|
||||
|
||||
unsigned char *us;
|
||||
|
||||
ctab[i] = i; /* restore table to initial state */
|
||||
ctab[i = from] = to;
|
||||
for (us = (unsigned char *) s; len-- > 0; us++)
|
||||
*us = ctab[*us];
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
line_t line0; /* initial node of line queue */
|
||||
|
||||
/* init_buf: open scratch buffer; initialize line queue */
|
||||
void
|
||||
init_buf()
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (sbopen() < 0)
|
||||
quit(2);
|
||||
requeue(&line0, &line0);
|
||||
for (i = 0; i < 256; i++)
|
||||
ctab[i] = i;
|
||||
}
|
||||
|
||||
|
||||
/* ckfn: return a legal filename */
|
||||
char *
|
||||
ckfn(s)
|
||||
|
|
|
@ -206,6 +206,7 @@ int desputc __P((int, FILE *));
|
|||
int docmd __P((int));
|
||||
void err __P((char *));
|
||||
char *ccl __P((char *));
|
||||
void clrmark __P((line_t *));
|
||||
void cvtkey __P((char *, char *));
|
||||
long doglob __P((int));
|
||||
void dohup __P((int));
|
||||
|
@ -223,6 +224,7 @@ int getkey __P((void));
|
|||
char *getlhs __P((int));
|
||||
int getline __P((void));
|
||||
int getlist __P((void));
|
||||
int getmark __P((int));
|
||||
long getnum __P((int));
|
||||
long getone __P((void));
|
||||
line_t *getlp __P((long));
|
||||
|
@ -236,12 +238,12 @@ line_t *lpdup __P((line_t *));
|
|||
void lpqueue __P((line_t *));
|
||||
void makekey __P((char *));
|
||||
char *makesub __P((int));
|
||||
char *translit __P((char *, int, int, int));
|
||||
int move __P((long));
|
||||
int move __P((long, int));
|
||||
int oddesc __P((char *, char *));
|
||||
void onhup __P((int));
|
||||
void onintr __P((int));
|
||||
pattern_t *optpat __P((void));
|
||||
int putmark __P((int, line_t *));
|
||||
void putstr __P((char *, int, long, int));
|
||||
char *puttxt __P((char *));
|
||||
void quit __P((int));
|
||||
|
@ -253,7 +255,8 @@ int catsub __P((char *, regmatch_t *, int));
|
|||
int subst __P((pattern_t *, int));
|
||||
int tobinhex __P((int, int));
|
||||
int transfer __P((long));
|
||||
int undo __P((void));
|
||||
char *translit __P((char *, int, int, int));
|
||||
int undo __P((int));
|
||||
undo_t *upush __P((int, long, long));
|
||||
void ureset __P((void));
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ optpat()
|
|||
sprintf(errmsg, "invalid pattern delimiter");
|
||||
return NULL;
|
||||
} else if (*ibufp == delim) {
|
||||
sprintf(errmsg, "no previous pattern");
|
||||
if (!exp) sprintf(errmsg, "no previous pattern");
|
||||
return exp;
|
||||
} else if ((exps = getlhs(delim)) == NULL)
|
||||
return NULL;
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
line5
|
|
@ -0,0 +1,5 @@
|
|||
linc 3
|
||||
xine 1
|
||||
xine 2
|
||||
xinc 4
|
||||
xinc5
|
|
@ -0,0 +1,4 @@
|
|||
g/./s//x/\
|
||||
3m0
|
||||
g/./s/e/c/\
|
||||
2,3m1
|
|
@ -0,0 +1,5 @@
|
|||
line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
line5
|
|
@ -0,0 +1,7 @@
|
|||
hello
|
||||
zine 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
line5
|
||||
world
|
|
@ -0,0 +1,13 @@
|
|||
g/./s/./x/\
|
||||
u\
|
||||
s/./y/\
|
||||
u\
|
||||
s/./z/\
|
||||
u
|
||||
u
|
||||
0a
|
||||
hello
|
||||
.
|
||||
$a
|
||||
world
|
||||
.
|
Loading…
Reference in New Issue