Fixed range address bug: 1,2, == 2,2 not 2,.
Overhauled the name space, reworked some modules and removed the obsolescent Addison-Wesley copyright.
This commit is contained in:
parent
52b9b80a1f
commit
8f826dd116
@ -1,8 +1,7 @@
|
||||
PROG= ed
|
||||
CFLAGS+=-DVI_BANG
|
||||
SRCS= ed.c re.c buf.c cbc.c
|
||||
LINKS= ${BINDIR}/ed ${BINDIR}/red
|
||||
MLINKS= ed.1 red.1
|
||||
SRCS= buf.c cbc.c glob.c io.c main.c re.c sub.c undo.c
|
||||
LINKS= ${BINDIR}/ed ${BINDIR}/red
|
||||
MLINKS= ed.1 red.1
|
||||
|
||||
.if exists(/usr/lib/libcrypt.a)
|
||||
CFLAGS+=-DDES
|
||||
@ -10,7 +9,4 @@ LDADD+= -lcrypt
|
||||
DPADD+= ${LIBCRYPT}
|
||||
.endif
|
||||
|
||||
LDADD+= -lgnuregex
|
||||
DPADD+= /usr/lib/libgnuregex.a
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
143
bin/ed/POSIX
143
bin/ed/POSIX
@ -1,62 +1,101 @@
|
||||
This version of ed is not strictly POSIX compliant, as described in the
|
||||
POSIX 1003.2 Draft 11.2 document. BSD commands have been implemented
|
||||
wherever they do not conflict with the POSIX standard. For backwards
|
||||
compatibility, the POSIX rule that says a range of addresses cannot be
|
||||
used where only a single address is expected has been relaxed.
|
||||
This version of ed(1) is not strictly POSIX compliant, as described in
|
||||
the POSIX 1003.2 document. The following is a summary of the omissions,
|
||||
extensions and possible deviations from POSIX 1003.2.
|
||||
|
||||
The BSD commands included are:
|
||||
1) `s' (i.e., s[rgp]*) to repeat a previous substitution,
|
||||
2) `W' for appending text to an existing file,
|
||||
3) `wq' for exiting after a write, and
|
||||
4) `z' for scrolling through the buffer.
|
||||
BSD line addressing syntax (i.e., `^' and `%'). is also recognized.
|
||||
OMISSIONS
|
||||
---------
|
||||
1) Locale(3) is not supported yet.
|
||||
|
||||
The POSIX interactive global commands `G' and `V' are extended to support
|
||||
multiple commands, including `a', `i' and `c'. The command format is the
|
||||
same as for the global commands `g' and `v', i.e., one command per line
|
||||
with each line, except for the last, ending in a backslash (\).
|
||||
2) For backwards compatibility, the POSIX rule that says a range of
|
||||
addresses cannot be used where only a single address is expected has
|
||||
been relaxed.
|
||||
|
||||
If crypt is available, files can be read and written using DES encryption.
|
||||
The `x' command prompts the user to enter a key used for encrypting/
|
||||
decrypting subsequent reads and writes. If only a newline is entered as
|
||||
the key, then encryption is disabled. Otherwise, a key is read in the
|
||||
same manner as a password entry. The key remains in effect until
|
||||
encryption is disabled. For more information on the encryption algorithm,
|
||||
see the bdes(1) man page. Encryption/decryption should be fully compatible
|
||||
with SunOS DES.
|
||||
3) To support the BSD `s' command (see extension [1] below),
|
||||
substitution patterns cannot be delimited by numbers or the characters
|
||||
`r', `g' and `p'. In contrast, POSIX specifies any character expect
|
||||
space or newline can used as a delimiter.
|
||||
|
||||
An extension to the POSIX file commands `E', `e', `r', `W' and `w' is that
|
||||
<file> arguments are processed for backslash escapes, i.e., any character
|
||||
preceded by a backslash is interpreted literally. If the first unescaped
|
||||
character of a <file> argument is a bang (!), then the rest of the line
|
||||
is interpreted as a shell command, and no escape processing is performed
|
||||
by ed.
|
||||
EXTENSIONS
|
||||
----------
|
||||
1) BSD commands have been implemented wherever they do not conflict with
|
||||
the POSIX standard. The BSD-ism's included are:
|
||||
i) `s' (i.e., s[n][rgp]*) to repeat a previous substitution,
|
||||
ii) `W' for appending text to an existing file,
|
||||
iii) `wq' for exiting after a write,
|
||||
iv) `z' for scrolling through the buffer, and
|
||||
v) BSD line addressing syntax (i.e., `^' and `%') is recognized.
|
||||
|
||||
The vi editor's bang command syntax is supported, i.e.,
|
||||
(addr1,addr2) !<shell-cmd> replaces the addressed lines with the output of
|
||||
the command <shell-cmd>.
|
||||
[rwe] !! reads/writes/edits the previous !<shell-cmd>.
|
||||
2) If crypt(3) is available, files can be read and written using DES
|
||||
encryption. The `x' command prompts the user to enter a key used for
|
||||
encrypting/ decrypting subsequent reads and writes. If only a newline
|
||||
is entered as the key, then encryption is disabled. Otherwise, a key
|
||||
is read in the same manner as a password entry. The key remains in
|
||||
effect until encryption is disabled. For more information on the
|
||||
encryption algorithm, see the bdes(1) man page. Encryption/decryption
|
||||
should be fully compatible with SunOS des(1).
|
||||
|
||||
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.
|
||||
3) The POSIX interactive global commands `G' and `V' are extended to
|
||||
support multiple commands, including `a', `i' and `c'. The command
|
||||
format is the same as for the global commands `g' and `v', i.e., one
|
||||
command per line with each line, except for the last, ending in a
|
||||
backslash (\).
|
||||
|
||||
ed runs in restricted mode if invoked as red. This limits editing of
|
||||
files in the local directory only and prohibits !<shell-cmd> commands.
|
||||
4) An extension to the POSIX file commands `E', `e', `r', `W' and `w' is
|
||||
that <file> arguments are processed for backslash escapes, i.e., any
|
||||
character preceded by a backslash is interpreted literally. If the
|
||||
first unescaped character of a <file> argument is a bang (!), then the
|
||||
rest of the line is interpreted as a shell command, and no escape
|
||||
processing is performed by ed.
|
||||
|
||||
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.
|
||||
5) For SunOS ed(1) compatibility, ed runs in restricted mode if invoked
|
||||
as red. This limits editing of files in the local directory only and
|
||||
prohibits shell commands.
|
||||
|
||||
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.
|
||||
DEVIATIONS
|
||||
----------
|
||||
1) Though ed is not a stream editor, it can be used 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. In particular, reading /dev/null
|
||||
prior to writing prevents appending a newline to a binary file.
|
||||
|
||||
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.
|
||||
For example, to create a file with ed containing a single NUL character:
|
||||
$ ed file
|
||||
a
|
||||
^@
|
||||
.
|
||||
r /dev/null
|
||||
wq
|
||||
|
||||
Similarly, to remove a newline from the end of binary `file':
|
||||
$ ed file
|
||||
r /dev/null
|
||||
wq
|
||||
|
||||
2) Since the behavior of `u' (undo) within a `g' (global) command list is
|
||||
not specified by POSIX, it follows the behavior of the SunOS ed:
|
||||
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. This seems the best way, since the
|
||||
alternatives are either too complicated to implement or too confusing
|
||||
to use.
|
||||
|
||||
The global/undo combination is useful for masking errors that
|
||||
would otherwise cause a script to fail. For instance, an ed script
|
||||
to remove any occurences of either `censor1' or `censor2' might be
|
||||
written as:
|
||||
ed - file <<EOF
|
||||
1g/.*/u\
|
||||
,s/censor1//g\
|
||||
,s/censor2//g
|
||||
...
|
||||
|
||||
3) 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.
|
||||
|
||||
4) 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.
|
||||
|
@ -3,13 +3,14 @@ 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()
|
||||
compile with little trouble. Otherwise, the macros SPL1() and SPL0()
|
||||
should be redefined to disable interrupts.
|
||||
|
||||
The following compiler directives are recognized:
|
||||
DES - use to add encryption support (requires crypt(3))
|
||||
NO_REALLOC_NULL - use if realloc(3) does not accept a NULL pointer
|
||||
BACKWARDS - use for backwards compatibility
|
||||
DES - to add encryption support (requires crypt(3))
|
||||
NO_REALLOC_NULL - if realloc(3) does not accept a NULL pointer
|
||||
BACKWARDS - for backwards compatibility
|
||||
NEED_INSQUE - if insque(3) is missing
|
||||
|
||||
The file `POSIX' describes extensions to and deviations from the POSIX
|
||||
standard.
|
||||
|
136
bin/ed/buf.c
136
bin/ed/buf.c
@ -1,12 +1,9 @@
|
||||
/* buf.c: This file contains the scratch-file buffer rountines for the
|
||||
ed line editor. */
|
||||
/*-
|
||||
* Copyright (c) 1992 The Regents of the University of California.
|
||||
* Copyright (c) 1993 Andrew Moore, Talke Studio.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Rodney Ruddock of the University of Guelph.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
@ -15,18 +12,11 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
@ -35,37 +25,32 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)buf.c 5.5 (Berkeley) 3/28/93";
|
||||
static char *rcsid = "@(#)$Id: buf.c,v 1.3 1993/12/14 16:19:56 alm Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/file.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "ed.h"
|
||||
|
||||
extern char errmsg[];
|
||||
|
||||
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 */
|
||||
line_t buffer_head; /* incore buffer */
|
||||
|
||||
/* gettxt: get a line of text from the scratch file; return pointer
|
||||
/* get_sbuf_line: get a line of text from the scratch file; return pointer
|
||||
to the text */
|
||||
char *
|
||||
gettxt(lp)
|
||||
get_sbuf_line(lp)
|
||||
line_t *lp;
|
||||
{
|
||||
static char *sfbuf = NULL; /* buffer */
|
||||
static int sfbufsz = 0; /* buffer size */
|
||||
|
||||
int len, ct;
|
||||
|
||||
if (lp == &line0)
|
||||
if (lp == &buffer_head)
|
||||
return NULL;
|
||||
seek_write = 1; /* force seek on write */
|
||||
/* out of position */
|
||||
@ -77,8 +62,8 @@ gettxt(lp)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
len = lp->len & ~ACTV;
|
||||
CKBUF(sfbuf, sfbufsz, len + 1, NULL);
|
||||
len = lp->len;
|
||||
REALLOC(sfbuf, sfbufsz, len + 1, NULL);
|
||||
if ((ct = fread(sfbuf, sizeof(char), len, sfp)) < 0 || ct != len) {
|
||||
fprintf(stderr, "%s\n", strerror(errno));
|
||||
sprintf(errmsg, "cannot read temp file");
|
||||
@ -90,13 +75,10 @@ gettxt(lp)
|
||||
}
|
||||
|
||||
|
||||
extern long curln;
|
||||
extern long lastln;
|
||||
|
||||
/* puttxt: write a line of text to the scratch file and add a line node
|
||||
/* put_sbuf_line: write a line of text to the scratch file and add a line node
|
||||
to the editor buffer; return a pointer to the end of the text */
|
||||
char *
|
||||
puttxt(cs)
|
||||
put_sbuf_line(cs)
|
||||
char *cs;
|
||||
{
|
||||
line_t *lp;
|
||||
@ -115,7 +97,7 @@ puttxt(cs)
|
||||
sprintf(errmsg, "line too long");
|
||||
return NULL;
|
||||
}
|
||||
len = (s - cs) & ~ACTV;
|
||||
len = s - cs;
|
||||
/* out of position */
|
||||
if (seek_write) {
|
||||
if (fseek(sfp, 0L, SEEK_END) < 0) {
|
||||
@ -126,7 +108,7 @@ puttxt(cs)
|
||||
sfseek = ftell(sfp);
|
||||
seek_write = 0;
|
||||
}
|
||||
/* assert: spl1() */
|
||||
/* assert: SPL1() */
|
||||
if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) {
|
||||
sfseek = -1;
|
||||
fprintf(stderr, "%s\n", strerror(errno));
|
||||
@ -135,37 +117,37 @@ puttxt(cs)
|
||||
}
|
||||
lp->len = len;
|
||||
lp->seek = sfseek;
|
||||
lpqueue(lp);
|
||||
add_line_node(lp);
|
||||
sfseek += len; /* update file position */
|
||||
return ++s;
|
||||
}
|
||||
|
||||
|
||||
/* lpqueue: add a line node in the editor buffer after the current line */
|
||||
/* add_line_node: add a line node in the editor buffer after the current line */
|
||||
void
|
||||
lpqueue(lp)
|
||||
add_line_node(lp)
|
||||
line_t *lp;
|
||||
{
|
||||
line_t *cp;
|
||||
|
||||
cp = getlp(curln); /* this getlp last! */
|
||||
insqueue(lp, cp);
|
||||
lastln++;
|
||||
curln++;
|
||||
cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */
|
||||
insque(lp, cp);
|
||||
addr_last++;
|
||||
current_addr++;
|
||||
}
|
||||
|
||||
|
||||
/* getaddr: return line number of pointer */
|
||||
/* get_line_node_addr: return line number of pointer */
|
||||
long
|
||||
getaddr(lp)
|
||||
get_line_node_addr(lp)
|
||||
line_t *lp;
|
||||
{
|
||||
line_t *cp = &line0;
|
||||
line_t *cp = &buffer_head;
|
||||
long n = 0;
|
||||
|
||||
while (cp != lp && (cp = cp->next) != &line0)
|
||||
while (cp != lp && (cp = cp->q_forw) != &buffer_head)
|
||||
n++;
|
||||
if (n && cp == &line0) {
|
||||
if (n && cp == &buffer_head) {
|
||||
sprintf(errmsg, "invalid address");
|
||||
return ERR;
|
||||
}
|
||||
@ -173,43 +155,47 @@ getaddr(lp)
|
||||
}
|
||||
|
||||
|
||||
/* getlp: return pointer to a line node in the editor buffer */
|
||||
/* get_addressed_line_node: return pointer to a line node in the editor buffer */
|
||||
line_t *
|
||||
getlp(n)
|
||||
get_addressed_line_node(n)
|
||||
long n;
|
||||
{
|
||||
static line_t *lp = &line0;
|
||||
static line_t *lp = &buffer_head;
|
||||
static long on = 0;
|
||||
|
||||
spl1();
|
||||
SPL1();
|
||||
if (n > on)
|
||||
if (n <= (on + lastln) >> 1)
|
||||
if (n <= (on + addr_last) >> 1)
|
||||
for (; on < n; on++)
|
||||
lp = lp->next;
|
||||
lp = lp->q_forw;
|
||||
else {
|
||||
lp = line0.prev;
|
||||
for (on = lastln; on > n; on--)
|
||||
lp = lp->prev;
|
||||
lp = buffer_head.q_back;
|
||||
for (on = addr_last; on > n; on--)
|
||||
lp = lp->q_back;
|
||||
}
|
||||
else
|
||||
if (n >= on >> 1)
|
||||
for (; on > n; on--)
|
||||
lp = lp->prev;
|
||||
lp = lp->q_back;
|
||||
else {
|
||||
lp = &line0;
|
||||
lp = &buffer_head;
|
||||
for (on = 0; on < n; on++)
|
||||
lp = lp->next;
|
||||
lp = lp->q_forw;
|
||||
}
|
||||
spl0();
|
||||
SPL0();
|
||||
return lp;
|
||||
}
|
||||
|
||||
|
||||
extern int newline_added;
|
||||
|
||||
char sfn[15] = ""; /* scratch file name */
|
||||
|
||||
/* sbopen: open scratch file */
|
||||
sbopen()
|
||||
/* open_sbuf: open scratch file */
|
||||
int
|
||||
open_sbuf()
|
||||
{
|
||||
isbinary = newline_added = 0;
|
||||
strcpy(sfn, "/tmp/ed.XXXXXX");
|
||||
if (mktemp(sfn) == NULL || (sfp = fopen(sfn, "w+")) == NULL) {
|
||||
fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
|
||||
@ -220,8 +206,9 @@ sbopen()
|
||||
}
|
||||
|
||||
|
||||
/* sbclose: close scratch file */
|
||||
sbclose()
|
||||
/* close_sbuf: close scratch file */
|
||||
int
|
||||
close_sbuf()
|
||||
{
|
||||
if (sfp) {
|
||||
if (fclose(sfp) < 0) {
|
||||
@ -237,7 +224,7 @@ sbclose()
|
||||
}
|
||||
|
||||
|
||||
/* quit: remove scratch file and exit */
|
||||
/* quit: remove_lines scratch file and exit */
|
||||
void
|
||||
quit(n)
|
||||
int n;
|
||||
@ -252,23 +239,30 @@ quit(n)
|
||||
|
||||
unsigned char ctab[256]; /* character translation table */
|
||||
|
||||
/* init_buf: open scratch buffer; initialize line queue */
|
||||
/* init_buffers: open scratch buffer; initialize line queue */
|
||||
void
|
||||
init_buf()
|
||||
init_buffers()
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (sbopen() < 0)
|
||||
/* Read stdin one character at a time to avoid i/o contention
|
||||
with shell escapes invoked by nonterminal input, e.g.,
|
||||
ed - <<EOF
|
||||
!cat
|
||||
hello, world
|
||||
EOF */
|
||||
setbuffer(stdin, stdinbuf, 1);
|
||||
if (open_sbuf() < 0)
|
||||
quit(2);
|
||||
requeue(&line0, &line0);
|
||||
REQUE(&buffer_head, &buffer_head);
|
||||
for (i = 0; i < 256; i++)
|
||||
ctab[i] = i;
|
||||
}
|
||||
|
||||
|
||||
/* translit: translate characters in a string */
|
||||
/* translit_text: translate characters in a string */
|
||||
char *
|
||||
translit(s, len, from, to)
|
||||
translit_text(s, len, from, to)
|
||||
char *s;
|
||||
int len;
|
||||
int from;
|
||||
|
114
bin/ed/cbc.c
114
bin/ed/cbc.c
@ -1,14 +1,10 @@
|
||||
/* cbc.c: This file contains the encryption routines for the ed line editor */
|
||||
/*-
|
||||
* Copyright (c) 1991 The Regents of the University of California.
|
||||
* Copyright (c) 1993 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Matt Bishop of Dartmouth College.
|
||||
*
|
||||
* The United States Government has rights in this work pursuant
|
||||
* to contract no. NAG 2-680 between the National Aeronautics and
|
||||
* Space Administration and Dartmouth College.
|
||||
* Copyright (c) 1993 Andrew Moore, Talke Studio.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -37,37 +33,22 @@
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)bdes.c 5.5 (Berkeley) 6/27/91
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)cbc.c 5.5 (Berkeley) 6/27/91";
|
||||
static char *rcsid = "@(#)$Id: cbc.c,v 1.3 1993/12/14 18:01:10 alm Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
/* Author: Matt Bishop
|
||||
* Department of Mathematics and Computer Science
|
||||
* Dartmouth College
|
||||
* Hanover, NH 03755
|
||||
* Email: Matt.Bishop@dartmouth.edu
|
||||
* ...!decvax!dartvax!Matt.Bishop
|
||||
*
|
||||
* See Technical Report PCS-TR91-158, Department of Mathematics and Computer
|
||||
* Science, Dartmouth College, for a detailed description of the implemen-
|
||||
* tation and differences between it and Sun's. The DES is described in
|
||||
* FIPS PUB 46, and the modes in FIPS PUB 81 (see either the manual page
|
||||
* or the technical report for a complete reference).
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "ed.h"
|
||||
|
||||
|
||||
/*
|
||||
* Define a divisor for rand() that yields a uniform distribution in the
|
||||
* range 0-255.
|
||||
@ -76,7 +57,7 @@ static char sccsid[] = "@(#)cbc.c 5.5 (Berkeley) 6/27/91";
|
||||
|
||||
/*
|
||||
* BSD and System V systems offer special library calls that do
|
||||
* block moves and fills, so if possible we take advantage of them
|
||||
* block move_liness and fills, so if possible we take advantage of them
|
||||
*/
|
||||
#define MEMCPY(dest,src,len) memcpy((dest),(src),(len))
|
||||
#define MEMZERO(dest,len) memset((dest), 0, (len))
|
||||
@ -84,10 +65,10 @@ static char sccsid[] = "@(#)cbc.c 5.5 (Berkeley) 6/27/91";
|
||||
/* Hide the calls to the primitive encryption routines. */
|
||||
#define DES_KEY(buf) \
|
||||
if (des_setkey(buf)) \
|
||||
err("des_setkey");
|
||||
des_error("des_setkey");
|
||||
#define DES_XFORM(buf) \
|
||||
if (des_cipher(buf, buf, 0L, (inverse ? -1 : 1))) \
|
||||
err("des_cipher");
|
||||
des_error("des_cipher");
|
||||
|
||||
/*
|
||||
* read/write - no error checking
|
||||
@ -119,14 +100,14 @@ char bits[] = { /* used to extract bits from a char */
|
||||
};
|
||||
int pflag; /* 1 to preserve parity bits */
|
||||
|
||||
char des_buf[8]; /* shared buffer for desgetc/desputc */
|
||||
int des_ct = 0; /* count for desgetc/desputc */
|
||||
int des_n = 0; /* index for desputc/desgetc */
|
||||
unsigned char des_buf[8]; /* shared buffer for get_des_char/put_des_char */
|
||||
int des_ct = 0; /* count for get_des_char/put_des_char */
|
||||
int des_n = 0; /* index for put_des_char/get_des_char */
|
||||
|
||||
|
||||
/* desinit: initialize DES */
|
||||
/* init_des_cipher: initialize DES */
|
||||
void
|
||||
desinit()
|
||||
init_des_cipher()
|
||||
{
|
||||
#ifdef DES
|
||||
int i;
|
||||
@ -144,28 +125,30 @@ desinit()
|
||||
}
|
||||
|
||||
|
||||
/* desgetc: return next char in an encrypted file */
|
||||
desgetc(fp)
|
||||
/* get_des_char: return next char in an encrypted file */
|
||||
int
|
||||
get_des_char(fp)
|
||||
FILE *fp;
|
||||
{
|
||||
#ifdef DES
|
||||
if (des_n >= des_ct) {
|
||||
des_n = 0;
|
||||
des_ct = cbcdec(des_buf, fp);
|
||||
des_ct = cbc_decode(des_buf, fp);
|
||||
}
|
||||
return (des_ct > 0) ? des_buf[des_n++] : EOF;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* desputc: write a char to an encrypted file; return char written */
|
||||
desputc(c, fp)
|
||||
/* put_des_char: write a char to an encrypted file; return char written */
|
||||
int
|
||||
put_des_char(c, fp)
|
||||
int c;
|
||||
FILE *fp;
|
||||
{
|
||||
#ifdef DES
|
||||
if (des_n == sizeof des_buf) {
|
||||
des_ct = cbcenc(des_buf, des_n, fp);
|
||||
des_ct = cbc_encode(des_buf, des_n, fp);
|
||||
des_n = 0;
|
||||
}
|
||||
return (des_ct >= 0) ? (des_buf[des_n++] = c) : EOF;
|
||||
@ -173,16 +156,17 @@ desputc(c, fp)
|
||||
}
|
||||
|
||||
|
||||
/* desflush: flush an encrypted file's output; return status */
|
||||
desflush(fp)
|
||||
/* flush_des_file: flush an encrypted file's output; return status */
|
||||
int
|
||||
flush_des_file(fp)
|
||||
FILE *fp;
|
||||
{
|
||||
#ifdef DES
|
||||
if (des_n == sizeof des_buf) {
|
||||
des_ct = cbcenc(des_buf, des_n, fp);
|
||||
des_ct = cbc_encode(des_buf, des_n, fp);
|
||||
des_n = 0;
|
||||
}
|
||||
return (des_ct >= 0 && cbcenc(des_buf, des_n, fp) >= 0) ? 0 : EOF;
|
||||
return (des_ct >= 0 && cbc_encode(des_buf, des_n, fp) >= 0) ? 0 : EOF;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -190,7 +174,8 @@ desflush(fp)
|
||||
/*
|
||||
* get keyword from tty or stdin
|
||||
*/
|
||||
getkey()
|
||||
int
|
||||
get_keyword()
|
||||
{
|
||||
register char *p; /* used to obtain the key */
|
||||
Desbuf msgbuf; /* I/O buffer */
|
||||
@ -203,9 +188,9 @@ getkey()
|
||||
/*
|
||||
* copy it, nul-padded, into the key area
|
||||
*/
|
||||
cvtkey(BUFFER(msgbuf), p);
|
||||
expand_des_key(BUFFER(msgbuf), p);
|
||||
MEMZERO(p, _PASSWORD_LEN);
|
||||
makekey(msgbuf);
|
||||
set_des_key(msgbuf);
|
||||
MEMZERO(msgbuf, sizeof msgbuf);
|
||||
return 1;
|
||||
}
|
||||
@ -213,13 +198,11 @@ getkey()
|
||||
}
|
||||
|
||||
|
||||
extern char errmsg[];
|
||||
|
||||
/*
|
||||
* print a warning message and, possibly, terminate
|
||||
*/
|
||||
void
|
||||
err(s)
|
||||
des_error(s)
|
||||
char *s; /* the message */
|
||||
{
|
||||
(void)sprintf(errmsg, "%s", s ? s : strerror(errno));
|
||||
@ -228,7 +211,8 @@ err(s)
|
||||
/*
|
||||
* map a hex character to an integer
|
||||
*/
|
||||
tobinhex(c, radix)
|
||||
int
|
||||
hex_to_binary(c, radix)
|
||||
int c; /* char to be converted */
|
||||
int radix; /* base (2 to 16) */
|
||||
{
|
||||
@ -260,7 +244,7 @@ tobinhex(c, radix)
|
||||
* convert the key to a bit pattern
|
||||
*/
|
||||
void
|
||||
cvtkey(obuf, ibuf)
|
||||
expand_des_key(obuf, ibuf)
|
||||
char *obuf; /* bit pattern */
|
||||
char *ibuf; /* the key itself */
|
||||
{
|
||||
@ -276,8 +260,8 @@ cvtkey(obuf, ibuf)
|
||||
* now translate it, bombing on any illegal hex digit
|
||||
*/
|
||||
for (i = 0; ibuf[i] && i < 16; i++)
|
||||
if ((nbuf[i] = tobinhex((int) ibuf[i], 16)) == -1)
|
||||
err("bad hex digit in key");
|
||||
if ((nbuf[i] = hex_to_binary((int) ibuf[i], 16)) == -1)
|
||||
des_error("bad hex digit in key");
|
||||
while (i < 16)
|
||||
nbuf[i++] = 0;
|
||||
for (i = 0; i < 8; i++)
|
||||
@ -296,8 +280,8 @@ cvtkey(obuf, ibuf)
|
||||
* now translate it, bombing on any illegal binary digit
|
||||
*/
|
||||
for (i = 0; ibuf[i] && i < 16; i++)
|
||||
if ((nbuf[i] = tobinhex((int) ibuf[i], 2)) == -1)
|
||||
err("bad binary digit in key");
|
||||
if ((nbuf[i] = hex_to_binary((int) ibuf[i], 2)) == -1)
|
||||
des_error("bad binary digit in key");
|
||||
while (i < 64)
|
||||
nbuf[i++] = 0;
|
||||
for (i = 0; i < 8; i++)
|
||||
@ -328,7 +312,7 @@ cvtkey(obuf, ibuf)
|
||||
* DES ignores the low order bit of each character.
|
||||
*/
|
||||
void
|
||||
makekey(buf)
|
||||
set_des_key(buf)
|
||||
Desbuf buf; /* key block */
|
||||
{
|
||||
register int i, j; /* counter in a for loop */
|
||||
@ -357,7 +341,8 @@ makekey(buf)
|
||||
/*
|
||||
* This encrypts using the Cipher Block Chaining mode of DES
|
||||
*/
|
||||
cbcenc(msgbuf, n, fp)
|
||||
int
|
||||
cbc_encode(msgbuf, n, fp)
|
||||
char *msgbuf;
|
||||
int n;
|
||||
FILE *fp;
|
||||
@ -395,7 +380,8 @@ cbcenc(msgbuf, n, fp)
|
||||
/*
|
||||
* This decrypts using the Cipher Block Chaining mode of DES
|
||||
*/
|
||||
cbcdec(msgbuf, fp)
|
||||
int
|
||||
cbc_decode(msgbuf, fp)
|
||||
char *msgbuf; /* I/O buffer */
|
||||
FILE *fp; /* input file descriptor */
|
||||
{
|
||||
@ -419,7 +405,7 @@ cbcdec(msgbuf, fp)
|
||||
if ((c = fgetc(fp)) == EOF) {
|
||||
n = CHAR(msgbuf, 7);
|
||||
if (n < 0 || n > 7) {
|
||||
err("decryption failed (block corrupted)");
|
||||
des_error("decryption failed (block corrupted)");
|
||||
return EOF;
|
||||
}
|
||||
} else
|
||||
@ -427,9 +413,9 @@ cbcdec(msgbuf, fp)
|
||||
return n;
|
||||
}
|
||||
if (n > 0)
|
||||
err("decryption failed (incomplete block)");
|
||||
des_error("decryption failed (incomplete block)");
|
||||
else if (n < 0)
|
||||
err("cannot read file");
|
||||
des_error("cannot read file");
|
||||
return EOF;
|
||||
}
|
||||
#endif /* DES */
|
||||
|
59
bin/ed/ed.1
59
bin/ed/ed.1
@ -134,7 +134,7 @@ The default filename is set to
|
||||
only if it is not prefixed with a bang.
|
||||
|
||||
.SS LINE ADDRESSING
|
||||
An address represents the number of line in the buffer.
|
||||
An address represents the number of a line in the buffer.
|
||||
.B ed
|
||||
maintains a
|
||||
.I current address
|
||||
@ -165,25 +165,26 @@ and is legal wherever it makes sense.
|
||||
|
||||
An address range is two addresses separated either by a comma or
|
||||
semi-colon. The value of the first address in a range cannot exceed the
|
||||
value of the the second. If an
|
||||
value of the the second. If only one address is given in a range, then
|
||||
the second address is set to the given address. If an
|
||||
.IR n- tuple
|
||||
of addresses is given where
|
||||
.I n > 2,
|
||||
then the corresponding range is determined by the last two addresses
|
||||
in the
|
||||
then the corresponding range is determined by the last two addresses in
|
||||
the
|
||||
.IR n- tuple.
|
||||
If only one address is expected, then the last
|
||||
address is used.
|
||||
If only one address is expected, then the last address is used.
|
||||
|
||||
Each address in a comma-delimited range is interpreted relative to the
|
||||
current address. In a semi-colon-delimited range, the first address is
|
||||
used to set the current address, and the second address is interpreted
|
||||
relative to the first.
|
||||
|
||||
|
||||
The following address symbols are recognized.
|
||||
|
||||
.TP 8
|
||||
\fR.\fR
|
||||
\&.
|
||||
The current line (address) in the buffer.
|
||||
|
||||
.TP 8
|
||||
@ -511,7 +512,9 @@ The current address is set to the last line read.
|
||||
.RI e \ !command
|
||||
Edits the standard output of
|
||||
.IR `!command' ,
|
||||
executed as described below.
|
||||
(see
|
||||
.RI ! command
|
||||
below).
|
||||
The default filename is unchanged.
|
||||
Any lines in the buffer are deleted before the output of
|
||||
.I command
|
||||
@ -629,6 +632,12 @@ deleted or otherwise modified.
|
||||
.TP 8
|
||||
(.,.)l
|
||||
Prints the addressed lines unambiguously.
|
||||
If a single line fills for than one screen (as might be the case
|
||||
when viewing a binary file, for instance), a `--More--'
|
||||
prompt is printed on the last line.
|
||||
.B ed
|
||||
waits until the RETURN key is pressed
|
||||
before displaying the next screen.
|
||||
The current address is set to the last line
|
||||
printed.
|
||||
|
||||
@ -689,7 +698,9 @@ Reads
|
||||
to after the addressed line
|
||||
the standard output of
|
||||
.IR `!command' ,
|
||||
executed as described below.
|
||||
(see the
|
||||
.RI ! command
|
||||
below).
|
||||
The default filename is unchanged.
|
||||
The current address is set to the last line read.
|
||||
|
||||
@ -707,9 +718,9 @@ matching a regular expression
|
||||
with
|
||||
.IR replacement .
|
||||
By default, only the first match in each line is replaced.
|
||||
The
|
||||
If the
|
||||
.I `g'
|
||||
(global) suffix causes every match to be replaced.
|
||||
(global) suffix is given, then every match to be replaced.
|
||||
The
|
||||
.I `n'
|
||||
suffix, where
|
||||
@ -724,7 +735,10 @@ The current address is set the last line affected.
|
||||
.I re
|
||||
and
|
||||
.I replacement
|
||||
may be delimited by any character other than space and newline.
|
||||
may be delimited by any character other than space and newline
|
||||
(see the
|
||||
.I `s'
|
||||
command below).
|
||||
If one or two of the last delimiters is omitted, then the last line
|
||||
affected is printed as though the print suffix
|
||||
.I `p'
|
||||
@ -755,12 +769,18 @@ if they are escaped with a backslash (\\).
|
||||
Repeats the last substitution.
|
||||
This form of the
|
||||
.I `s'
|
||||
command may be suffixed with
|
||||
any combination of the characters
|
||||
command accepts a count suffix
|
||||
.IR `n' ,
|
||||
or any combination of the characters
|
||||
.IR `r' ,
|
||||
.IR `g' ,
|
||||
and
|
||||
.IR `p' .
|
||||
If a count suffix
|
||||
.I `n'
|
||||
is given, then only the
|
||||
.IR n th
|
||||
match is replaced.
|
||||
The
|
||||
.I `r'
|
||||
suffix causes
|
||||
@ -840,7 +860,9 @@ command.
|
||||
.RI (1,$)w \ !command
|
||||
Writes the addressed lines to the standard input of
|
||||
.IR `!command' ,
|
||||
executed as described below.
|
||||
(see the
|
||||
.RI ! command
|
||||
below).
|
||||
The default filename and current address are unchanged.
|
||||
|
||||
.TP 8
|
||||
@ -890,13 +912,6 @@ When the shell returns from execution, a `!'
|
||||
is printed to the standard output.
|
||||
The current line is unchanged.
|
||||
|
||||
.TP 8
|
||||
.RI (.,.)! command
|
||||
Replaces the addressed lines with the output of
|
||||
.I `!command'
|
||||
as described above.
|
||||
The current address is set to the last line read.
|
||||
|
||||
.TP 8
|
||||
($)=
|
||||
Prints the line number of the addressed line.
|
||||
|
290
bin/ed/ed.h
290
bin/ed/ed.h
@ -1,11 +1,8 @@
|
||||
/* ed.h: type and constant definitions for the ed editor. */
|
||||
/*
|
||||
* Copyright (c) 1993 The Regents of the University of California.
|
||||
* Copyright (c) 1993 Andrew Moore
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Andrew Moore, Talke Studio.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
@ -14,13 +11,6 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
@ -34,22 +24,22 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)ed.h 5.5 (Berkeley) 3/28/93
|
||||
* @(#)$Id: ed.h,v 1.4 1993/12/15 15:22:02 alm Exp alm $
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#if defined(BSD) && BSD >= 199103 || defined(__386BSD__)
|
||||
# include <sys/param.h> /* for MAXPATHLEN */
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#ifdef sun
|
||||
# include <limits.h>
|
||||
#endif
|
||||
#include <regex.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define BITSPERBYTE 8
|
||||
#define BITS(type) (BITSPERBYTE * (int)sizeof(type))
|
||||
#define CHARBITS BITS(char)
|
||||
#define INTBITS BITS(int)
|
||||
#define INTHIBIT (unsigned) (1 << (INTBITS - 1))
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define ERR (-2)
|
||||
#define EMOD (-3)
|
||||
@ -59,21 +49,28 @@
|
||||
# define MAXPATHLEN 255 /* _POSIX_PATH_MAX */
|
||||
#endif
|
||||
|
||||
#define MAXFNAME MAXPATHLEN /* max file name size */
|
||||
#define MINBUFSZ 512 /* minimum buffer size - must be > 0 */
|
||||
#define LINECHARS (INTHIBIT - 1) /* max chars per line */
|
||||
#define SE_MAX 30 /* max subexpressions in a regular expression */
|
||||
#ifdef INT_MAX
|
||||
# define LINECHARS INT_MAX /* max chars per line */
|
||||
#else
|
||||
# define LINECHARS MAXINT /* max chars per line */
|
||||
#endif
|
||||
|
||||
/* gflags */
|
||||
#define GLB 001 /* global command */
|
||||
#define GPR 002 /* print after command */
|
||||
#define GLS 004 /* list after command */
|
||||
#define GNP 010 /* enumerate after command */
|
||||
#define GSG 020 /* global substitute */
|
||||
|
||||
typedef regex_t pattern_t;
|
||||
|
||||
/* Line node */
|
||||
typedef struct line {
|
||||
struct line *next;
|
||||
struct line *prev;
|
||||
struct line *q_forw;
|
||||
struct line *q_back;
|
||||
off_t seek; /* address of line in scratch buffer */
|
||||
|
||||
#define ACTV INTHIBIT /* active bit: high bit of len */
|
||||
|
||||
int len; /* length of line */
|
||||
} line_t;
|
||||
|
||||
@ -98,87 +95,94 @@ typedef struct undo {
|
||||
# define min(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/* nextln: return line after l mod k */
|
||||
#define nextln(l,k) ((l)+1 > (k) ? 0 : (l)+1)
|
||||
#define INC_MOD(l, k) ((l) + 1 > (k) ? 0 : (l) + 1)
|
||||
#define DEC_MOD(l, k) ((l) - 1 < 0 ? (k) : (l) - 1)
|
||||
|
||||
/* nextln: return line before l mod k */
|
||||
#define prevln(l,k) ((l)-1 < 0 ? (k) : (l)-1)
|
||||
/* SPL1: disable some interrupts (requires reliable signals) */
|
||||
#define SPL1() mutex++
|
||||
|
||||
#define skipblanks() while (isspace(*ibufp) && *ibufp != '\n') ibufp++
|
||||
|
||||
/* spl1: disable some interrupts (requires reliable signals) */
|
||||
#define spl1() mutex++
|
||||
|
||||
/* spl0: enable all interrupts; check sigflags (requires reliable signals) */
|
||||
#define spl0() \
|
||||
/* SPL0: enable all interrupts; check sigflags (requires reliable signals) */
|
||||
#define SPL0() \
|
||||
if (--mutex == 0) { \
|
||||
if (sigflags & (1 << SIGHUP)) dohup(SIGHUP); \
|
||||
if (sigflags & (1 << SIGINT)) dointr(SIGINT); \
|
||||
if (sigflags & (1 << (SIGHUP - 1))) handle_hup(SIGHUP); \
|
||||
if (sigflags & (1 << (SIGINT - 1))) handle_int(SIGINT); \
|
||||
}
|
||||
|
||||
/* STRTOL: convert a string to long */
|
||||
#define STRTOL(i, p) { \
|
||||
if (((i = strtol(p, &p, 10)) == LONG_MIN || i == LONG_MAX) && \
|
||||
errno == ERANGE) { \
|
||||
sprintf(errmsg, "number out of range"); \
|
||||
i = 0; \
|
||||
return ERR; \
|
||||
} \
|
||||
}
|
||||
|
||||
#if defined(sun) || defined(NO_REALLOC_NULL)
|
||||
/* CKBUF: assure at least a minimum size for buffer b */
|
||||
#define CKBUF(b,n,i,err) \
|
||||
/* REALLOC: assure at least a minimum size for buffer b */
|
||||
#define REALLOC(b,n,i,err) \
|
||||
if ((i) > (n)) { \
|
||||
int ti = (n); \
|
||||
char *ts; \
|
||||
spl1(); \
|
||||
SPL1(); \
|
||||
if ((b) != NULL) { \
|
||||
if ((ts = (char *) realloc((b), ti += max((i), MINBUFSZ))) == NULL) { \
|
||||
fprintf(stderr, "%s\n", strerror(errno)); \
|
||||
sprintf(errmsg, "out of memory"); \
|
||||
spl0(); \
|
||||
SPL0(); \
|
||||
return err; \
|
||||
} \
|
||||
} else { \
|
||||
if ((ts = (char *) malloc(ti += max((i), MINBUFSZ))) == NULL) { \
|
||||
fprintf(stderr, "%s\n", strerror(errno)); \
|
||||
sprintf(errmsg, "out of memory"); \
|
||||
spl0(); \
|
||||
SPL0(); \
|
||||
return err; \
|
||||
} \
|
||||
} \
|
||||
(n) = ti; \
|
||||
(b) = ts; \
|
||||
spl0(); \
|
||||
SPL0(); \
|
||||
}
|
||||
#else /* NO_REALLOC_NULL */
|
||||
/* CKBUF: assure at least a minimum size for buffer b */
|
||||
#define CKBUF(b,n,i,err) \
|
||||
/* REALLOC: assure at least a minimum size for buffer b */
|
||||
#define REALLOC(b,n,i,err) \
|
||||
if ((i) > (n)) { \
|
||||
int ti = (n); \
|
||||
char *ts; \
|
||||
spl1(); \
|
||||
SPL1(); \
|
||||
if ((ts = (char *) realloc((b), ti += max((i), MINBUFSZ))) == NULL) { \
|
||||
fprintf(stderr, "%s\n", strerror(errno)); \
|
||||
sprintf(errmsg, "out of memory"); \
|
||||
spl0(); \
|
||||
SPL0(); \
|
||||
return err; \
|
||||
} \
|
||||
(n) = ti; \
|
||||
(b) = ts; \
|
||||
spl0(); \
|
||||
SPL0(); \
|
||||
}
|
||||
#endif /* NO_REALLOC_NULL */
|
||||
|
||||
/* requeue: link pred before succ */
|
||||
#define requeue(pred, succ) (pred)->next = (succ), (succ)->prev = (pred)
|
||||
/* REQUE: link pred before succ */
|
||||
#define REQUE(pred, succ) (pred)->q_forw = (succ), (succ)->q_back = (pred)
|
||||
|
||||
/* insqueue: insert elem in circular queue after pred */
|
||||
#define insqueue(elem, pred) \
|
||||
#ifdef NEED_INSQUE
|
||||
/* insque: insert elem in circular queue after pred */
|
||||
#define insque(elem, pred) \
|
||||
{ \
|
||||
requeue((elem), (pred)->next); \
|
||||
requeue((pred), elem); \
|
||||
REQUE((elem), (pred)->q_forw); \
|
||||
REQUE((pred), elem); \
|
||||
}
|
||||
|
||||
/* remqueue: remove elem from circular queue */
|
||||
#define remqueue(elem) requeue((elem)->prev, (elem)->next);
|
||||
/* remque: remove_lines elem from circular queue */
|
||||
#define remque(elem) REQUE((elem)->q_back, (elem)->q_forw);
|
||||
#endif /* NEED_INSQUE */
|
||||
|
||||
/* nultonl: overwrite ASCII NULs with newlines */
|
||||
#define nultonl(s, l) translit(s, l, '\0', '\n')
|
||||
/* NUL_TO_NEWLINE: overwrite ASCII NULs with newlines */
|
||||
#define NUL_TO_NEWLINE(s, l) translit_text(s, l, '\0', '\n')
|
||||
|
||||
/* nltonul: overwrite newlines with ASCII NULs */
|
||||
#define nltonul(s, l) translit(s, l, '\n', '\0')
|
||||
/* NEWLINE_TO_NUL: overwrite newlines with ASCII NULs */
|
||||
#define NEWLINE_TO_NUL(s, l) translit_text(s, l, '\n', '\0')
|
||||
|
||||
#ifndef strerror
|
||||
# define strerror(n) sys_errlist[n]
|
||||
@ -192,75 +196,101 @@ if ((i) > (n)) { \
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* local function declarations */
|
||||
int append __P((long, int));
|
||||
int cbcdec __P((char *, FILE *));
|
||||
int cbcenc __P((char *, int, FILE *));
|
||||
char *ckfn __P((char *));
|
||||
int ckglob __P((void));
|
||||
int ckrange __P((long, long));
|
||||
int desflush __P((FILE *));
|
||||
int desgetc __P((FILE *));
|
||||
void desinit __P((void));
|
||||
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));
|
||||
void dointr __P((int));
|
||||
void dowinch __P((int));
|
||||
int doprint __P((long, long, int));
|
||||
long doread __P((long, char *));
|
||||
long dowrite __P((long, long, char *, char *));
|
||||
char *esctos __P((char *));
|
||||
long patscan __P((pattern_t *, int));
|
||||
long getaddr __P((line_t *));
|
||||
char *getcmdv __P((int *, int));
|
||||
char *getfn __P((void));
|
||||
int getkey __P((void));
|
||||
char *getlhs __P((int));
|
||||
int getline __P((void));
|
||||
int getlist __P((void));
|
||||
long getmark __P((int));
|
||||
long getnum __P((int));
|
||||
long getone __P((void));
|
||||
line_t *getlp __P((long));
|
||||
int getrhs __P((int));
|
||||
int getshcmd __P((void));
|
||||
char *gettxt __P((line_t *));
|
||||
void init_buf __P((void));
|
||||
int join __P((long, long));
|
||||
int lndelete __P((long, long));
|
||||
line_t *lpdup __P((line_t *));
|
||||
void lpqueue __P((line_t *));
|
||||
void makekey __P((char *));
|
||||
char *makesub __P((int));
|
||||
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 *));
|
||||
/* Local Function Declarations */
|
||||
void add_line_node __P((line_t *));
|
||||
int append_lines __P((long));
|
||||
int apply_subst_template __P((char *, regmatch_t *, int, int));
|
||||
int build_active_list __P((int));
|
||||
int cbc_decode __P((char *, FILE *));
|
||||
int cbc_encode __P((char *, int, FILE *));
|
||||
int check_addr_range __P((long, long));
|
||||
void clear_active_list __P((void));
|
||||
void clear_undo_stack __P((void));
|
||||
int close_sbuf __P((void));
|
||||
int copy_lines __P((long));
|
||||
int delete_lines __P((long, long));
|
||||
void des_error __P((char *));
|
||||
int display_lines __P((long, long, int));
|
||||
line_t *dup_line_node __P((line_t *));
|
||||
int exec_command __P((void));
|
||||
long exec_global __P((int, int));
|
||||
void expand_des_key __P((char *, char *));
|
||||
int extract_addr_range __P((void));
|
||||
char *extract_pattern __P((int));
|
||||
int extract_subst_tail __P((int *, int *));
|
||||
char *extract_subst_template __P((void));
|
||||
int filter_lines __P((long, long, char *));
|
||||
int flush_des_file __P((FILE *));
|
||||
line_t *get_addressed_line_node __P((long));
|
||||
pattern_t *get_compiled_pattern __P((void));
|
||||
int get_des_char __P((FILE *));
|
||||
char *get_extended_line __P((int *, int));
|
||||
char *get_filename __P((void));
|
||||
int get_keyword __P((void));
|
||||
long get_line_node_addr __P((line_t *));
|
||||
long get_matching_node_addr __P((pattern_t *, int));
|
||||
long get_marked_node_addr __P((int));
|
||||
char *get_sbuf_line __P((line_t *));
|
||||
int get_shell_command __P((void));
|
||||
int get_stream_line __P((FILE *));
|
||||
int get_tty_line __P((void));
|
||||
void handle_hup __P((int));
|
||||
void handle_int __P((int));
|
||||
void handle_winch __P((int));
|
||||
int has_trailing_escape __P((char *, char *));
|
||||
int hex_to_binary __P((int, int));
|
||||
void init_buffers __P((void));
|
||||
void init_des_cipher __P((void));
|
||||
int is_legal_filename __P((char *));
|
||||
int join_lines __P((long, long));
|
||||
int mark_line_node __P((line_t *, int));
|
||||
int move_lines __P((long));
|
||||
line_t *next_active_node __P(());
|
||||
long next_addr __P((void));
|
||||
int open_sbuf __P((void));
|
||||
char *parse_char_class __P((char *));
|
||||
int pop_undo_stack __P((void));
|
||||
undo_t *push_undo_stack __P((int, long, long));
|
||||
int put_des_char __P((int, FILE *));
|
||||
char *put_sbuf_line __P((char *));
|
||||
int put_stream_line __P((FILE *, char *, int));
|
||||
int put_tty_line __P((char *, int, long, int));
|
||||
void quit __P((int));
|
||||
int regsub __P((pattern_t *, line_t *, int));
|
||||
int sbclose __P((void));
|
||||
int sbopen __P((void));
|
||||
int sgetline __P((FILE *));
|
||||
int catsub __P((char *, regmatch_t *, int));
|
||||
int subst __P((pattern_t *, int));
|
||||
int tobinhex __P((int, int));
|
||||
int transfer __P((long));
|
||||
char *translit __P((char *, int, int, int));
|
||||
int undo __P((int));
|
||||
undo_t *upush __P((int, long, long));
|
||||
void ureset __P((void));
|
||||
long read_file __P((char *, long));
|
||||
long read_stream __P((FILE *, long));
|
||||
int search_and_replace __P((pattern_t *, int, int));
|
||||
int set_active_node __P((line_t *));
|
||||
void set_des_key __P((char *));
|
||||
void signal_hup __P((int));
|
||||
void signal_int __P((int));
|
||||
char *strip_escapes __P((char *));
|
||||
int substitute_matching_text __P((pattern_t *, line_t *, int, int));
|
||||
char *translit_text __P((char *, int, int, int));
|
||||
void unmark_line_node __P((line_t *));
|
||||
void unset_active_nodes __P((line_t *, line_t *));
|
||||
long write_file __P((char *, char *, long, long));
|
||||
long write_stream __P((FILE *, long, long));
|
||||
|
||||
/* global buffers */
|
||||
extern char stdinbuf[];
|
||||
extern char *ibuf;
|
||||
extern char *ibufp;
|
||||
extern int ibufsz;
|
||||
|
||||
extern char *sys_errlist[];
|
||||
/* global flags */
|
||||
extern int isbinary;
|
||||
extern int isglobal;
|
||||
extern int modified;
|
||||
extern int mutex;
|
||||
extern int sigflags;
|
||||
|
||||
/* global vars */
|
||||
extern long addr_last;
|
||||
extern long current_addr;
|
||||
extern char errmsg[];
|
||||
extern long first_addr;
|
||||
extern int lineno;
|
||||
extern long second_addr;
|
||||
#ifdef sun
|
||||
extern char *sys_errlist[];
|
||||
#endif
|
||||
|
375
bin/ed/io.c
Normal file
375
bin/ed/io.c
Normal file
@ -0,0 +1,375 @@
|
||||
/* io.c: This file contains the i/o routines for the ed line editor */
|
||||
/*-
|
||||
* Copyright (c) 1993 Andrew Moore, Talke Studio.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char *rcsid = "@(#)$Id: io.c,v 1.3 1993/12/14 16:19:56 alm Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "ed.h"
|
||||
|
||||
|
||||
extern int scripted;
|
||||
|
||||
/* read_file: read a named file/pipe into the buffer; return line count */
|
||||
long
|
||||
read_file(fn, n)
|
||||
char *fn;
|
||||
long n;
|
||||
{
|
||||
FILE *fp;
|
||||
long size;
|
||||
|
||||
|
||||
fp = (*fn == '!') ? popen(fn + 1, "r") : fopen(strip_escapes(fn), "r");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "%s: %s\n", fn, strerror(errno));
|
||||
sprintf(errmsg, "cannot open input file");
|
||||
return ERR;
|
||||
} else if ((size = read_stream(fp, n)) < 0)
|
||||
return ERR;
|
||||
else if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) {
|
||||
fprintf(stderr, "%s: %s\n", fn, strerror(errno));
|
||||
sprintf(errmsg, "cannot close input file");
|
||||
return ERR;
|
||||
}
|
||||
fprintf(stderr, !scripted ? "%lu\n" : "", size);
|
||||
return current_addr - n;
|
||||
}
|
||||
|
||||
|
||||
extern int des;
|
||||
|
||||
char *sbuf; /* file i/o buffer */
|
||||
int sbufsz; /* file i/o buffer size */
|
||||
int newline_added; /* if set, newline appended to input file */
|
||||
|
||||
/* read_stream: read a stream into the editor buffer; return status */
|
||||
long
|
||||
read_stream(fp, n)
|
||||
FILE *fp;
|
||||
long n;
|
||||
{
|
||||
line_t *lp = get_addressed_line_node(n);
|
||||
undo_t *up = NULL;
|
||||
unsigned long size = 0;
|
||||
int o_newline_added = newline_added;
|
||||
int o_isbinary = isbinary;
|
||||
int appended = (n == addr_last);
|
||||
int len;
|
||||
|
||||
isbinary = newline_added = 0;
|
||||
if (des)
|
||||
init_des_cipher();
|
||||
for (current_addr = n; (len = get_stream_line(fp)) > 0; size += len) {
|
||||
SPL1();
|
||||
if (put_sbuf_line(sbuf) == NULL) {
|
||||
SPL0();
|
||||
return ERR;
|
||||
}
|
||||
lp = lp->q_forw;
|
||||
if (up)
|
||||
up->t = lp;
|
||||
else if ((up = push_undo_stack(UADD, current_addr,
|
||||
current_addr)) == NULL) {
|
||||
SPL0();
|
||||
return ERR;
|
||||
}
|
||||
SPL0();
|
||||
}
|
||||
if (len < 0)
|
||||
return ERR;
|
||||
if (appended && size && o_isbinary && o_newline_added)
|
||||
fputs("newline inserted\n", stderr);
|
||||
else if (newline_added && (!appended || !isbinary && !o_isbinary))
|
||||
fputs("newline appended\n", stderr);
|
||||
if (isbinary && newline_added && !appended)
|
||||
size += 1;
|
||||
if (!size)
|
||||
newline_added = 1;
|
||||
newline_added = appended ? newline_added : o_newline_added;
|
||||
isbinary = isbinary | o_isbinary;
|
||||
if (des)
|
||||
size += 8 - size % 8; /* adjust DES size */
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/* get_stream_line: read a line of text from a stream; return line length */
|
||||
int
|
||||
get_stream_line(fp)
|
||||
FILE *fp;
|
||||
{
|
||||
register int c;
|
||||
register int i = 0;
|
||||
|
||||
while (((c = des ? get_des_char(fp) : getc(fp)) != EOF || !feof(fp) &&
|
||||
!ferror(fp)) && c != '\n') {
|
||||
REALLOC(sbuf, sbufsz, i + 1, ERR);
|
||||
if (!(sbuf[i++] = c))
|
||||
isbinary = 1;
|
||||
}
|
||||
REALLOC(sbuf, sbufsz, i + 2, ERR);
|
||||
if (c == '\n')
|
||||
sbuf[i++] = c;
|
||||
else if (ferror(fp)) {
|
||||
fprintf(stderr, "%s\n", strerror(errno));
|
||||
sprintf(errmsg, "cannot read input file");
|
||||
return ERR;
|
||||
} else if (i) {
|
||||
sbuf[i++] = '\n';
|
||||
newline_added = 1;
|
||||
}
|
||||
sbuf[i] = '\0';
|
||||
return (isbinary && newline_added && i) ? --i : i;
|
||||
}
|
||||
|
||||
|
||||
/* write_file: write a range of lines to a named file/pipe; return line count */
|
||||
long
|
||||
write_file(fn, mode, n, m)
|
||||
char *fn;
|
||||
char *mode;
|
||||
long n;
|
||||
long m;
|
||||
{
|
||||
FILE *fp;
|
||||
long size;
|
||||
|
||||
fp = (*fn == '!') ? popen(fn+1, "w") : fopen(strip_escapes(fn), mode);
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "%s: %s\n", fn, strerror(errno));
|
||||
sprintf(errmsg, "cannot open output file");
|
||||
return ERR;
|
||||
} else if ((size = write_stream(fp, n, m)) < 0)
|
||||
return ERR;
|
||||
else if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) {
|
||||
fprintf(stderr, "%s: %s\n", fn, strerror(errno));
|
||||
sprintf(errmsg, "cannot close output file");
|
||||
return ERR;
|
||||
}
|
||||
fprintf(stderr, !scripted ? "%lu\n" : "", size);
|
||||
return n ? m - n + 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
/* write_stream: write a range of lines to a stream; return status */
|
||||
long
|
||||
write_stream(fp, n, m)
|
||||
FILE *fp;
|
||||
long n;
|
||||
long m;
|
||||
{
|
||||
line_t *lp = get_addressed_line_node(n);
|
||||
unsigned long size = 0;
|
||||
char *s;
|
||||
int len;
|
||||
|
||||
if (des)
|
||||
init_des_cipher();
|
||||
for (; n && n <= m; n++, lp = lp->q_forw) {
|
||||
if ((s = get_sbuf_line(lp)) == NULL)
|
||||
return ERR;
|
||||
len = lp->len;
|
||||
if (n != addr_last || !isbinary || !newline_added)
|
||||
s[len++] = '\n';
|
||||
if (put_stream_line(fp, s, len) < 0)
|
||||
return ERR;
|
||||
size += len;
|
||||
}
|
||||
if (des) {
|
||||
flush_des_file(fp); /* flush buffer */
|
||||
size += 8 - size % 8; /* adjust DES size */
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/* put_stream_line: write a line of text to a stream; return status */
|
||||
int
|
||||
put_stream_line(fp, s, len)
|
||||
FILE *fp;
|
||||
char *s;
|
||||
int len;
|
||||
{
|
||||
while (len--)
|
||||
if ((des ? put_des_char(*s++, fp) : fputc(*s++, fp)) < 0) {
|
||||
fprintf(stderr, "%s\n", strerror(errno));
|
||||
sprintf(errmsg, "cannot write file");
|
||||
return ERR;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get_extended_line: get a an extended line from stdin */
|
||||
char *
|
||||
get_extended_line(sizep, nonl)
|
||||
int *sizep;
|
||||
int nonl;
|
||||
{
|
||||
static char *cvbuf = NULL; /* buffer */
|
||||
static int cvbufsz = 0; /* buffer size */
|
||||
|
||||
int l, n;
|
||||
char *t = ibufp;
|
||||
|
||||
while (*t++ != '\n')
|
||||
;
|
||||
if ((l = t - ibufp) < 2 || !has_trailing_escape(ibufp, ibufp + l - 1)) {
|
||||
*sizep = l;
|
||||
return ibufp;
|
||||
}
|
||||
*sizep = -1;
|
||||
REALLOC(cvbuf, cvbufsz, l, NULL);
|
||||
memcpy(cvbuf, ibufp, l);
|
||||
*(cvbuf + --l - 1) = '\n'; /* strip trailing esc */
|
||||
if (nonl) l--; /* strip newline */
|
||||
for (;;) {
|
||||
if ((n = get_tty_line()) < 0)
|
||||
return NULL;
|
||||
else if (n == 0 || ibuf[n - 1] != '\n') {
|
||||
sprintf(errmsg, "unexpected end-of-file");
|
||||
return NULL;
|
||||
}
|
||||
REALLOC(cvbuf, cvbufsz, l + n, NULL);
|
||||
memcpy(cvbuf + l, ibuf, n);
|
||||
l += n;
|
||||
if (n < 2 || !has_trailing_escape(cvbuf, cvbuf + l - 1))
|
||||
break;
|
||||
*(cvbuf + --l - 1) = '\n'; /* strip trailing esc */
|
||||
if (nonl) l--; /* strip newline */
|
||||
}
|
||||
REALLOC(cvbuf, cvbufsz, l + 1, NULL);
|
||||
cvbuf[l] = '\0';
|
||||
*sizep = l;
|
||||
return cvbuf;
|
||||
}
|
||||
|
||||
|
||||
/* get_tty_line: read a line of text from stdin; return line length */
|
||||
int
|
||||
get_tty_line()
|
||||
{
|
||||
register int oi = 0;
|
||||
register int i = 0;
|
||||
int c;
|
||||
|
||||
for (;;)
|
||||
switch (c = getchar()) {
|
||||
default:
|
||||
oi = 0;
|
||||
REALLOC(ibuf, ibufsz, i + 2, ERR);
|
||||
if (!(ibuf[i++] = c)) isbinary = 1;
|
||||
if (c != '\n')
|
||||
continue;
|
||||
lineno++;
|
||||
ibuf[i] = '\0';
|
||||
ibufp = ibuf;
|
||||
return i;
|
||||
case EOF:
|
||||
if (ferror(stdin)) {
|
||||
fprintf(stderr, "stdin: %s\n", strerror(errno));
|
||||
sprintf(errmsg, "cannot read stdin");
|
||||
clearerr(stdin);
|
||||
ibufp = NULL;
|
||||
return ERR;
|
||||
} else {
|
||||
clearerr(stdin);
|
||||
if (i != oi) {
|
||||
oi = i;
|
||||
continue;
|
||||
} else if (i)
|
||||
ibuf[i] = '\0';
|
||||
ibufp = ibuf;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define ESCAPES "\a\b\f\n\r\t\v\\"
|
||||
#define ESCCHARS "abfnrtv\\"
|
||||
|
||||
extern int rows;
|
||||
extern int cols;
|
||||
|
||||
/* put_tty_line: print text to stdout */
|
||||
int
|
||||
put_tty_line(s, l, n, gflag)
|
||||
char *s;
|
||||
int l;
|
||||
long n;
|
||||
int gflag;
|
||||
{
|
||||
int col = 0;
|
||||
int lc = 0;
|
||||
char *cp;
|
||||
|
||||
if (gflag & GNP) {
|
||||
printf("%ld\t", n);
|
||||
col = 8;
|
||||
}
|
||||
for (; l--; s++) {
|
||||
if ((gflag & GLS) && ++col > cols) {
|
||||
fputs("\\\n", stdout);
|
||||
col = 1;
|
||||
#ifndef BACKWARDS
|
||||
if (!scripted && !isglobal && ++lc > rows) {
|
||||
lc = 0;
|
||||
fputs("Press <RETURN> to continue... ", stdout);
|
||||
fflush(stdout);
|
||||
if (get_tty_line() < 0)
|
||||
return ERR;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (gflag & GLS) {
|
||||
if (31 < *s && *s < 127 && *s != '\\')
|
||||
putchar(*s);
|
||||
else {
|
||||
putchar('\\');
|
||||
col++;
|
||||
if (*s && (cp = strchr(ESCAPES, *s)) != NULL)
|
||||
putchar(ESCCHARS[cp - ESCAPES]);
|
||||
else {
|
||||
putchar((((unsigned char) *s & 0300) >> 6) + '0');
|
||||
putchar((((unsigned char) *s & 070) >> 3) + '0');
|
||||
putchar(((unsigned char) *s & 07) + '0');
|
||||
col += 2;
|
||||
}
|
||||
}
|
||||
|
||||
} else
|
||||
putchar(*s);
|
||||
}
|
||||
#ifndef BACKWARDS
|
||||
if (gflag & GLS)
|
||||
putchar('$');
|
||||
#endif
|
||||
putchar('\n');
|
||||
return 0;
|
||||
}
|
1432
bin/ed/main.c
Normal file
1432
bin/ed/main.c
Normal file
File diff suppressed because it is too large
Load Diff
67
bin/ed/re.c
67
bin/ed/re.c
@ -1,12 +1,9 @@
|
||||
/* re.c: This file contains the regular expression interface routines for
|
||||
the ed line editor. */
|
||||
/*-
|
||||
* Copyright (c) 1993 The Regents of the University of California.
|
||||
* Copyright (c) 1993 Andrew Moore, Talke Studio.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley
|
||||
* by Andrew Moore, Talke Studio.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
@ -15,18 +12,11 @@
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
@ -37,40 +27,34 @@
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)re.c 5.5 (Berkeley) 3/28/93";
|
||||
static char *rcsid = "@(#)$Id: re.c,v 1.2 1993/12/14 16:19:56 alm Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ed.h"
|
||||
|
||||
extern char *lhbuf;
|
||||
extern int lhbufsz;
|
||||
extern char *ibufp;
|
||||
extern int ibufsz;
|
||||
|
||||
extern int patlock;
|
||||
|
||||
char errmsg[MAXFNAME + 40] = "";
|
||||
char errmsg[MAXPATHLEN + 40] = "";
|
||||
|
||||
/* optpat: return pointer to compiled pattern from command buffer */
|
||||
/* get_compiled_pattern: return pointer to compiled pattern from command
|
||||
buffer */
|
||||
pattern_t *
|
||||
optpat()
|
||||
get_compiled_pattern()
|
||||
{
|
||||
static pattern_t *exp = NULL;
|
||||
|
||||
char *exps;
|
||||
char delim;
|
||||
char delimiter;
|
||||
int n;
|
||||
|
||||
if ((delim = *ibufp) == ' ') {
|
||||
if ((delimiter = *ibufp) == ' ') {
|
||||
sprintf(errmsg, "invalid pattern delimiter");
|
||||
return NULL;
|
||||
} else if (delim == '\n' || *++ibufp == '\n' || *ibufp == delim) {
|
||||
} else if (delimiter == '\n' || *++ibufp == '\n' || *ibufp == delimiter) {
|
||||
if (!exp) sprintf(errmsg, "no previous pattern");
|
||||
return exp;
|
||||
} else if ((exps = getlhs(delim)) == NULL)
|
||||
} else if ((exps = extract_pattern(delimiter)) == NULL)
|
||||
return NULL;
|
||||
/* buffer alloc'd && not reserved */
|
||||
if (exp && !patlock)
|
||||
@ -90,23 +74,24 @@ optpat()
|
||||
}
|
||||
|
||||
|
||||
extern int isbinary;
|
||||
|
||||
/* getlhs: copy a pattern string from the command buffer; return pointer
|
||||
to the copy */
|
||||
/* extract_pattern: copy a pattern string from the command buffer; return
|
||||
pointer to the copy */
|
||||
char *
|
||||
getlhs(delim)
|
||||
int delim;
|
||||
extract_pattern(delimiter)
|
||||
int delimiter;
|
||||
{
|
||||
static char *lhbuf = NULL; /* buffer */
|
||||
static int lhbufsz = 0; /* buffer size */
|
||||
|
||||
char *nd;
|
||||
int len;
|
||||
|
||||
for (nd = ibufp; *nd != delim && *nd != '\n'; nd++)
|
||||
for (nd = ibufp; *nd != delimiter && *nd != '\n'; nd++)
|
||||
switch (*nd) {
|
||||
default:
|
||||
break;
|
||||
case '[':
|
||||
if ((nd = ccl(++nd)) == NULL) {
|
||||
if ((nd = parse_char_class(++nd)) == NULL) {
|
||||
sprintf(errmsg, "unbalanced brackets ([])");
|
||||
return NULL;
|
||||
}
|
||||
@ -119,17 +104,17 @@ getlhs(delim)
|
||||
break;
|
||||
}
|
||||
len = nd - ibufp;
|
||||
CKBUF(lhbuf, lhbufsz, len + 1, NULL);
|
||||
REALLOC(lhbuf, lhbufsz, len + 1, NULL);
|
||||
memcpy(lhbuf, ibufp, len);
|
||||
lhbuf[len] = '\0';
|
||||
ibufp = nd;
|
||||
return (isbinary) ? nultonl(lhbuf, len) : lhbuf;
|
||||
return (isbinary) ? NUL_TO_NEWLINE(lhbuf, len) : lhbuf;
|
||||
}
|
||||
|
||||
|
||||
/* ccl: expand a POSIX character class */
|
||||
/* parse_char_class: expand a POSIX character class */
|
||||
char *
|
||||
ccl(s)
|
||||
parse_char_class(s)
|
||||
char *s;
|
||||
{
|
||||
int c, d;
|
||||
|
263
bin/ed/sub.c
Normal file
263
bin/ed/sub.c
Normal file
@ -0,0 +1,263 @@
|
||||
/* sub.c: This file contains the substitution routines for the ed
|
||||
line editor */
|
||||
/*-
|
||||
* Copyright (c) 1993 Andrew Moore, Talke Studio.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char *rcsid = "@(#)$Id: sub.c,v 1.3 1993/12/15 15:22:02 alm Exp alm $";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "ed.h"
|
||||
|
||||
|
||||
char *rhbuf; /* rhs substitution buffer */
|
||||
int rhbufsz; /* rhs substitution buffer size */
|
||||
int rhbufi; /* rhs substitution buffer index */
|
||||
|
||||
/* extract_subst_tail: extract substitution tail from the command buffer */
|
||||
int
|
||||
extract_subst_tail(flagp, np)
|
||||
int *flagp;
|
||||
int *np;
|
||||
{
|
||||
char delimiter;
|
||||
|
||||
*flagp = *np = 0;
|
||||
if ((delimiter = *ibufp) == '\n') {
|
||||
rhbufi = 0;
|
||||
*flagp = GPR;
|
||||
return 0;
|
||||
} else if (extract_subst_template() == NULL)
|
||||
return ERR;
|
||||
else if (*ibufp == '\n') {
|
||||
*flagp = GPR;
|
||||
return 0;
|
||||
} else if (*ibufp == delimiter)
|
||||
ibufp++;
|
||||
if ('1' <= *ibufp && *ibufp <= '9') {
|
||||
STRTOL(*np, ibufp);
|
||||
return 0;
|
||||
} else if (*ibufp == 'g') {
|
||||
ibufp++;
|
||||
*flagp = GSG;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* extract_subst_template: return pointer to copy of substitution template
|
||||
in the command buffer */
|
||||
char *
|
||||
extract_subst_template()
|
||||
{
|
||||
int n = 0;
|
||||
int i = 0;
|
||||
char c;
|
||||
char delimiter = *ibufp++;
|
||||
|
||||
if (*ibufp == '%' && *(ibufp + 1) == delimiter) {
|
||||
ibufp++;
|
||||
if (!rhbuf) sprintf(errmsg, "no previous substitution");
|
||||
return rhbuf;
|
||||
}
|
||||
while (*ibufp != delimiter) {
|
||||
REALLOC(rhbuf, rhbufsz, i + 2, NULL);
|
||||
if ((c = rhbuf[i++] = *ibufp++) == '\n' && *ibufp == '\0') {
|
||||
i--, ibufp--;
|
||||
break;
|
||||
} else if (c != '\\')
|
||||
;
|
||||
else if ((rhbuf[i++] = *ibufp++) != '\n')
|
||||
;
|
||||
else if (!isglobal) {
|
||||
while ((n = get_tty_line()) == 0 ||
|
||||
n > 0 && ibuf[n - 1] != '\n')
|
||||
clearerr(stdin);
|
||||
if (n < 0)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
REALLOC(rhbuf, rhbufsz, i + 1, NULL);
|
||||
rhbuf[rhbufi = i] = '\0';
|
||||
return rhbuf;
|
||||
}
|
||||
|
||||
|
||||
char *rbuf; /* substitute_matching_text buffer */
|
||||
int rbufsz; /* substitute_matching_text buffer size */
|
||||
|
||||
/* search_and_replace: for each line in a range, change text matching a pattern
|
||||
according to a substitution template; return status */
|
||||
int
|
||||
search_and_replace(pat, gflag, kth)
|
||||
pattern_t *pat;
|
||||
int gflag;
|
||||
int kth;
|
||||
{
|
||||
undo_t *up;
|
||||
char *txt;
|
||||
char *eot;
|
||||
long lc;
|
||||
int nsubs = 0;
|
||||
line_t *lp;
|
||||
int len;
|
||||
|
||||
current_addr = first_addr - 1;
|
||||
for (lc = 0; lc <= second_addr - first_addr; lc++) {
|
||||
lp = get_addressed_line_node(++current_addr);
|
||||
if ((len = substitute_matching_text(pat, lp, gflag, kth)) < 0)
|
||||
return ERR;
|
||||
else if (len) {
|
||||
up = NULL;
|
||||
if (delete_lines(current_addr, current_addr) < 0)
|
||||
return ERR;
|
||||
txt = rbuf;
|
||||
eot = rbuf + len;
|
||||
SPL1();
|
||||
do {
|
||||
if ((txt = put_sbuf_line(txt)) == NULL) {
|
||||
SPL0();
|
||||
return ERR;
|
||||
} else if (up)
|
||||
up->t = get_addressed_line_node(current_addr);
|
||||
else if ((up = push_undo_stack(UADD,
|
||||
current_addr, current_addr)) == NULL) {
|
||||
SPL0();
|
||||
return ERR;
|
||||
}
|
||||
} while (txt != eot);
|
||||
SPL0();
|
||||
nsubs++;
|
||||
}
|
||||
}
|
||||
if (nsubs == 0 && !(gflag & GLB)) {
|
||||
sprintf(errmsg, "no match");
|
||||
return ERR;
|
||||
} else if ((gflag & (GPR | GLS | GNP)) &&
|
||||
display_lines(current_addr, current_addr, gflag) < 0)
|
||||
return ERR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* substitute_matching_text: replace text matched by a pattern according to
|
||||
a substitution template; return pointer to the modified text */
|
||||
int
|
||||
substitute_matching_text(pat, lp, gflag, kth)
|
||||
pattern_t *pat;
|
||||
line_t *lp;
|
||||
int gflag;
|
||||
int kth;
|
||||
{
|
||||
int off = 0;
|
||||
int changed = 0;
|
||||
int matchno = 0;
|
||||
int i = 0;
|
||||
regmatch_t rm[SE_MAX];
|
||||
char *txt;
|
||||
char *eot;
|
||||
|
||||
if ((txt = get_sbuf_line(lp)) == NULL)
|
||||
return ERR;
|
||||
if (isbinary)
|
||||
NUL_TO_NEWLINE(txt, lp->len);
|
||||
eot = txt + lp->len;
|
||||
if (!regexec(pat, txt, SE_MAX, rm, 0)) {
|
||||
do {
|
||||
if (!kth || kth == ++matchno) {
|
||||
changed++;
|
||||
i = rm[0].rm_so;
|
||||
REALLOC(rbuf, rbufsz, off + i, ERR);
|
||||
if (isbinary)
|
||||
NEWLINE_TO_NUL(txt, rm[0].rm_eo);
|
||||
memcpy(rbuf + off, txt, i);
|
||||
off += i;
|
||||
if ((off = apply_subst_template(txt, rm, off,
|
||||
pat->re_nsub)) < 0)
|
||||
return ERR;
|
||||
} else {
|
||||
i = rm[0].rm_eo;
|
||||
REALLOC(rbuf, rbufsz, off + i, ERR);
|
||||
if (isbinary)
|
||||
NEWLINE_TO_NUL(txt, i);
|
||||
memcpy(rbuf + off, txt, i);
|
||||
off += i;
|
||||
}
|
||||
txt += rm[0].rm_eo;
|
||||
} while (*txt && (!changed || (gflag & GSG) && rm[0].rm_eo) &&
|
||||
!regexec(pat, txt, SE_MAX, rm, REG_NOTBOL));
|
||||
i = eot - txt;
|
||||
REALLOC(rbuf, rbufsz, off + i + 2, ERR);
|
||||
if (i > 0 && !rm[0].rm_eo && (gflag & GSG)) {
|
||||
sprintf(errmsg, "infinite substitution loop");
|
||||
return ERR;
|
||||
}
|
||||
if (isbinary)
|
||||
NEWLINE_TO_NUL(txt, i);
|
||||
memcpy(rbuf + off, txt, i);
|
||||
memcpy(rbuf + off + i, "\n", 2);
|
||||
}
|
||||
return changed ? off + i + 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
/* apply_subst_template: modify text according to a substitution template;
|
||||
return offset to end of modified text */
|
||||
int
|
||||
apply_subst_template(boln, rm, off, re_nsub)
|
||||
char *boln;
|
||||
regmatch_t *rm;
|
||||
int off;
|
||||
int re_nsub;
|
||||
{
|
||||
int j = 0;
|
||||
int k = 0;
|
||||
int n;
|
||||
char *sub = rhbuf;
|
||||
|
||||
for (; sub - rhbuf < rhbufi; sub++)
|
||||
if (*sub == '&') {
|
||||
j = rm[0].rm_so;
|
||||
k = rm[0].rm_eo;
|
||||
REALLOC(rbuf, rbufsz, off + k - j, ERR);
|
||||
while (j < k)
|
||||
rbuf[off++] = boln[j++];
|
||||
} else if (*sub == '\\' && '1' <= *++sub && *sub <= '9' &&
|
||||
(n = *sub - '0') <= re_nsub) {
|
||||
j = rm[n].rm_so;
|
||||
k = rm[n].rm_eo;
|
||||
REALLOC(rbuf, rbufsz, off + k - j, ERR);
|
||||
while (j < k)
|
||||
rbuf[off++] = boln[j++];
|
||||
} else {
|
||||
REALLOC(rbuf, rbufsz, off + 1, ERR);
|
||||
rbuf[off++] = *sub;
|
||||
}
|
||||
REALLOC(rbuf, rbufsz, off + 1, ERR);
|
||||
rbuf[off] = '\0';
|
||||
return off;
|
||||
}
|
@ -1,17 +1,23 @@
|
||||
SHELL= /bin/sh
|
||||
ED= ../obj/ed
|
||||
|
||||
all: build test
|
||||
@echo done
|
||||
all: check
|
||||
@:
|
||||
|
||||
check: build test
|
||||
@if grep -h '\*\*\*' errs.o scripts.o; then :; else \
|
||||
echo "tests completed successfully."; \
|
||||
fi
|
||||
|
||||
build: mkscripts.sh
|
||||
@echo building test scripts...
|
||||
@chmod +x mkscripts.sh
|
||||
@./mkscripts.sh ${ED}
|
||||
@if [ -f errs.o ]; then :; else \
|
||||
echo "building test scripts for $(ED) ..."; \
|
||||
$(SHELL) mkscripts.sh $(ED); \
|
||||
fi
|
||||
|
||||
test: build ckscripts.sh
|
||||
@echo running test scripts...
|
||||
@chmod +x ckscripts.sh
|
||||
@./ckscripts.sh ${ED}
|
||||
@echo testing $(ED) ...
|
||||
@$(SHELL) ckscripts.sh $(ED)
|
||||
|
||||
clean:
|
||||
rm -f *.ed *.[oz] *~
|
||||
rm -f *.ed *.red *.[oz] *~
|
||||
|
@ -19,14 +19,6 @@ which look like:
|
||||
or:
|
||||
*** Output u.o of script u.ed is incorrect ***
|
||||
|
||||
It is assumed that the ed being tested processes escapes (\) in file names.
|
||||
This is so that a name starting with bang (!) can be read, via:
|
||||
r \!file
|
||||
Without the escape, a POSIX ed would attempt to read the output of
|
||||
the shell command `file'. If the ed being tested does not support escape
|
||||
processing on file names, then the script `mkscripts.sh' should be modified
|
||||
accordingly.
|
||||
|
||||
The POSIX requirement that an address range not be used where at most
|
||||
a single address is expected has been relaxed in this version of ed.
|
||||
Therefore, the following scripts which test for compliance with this
|
||||
@ -36,6 +28,3 @@ a1-err.ed
|
||||
i1-err.ed
|
||||
k1-err.ed
|
||||
r1-err.ed
|
||||
|
||||
In addition, one of bang1-err.ed or bang2.ed will fail, depending on whether or
|
||||
not ed was compiled with the VI_BANG directive.
|
||||
|
9
bin/ed/test/addr.d
Normal file
9
bin/ed/test/addr.d
Normal file
@ -0,0 +1,9 @@
|
||||
line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
line5
|
||||
1ine6
|
||||
line7
|
||||
line8
|
||||
line9
|
2
bin/ed/test/addr.r
Normal file
2
bin/ed/test/addr.r
Normal file
@ -0,0 +1,2 @@
|
||||
line 2
|
||||
line9
|
5
bin/ed/test/addr.t
Normal file
5
bin/ed/test/addr.t
Normal file
@ -0,0 +1,5 @@
|
||||
1 d
|
||||
1 1 d
|
||||
1,2,d
|
||||
1;+ + ,d
|
||||
1,2;., + 2d
|
@ -5,26 +5,24 @@
|
||||
|
||||
PATH="/bin:/usr/bin:/usr/local/bin/:."
|
||||
ED=$1
|
||||
[ 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;
|
||||
# rename then to *-err.ed~; they exit with non-zero status
|
||||
for i in *-err.ed; do
|
||||
echo $i~
|
||||
# Run the *.red scripts first, since these don't generate output;
|
||||
# they exit with non-zero status
|
||||
for i in *.red; do
|
||||
echo $i
|
||||
if $i; then
|
||||
echo "*** The script $i~ exited abnormally ***"
|
||||
echo "*** The script $i exited abnormally ***"
|
||||
fi
|
||||
mv $i $i~
|
||||
done >errs.o 2>&1
|
||||
|
||||
# Run the remainding scripts; they exit with zero status
|
||||
for i in *.ed; do
|
||||
base=`expr $i : '\([^.]*\)'`
|
||||
# base=`expr $i : '\([^.]*\)'`
|
||||
# base=`echo $i | sed 's/\..*//'`
|
||||
# base=`$ED - \!"echo \\\\$i" <<-EOF
|
||||
# s/\..*
|
||||
# EOF`
|
||||
base=`$ED - \!"echo $i" <<-EOF
|
||||
s/\..*
|
||||
EOF`
|
||||
if $base.ed; then
|
||||
if cmp -s $base.o $base.r; then :; else
|
||||
echo "*** Output $base.o of script $i is incorrect ***"
|
||||
|
3
bin/ed/test/g5.d
Normal file
3
bin/ed/test/g5.d
Normal file
@ -0,0 +1,3 @@
|
||||
line 1
|
||||
line 2
|
||||
line 3
|
9
bin/ed/test/g5.r
Normal file
9
bin/ed/test/g5.r
Normal file
@ -0,0 +1,9 @@
|
||||
line 1
|
||||
line 2
|
||||
line 3
|
||||
line 2
|
||||
line 3
|
||||
line 1
|
||||
line 3
|
||||
line 1
|
||||
line 2
|
2
bin/ed/test/g5.t
Normal file
2
bin/ed/test/g5.t
Normal file
@ -0,0 +1,2 @@
|
||||
g/./1,3t$\
|
||||
1d
|
@ -3,69 +3,71 @@
|
||||
|
||||
PATH="/bin:/usr/bin:/usr/local/bin/:."
|
||||
ED=$1
|
||||
[ X"$ED" = X -o ! -x $ED ] && ED="../ed"
|
||||
[ ! -x $ED ] && { echo "$ED: cannot execute"; exit 1; }
|
||||
|
||||
for i in *.t; do
|
||||
# base=${i%.*}
|
||||
# base=`echo $i | sed 's/\..*//'`
|
||||
base=`expr $i : '\([^.]*\)'`
|
||||
(
|
||||
echo "#!/bin/sh -"
|
||||
echo "$ED - <<\EOT"
|
||||
echo "r \\$base.d"
|
||||
cat $i
|
||||
echo "w \\$base.o"
|
||||
echo EOT
|
||||
) >$base.ed
|
||||
chmod +x $base.ed
|
||||
# The following is pretty ugly and not appropriate use of ed
|
||||
# but the point is that it can be done...
|
||||
# base=`$ED - \!"echo \\\\$i" <<-EOF
|
||||
# s/\..*
|
||||
# EOF`
|
||||
# $ED - <<-EOF
|
||||
# a
|
||||
# #!/bin/sh -
|
||||
# $ED - <<\EOT
|
||||
# r \\$base.d
|
||||
# w \\$base.o
|
||||
# EOT
|
||||
# .
|
||||
# -2r \\$i
|
||||
# w \\$base.ed
|
||||
# !chmod +x \\$base.ed
|
||||
# EOF
|
||||
# base=`expr $i : '\([^.]*\)'`
|
||||
# (
|
||||
# echo "#!/bin/sh -"
|
||||
# echo "$ED - <<\EOT"
|
||||
# echo "r $base.d"
|
||||
# cat $i
|
||||
# echo "w $base.o"
|
||||
# echo EOT
|
||||
# ) >$base.ed
|
||||
# chmod +x $base.ed
|
||||
# The following is pretty ugly way of doing the above, and not appropriate
|
||||
# use of ed but the point is that it can be done...
|
||||
base=`$ED - \!"echo $i" <<-EOF
|
||||
s/\..*
|
||||
EOF`
|
||||
$ED - <<-EOF
|
||||
a
|
||||
#!/bin/sh -
|
||||
$ED - <<\EOT
|
||||
H
|
||||
r $base.d
|
||||
w $base.o
|
||||
EOT
|
||||
.
|
||||
-2r $i
|
||||
w $base.ed
|
||||
!chmod +x $base.ed
|
||||
EOF
|
||||
done
|
||||
|
||||
for i in *.err; do
|
||||
# base=${i%.*}
|
||||
# base=`echo $i | sed 's/\..*//'`
|
||||
base=`expr $i : '\([^.]*\)'`
|
||||
(
|
||||
echo "#!/bin/sh -"
|
||||
echo "$ED - <<\EOT"
|
||||
echo H
|
||||
echo "r \\$base.err"
|
||||
cat $i
|
||||
echo "w \\$base.o"
|
||||
echo EOT
|
||||
) >$base-err.ed
|
||||
chmod +x $base-err.ed
|
||||
# base=`$ED - \!"echo \\\\$i" <<-EOF
|
||||
# s/\..*
|
||||
# EOF`
|
||||
# $ED - <<-EOF
|
||||
# a
|
||||
# #!/bin/sh -
|
||||
# $ED - <<\EOT
|
||||
# H
|
||||
# r \\$base.err
|
||||
# w \\$base.o
|
||||
# EOT
|
||||
# .
|
||||
# -2r \\$i
|
||||
# w \\${base}-err.ed
|
||||
# !chmod +x ${base}-err.ed
|
||||
# EOF
|
||||
# base=`expr $i : '\([^.]*\)'`
|
||||
# (
|
||||
# echo "#!/bin/sh -"
|
||||
# echo "$ED - <<\EOT"
|
||||
# echo H
|
||||
# echo "r $base.err"
|
||||
# cat $i
|
||||
# echo "w $base.o"
|
||||
# echo EOT
|
||||
# ) >$base-err.ed
|
||||
# chmod +x $base-err.ed
|
||||
# The following is pretty ugly way of doing the above, and not appropriate
|
||||
# use of ed but the point is that it can be done...
|
||||
base=`$ED - \!"echo $i" <<-EOF
|
||||
s/\..*
|
||||
EOF`
|
||||
$ED - <<-EOF
|
||||
a
|
||||
#!/bin/sh -
|
||||
$ED - <<\EOT
|
||||
H
|
||||
r $base.err
|
||||
w $base.o
|
||||
EOT
|
||||
.
|
||||
-2r $i
|
||||
w ${base}.red
|
||||
!chmod +x ${base}.red
|
||||
EOF
|
||||
done
|
||||
|
154
bin/ed/undo.c
Normal file
154
bin/ed/undo.c
Normal file
@ -0,0 +1,154 @@
|
||||
/* undo.c: This file contains the undo routines for the ed line editor */
|
||||
/*-
|
||||
* Copyright (c) 1993 Andrew Moore, Talke Studio.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char *rcsid = "@(#)$Id: undo.c,v 1.2 1993/12/14 16:19:56 alm Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "ed.h"
|
||||
|
||||
|
||||
#define USIZE 100 /* undo stack size */
|
||||
undo_t *ustack = NULL; /* undo stack */
|
||||
long usize = 0; /* stack size variable */
|
||||
long u_p = 0; /* undo stack pointer */
|
||||
|
||||
/* push_undo_stack: return pointer to intialized undo node */
|
||||
undo_t *
|
||||
push_undo_stack(type, from, to)
|
||||
int type;
|
||||
long from;
|
||||
long to;
|
||||
{
|
||||
undo_t *t;
|
||||
|
||||
#if defined(sun) || defined(NO_REALLOC_NULL)
|
||||
if (ustack == NULL &&
|
||||
(ustack = (undo_t *) malloc((usize = USIZE) * sizeof(undo_t))) == NULL) {
|
||||
fprintf(stderr, "%s\n", strerror(errno));
|
||||
sprintf(errmsg, "out of memory");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
t = ustack;
|
||||
if (u_p < usize ||
|
||||
(t = (undo_t *) realloc(ustack, (usize += USIZE) * sizeof(undo_t))) != NULL) {
|
||||
ustack = t;
|
||||
ustack[u_p].type = type;
|
||||
ustack[u_p].t = get_addressed_line_node(to);
|
||||
ustack[u_p].h = get_addressed_line_node(from);
|
||||
return ustack + u_p++;
|
||||
}
|
||||
/* out of memory - release undo stack */
|
||||
fprintf(stderr, "%s\n", strerror(errno));
|
||||
sprintf(errmsg, "out of memory");
|
||||
clear_undo_stack();
|
||||
free(ustack);
|
||||
ustack = NULL;
|
||||
usize = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* USWAP: swap undo nodes */
|
||||
#define USWAP(x,y) { \
|
||||
undo_t utmp; \
|
||||
utmp = x, x = y, y = utmp; \
|
||||
}
|
||||
|
||||
|
||||
long u_current_addr = -1; /* if >= 0, undo enabled */
|
||||
long u_addr_last = -1; /* if >= 0, undo enabled */
|
||||
|
||||
/* pop_undo_stack: undo last change to the editor buffer */
|
||||
int
|
||||
pop_undo_stack()
|
||||
{
|
||||
long n;
|
||||
long o_current_addr = current_addr;
|
||||
long o_addr_last = addr_last;
|
||||
|
||||
if (u_current_addr == -1 || u_addr_last == -1) {
|
||||
sprintf(errmsg, "nothing to undo");
|
||||
return ERR;
|
||||
} else if (u_p)
|
||||
modified = 1;
|
||||
get_addressed_line_node(0); /* this get_addressed_line_node last! */
|
||||
SPL1();
|
||||
for (n = u_p; n-- > 0;) {
|
||||
switch(ustack[n].type) {
|
||||
case UADD:
|
||||
REQUE(ustack[n].h->q_back, ustack[n].t->q_forw);
|
||||
break;
|
||||
case UDEL:
|
||||
REQUE(ustack[n].h->q_back, ustack[n].h);
|
||||
REQUE(ustack[n].t, ustack[n].t->q_forw);
|
||||
break;
|
||||
case UMOV:
|
||||
case VMOV:
|
||||
REQUE(ustack[n - 1].h, ustack[n].h->q_forw);
|
||||
REQUE(ustack[n].t->q_back, ustack[n - 1].t);
|
||||
REQUE(ustack[n].h, ustack[n].t);
|
||||
n--;
|
||||
break;
|
||||
default:
|
||||
/*NOTREACHED*/
|
||||
;
|
||||
}
|
||||
ustack[n].type ^= 1;
|
||||
}
|
||||
/* reverse undo stack order */
|
||||
for (n = u_p; n-- > (u_p + 1)/ 2;)
|
||||
USWAP(ustack[n], ustack[u_p - 1 - n]);
|
||||
if (isglobal)
|
||||
clear_active_list();
|
||||
current_addr = u_current_addr, u_current_addr = o_current_addr;
|
||||
addr_last = u_addr_last, u_addr_last = o_addr_last;
|
||||
SPL0();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* clear_undo_stack: clear the undo stack */
|
||||
void
|
||||
clear_undo_stack()
|
||||
{
|
||||
line_t *lp, *ep, *tl;
|
||||
|
||||
while (u_p--)
|
||||
if (ustack[u_p].type == UDEL) {
|
||||
ep = ustack[u_p].t->q_forw;
|
||||
for (lp = ustack[u_p].h; lp != ep; lp = tl) {
|
||||
unmark_line_node(lp);
|
||||
tl = lp->q_forw;
|
||||
free(lp);
|
||||
}
|
||||
}
|
||||
u_p = 0;
|
||||
u_current_addr = current_addr;
|
||||
u_addr_last = addr_last;
|
||||
}
|
Loading…
Reference in New Issue
Block a user