Import NetBSD ed(1)
This commit is contained in:
parent
d65f6f7009
commit
7e81b07cc5
147 changed files with 5400 additions and 2273 deletions
|
@ -2,6 +2,6 @@
|
||||||
|
|
||||||
.include <bsd.own.mk>
|
.include <bsd.own.mk>
|
||||||
|
|
||||||
SUBDIR= mkdir rm rmdir date
|
SUBDIR= date ed mkdir rm rmdir
|
||||||
|
|
||||||
.include <bsd.subdir.mk>
|
.include <bsd.subdir.mk>
|
||||||
|
|
20
bin/ed/Makefile
Normal file
20
bin/ed/Makefile
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# $NetBSD: Makefile,v 1.36 2009/07/26 01:58:20 dholland Exp $
|
||||||
|
|
||||||
|
.include <bsd.own.mk>
|
||||||
|
|
||||||
|
PROG= ed
|
||||||
|
CPPFLAGS+=-DBACKWARDS
|
||||||
|
|
||||||
|
.if (${MKCRYPTO} != "no")
|
||||||
|
CPPFLAGS+=-DDES
|
||||||
|
.endif
|
||||||
|
|
||||||
|
SRCS= buf.c cbc.c glbl.c io.c main.c re.c sub.c undo.c
|
||||||
|
|
||||||
|
LDADD+= -lcrypt
|
||||||
|
DPADD+= ${LIBCRYPT}
|
||||||
|
|
||||||
|
#LINKS= ${BINDIR}/ed ${BINDIR}/red
|
||||||
|
#MLINKS= ed.1 red.1
|
||||||
|
|
||||||
|
.include <bsd.prog.mk>
|
103
bin/ed/POSIX
Normal file
103
bin/ed/POSIX
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
$NetBSD: POSIX,v 1.10 1999/11/18 19:16:34 kristerw Exp $
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
OMISSIONS
|
||||||
|
---------
|
||||||
|
1) Locale(3) is not supported yet.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
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 (\).
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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 occurrences 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.
|
24
bin/ed/README
Normal file
24
bin/ed/README
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
$NetBSD: README,v 1.9 1995/03/21 09:04:33 cgd Exp $
|
||||||
|
|
||||||
|
ed is an 8-bit-clean, POSIX-compliant line editor. It should work with
|
||||||
|
any regular expression package that conforms to the POSIX interface
|
||||||
|
standard, such as GNU regex(3).
|
||||||
|
|
||||||
|
If reliable signals are supported (e.g., POSIX sigaction(2)), it should
|
||||||
|
compile with little trouble. Otherwise, the macros SPL1() and SPL0()
|
||||||
|
should be redefined to disable interrupts.
|
||||||
|
|
||||||
|
The following compiler directives are recognized:
|
||||||
|
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.
|
||||||
|
|
||||||
|
The ./test directory contains regression tests for ed. The README
|
||||||
|
file in that directory explains how to run these.
|
||||||
|
|
||||||
|
For a description of the ed algorithm, see Kernighan and Plauger's book
|
||||||
|
"Software Tools in Pascal," Addison-Wesley, 1981.
|
319
bin/ed/buf.c
Normal file
319
bin/ed/buf.c
Normal file
|
@ -0,0 +1,319 @@
|
||||||
|
/* $NetBSD: buf.c,v 1.26 2006/03/17 14:37:14 rumble Exp $ */
|
||||||
|
|
||||||
|
/* buf.c: This file contains the scratch-file buffer 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef lint
|
||||||
|
#if 0
|
||||||
|
static char *rcsid = "@(#)buf.c,v 1.4 1994/02/01 00:34:35 alm Exp";
|
||||||
|
#else
|
||||||
|
__RCSID("$NetBSD: buf.c,v 1.26 2006/03/17 14:37:14 rumble Exp $");
|
||||||
|
#endif
|
||||||
|
#endif /* not lint */
|
||||||
|
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <paths.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <err.h>
|
||||||
|
|
||||||
|
#include "ed.h"
|
||||||
|
|
||||||
|
|
||||||
|
FILE *sfp; /* scratch file pointer */
|
||||||
|
off_t sfseek; /* scratch file position */
|
||||||
|
int seek_write; /* seek before writing */
|
||||||
|
line_t buffer_head; /* incore buffer */
|
||||||
|
|
||||||
|
/* get_sbuf_line: get a line of text from the scratch file; return pointer
|
||||||
|
to the text */
|
||||||
|
char *
|
||||||
|
get_sbuf_line(line_t *lp)
|
||||||
|
{
|
||||||
|
static char *sfbuf = NULL; /* buffer */
|
||||||
|
static int sfbufsz = 0; /* buffer size */
|
||||||
|
|
||||||
|
int len, ct;
|
||||||
|
|
||||||
|
if (lp == &buffer_head)
|
||||||
|
return NULL;
|
||||||
|
seek_write = 1; /* force seek on write */
|
||||||
|
/* out of position */
|
||||||
|
if (sfseek != lp->seek) {
|
||||||
|
sfseek = lp->seek;
|
||||||
|
if (fseek(sfp, sfseek, SEEK_SET) < 0) {
|
||||||
|
fprintf(stderr, "%s\n", strerror(errno));
|
||||||
|
sprintf(errmsg, "cannot seek temp file");
|
||||||
|
return 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");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
sfseek += len; /* update file position */
|
||||||
|
sfbuf[len] = '\0';
|
||||||
|
return sfbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 *
|
||||||
|
put_sbuf_line(char *cs)
|
||||||
|
{
|
||||||
|
line_t *lp;
|
||||||
|
int len, ct;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) {
|
||||||
|
fprintf(stderr, "%s\n", strerror(errno));
|
||||||
|
sprintf(errmsg, "out of memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* assert: cs is '\n' terminated */
|
||||||
|
for (s = cs; *s != '\n'; s++)
|
||||||
|
;
|
||||||
|
if (s - cs >= LINECHARS) {
|
||||||
|
sprintf(errmsg, "line too long");
|
||||||
|
free(lp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
len = s - cs;
|
||||||
|
/* out of position */
|
||||||
|
if (seek_write) {
|
||||||
|
if (fseek(sfp, 0L, SEEK_END) < 0) {
|
||||||
|
fprintf(stderr, "%s\n", strerror(errno));
|
||||||
|
sprintf(errmsg, "cannot seek temp file");
|
||||||
|
free(lp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
sfseek = ftell(sfp);
|
||||||
|
seek_write = 0;
|
||||||
|
}
|
||||||
|
/* assert: SPL1() */
|
||||||
|
if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) {
|
||||||
|
sfseek = -1;
|
||||||
|
fprintf(stderr, "%s\n", strerror(errno));
|
||||||
|
sprintf(errmsg, "cannot write temp file");
|
||||||
|
free(lp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
lp->len = len;
|
||||||
|
lp->seek = sfseek;
|
||||||
|
add_line_node(lp);
|
||||||
|
sfseek += len; /* update file position */
|
||||||
|
return ++s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* add_line_node: add a line node in the editor buffer after the current line */
|
||||||
|
void
|
||||||
|
add_line_node(line_t *lp)
|
||||||
|
{
|
||||||
|
line_t *cp;
|
||||||
|
|
||||||
|
cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */
|
||||||
|
INSQUE(lp, cp);
|
||||||
|
addr_last++;
|
||||||
|
current_addr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* get_line_node_addr: return line number of pointer */
|
||||||
|
long
|
||||||
|
get_line_node_addr(line_t *lp)
|
||||||
|
{
|
||||||
|
line_t *cp = &buffer_head;
|
||||||
|
long n = 0;
|
||||||
|
|
||||||
|
while (cp != lp && (cp = cp->q_forw) != &buffer_head)
|
||||||
|
n++;
|
||||||
|
if (n && cp == &buffer_head) {
|
||||||
|
sprintf(errmsg, "invalid address");
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* get_addressed_line_node: return pointer to a line node in the editor buffer */
|
||||||
|
line_t *
|
||||||
|
get_addressed_line_node(long n)
|
||||||
|
{
|
||||||
|
static line_t *lp = &buffer_head;
|
||||||
|
static long on = 0;
|
||||||
|
|
||||||
|
SPL1();
|
||||||
|
if (n > on) {
|
||||||
|
if (n <= (on + addr_last) >> 1) {
|
||||||
|
for (; on < n; on++)
|
||||||
|
lp = lp->q_forw;
|
||||||
|
} else {
|
||||||
|
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->q_back;
|
||||||
|
} else {
|
||||||
|
lp = &buffer_head;
|
||||||
|
for (on = 0; on < n; on++)
|
||||||
|
lp = lp->q_forw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SPL0();
|
||||||
|
return lp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *sfn = NULL; /* scratch file name */
|
||||||
|
|
||||||
|
/* open_sbuf: open scratch file */
|
||||||
|
int
|
||||||
|
open_sbuf(void)
|
||||||
|
{
|
||||||
|
int u, fd;
|
||||||
|
const char *tmp;
|
||||||
|
size_t s;
|
||||||
|
|
||||||
|
isbinary = newline_added = 0;
|
||||||
|
fd = -1;
|
||||||
|
u = umask(077);
|
||||||
|
|
||||||
|
if ((tmp = getenv("TMPDIR")) == NULL)
|
||||||
|
tmp = _PATH_TMP;
|
||||||
|
|
||||||
|
if ((s = strlen(tmp)) == 0 || tmp[s - 1] == '/')
|
||||||
|
(void)asprintf(&sfn, "%sed.XXXXXX", tmp);
|
||||||
|
else
|
||||||
|
(void)asprintf(&sfn, "%s/ed.XXXXXX", tmp);
|
||||||
|
if (sfn == NULL) {
|
||||||
|
warn(NULL);
|
||||||
|
sprintf(errmsg, "could not allocate memory");
|
||||||
|
umask(u);
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ((fd = mkstemp(sfn)) == -1 || (sfp = fdopen(fd, "w+")) == NULL) {
|
||||||
|
if (fd != -1)
|
||||||
|
close(fd);
|
||||||
|
warn("%s", sfn);
|
||||||
|
sprintf(errmsg, "cannot open temp file");
|
||||||
|
umask(u);
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
umask(u);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* close_sbuf: close scratch file */
|
||||||
|
int
|
||||||
|
close_sbuf(void)
|
||||||
|
{
|
||||||
|
if (sfp) {
|
||||||
|
if (fclose(sfp) < 0) {
|
||||||
|
fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
|
||||||
|
sprintf(errmsg, "cannot close temp file");
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
sfp = NULL;
|
||||||
|
if (sfn) {
|
||||||
|
unlink(sfn);
|
||||||
|
free(sfn);
|
||||||
|
sfn = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sfseek = seek_write = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* quit: remove_lines scratch file and exit */
|
||||||
|
void
|
||||||
|
quit(int n)
|
||||||
|
{
|
||||||
|
if (sfp) {
|
||||||
|
fclose(sfp);
|
||||||
|
if (sfn) {
|
||||||
|
unlink(sfn);
|
||||||
|
free(sfn);
|
||||||
|
sfn = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit(n);
|
||||||
|
/* NOTREACHED */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned char ctab[256]; /* character translation table */
|
||||||
|
|
||||||
|
/* init_buffers: open scratch buffer; initialize line queue */
|
||||||
|
void
|
||||||
|
init_buffers(void)
|
||||||
|
{
|
||||||
|
int i = 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);
|
||||||
|
REQUE(&buffer_head, &buffer_head);
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
ctab[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* translit_text: translate characters in a string */
|
||||||
|
char *
|
||||||
|
translit_text(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;
|
||||||
|
}
|
460
bin/ed/cbc.c
Normal file
460
bin/ed/cbc.c
Normal file
|
@ -0,0 +1,460 @@
|
||||||
|
/* $NetBSD: cbc.c,v 1.22 2010/06/09 19:20:18 riz Exp $ */
|
||||||
|
|
||||||
|
/* cbc.c: This file contains the encryption routines for the ed line editor */
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 1993 The Regents of the University of California.
|
||||||
|
* 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.
|
||||||
|
* 3. 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
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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.
|
||||||
|
*
|
||||||
|
* from: @(#)bdes.c 5.5 (Berkeley) 6/27/91
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* 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.
|
||||||
|
* 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
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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.
|
||||||
|
*
|
||||||
|
* from: @(#)bdes.c 5.5 (Berkeley) 6/27/91
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef lint
|
||||||
|
#if 0
|
||||||
|
static char *rcsid = "@(#)cbc.c,v 1.2 1994/02/01 00:34:36 alm Exp";
|
||||||
|
#else
|
||||||
|
__RCSID("$NetBSD: cbc.c,v 1.22 2010/06/09 19:20:18 riz Exp $");
|
||||||
|
#endif
|
||||||
|
#endif /* not lint */
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#ifdef DES
|
||||||
|
#include <time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ed.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define a divisor for rand() that yields a uniform distribution in the
|
||||||
|
* range 0-255.
|
||||||
|
*/
|
||||||
|
#define RAND_DIV (((unsigned) RAND_MAX + 1) >> 8)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BSD and System V systems offer special library calls that do
|
||||||
|
* 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))
|
||||||
|
|
||||||
|
/* Hide the calls to the primitive encryption routines. */
|
||||||
|
#define DES_KEY(buf) \
|
||||||
|
if (des_setkey(buf)) \
|
||||||
|
des_error("des_setkey");
|
||||||
|
#define DES_XFORM(buf) \
|
||||||
|
if (des_cipher(buf, buf, 0L, (inverse ? -1 : 1))) \
|
||||||
|
des_error("des_cipher");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read/write - no error checking
|
||||||
|
*/
|
||||||
|
#define READ(buf, n, fp) fread(buf, sizeof(char), n, fp)
|
||||||
|
#define WRITE(buf, n, fp) fwrite(buf, sizeof(char), n, fp)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* some things to make references easier
|
||||||
|
*/
|
||||||
|
typedef char Desbuf[8];
|
||||||
|
#define CHAR(x,i) (x[i])
|
||||||
|
#define UCHAR(x,i) (x[i])
|
||||||
|
#define BUFFER(x) (x)
|
||||||
|
#define UBUFFER(x) (x)
|
||||||
|
|
||||||
|
#ifdef DES
|
||||||
|
/*
|
||||||
|
* global variables and related macros
|
||||||
|
*/
|
||||||
|
|
||||||
|
static Desbuf ivec; /* initialization vector */
|
||||||
|
static Desbuf pvec; /* padding vector */
|
||||||
|
static char bits[] = { /* used to extract bits from a char */
|
||||||
|
'\200', '\100', '\040', '\020', '\010', '\004', '\002', '\001'
|
||||||
|
};
|
||||||
|
static int pflag; /* 1 to preserve parity bits */
|
||||||
|
|
||||||
|
static char des_buf[8]; /* shared buffer for get_des_char/put_des_char */
|
||||||
|
static int des_ct = 0; /* count for get_des_char/put_des_char */
|
||||||
|
static int des_n = 0; /* index for put_des_char/get_des_char */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef DES
|
||||||
|
static void des_error(const char *);
|
||||||
|
static int hex_to_binary(int, int);
|
||||||
|
static void expand_des_key(char *, char *);
|
||||||
|
static void set_des_key(char *);
|
||||||
|
static int cbc_decode(char *, FILE *);
|
||||||
|
static int cbc_encode(char *, int, FILE *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* init_des_cipher: initialize DES */
|
||||||
|
void
|
||||||
|
init_des_cipher(void)
|
||||||
|
{
|
||||||
|
#ifdef DES
|
||||||
|
int i;
|
||||||
|
|
||||||
|
des_ct = des_n = 0;
|
||||||
|
|
||||||
|
/* initialize the initialization vector */
|
||||||
|
MEMZERO(ivec, 8);
|
||||||
|
|
||||||
|
/* intialize the padding vector */
|
||||||
|
srand((unsigned) time((time_t *) 0));
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
CHAR(pvec, i) = (char) (rand()/RAND_DIV);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* get_des_char: return next char in an encrypted file */
|
||||||
|
int
|
||||||
|
get_des_char(FILE *fp)
|
||||||
|
{
|
||||||
|
#ifdef DES
|
||||||
|
if (des_n >= des_ct) {
|
||||||
|
des_n = 0;
|
||||||
|
des_ct = cbc_decode(des_buf, fp);
|
||||||
|
}
|
||||||
|
return (des_ct > 0) ? (unsigned char) des_buf[des_n++] : EOF;
|
||||||
|
#else
|
||||||
|
return EOF;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* put_des_char: write a char to an encrypted file; return char written */
|
||||||
|
int
|
||||||
|
put_des_char(int c, FILE *fp)
|
||||||
|
{
|
||||||
|
#ifdef DES
|
||||||
|
if (des_n == sizeof des_buf) {
|
||||||
|
des_ct = cbc_encode(des_buf, des_n, fp);
|
||||||
|
des_n = 0;
|
||||||
|
}
|
||||||
|
return (des_ct >= 0) ? (unsigned char) (des_buf[des_n++] = c) : EOF;
|
||||||
|
#else
|
||||||
|
return EOF;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* flush_des_file: flush an encrypted file's output; return status */
|
||||||
|
int
|
||||||
|
flush_des_file(FILE *fp)
|
||||||
|
{
|
||||||
|
#ifdef DES
|
||||||
|
if (des_n == sizeof des_buf) {
|
||||||
|
des_ct = cbc_encode(des_buf, des_n, fp);
|
||||||
|
des_n = 0;
|
||||||
|
}
|
||||||
|
return (des_ct >= 0 && cbc_encode(des_buf, des_n, fp) >= 0) ? 0 : EOF;
|
||||||
|
#else
|
||||||
|
return EOF;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DES
|
||||||
|
/*
|
||||||
|
* get keyword from tty or stdin
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
get_keyword(void)
|
||||||
|
{
|
||||||
|
char *p; /* used to obtain the key */
|
||||||
|
Desbuf msgbuf; /* I/O buffer */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get the key
|
||||||
|
*/
|
||||||
|
if (*(p = getpass("Enter key: "))) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* copy it, nul-padded, into the key area
|
||||||
|
*/
|
||||||
|
expand_des_key(BUFFER(msgbuf), p);
|
||||||
|
MEMZERO(p, _PASSWORD_LEN);
|
||||||
|
set_des_key(msgbuf);
|
||||||
|
MEMZERO(msgbuf, sizeof msgbuf);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* print a warning message and, possibly, terminate
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
des_error(const char *s /* the message */)
|
||||||
|
{
|
||||||
|
(void)sprintf(errmsg, "%s", s ? s : strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* map a hex character to an integer
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
hex_to_binary(int c /* char to be converted */,
|
||||||
|
int radix /* base (2 to 16) */)
|
||||||
|
{
|
||||||
|
switch(c) {
|
||||||
|
case '0': return(0x0);
|
||||||
|
case '1': return(0x1);
|
||||||
|
case '2': return(radix > 2 ? 0x2 : -1);
|
||||||
|
case '3': return(radix > 3 ? 0x3 : -1);
|
||||||
|
case '4': return(radix > 4 ? 0x4 : -1);
|
||||||
|
case '5': return(radix > 5 ? 0x5 : -1);
|
||||||
|
case '6': return(radix > 6 ? 0x6 : -1);
|
||||||
|
case '7': return(radix > 7 ? 0x7 : -1);
|
||||||
|
case '8': return(radix > 8 ? 0x8 : -1);
|
||||||
|
case '9': return(radix > 9 ? 0x9 : -1);
|
||||||
|
case 'A': case 'a': return(radix > 10 ? 0xa : -1);
|
||||||
|
case 'B': case 'b': return(radix > 11 ? 0xb : -1);
|
||||||
|
case 'C': case 'c': return(radix > 12 ? 0xc : -1);
|
||||||
|
case 'D': case 'd': return(radix > 13 ? 0xd : -1);
|
||||||
|
case 'E': case 'e': return(radix > 14 ? 0xe : -1);
|
||||||
|
case 'F': case 'f': return(radix > 15 ? 0xf : -1);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* invalid character
|
||||||
|
*/
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* convert the key to a bit pattern
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
expand_des_key(char *obuf /* bit pattern */, char *inbuf /* the key itself */)
|
||||||
|
{
|
||||||
|
int i, j; /* counter in a for loop */
|
||||||
|
int nbuf[64]; /* used for hex/key translation */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* leading '0x' or '0X' == hex key
|
||||||
|
*/
|
||||||
|
if (inbuf[0] == '0' && (inbuf[1] == 'x' || inbuf[1] == 'X')) {
|
||||||
|
inbuf = &inbuf[2];
|
||||||
|
/*
|
||||||
|
* now translate it, bombing on any illegal hex digit
|
||||||
|
*/
|
||||||
|
for (i = 0; inbuf[i] && i < 16; i++)
|
||||||
|
if ((nbuf[i] = hex_to_binary((int) inbuf[i], 16)) == -1)
|
||||||
|
des_error("bad hex digit in key");
|
||||||
|
while (i < 16)
|
||||||
|
nbuf[i++] = 0;
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
obuf[i] =
|
||||||
|
((nbuf[2*i]&0xf)<<4) | (nbuf[2*i+1]&0xf);
|
||||||
|
/* preserve parity bits */
|
||||||
|
pflag = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* leading '0b' or '0B' == binary key
|
||||||
|
*/
|
||||||
|
if (inbuf[0] == '0' && (inbuf[1] == 'b' || inbuf[1] == 'B')) {
|
||||||
|
inbuf = &inbuf[2];
|
||||||
|
/*
|
||||||
|
* now translate it, bombing on any illegal binary digit
|
||||||
|
*/
|
||||||
|
for (i = 0; inbuf[i] && i < 16; i++)
|
||||||
|
if ((nbuf[i] = hex_to_binary((int) inbuf[i], 2)) == -1)
|
||||||
|
des_error("bad binary digit in key");
|
||||||
|
while (i < 64)
|
||||||
|
nbuf[i++] = 0;
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
obuf[i] = (obuf[i]<<1)|nbuf[8*i+j];
|
||||||
|
/* preserve parity bits */
|
||||||
|
pflag = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* no special leader -- ASCII
|
||||||
|
*/
|
||||||
|
(void)strncpy(obuf, inbuf, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************
|
||||||
|
* DES FUNCTIONS *
|
||||||
|
*****************/
|
||||||
|
/*
|
||||||
|
* This sets the DES key and (if you're using the deszip version)
|
||||||
|
* the direction of the transformation. This uses the Sun
|
||||||
|
* to map the 64-bit key onto the 56 bits that the key schedule
|
||||||
|
* generation routines use: the old way, which just uses the user-
|
||||||
|
* supplied 64 bits as is, and the new way, which resets the parity
|
||||||
|
* bit to be the same as the low-order bit in each character. The
|
||||||
|
* new way generates a greater variety of key schedules, since many
|
||||||
|
* systems set the parity (high) bit of each character to 0, and the
|
||||||
|
* DES ignores the low order bit of each character.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
set_des_key(Desbuf buf /* key block */)
|
||||||
|
{
|
||||||
|
int i, j; /* counter in a for loop */
|
||||||
|
int par; /* parity counter */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if the parity is not preserved, flip it
|
||||||
|
*/
|
||||||
|
if (!pflag) {
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
par = 0;
|
||||||
|
for (j = 1; j < 8; j++)
|
||||||
|
if ((bits[j]&UCHAR(buf, i)) != 0)
|
||||||
|
par++;
|
||||||
|
if ((par&01) == 01)
|
||||||
|
UCHAR(buf, i) = UCHAR(buf, i)&0177;
|
||||||
|
else
|
||||||
|
UCHAR(buf, i) = (UCHAR(buf, i)&0177)|0200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DES_KEY(UBUFFER(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This encrypts using the Cipher Block Chaining mode of DES
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
cbc_encode(char *msgbuf, int n, FILE *fp)
|
||||||
|
{
|
||||||
|
int inverse = 0; /* 0 to encrypt, 1 to decrypt */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* do the transformation
|
||||||
|
*/
|
||||||
|
if (n == 8) {
|
||||||
|
for (n = 0; n < 8; n++)
|
||||||
|
CHAR(msgbuf, n) ^= CHAR(ivec, n);
|
||||||
|
DES_XFORM(UBUFFER(msgbuf));
|
||||||
|
MEMCPY(BUFFER(ivec), BUFFER(msgbuf), 8);
|
||||||
|
return WRITE(BUFFER(msgbuf), 8, fp);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* at EOF or last block -- in either case, the last byte contains
|
||||||
|
* the character representation of the number of bytes in it
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
MEMZERO(msgbuf + n, 8 - n);
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Pad the last block randomly
|
||||||
|
*/
|
||||||
|
(void)MEMCPY(BUFFER(msgbuf + n), BUFFER(pvec), 8 - n);
|
||||||
|
CHAR(msgbuf, 7) = n;
|
||||||
|
for (n = 0; n < 8; n++)
|
||||||
|
CHAR(msgbuf, n) ^= CHAR(ivec, n);
|
||||||
|
DES_XFORM(UBUFFER(msgbuf));
|
||||||
|
return WRITE(BUFFER(msgbuf), 8, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This decrypts using the Cipher Block Chaining mode of DES
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
cbc_decode(char *msgbuf /* I/O buffer */,
|
||||||
|
FILE *fp /* input file descriptor */)
|
||||||
|
{
|
||||||
|
Desbuf inbuf; /* temp buffer for initialization vector */
|
||||||
|
int n; /* number of bytes actually read */
|
||||||
|
int c; /* used to test for EOF */
|
||||||
|
int inverse = 1; /* 0 to encrypt, 1 to decrypt */
|
||||||
|
|
||||||
|
if ((n = READ(BUFFER(msgbuf), 8, fp)) == 8) {
|
||||||
|
/*
|
||||||
|
* do the transformation
|
||||||
|
*/
|
||||||
|
MEMCPY(BUFFER(inbuf), BUFFER(msgbuf), 8);
|
||||||
|
DES_XFORM(UBUFFER(msgbuf));
|
||||||
|
for (c = 0; c < 8; c++)
|
||||||
|
UCHAR(msgbuf, c) ^= UCHAR(ivec, c);
|
||||||
|
MEMCPY(BUFFER(ivec), BUFFER(inbuf), 8);
|
||||||
|
/*
|
||||||
|
* if the last one, handle it specially
|
||||||
|
*/
|
||||||
|
if ((c = fgetc(fp)) == EOF) {
|
||||||
|
n = CHAR(msgbuf, 7);
|
||||||
|
if (n < 0 || n > 7) {
|
||||||
|
des_error("decryption failed (block corrupted)");
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
(void)ungetc(c, fp);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
if (n > 0)
|
||||||
|
des_error("decryption failed (incomplete block)");
|
||||||
|
else if (n < 0)
|
||||||
|
des_error("cannot read file");
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
#endif /* DES */
|
972
bin/ed/ed.1
Normal file
972
bin/ed/ed.1
Normal file
|
@ -0,0 +1,972 @@
|
||||||
|
.\" $NetBSD: ed.1,v 1.30 2010/05/14 02:09:58 joerg Exp $
|
||||||
|
.\" $OpenBSD: ed.1,v 1.42 2003/07/27 13:25:43 jmc Exp $
|
||||||
|
.\"
|
||||||
|
.\" 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.
|
||||||
|
.\"
|
||||||
|
.Dd January 23, 2002
|
||||||
|
.Dt ED 1
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm ed
|
||||||
|
.Nd text editor
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl
|
||||||
|
.Op Fl Esx
|
||||||
|
.Op Fl p Ar string
|
||||||
|
.Op Ar file
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
is a line-oriented text editor.
|
||||||
|
It is used to create, display, modify, and otherwise manipulate text files.
|
||||||
|
If invoked with a
|
||||||
|
.Ar file
|
||||||
|
argument, then a copy of
|
||||||
|
.Ar file
|
||||||
|
is read into the editor's buffer.
|
||||||
|
Changes are made to this copy and not directly to
|
||||||
|
.Ar file
|
||||||
|
itself.
|
||||||
|
Upon quitting
|
||||||
|
.Nm ,
|
||||||
|
any changes not explicitly saved with a
|
||||||
|
.Ic w
|
||||||
|
command are lost.
|
||||||
|
.Pp
|
||||||
|
Editing is done in two distinct modes:
|
||||||
|
.Em command
|
||||||
|
and
|
||||||
|
.Em input .
|
||||||
|
When first invoked,
|
||||||
|
.Nm
|
||||||
|
is in command mode.
|
||||||
|
In this mode, commands are read from the standard input and
|
||||||
|
executed to manipulate the contents of the editor buffer.
|
||||||
|
.Pp
|
||||||
|
A typical command might look like:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
,s/old/new/g
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
which replaces all occurrences of the string
|
||||||
|
.Pa old
|
||||||
|
with
|
||||||
|
.Pa new .
|
||||||
|
.Pp
|
||||||
|
When an input command, such as
|
||||||
|
.Ic a
|
||||||
|
(append),
|
||||||
|
.Ic i
|
||||||
|
(insert),
|
||||||
|
or
|
||||||
|
.Ic c
|
||||||
|
(change) is given,
|
||||||
|
.Nm
|
||||||
|
enters input mode.
|
||||||
|
This is the primary means of adding text to a file.
|
||||||
|
In this mode, no commands are available;
|
||||||
|
instead, the standard input is written directly to the editor buffer.
|
||||||
|
Lines consist of text up to and including a newline character.
|
||||||
|
Input mode is terminated by entering a single period
|
||||||
|
.Pq Ql \&.
|
||||||
|
on a line.
|
||||||
|
.Pp
|
||||||
|
All
|
||||||
|
.Nm
|
||||||
|
commands operate on whole lines or ranges of lines; e.g.,
|
||||||
|
the
|
||||||
|
.Ic d
|
||||||
|
command deletes lines; the
|
||||||
|
.Ic m
|
||||||
|
command moves lines, and so on.
|
||||||
|
It is possible to modify only a portion of a line by means of replacement,
|
||||||
|
as in the example above.
|
||||||
|
However, even here, the
|
||||||
|
.Ic s
|
||||||
|
command is applied to whole lines at a time.
|
||||||
|
.Pp
|
||||||
|
In general,
|
||||||
|
.Nm
|
||||||
|
commands consist of zero or more line addresses, followed by a single
|
||||||
|
character command and possibly additional parameters; i.e.,
|
||||||
|
commands have the structure:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
[address [,address]]command[parameters]
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
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.
|
||||||
|
.Pp
|
||||||
|
The options are as follows:
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl
|
||||||
|
Same as the
|
||||||
|
.Fl s
|
||||||
|
option (deprecated).
|
||||||
|
.It Fl E
|
||||||
|
Enables the use of extended regular expressions instead of the basic
|
||||||
|
regular expressions that are normally used.
|
||||||
|
.It Fl p Ar string
|
||||||
|
Specifies a command prompt.
|
||||||
|
This may be toggled on and off with the
|
||||||
|
.Ic P
|
||||||
|
command.
|
||||||
|
.It Fl s
|
||||||
|
Suppress diagnostics.
|
||||||
|
This should be used if
|
||||||
|
.Nm
|
||||||
|
standard input is from a script.
|
||||||
|
.It Fl x
|
||||||
|
Prompt for an encryption key to be used in subsequent reads and writes
|
||||||
|
(see the
|
||||||
|
.Ic x
|
||||||
|
command).
|
||||||
|
.It Ar file
|
||||||
|
Specifies the name of a file to read.
|
||||||
|
If
|
||||||
|
.Ar file
|
||||||
|
is prefixed with a
|
||||||
|
bang
|
||||||
|
.Pq Ql \&! ,
|
||||||
|
then it is interpreted as a shell command.
|
||||||
|
In this case, what is read is the standard output of
|
||||||
|
.Ar file
|
||||||
|
executed via
|
||||||
|
.Xr sh 1 .
|
||||||
|
To read a file whose name begins with a bang, prefix the
|
||||||
|
name with a backslash
|
||||||
|
.Pq Ql \e .
|
||||||
|
The default filename is set to
|
||||||
|
.Ar file
|
||||||
|
only if it is not prefixed with a bang.
|
||||||
|
.El
|
||||||
|
.Ss LINE ADDRESSING
|
||||||
|
An address represents the number of a line in the buffer.
|
||||||
|
.Nm
|
||||||
|
maintains a
|
||||||
|
.Em current address
|
||||||
|
which is typically supplied to commands as the default address
|
||||||
|
when none is specified.
|
||||||
|
When a file is first read, the current address is set to the last line
|
||||||
|
of the file.
|
||||||
|
In general, the current address is set to the last line affected by a command.
|
||||||
|
.Pp
|
||||||
|
A line address is
|
||||||
|
constructed from one of the bases in the list below, optionally followed
|
||||||
|
by a numeric offset.
|
||||||
|
The offset may include any combination of digits, operators (i.e.,
|
||||||
|
.Sq + ,
|
||||||
|
.Sq - ,
|
||||||
|
and
|
||||||
|
.Sq ^ ) ,
|
||||||
|
and whitespace.
|
||||||
|
Addresses are read from left to right, and their values are computed
|
||||||
|
relative to the current address.
|
||||||
|
.Pp
|
||||||
|
One exception to the rule that addresses represent line numbers is the
|
||||||
|
address
|
||||||
|
.Em 0
|
||||||
|
(zero).
|
||||||
|
This means
|
||||||
|
.Dq before the first line ,
|
||||||
|
and is legal wherever it makes sense.
|
||||||
|
.Pp
|
||||||
|
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 second.
|
||||||
|
If only one address is given in a range,
|
||||||
|
then the second address is set to the given address.
|
||||||
|
If an
|
||||||
|
.Em n Ns No -tuple
|
||||||
|
of addresses is given where
|
||||||
|
.Em n \*[Gt] 2 ,
|
||||||
|
then the corresponding range is determined by the last two addresses in the
|
||||||
|
.Em n Ns No -tuple.
|
||||||
|
If only one address is expected, then the last address is used.
|
||||||
|
.Pp
|
||||||
|
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.
|
||||||
|
.Pp
|
||||||
|
The following address symbols are recognized:
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Em \&.
|
||||||
|
The current line (address) in the buffer.
|
||||||
|
.It Em $
|
||||||
|
The last line in the buffer.
|
||||||
|
.It Em n
|
||||||
|
The
|
||||||
|
.Em n Ns No th
|
||||||
|
line in the buffer where
|
||||||
|
.Em n
|
||||||
|
is a number in the range
|
||||||
|
.Em [0,$] .
|
||||||
|
.It Em - No or Em ^
|
||||||
|
The previous line.
|
||||||
|
This is equivalent to
|
||||||
|
.Em -1
|
||||||
|
and may be repeated with cumulative effect.
|
||||||
|
.It Em -n No or Em ^n
|
||||||
|
The
|
||||||
|
.Em n Ns No th
|
||||||
|
previous line, where
|
||||||
|
.Em n
|
||||||
|
is a non-negative number.
|
||||||
|
.It Em +
|
||||||
|
The next line.
|
||||||
|
This is equivalent to
|
||||||
|
.Em +1
|
||||||
|
and may be repeated with cumulative effect.
|
||||||
|
.It Em +n
|
||||||
|
The
|
||||||
|
.Em n Ns No th
|
||||||
|
next line, where
|
||||||
|
.Em n
|
||||||
|
is a non-negative number.
|
||||||
|
.It Em whitespace Em n
|
||||||
|
.Em whitespace
|
||||||
|
followed by a number
|
||||||
|
.Em n
|
||||||
|
is interpreted as
|
||||||
|
.Sq Em +n .
|
||||||
|
.It Em \&, No or Em %
|
||||||
|
The first through last lines in the buffer.
|
||||||
|
This is equivalent to the address range
|
||||||
|
.Em 1,$ .
|
||||||
|
.It Em \&;
|
||||||
|
The current through last lines in the buffer.
|
||||||
|
This is equivalent to the address range
|
||||||
|
.Em .,$ .
|
||||||
|
.It Em / Ns Ar re Ns Em /
|
||||||
|
The next line containing the regular expression
|
||||||
|
.Ar re .
|
||||||
|
The search wraps to the beginning of the buffer and continues down to the
|
||||||
|
current line, if necessary.
|
||||||
|
.Em //
|
||||||
|
repeats the last search.
|
||||||
|
.It Em \&? Ns Ar re Ns Em \&?
|
||||||
|
The previous line containing the regular expression
|
||||||
|
.Ar re .
|
||||||
|
The search wraps to the end of the buffer and continues up to the
|
||||||
|
current line, if necessary.
|
||||||
|
.Em ??
|
||||||
|
repeats the last search.
|
||||||
|
.It Em \&\' Ns Ar lc
|
||||||
|
The line previously marked by a
|
||||||
|
.Ic k
|
||||||
|
(mark) command, where
|
||||||
|
.Ar lc
|
||||||
|
is a lower case letter.
|
||||||
|
.El
|
||||||
|
.Ss REGULAR EXPRESSIONS
|
||||||
|
Regular expressions are patterns used in selecting text.
|
||||||
|
For example, the
|
||||||
|
.Nm
|
||||||
|
command
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
g/string/
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
prints all lines containing
|
||||||
|
.Em string .
|
||||||
|
Regular expressions are also used by the
|
||||||
|
.Ic s
|
||||||
|
command for selecting old text to be replaced with new.
|
||||||
|
.Pp
|
||||||
|
In addition to specifying string literals, regular expressions can
|
||||||
|
represent classes of strings.
|
||||||
|
Strings thus represented are said to be matched by the
|
||||||
|
corresponding regular expression.
|
||||||
|
If it is possible for a regular expression to match several strings in
|
||||||
|
a line, then the leftmost longest match is the one selected.
|
||||||
|
.Pp
|
||||||
|
The following symbols are used in constructing regular expressions:
|
||||||
|
.Bl -tag -width Dsasdfsd
|
||||||
|
.It Em c
|
||||||
|
Any character
|
||||||
|
.Em c
|
||||||
|
not listed below, including
|
||||||
|
.Sq { ,
|
||||||
|
.Sq } ,
|
||||||
|
.Sq \&( ,
|
||||||
|
.Sq \&) ,
|
||||||
|
.Sq \*[Lt] ,
|
||||||
|
and
|
||||||
|
.Sq \*[Gt]
|
||||||
|
matches itself.
|
||||||
|
.It Em \ec
|
||||||
|
Any backslash-escaped character
|
||||||
|
.Em c ,
|
||||||
|
except for
|
||||||
|
.Sq { ,
|
||||||
|
.Sq } ,
|
||||||
|
.Sq \&( ,
|
||||||
|
.Sq \&) ,
|
||||||
|
.Sq \*[Lt] ,
|
||||||
|
and
|
||||||
|
.Sq \*[Gt]
|
||||||
|
matches itself.
|
||||||
|
.It Em \&.
|
||||||
|
Matches any single character.
|
||||||
|
.It Em [char-class]
|
||||||
|
Matches any single character in the character class
|
||||||
|
.Em char-class .
|
||||||
|
See
|
||||||
|
.Sx CHARACTER CLASSES
|
||||||
|
below for further information.
|
||||||
|
.It Em [^char-class]
|
||||||
|
Matches any single character, other than newline, not in the
|
||||||
|
character class
|
||||||
|
.Em char-class .
|
||||||
|
.It Em ^
|
||||||
|
If
|
||||||
|
.Em ^
|
||||||
|
is the first character of a regular expression, then it
|
||||||
|
anchors the regular expression to the beginning of a line.
|
||||||
|
Otherwise, it matches itself.
|
||||||
|
.It Em $
|
||||||
|
If
|
||||||
|
.Em $
|
||||||
|
is the last character of a regular expression,
|
||||||
|
it anchors the regular expression to the end of a line.
|
||||||
|
Otherwise, it matches itself.
|
||||||
|
.It Em \e\*[Lt]
|
||||||
|
Anchors the single character regular expression or subexpression
|
||||||
|
immediately following it to the beginning of a word.
|
||||||
|
(This may not be available.)
|
||||||
|
.It Em \e\*[Gt]
|
||||||
|
Anchors the single character regular expression or subexpression
|
||||||
|
immediately following it to the end of a word.
|
||||||
|
(This may not be available.)
|
||||||
|
.It Em \e( Ns Ar re Ns Em \e)
|
||||||
|
Defines a subexpression
|
||||||
|
.Ar re .
|
||||||
|
Subexpressions may be nested.
|
||||||
|
A subsequent backreference of the form
|
||||||
|
.Em \en ,
|
||||||
|
where
|
||||||
|
.Em n
|
||||||
|
is a number in the range [1,9], expands to the text matched by the
|
||||||
|
.Em n Ns No th
|
||||||
|
subexpression.
|
||||||
|
For example, the regular expression
|
||||||
|
.Em \e(.*\e)\e1
|
||||||
|
matches any string consisting of identical adjacent substrings.
|
||||||
|
Subexpressions are ordered relative to their left delimiter.
|
||||||
|
.It Em *
|
||||||
|
Matches the single character regular expression or subexpression
|
||||||
|
immediately preceding it zero or more times.
|
||||||
|
If
|
||||||
|
.Em *
|
||||||
|
is the first character of a regular expression or subexpression,
|
||||||
|
then it matches itself.
|
||||||
|
The
|
||||||
|
.Em *
|
||||||
|
operator sometimes yields unexpected results.
|
||||||
|
For example, the regular expression
|
||||||
|
.Em b*
|
||||||
|
matches the beginning of the string
|
||||||
|
.Em abbb
|
||||||
|
(as opposed to the substring
|
||||||
|
.Em bbb ) ,
|
||||||
|
since a null match is the only leftmost match.
|
||||||
|
.Sm off
|
||||||
|
.It Em \e{ No n,m Em \e}\ \e{ No n, Em \e}\ \& Em \e{ No n Em \e}
|
||||||
|
.Sm on
|
||||||
|
Matches the single character regular expression or subexpression
|
||||||
|
immediately preceding it at least
|
||||||
|
.Em n
|
||||||
|
and at most
|
||||||
|
.Em m
|
||||||
|
times.
|
||||||
|
If
|
||||||
|
.Em m
|
||||||
|
is omitted, then it matches at least
|
||||||
|
.Em n
|
||||||
|
times.
|
||||||
|
If the comma is also omitted, then it matches exactly
|
||||||
|
.Em n
|
||||||
|
times.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
Additional regular expression operators may be defined depending on the
|
||||||
|
particular
|
||||||
|
.Xr regex 3
|
||||||
|
implementation.
|
||||||
|
.Ss CHARACTER CLASSES
|
||||||
|
A character class specifies a set of characters. It is written within
|
||||||
|
square brackets
|
||||||
|
.Pq []
|
||||||
|
and in its most basic form contains just the characters in the set.
|
||||||
|
.Pp
|
||||||
|
To include a
|
||||||
|
.Sq \&]
|
||||||
|
in a character class, it must be the first character.
|
||||||
|
A range of characters may be specified by separating the end characters
|
||||||
|
of the range with a
|
||||||
|
.Sq \&- ,
|
||||||
|
e.g.,
|
||||||
|
.Sq a-z
|
||||||
|
specifies the lower case characters.
|
||||||
|
.Pp
|
||||||
|
The following literals can also be used within character classes as
|
||||||
|
shorthand for particular sets of characters:
|
||||||
|
.Bl -tag -offset indent -compact -width [:blahblah:]
|
||||||
|
.It [:alnum:]
|
||||||
|
Alphanumeric characters.
|
||||||
|
.It [:cntrl:]
|
||||||
|
Control characters.
|
||||||
|
.It [:lower:]
|
||||||
|
Lowercase alphabetic characters.
|
||||||
|
.It [:space:]
|
||||||
|
Whitespace (space, tab, newline, form feed, etc.)
|
||||||
|
.It [:alpha:]
|
||||||
|
Alphabetic characters.
|
||||||
|
.It [:digit:]
|
||||||
|
Numeric characters (digits).
|
||||||
|
.It [:print:]
|
||||||
|
Printable characters.
|
||||||
|
.It [:upper:]
|
||||||
|
Uppercase alphabetic characters.
|
||||||
|
.It [:blank:]
|
||||||
|
Blank characters (space and tab).
|
||||||
|
.It [:graph:]
|
||||||
|
Graphical characters (printing nonblank characters).
|
||||||
|
.It [:punct:]
|
||||||
|
Punctuation characters.
|
||||||
|
.It [:xdigit:]
|
||||||
|
Hexadecimal digits.
|
||||||
|
.El
|
||||||
|
If
|
||||||
|
.Sq \&-
|
||||||
|
appears as the first or last character of a character class, then
|
||||||
|
it matches itself.
|
||||||
|
All other characters in a character class match themselves.
|
||||||
|
.Pp
|
||||||
|
Patterns in
|
||||||
|
a character class
|
||||||
|
of the form
|
||||||
|
.Em [.col-elm.]
|
||||||
|
or
|
||||||
|
.Em [=col-elm=]
|
||||||
|
where
|
||||||
|
.Em col-elm
|
||||||
|
is a
|
||||||
|
.Em collating element
|
||||||
|
are interpreted according to
|
||||||
|
.Xr locale 5
|
||||||
|
(not currently supported).
|
||||||
|
See
|
||||||
|
.Xr regex 3
|
||||||
|
for an explanation of these constructs.
|
||||||
|
.Ss COMMANDS
|
||||||
|
All
|
||||||
|
.Nm
|
||||||
|
commands are single characters, though some require additional parameters.
|
||||||
|
If a command's parameters extend over several lines, then
|
||||||
|
each line except for the last must be terminated with a backslash
|
||||||
|
.Pq Ql \e .
|
||||||
|
.Pp
|
||||||
|
In general, at most one command is allowed per line.
|
||||||
|
However, most commands accept a print suffix, which is any of
|
||||||
|
.Ic p
|
||||||
|
(print),
|
||||||
|
.Ic l
|
||||||
|
(list),
|
||||||
|
or
|
||||||
|
.Ic n
|
||||||
|
(enumerate), to print the last line affected by the command.
|
||||||
|
.Pp
|
||||||
|
An interrupt (typically ^C) has the effect of aborting the current command
|
||||||
|
and returning the editor to command mode.
|
||||||
|
.Pp
|
||||||
|
.Nm
|
||||||
|
recognizes the following commands.
|
||||||
|
The commands are shown together with
|
||||||
|
the default address or address range supplied if none is
|
||||||
|
specified (in parentheses), and other possible arguments on the right.
|
||||||
|
.Bl -tag -width Dxxs
|
||||||
|
.It (.) Ns Ic a
|
||||||
|
Appends text to the buffer after the addressed line.
|
||||||
|
Text is entered in input mode.
|
||||||
|
The current address is set to last line entered.
|
||||||
|
.It (.,.) Ns Ic c
|
||||||
|
Changes lines in the buffer.
|
||||||
|
The addressed lines are deleted from the buffer,
|
||||||
|
and text is appended in their place.
|
||||||
|
Text is entered in input mode.
|
||||||
|
The current address is set to last line entered.
|
||||||
|
.It (.,.) Ns Ic d
|
||||||
|
Deletes the addressed lines from the buffer.
|
||||||
|
If there is a line after the deleted range, then the current address is set
|
||||||
|
to this line.
|
||||||
|
Otherwise the current address is set to the line before the deleted range.
|
||||||
|
.It Ic e Ar file
|
||||||
|
Edits
|
||||||
|
.Ar file ,
|
||||||
|
and sets the default filename.
|
||||||
|
If
|
||||||
|
.Ar file
|
||||||
|
is not specified, then the default filename is used.
|
||||||
|
Any lines in the buffer are deleted before the new file is read.
|
||||||
|
The current address is set to the last line read.
|
||||||
|
.It Ic e Ar !command
|
||||||
|
Edits the standard output of
|
||||||
|
.Ar command ,
|
||||||
|
(see
|
||||||
|
.Ic \&! Ar command
|
||||||
|
below).
|
||||||
|
The default filename is unchanged.
|
||||||
|
Any lines in the buffer are deleted before the output of
|
||||||
|
.Em command
|
||||||
|
is read.
|
||||||
|
The current address is set to the last line read.
|
||||||
|
.It Ic E Ar file
|
||||||
|
Edits
|
||||||
|
.Ar file
|
||||||
|
unconditionally.
|
||||||
|
This is similar to the
|
||||||
|
.Ic e
|
||||||
|
command, except that unwritten changes are discarded without warning.
|
||||||
|
The current address is set to the last line read.
|
||||||
|
.It Ic f Ar file
|
||||||
|
Sets the default filename to
|
||||||
|
.Ar file .
|
||||||
|
If
|
||||||
|
.Ar file
|
||||||
|
is not specified, then the default unescaped filename is printed.
|
||||||
|
.It (1,$) Ns Ic g Ns Ar /re/command-list
|
||||||
|
Applies
|
||||||
|
.Ar command-list
|
||||||
|
to each of the addressed lines matching a regular expression
|
||||||
|
.Ar re .
|
||||||
|
The current address is set to the line currently matched before
|
||||||
|
.Ar command-list
|
||||||
|
is executed.
|
||||||
|
At the end of the
|
||||||
|
.Ic g
|
||||||
|
command, the current address is set to the last line affected by
|
||||||
|
.Ar command-list .
|
||||||
|
.Pp
|
||||||
|
Each command in
|
||||||
|
.Ar command-list
|
||||||
|
must be on a separate line,
|
||||||
|
and every line except for the last must be terminated by a backslash
|
||||||
|
.Pq Sq \e .
|
||||||
|
Any commands are allowed, except for
|
||||||
|
.Ic g ,
|
||||||
|
.Ic G ,
|
||||||
|
.Ic v ,
|
||||||
|
and
|
||||||
|
.Ic V .
|
||||||
|
A newline alone in
|
||||||
|
.Ar command-list
|
||||||
|
is equivalent to a
|
||||||
|
.Ic p
|
||||||
|
command.
|
||||||
|
.It (1,$) Ns Ic G Ns Ar /re/
|
||||||
|
Interactively edits the addressed lines matching a regular expression
|
||||||
|
.Ar re .
|
||||||
|
For each matching line, the line is printed, the current address is set,
|
||||||
|
and the user is prompted to enter a
|
||||||
|
.Ar command-list .
|
||||||
|
At the end of the
|
||||||
|
.Ic G
|
||||||
|
command, the current address is set to the last line affected by (the last)
|
||||||
|
.Ar command-list .
|
||||||
|
.Pp
|
||||||
|
The format of
|
||||||
|
.Ar command-list
|
||||||
|
is the same as that of the
|
||||||
|
.Ic g
|
||||||
|
command.
|
||||||
|
A newline alone acts as a null command list.
|
||||||
|
A single
|
||||||
|
.Sq \*[Am]
|
||||||
|
repeats the last non-null command list.
|
||||||
|
.It Ic H
|
||||||
|
Toggles the printing of error explanations.
|
||||||
|
By default, explanations are not printed.
|
||||||
|
It is recommended that
|
||||||
|
.Nm
|
||||||
|
scripts begin with this command to aid in debugging.
|
||||||
|
.It Ic h
|
||||||
|
Prints an explanation of the last error.
|
||||||
|
.It (.) Ns Ic i
|
||||||
|
Inserts text in the buffer before the current line.
|
||||||
|
Text is entered in input mode.
|
||||||
|
The current address is set to the last line entered.
|
||||||
|
.It (.,.+1) Ns Ic j
|
||||||
|
Joins the addressed lines.
|
||||||
|
The addressed lines are deleted from the buffer and replaced by a single
|
||||||
|
line containing their joined text.
|
||||||
|
The current address is set to the resultant line.
|
||||||
|
.It (.) Ns Ic k Ns Ar lc
|
||||||
|
Marks a line with a lower case letter
|
||||||
|
.Ar lc .
|
||||||
|
The line can then be addressed as
|
||||||
|
.Ar \&'lc
|
||||||
|
(i.e., a single quote followed by
|
||||||
|
.Ar lc )
|
||||||
|
in subsequent commands.
|
||||||
|
The mark is not cleared until the line is deleted or otherwise modified.
|
||||||
|
.It (.,.) Ns Ic l
|
||||||
|
Prints the addressed lines unambiguously.
|
||||||
|
If a single line fills more than one screen (as might be the case
|
||||||
|
when viewing a binary file, for instance), a
|
||||||
|
.Dq --More--
|
||||||
|
prompt is printed on the last line.
|
||||||
|
.Nm
|
||||||
|
waits until the RETURN key is pressed before displaying the next screen.
|
||||||
|
The current address is set to the last line printed.
|
||||||
|
.It (.,.) Ns Ic m Ns No (.)
|
||||||
|
Moves lines in the buffer.
|
||||||
|
The addressed lines are moved to after the
|
||||||
|
right-hand destination address, which may be the address
|
||||||
|
.Em 0
|
||||||
|
(zero).
|
||||||
|
The current address is set to the last line moved.
|
||||||
|
.It (.,.) Ns Ic n
|
||||||
|
Prints the addressed lines along with their line numbers.
|
||||||
|
The current address is set to the last line printed.
|
||||||
|
.It (.,.) Ns Ic p
|
||||||
|
Prints the addressed lines.
|
||||||
|
The current address is set to the last line printed.
|
||||||
|
.It Ic P
|
||||||
|
Toggles the command prompt on and off.
|
||||||
|
Unless a prompt was specified with the command-line option
|
||||||
|
.Fl p Ar string ,
|
||||||
|
the command prompt is by default turned off.
|
||||||
|
.It Ic q
|
||||||
|
Quits
|
||||||
|
.Nm .
|
||||||
|
.It Ic Q
|
||||||
|
Quits
|
||||||
|
.Nm
|
||||||
|
unconditionally.
|
||||||
|
This is similar to the
|
||||||
|
.Ic q
|
||||||
|
command, except that unwritten changes are discarded without warning.
|
||||||
|
.It ($) Ns Ic r Ar file
|
||||||
|
Reads
|
||||||
|
.Ar file
|
||||||
|
to after the addressed line.
|
||||||
|
If
|
||||||
|
.Ar file
|
||||||
|
is not specified, then the default filename is used.
|
||||||
|
If there was no default filename prior to the command,
|
||||||
|
then the default filename is set to
|
||||||
|
.Ar file .
|
||||||
|
Otherwise, the default filename is unchanged.
|
||||||
|
The current address is set to the last line read.
|
||||||
|
.It ($) Ns Ic r Ar !command
|
||||||
|
Reads to after the addressed line the standard output of
|
||||||
|
.Ar command ,
|
||||||
|
(see the
|
||||||
|
.Ic \&!
|
||||||
|
command below).
|
||||||
|
The default filename is unchanged.
|
||||||
|
The current address is set to the last line read.
|
||||||
|
.Sm off
|
||||||
|
.It (.,.) Ic s Ar /re/replacement/ , \ (.,.) \
|
||||||
|
Ic s Ar /re/replacement/ Em g , Ar \ (.,.) \
|
||||||
|
Ic s Ar /re/replacement/ Em n
|
||||||
|
.Sm on
|
||||||
|
Replaces text in the addressed lines matching a regular expression
|
||||||
|
.Ar re
|
||||||
|
with
|
||||||
|
.Ar replacement .
|
||||||
|
By default, only the first match in each line is replaced.
|
||||||
|
If the
|
||||||
|
.Em g
|
||||||
|
(global) suffix is given, then every match to be replaced.
|
||||||
|
The
|
||||||
|
.Em n
|
||||||
|
suffix, where
|
||||||
|
.Em n
|
||||||
|
is a positive number, causes only the
|
||||||
|
.Em n Ns No th
|
||||||
|
match to be replaced.
|
||||||
|
It is an error if no substitutions are performed on any of the addressed
|
||||||
|
lines.
|
||||||
|
The current address is set the last line affected.
|
||||||
|
.Pp
|
||||||
|
.Ar re
|
||||||
|
and
|
||||||
|
.Ar replacement
|
||||||
|
may be delimited by any character other than space and newline
|
||||||
|
(see the
|
||||||
|
.Ic 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
|
||||||
|
.Em p
|
||||||
|
were specified.
|
||||||
|
.Pp
|
||||||
|
An unescaped
|
||||||
|
.Ql \*[Am]
|
||||||
|
in
|
||||||
|
.Ar replacement
|
||||||
|
is replaced by the currently matched text.
|
||||||
|
The character sequence
|
||||||
|
.Em \em ,
|
||||||
|
where
|
||||||
|
.Em m
|
||||||
|
is a number in the range [1,9], is replaced by the
|
||||||
|
.Em m Ns No th
|
||||||
|
backreference expression of the matched text.
|
||||||
|
If
|
||||||
|
.Ar replacement
|
||||||
|
consists of a single
|
||||||
|
.Ql % ,
|
||||||
|
then
|
||||||
|
.Ar replacement
|
||||||
|
from the last substitution is used.
|
||||||
|
Newlines may be embedded in
|
||||||
|
.Ar replacement
|
||||||
|
if they are escaped with a backslash
|
||||||
|
.Pq Ql \e .
|
||||||
|
.It (.,.) Ns Ic s
|
||||||
|
Repeats the last substitution.
|
||||||
|
This form of the
|
||||||
|
.Ic s
|
||||||
|
command accepts a count suffix
|
||||||
|
.Em n ,
|
||||||
|
or any combination of the characters
|
||||||
|
.Em r ,
|
||||||
|
.Em g ,
|
||||||
|
and
|
||||||
|
.Em p .
|
||||||
|
If a count suffix
|
||||||
|
.Em n
|
||||||
|
is given, then only the
|
||||||
|
.Em n Ns No th
|
||||||
|
match is replaced.
|
||||||
|
The
|
||||||
|
.Em r
|
||||||
|
suffix causes
|
||||||
|
the regular expression of the last search to be used instead of
|
||||||
|
that of the last substitution.
|
||||||
|
The
|
||||||
|
.Em g
|
||||||
|
suffix toggles the global suffix of the last substitution.
|
||||||
|
The
|
||||||
|
.Em p
|
||||||
|
suffix toggles the print suffix of the last substitution.
|
||||||
|
The current address is set to the last line affected.
|
||||||
|
.It (.,.) Ns Ic t Ns No (.)
|
||||||
|
Copies (i.e., transfers) the addressed lines to after the right-hand
|
||||||
|
destination address, which may be the address
|
||||||
|
.Em 0
|
||||||
|
(zero).
|
||||||
|
The current address is set to the last line copied.
|
||||||
|
.It Ic u
|
||||||
|
Undoes the last command and restores the current address
|
||||||
|
to what it was before the command.
|
||||||
|
The global commands
|
||||||
|
.Ic g ,
|
||||||
|
.Ic G ,
|
||||||
|
.Ic v ,
|
||||||
|
and
|
||||||
|
.Ic V
|
||||||
|
are treated as a single command by undo.
|
||||||
|
.Ic u
|
||||||
|
is its own inverse.
|
||||||
|
.It (1,$) Ns Ic v Ns Ar /re/command-list
|
||||||
|
Applies
|
||||||
|
.Ar command-list
|
||||||
|
to each of the addressed lines not matching a regular expression
|
||||||
|
.Ar re .
|
||||||
|
This is similar to the
|
||||||
|
.Ic g
|
||||||
|
command.
|
||||||
|
.It (1,$) Ns Ic V Ns Ar /re/
|
||||||
|
Interactively edits the addressed lines not matching a regular expression
|
||||||
|
.Ar re .
|
||||||
|
This is similar to the
|
||||||
|
.Ic G
|
||||||
|
command.
|
||||||
|
.It (1,$) Ns Ic w Ar file
|
||||||
|
Writes the addressed lines to
|
||||||
|
.Ar file .
|
||||||
|
Any previous contents of
|
||||||
|
.Ar file
|
||||||
|
are lost without warning.
|
||||||
|
If there is no default filename, then the default filename is set to
|
||||||
|
.Ar file ,
|
||||||
|
otherwise it is unchanged.
|
||||||
|
If no filename is specified, then the default filename is used.
|
||||||
|
The current address is unchanged.
|
||||||
|
.It (1,$) Ns Ic wq Ar file
|
||||||
|
Writes the addressed lines to
|
||||||
|
.Ar file ,
|
||||||
|
and then executes a
|
||||||
|
.Ic q
|
||||||
|
command.
|
||||||
|
.It (1,$) Ns Ic w Ar !command
|
||||||
|
Writes the addressed lines to the standard input of
|
||||||
|
.Ar command ,
|
||||||
|
(see the
|
||||||
|
.Ic \&!
|
||||||
|
command below).
|
||||||
|
The default filename and current address are unchanged.
|
||||||
|
.It (1,$) Ns Ic W Ar file
|
||||||
|
Appends the addressed lines to the end of
|
||||||
|
.Ar file .
|
||||||
|
This is similar to the
|
||||||
|
.Ic w
|
||||||
|
command, except that the previous contents of file are not clobbered.
|
||||||
|
The current address is unchanged.
|
||||||
|
.It Ic x
|
||||||
|
Prompts for an encryption key which is used in subsequent reads and writes.
|
||||||
|
If a newline alone is entered as the key, then encryption is turned off.
|
||||||
|
Otherwise, echoing is disabled while a key is read.
|
||||||
|
Encryption/decryption is done using the
|
||||||
|
.Xr bdes 1
|
||||||
|
algorithm.
|
||||||
|
.It (.+1) Ns Ic z Ns Ar n
|
||||||
|
Scrolls
|
||||||
|
.Ar n
|
||||||
|
lines at a time starting at addressed line.
|
||||||
|
If
|
||||||
|
.Ar n
|
||||||
|
is not specified, then the current window size is used.
|
||||||
|
The current address is set to the last line printed.
|
||||||
|
.It ($) Ns Ic =
|
||||||
|
Prints the line number of the addressed line.
|
||||||
|
.It (.+1) Ns Ic newline
|
||||||
|
Prints the addressed line, and sets the current address to that line.
|
||||||
|
.It Ic \&! Ns Ar command
|
||||||
|
Executes
|
||||||
|
.Ar command
|
||||||
|
via
|
||||||
|
.Xr sh 1 .
|
||||||
|
If the first character of
|
||||||
|
.Ar command
|
||||||
|
is
|
||||||
|
.Ic \&! ,
|
||||||
|
then it is replaced by text of the previous
|
||||||
|
.Ic !command .
|
||||||
|
.Nm
|
||||||
|
does not process
|
||||||
|
.Ar command
|
||||||
|
for
|
||||||
|
.Sq \e
|
||||||
|
(backslash) escapes.
|
||||||
|
However, an unescaped
|
||||||
|
.Sq %
|
||||||
|
is replaced by the default filename.
|
||||||
|
When the shell returns from execution, a
|
||||||
|
.Sq \&!
|
||||||
|
is printed to the standard output.
|
||||||
|
The current line is unchanged.
|
||||||
|
.El
|
||||||
|
.Sh LIMITATIONS
|
||||||
|
.Nm
|
||||||
|
processes
|
||||||
|
.Em file
|
||||||
|
arguments for backslash escapes, i.e., in a filename,
|
||||||
|
any characters preceded by a backslash
|
||||||
|
.Pq Ql \e
|
||||||
|
are interpreted literally.
|
||||||
|
.Pp
|
||||||
|
If a text (non-binary) file is not terminated by a newline character,
|
||||||
|
then
|
||||||
|
.Nm
|
||||||
|
appends one on reading/writing it.
|
||||||
|
In the case of a binary file,
|
||||||
|
.Nm
|
||||||
|
does not append a newline on reading/writing.
|
||||||
|
.Sh ENVIRONMENT
|
||||||
|
.Bl -tag -width iTMPDIR
|
||||||
|
.It Ev TMPDIR
|
||||||
|
The location used to store temporary files.
|
||||||
|
.El
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width /tmp/ed.* -compact
|
||||||
|
.It Pa /tmp/ed.*
|
||||||
|
buffer file
|
||||||
|
.It Pa ed.hup
|
||||||
|
where
|
||||||
|
.Nm
|
||||||
|
attempts to write the buffer if the terminal hangs up
|
||||||
|
.El
|
||||||
|
.Sh DIAGNOSTICS
|
||||||
|
When an error occurs,
|
||||||
|
.Nm
|
||||||
|
prints a
|
||||||
|
.Dq \&?
|
||||||
|
and either returns to command mode or exits if its input is from a script.
|
||||||
|
An explanation of the last error can be printed with the
|
||||||
|
.Ic h
|
||||||
|
(help) command.
|
||||||
|
.Pp
|
||||||
|
Since the
|
||||||
|
.Ic g
|
||||||
|
(global) command masks any errors from failed searches and substitutions,
|
||||||
|
it can be used to perform conditional operations in scripts; e.g.,
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
g/old/s//new/
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
replaces any occurrences of
|
||||||
|
.Em old
|
||||||
|
with
|
||||||
|
.Em new .
|
||||||
|
.Pp
|
||||||
|
If the
|
||||||
|
.Ic u
|
||||||
|
(undo) command occurs in a global command list, then
|
||||||
|
the command list is executed only once.
|
||||||
|
.Pp
|
||||||
|
If diagnostics are not disabled, attempting to quit
|
||||||
|
.Nm
|
||||||
|
or edit another file before writing a modified buffer results in an error.
|
||||||
|
If the command is entered a second time, it succeeds,
|
||||||
|
but any changes to the buffer are lost.
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr bdes 1 ,
|
||||||
|
.Xr sed 1 ,
|
||||||
|
.Xr sh 1 ,
|
||||||
|
.Xr vi 1 ,
|
||||||
|
.Xr regex 3
|
||||||
|
.Pp
|
||||||
|
USD:09-10
|
||||||
|
.Rs
|
||||||
|
.%A B. W. Kernighan
|
||||||
|
.%A P. J. Plauger
|
||||||
|
.%B Software Tools in Pascal
|
||||||
|
.%I Addison-Wesley
|
||||||
|
.%D 1981
|
||||||
|
.Re
|
||||||
|
.Sh HISTORY
|
||||||
|
An
|
||||||
|
.Nm
|
||||||
|
command appeared in
|
||||||
|
.At v1 .
|
293
bin/ed/ed.h
Normal file
293
bin/ed/ed.h
Normal file
|
@ -0,0 +1,293 @@
|
||||||
|
/* $NetBSD: ed.h,v 1.35 2011/08/29 14:51:18 joerg Exp $ */
|
||||||
|
|
||||||
|
/* ed.h: type and constant definitions for the ed editor. */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1993 Andrew Moore
|
||||||
|
* 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 REGENTS 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
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @(#)ed.h,v 1.5 1994/02/01 00:34:39 alm Exp
|
||||||
|
*/
|
||||||
|
#include <sys/types.h>
|
||||||
|
#if defined(BSD) && BSD >= 199103 || defined(__386BSD__)
|
||||||
|
# include <sys/param.h> /* for MAXPATHLEN */
|
||||||
|
#endif
|
||||||
|
#include <errno.h>
|
||||||
|
#if defined(sun) || defined(__NetBSD__) || defined(__APPLE__) || \
|
||||||
|
defined(__minix)
|
||||||
|
# include <limits.h>
|
||||||
|
#endif
|
||||||
|
#include <regex.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define ERR (-2)
|
||||||
|
#define EMOD (-3)
|
||||||
|
#define FATAL (-4)
|
||||||
|
|
||||||
|
#ifndef MAXPATHLEN
|
||||||
|
# define MAXPATHLEN 255 /* _POSIX_PATH_MAX */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MINBUFSZ 512 /* minimum buffer size - must be > 0 */
|
||||||
|
#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 *q_forw;
|
||||||
|
struct line *q_back;
|
||||||
|
off_t seek; /* address of line in scratch buffer */
|
||||||
|
int len; /* length of line */
|
||||||
|
} line_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct undo {
|
||||||
|
|
||||||
|
/* type of undo nodes */
|
||||||
|
#define UADD 0
|
||||||
|
#define UDEL 1
|
||||||
|
#define UMOV 2
|
||||||
|
#define VMOV 3
|
||||||
|
|
||||||
|
int type; /* command type */
|
||||||
|
line_t *h; /* head of list */
|
||||||
|
line_t *t; /* tail of list */
|
||||||
|
} undo_t;
|
||||||
|
|
||||||
|
#ifndef max
|
||||||
|
# define max(a,b) ((a) > (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
#ifndef min
|
||||||
|
# define min(a,b) ((a) < (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define INC_MOD(l, k) ((l) + 1 > (k) ? 0 : (l) + 1)
|
||||||
|
#define DEC_MOD(l, k) ((l) - 1 < 0 ? (k) : (l) - 1)
|
||||||
|
|
||||||
|
/* SPL1: disable some interrupts (requires reliable signals) */
|
||||||
|
#define SPL1() mutex++
|
||||||
|
|
||||||
|
/* SPL0: enable all interrupts; check sigflags (requires reliable signals) */
|
||||||
|
#define SPL0() \
|
||||||
|
if (--mutex == 0) { \
|
||||||
|
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) { \
|
||||||
|
errno = 0 ; \
|
||||||
|
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)
|
||||||
|
/* 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(); \
|
||||||
|
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(); \
|
||||||
|
return err; \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
|
if ((ts = (char *) malloc(ti += max((i), MINBUFSZ))) == NULL) { \
|
||||||
|
fprintf(stderr, "%s\n", strerror(errno)); \
|
||||||
|
sprintf(errmsg, "out of memory"); \
|
||||||
|
SPL0(); \
|
||||||
|
return err; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
(n) = ti; \
|
||||||
|
(b) = ts; \
|
||||||
|
SPL0(); \
|
||||||
|
}
|
||||||
|
#else /* NO_REALLOC_NULL */
|
||||||
|
/* 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(); \
|
||||||
|
if ((ts = (char *) realloc((b), ti += max((i), MINBUFSZ))) == NULL) { \
|
||||||
|
fprintf(stderr, "%s\n", strerror(errno)); \
|
||||||
|
sprintf(errmsg, "out of memory"); \
|
||||||
|
SPL0(); \
|
||||||
|
return err; \
|
||||||
|
} \
|
||||||
|
(n) = ti; \
|
||||||
|
(b) = ts; \
|
||||||
|
SPL0(); \
|
||||||
|
}
|
||||||
|
#endif /* NO_REALLOC_NULL */
|
||||||
|
|
||||||
|
/* REQUE: link pred before succ */
|
||||||
|
#define REQUE(pred, succ) (pred)->q_forw = (succ), (succ)->q_back = (pred)
|
||||||
|
|
||||||
|
/* INSQUE: insert elem in circular queue after pred */
|
||||||
|
#define INSQUE(elem, pred) \
|
||||||
|
{ \
|
||||||
|
REQUE((elem), (pred)->q_forw); \
|
||||||
|
REQUE((pred), elem); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remque: remove_lines elem from circular queue */
|
||||||
|
#define REMQUE(elem) REQUE((elem)->q_back, (elem)->q_forw);
|
||||||
|
|
||||||
|
/* NUL_TO_NEWLINE: overwrite ASCII NULs with newlines */
|
||||||
|
#define NUL_TO_NEWLINE(s, l) translit_text(s, l, '\0', '\n')
|
||||||
|
|
||||||
|
/* NEWLINE_TO_NUL: overwrite newlines with ASCII NULs */
|
||||||
|
#define NEWLINE_TO_NUL(s, l) translit_text(s, l, '\n', '\0')
|
||||||
|
|
||||||
|
#if defined(sun) && !defined(__SVR4)
|
||||||
|
# define strerror(n) sys_errlist[n]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Local Function Declarations */
|
||||||
|
void add_line_node(line_t *);
|
||||||
|
int append_lines(long);
|
||||||
|
int apply_subst_template(char *, regmatch_t *, int, int);
|
||||||
|
int build_active_list(int);
|
||||||
|
int check_addr_range(long, long);
|
||||||
|
void clear_active_list(void);
|
||||||
|
void clear_undo_stack(void);
|
||||||
|
int close_sbuf(void);
|
||||||
|
int copy_lines(long);
|
||||||
|
int delete_lines(long, long);
|
||||||
|
int display_lines(long, long, int);
|
||||||
|
line_t *dup_line_node(line_t *);
|
||||||
|
int exec_command(void);
|
||||||
|
long exec_global(int, int);
|
||||||
|
int extract_addr_range(void);
|
||||||
|
char *extract_pattern(int);
|
||||||
|
int extract_subst_tail(int *, long *);
|
||||||
|
char *extract_subst_template(void);
|
||||||
|
int filter_lines(long, long, char *);
|
||||||
|
int flush_des_file(FILE *);
|
||||||
|
line_t *get_addressed_line_node(long);
|
||||||
|
pattern_t *get_compiled_pattern(void);
|
||||||
|
int get_des_char(FILE *);
|
||||||
|
char *get_extended_line(int *, int);
|
||||||
|
char *get_filename(void);
|
||||||
|
int get_keyword(void);
|
||||||
|
long get_line_node_addr(line_t *);
|
||||||
|
long get_matching_node_addr(pattern_t *, int);
|
||||||
|
long get_marked_node_addr(int);
|
||||||
|
char *get_sbuf_line(line_t *);
|
||||||
|
int get_shell_command(void);
|
||||||
|
int get_stream_line(FILE *);
|
||||||
|
int get_tty_line(void);
|
||||||
|
__dead void handle_hup(int);
|
||||||
|
__dead void handle_int(int);
|
||||||
|
void handle_winch(int);
|
||||||
|
int has_trailing_escape(char *, char *);
|
||||||
|
void init_buffers(void);
|
||||||
|
void init_des_cipher(void);
|
||||||
|
int is_legal_filename(char *);
|
||||||
|
int join_lines(long, long);
|
||||||
|
int mark_line_node(line_t *, int);
|
||||||
|
int move_lines(long);
|
||||||
|
line_t *next_active_node(void);
|
||||||
|
long next_addr(void);
|
||||||
|
int open_sbuf(void);
|
||||||
|
char *parse_char_class(char *);
|
||||||
|
int pop_undo_stack(void);
|
||||||
|
undo_t *push_undo_stack(int, long, long);
|
||||||
|
int put_des_char(int, FILE *);
|
||||||
|
char *put_sbuf_line(char *);
|
||||||
|
int put_stream_line(FILE *, char *, int);
|
||||||
|
int put_tty_line(char *, int, long, int);
|
||||||
|
__dead void quit(int);
|
||||||
|
long read_file(char *, long);
|
||||||
|
long read_stream(FILE *, long);
|
||||||
|
int search_and_replace(pattern_t *, int, int);
|
||||||
|
int set_active_node(line_t *);
|
||||||
|
void signal_hup(int);
|
||||||
|
void signal_int(int);
|
||||||
|
char *strip_escapes(const char *);
|
||||||
|
int substitute_matching_text(pattern_t *, line_t *, int, int);
|
||||||
|
char *translit_text(char *, int, int, int);
|
||||||
|
void unmark_line_node(line_t *);
|
||||||
|
void unset_active_nodes(line_t *, line_t *);
|
||||||
|
long write_file(const char *, const char *, long, long);
|
||||||
|
long write_stream(FILE *, long, long);
|
||||||
|
|
||||||
|
/* global buffers */
|
||||||
|
extern char stdinbuf[];
|
||||||
|
extern char *ibuf;
|
||||||
|
extern char *ibufp;
|
||||||
|
extern int ibufsz;
|
||||||
|
|
||||||
|
/* 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 long first_addr;
|
||||||
|
extern int lineno;
|
||||||
|
extern long second_addr;
|
||||||
|
extern long rows;
|
||||||
|
extern int cols;
|
||||||
|
extern int scripted;
|
||||||
|
extern int ere;
|
||||||
|
extern int des;
|
||||||
|
extern int newline_added; /* io.c */
|
||||||
|
extern int patlock;
|
||||||
|
extern char errmsg[]; /* re.c */
|
||||||
|
extern long u_current_addr; /* undo.c */
|
||||||
|
extern long u_addr_last; /* undo.c */
|
||||||
|
#if defined(sun) && !defined(__SVR4)
|
||||||
|
extern char *sys_errlist[];
|
||||||
|
#endif
|
227
bin/ed/glbl.c
Normal file
227
bin/ed/glbl.c
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
/* $NetBSD: glbl.c,v 1.6 2005/06/26 19:10:49 christos Exp $ */
|
||||||
|
|
||||||
|
/* glob.c: This file contains the global command 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef lint
|
||||||
|
#if 0
|
||||||
|
static char *rcsid = "@(#)glob.c,v 1.1 1994/02/01 00:34:40 alm Exp";
|
||||||
|
#else
|
||||||
|
__RCSID("$NetBSD: glbl.c,v 1.6 2005/06/26 19:10:49 christos Exp $");
|
||||||
|
#endif
|
||||||
|
#endif /* not lint */
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include "ed.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* build_active_list: add line matching a pattern to the global-active list */
|
||||||
|
int
|
||||||
|
build_active_list(int isgcmd)
|
||||||
|
{
|
||||||
|
pattern_t *pat;
|
||||||
|
line_t *lp;
|
||||||
|
long n;
|
||||||
|
char *s;
|
||||||
|
char delimiter;
|
||||||
|
|
||||||
|
if ((delimiter = *ibufp) == ' ' || delimiter == '\n') {
|
||||||
|
sprintf(errmsg, "invalid pattern delimiter");
|
||||||
|
return ERR;
|
||||||
|
} else if ((pat = get_compiled_pattern()) == NULL)
|
||||||
|
return ERR;
|
||||||
|
else if (*ibufp == delimiter)
|
||||||
|
ibufp++;
|
||||||
|
clear_active_list();
|
||||||
|
lp = get_addressed_line_node(first_addr);
|
||||||
|
for (n = first_addr; n <= second_addr; n++, lp = lp->q_forw) {
|
||||||
|
if ((s = get_sbuf_line(lp)) == NULL)
|
||||||
|
return ERR;
|
||||||
|
if (isbinary)
|
||||||
|
NUL_TO_NEWLINE(s, lp->len);
|
||||||
|
if (!regexec(pat, s, 0, NULL, 0) == isgcmd &&
|
||||||
|
set_active_node(lp) < 0)
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* exec_global: apply command list in the command buffer to the active
|
||||||
|
lines in a range; return command status */
|
||||||
|
long
|
||||||
|
exec_global(int interact, int gflag)
|
||||||
|
{
|
||||||
|
static char *ocmd = NULL;
|
||||||
|
static int ocmdsz = 0;
|
||||||
|
|
||||||
|
line_t *lp = NULL;
|
||||||
|
int status;
|
||||||
|
int n;
|
||||||
|
char *cmd = NULL;
|
||||||
|
#ifdef BACKWARDS
|
||||||
|
char cmdp[] = "p\n";
|
||||||
|
|
||||||
|
if (!interact) {
|
||||||
|
if (!strcmp(ibufp, "\n"))
|
||||||
|
cmd = cmdp; /* null cmd-list == `p' */
|
||||||
|
else if ((cmd = get_extended_line(&n, 0)) == NULL)
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (!interact && (cmd = get_extended_line(&n, 0)) == NULL)
|
||||||
|
return ERR;
|
||||||
|
#endif
|
||||||
|
clear_undo_stack();
|
||||||
|
while ((lp = next_active_node()) != NULL) {
|
||||||
|
if ((current_addr = get_line_node_addr(lp)) < 0)
|
||||||
|
return ERR;
|
||||||
|
if (interact) {
|
||||||
|
/* print current_addr; get a command in global syntax */
|
||||||
|
if (display_lines(current_addr, current_addr, gflag) < 0)
|
||||||
|
return ERR;
|
||||||
|
while ((n = get_tty_line()) > 0 &&
|
||||||
|
ibuf[n - 1] != '\n')
|
||||||
|
clearerr(stdin);
|
||||||
|
if (n < 0)
|
||||||
|
return ERR;
|
||||||
|
else if (n == 0) {
|
||||||
|
sprintf(errmsg, "unexpected end-of-file");
|
||||||
|
return ERR;
|
||||||
|
} else if (n == 1 && !strcmp(ibuf, "\n"))
|
||||||
|
continue;
|
||||||
|
else if (n == 2 && !strcmp(ibuf, "&\n")) {
|
||||||
|
if (cmd == NULL) {
|
||||||
|
sprintf(errmsg, "no previous command");
|
||||||
|
return ERR;
|
||||||
|
} else cmd = ocmd;
|
||||||
|
} else if ((cmd = get_extended_line(&n, 0)) == NULL)
|
||||||
|
return ERR;
|
||||||
|
else {
|
||||||
|
REALLOC(ocmd, ocmdsz, n + 1, ERR);
|
||||||
|
memcpy(ocmd, cmd, n + 1);
|
||||||
|
cmd = ocmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
ibufp = cmd;
|
||||||
|
for (; *ibufp;)
|
||||||
|
if ((status = extract_addr_range()) < 0 ||
|
||||||
|
(status = exec_command()) < 0 ||
|
||||||
|
(status > 0 && (status = display_lines(
|
||||||
|
current_addr, current_addr, status))) < 0)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
line_t **active_list; /* list of lines active in a global command */
|
||||||
|
long active_last; /* index of last active line in active_list */
|
||||||
|
long active_size; /* size of active_list */
|
||||||
|
long active_ptr; /* active_list index (non-decreasing) */
|
||||||
|
long active_ndx; /* active_list index (modulo active_last) */
|
||||||
|
|
||||||
|
/* set_active_node: add a line node to the global-active list */
|
||||||
|
int
|
||||||
|
set_active_node(line_t *lp)
|
||||||
|
{
|
||||||
|
if (active_last + 1 > active_size) {
|
||||||
|
int ti = active_size;
|
||||||
|
line_t **ts;
|
||||||
|
SPL1();
|
||||||
|
#if defined(sun) || defined(NO_REALLOC_NULL)
|
||||||
|
if (active_list != NULL) {
|
||||||
|
#endif
|
||||||
|
if ((ts = (line_t **) realloc(active_list,
|
||||||
|
(ti += MINBUFSZ) * sizeof(line_t **))) == NULL) {
|
||||||
|
fprintf(stderr, "%s\n", strerror(errno));
|
||||||
|
sprintf(errmsg, "out of memory");
|
||||||
|
SPL0();
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
#if defined(sun) || defined(NO_REALLOC_NULL)
|
||||||
|
} else {
|
||||||
|
if ((ts = (line_t **) malloc((ti += MINBUFSZ) *
|
||||||
|
sizeof(line_t **))) == NULL) {
|
||||||
|
fprintf(stderr, "%s\n", strerror(errno));
|
||||||
|
sprintf(errmsg, "out of memory");
|
||||||
|
SPL0();
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
active_size = ti;
|
||||||
|
active_list = ts;
|
||||||
|
SPL0();
|
||||||
|
}
|
||||||
|
active_list[active_last++] = lp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* unset_active_nodes: remove a range of lines from the global-active list */
|
||||||
|
void
|
||||||
|
unset_active_nodes(line_t *np, line_t *mp)
|
||||||
|
{
|
||||||
|
line_t *lp;
|
||||||
|
long i;
|
||||||
|
|
||||||
|
for (lp = np; lp != mp; lp = lp->q_forw)
|
||||||
|
for (i = 0; i < active_last; i++)
|
||||||
|
if (active_list[active_ndx] == lp) {
|
||||||
|
active_list[active_ndx] = NULL;
|
||||||
|
active_ndx = INC_MOD(active_ndx, active_last - 1);
|
||||||
|
break;
|
||||||
|
} else active_ndx = INC_MOD(active_ndx, active_last - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* next_active_node: return the next global-active line node */
|
||||||
|
line_t *
|
||||||
|
next_active_node(void)
|
||||||
|
{
|
||||||
|
while (active_ptr < active_last && active_list[active_ptr] == NULL)
|
||||||
|
active_ptr++;
|
||||||
|
return (active_ptr < active_last) ? active_list[active_ptr++] : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* clear_active_list: clear the global-active list */
|
||||||
|
void
|
||||||
|
clear_active_list(void)
|
||||||
|
{
|
||||||
|
SPL1();
|
||||||
|
active_size = active_last = active_ptr = active_ndx = 0;
|
||||||
|
free(active_list);
|
||||||
|
active_list = NULL;
|
||||||
|
SPL0();
|
||||||
|
}
|
358
bin/ed/io.c
Normal file
358
bin/ed/io.c
Normal file
|
@ -0,0 +1,358 @@
|
||||||
|
/* $NetBSD: io.c,v 1.9 2011/05/23 23:13:10 joerg Exp $ */
|
||||||
|
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef lint
|
||||||
|
#if 0
|
||||||
|
static char *rcsid = "@(#)io.c,v 1.1 1994/02/01 00:34:41 alm Exp";
|
||||||
|
#else
|
||||||
|
__RCSID("$NetBSD: io.c,v 1.9 2011/05/23 23:13:10 joerg Exp $");
|
||||||
|
#endif
|
||||||
|
#endif /* not lint */
|
||||||
|
|
||||||
|
#include "ed.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* read_file: read a named file/pipe into the buffer; return line count */
|
||||||
|
long
|
||||||
|
read_file(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;
|
||||||
|
}
|
||||||
|
if (!scripted)
|
||||||
|
fprintf(stderr, "%lu\n", size);
|
||||||
|
return current_addr - n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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(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(FILE *fp)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
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(const char *fn, const 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;
|
||||||
|
}
|
||||||
|
if (!scripted)
|
||||||
|
fprintf(stderr, "%lu\n", size);
|
||||||
|
return n ? m - n + 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* write_stream: write a range of lines to a stream; return status */
|
||||||
|
long
|
||||||
|
write_stream(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(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(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(void)
|
||||||
|
{
|
||||||
|
int oi = 0;
|
||||||
|
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\\"
|
||||||
|
|
||||||
|
/* put_tty_line: print text to stdout */
|
||||||
|
int
|
||||||
|
put_tty_line(char *s, int l, long n, int gflag)
|
||||||
|
{
|
||||||
|
int col = 0;
|
||||||
|
char *cp;
|
||||||
|
#ifndef BACKWARDS
|
||||||
|
int lc = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
1425
bin/ed/main.c
Normal file
1425
bin/ed/main.c
Normal file
File diff suppressed because it is too large
Load diff
135
bin/ed/re.c
Normal file
135
bin/ed/re.c
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
/* $NetBSD: re.c,v 1.19 2005/02/17 16:29:26 xtraeme Exp $ */
|
||||||
|
|
||||||
|
/* re.c: This file contains the regular expression interface 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef lint
|
||||||
|
#if 0
|
||||||
|
static char *rcsid = "@(#)re.c,v 1.6 1994/02/01 00:34:43 alm Exp";
|
||||||
|
#else
|
||||||
|
__RCSID("$NetBSD: re.c,v 1.19 2005/02/17 16:29:26 xtraeme Exp $");
|
||||||
|
#endif
|
||||||
|
#endif /* not lint */
|
||||||
|
|
||||||
|
#include "ed.h"
|
||||||
|
|
||||||
|
|
||||||
|
char errmsg[MAXPATHLEN + 40] = "";
|
||||||
|
|
||||||
|
/* get_compiled_pattern: return pointer to compiled pattern from command
|
||||||
|
buffer */
|
||||||
|
pattern_t *
|
||||||
|
get_compiled_pattern(void)
|
||||||
|
{
|
||||||
|
static pattern_t *expr = NULL;
|
||||||
|
|
||||||
|
char *exps;
|
||||||
|
char delimiter;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if ((delimiter = *ibufp) == ' ') {
|
||||||
|
sprintf(errmsg, "invalid pattern delimiter");
|
||||||
|
return NULL;
|
||||||
|
} else if (delimiter == '\n' || *++ibufp == '\n' || *ibufp == delimiter) {
|
||||||
|
if (!expr) sprintf(errmsg, "no previous pattern");
|
||||||
|
return expr;
|
||||||
|
} else if ((exps = extract_pattern(delimiter)) == NULL)
|
||||||
|
return NULL;
|
||||||
|
/* buffer alloc'd && not reserved */
|
||||||
|
if (expr && !patlock)
|
||||||
|
regfree(expr);
|
||||||
|
else if ((expr = (pattern_t *) malloc(sizeof(pattern_t))) == NULL) {
|
||||||
|
fprintf(stderr, "%s\n", strerror(errno));
|
||||||
|
sprintf(errmsg, "out of memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
patlock = 0;
|
||||||
|
if ((n = regcomp(expr, exps, ere)) != 0) {
|
||||||
|
regerror(n, expr, errmsg, sizeof errmsg);
|
||||||
|
free(expr);
|
||||||
|
return expr = NULL;
|
||||||
|
}
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* extract_pattern: copy a pattern string from the command buffer; return
|
||||||
|
pointer to the copy */
|
||||||
|
char *
|
||||||
|
extract_pattern(int delimiter)
|
||||||
|
{
|
||||||
|
static char *lhbuf = NULL; /* buffer */
|
||||||
|
static int lhbufsz = 0; /* buffer size */
|
||||||
|
|
||||||
|
char *nd;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
for (nd = ibufp; *nd != delimiter && *nd != '\n'; nd++)
|
||||||
|
switch (*nd) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
if ((nd = parse_char_class(++nd)) == NULL) {
|
||||||
|
sprintf(errmsg, "unbalanced brackets ([])");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
if (*++nd == '\n') {
|
||||||
|
sprintf(errmsg, "trailing backslash (\\)");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len = nd - ibufp;
|
||||||
|
REALLOC(lhbuf, lhbufsz, len + 1, NULL);
|
||||||
|
memcpy(lhbuf, ibufp, len);
|
||||||
|
lhbuf[len] = '\0';
|
||||||
|
ibufp = nd;
|
||||||
|
return (isbinary) ? NUL_TO_NEWLINE(lhbuf, len) : lhbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* parse_char_class: expand a POSIX character class */
|
||||||
|
char *
|
||||||
|
parse_char_class(char *s)
|
||||||
|
{
|
||||||
|
int c, d;
|
||||||
|
|
||||||
|
if (*s == '^')
|
||||||
|
s++;
|
||||||
|
if (*s == ']')
|
||||||
|
s++;
|
||||||
|
for (; *s != ']' && *s != '\n'; s++)
|
||||||
|
if (*s == '[' && ((d = *(s+1)) == '.' || d == ':' || d == '='))
|
||||||
|
for (s++, c = *++s; *s != ']' || c != d; s++)
|
||||||
|
if ((c = *s) == '\n')
|
||||||
|
return NULL;
|
||||||
|
return (*s == ']') ? s : NULL;
|
||||||
|
}
|
260
bin/ed/sub.c
Normal file
260
bin/ed/sub.c
Normal file
|
@ -0,0 +1,260 @@
|
||||||
|
/* $NetBSD: sub.c,v 1.6 2005/02/17 16:29:26 xtraeme Exp $ */
|
||||||
|
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef lint
|
||||||
|
#if 0
|
||||||
|
static char *rcsid = "@(#)sub.c,v 1.1 1994/02/01 00:34:44 alm Exp";
|
||||||
|
#else
|
||||||
|
__RCSID("$NetBSD: sub.c,v 1.6 2005/02/17 16:29:26 xtraeme Exp $");
|
||||||
|
#endif
|
||||||
|
#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(int *flagp, long *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(void)
|
||||||
|
{
|
||||||
|
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(pattern_t *pat, int gflag, int kth)
|
||||||
|
{
|
||||||
|
undo_t *up;
|
||||||
|
char *txt;
|
||||||
|
char *eot;
|
||||||
|
long lc;
|
||||||
|
long xa = current_addr;
|
||||||
|
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++;
|
||||||
|
xa = current_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current_addr = xa;
|
||||||
|
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(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(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
bin/ed/test/=.err
Normal file
1
bin/ed/test/=.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
1,$=
|
28
bin/ed/test/Makefile
Normal file
28
bin/ed/test/Makefile
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# $NetBSD: Makefile,v 1.12 2003/10/26 03:50:07 lukem Exp $
|
||||||
|
|
||||||
|
.include <bsd.own.mk>
|
||||||
|
|
||||||
|
ED?= ../obj/ed
|
||||||
|
|
||||||
|
all: check
|
||||||
|
@:
|
||||||
|
|
||||||
|
check: build test
|
||||||
|
@if grep -h '\*\*\*' errs.o scripts.o; then :; else \
|
||||||
|
echo "tests completed successfully."; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
build: mkscripts.sh
|
||||||
|
@if [ -f errs.o ]; then :; else \
|
||||||
|
echo "building test scripts for $(ED) ..."; \
|
||||||
|
${HOST_SH} ${.CURDIR}/mkscripts.sh $(ED); \
|
||||||
|
fi
|
||||||
|
|
||||||
|
test: build ckscripts.sh
|
||||||
|
@echo testing $(ED) ...
|
||||||
|
@${HOST_SH} ckscripts.sh $(ED)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.ed *.red *.[oz] *~
|
||||||
|
|
||||||
|
.include <bsd.prog.mk>
|
32
bin/ed/test/README
Normal file
32
bin/ed/test/README
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
$NetBSD: README,v 1.8 1995/03/21 09:05:18 cgd Exp $
|
||||||
|
|
||||||
|
The files in this directory with suffixes `.t', `.d', `.r' and `.err' are
|
||||||
|
used for testing ed. To run the tests, set the ED variable in the Makefile
|
||||||
|
for the path name of the program to be tested (e.g., /bin/ed), and type
|
||||||
|
`make'. The tests do not exhaustively verify POSIX compliance nor do
|
||||||
|
they verify correct 8-bit or long line support.
|
||||||
|
|
||||||
|
The test file suffixes have the following meanings:
|
||||||
|
.t Template - a list of ed commands from which an ed script is
|
||||||
|
constructed
|
||||||
|
.d Data - read by an ed script
|
||||||
|
.r Result - the expected output after processing data via an ed
|
||||||
|
script.
|
||||||
|
.err Error - invalid ed commands that should generate an error
|
||||||
|
|
||||||
|
The output of the tests is written to the two files err.o and scripts.o.
|
||||||
|
At the end of the tests, these files are grep'ed for error messages,
|
||||||
|
which look like:
|
||||||
|
*** The script u.ed exited abnormally ***
|
||||||
|
or:
|
||||||
|
*** Output u.o of script u.ed is incorrect ***
|
||||||
|
|
||||||
|
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
|
||||||
|
POSIX rule exit abnormally:
|
||||||
|
=-err.ed
|
||||||
|
a1-err.ed
|
||||||
|
i1-err.ed
|
||||||
|
k1-err.ed
|
||||||
|
r1-err.ed
|
17
bin/ed/test/TODO
Normal file
17
bin/ed/test/TODO
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
$NetBSD: TODO,v 1.3 1995/03/21 09:05:20 cgd Exp $
|
||||||
|
|
||||||
|
Some missing tests:
|
||||||
|
0) g/./s^@^@ - okay: NULs in commands
|
||||||
|
1) g/./s/^@/ - okay: NULs in patterns
|
||||||
|
2) a
|
||||||
|
hello^V^Jworld
|
||||||
|
. - okay: embedded newlines in insert mode
|
||||||
|
3) ed "" - error: invalid filename
|
||||||
|
4) red .. - error: restricted
|
||||||
|
5) red / - error: restricted
|
||||||
|
5) red !xx - error: restricted
|
||||||
|
6) ed -x - verify: 8-bit clean
|
||||||
|
7) ed - verify: long-line support
|
||||||
|
8) ed - verify: interactive/help mode
|
||||||
|
9) G/pat/ - verify: global interactive command
|
||||||
|
10) V/pat/ - verify: global interactive command
|
8
bin/ed/test/a.r
Normal file
8
bin/ed/test/a.r
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
hello world
|
||||||
|
line 1
|
||||||
|
hello world!
|
||||||
|
line 2
|
||||||
|
line 3
|
||||||
|
line 4
|
||||||
|
line5
|
||||||
|
hello world!!
|
9
bin/ed/test/a.t
Normal file
9
bin/ed/test/a.t
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
0a
|
||||||
|
hello world
|
||||||
|
.
|
||||||
|
2a
|
||||||
|
hello world!
|
||||||
|
.
|
||||||
|
$a
|
||||||
|
hello world!!
|
||||||
|
.
|
3
bin/ed/test/a1.err
Normal file
3
bin/ed/test/a1.err
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
1,$a
|
||||||
|
hello world
|
||||||
|
.
|
3
bin/ed/test/a2.err
Normal file
3
bin/ed/test/a2.err
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
aa
|
||||||
|
hello world
|
||||||
|
.
|
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
|
1
bin/ed/test/addr1.err
Normal file
1
bin/ed/test/addr1.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
100
|
1
bin/ed/test/addr2.err
Normal file
1
bin/ed/test/addr2.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
-100
|
BIN
bin/ed/test/ascii.r
Normal file
BIN
bin/ed/test/ascii.r
Normal file
Binary file not shown.
0
bin/ed/test/ascii.t
Normal file
0
bin/ed/test/ascii.t
Normal file
1
bin/ed/test/bang1.err
Normal file
1
bin/ed/test/bang1.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
.!date
|
1
bin/ed/test/bang1.r
Normal file
1
bin/ed/test/bang1.r
Normal file
|
@ -0,0 +1 @@
|
||||||
|
okay
|
5
bin/ed/test/bang1.t
Normal file
5
bin/ed/test/bang1.t
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
!read one
|
||||||
|
hello, world
|
||||||
|
a
|
||||||
|
okay
|
||||||
|
.
|
1
bin/ed/test/bang2.err
Normal file
1
bin/ed/test/bang2.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
!!
|
4
bin/ed/test/c.r
Normal file
4
bin/ed/test/c.r
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
at the top
|
||||||
|
between top/middle
|
||||||
|
in the middle
|
||||||
|
at the bottom
|
12
bin/ed/test/c.t
Normal file
12
bin/ed/test/c.t
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
1c
|
||||||
|
at the top
|
||||||
|
.
|
||||||
|
4c
|
||||||
|
in the middle
|
||||||
|
.
|
||||||
|
$c
|
||||||
|
at the bottom
|
||||||
|
.
|
||||||
|
2,3c
|
||||||
|
between top/middle
|
||||||
|
.
|
3
bin/ed/test/c1.err
Normal file
3
bin/ed/test/c1.err
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
cc
|
||||||
|
hello world
|
||||||
|
.
|
3
bin/ed/test/c2.err
Normal file
3
bin/ed/test/c2.err
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
0c
|
||||||
|
hello world
|
||||||
|
.
|
37
bin/ed/test/ckscripts.sh
Executable file
37
bin/ed/test/ckscripts.sh
Executable file
|
@ -0,0 +1,37 @@
|
||||||
|
#!/bin/sh -
|
||||||
|
# $NetBSD: ckscripts.sh,v 1.9 1995/04/23 10:07:34 cgd Exp $
|
||||||
|
#
|
||||||
|
# This script runs the .ed scripts generated by mkscripts.sh
|
||||||
|
# and compares their output against the .r files, which contain
|
||||||
|
# the correct output
|
||||||
|
|
||||||
|
PATH="/bin:/usr/bin:/usr/local/bin/:."
|
||||||
|
ED=$1
|
||||||
|
[ ! -x $ED ] && { echo "$ED: cannot execute"; exit 1; }
|
||||||
|
|
||||||
|
# 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 ***"
|
||||||
|
fi
|
||||||
|
done >errs.o 2>&1
|
||||||
|
|
||||||
|
# Run the remainding scripts; they exit with zero status
|
||||||
|
for i in *.ed; do
|
||||||
|
# base=`expr $i : '\([^.]*\)'`
|
||||||
|
# base=`echo $i | sed 's/\..*//'`
|
||||||
|
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 ***"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "*** The script $i exited abnormally ***"
|
||||||
|
fi
|
||||||
|
done >scripts.o 2>&1
|
||||||
|
|
||||||
|
grep -h '\*\*\*' errs.o scripts.o
|
1
bin/ed/test/d.err
Normal file
1
bin/ed/test/d.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
dd
|
1
bin/ed/test/d.r
Normal file
1
bin/ed/test/d.r
Normal file
|
@ -0,0 +1 @@
|
||||||
|
line 2
|
3
bin/ed/test/d.t
Normal file
3
bin/ed/test/d.t
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
1d
|
||||||
|
2;+1d
|
||||||
|
$d
|
1
bin/ed/test/e1.err
Normal file
1
bin/ed/test/e1.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ee e1.err
|
1
bin/ed/test/e1.r
Normal file
1
bin/ed/test/e1.r
Normal file
|
@ -0,0 +1 @@
|
||||||
|
E e1.t
|
1
bin/ed/test/e1.t
Normal file
1
bin/ed/test/e1.t
Normal file
|
@ -0,0 +1 @@
|
||||||
|
E e1.t
|
1
bin/ed/test/e2.err
Normal file
1
bin/ed/test/e2.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
.e e2.err
|
1
bin/ed/test/e2.r
Normal file
1
bin/ed/test/e2.r
Normal file
|
@ -0,0 +1 @@
|
||||||
|
hello world-
|
1
bin/ed/test/e2.t
Normal file
1
bin/ed/test/e2.t
Normal file
|
@ -0,0 +1 @@
|
||||||
|
E !echo hello world-
|
1
bin/ed/test/e3.err
Normal file
1
bin/ed/test/e3.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ee.err
|
1
bin/ed/test/e3.r
Normal file
1
bin/ed/test/e3.r
Normal file
|
@ -0,0 +1 @@
|
||||||
|
E !echo hello world-
|
1
bin/ed/test/e3.t
Normal file
1
bin/ed/test/e3.t
Normal file
|
@ -0,0 +1 @@
|
||||||
|
E
|
1
bin/ed/test/e4.r
Normal file
1
bin/ed/test/e4.r
Normal file
|
@ -0,0 +1 @@
|
||||||
|
E !echo hello world-
|
1
bin/ed/test/e4.t
Normal file
1
bin/ed/test/e4.t
Normal file
|
@ -0,0 +1 @@
|
||||||
|
e
|
1
bin/ed/test/f1.err
Normal file
1
bin/ed/test/f1.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
.f f1.err
|
1
bin/ed/test/f2.err
Normal file
1
bin/ed/test/f2.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ff1.err
|
1
bin/ed/test/g1.err
Normal file
1
bin/ed/test/g1.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
g/./s //x/
|
15
bin/ed/test/g1.r
Normal file
15
bin/ed/test/g1.r
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
line5
|
||||||
|
help! world
|
||||||
|
order
|
||||||
|
line 4
|
||||||
|
help! world
|
||||||
|
order
|
||||||
|
line 3
|
||||||
|
help! world
|
||||||
|
order
|
||||||
|
line 2
|
||||||
|
help! world
|
||||||
|
order
|
||||||
|
line 1
|
||||||
|
help! world
|
||||||
|
order
|
6
bin/ed/test/g1.t
Normal file
6
bin/ed/test/g1.t
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
g/./m0
|
||||||
|
g/./s/$/\
|
||||||
|
hello world
|
||||||
|
g/hello /s/lo/p!/\
|
||||||
|
a\
|
||||||
|
order
|
1
bin/ed/test/g2.err
Normal file
1
bin/ed/test/g2.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
g//s/./x/
|
1
bin/ed/test/g2.r
Normal file
1
bin/ed/test/g2.r
Normal file
|
@ -0,0 +1 @@
|
||||||
|
hello world
|
2
bin/ed/test/g2.t
Normal file
2
bin/ed/test/g2.t
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
g/[2-4]/-1,+1c\
|
||||||
|
hello world
|
1
bin/ed/test/g3.err
Normal file
1
bin/ed/test/g3.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
g
|
5
bin/ed/test/g3.r
Normal file
5
bin/ed/test/g3.r
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
linc 3
|
||||||
|
xine 1
|
||||||
|
xine 2
|
||||||
|
xinc 4
|
||||||
|
xinc5
|
4
bin/ed/test/g3.t
Normal file
4
bin/ed/test/g3.t
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
g/./s//x/\
|
||||||
|
3m0
|
||||||
|
g/./s/e/c/\
|
||||||
|
2,3m1
|
7
bin/ed/test/g4.r
Normal file
7
bin/ed/test/g4.r
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
hello
|
||||||
|
zine 1
|
||||||
|
line 2
|
||||||
|
line 3
|
||||||
|
line 4
|
||||||
|
line5
|
||||||
|
world
|
13
bin/ed/test/g4.t
Normal file
13
bin/ed/test/g4.t
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
g/./s/./x/\
|
||||||
|
u\
|
||||||
|
s/./y/\
|
||||||
|
u\
|
||||||
|
s/./z/\
|
||||||
|
u
|
||||||
|
u
|
||||||
|
0a
|
||||||
|
hello
|
||||||
|
.
|
||||||
|
$a
|
||||||
|
world
|
||||||
|
.
|
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
|
1
bin/ed/test/h.err
Normal file
1
bin/ed/test/h.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
.h
|
8
bin/ed/test/i.r
Normal file
8
bin/ed/test/i.r
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
hello world
|
||||||
|
hello world!
|
||||||
|
line 1
|
||||||
|
line 2
|
||||||
|
line 3
|
||||||
|
line 4
|
||||||
|
hello world!!
|
||||||
|
line5
|
9
bin/ed/test/i.t
Normal file
9
bin/ed/test/i.t
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
1i
|
||||||
|
hello world
|
||||||
|
.
|
||||||
|
2i
|
||||||
|
hello world!
|
||||||
|
.
|
||||||
|
$i
|
||||||
|
hello world!!
|
||||||
|
.
|
3
bin/ed/test/i1.err
Normal file
3
bin/ed/test/i1.err
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
1,$i
|
||||||
|
hello world
|
||||||
|
.
|
3
bin/ed/test/i2.err
Normal file
3
bin/ed/test/i2.err
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
ii
|
||||||
|
hello world
|
||||||
|
.
|
3
bin/ed/test/i3.err
Normal file
3
bin/ed/test/i3.err
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
0i
|
||||||
|
hello world
|
||||||
|
.
|
4
bin/ed/test/j.r
Normal file
4
bin/ed/test/j.r
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
line 1
|
||||||
|
line 2line 3
|
||||||
|
line 4
|
||||||
|
line5
|
2
bin/ed/test/j.t
Normal file
2
bin/ed/test/j.t
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
1,1j
|
||||||
|
2,3j
|
5
bin/ed/test/k.r
Normal file
5
bin/ed/test/k.r
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
line 3
|
||||||
|
hello world
|
||||||
|
line 4
|
||||||
|
line5
|
||||||
|
line 2
|
10
bin/ed/test/k.t
Normal file
10
bin/ed/test/k.t
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
2ka
|
||||||
|
1d
|
||||||
|
'am$
|
||||||
|
1ka
|
||||||
|
0a
|
||||||
|
hello world
|
||||||
|
.
|
||||||
|
'ad
|
||||||
|
u
|
||||||
|
'am0
|
1
bin/ed/test/k1.err
Normal file
1
bin/ed/test/k1.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
1,$ka
|
1
bin/ed/test/k2.err
Normal file
1
bin/ed/test/k2.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
kA
|
1
bin/ed/test/k3.err
Normal file
1
bin/ed/test/k3.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
0ka
|
6
bin/ed/test/k4.err
Normal file
6
bin/ed/test/k4.err
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
a
|
||||||
|
hello
|
||||||
|
.
|
||||||
|
.ka
|
||||||
|
'ad
|
||||||
|
'ap
|
0
bin/ed/test/l.r
Normal file
0
bin/ed/test/l.r
Normal file
0
bin/ed/test/l.t
Normal file
0
bin/ed/test/l.t
Normal file
4
bin/ed/test/m.err
Normal file
4
bin/ed/test/m.err
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
a
|
||||||
|
hello world
|
||||||
|
.
|
||||||
|
1,$m1
|
5
bin/ed/test/m.r
Normal file
5
bin/ed/test/m.r
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
line5
|
||||||
|
line 1
|
||||||
|
line 2
|
||||||
|
line 3
|
||||||
|
line 4
|
7
bin/ed/test/m.t
Normal file
7
bin/ed/test/m.t
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
1,2m$
|
||||||
|
1,2m$
|
||||||
|
1,2m$
|
||||||
|
$m0
|
||||||
|
$m0
|
||||||
|
2,3m1
|
||||||
|
2,3m3
|
75
bin/ed/test/mkscripts.sh
Executable file
75
bin/ed/test/mkscripts.sh
Executable file
|
@ -0,0 +1,75 @@
|
||||||
|
#!/bin/sh -
|
||||||
|
# $NetBSD: mkscripts.sh,v 1.10 1995/04/23 10:07:36 cgd Exp $
|
||||||
|
#
|
||||||
|
# This script generates ed test scripts (.ed) from .t files
|
||||||
|
|
||||||
|
PATH="/bin:/usr/bin:/usr/local/bin/:."
|
||||||
|
ED=$1
|
||||||
|
[ ! -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 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
|
||||||
|
# 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
|
0
bin/ed/test/n.r
Normal file
0
bin/ed/test/n.r
Normal file
0
bin/ed/test/n.t
Normal file
0
bin/ed/test/n.t
Normal file
1
bin/ed/test/nl.err
Normal file
1
bin/ed/test/nl.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
,1
|
8
bin/ed/test/nl1.r
Normal file
8
bin/ed/test/nl1.r
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
|
||||||
|
hello world
|
||||||
|
line 1
|
||||||
|
line 2
|
||||||
|
line 3
|
||||||
|
line 4
|
||||||
|
line5
|
8
bin/ed/test/nl1.t
Normal file
8
bin/ed/test/nl1.t
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
1
|
||||||
|
|
||||||
|
|
||||||
|
0a
|
||||||
|
|
||||||
|
|
||||||
|
hello world
|
||||||
|
.
|
6
bin/ed/test/nl2.r
Normal file
6
bin/ed/test/nl2.r
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
line 1
|
||||||
|
line 2
|
||||||
|
line 3
|
||||||
|
line 4
|
||||||
|
line5
|
||||||
|
hello world
|
4
bin/ed/test/nl2.t
Normal file
4
bin/ed/test/nl2.t
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
a
|
||||||
|
hello world
|
||||||
|
.
|
||||||
|
0;/./
|
0
bin/ed/test/p.r
Normal file
0
bin/ed/test/p.r
Normal file
0
bin/ed/test/p.t
Normal file
0
bin/ed/test/p.t
Normal file
0
bin/ed/test/q.r
Normal file
0
bin/ed/test/q.r
Normal file
5
bin/ed/test/q.t
Normal file
5
bin/ed/test/q.t
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
w q.o
|
||||||
|
a
|
||||||
|
hello
|
||||||
|
.
|
||||||
|
q
|
1
bin/ed/test/q1.err
Normal file
1
bin/ed/test/q1.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
.q
|
1
bin/ed/test/r1.err
Normal file
1
bin/ed/test/r1.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
1,$r r1.err
|
7
bin/ed/test/r1.r
Normal file
7
bin/ed/test/r1.r
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
line 1
|
||||||
|
hello world
|
||||||
|
line 2
|
||||||
|
line 3
|
||||||
|
line 4
|
||||||
|
line5
|
||||||
|
hello world
|
3
bin/ed/test/r1.t
Normal file
3
bin/ed/test/r1.t
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
1;r !echo hello world
|
||||||
|
1
|
||||||
|
r !echo hello world
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue