diff options
Diffstat (limited to 'bin')
69 files changed, 3503 insertions, 3219 deletions
diff --git a/bin/Makefile.inc b/bin/Makefile.inc index 7178a59782ec..e293cb3e9352 100644 --- a/bin/Makefile.inc +++ b/bin/Makefile.inc @@ -1,3 +1,4 @@ # @(#)Makefile.inc 5.1 (Berkeley) 5/11/90 BINDIR?= /bin +NOSHARED?= YES diff --git a/bin/cp/cp.c b/bin/cp/cp.c index 72dee7769559..e21bba631e9d 100644 --- a/bin/cp/cp.c +++ b/bin/cp/cp.c @@ -325,7 +325,7 @@ copy_file(fs, dne) checkch = ch = getchar(); while (ch != '\n' && ch != EOF) ch = getchar(); - if (checkch != 'y') { + if (checkch != 'y' && checkch != 'Y') { (void)close(from_fd); return; } @@ -350,10 +350,13 @@ copy_file(fs, dne) if ((p = mmap(NULL, fs->st_size, PROT_READ, MAP_FILE, from_fd, (off_t)0)) == (char *)-1) err("%s: %s", from.p_path, strerror(errno)); - madvise((caddr_t) p, fs->st_size, MADV_SEQUENTIAL); + /* Not implemented yet... + madvise((caddr_t) p, fs->st_size, MADV_SEQUENTIAL); + */ if (write(to_fd, p, fs->st_size) != fs->st_size) err("%s: %s", to.p_path, strerror(errno)); - munmap((caddr_t) p, fs->st_size); + if (munmap((caddr_t) p, fs->st_size) < 0) + err("%s: %s", from.p_path, strerror(errno)); } else { while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) { wcount = write(to_fd, buf, rcount); diff --git a/bin/csh/glob.c b/bin/csh/glob.c index 3947275c194d..7a3d21eb4231 100644 --- a/bin/csh/glob.c +++ b/bin/csh/glob.c @@ -354,7 +354,7 @@ static Char ** libglob(vl) Char **vl; { - int gflgs = GLOB_QUOTE | GLOB_NOCHECK; + int gflgs = GLOB_QUOTE | GLOB_NOCHECK, badmagic = 0, goodmagic = 0; glob_t globv; char *ptr; @@ -377,12 +377,21 @@ libglob(vl) } if (!nonomatch && (globv.gl_matchc == 0) && (globv.gl_flags & GLOB_MAGCHAR)) { - globfree(&globv); - return (NULL); - } + badmagic = 1; + globv.gl_pathc--; + free(globv.gl_pathv[globv.gl_pathc]); + globv.gl_pathv[globv.gl_pathc] = (char *)0; + } else + if (!nonomatch && (globv.gl_matchc > 0) && + (globv.gl_flags & GLOB_MAGCHAR)) + goodmagic = 1; gflgs |= GLOB_APPEND; } while (*++vl); + if (badmagic && !goodmagic) { + globfree(&globv); + return (NULL); + } vl = blk2short(globv.gl_pathv); globfree(&globv); return (vl); diff --git a/bin/date/date.1 b/bin/date/date.1 index 56b7233ceaed..e6a9ccc3ff78 100644 --- a/bin/date/date.1 +++ b/bin/date/date.1 @@ -218,4 +218,4 @@ will be running on The .Nm date command is expected to be compatible with -.St p1003.2 . +.St -p1003.2 . diff --git a/bin/df/df.c b/bin/df/df.c index 5fe225d8e1c7..a28a862cc09b 100644 --- a/bin/df/df.c +++ b/bin/df/df.c @@ -1,4 +1,13 @@ /* + * Copyright (c) UNIX System Laboratories, Inc. All or some portions + * of this file are derived from material licensed to the + * University of California by American Telephone and Telegraph Co. + * or UNIX System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * $Id: df.c,v 1.3.2.2 1994/05/04 07:35:01 rgrimes Exp $ + */ +/* * Copyright (c) 1980, 1990 The Regents of the University of California. * All rights reserved. * @@ -199,9 +208,9 @@ prtstat(sfsp, maxwidth) used = sfsp->f_blocks - sfsp->f_bfree; availblks = sfsp->f_bavail + used; (void)printf(" %*ld %7ld %7ld", headerlen, - sfsp->f_blocks * sfsp->f_fsize / blocksize, - used * sfsp->f_fsize / blocksize, - sfsp->f_bavail * sfsp->f_fsize / blocksize); + (long)((double)sfsp->f_blocks * (double)sfsp->f_fsize / (double)blocksize), + (long)((double)used * (double)sfsp->f_fsize / (double)blocksize), + (long)((double)sfsp->f_bavail * (double)sfsp->f_fsize / (double)blocksize)); (void)printf(" %5.0f%%", availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0); if (iflag) { diff --git a/bin/domainname/domainname.c b/bin/domainname/domainname.c index 354421dda5cf..b480a28c2c3f 100644 --- a/bin/domainname/domainname.c +++ b/bin/domainname/domainname.c @@ -1,44 +1,83 @@ +/* + * Copyright (c) 1983, 1988 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. 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. + */ + +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + #ifndef lint -static char rcsid[] = "$Id: domainname.c,v 1.2 1993/10/25 03:12:32 rgrimes Exp $"; +static char sccsid1[] = "From@(#)hostname.c 5.4 (Berkeley) 5/31/90"; +static char sccsid2[] = "From@(#)id.c 5.1 (Berkeley) 6/29/91"; +static char rcsid[] = "$Id: domainname.c,v 1.3 1994/02/22 21:54:03 nate Exp $ +"; #endif /* not lint */ #include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> #include <sys/param.h> +#include <unistd.h> +#include <stdlib.h> + -static void usage __P((void)); +void usage __P((void)); -main(argc, argv) +main(argc,argv) int argc; char **argv; { - char dom[MAXHOSTNAMELEN]; + char domainname[MAXHOSTNAMELEN]; - if( argc>2 ) { - usage (); - /* NOTREACHED */ - } + if (argc > 2) + usage(); - if( argc==2 ) { - if( setdomainname(argv[1], strlen(argv[1])+1) == -1) { + if (argc == 2) { + if (setdomainname(argv[1], (strlen(argv[1]) + 1))) { perror("setdomainname"); exit(1); } } else { - if( getdomainname(dom, sizeof(dom)) == -1) { + if (getdomainname(domainname, sizeof(domainname))) { perror("getdomainname"); exit(1); } - printf("%s\n", dom); + printf("%s\n", domainname); } - exit(0); } -static void -usage () +void +usage() { (void)fprintf(stderr, "usage: domainname [name-of-domain]\n"); exit(1); diff --git a/bin/ed/Makefile b/bin/ed/Makefile index 5a6a4ea4aee8..a99763cc9202 100644 --- a/bin/ed/Makefile +++ b/bin/ed/Makefile @@ -1,8 +1,7 @@ PROG= ed -CFLAGS+=-DVI_BANG -SRCS= ed.c re.c buf.c cbc.c -LINKS= ${BINDIR}/ed ${BINDIR}/red -MLINKS= ed.1 red.1 +SRCS= buf.c cbc.c glob.c io.c main.c re.c sub.c undo.c +LINKS= ${BINDIR}/ed ${BINDIR}/red +MLINKS= ed.1 red.1 .if exists(/usr/lib/libcrypt.a) CFLAGS+=-DDES @@ -10,7 +9,4 @@ LDADD+= -lcrypt DPADD+= ${LIBCRYPT} .endif -LDADD+= -lgnuregex -DPADD+= /usr/lib/libgnuregex.a - .include <bsd.prog.mk> diff --git a/bin/ed/POSIX b/bin/ed/POSIX index 47a80b9e72a0..e724c12a2e3b 100644 --- a/bin/ed/POSIX +++ b/bin/ed/POSIX @@ -1,62 +1,101 @@ -This version of ed is not strictly POSIX compliant, as described in the -POSIX 1003.2 Draft 11.2 document. BSD commands have been implemented -wherever they do not conflict with the POSIX standard. For backwards -compatibility, the POSIX rule that says a range of addresses cannot be -used where only a single address is expected has been relaxed. - -The BSD commands included are: - 1) `s' (i.e., s[rgp]*) to repeat a previous substitution, - 2) `W' for appending text to an existing file, - 3) `wq' for exiting after a write, and - 4) `z' for scrolling through the buffer. -BSD line addressing syntax (i.e., `^' and `%'). is also recognized. - -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 (\). - -If crypt is available, files can be read and written using DES encryption. -The `x' command prompts the user to enter a key used for encrypting/ -decrypting subsequent reads and writes. If only a newline is entered as -the key, then encryption is disabled. Otherwise, a key is read in the -same manner as a password entry. The key remains in effect until -encryption is disabled. For more information on the encryption algorithm, -see the bdes(1) man page. Encryption/decryption should be fully compatible -with SunOS DES. - -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. - -The vi editor's bang command syntax is supported, i.e., -(addr1,addr2) !<shell-cmd> replaces the addressed lines with the output of - the command <shell-cmd>. -[rwe] !! reads/writes/edits the previous !<shell-cmd>. - -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. - -ed runs in restricted mode if invoked as red. This limits editing of -files in the local directory only and prohibits !<shell-cmd> commands. - -Though ed is not a binary editor, it can be used (if painfully) to edit -binary files. To assist in binary editing, when a file containing at -least one ASCII NUL character is written, a newline is not appended -if it did not already contain one upon reading. - -Since the behavior of `u' (undo) within a `g' (global) command list is -not specified by POSIX D11/2, it follows the behavior of the SunOS ed -(this is the best way, I think, in that the alternatives are either too -complicated to implement or too confusing to use): undo forces a global -command list to be executed only once, rather than for each line matching -a global pattern. In addtion, each instance of `u' within a global command -undoes all previous commands (including undo's) in the command list. - -The `m' (move) command within a `g' command list also follows the SunOS -ed implementation: any moved lines are removed from the global command's -`active' list. +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 occurences of either `censor1' or `censor2' might be + written as: + ed - file <<EOF + 1g/.*/u\ + ,s/censor1//g\ + ,s/censor2//g + ... + +3) The `m' (move) command within a `g' command list also follows the SunOS + ed implementation: any moved lines are removed from the global command's + `active' list. + +4) If ed is invoked with a name argument prefixed by a bang (!), then the + remainder of the argument is interpreted as a shell command. To invoke + ed on a file whose name starts with bang, prefix the name with a + backslash. diff --git a/bin/ed/README b/bin/ed/README index 06e302d7b116..c600c2739498 100644 --- a/bin/ed/README +++ b/bin/ed/README @@ -3,13 +3,14 @@ any regular expression package that conforms to the POSIX interface standard, such as GNU regex(3). If reliable signals are supported (e.g., POSIX sigaction(2)), it should -compile with little trouble. Otherwise, the macros spl1() and spl0() +compile with little trouble. Otherwise, the macros SPL1() and SPL0() should be redefined to disable interrupts. The following compiler directives are recognized: -DES - use to add encryption support (requires crypt(3)) -NO_REALLOC_NULL - use if realloc(3) does not accept a NULL pointer -BACKWARDS - use for backwards compatibility +DES - to add encryption support (requires crypt(3)) +NO_REALLOC_NULL - if realloc(3) does not accept a NULL pointer +BACKWARDS - for backwards compatibility +NEED_INSQUE - if insque(3) is missing The file `POSIX' describes extensions to and deviations from the POSIX standard. diff --git a/bin/ed/buf.c b/bin/ed/buf.c index 7c92e5586269..f5b8045ebb3b 100644 --- a/bin/ed/buf.c +++ b/bin/ed/buf.c @@ -1,12 +1,9 @@ /* buf.c: This file contains the scratch-file buffer rountines for the ed line editor. */ /*- - * Copyright (c) 1992 The Regents of the University of California. + * Copyright (c) 1993 Andrew Moore, Talke Studio. * All rights reserved. * - * This code is derived from software contributed to Berkeley by - * Rodney Ruddock of the University of Guelph. - * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -15,18 +12,11 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -35,37 +25,32 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ - #ifndef lint -static char sccsid[] = "@(#)buf.c 5.5 (Berkeley) 3/28/93"; +static char *rcsid = "@(#)$Id: buf.c,v 1.4 1994/02/01 00:34:35 alm Exp $"; #endif /* not lint */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> #include <sys/file.h> -#include <unistd.h> #include "ed.h" -extern char errmsg[]; FILE *sfp; /* scratch file pointer */ -char *sfbuf = NULL; /* scratch file input buffer */ -int sfbufsz = 0; /* scratch file input buffer size */ off_t sfseek; /* scratch file position */ int seek_write; /* seek before writing */ -line_t line0; /* initial node of line queue */ +line_t buffer_head; /* incore buffer */ -/* gettxt: get a line of text from the scratch file; return pointer +/* get_sbuf_line: get a line of text from the scratch file; return pointer to the text */ char * -gettxt(lp) +get_sbuf_line(lp) line_t *lp; { + static char *sfbuf = NULL; /* buffer */ + static int sfbufsz = 0; /* buffer size */ + int len, ct; - if (lp == &line0) + if (lp == &buffer_head) return NULL; seek_write = 1; /* force seek on write */ /* out of position */ @@ -77,8 +62,8 @@ gettxt(lp) return NULL; } } - len = lp->len & ~ACTV; - CKBUF(sfbuf, sfbufsz, len + 1, NULL); + len = lp->len; + REALLOC(sfbuf, sfbufsz, len + 1, NULL); if ((ct = fread(sfbuf, sizeof(char), len, sfp)) < 0 || ct != len) { fprintf(stderr, "%s\n", strerror(errno)); sprintf(errmsg, "cannot read temp file"); @@ -90,13 +75,10 @@ gettxt(lp) } -extern long curln; -extern long lastln; - -/* puttxt: write a line of text to the scratch file and add a line node +/* put_sbuf_line: write a line of text to the scratch file and add a line node to the editor buffer; return a pointer to the end of the text */ char * -puttxt(cs) +put_sbuf_line(cs) char *cs; { line_t *lp; @@ -115,7 +97,7 @@ puttxt(cs) sprintf(errmsg, "line too long"); return NULL; } - len = (s - cs) & ~ACTV; + len = s - cs; /* out of position */ if (seek_write) { if (fseek(sfp, 0L, SEEK_END) < 0) { @@ -126,7 +108,7 @@ puttxt(cs) sfseek = ftell(sfp); seek_write = 0; } - /* assert: spl1() */ + /* assert: SPL1() */ if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) { sfseek = -1; fprintf(stderr, "%s\n", strerror(errno)); @@ -135,37 +117,37 @@ puttxt(cs) } lp->len = len; lp->seek = sfseek; - lpqueue(lp); + add_line_node(lp); sfseek += len; /* update file position */ return ++s; } -/* lpqueue: add a line node in the editor buffer after the current line */ +/* add_line_node: add a line node in the editor buffer after the current line */ void -lpqueue(lp) +add_line_node(lp) line_t *lp; { line_t *cp; - cp = getlp(curln); /* this getlp last! */ - insqueue(lp, cp); - lastln++; - curln++; + cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */ + insque(lp, cp); + addr_last++; + current_addr++; } -/* getaddr: return line number of pointer */ +/* get_line_node_addr: return line number of pointer */ long -getaddr(lp) +get_line_node_addr(lp) line_t *lp; { - line_t *cp = &line0; + line_t *cp = &buffer_head; long n = 0; - while (cp != lp && (cp = cp->next) != &line0) + while (cp != lp && (cp = cp->q_forw) != &buffer_head) n++; - if (n && cp == &line0) { + if (n && cp == &buffer_head) { sprintf(errmsg, "invalid address"); return ERR; } @@ -173,43 +155,47 @@ getaddr(lp) } -/* getlp: return pointer to a line node in the editor buffer */ +/* get_addressed_line_node: return pointer to a line node in the editor buffer */ line_t * -getlp(n) +get_addressed_line_node(n) long n; { - static line_t *lp = &line0; + static line_t *lp = &buffer_head; static long on = 0; - spl1(); + SPL1(); if (n > on) - if (n <= (on + lastln) >> 1) + if (n <= (on + addr_last) >> 1) for (; on < n; on++) - lp = lp->next; + lp = lp->q_forw; else { - lp = line0.prev; - for (on = lastln; on > n; on--) - lp = lp->prev; + lp = buffer_head.q_back; + for (on = addr_last; on > n; on--) + lp = lp->q_back; } else if (n >= on >> 1) for (; on > n; on--) - lp = lp->prev; + lp = lp->q_back; else { - lp = &line0; + lp = &buffer_head; for (on = 0; on < n; on++) - lp = lp->next; + lp = lp->q_forw; } - spl0(); + SPL0(); return lp; } +extern int newline_added; + char sfn[15] = ""; /* scratch file name */ -/* sbopen: open scratch file */ -sbopen() +/* open_sbuf: open scratch file */ +int +open_sbuf() { + isbinary = newline_added = 0; strcpy(sfn, "/tmp/ed.XXXXXX"); if (mktemp(sfn) == NULL || (sfp = fopen(sfn, "w+")) == NULL) { fprintf(stderr, "%s: %s\n", sfn, strerror(errno)); @@ -220,8 +206,9 @@ sbopen() } -/* sbclose: close scratch file */ -sbclose() +/* close_sbuf: close scratch file */ +int +close_sbuf() { if (sfp) { if (fclose(sfp) < 0) { @@ -237,7 +224,7 @@ sbclose() } -/* quit: remove scratch file and exit */ +/* quit: remove_lines scratch file and exit */ void quit(n) int n; @@ -252,23 +239,30 @@ quit(n) unsigned char ctab[256]; /* character translation table */ -/* init_buf: open scratch buffer; initialize line queue */ +/* init_buffers: open scratch buffer; initialize line queue */ void -init_buf() +init_buffers() { int i = 0; - if (sbopen() < 0) + /* Read stdin one character at a time to avoid i/o contention + with shell escapes invoked by nonterminal input, e.g., + ed - <<EOF + !cat + hello, world + EOF */ + setbuffer(stdin, stdinbuf, 1); + if (open_sbuf() < 0) quit(2); - requeue(&line0, &line0); + REQUE(&buffer_head, &buffer_head); for (i = 0; i < 256; i++) ctab[i] = i; } -/* translit: translate characters in a string */ +/* translit_text: translate characters in a string */ char * -translit(s, len, from, to) +translit_text(s, len, from, to) char *s; int len; int from; diff --git a/bin/ed/cbc.c b/bin/ed/cbc.c index 95ce63cd2967..9d1d9894583e 100644 --- a/bin/ed/cbc.c +++ b/bin/ed/cbc.c @@ -1,14 +1,10 @@ /* cbc.c: This file contains the encryption routines for the ed line editor */ /*- - * Copyright (c) 1991 The Regents of the University of California. + * Copyright (c) 1993 The Regents of the University of California. * All rights reserved. * - * This code is derived from software contributed to Berkeley by - * Matt Bishop of Dartmouth College. - * - * The United States Government has rights in this work pursuant - * to contract no. NAG 2-680 between the National Aeronautics and - * Space Administration and Dartmouth College. + * Copyright (c) 1993 Andrew Moore, Talke Studio. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,37 +33,22 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * from: @(#)bdes.c 5.5 (Berkeley) 6/27/91 */ #ifndef lint -static char sccsid[] = "@(#)cbc.c 5.5 (Berkeley) 6/27/91"; +static char *rcsid = "@(#)$Id: cbc.c,v 1.2 1994/02/01 00:34:36 alm Exp $"; #endif /* not lint */ -/* Author: Matt Bishop - * Department of Mathematics and Computer Science - * Dartmouth College - * Hanover, NH 03755 - * Email: Matt.Bishop@dartmouth.edu - * ...!decvax!dartvax!Matt.Bishop - * - * See Technical Report PCS-TR91-158, Department of Mathematics and Computer - * Science, Dartmouth College, for a detailed description of the implemen- - * tation and differences between it and Sun's. The DES is described in - * FIPS PUB 46, and the modes in FIPS PUB 81 (see either the manual page - * or the technical report for a complete reference). - */ - +#include <sys/types.h> +#include <ctype.h> #include <errno.h> #include <pwd.h> -#include <unistd.h> -#include <stdio.h> -#include <ctype.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> #include "ed.h" + /* * Define a divisor for rand() that yields a uniform distribution in the * range 0-255. @@ -76,7 +57,7 @@ static char sccsid[] = "@(#)cbc.c 5.5 (Berkeley) 6/27/91"; /* * BSD and System V systems offer special library calls that do - * block moves and fills, so if possible we take advantage of them + * block move_liness and fills, so if possible we take advantage of them */ #define MEMCPY(dest,src,len) memcpy((dest),(src),(len)) #define MEMZERO(dest,len) memset((dest), 0, (len)) @@ -84,10 +65,10 @@ static char sccsid[] = "@(#)cbc.c 5.5 (Berkeley) 6/27/91"; /* Hide the calls to the primitive encryption routines. */ #define DES_KEY(buf) \ if (des_setkey(buf)) \ - err("des_setkey"); + des_error("des_setkey"); #define DES_XFORM(buf) \ if (des_cipher(buf, buf, 0L, (inverse ? -1 : 1))) \ - err("des_cipher"); + des_error("des_cipher"); /* * read/write - no error checking @@ -119,14 +100,14 @@ char bits[] = { /* used to extract bits from a char */ }; int pflag; /* 1 to preserve parity bits */ -char des_buf[8]; /* shared buffer for desgetc/desputc */ -int des_ct = 0; /* count for desgetc/desputc */ -int des_n = 0; /* index for desputc/desgetc */ +unsigned char des_buf[8]; /* shared buffer for get_des_char/put_des_char */ +int des_ct = 0; /* count for get_des_char/put_des_char */ +int des_n = 0; /* index for put_des_char/get_des_char */ -/* desinit: initialize DES */ +/* init_des_cipher: initialize DES */ void -desinit() +init_des_cipher() { #ifdef DES int i; @@ -144,28 +125,30 @@ desinit() } -/* desgetc: return next char in an encrypted file */ -desgetc(fp) +/* get_des_char: return next char in an encrypted file */ +int +get_des_char(fp) FILE *fp; { #ifdef DES if (des_n >= des_ct) { des_n = 0; - des_ct = cbcdec(des_buf, fp); + des_ct = cbc_decode(des_buf, fp); } return (des_ct > 0) ? des_buf[des_n++] : EOF; #endif } -/* desputc: write a char to an encrypted file; return char written */ -desputc(c, fp) +/* put_des_char: write a char to an encrypted file; return char written */ +int +put_des_char(c, fp) int c; FILE *fp; { #ifdef DES if (des_n == sizeof des_buf) { - des_ct = cbcenc(des_buf, des_n, fp); + des_ct = cbc_encode(des_buf, des_n, fp); des_n = 0; } return (des_ct >= 0) ? (des_buf[des_n++] = c) : EOF; @@ -173,16 +156,17 @@ desputc(c, fp) } -/* desflush: flush an encrypted file's output; return status */ -desflush(fp) +/* flush_des_file: flush an encrypted file's output; return status */ +int +flush_des_file(fp) FILE *fp; { #ifdef DES if (des_n == sizeof des_buf) { - des_ct = cbcenc(des_buf, des_n, fp); + des_ct = cbc_encode(des_buf, des_n, fp); des_n = 0; } - return (des_ct >= 0 && cbcenc(des_buf, des_n, fp) >= 0) ? 0 : EOF; + return (des_ct >= 0 && cbc_encode(des_buf, des_n, fp) >= 0) ? 0 : EOF; #endif } @@ -190,7 +174,8 @@ desflush(fp) /* * get keyword from tty or stdin */ -getkey() +int +get_keyword() { register char *p; /* used to obtain the key */ Desbuf msgbuf; /* I/O buffer */ @@ -203,9 +188,9 @@ getkey() /* * copy it, nul-padded, into the key area */ - cvtkey(BUFFER(msgbuf), p); + expand_des_key(BUFFER(msgbuf), p); MEMZERO(p, _PASSWORD_LEN); - makekey(msgbuf); + set_des_key(msgbuf); MEMZERO(msgbuf, sizeof msgbuf); return 1; } @@ -213,13 +198,11 @@ getkey() } -extern char errmsg[]; - /* * print a warning message and, possibly, terminate */ void -err(s) +des_error(s) char *s; /* the message */ { (void)sprintf(errmsg, "%s", s ? s : strerror(errno)); @@ -228,7 +211,8 @@ err(s) /* * map a hex character to an integer */ -tobinhex(c, radix) +int +hex_to_binary(c, radix) int c; /* char to be converted */ int radix; /* base (2 to 16) */ { @@ -260,7 +244,7 @@ tobinhex(c, radix) * convert the key to a bit pattern */ void -cvtkey(obuf, ibuf) +expand_des_key(obuf, ibuf) char *obuf; /* bit pattern */ char *ibuf; /* the key itself */ { @@ -276,8 +260,8 @@ cvtkey(obuf, ibuf) * now translate it, bombing on any illegal hex digit */ for (i = 0; ibuf[i] && i < 16; i++) - if ((nbuf[i] = tobinhex((int) ibuf[i], 16)) == -1) - err("bad hex digit in key"); + if ((nbuf[i] = hex_to_binary((int) ibuf[i], 16)) == -1) + des_error("bad hex digit in key"); while (i < 16) nbuf[i++] = 0; for (i = 0; i < 8; i++) @@ -296,8 +280,8 @@ cvtkey(obuf, ibuf) * now translate it, bombing on any illegal binary digit */ for (i = 0; ibuf[i] && i < 16; i++) - if ((nbuf[i] = tobinhex((int) ibuf[i], 2)) == -1) - err("bad binary digit in key"); + if ((nbuf[i] = hex_to_binary((int) ibuf[i], 2)) == -1) + des_error("bad binary digit in key"); while (i < 64) nbuf[i++] = 0; for (i = 0; i < 8; i++) @@ -328,7 +312,7 @@ cvtkey(obuf, ibuf) * DES ignores the low order bit of each character. */ void -makekey(buf) +set_des_key(buf) Desbuf buf; /* key block */ { register int i, j; /* counter in a for loop */ @@ -357,7 +341,8 @@ makekey(buf) /* * This encrypts using the Cipher Block Chaining mode of DES */ -cbcenc(msgbuf, n, fp) +int +cbc_encode(msgbuf, n, fp) char *msgbuf; int n; FILE *fp; @@ -395,7 +380,8 @@ cbcenc(msgbuf, n, fp) /* * This decrypts using the Cipher Block Chaining mode of DES */ -cbcdec(msgbuf, fp) +int +cbc_decode(msgbuf, fp) char *msgbuf; /* I/O buffer */ FILE *fp; /* input file descriptor */ { @@ -419,7 +405,7 @@ cbcdec(msgbuf, fp) if ((c = fgetc(fp)) == EOF) { n = CHAR(msgbuf, 7); if (n < 0 || n > 7) { - err("decryption failed (block corrupted)"); + des_error("decryption failed (block corrupted)"); return EOF; } } else @@ -427,9 +413,9 @@ cbcdec(msgbuf, fp) return n; } if (n > 0) - err("decryption failed (incomplete block)"); + des_error("decryption failed (incomplete block)"); else if (n < 0) - err("cannot read file"); + des_error("cannot read file"); return EOF; } #endif /* DES */ diff --git a/bin/ed/ed.1 b/bin/ed/ed.1 index e9a318080b39..f7f468304ffb 100644 --- a/bin/ed/ed.1 +++ b/bin/ed/ed.1 @@ -1,20 +1,21 @@ .TH ED 1 "21 May 1993" .SH NAME -ed, red \- text editor +.\" ed, red \- text editor +ed \- text editor .SH SYNOPSIS ed [-] [-sx] [-p \fIstring\fR] [\fIfile\fR] -.LP -red [-] [-sx] [-p \fIstring\fR] [\fIfile\fR] +.\" .LP +.\" red [-] [-sx] [-p \fIstring\fR] [\fIfile\fR] .SH DESCRIPTION .B ed is a line-oriented text editor. It is used to create, display, modify and otherwise manipulate text files. -.B red -is a restricted -.BR ed : -it can only edit files in the current -directory and cannot execute shell commands. +.\" .B red +.\" is a restricted +.\" .BR ed : +.\" it can only edit files in the current +.\" directory and cannot execute shell commands. If invoked with a .I file @@ -45,7 +46,7 @@ A typical command might look like: ,s/\fIold\fR/\fInew\fR/g .RE .sp -which replaces all occurences of the string +which replaces all occurrences of the string .I old with .IR new . @@ -134,7 +135,7 @@ The default filename is set to only if it is not prefixed with a bang. .SS LINE ADDRESSING -An address represents the number of line in the buffer. +An address represents the number of a line in the buffer. .B ed maintains a .I current address @@ -165,25 +166,26 @@ and is legal wherever it makes sense. An address range is two addresses separated either by a comma or semi-colon. The value of the first address in a range cannot exceed the -value of the the second. If an +value of the the second. If only one address is given in a range, then +the second address is set to the given address. If an .IR n- tuple of addresses is given where .I n > 2, -then the corresponding range is determined by the last two addresses -in the +then the corresponding range is determined by the last two addresses in +the .IR n- tuple. -If only one address is expected, then the last -address is used. +If only one address is expected, then the last address is used. Each address in a comma-delimited range is interpreted relative to the current address. In a semi-colon-delimited range, the first address is used to set the current address, and the second address is interpreted relative to the first. + The following address symbols are recognized. .TP 8 -\fR.\fR +\&. The current line (address) in the buffer. .TP 8 @@ -511,7 +513,9 @@ The current address is set to the last line read. .RI e \ !command Edits the standard output of .IR `!command' , -executed as described below. +(see +.RI ! command +below). The default filename is unchanged. Any lines in the buffer are deleted before the output of .I command @@ -629,6 +633,12 @@ deleted or otherwise modified. .TP 8 (.,.)l Prints the addressed lines unambiguously. +If a single line fills for than one screen (as might be the case +when viewing a binary file, for instance), a `--More--' +prompt is printed on the last line. +.B ed +waits until the RETURN key is pressed +before displaying the next screen. The current address is set to the last line printed. @@ -689,7 +699,9 @@ Reads to after the addressed line the standard output of .IR `!command' , -executed as described below. +(see the +.RI ! command +below). The default filename is unchanged. The current address is set to the last line read. @@ -707,14 +719,14 @@ matching a regular expression with .IR replacement . By default, only the first match in each line is replaced. -The +If the .I `g' -(global) suffix causes every match to be replaced. +(global) suffix is given, then every match to be replaced. The .I `n' suffix, where .I n -is a postive number, causes only the +is a positive number, causes only the .IR n th match to be replaced. It is an error if no substitutions are performed on any of the addressed @@ -724,7 +736,10 @@ The current address is set the last line affected. .I re and .I replacement -may be delimited by any character other than space and newline. +may be delimited by any character other than space and newline +(see the +.I `s' +command below). If one or two of the last delimiters is omitted, then the last line affected is printed as though the print suffix .I `p' @@ -755,12 +770,18 @@ if they are escaped with a backslash (\\). Repeats the last substitution. This form of the .I `s' -command may be suffixed with -any combination of the characters +command accepts a count suffix +.IR `n' , +or any combination of the characters .IR `r' , .IR `g' , and .IR `p' . +If a count suffix +.I `n' +is given, then only the +.IR n th +match is replaced. The .I `r' suffix causes @@ -840,7 +861,9 @@ command. .RI (1,$)w \ !command Writes the addressed lines to the standard input of .IR `!command' , -executed as described below. +(see the +.RI ! command +below). The default filename and current address are unchanged. .TP 8 @@ -891,13 +914,6 @@ is printed to the standard output. The current line is unchanged. .TP 8 -.RI (.,.)! command -Replaces the addressed lines with the output of -.I `!command' -as described above. -The current address is set to the last line read. - -.TP 8 ($)= Prints the line number of the addressed line. diff --git a/bin/ed/ed.c b/bin/ed/ed.c deleted file mode 100644 index 180232770d82..000000000000 --- a/bin/ed/ed.c +++ /dev/null @@ -1,2206 +0,0 @@ -/* ed.c: This file contains the main control and user-interface routines - for the ed line editor. */ -/*- - * Copyright (c) 1993 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley - * by Andrew Moore, Talke Studio. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 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. - */ -/*- - * Kernighan/Plauger, "Software Tools in Pascal," (c) 1981 by - * Addison-Wesley Publishing Company, Inc. Reprinted with permission of - * the publisher. - */ - -#ifndef lint -char copyright1[] = -"@(#) Copyright (c) 1993 The Regents of the University of California.\n\ - All rights reserved.\n"; -char copyright2[] = -"@(#) Kernighan/Plauger, Software Tools in Pascal, (c) 1981 by\n\ - Addison-Wesley Publishing Company, Inc. Reprinted with permission of\n\ - the publisher.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)ed.c 5.5 (Berkeley) 3/28/93"; -#endif /* not lint */ - -/* - * CREDITS - * The buf.c algorithm is attributed to Rodney Ruddock of - * the University of Guelph, Guelph, Ontario. - * - * The cbc.c encryption code is adapted from - * the bdes program by Matt Bishop of Dartmouth College, - * Hanover, NH. - * - * Addison-Wesley Publishing Company generously granted - * permission to distribute this program over Internet. - * - */ - -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <setjmp.h> -#include <pwd.h> -#include <sys/ioctl.h> - -#include "ed.h" - -#ifdef _POSIX_SOURCE -sigjmp_buf env; -#else -jmp_buf env; -#endif - -/* static buffers */ -char *shcmd; /* shell command buffer */ -int shcmdsz; /* shell command buffer size */ -int shcmdi; /* shell command buffer index */ -char *cvbuf; /* global command buffer */ -int cvbufsz; /* global command buffer size */ -char *lhbuf; /* lhs buffer */ -int lhbufsz; /* lhs buffer size */ -char *rhbuf; /* rhs buffer */ -int rhbufsz; /* rhs buffer size */ -int rhbufi; /* rhs buffer index */ -char *rbuf; /* regsub buffer */ -int rbufsz; /* regsub buffer size */ -char *sbuf; /* file i/o buffer */ -int sbufsz; /* file i/o buffer size */ -char *ibuf; /* ed command-line buffer */ -int ibufsz; /* ed command-line buffer size */ -char *ibufp; /* pointer to ed command-line buffer */ - -/* global flags */ -int isbinary; /* if set, buffer contains ASCII NULs */ -int modified; /* if set, buffer modified since last write */ -int garrulous = 0; /* if set, print all error messages */ -int scripted = 0; /* if set, suppress diagnostics */ -int des = 0; /* if set, use crypt(3) for i/o */ -int mutex = 0; /* if set, signals set "sigflags" */ -int sigflags = 0; /* if set, signals received while mutex set */ -int sigactive = 0; /* if set, signal handlers are enabled */ -int red = 0; /* if set, restrict shell/directory access */ - -char dfn[MAXFNAME + 1] = ""; /* default filename */ -long curln; /* current address */ -long lastln; /* last address */ -int lineno; /* script line number */ -char *prompt; /* command-line prompt */ -char *dps = "*"; /* default command-line prompt */ - -char *usage = "usage: %s [-] [-sx] [-p string] [name]\n"; - -extern char errmsg[]; -extern int optind; -extern char *optarg; - -/* ed: line editor */ -main(argc, argv) - int argc; - char **argv; -{ - int c, n; - long status = 0; - - red = (n = strlen(argv[0])) > 2 && argv[0][n - 3] == 'r'; -top: - while ((c = getopt(argc, argv, "p:sx")) != EOF) - switch(c) { - case 'p': /* set prompt */ - prompt = optarg; - break; - case 's': /* run script */ - scripted = 1; - break; - case 'x': /* use crypt */ -#ifdef DES - des = getkey(); -#else - fprintf(stderr, "crypt unavailable\n?\n"); -#endif - break; - - default: - fprintf(stderr, usage, argv[0]); - exit(1); - } - argv += optind; - argc -= optind; - if (argc && **argv == '-') { - scripted = 1; - if (argc > 1) { - optind = 1; - goto top; - } - argv++; - argc--; - } - /* assert: reliable signals! */ -#ifdef SIGWINCH - dowinch(SIGWINCH); - if (isatty(0)) signal(SIGWINCH, dowinch); -#endif - signal(SIGHUP, onhup); - signal(SIGQUIT, SIG_IGN); - signal(SIGINT, onintr); -#ifdef _POSIX_SOURCE - if (status = sigsetjmp(env, 1)) -#else - if (status = setjmp(env)) -#endif - { - fputs("\n?\n", stderr); - sprintf(errmsg, "interrupt"); - } else { - init_buf(); - sigactive = 1; /* enable signal handlers */ - if (argc && **argv && ckfn(*argv)) { - if (doread(0, *argv) < 0 && !isatty(0)) - quit(2); - else if (**argv != '!') - strcpy(dfn, *argv); - } else if (argc) { - fputs("?\n", stderr); - if (**argv == '\0') - sprintf(errmsg, "invalid filename"); - if (!isatty(0)) - quit(2); - } - } - for (;;) { - if (status < 0 && garrulous) - fprintf(stderr, "%s\n", errmsg); - if (prompt) { - printf("%s", prompt); - fflush(stdout); - } - if ((n = getline()) < 0) { - status = ERR; - continue; - } else if (n == 0) { - if (modified && !scripted) { - fputs("?\n", stderr); - sprintf(errmsg, "warning: file modified"); - if (!isatty(0)) { - fprintf(stderr, garrulous ? "script, line %d: %s\n" - : "", lineno, errmsg); - quit(2); - } - clearerr(stdin); - modified = 0; - status = EMOD; - continue; - } else - quit(0); - } else if (ibuf[n - 1] != '\n') { - /* discard line */ - sprintf(errmsg, "unexpected end-of-file"); - clearerr(stdin); - status = ERR; - continue; - } - if ((n = getlist()) >= 0 && (status = ckglob()) != 0) { - if (status > 0 && (status = doglob(status)) >= 0) { - curln = status; - continue; - } - } else if ((status = n) >= 0 && (status = docmd(0)) >= 0) { - if (!status || status - && (status = doprint(curln, curln, status)) >= 0) - continue; - } - switch (status) { - case EOF: - quit(0); - case EMOD: - modified = 0; - fputs("?\n", stderr); /* give warning */ - sprintf(errmsg, "warning: file modified"); - if (!isatty(0)) { - fprintf(stderr, garrulous ? "script, line %d: %s\n" : "", lineno, errmsg); - quit(2); - } - break; - case FATAL: - if (!isatty(0)) - fprintf(stderr, garrulous ? "script, line %d: %s\n" : "", lineno, errmsg); - else - fprintf(stderr, garrulous ? "%s\n" : "", errmsg); - quit(3); - default: - fputs("?\n", stderr); - if (!isatty(0)) { - fprintf(stderr, garrulous ? "script, line %d: %s\n" : "", lineno, errmsg); - quit(2); - } - break; - } - } - /*NOTREACHED*/ -} - - -long line1, line2, nlines; - -/* getlist: get line numbers from the command buffer until an illegal - address is seen. return range status */ -getlist() -{ - long num; - - nlines = line2 = 0; - while ((num = getone()) >= 0) { - line1 = line2; - line2 = num; - nlines++; - if (*ibufp != ',' && *ibufp != ';') - break; - else if (*ibufp++ == ';') - curln = num; - } - nlines = min(nlines, 2); - if (nlines == 0) - line2 = curln; - if (nlines <= 1) - line1 = line2; - return (num == ERR) ? ERR : nlines; -} - - -/* getone: return the next line number in the command buffer */ -long -getone() -{ - int c; - long i, num; - - if ((num = getnum(1)) < 0) - return num; - for (;;) { - c = isspace(*ibufp); - skipblanks(); - c = c && isdigit(*ibufp); - if (!c && *ibufp != '+' && *ibufp != '-' && *ibufp != '^') - break; - c = c ? '+' : *ibufp++; - if ((i = getnum(0)) < 0) { - sprintf(errmsg, "invalid address"); - return i; - } - if (c == '+') - num += i; - else num -= i; - } - if (num > lastln || num < 0) { - sprintf(errmsg, "invalid address"); - return ERR; - } - return num; -} - - -/* getnum: return a relative line number from the command buffer */ -long -getnum(first) - int first; -{ - pattern_t *pat; - char c; - - skipblanks(); - if (isdigit(*ibufp)) - return strtol(ibufp, &ibufp, 10); - switch(c = *ibufp) { - case '.': - ibufp++; - return first ? curln : ERR; - case '$': - ibufp++; - return first ? lastln : ERR; - case '/': - case '?': - if ((pat = optpat()) == NULL) - return ERR; - else if (*ibufp == c) - ibufp++; - return first ? patscan(pat, (c == '/') ? 1 : 0) : ERR; - case '^': - case '-': - case '+': - return first ? curln : 1; - case '\'': - ibufp++; - return first ? getmark(*ibufp++) : ERR; - case '%': - case ',': - case ';': - if (first) { - ibufp++; - line2 = (c == ';') ? curln : 1; - nlines++; - return lastln; - } - return 1; - default: - return first ? EOF : 1; - } -} - - -/* 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 */ - - -/* VRFYCMD: verify the command suffix in the command buffer */ -#define VRFYCMD() { \ - int done = 0; \ - do { \ - switch(*ibufp) { \ - case 'p': \ - gflag |= GPR, ibufp++; \ - break; \ - case 'l': \ - gflag |= GLS, ibufp++; \ - break; \ - case 'n': \ - gflag |= GNP, ibufp++; \ - break; \ - default: \ - done++; \ - } \ - } while (!done); \ - if (*ibufp++ != '\n') { \ - sprintf(errmsg, "invalid command suffix"); \ - return ERR; \ - } \ -} - - -/* ckglob: set lines matching a pattern in the command buffer; return - global status */ -ckglob() -{ - pattern_t *pat; - char c, delim; - char *s; - int nomatch; - long n; - line_t *lp; - int gflag = 0; /* print suffix of interactive cmd */ - - if ((c = *ibufp) == 'V' || c == 'G') - gflag = GLB; - else if (c != 'g' && c != 'v') - return 0; - if (ckrange(1, lastln) < 0) - return ERR; - else if ((delim = *++ibufp) == ' ' || delim == '\n') { - sprintf(errmsg, "invalid pattern delimiter"); - return ERR; - } else if ((pat = optpat()) == NULL) - return ERR; - else if (*ibufp == delim) - ibufp++; - if (gflag) - VRFYCMD(); /* get print suffix */ - for (lp = getlp(n = 1); n <= lastln; n++, lp = lp->next) { - if ((s = gettxt(lp)) == NULL) - return ERR; - lp->len &= ~ACTV; /* zero ACTV bit */ - if (isbinary) - s = nultonl(s, lp->len & ~ACTV); - if (line1 <= n && n <= line2 - && (!(nomatch = regexec(pat, s, 0, NULL, 0)) - && (c == 'g' || c == 'G') - || nomatch && (c == 'v' || c == 'V'))) - lp->len |= ACTV; - } - return gflag | GSG; -} - - -/* doglob: apply command list in the command buffer to the active - lines in a range; return command status */ -long -doglob(gflag) - int gflag; -{ - static char *ocmd = NULL; - static int ocmdsz = 0; - - line_t *lp = NULL; - long lc; - int status; - int n; - int interact = gflag & ~GSG; /* GLB & gflag ? */ - char *cmd = NULL; - -#ifdef BACKWARDS - if (!interact) - if (!strcmp(ibufp, "\n")) - cmd = "p\n"; /* null cmd-list == `p' */ - else if ((cmd = getcmdv(&n, 0)) == NULL) - return ERR; -#else - if (!interact && (cmd = getcmdv(&n, 0)) == NULL) - return ERR; -#endif - ureset(); - for (;;) { - for (lp = getlp(lc = 1); lc <= lastln; lc++, lp = lp->next) - if (lp->len & ACTV) /* active line */ - break; - if (lc > lastln) - break; - lp->len ^= ACTV; /* zero ACTV bit */ - curln = lc; - if (interact) { - /* print curln and get a command in global syntax */ - if (doprint(curln, curln, 0) < 0) - return ERR; - while ((n = getline()) > 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 = getcmdv(&n, 0)) == NULL) - return ERR; - else { - CKBUF(ocmd, ocmdsz, n + 1, ERR); - memcpy(ocmd, cmd, n + 1); - cmd = ocmd; - } - - } - ibufp = cmd; - for (; *ibufp;) - if ((status = getlist()) < 0 - || (status = docmd(1)) < 0 - || (status > 0 - && (status = doprint(curln, curln, status)) < 0)) - return status; - } - return ((interact & ~GLB ) && doprint(curln, curln, interact) < 0) ? ERR : curln; -} - - -#ifdef BACKWARDS -/* GETLINE3: get a legal address from the command buffer */ -#define GETLINE3(num) \ -{ \ - long ol1, ol2; \ -\ - ol1 = line1, ol2 = line2; \ - if (getlist() < 0) \ - return ERR; \ - else if (nlines == 0) { \ - sprintf(errmsg, "destination expected"); \ - return ERR; \ - } else if (line2 < 0 || lastln < line2) { \ - sprintf(errmsg, "invalid address"); \ - return ERR; \ - } \ - num = line2; \ - line1 = ol1, line2 = ol2; \ -} -#else /* BACKWARDS */ -/* GETLINE3: get a legal address from the command buffer */ -#define GETLINE3(num) \ -{ \ - long ol1, ol2; \ -\ - ol1 = line1, ol2 = line2; \ - if (getlist() < 0) \ - return ERR; \ - if (line2 < 0 || lastln < line2) { \ - sprintf(errmsg, "invalid address"); \ - return ERR; \ - } \ - num = line2; \ - line1 = ol1, line2 = ol2; \ -} -#endif - -/* sgflags */ -#define SGG 001 /* complement previous global substitute suffix */ -#define SGP 002 /* complement previous print suffix */ -#define SGR 004 /* use last regex instead of last pat */ -#define SGF 010 /* newline found */ - -long ucurln = -1; /* if >= 0, undo enabled */ -long ulastln = -1; /* if >= 0, undo enabled */ -int patlock = 0; /* if set, pattern not released by optpat() */ - -long rows = 22; /* scroll length: ws_row - 2 */ - -/* docmd: execute the next command in command buffer; return print - request, if any */ -docmd(glob) - int glob; -{ - static pattern_t *pat = NULL; - static int sgflag = 0; - - pattern_t *tpat; - char *fnp; - int gflag = 0; - int sflags = 0; - long num = 0; - int n = 0; - int c; - - skipblanks(); - switch(c = *ibufp++) { - case 'a': - VRFYCMD(); - if (!glob) ureset(); - if (append(line2, glob) < 0) - return ERR; - break; - case 'c': - if (ckrange(curln, curln) < 0) - return ERR; - VRFYCMD(); - if (!glob) ureset(); - if (lndelete(line1, line2) < 0 || append(curln, glob) < 0) - return ERR; - break; - case 'd': - if (ckrange(curln, curln) < 0) - return ERR; - VRFYCMD(); - if (!glob) ureset(); - if (lndelete(line1, line2) < 0) - return ERR; - else if (nextln(curln, lastln) != 0) - curln = nextln(curln, lastln); - modified = 1; - break; - case 'e': - if (modified && !scripted) - return EMOD; - /* fall through */ - case 'E': - if (nlines > 0) { - sprintf(errmsg, "unexpected address"); - return ERR; - } else if (!isspace(*ibufp)) { - sprintf(errmsg, "unexpected command suffix"); - return ERR; - } else if ((fnp = getfn()) == NULL) - return ERR; - VRFYCMD(); - if (lndelete(1, lastln) < 0) - return ERR; - ureset(); - if (sbclose() < 0) - return ERR; - else if (sbopen() < 0) - return FATAL; - if (*fnp && *fnp != '!') strcpy(dfn, fnp); -#ifdef BACKWARDS - if (*fnp == '\0' && *dfn == '\0') { - sprintf(errmsg, "no current filename"); - return ERR; - } -#endif - if (doread(0, *fnp ? fnp : dfn) < 0) - return ERR; - ureset(); - modified = 0; - ucurln = ulastln = -1; - break; - case 'f': - if (nlines > 0) { - sprintf(errmsg, "unexpected address"); - return ERR; - } else if (!isspace(*ibufp)) { - sprintf(errmsg, "unexpected command suffix"); - return ERR; - } else if ((fnp = getfn()) == NULL) - return ERR; - else if (*fnp == '!') { - sprintf(errmsg, "invalid redirection"); - return ERR; - } - VRFYCMD(); - if (*fnp) strcpy(dfn, fnp); - printf("%s\n", esctos(dfn)); - break; - case 'g': - case 'G': - sprintf(errmsg, "cannot nest global commands"); - return ERR; - case 'h': - if (nlines > 0) { - sprintf(errmsg, "unexpected address"); - return ERR; - } - VRFYCMD(); - if (*errmsg) fprintf(stderr, "%s\n", errmsg); - break; - case 'H': - if (nlines > 0) { - sprintf(errmsg, "unexpected address"); - return ERR; - } - VRFYCMD(); - if ((garrulous = 1 - garrulous) && *errmsg) - fprintf(stderr, "%s\n", errmsg); - break; - case 'i': - if (line2 == 0) { - sprintf(errmsg, "invalid address"); - return ERR; - } - VRFYCMD(); - if (!glob) ureset(); - if (append(prevln(line2, lastln), glob) < 0) - return ERR; - break; - case 'j': - if (ckrange(curln, curln + 1) < 0) - return ERR; - VRFYCMD(); - if (!glob) ureset(); - if (line1 != line2 && join(line1, line2) < 0) - return ERR; - break; - case 'k': - c = *ibufp++; - if (line2 == 0) { - sprintf(errmsg, "invalid address"); - return ERR; - } - VRFYCMD(); - if (putmark(c, getlp(line2)) < 0) - return ERR; - break; - case 'l': - if (ckrange(curln, curln) < 0) - return ERR; - VRFYCMD(); - if (doprint(line1, line2, gflag | GLS) < 0) - return ERR; - gflag = 0; - break; - case 'm': - if (ckrange(curln, curln) < 0) - return ERR; - GETLINE3(num); - if (line1 <= num && num < line2) { - sprintf(errmsg, "invalid destination"); - return ERR; - } - VRFYCMD(); - if (!glob) ureset(); - if (move(num, glob) < 0) - return ERR; - else - modified = 1; - break; - case 'n': - if (ckrange(curln, curln) < 0) - return ERR; - VRFYCMD(); - if (doprint(line1, line2, gflag | GNP) < 0) - return ERR; - gflag = 0; - break; - case 'p': - if (ckrange(curln, curln) < 0) - return ERR; - VRFYCMD(); - if (doprint(line1, line2, gflag | GPR) < 0) - return ERR; - gflag = 0; - break; - case 'P': - if (nlines > 0) { - sprintf(errmsg, "unexpected address"); - return ERR; - } - VRFYCMD(); - prompt = prompt ? NULL : optarg ? optarg : dps; - break; - case 'q': - case 'Q': - if (nlines > 0) { - sprintf(errmsg, "unexpected address"); - return ERR; - } - VRFYCMD(); - gflag = (modified && !scripted && c == 'q') ? EMOD : EOF; - break; - case 'r': - if (!isspace(*ibufp)) { - sprintf(errmsg, "unexpected command suffix"); - return ERR; - } else if (nlines == 0) - line2 = lastln; - if ((fnp = getfn()) == NULL) - return ERR; - VRFYCMD(); - if (!glob) ureset(); - if (*dfn == '\0' && *fnp != '!') strcpy(dfn, fnp); -#ifdef BACKWARDS - if (*fnp == '\0' && *dfn == '\0') { - sprintf(errmsg, "no current filename"); - return ERR; - } -#endif - if ((num = doread(line2, *fnp ? fnp : dfn)) < 0) - return ERR; - else if (num && num != lastln) - modified = 1; - break; - case 's': - do { - switch(*ibufp) { - case '\n': - sflags |=SGF; - break; - case 'g': - sflags |= SGG; - ibufp++; - break; - case 'p': - sflags |= SGP; - ibufp++; - break; - case 'r': - sflags |= SGR; - ibufp++; - break; - default: - if (sflags) { - sprintf(errmsg, "invalid command suffix"); - return ERR; - } - } - } while (sflags && *ibufp != '\n'); - if (sflags && !pat) { - sprintf(errmsg, "no previous substitution"); - return ERR; - } else if (!(sflags & SGF)) - sgflag &= 0xff; - if (*ibufp != '\n' && *(ibufp + 1) == '\n') { - sprintf(errmsg, "invalid pattern delimiter"); - return ERR; - } - tpat = pat; - spl1(); - if ((!sflags || (sflags & SGR)) - && (tpat = optpat()) == NULL) - return ERR; - else if (tpat != pat) { - if (pat) { - regfree(pat); - free(pat); - } - pat = tpat; - patlock = 1; /* reserve pattern */ - } else if (pat == NULL) { - /* NOTREACHED */ - sprintf(errmsg, "no previous substitution"); - return ERR; - } - spl0(); - if (!sflags && (sgflag = getrhs(glob)) < 0) - return ERR; - else if (glob) - sgflag |= GLB; - else - sgflag &= ~GLB; - if (sflags & SGG) - sgflag ^= GSG; - if (sflags & SGP) - sgflag ^= GPR, sgflag &= ~(GLS | GNP); - do { - switch(*ibufp) { - case 'p': - sgflag |= GPR, ibufp++; - break; - case 'l': - sgflag |= GLS, ibufp++; - break; - case 'n': - sgflag |= GNP, ibufp++; - break; - default: - n++; - } - } while (!n); - if (ckrange(curln, curln) < 0) - return ERR; - VRFYCMD(); - if (!glob) ureset(); - if ((n = subst(pat, sgflag)) < 0) - return ERR; - else if (n) - modified = 1; - break; - case 't': - if (ckrange(curln, curln) < 0) - return ERR; - GETLINE3(num); - VRFYCMD(); - if (!glob) ureset(); - if (transfer(num) < 0) - return ERR; - modified = 1; - break; - case 'u': - if (nlines > 0) { - sprintf(errmsg, "unexpected address"); - return ERR; - } - VRFYCMD(); - if (undo(glob) < 0) - return ERR; - break; - case 'v': - case 'V': - sprintf(errmsg, "cannot nest global commands"); - return ERR; - case 'w': - case 'W': - if ((n = *ibufp) == 'q' || n == 'Q') { - gflag = EOF; - ibufp++; - } - if (!isspace(*ibufp)) { - sprintf(errmsg, "unexpected command suffix"); - return ERR; - } else if ((fnp = getfn()) == NULL) - return ERR; - if (nlines == 0 && !lastln) - line1 = line2 = 0; - else if (ckrange(1, lastln) < 0) - return ERR; - VRFYCMD(); - if (*dfn == '\0' && *fnp != '!') strcpy(dfn, fnp); -#ifdef BACKWARDS - if (*fnp == '\0' && *dfn == '\0') { - sprintf(errmsg, "no current filename"); - return ERR; - } -#endif - if ((num = dowrite(line1, line2, *fnp ? fnp : dfn, (c == 'W') ? "a" : "w")) < 0) - return ERR; - else if (num == lastln) - modified = 0; - else if (modified && !scripted && n == 'q') - gflag = EMOD; - break; - case 'x': - if (nlines > 0) { - sprintf(errmsg, "unexpected address"); - return ERR; - } - VRFYCMD(); -#ifdef DES - des = getkey(); -#else - sprintf(errmsg, "crypt unavailable"); - return ERR; -#endif - break; - case 'z': -#ifdef BACKWARDS - if (ckrange(line1 = 1, curln + 1) < 0) -#else - if (ckrange(line1 = 1, curln + !glob) < 0) -#endif - return ERR; - else if ('0' < *ibufp && *ibufp <= '9') - rows = strtol(ibufp, &ibufp, 10); - VRFYCMD(); - if (doprint(line2, min(lastln, line2 + rows - 1), gflag) < 0) - return ERR; - gflag = 0; - break; - case '=': - VRFYCMD(); - printf("%d\n", nlines ? line2 : lastln); - break; - case '!': -#ifndef VI_BANG - if (nlines > 0) { - sprintf(errmsg, "unexpected address"); - return ERR; - } -#endif - if ((sflags = getshcmd()) < 0) - return ERR; - VRFYCMD(); - if (sflags) printf("%s\n", shcmd + 1); -#ifdef VI_BANG - if (nlines == 0) { -#endif - system(shcmd + 1); - if (!scripted) printf("!\n"); - break; -#ifdef VI_BANG - } - if (!lastln && !line1 && !line2) { - if (!glob) ureset(); - } else if (ckrange(curln, curln) < 0) - return ERR; - else { - if (!glob) ureset(); - if (lndelete(line1, line2) < 0) - return ERR; - line2 = curln; - modified = 1; - } - if ((num = doread(line2, shcmd)) < 0) - return ERR; - else if (num && num != lastln) - modified = 1; - break; -#endif - case '\n': -#ifdef BACKWARDS - if (ckrange(line1 = 1, curln + 1) < 0 -#else - if (ckrange(line1 = 1, curln + !glob) < 0 -#endif - || doprint(line2, line2, 0) < 0) - return ERR; - break; - default: - sprintf(errmsg, "unknown command"); - return ERR; - } - return gflag; -} - - -/* ckrange: return status of line number range check */ -ckrange(def1, def2) - long def1, def2; -{ - if (nlines == 0) { - line1 = def1; - line2 = def2; - } - if (line1 > line2 || 1 > line1 || line2 > lastln) { - sprintf(errmsg, "invalid address"); - return ERR; - } - return 0; -} - - -/* patscan: return the number of the next line matching a pattern in a - given direction. wrap around begin/end of line queue if necessary */ -long -patscan(pat, dir) - pattern_t *pat; - int dir; -{ - char *s; - long n = curln; - line_t *lp; - - do { - if (n = dir ? nextln(n, lastln) : prevln(n, lastln)) { - if ((s = gettxt(lp = getlp(n))) == NULL) - return ERR; - if (isbinary) - s = nultonl(s, lp->len & ~ACTV); - if (!regexec(pat, s, 0, NULL, 0)) - return n; - } - } while (n != curln); - sprintf(errmsg, "no match"); - return ERR; -} - - -/* getfn: return pointer to copy of filename in the command buffer */ -char * -getfn() -{ - static char *file = NULL; - static int filesz = 0; - - int n; - - if (*ibufp != '\n') { - skipblanks(); - if (*ibufp == '\n') { - sprintf(errmsg, "invalid filename"); - return NULL; - } else if ((ibufp = getcmdv(&n, 1)) == NULL) - return NULL; -#ifdef VI_BANG - else if (*ibufp == '!') { - ibufp++; - if ((n = getshcmd()) < 0) - return NULL; - if (n) printf("%s\n", shcmd + 1); - return shcmd; - } -#endif - else if (n - 1 > MAXFNAME) { - sprintf(errmsg, "filename too long"); - return NULL; - } - } -#ifndef BACKWARDS - else if (*dfn == '\0') { - sprintf(errmsg, "no current filename"); - return NULL; - } -#endif - CKBUF(file, filesz, MAXFNAME + 1, NULL); - for (n = 0; *ibufp != '\n';) - file[n++] = *ibufp++; - file[n] = '\0'; - return ckfn(file); -} - - -/* getrhs: extract substitution template from the command buffer */ -getrhs(glob) - int glob; -{ - char delim; - - if ((delim = *ibufp) == '\n') { - rhbufi = 0; - return GPR; - } else if (makesub(glob) == NULL) - return ERR; - else if (*ibufp == '\n') - return GPR; - else if (*ibufp == delim) - ibufp++; - if ('1' <= *ibufp && *ibufp <= '9') - return (int) strtol(ibufp, &ibufp, 10) << 8; - else if (*ibufp == 'g') { - ibufp++; - return GSG; - } - return 0; -} - - -/* makesub: return pointer to copy of substitution template in the command - buffer */ -char * -makesub(glob) - int glob; -{ - int n = 0; - int i = 0; - char delim = *ibufp++; - char c; - - if (*ibufp == '%' && *(ibufp + 1) == delim) { - ibufp++; - if (!rhbuf) sprintf(errmsg, "no previous substitution"); - return rhbuf; - } - while (*ibufp != delim) { - CKBUF(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 (!glob) { - while ((n = getline()) == 0 - || n > 0 && ibuf[n - 1] != '\n') - clearerr(stdin); - if (n < 0) - return NULL; - } else - /*NOTREACHED*/ - ; - } - CKBUF(rhbuf, rhbufsz, i + 1, NULL); - rhbuf[rhbufi = i] = '\0'; - return rhbuf; -} - - -/* getshcmd: read a shell command up a maximum size from stdin; return - substitution status */ -int -getshcmd() -{ - static char *buf = NULL; - static int n = 0; - - char *s; /* substitution char pointer */ - int i = 0; - int j = 0; - - if (red) { - sprintf(errmsg, "shell access restricted"); - return ERR; - } else if ((s = ibufp = getcmdv(&j, 1)) == NULL) - return ERR; - CKBUF(buf, n, j + 1, ERR); - buf[i++] = '!'; /* prefix command w/ bang */ - while (*ibufp != '\n') - switch (*ibufp) { - default: - CKBUF(buf, n, i + 2, ERR); - buf[i++] = *ibufp; - if (*ibufp++ == '\\') - buf[i++] = *ibufp++; - break; - case '!': - if (s != ibufp) { - CKBUF(buf, n, i + 1, ERR); - buf[i++] = *ibufp++; - } -#ifdef BACKWARDS - else if (shcmd == NULL || *(shcmd + 1) == '\0') -#else - else if (shcmd == NULL) -#endif - { - sprintf(errmsg, "no previous command"); - return ERR; - } else { - CKBUF(buf, n, i + shcmdi, ERR); - for (s = shcmd + 1; s < shcmd + shcmdi;) - buf[i++] = *s++; - s = ibufp++; - } - break; - case '%': - if (*dfn == '\0') { - sprintf(errmsg, "no current filename"); - return ERR; - } - j = strlen(s = esctos(dfn)); - CKBUF(buf, n, i + j, ERR); - while (j--) - buf[i++] = *s++; - s = ibufp++; - break; - } - CKBUF(shcmd, shcmdsz, i + 1, ERR); - memcpy(shcmd, buf, i); - shcmd[shcmdi = i] = '\0'; - return *s == '!' || *s == '%'; -} - - -/* append: insert text from stdin to after line n; stop when either a - single period is read or EOF; return status */ -append(n, glob) - long n; - int glob; -{ - int l; - char *lp = ibuf; - char *eot; - undo_t *up = NULL; - - for (curln = n;;) { - if (!glob) { - if ((l = getline()) < 0) - return ERR; - else if (l == 0 || ibuf[l - 1] != '\n') { - clearerr(stdin); - return l ? EOF : 0; - } - lp = ibuf; - } else if (*(lp = ibufp) == '\0') - return 0; - else { - while (*ibufp++ != '\n') - ; - l = ibufp - lp; - } - if (l == 2 && lp[0] == '.' && lp[1] == '\n') { - return 0; - } - eot = lp + l; - spl1(); - do { - if ((lp = puttxt(lp)) == NULL) { - spl0(); - return ERR; - } else if (up) - up->t = getlp(curln); - else if ((up = upush(UADD, curln, curln)) == NULL) { - spl0(); - return ERR; - } - } while (lp != eot); - spl0(); - modified = 1; - } -} - - -/* subst: change all text matching a pattern in a range of lines according to - a substitution template; return status */ -subst(pat, gflag) - pattern_t *pat; - int gflag; -{ - undo_t *up; - char *txt; - char *eot; - long lc; - int nsubs = 0; - line_t *lp; - int len; - - curln = prevln(line1, lastln); - for (lc = 0; lc <= line2 - line1; lc++) { - lp = getlp(curln = nextln(curln, lastln)); - if ((len = regsub(pat, lp, gflag)) < 0) - return ERR; - else if (len) { - up = NULL; - if (lndelete(curln, curln) < 0) - return ERR; - txt = rbuf; - eot = rbuf + len; - spl1(); - do { - if ((txt = puttxt(txt)) == NULL) { - spl0(); - return ERR; - } else if (up) - up->t = getlp(curln); - else if ((up = upush(UADD, curln, curln)) == NULL) { - spl0(); - return ERR; - } - } while (txt != eot); - spl0(); - nsubs++; - } - } - if (nsubs == 0 && !(gflag & GLB)) { - sprintf(errmsg, "no match"); - return ERR; - } else if ((gflag & (GPR | GLS | GNP)) - && doprint(curln, curln, gflag) < 0) - return ERR; - return 1; -} - - -/* regsub: replace text matched by a pattern according to a substitution - template; return pointer to the modified text */ -regsub(pat, lp, gflag) - pattern_t *pat; - line_t *lp; - int gflag; -{ - int off = 0; - int kth = gflag >> 8; /* substitute kth match only */ - int chngd = 0; - int matchno = 0; - int len; - int i = 0; - regmatch_t rm[SE_MAX]; - char *txt; - char *eot; - - if ((txt = gettxt(lp)) == NULL) - return ERR; - len = lp->len & ~ACTV; - eot = txt + len; - if (isbinary) txt = nultonl(txt, len); - if (!regexec(pat, txt, SE_MAX, rm, 0)) { - do { - if (!kth || kth == ++matchno) { - chngd++; - i = rm[0].rm_so; - CKBUF(rbuf, rbufsz, off + i, ERR); - if (isbinary) txt = nltonul(txt, rm[0].rm_eo); - memcpy(rbuf + off, txt, i); - if ((off = catsub(txt, rm, off += i)) < 0) - return ERR; - } else { - i = rm[0].rm_eo; - CKBUF(rbuf, rbufsz, off + i, ERR); - if (isbinary) txt = nltonul(txt, i); - memcpy(rbuf + off, txt, i); - off += i; - } - txt += rm[0].rm_eo; - } while (*txt && (!chngd || (gflag & GSG) && rm[0].rm_eo) - && !regexec(pat, txt, SE_MAX, rm, REG_NOTBOL)); - i = eot - txt; - CKBUF(rbuf, rbufsz, off + i + 2, ERR); - if (i > 0 && !rm[0].rm_eo && (gflag & GSG)) { - sprintf(errmsg, "infinite substitution loop"); - return ERR; - } - if (isbinary) txt = nltonul(txt, i); - memcpy(rbuf + off, txt, i); - memcpy(rbuf + off + i, "\n", 2); - } - return chngd ? off + i + 1 : 0; -} - - -/* join: replace a range of lines with the joined text of those lines */ -join(from, to) - long from; - long to; -{ - static char *buf = NULL; - static int n; - - char *s; - int len = 0; - int size = 0; - line_t *bp, *ep; - - ep = getlp(nextln(to, lastln)); - for (bp = getlp(from); bp != ep; bp = bp->next, size += len) { - if ((s = gettxt(bp)) == NULL) - return ERR; - len = bp->len & ~ACTV; - CKBUF(buf, n, size + len, ERR); - memcpy(buf + size, s, len); - } - CKBUF(buf, n, size + 2, ERR); - memcpy(buf + size, "\n", 2); - if (lndelete(from, to) < 0) - return ERR; - curln = from - 1; - spl1(); - if (puttxt(buf) == NULL - || upush(UADD, curln, curln) == NULL) { - spl0(); - return ERR; - } - spl0(); - modified = 1; - return 0; -} - - -/* move: move a range of lines */ -move(num, glob) - long num; - int glob; -{ - line_t *b1, *a1, *b2, *a2, *lp; - long n = nextln(line2, lastln); - long p = prevln(line1, lastln); - int done = (num == line1 - 1 || num == line2); - - spl1(); - if (done) { - a2 = getlp(n); - b2 = getlp(p); - curln = line2; - } else if (upush(UMOV, p, n) == NULL - || upush(UMOV, num, nextln(num, lastln)) == NULL) { - spl0(); - return ERR; - } else { - a1 = getlp(n); - if (num < line1) - b1 = getlp(p), b2 = getlp(num); /* this getlp last! */ - else b2 = getlp(num), b1 = getlp(p); /* this getlp last! */ - a2 = b2->next; - requeue(b2, b1->next); - requeue(a1->prev, a2); - requeue(b1, a1); - curln = num + ((num < line1) ? line2 - line1 + 1 : 0); - } - if (glob) - for (lp = b2->next; lp != a2; lp = lp->next) - lp->len &= ~ACTV; /* zero ACTV bit */ - spl0(); - return 0; -} - - -/* transfer: copy a range of lines; return status */ -transfer(num) - long num; -{ - line_t *lp; - long nl, nt, lc; - long mid = (num < line2) ? num : line2; - undo_t *up = NULL; - - curln = num; - for (nt = 0, nl = line1; nl <= mid; nl++, nt++) { - spl1(); - if ((lp = lpdup(getlp(nl))) == NULL) { - spl0(); - return ERR; - } - lpqueue(lp); - if (up) - up->t = lp; - else if ((up = upush(UADD, curln, curln)) == NULL) { - spl0(); - return ERR; - } - spl0(); - } - for (nl += nt, lc = line2 + nt; nl <= lc; nl += 2, lc++) { - spl1(); - if ((lp = lpdup(getlp(nl))) == NULL) { - spl0(); - return ERR; - } - lpqueue(lp); - if (up) - up->t = lp; - else if ((up = upush(UADD, curln, curln)) == NULL) { - spl0(); - return ERR; - } - spl0(); - } - return 0; -} - - -/* lndelete: delete a range of lines */ -lndelete(from, to) - long from, to; -{ - line_t *before, *after; - - spl1(); - if (upush(UDEL, from, to) == NULL) { - spl0(); - return ERR; - } - after = getlp(nextln(to, lastln)); - before = getlp(prevln(from, lastln)); /* this getlp last! */ - requeue(before, after); - lastln -= to - from + 1; - curln = prevln(from, lastln); - spl0(); - return 0; -} - - -/* catsub: modify text according to a substitution template; - return offset to end of modified text */ -catsub(boln, rm, off) - char *boln; - regmatch_t *rm; - int off; -{ - int j = 0; - int k = 0; - char *sub = rhbuf; - - for (; sub - rhbuf < rhbufi; sub++) - if (*sub == '&') { - j = rm[0].rm_so; - k = rm[0].rm_eo; - CKBUF(rbuf, rbufsz, off + k - j, ERR); - while (j < k) - rbuf[off++] = boln[j++]; - } else if (*sub == '\\' && '1' <= *++sub && *sub <= '9' - && rm[*sub - '0'].rm_so >= 0 - && rm[*sub - '0'].rm_eo >= 0) { - j = rm[*sub - '0'].rm_so; - k = rm[*sub - '0'].rm_eo; - CKBUF(rbuf, rbufsz, off + k - j, ERR); - while (j < k) - rbuf[off++] = boln[j++]; - } else { - CKBUF(rbuf, rbufsz, off + 1, ERR); - rbuf[off++] = *sub; - } - CKBUF(rbuf, rbufsz, off + 1, ERR); - rbuf[off] = '\0'; - return off; -} - -/* doprint: print a range of lines to stdout */ -doprint(from, to, gflag) - long from; - long to; - int gflag; -{ - line_t *bp; - line_t *ep; - char *s; - - if (!from) { - sprintf(errmsg, "invalid address"); - return ERR; - } - ep = getlp(nextln(to, lastln)); - for (bp = getlp(from); bp != ep; bp = bp->next) { - if ((s = gettxt(bp)) == NULL) - return ERR; - putstr(s, bp->len & ~ACTV, curln = from++, gflag); - } - return 0; -} - - -int cols = 72; /* wrap column: ws_col - 8 */ - -/* putstr: print text to stdout */ -void -putstr(s, l, n, gflag) - char *s; - int l; - long n; - int gflag; -{ - int col = 0; - - if (gflag & GNP) { - printf("%ld\t", n); - col = 8; - } - for (; l--; s++) { - if ((gflag & GLS) && ++col > cols) { - fputs("\\\n", stdout); - col = 1; - } - if (gflag & GLS) { - switch (*s) { - case '\b': - fputs("\\b", stdout); - break; - case '\f': - fputs("\\f", stdout); - break; - case '\n': - fputs("\\n", stdout); - break; - case '\r': - fputs("\\r", stdout); - break; - case '\t': - fputs("\\t", stdout); - break; - case '\v': - fputs("\\v", stdout); - break; - default: - if (*s < 32 || 126 < *s) { - putchar('\\'); - putchar((((unsigned char) *s & 0300) >> 6) + '0'); - putchar((((unsigned char) *s & 070) >> 3) + '0'); - putchar(((unsigned char) *s & 07) + '0'); - col += 2; - } else if (*s == '\\') - fputs("\\\\", stdout); - else { - putchar(*s); - col--; - } - } - col++; - } else - putchar(*s); - } -#ifndef BACKWARDS - if (gflag & GLS) - putchar('$'); -#endif - putchar('\n'); -} - - -int newline_added; /* set if newline appended to input file */ - -/* doread: read a text file into the editor buffer; return line count */ -long -doread(n, fn) - long n; - char *fn; -{ - FILE *fp; - line_t *lp = getlp(n); - unsigned long size = 0; - undo_t *up = NULL; - int len; - - isbinary = newline_added = 0; - if ((fp = (*fn == '!') ? popen(fn + 1, "r") : fopen(esctos(fn), "r")) == NULL) { - fprintf(stderr, "%s: %s\n", fn, strerror(errno)); - sprintf(errmsg, "cannot open input file"); - return ERR; - } else if (des) - desinit(); - for (curln = n; (len = sgetline(fp)) > 0; size += len) { - spl1(); - if (puttxt(sbuf) == NULL) { - spl0(); - return ERR; - } - lp = lp->next; - if (up) - up->t = lp; - else if ((up = upush(UADD, curln, curln)) == NULL) { - spl0(); - return ERR; - } - spl0(); - } - if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) { - fprintf(stderr, "%s: %s\n", fn, strerror(errno)); - sprintf(errmsg, "cannot close input file"); - return ERR; - } - if (newline_added && !isbinary) - fputs("newline appended\n", stderr); - if (des) size += 8 - size % 8; - fprintf(stderr, !scripted ? "%lu\n" : "", size); - return (len < 0) ? ERR : curln - n; -} - - -/* dowrite: write the text of a range of lines to a file; return line count */ -long -dowrite(n, m, fn, mode) - long n; - long m; - char *fn; - char *mode; -{ - FILE *fp; - line_t *lp; - unsigned long size = 0; - long lc = n ? m - n + 1 : 0; - char *s = NULL; - int len; - int ct; - - if ((fp = ((*fn == '!') ? popen(fn + 1, "w") : fopen(esctos(fn), mode))) == NULL) { - fprintf(stderr, "%s: %s\n", fn, strerror(errno)); - sprintf(errmsg, "cannot open output file"); - return ERR; - } else if (des) - desinit(); - if (n && !des) - for (lp = getlp(n); n <= m; n++, lp = lp->next) { - if ((s = gettxt(lp)) == NULL) - return ERR; - len = lp->len & ~ACTV; - if (n != lastln || !isbinary || !newline_added) - s[len++] = '\n'; - if ((ct = fwrite(s, sizeof(char), len, fp)) < 0 || ct != len) { - fprintf(stderr, "%s: %s\n", fn, strerror(errno)); - sprintf(errmsg, "cannot write file"); - return ERR; - } - size += len; - } - else if (n) - for (lp = getlp(n); n <= m; n++, lp = lp->next) { - if ((s = gettxt(lp)) == NULL) - return ERR; - len = lp->len & ~ACTV; - while (len--) { - if (desputc(*s++, fp) == EOF && ferror(fp)) { - fprintf(stderr, "%s: %s\n", fn, strerror(errno)); - sprintf(errmsg, "cannot write file"); - return ERR; - } - } - if (n != lastln || !isbinary || !newline_added) { - if (desputc('\n', fp) < 0) { - fprintf(stderr, "%s: %s\n", fn, strerror(errno)); - sprintf(errmsg, "cannot write file"); - return ERR; - } - size++; /* for '\n' */ - } - size += (lp->len & ~ACTV); - } - if (des) { - desflush(fp); /* flush buffer */ - size += 8 - size % 8; /* adjust DES size */ - } - if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) { - fprintf(stderr, "%s: %s\n", fn, strerror(errno)); - sprintf(errmsg, "cannot close output file"); - return ERR; - } - fprintf(stderr, !scripted ? "%lu\n" : "", size); - return lc; -} - - -#define USIZE 100 /* undo stack size */ -undo_t *ustack = NULL; /* undo stack */ -long usize = 0; /* stack size variable */ -long u_p = 0; /* undo stack pointer */ - -/* upush: return pointer to intialized undo node */ -undo_t * -upush(type, from, to) - int type; - long from; - long to; -{ - undo_t *t; - -#if defined(sun) || defined(NO_REALLOC_NULL) - if (ustack == NULL - && (ustack = (undo_t *) malloc((usize = USIZE) * sizeof(undo_t))) == NULL) { - fprintf(stderr, "%s\n", strerror(errno)); - sprintf(errmsg, "out of memory"); - return NULL; - } -#endif - t = ustack; - if (u_p < usize - || (t = (undo_t *) realloc(ustack, (usize += USIZE) * sizeof(undo_t))) != NULL) { - ustack = t; - ustack[u_p].type = type; - ustack[u_p].t = getlp(to); - ustack[u_p].h = getlp(from); - return ustack + u_p++; - } - /* out of memory - release undo stack */ - fprintf(stderr, "%s\n", strerror(errno)); - sprintf(errmsg, "out of memory"); - ureset(); - free(ustack); - ustack = NULL; - usize = 0; - return NULL; -} - - -/* USWAP: swap undo nodes */ -#define USWAP(x,y) { \ - undo_t utmp; \ - utmp = x, x = y, y = utmp; \ -} - - -/* undo: undo last change to the editor buffer */ -undo(glob) - int glob; -{ - long n; - long ocurln = curln; - long olastln = lastln; - line_t *lp, *np; - - if (ucurln == -1 || ulastln == -1) { - sprintf(errmsg, "nothing to undo"); - return ERR; - } else if (u_p) - modified = 1; - getlp(0); /* this getlp last! */ - spl1(); - for (n = u_p; n-- > 0;) { - switch(ustack[n].type) { - case UADD: - requeue(ustack[n].h->prev, ustack[n].t->next); - break; - case UDEL: - requeue(ustack[n].h->prev, ustack[n].h); - requeue(ustack[n].t, ustack[n].t->next); - break; - case UMOV: - case VMOV: - requeue(ustack[n - 1].h, ustack[n].h->next); - requeue(ustack[n].t->prev, ustack[n - 1].t); - requeue(ustack[n].h, ustack[n].t); - n--; - break; - default: - /*NOTREACHED*/ - ; - } - ustack[n].type ^= 1; - } - /* reverse undo order */ - for (n = u_p; n-- > (u_p + 1)/ 2;) - USWAP(ustack[n], ustack[u_p - 1 - n]); - if (glob) - for (lp = np = getlp(0); (lp = lp->next) != np;) - lp->len &= ~ACTV; /* zero ACTV bit */ - curln = ucurln, ucurln = ocurln; - lastln = ulastln, ulastln = olastln; - spl0(); - return 0; -} - - -/* ureset: clear the undo stack */ -void -ureset() -{ - line_t *lp, *ep, *tl; - - while (u_p--) - if (ustack[u_p].type == UDEL) { - ep = ustack[u_p].t->next; - for (lp = ustack[u_p].h; lp != ep; lp = tl) { - clrmark(lp); - tl = lp->next; - free(lp); - } - } - u_p = 0; - ucurln = curln; - ulastln = lastln; -} - - -#define MAXMARK 26 /* max number of marks */ - -line_t *mark[MAXMARK]; /* line markers */ -int markno; /* line marker count */ - -/* getmark: return address of a marked line */ -long -getmark(n) - int n; -{ - if (!islower(n)) { - sprintf(errmsg, "invalid mark character"); - return ERR; - } - return getaddr(mark[n - 'a']); -} - - -/* putmark: set a line node mark */ -int -putmark(n, lp) - int n; - line_t *lp; -{ - if (!islower(n)) { - sprintf(errmsg, "invalid mark character"); - return ERR; - } else if (mark[n - 'a'] == NULL) - markno++; - mark[n - 'a'] = lp; - return 0; -} - - -/* clrmark: clear line node marks */ -void -clrmark(lp) - line_t *lp; -{ - int i; - - if (markno) - for (i = 0; i < MAXMARK; i++) - if (mark[i] == lp) { - mark[i] = NULL; - markno--; - } -} - - -/* sgetline: read a line of text up a maximum size from a file; return - line length */ -sgetline(fp) - FILE *fp; -{ - register int c; - register int i = 0; - - while (((c = des ? desgetc(fp) : getc(fp)) != EOF || !feof(fp) && !ferror(fp)) && c != '\n') { - CKBUF(sbuf, sbufsz, i + 1, ERR); - if (!(sbuf[i++] = c)) isbinary = 1; - } - CKBUF(sbuf, sbufsz, i + 2, ERR); - if (c == '\n') - sbuf[i++] = c; - else if (feof(fp) && i) { - sbuf[i++] = '\n'; - newline_added = 1; - } else if (ferror(fp)) { - fprintf(stderr, "%s\n", strerror(errno)); - sprintf(errmsg, "cannot read input file"); - return ERR; - } - sbuf[i] = '\0'; - return (isbinary && newline_added && i) ? --i : i; -} - - -/* getline: read a line of text up a maximum size from stdin; return - line length */ -getline() -{ - register int i = 0; - register int oi = 0; - char c; - - /* Read 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 */ - for (;;) - switch (read(0, &c, 1)) { - default: - oi = 0; - CKBUF(ibuf, ibufsz, i + 2, ERR); - if (!(ibuf[i++] = c)) isbinary = 1; - if (c != '\n') - continue; - lineno++; /* script line no. */ - ibuf[i] = '\0'; - ibufp = ibuf; - return i; - case 0: - if (i != oi) { - oi = i; - continue; - } else if (i) - ibuf[i] = '\0'; - ibufp = ibuf; - return i; - case -1: - fprintf(stderr, "%s\n", strerror(errno)); - sprintf(errmsg, "cannot read standard input"); - clearerr(stdin); - ibufp = NULL; - return ERR; - } -} - - -/* getcmdv: get a command vector */ -char * -getcmdv(sizep, nonl) - int *sizep; - int nonl; -{ - int l, n; - char *t = ibufp; - - while (*t++ != '\n') - ; - if ((l = t - ibufp) < 2 || !oddesc(ibufp, ibufp + l - 1)) { - *sizep = l; - return ibufp; - } - *sizep = -1; - CKBUF(cvbuf, cvbufsz, l, NULL); - memcpy(cvbuf, ibufp, l); - *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */ - if (nonl) l--; /* strip newline */ - for (;;) { - if ((n = getline()) < 0) - return NULL; - else if (n == 0 || ibuf[n - 1] != '\n') { - sprintf(errmsg, "unexpected end-of-file"); - return NULL; - } - CKBUF(cvbuf, cvbufsz, l + n, NULL); - memcpy(cvbuf + l, ibuf, n); - l += n; - if (n < 2 || !oddesc(cvbuf, cvbuf + l - 1)) - break; - *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */ - if (nonl) l--; /* strip newline */ - } - CKBUF(cvbuf, cvbufsz, l + 1, NULL); - cvbuf[l] = '\0'; - *sizep = l; - return cvbuf; -} - - -/* lpdup: return a pointer to a copy of a line node */ -line_t * -lpdup(lp) - line_t *lp; -{ - line_t *np; - - if ((np = (line_t *) malloc(sizeof(line_t))) == NULL) { - fprintf(stderr, "%s\n", strerror(errno)); - sprintf(errmsg, "out of memory"); - return NULL; - } - np->seek = lp->seek; - np->len = (lp->len & ~ACTV); /* zero ACTV bit */ - return np; -} - - -/* oddesc: return the parity of escapes preceding a character in a - string */ -oddesc(s, t) - char *s; - char *t; -{ - return (s == t || *(t - 1) != '\\') ? 0 : !oddesc(s, t - 1); -} - - -/* esctos: return copy of escaped string */ -char * -esctos(s) - char *s; -{ - static char *file = NULL; - static int filesz = 0; - - int i = 0; - - CKBUF(file, filesz, MAXFNAME + 1, NULL); - /* assert: no trailing escape */ - while (file[i++] = (*s == '\\') ? *++s : *s) - s++; - return file; -} - - -void -onhup(signo) - int signo; -{ - if (mutex) - sigflags |= (1 << signo); - else dohup(signo); -} - - -void -onintr(signo) - int signo; -{ - if (mutex) - sigflags |= (1 << signo); - else dointr(signo); -} - - -void -dohup(signo) - int signo; -{ - char *hup = NULL; /* hup filename */ - char *s; - int n; - - if (!sigactive) - quit(1); - sigflags &= ~(1 << signo); - if (lastln && dowrite(1, lastln, "ed.hup", "w") < 0 - && (s = getenv("HOME")) != NULL - && (n = strlen(s)) + 8 <= MAXFNAME /* "ed.hup" + '/' */ - && (hup = (char *) malloc(n + 10)) != NULL) { - strcpy(hup, s); - if (hup[n - 1] != '/') - hup[n] = '/', hup[n+1] = '\0'; - strcat(hup, "ed.hup"); - dowrite(1, lastln, hup, "w"); - } - quit(2); -} - - -void -dointr(signo) - int signo; -{ - if (!sigactive) - quit(1); - sigflags &= ~(1 << signo); -#ifdef _POSIX_SOURCE - siglongjmp(env, -1); -#else - longjmp(env, -1); -#endif -} - - -struct winsize ws; /* window size structure */ - -void -dowinch(signo) - int signo; -{ - sigflags &= ~(1 << signo); - if (ioctl(0, TIOCGWINSZ, (char *) &ws) >= 0) { - if (ws.ws_row > 2) rows = ws.ws_row - 2; - if (ws.ws_col > 8) cols = ws.ws_col - 8; - } -} - - -/* ckfn: return a legal filename */ -char * -ckfn(s) - char *s; -{ - if (red && (*s == '!' || !strcmp(s, "..") || strchr(s, '/'))) { - sprintf(errmsg, "shell access restricted"); - return NULL; - } - return s; -} diff --git a/bin/ed/ed.h b/bin/ed/ed.h index b3905370f949..1f61428eb73a 100644 --- a/bin/ed/ed.h +++ b/bin/ed/ed.h @@ -1,11 +1,8 @@ /* ed.h: type and constant definitions for the ed editor. */ /* - * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1993 Andrew Moore * All rights reserved. * - * This code is derived from software contributed to Berkeley by - * Andrew Moore, Talke Studio. - * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -14,13 +11,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -34,22 +24,22 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ed.h 5.5 (Berkeley) 3/28/93 + * @(#)$Id: ed.h,v 1.5 1994/02/01 00:34:39 alm Exp $ */ -#include <unistd.h> -#include <errno.h> #if defined(BSD) && BSD >= 199103 || defined(__386BSD__) # include <sys/param.h> /* for MAXPATHLEN */ #endif +#include <errno.h> +#ifdef sun +# include <limits.h> +#endif #include <regex.h> #include <signal.h> - -#define BITSPERBYTE 8 -#define BITS(type) (BITSPERBYTE * (int)sizeof(type)) -#define CHARBITS BITS(char) -#define INTBITS BITS(int) -#define INTHIBIT (unsigned) (1 << (INTBITS - 1)) +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> #define ERR (-2) #define EMOD (-3) @@ -59,21 +49,28 @@ # define MAXPATHLEN 255 /* _POSIX_PATH_MAX */ #endif -#define MAXFNAME MAXPATHLEN /* max file name size */ #define MINBUFSZ 512 /* minimum buffer size - must be > 0 */ -#define LINECHARS (INTHIBIT - 1) /* max chars per line */ #define SE_MAX 30 /* max subexpressions in a regular expression */ +#ifdef INT_MAX +# define LINECHARS INT_MAX /* max chars per line */ +#else +# define LINECHARS MAXINT /* max chars per line */ +#endif + +/* gflags */ +#define GLB 001 /* global command */ +#define GPR 002 /* print after command */ +#define GLS 004 /* list after command */ +#define GNP 010 /* enumerate after command */ +#define GSG 020 /* global substitute */ typedef regex_t pattern_t; /* Line node */ typedef struct line { - struct line *next; - struct line *prev; + struct line *q_forw; + struct line *q_back; off_t seek; /* address of line in scratch buffer */ - -#define ACTV INTHIBIT /* active bit: high bit of len */ - int len; /* length of line */ } line_t; @@ -98,87 +95,94 @@ typedef struct undo { # define min(a,b) ((a) < (b) ? (a) : (b)) #endif -/* nextln: return line after l mod k */ -#define nextln(l,k) ((l)+1 > (k) ? 0 : (l)+1) - -/* nextln: return line before l mod k */ -#define prevln(l,k) ((l)-1 < 0 ? (k) : (l)-1) - -#define skipblanks() while (isspace(*ibufp) && *ibufp != '\n') ibufp++ +#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++ +/* SPL1: disable some interrupts (requires reliable signals) */ +#define SPL1() mutex++ -/* spl0: enable all interrupts; check sigflags (requires reliable signals) */ -#define spl0() \ +/* SPL0: enable all interrupts; check sigflags (requires reliable signals) */ +#define SPL0() \ if (--mutex == 0) { \ - if (sigflags & (1 << SIGHUP)) dohup(SIGHUP); \ - if (sigflags & (1 << SIGINT)) dointr(SIGINT); \ + if (sigflags & (1 << (SIGHUP - 1))) handle_hup(SIGHUP); \ + if (sigflags & (1 << (SIGINT - 1))) handle_int(SIGINT); \ +} + +/* STRTOL: convert a string to long */ +#define STRTOL(i, p) { \ + if (((i = strtol(p, &p, 10)) == LONG_MIN || i == LONG_MAX) && \ + errno == ERANGE) { \ + sprintf(errmsg, "number out of range"); \ + i = 0; \ + return ERR; \ + } \ } #if defined(sun) || defined(NO_REALLOC_NULL) -/* CKBUF: assure at least a minimum size for buffer b */ -#define CKBUF(b,n,i,err) \ +/* REALLOC: assure at least a minimum size for buffer b */ +#define REALLOC(b,n,i,err) \ if ((i) > (n)) { \ int ti = (n); \ char *ts; \ - spl1(); \ + SPL1(); \ if ((b) != NULL) { \ if ((ts = (char *) realloc((b), ti += max((i), MINBUFSZ))) == NULL) { \ fprintf(stderr, "%s\n", strerror(errno)); \ sprintf(errmsg, "out of memory"); \ - spl0(); \ + SPL0(); \ return err; \ } \ } else { \ if ((ts = (char *) malloc(ti += max((i), MINBUFSZ))) == NULL) { \ fprintf(stderr, "%s\n", strerror(errno)); \ sprintf(errmsg, "out of memory"); \ - spl0(); \ + SPL0(); \ return err; \ } \ } \ (n) = ti; \ (b) = ts; \ - spl0(); \ + SPL0(); \ } #else /* NO_REALLOC_NULL */ -/* CKBUF: assure at least a minimum size for buffer b */ -#define CKBUF(b,n,i,err) \ +/* REALLOC: assure at least a minimum size for buffer b */ +#define REALLOC(b,n,i,err) \ if ((i) > (n)) { \ int ti = (n); \ char *ts; \ - spl1(); \ + SPL1(); \ if ((ts = (char *) realloc((b), ti += max((i), MINBUFSZ))) == NULL) { \ fprintf(stderr, "%s\n", strerror(errno)); \ sprintf(errmsg, "out of memory"); \ - spl0(); \ + SPL0(); \ return err; \ } \ (n) = ti; \ (b) = ts; \ - spl0(); \ + SPL0(); \ } #endif /* NO_REALLOC_NULL */ -/* requeue: link pred before succ */ -#define requeue(pred, succ) (pred)->next = (succ), (succ)->prev = (pred) +/* REQUE: link pred before succ */ +#define REQUE(pred, succ) (pred)->q_forw = (succ), (succ)->q_back = (pred) -/* insqueue: insert elem in circular queue after pred */ -#define insqueue(elem, pred) \ +#ifdef NEED_INSQUE +/* insque: insert elem in circular queue after pred */ +#define insque(elem, pred) \ { \ - requeue((elem), (pred)->next); \ - requeue((pred), elem); \ + REQUE((elem), (pred)->q_forw); \ + REQUE((pred), elem); \ } -/* remqueue: remove elem from circular queue */ -#define remqueue(elem) requeue((elem)->prev, (elem)->next); +/* remque: remove_lines elem from circular queue */ +#define remque(elem) REQUE((elem)->q_back, (elem)->q_forw); +#endif /* NEED_INSQUE */ -/* nultonl: overwrite ASCII NULs with newlines */ -#define nultonl(s, l) translit(s, l, '\0', '\n') +/* NUL_TO_NEWLINE: overwrite ASCII NULs with newlines */ +#define NUL_TO_NEWLINE(s, l) translit_text(s, l, '\0', '\n') -/* nltonul: overwrite newlines with ASCII NULs */ -#define nltonul(s, l) translit(s, l, '\n', '\0') +/* NEWLINE_TO_NUL: overwrite newlines with ASCII NULs */ +#define NEWLINE_TO_NUL(s, l) translit_text(s, l, '\n', '\0') #ifndef strerror # define strerror(n) sys_errlist[n] @@ -192,75 +196,101 @@ if ((i) > (n)) { \ # endif #endif -/* local function declarations */ -int append __P((long, int)); -int cbcdec __P((char *, FILE *)); -int cbcenc __P((char *, int, FILE *)); -char *ckfn __P((char *)); -int ckglob __P((void)); -int ckrange __P((long, long)); -int desflush __P((FILE *)); -int desgetc __P((FILE *)); -void desinit __P((void)); -int desputc __P((int, FILE *)); -int docmd __P((int)); -void err __P((char *)); -char *ccl __P((char *)); -void clrmark __P((line_t *)); -void cvtkey __P((char *, char *)); -long doglob __P((int)); -void dohup __P((int)); -void dointr __P((int)); -void dowinch __P((int)); -int doprint __P((long, long, int)); -long doread __P((long, char *)); -long dowrite __P((long, long, char *, char *)); -char *esctos __P((char *)); -long patscan __P((pattern_t *, int)); -long getaddr __P((line_t *)); -char *getcmdv __P((int *, int)); -char *getfn __P((void)); -int getkey __P((void)); -char *getlhs __P((int)); -int getline __P((void)); -int getlist __P((void)); -long getmark __P((int)); -long getnum __P((int)); -long getone __P((void)); -line_t *getlp __P((long)); -int getrhs __P((int)); -int getshcmd __P((void)); -char *gettxt __P((line_t *)); -void init_buf __P((void)); -int join __P((long, long)); -int lndelete __P((long, long)); -line_t *lpdup __P((line_t *)); -void lpqueue __P((line_t *)); -void makekey __P((char *)); -char *makesub __P((int)); -int move __P((long, int)); -int oddesc __P((char *, char *)); -void onhup __P((int)); -void onintr __P((int)); -pattern_t *optpat __P((void)); -int putmark __P((int, line_t *)); -void putstr __P((char *, int, long, int)); -char *puttxt __P((char *)); +/* Local Function Declarations */ +void add_line_node __P((line_t *)); +int append_lines __P((long)); +int apply_subst_template __P((char *, regmatch_t *, int, int)); +int build_active_list __P((int)); +int cbc_decode __P((char *, FILE *)); +int cbc_encode __P((char *, int, FILE *)); +int check_addr_range __P((long, long)); +void clear_active_list __P((void)); +void clear_undo_stack __P((void)); +int close_sbuf __P((void)); +int copy_lines __P((long)); +int delete_lines __P((long, long)); +void des_error __P((char *)); +int display_lines __P((long, long, int)); +line_t *dup_line_node __P((line_t *)); +int exec_command __P((void)); +long exec_global __P((int, int)); +void expand_des_key __P((char *, char *)); +int extract_addr_range __P((void)); +char *extract_pattern __P((int)); +int extract_subst_tail __P((int *, int *)); +char *extract_subst_template __P((void)); +int filter_lines __P((long, long, char *)); +int flush_des_file __P((FILE *)); +line_t *get_addressed_line_node __P((long)); +pattern_t *get_compiled_pattern __P((void)); +int get_des_char __P((FILE *)); +char *get_extended_line __P((int *, int)); +char *get_filename __P((void)); +int get_keyword __P((void)); +long get_line_node_addr __P((line_t *)); +long get_matching_node_addr __P((pattern_t *, int)); +long get_marked_node_addr __P((int)); +char *get_sbuf_line __P((line_t *)); +int get_shell_command __P((void)); +int get_stream_line __P((FILE *)); +int get_tty_line __P((void)); +void handle_hup __P((int)); +void handle_int __P((int)); +void handle_winch __P((int)); +int has_trailing_escape __P((char *, char *)); +int hex_to_binary __P((int, int)); +void init_buffers __P((void)); +void init_des_cipher __P((void)); +int is_legal_filename __P((char *)); +int join_lines __P((long, long)); +int mark_line_node __P((line_t *, int)); +int move_lines __P((long)); +line_t *next_active_node __P(()); +long next_addr __P((void)); +int open_sbuf __P((void)); +char *parse_char_class __P((char *)); +int pop_undo_stack __P((void)); +undo_t *push_undo_stack __P((int, long, long)); +int put_des_char __P((int, FILE *)); +char *put_sbuf_line __P((char *)); +int put_stream_line __P((FILE *, char *, int)); +int put_tty_line __P((char *, int, long, int)); void quit __P((int)); -int regsub __P((pattern_t *, line_t *, int)); -int sbclose __P((void)); -int sbopen __P((void)); -int sgetline __P((FILE *)); -int catsub __P((char *, regmatch_t *, int)); -int subst __P((pattern_t *, int)); -int tobinhex __P((int, int)); -int transfer __P((long)); -char *translit __P((char *, int, int, int)); -int undo __P((int)); -undo_t *upush __P((int, long, long)); -void ureset __P((void)); +long read_file __P((char *, long)); +long read_stream __P((FILE *, long)); +int search_and_replace __P((pattern_t *, int, int)); +int set_active_node __P((line_t *)); +void set_des_key __P((char *)); +void signal_hup __P((int)); +void signal_int __P((int)); +char *strip_escapes __P((char *)); +int substitute_matching_text __P((pattern_t *, line_t *, int, int)); +char *translit_text __P((char *, int, int, int)); +void unmark_line_node __P((line_t *)); +void unset_active_nodes __P((line_t *, line_t *)); +long write_file __P((char *, char *, long, long)); +long write_stream __P((FILE *, long, long)); +/* global buffers */ +extern char stdinbuf[]; +extern char *ibuf; +extern char *ibufp; +extern int ibufsz; -extern char *sys_errlist[]; +/* global flags */ +extern int isbinary; +extern int isglobal; +extern int modified; extern int mutex; extern int sigflags; + +/* global vars */ +extern long addr_last; +extern long current_addr; +extern char errmsg[]; +extern long first_addr; +extern int lineno; +extern long second_addr; +#ifdef sun +extern char *sys_errlist[]; +#endif diff --git a/bin/ed/glob.c b/bin/ed/glob.c new file mode 100644 index 000000000000..5c77d224cdff --- /dev/null +++ b/bin/ed/glob.c @@ -0,0 +1,223 @@ +/* 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. + */ + +#ifndef lint +static char *rcsid = "@(#)$Id: glob.c,v 1.1 1994/02/01 00:34:40 alm Exp $"; +#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(isgcmd) + 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(interact, gflag) + 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 + if (!interact) + if (!strcmp(ibufp, "\n")) + cmd = "p\n"; /* 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(lp) + 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(np, mp) + line_t *np, *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() +{ + 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() +{ + SPL1(); + active_size = active_last = active_ptr = active_ndx = 0; + free(active_list); + active_list = NULL; + SPL0(); +} diff --git a/bin/ed/io.c b/bin/ed/io.c new file mode 100644 index 000000000000..0c63f3dc77fb --- /dev/null +++ b/bin/ed/io.c @@ -0,0 +1,375 @@ +/* io.c: This file contains the i/o routines for the ed line editor */ +/*- + * Copyright (c) 1993 Andrew Moore, Talke Studio. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char *rcsid = "@(#)$Id: io.c,v 1.1 1994/02/01 00:34:41 alm Exp $"; +#endif /* not lint */ + +#include "ed.h" + + +extern int scripted; + +/* read_file: read a named file/pipe into the buffer; return line count */ +long +read_file(fn, n) + char *fn; + long n; +{ + FILE *fp; + long size; + + + fp = (*fn == '!') ? popen(fn + 1, "r") : fopen(strip_escapes(fn), "r"); + if (fp == NULL) { + fprintf(stderr, "%s: %s\n", fn, strerror(errno)); + sprintf(errmsg, "cannot open input file"); + return ERR; + } else if ((size = read_stream(fp, n)) < 0) + return ERR; + else if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) { + fprintf(stderr, "%s: %s\n", fn, strerror(errno)); + sprintf(errmsg, "cannot close input file"); + return ERR; + } + fprintf(stderr, !scripted ? "%lu\n" : "", size); + return current_addr - n; +} + + +extern int des; + +char *sbuf; /* file i/o buffer */ +int sbufsz; /* file i/o buffer size */ +int newline_added; /* if set, newline appended to input file */ + +/* read_stream: read a stream into the editor buffer; return status */ +long +read_stream(fp, n) + FILE *fp; + long n; +{ + line_t *lp = get_addressed_line_node(n); + undo_t *up = NULL; + unsigned long size = 0; + int o_newline_added = newline_added; + int o_isbinary = isbinary; + int appended = (n == addr_last); + int len; + + isbinary = newline_added = 0; + if (des) + init_des_cipher(); + for (current_addr = n; (len = get_stream_line(fp)) > 0; size += len) { + SPL1(); + if (put_sbuf_line(sbuf) == NULL) { + SPL0(); + return ERR; + } + lp = lp->q_forw; + if (up) + up->t = lp; + else if ((up = push_undo_stack(UADD, current_addr, + current_addr)) == NULL) { + SPL0(); + return ERR; + } + SPL0(); + } + if (len < 0) + return ERR; + if (appended && size && o_isbinary && o_newline_added) + fputs("newline inserted\n", stderr); + else if (newline_added && (!appended || !isbinary && !o_isbinary)) + fputs("newline appended\n", stderr); + if (isbinary && newline_added && !appended) + size += 1; + if (!size) + newline_added = 1; + newline_added = appended ? newline_added : o_newline_added; + isbinary = isbinary | o_isbinary; + if (des) + size += 8 - size % 8; /* adjust DES size */ + return size; +} + + +/* get_stream_line: read a line of text from a stream; return line length */ +int +get_stream_line(fp) + FILE *fp; +{ + register int c; + register int i = 0; + + while (((c = des ? get_des_char(fp) : getc(fp)) != EOF || !feof(fp) && + !ferror(fp)) && c != '\n') { + REALLOC(sbuf, sbufsz, i + 1, ERR); + if (!(sbuf[i++] = c)) + isbinary = 1; + } + REALLOC(sbuf, sbufsz, i + 2, ERR); + if (c == '\n') + sbuf[i++] = c; + else if (ferror(fp)) { + fprintf(stderr, "%s\n", strerror(errno)); + sprintf(errmsg, "cannot read input file"); + return ERR; + } else if (i) { + sbuf[i++] = '\n'; + newline_added = 1; + } + sbuf[i] = '\0'; + return (isbinary && newline_added && i) ? --i : i; +} + + +/* write_file: write a range of lines to a named file/pipe; return line count */ +long +write_file(fn, mode, n, m) + char *fn; + char *mode; + long n; + long m; +{ + FILE *fp; + long size; + + fp = (*fn == '!') ? popen(fn+1, "w") : fopen(strip_escapes(fn), mode); + if (fp == NULL) { + fprintf(stderr, "%s: %s\n", fn, strerror(errno)); + sprintf(errmsg, "cannot open output file"); + return ERR; + } else if ((size = write_stream(fp, n, m)) < 0) + return ERR; + else if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) { + fprintf(stderr, "%s: %s\n", fn, strerror(errno)); + sprintf(errmsg, "cannot close output file"); + return ERR; + } + fprintf(stderr, !scripted ? "%lu\n" : "", size); + return n ? m - n + 1 : 0; +} + + +/* write_stream: write a range of lines to a stream; return status */ +long +write_stream(fp, n, m) + FILE *fp; + long n; + long m; +{ + line_t *lp = get_addressed_line_node(n); + unsigned long size = 0; + char *s; + int len; + + if (des) + init_des_cipher(); + for (; n && n <= m; n++, lp = lp->q_forw) { + if ((s = get_sbuf_line(lp)) == NULL) + return ERR; + len = lp->len; + if (n != addr_last || !isbinary || !newline_added) + s[len++] = '\n'; + if (put_stream_line(fp, s, len) < 0) + return ERR; + size += len; + } + if (des) { + flush_des_file(fp); /* flush buffer */ + size += 8 - size % 8; /* adjust DES size */ + } + return size; +} + + +/* put_stream_line: write a line of text to a stream; return status */ +int +put_stream_line(fp, s, len) + FILE *fp; + char *s; + int len; +{ + while (len--) + if ((des ? put_des_char(*s++, fp) : fputc(*s++, fp)) < 0) { + fprintf(stderr, "%s\n", strerror(errno)); + sprintf(errmsg, "cannot write file"); + return ERR; + } + return 0; +} + +/* get_extended_line: get a an extended line from stdin */ +char * +get_extended_line(sizep, nonl) + int *sizep; + int nonl; +{ + static char *cvbuf = NULL; /* buffer */ + static int cvbufsz = 0; /* buffer size */ + + int l, n; + char *t = ibufp; + + while (*t++ != '\n') + ; + if ((l = t - ibufp) < 2 || !has_trailing_escape(ibufp, ibufp + l - 1)) { + *sizep = l; + return ibufp; + } + *sizep = -1; + REALLOC(cvbuf, cvbufsz, l, NULL); + memcpy(cvbuf, ibufp, l); + *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */ + if (nonl) l--; /* strip newline */ + for (;;) { + if ((n = get_tty_line()) < 0) + return NULL; + else if (n == 0 || ibuf[n - 1] != '\n') { + sprintf(errmsg, "unexpected end-of-file"); + return NULL; + } + REALLOC(cvbuf, cvbufsz, l + n, NULL); + memcpy(cvbuf + l, ibuf, n); + l += n; + if (n < 2 || !has_trailing_escape(cvbuf, cvbuf + l - 1)) + break; + *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */ + if (nonl) l--; /* strip newline */ + } + REALLOC(cvbuf, cvbufsz, l + 1, NULL); + cvbuf[l] = '\0'; + *sizep = l; + return cvbuf; +} + + +/* get_tty_line: read a line of text from stdin; return line length */ +int +get_tty_line() +{ + register int oi = 0; + register int i = 0; + int c; + + for (;;) + switch (c = getchar()) { + default: + oi = 0; + REALLOC(ibuf, ibufsz, i + 2, ERR); + if (!(ibuf[i++] = c)) isbinary = 1; + if (c != '\n') + continue; + lineno++; + ibuf[i] = '\0'; + ibufp = ibuf; + return i; + case EOF: + if (ferror(stdin)) { + fprintf(stderr, "stdin: %s\n", strerror(errno)); + sprintf(errmsg, "cannot read stdin"); + clearerr(stdin); + ibufp = NULL; + return ERR; + } else { + clearerr(stdin); + if (i != oi) { + oi = i; + continue; + } else if (i) + ibuf[i] = '\0'; + ibufp = ibuf; + return i; + } + } +} + + + +#define ESCAPES "\a\b\f\n\r\t\v\\" +#define ESCCHARS "abfnrtv\\" + +extern int rows; +extern int cols; + +/* put_tty_line: print text to stdout */ +int +put_tty_line(s, l, n, gflag) + char *s; + int l; + long n; + int gflag; +{ + int col = 0; + int lc = 0; + char *cp; + + if (gflag & GNP) { + printf("%ld\t", n); + col = 8; + } + for (; l--; s++) { + if ((gflag & GLS) && ++col > cols) { + fputs("\\\n", stdout); + col = 1; +#ifndef BACKWARDS + if (!scripted && !isglobal && ++lc > rows) { + lc = 0; + fputs("Press <RETURN> to continue... ", stdout); + fflush(stdout); + if (get_tty_line() < 0) + return ERR; + } +#endif + } + if (gflag & GLS) { + if (31 < *s && *s < 127 && *s != '\\') + putchar(*s); + else { + putchar('\\'); + col++; + if (*s && (cp = strchr(ESCAPES, *s)) != NULL) + putchar(ESCCHARS[cp - ESCAPES]); + else { + putchar((((unsigned char) *s & 0300) >> 6) + '0'); + putchar((((unsigned char) *s & 070) >> 3) + '0'); + putchar(((unsigned char) *s & 07) + '0'); + col += 2; + } + } + + } else + putchar(*s); + } +#ifndef BACKWARDS + if (gflag & GLS) + putchar('$'); +#endif + putchar('\n'); + return 0; +} diff --git a/bin/ed/main.c b/bin/ed/main.c new file mode 100644 index 000000000000..ddaf513f4337 --- /dev/null +++ b/bin/ed/main.c @@ -0,0 +1,1432 @@ +/* main.c: This file contains the main control and user-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. + */ + +#ifndef lint +char *copyright = +"@(#) Copyright (c) 1993 Andrew Moore, Talke Studio. \n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char *rcsid = "@(#)$Id: main.c,v 1.1 1994/02/01 00:34:42 alm Exp $"; +#endif /* not lint */ + +/* + * CREDITS + * + * This program is based on the editor algorithm described in + * Brian W. Kernighan and P. J. Plauger's book "Software Tools + * in Pascal," Addison-Wesley, 1981. + * + * The buffering algorithm is attributed to Rodney Ruddock of + * the University of Guelph, Guelph, Ontario. + * + * The cbc.c encryption code is adapted from + * the bdes program by Matt Bishop of Dartmouth College, + * Hanover, NH. + * + */ + +#include <sys/ioctl.h> +#include <sys/wait.h> +#include <ctype.h> +#include <setjmp.h> +#include <pwd.h> + +#include "ed.h" + + +#ifdef _POSIX_SOURCE +sigjmp_buf env; +#else +jmp_buf env; +#endif + +/* static buffers */ +char stdinbuf[1]; /* stdin buffer */ +char *shcmd; /* shell command buffer */ +int shcmdsz; /* shell command buffer size */ +int shcmdi; /* shell command buffer index */ +char *ibuf; /* ed command-line buffer */ +int ibufsz; /* ed command-line buffer size */ +char *ibufp; /* pointer to ed command-line buffer */ + +/* global flags */ +int des = 0; /* if set, use crypt(3) for i/o */ +int garrulous = 0; /* if set, print all error messages */ +int isbinary; /* if set, buffer contains ASCII NULs */ +int isglobal; /* if set, doing a global command */ +int modified; /* if set, buffer modified since last write */ +int mutex = 0; /* if set, signals set "sigflags" */ +int red = 0; /* if set, restrict shell/directory access */ +int scripted = 0; /* if set, suppress diagnostics */ +int sigflags = 0; /* if set, signals received while mutex set */ +int sigactive = 0; /* if set, signal handlers are enabled */ + +char old_filename[MAXPATHLEN + 1] = ""; /* default filename */ +long current_addr; /* current address in editor buffer */ +long addr_last; /* last address in editor buffer */ +int lineno; /* script line number */ +char *prompt; /* command-line prompt */ +char *dps = "*"; /* default command-line prompt */ + +char *usage = "usage: %s [-] [-sx] [-p string] [name]\n"; + +extern char errmsg[]; +extern int optind; +extern char *optarg; + +/* ed: line editor */ +int +main(argc, argv) + int argc; + char **argv; +{ + int c, n; + long status = 0; + + red = (n = strlen(argv[0])) > 2 && argv[0][n - 3] == 'r'; +top: + while ((c = getopt(argc, argv, "p:sx")) != EOF) + switch(c) { + case 'p': /* set prompt */ + prompt = optarg; + break; + case 's': /* run script */ + scripted = 1; + break; + case 'x': /* use crypt */ +#ifdef DES + des = get_keyword(); +#else + fprintf(stderr, "crypt unavailable\n?\n"); +#endif + break; + + default: + fprintf(stderr, usage, argv[0]); + exit(1); + } + argv += optind; + argc -= optind; + if (argc && **argv == '-') { + scripted = 1; + if (argc > 1) { + optind = 1; + goto top; + } + argv++; + argc--; + } + /* assert: reliable signals! */ +#ifdef SIGWINCH + handle_winch(SIGWINCH); + if (isatty(0)) signal(SIGWINCH, handle_winch); +#endif + signal(SIGHUP, signal_hup); + signal(SIGQUIT, SIG_IGN); + signal(SIGINT, signal_int); +#ifdef _POSIX_SOURCE + if (status = sigsetjmp(env, 1)) +#else + if (status = setjmp(env)) +#endif + { + fputs("\n?\n", stderr); + sprintf(errmsg, "interrupt"); + } else { + init_buffers(); + sigactive = 1; /* enable signal handlers */ + if (argc && **argv && is_legal_filename(*argv)) { + if (read_file(*argv, 0) < 0 && !isatty(0)) + quit(2); + else if (**argv != '!') + strcpy(old_filename, *argv); + } else if (argc) { + fputs("?\n", stderr); + if (**argv == '\0') + sprintf(errmsg, "invalid filename"); + if (!isatty(0)) + quit(2); + } + } + for (;;) { + if (status < 0 && garrulous) + fprintf(stderr, "%s\n", errmsg); + if (prompt) { + printf("%s", prompt); + fflush(stdout); + } + if ((n = get_tty_line()) < 0) { + status = ERR; + continue; + } else if (n == 0) { + if (modified && !scripted) { + fputs("?\n", stderr); + sprintf(errmsg, "warning: file modified"); + if (!isatty(0)) { + fprintf(stderr, garrulous ? + "script, line %d: %s\n" : + "", lineno, errmsg); + quit(2); + } + clearerr(stdin); + modified = 0; + status = EMOD; + continue; + } else + quit(0); + } else if (ibuf[n - 1] != '\n') { + /* discard line */ + sprintf(errmsg, "unexpected end-of-file"); + clearerr(stdin); + status = ERR; + continue; + } + isglobal = 0; + if ((status = extract_addr_range()) >= 0 && + (status = exec_command()) >= 0) + if (!status || status && + (status = display_lines(current_addr, current_addr, + status)) >= 0) + continue; + switch (status) { + case EOF: + quit(0); + case EMOD: + modified = 0; + fputs("?\n", stderr); /* give warning */ + sprintf(errmsg, "warning: file modified"); + if (!isatty(0)) { + fprintf(stderr, garrulous ? + "script, line %d: %s\n" : + "", lineno, errmsg); + quit(2); + } + break; + case FATAL: + if (!isatty(0)) + fprintf(stderr, garrulous ? + "script, line %d: %s\n" : "", + lineno, errmsg); + else + fprintf(stderr, garrulous ? "%s\n" : "", + errmsg); + quit(3); + default: + fputs("?\n", stderr); + if (!isatty(0)) { + fprintf(stderr, garrulous ? + "script, line %d: %s\n" : "", + lineno, errmsg); + quit(2); + } + break; + } + } + /*NOTREACHED*/ +} + +long first_addr, second_addr, addr_cnt; + +/* extract_addr_range: get line addresses from the command buffer until an + illegal address is seen; return status */ +int +extract_addr_range() +{ + long addr; + + addr_cnt = 0; + first_addr = second_addr = current_addr; + while ((addr = next_addr()) >= 0) { + addr_cnt++; + first_addr = second_addr; + second_addr = addr; + if (*ibufp != ',' && *ibufp != ';') + break; + else if (*ibufp++ == ';') + current_addr = addr; + } + if ((addr_cnt = min(addr_cnt, 2)) == 1 || second_addr != addr) + first_addr = second_addr; + return (addr == ERR) ? ERR : 0; +} + + +#define SKIP_BLANKS() while (isspace(*ibufp) && *ibufp != '\n') ibufp++ + +#define MUST_BE_FIRST() \ + if (!first) { sprintf(errmsg, "invalid address"); return ERR; } + +/* next_addr: return the next line address in the command buffer */ +long +next_addr() +{ + char *hd; + long addr = current_addr; + long n; + int first = 1; + int c; + + SKIP_BLANKS(); + for (hd = ibufp;; first = 0) + switch (c = *ibufp) { + case '+': + case '\t': + case ' ': + case '-': + case '^': + ibufp++; + SKIP_BLANKS(); + if (isdigit(*ibufp)) { + STRTOL(n, ibufp); + addr += (c == '-' || c == '^') ? -n : n; + } else if (!isspace(c)) + addr += (c == '-' || c == '^') ? -1 : 1; + break; + case '0': case '1': case '2': + case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + MUST_BE_FIRST(); + STRTOL(addr, ibufp); + break; + case '.': + case '$': + MUST_BE_FIRST(); + ibufp++; + addr = (c == '.') ? current_addr : addr_last; + break; + case '/': + case '?': + MUST_BE_FIRST(); + if ((addr = get_matching_node_addr( + get_compiled_pattern(), c == '/')) < 0) + return ERR; + else if (c == *ibufp) + ibufp++; + break; + case '\'': + MUST_BE_FIRST(); + ibufp++; + if ((addr = get_marked_node_addr(*ibufp++)) < 0) + return ERR; + break; + case '%': + case ',': + case ';': + if (first) { + ibufp++; + addr_cnt++; + second_addr = (c == ';') ? current_addr : 1; + addr = addr_last; + break; + } + /* FALL THROUGH */ + default: + if (ibufp == hd) + return EOF; + else if (addr < 0 || addr_last < addr) { + sprintf(errmsg, "invalid address"); + return ERR; + } else + return addr; + } + /* NOTREACHED */ +} + + +#ifdef BACKWARDS +/* GET_THIRD_ADDR: get a legal address from the command buffer */ +#define GET_THIRD_ADDR(addr) \ +{ \ + long ol1, ol2; \ +\ + ol1 = first_addr, ol2 = second_addr; \ + if (extract_addr_range() < 0) \ + return ERR; \ + else if (addr_cnt == 0) { \ + sprintf(errmsg, "destination expected"); \ + return ERR; \ + } else if (second_addr < 0 || addr_last < second_addr) { \ + sprintf(errmsg, "invalid address"); \ + return ERR; \ + } \ + addr = second_addr; \ + first_addr = ol1, second_addr = ol2; \ +} +#else /* BACKWARDS */ +/* GET_THIRD_ADDR: get a legal address from the command buffer */ +#define GET_THIRD_ADDR(addr) \ +{ \ + long ol1, ol2; \ +\ + ol1 = first_addr, ol2 = second_addr; \ + if (extract_addr_range() < 0) \ + return ERR; \ + if (second_addr < 0 || addr_last < second_addr) { \ + sprintf(errmsg, "invalid address"); \ + return ERR; \ + } \ + addr = second_addr; \ + first_addr = ol1, second_addr = ol2; \ +} +#endif + + +/* GET_COMMAND_SUFFIX: verify the command suffix in the command buffer */ +#define GET_COMMAND_SUFFIX() { \ + int done = 0; \ + do { \ + switch(*ibufp) { \ + case 'p': \ + gflag |= GPR, ibufp++; \ + break; \ + case 'l': \ + gflag |= GLS, ibufp++; \ + break; \ + case 'n': \ + gflag |= GNP, ibufp++; \ + break; \ + default: \ + done++; \ + } \ + } while (!done); \ + if (*ibufp++ != '\n') { \ + sprintf(errmsg, "invalid command suffix"); \ + return ERR; \ + } \ +} + + +/* sflags */ +#define SGG 001 /* complement previous global substitute suffix */ +#define SGP 002 /* complement previous print suffix */ +#define SGR 004 /* use last regex instead of last pat */ +#define SGF 010 /* repeat last substitution */ + +int patlock = 0; /* if set, pattern not freed by get_compiled_pattern() */ + +long rows = 22; /* scroll length: ws_row - 2 */ + +/* exec_command: execute the next command in command buffer; return print + request, if any */ +int +exec_command() +{ + extern long u_current_addr; + extern long u_addr_last; + + static pattern_t *pat = NULL; + static int sgflag = 0; + static int sgnum = 0; + + pattern_t *tpat; + char *fnp; + int gflag = 0; + int sflags = 0; + long addr = 0; + int n = 0; + int c; + + SKIP_BLANKS(); + switch(c = *ibufp++) { + case 'a': + GET_COMMAND_SUFFIX(); + if (!isglobal) clear_undo_stack(); + if (append_lines(second_addr) < 0) + return ERR; + break; + case 'c': + if (check_addr_range(current_addr, current_addr) < 0) + return ERR; + GET_COMMAND_SUFFIX(); + if (!isglobal) clear_undo_stack(); + if (delete_lines(first_addr, second_addr) < 0 || + append_lines(current_addr) < 0) + return ERR; + break; + case 'd': + if (check_addr_range(current_addr, current_addr) < 0) + return ERR; + GET_COMMAND_SUFFIX(); + if (!isglobal) clear_undo_stack(); + if (delete_lines(first_addr, second_addr) < 0) + return ERR; + else if ((addr = INC_MOD(current_addr, addr_last)) != 0) + current_addr = addr; + break; + case 'e': + if (modified && !scripted) + return EMOD; + /* fall through */ + case 'E': + if (addr_cnt > 0) { + sprintf(errmsg, "unexpected address"); + return ERR; + } else if (!isspace(*ibufp)) { + sprintf(errmsg, "unexpected command suffix"); + return ERR; + } else if ((fnp = get_filename()) == NULL) + return ERR; + GET_COMMAND_SUFFIX(); + if (delete_lines(1, addr_last) < 0) + return ERR; + clear_undo_stack(); + if (close_sbuf() < 0) + return ERR; + else if (open_sbuf() < 0) + return FATAL; + if (*fnp && *fnp != '!') strcpy(old_filename, fnp); +#ifdef BACKWARDS + if (*fnp == '\0' && *old_filename == '\0') { + sprintf(errmsg, "no current filename"); + return ERR; + } +#endif + if (read_file(*fnp ? fnp : old_filename, 0) < 0) + return ERR; + clear_undo_stack(); + modified = 0; + u_current_addr = u_addr_last = -1; + break; + case 'f': + if (addr_cnt > 0) { + sprintf(errmsg, "unexpected address"); + return ERR; + } else if (!isspace(*ibufp)) { + sprintf(errmsg, "unexpected command suffix"); + return ERR; + } else if ((fnp = get_filename()) == NULL) + return ERR; + else if (*fnp == '!') { + sprintf(errmsg, "invalid redirection"); + return ERR; + } + GET_COMMAND_SUFFIX(); + if (*fnp) strcpy(old_filename, fnp); + printf("%s\n", strip_escapes(old_filename)); + break; + case 'g': + case 'v': + case 'G': + case 'V': + if (isglobal) { + sprintf(errmsg, "cannot nest global commands"); + return ERR; + } else if (check_addr_range(1, addr_last) < 0) + return ERR; + else if (build_active_list(c == 'g' || c == 'G') < 0) + return ERR; + else if (n = (c == 'G' || c == 'V')) + GET_COMMAND_SUFFIX(); + isglobal++; + if (exec_global(n, gflag) < 0) + return ERR; + break; + case 'h': + if (addr_cnt > 0) { + sprintf(errmsg, "unexpected address"); + return ERR; + } + GET_COMMAND_SUFFIX(); + if (*errmsg) fprintf(stderr, "%s\n", errmsg); + break; + case 'H': + if (addr_cnt > 0) { + sprintf(errmsg, "unexpected address"); + return ERR; + } + GET_COMMAND_SUFFIX(); + if ((garrulous = 1 - garrulous) && *errmsg) + fprintf(stderr, "%s\n", errmsg); + break; + case 'i': + if (second_addr == 0) { + sprintf(errmsg, "invalid address"); + return ERR; + } + GET_COMMAND_SUFFIX(); + if (!isglobal) clear_undo_stack(); + if (append_lines(second_addr - 1) < 0) + return ERR; + break; + case 'j': + if (check_addr_range(current_addr, current_addr + 1) < 0) + return ERR; + GET_COMMAND_SUFFIX(); + if (!isglobal) clear_undo_stack(); + if (first_addr != second_addr && + join_lines(first_addr, second_addr) < 0) + return ERR; + break; + case 'k': + c = *ibufp++; + if (second_addr == 0) { + sprintf(errmsg, "invalid address"); + return ERR; + } + GET_COMMAND_SUFFIX(); + if (mark_line_node(get_addressed_line_node(second_addr), c) < 0) + return ERR; + break; + case 'l': + if (check_addr_range(current_addr, current_addr) < 0) + return ERR; + GET_COMMAND_SUFFIX(); + if (display_lines(first_addr, second_addr, gflag | GLS) < 0) + return ERR; + gflag = 0; + break; + case 'm': + if (check_addr_range(current_addr, current_addr) < 0) + return ERR; + GET_THIRD_ADDR(addr); + if (first_addr <= addr && addr < second_addr) { + sprintf(errmsg, "invalid destination"); + return ERR; + } + GET_COMMAND_SUFFIX(); + if (!isglobal) clear_undo_stack(); + if (move_lines(addr) < 0) + return ERR; + break; + case 'n': + if (check_addr_range(current_addr, current_addr) < 0) + return ERR; + GET_COMMAND_SUFFIX(); + if (display_lines(first_addr, second_addr, gflag | GNP) < 0) + return ERR; + gflag = 0; + break; + case 'p': + if (check_addr_range(current_addr, current_addr) < 0) + return ERR; + GET_COMMAND_SUFFIX(); + if (display_lines(first_addr, second_addr, gflag | GPR) < 0) + return ERR; + gflag = 0; + break; + case 'P': + if (addr_cnt > 0) { + sprintf(errmsg, "unexpected address"); + return ERR; + } + GET_COMMAND_SUFFIX(); + prompt = prompt ? NULL : optarg ? optarg : dps; + break; + case 'q': + case 'Q': + if (addr_cnt > 0) { + sprintf(errmsg, "unexpected address"); + return ERR; + } + GET_COMMAND_SUFFIX(); + gflag = (modified && !scripted && c == 'q') ? EMOD : EOF; + break; + case 'r': + if (!isspace(*ibufp)) { + sprintf(errmsg, "unexpected command suffix"); + return ERR; + } else if (addr_cnt == 0) + second_addr = addr_last; + if ((fnp = get_filename()) == NULL) + return ERR; + GET_COMMAND_SUFFIX(); + if (!isglobal) clear_undo_stack(); + if (*old_filename == '\0' && *fnp != '!') + strcpy(old_filename, fnp); +#ifdef BACKWARDS + if (*fnp == '\0' && *old_filename == '\0') { + sprintf(errmsg, "no current filename"); + return ERR; + } +#endif + if ((addr = read_file(*fnp ? fnp : old_filename, second_addr)) < 0) + return ERR; + else if (addr && addr != addr_last) + modified = 1; + break; + case 's': + do { + switch(*ibufp) { + case '\n': + sflags |=SGF; + break; + case 'g': + sflags |= SGG; + ibufp++; + break; + case 'p': + sflags |= SGP; + ibufp++; + break; + case 'r': + sflags |= SGR; + ibufp++; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + STRTOL(sgnum, ibufp); + sflags |= SGF; + sgflag &= ~GSG; /* override GSG */ + break; + default: + if (sflags) { + sprintf(errmsg, "invalid command suffix"); + return ERR; + } + } + } while (sflags && *ibufp != '\n'); + if (sflags && !pat) { + sprintf(errmsg, "no previous substitution"); + return ERR; + } else if (sflags & SGG) + sgnum = 0; /* override numeric arg */ + if (*ibufp != '\n' && *(ibufp + 1) == '\n') { + sprintf(errmsg, "invalid pattern delimiter"); + return ERR; + } + tpat = pat; + SPL1(); + if ((!sflags || (sflags & SGR)) && + (tpat = get_compiled_pattern()) == NULL) { + SPL0(); + return ERR; + } else if (tpat != pat) { + if (pat) { + regfree(pat); + free(pat); + } + pat = tpat; + patlock = 1; /* reserve pattern */ + } + SPL0(); + if (!sflags && extract_subst_tail(&sgflag, &sgnum) < 0) + return ERR; + else if (isglobal) + sgflag |= GLB; + else + sgflag &= ~GLB; + if (sflags & SGG) + sgflag ^= GSG; + if (sflags & SGP) + sgflag ^= GPR, sgflag &= ~(GLS | GNP); + do { + switch(*ibufp) { + case 'p': + sgflag |= GPR, ibufp++; + break; + case 'l': + sgflag |= GLS, ibufp++; + break; + case 'n': + sgflag |= GNP, ibufp++; + break; + default: + n++; + } + } while (!n); + if (check_addr_range(current_addr, current_addr) < 0) + return ERR; + GET_COMMAND_SUFFIX(); + if (!isglobal) clear_undo_stack(); + if (search_and_replace(pat, sgflag, sgnum) < 0) + return ERR; + break; + case 't': + if (check_addr_range(current_addr, current_addr) < 0) + return ERR; + GET_THIRD_ADDR(addr); + GET_COMMAND_SUFFIX(); + if (!isglobal) clear_undo_stack(); + if (copy_lines(addr) < 0) + return ERR; + break; + case 'u': + if (addr_cnt > 0) { + sprintf(errmsg, "unexpected address"); + return ERR; + } + GET_COMMAND_SUFFIX(); + if (pop_undo_stack() < 0) + return ERR; + break; + case 'w': + case 'W': + if ((n = *ibufp) == 'q' || n == 'Q') { + gflag = EOF; + ibufp++; + } + if (!isspace(*ibufp)) { + sprintf(errmsg, "unexpected command suffix"); + return ERR; + } else if ((fnp = get_filename()) == NULL) + return ERR; + if (addr_cnt == 0 && !addr_last) + first_addr = second_addr = 0; + else if (check_addr_range(1, addr_last) < 0) + return ERR; + GET_COMMAND_SUFFIX(); + if (*old_filename == '\0' && *fnp != '!') + strcpy(old_filename, fnp); +#ifdef BACKWARDS + if (*fnp == '\0' && *old_filename == '\0') { + sprintf(errmsg, "no current filename"); + return ERR; + } +#endif + if ((addr = write_file(*fnp ? fnp : old_filename, + (c == 'W') ? "a" : "w", first_addr, second_addr)) < 0) + return ERR; + else if (addr == addr_last) + modified = 0; + else if (modified && !scripted && n == 'q') + gflag = EMOD; + break; + case 'x': + if (addr_cnt > 0) { + sprintf(errmsg, "unexpected address"); + return ERR; + } + GET_COMMAND_SUFFIX(); +#ifdef DES + des = get_keyword(); +#else + sprintf(errmsg, "crypt unavailable"); + return ERR; +#endif + break; + case 'z': +#ifdef BACKWARDS + if (check_addr_range(first_addr = 1, current_addr + 1) < 0) +#else + if (check_addr_range(first_addr = 1, current_addr + !isglobal) < 0) +#endif + return ERR; + else if ('0' < *ibufp && *ibufp <= '9') + STRTOL(rows, ibufp); + GET_COMMAND_SUFFIX(); + if (display_lines(second_addr, min(addr_last, + second_addr + rows), gflag) < 0) + return ERR; + gflag = 0; + break; + case '=': + GET_COMMAND_SUFFIX(); + printf("%d\n", addr_cnt ? second_addr : addr_last); + break; + case '!': + if (addr_cnt > 0) { + sprintf(errmsg, "unexpected address"); + return ERR; + } else if ((sflags = get_shell_command()) < 0) + return ERR; + GET_COMMAND_SUFFIX(); + if (sflags) printf("%s\n", shcmd + 1); + system(shcmd + 1); + if (!scripted) printf("!\n"); + break; + case '\n': +#ifdef BACKWARDS + if (check_addr_range(first_addr = 1, current_addr + 1) < 0 +#else + if (check_addr_range(first_addr = 1, current_addr + !isglobal) < 0 +#endif + || display_lines(second_addr, second_addr, 0) < 0) + return ERR; + break; + default: + sprintf(errmsg, "unknown command"); + return ERR; + } + return gflag; +} + + +/* check_addr_range: return status of address range check */ +int +check_addr_range(n, m) + long n, m; +{ + if (addr_cnt == 0) { + first_addr = n; + second_addr = m; + } + if (first_addr > second_addr || 1 > first_addr || + second_addr > addr_last) { + sprintf(errmsg, "invalid address"); + return ERR; + } + return 0; +} + + +/* get_matching_node_addr: return the address of the next line matching a + pattern in a given direction. wrap around begin/end of editor buffer if + necessary */ +long +get_matching_node_addr(pat, dir) + pattern_t *pat; + int dir; +{ + char *s; + long n = current_addr; + line_t *lp; + + if (!pat) return ERR; + do { + if (n = dir ? INC_MOD(n, addr_last) : DEC_MOD(n, addr_last)) { + lp = get_addressed_line_node(n); + if ((s = get_sbuf_line(lp)) == NULL) + return ERR; + if (isbinary) + NUL_TO_NEWLINE(s, lp->len); + if (!regexec(pat, s, 0, NULL, 0)) + return n; + } + } while (n != current_addr); + sprintf(errmsg, "no match"); + return ERR; +} + + +/* get_filename: return pointer to copy of filename in the command buffer */ +char * +get_filename() +{ + static char *file = NULL; + static int filesz = 0; + + int n; + + if (*ibufp != '\n') { + SKIP_BLANKS(); + if (*ibufp == '\n') { + sprintf(errmsg, "invalid filename"); + return NULL; + } else if ((ibufp = get_extended_line(&n, 1)) == NULL) + return NULL; + else if (*ibufp == '!') { + ibufp++; + if ((n = get_shell_command()) < 0) + return NULL; + if (n) printf("%s\n", shcmd + 1); + return shcmd; + } else if (n - 1 > MAXPATHLEN) { + sprintf(errmsg, "filename too long"); + return NULL; + } + } +#ifndef BACKWARDS + else if (*old_filename == '\0') { + sprintf(errmsg, "no current filename"); + return NULL; + } +#endif + REALLOC(file, filesz, MAXPATHLEN + 1, NULL); + for (n = 0; *ibufp != '\n';) + file[n++] = *ibufp++; + file[n] = '\0'; + return is_legal_filename(file) ? file : NULL; +} + + +/* get_shell_command: read a shell command from stdin; return substitution + status */ +int +get_shell_command() +{ + static char *buf = NULL; + static int n = 0; + + char *s; /* substitution char pointer */ + int i = 0; + int j = 0; + + if (red) { + sprintf(errmsg, "shell access restricted"); + return ERR; + } else if ((s = ibufp = get_extended_line(&j, 1)) == NULL) + return ERR; + REALLOC(buf, n, j + 1, ERR); + buf[i++] = '!'; /* prefix command w/ bang */ + while (*ibufp != '\n') + switch (*ibufp) { + default: + REALLOC(buf, n, i + 2, ERR); + buf[i++] = *ibufp; + if (*ibufp++ == '\\') + buf[i++] = *ibufp++; + break; + case '!': + if (s != ibufp) { + REALLOC(buf, n, i + 1, ERR); + buf[i++] = *ibufp++; + } +#ifdef BACKWARDS + else if (shcmd == NULL || *(shcmd + 1) == '\0') +#else + else if (shcmd == NULL) +#endif + { + sprintf(errmsg, "no previous command"); + return ERR; + } else { + REALLOC(buf, n, i + shcmdi, ERR); + for (s = shcmd + 1; s < shcmd + shcmdi;) + buf[i++] = *s++; + s = ibufp++; + } + break; + case '%': + if (*old_filename == '\0') { + sprintf(errmsg, "no current filename"); + return ERR; + } + j = strlen(s = strip_escapes(old_filename)); + REALLOC(buf, n, i + j, ERR); + while (j--) + buf[i++] = *s++; + s = ibufp++; + break; + } + REALLOC(shcmd, shcmdsz, i + 1, ERR); + memcpy(shcmd, buf, i); + shcmd[shcmdi = i] = '\0'; + return *s == '!' || *s == '%'; +} + + +/* append_lines: insert text from stdin to after line n; stop when either a + single period is read or EOF; return status */ +int +append_lines(n) + long n; +{ + int l; + char *lp = ibuf; + char *eot; + undo_t *up = NULL; + + for (current_addr = n;;) { + if (!isglobal) { + if ((l = get_tty_line()) < 0) + return ERR; + else if (l == 0 || ibuf[l - 1] != '\n') { + clearerr(stdin); + return l ? EOF : 0; + } + lp = ibuf; + } else if (*(lp = ibufp) == '\0') + return 0; + else { + while (*ibufp++ != '\n') + ; + l = ibufp - lp; + } + if (l == 2 && lp[0] == '.' && lp[1] == '\n') { + return 0; + } + eot = lp + l; + SPL1(); + do { + if ((lp = put_sbuf_line(lp)) == 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 (lp != eot); + modified = 1; + SPL0(); + } + /* NOTREACHED */ +} + + +/* join_lines: replace a range of lines with the joined text of those lines */ +int +join_lines(from, to) + long from; + long to; +{ + static char *buf = NULL; + static int n; + + char *s; + int size = 0; + line_t *bp, *ep; + + ep = get_addressed_line_node(INC_MOD(to, addr_last)); + bp = get_addressed_line_node(from); + for (; bp != ep; bp = bp->q_forw) { + if ((s = get_sbuf_line(bp)) == NULL) + return ERR; + REALLOC(buf, n, size + bp->len, ERR); + memcpy(buf + size, s, bp->len); + size += bp->len; + } + REALLOC(buf, n, size + 2, ERR); + memcpy(buf + size, "\n", 2); + if (delete_lines(from, to) < 0) + return ERR; + current_addr = from - 1; + SPL1(); + if (put_sbuf_line(buf) == NULL || + push_undo_stack(UADD, current_addr, current_addr) == NULL) { + SPL0(); + return ERR; + } + modified = 1; + SPL0(); + return 0; +} + + +/* move_lines: move a range of lines */ +int +move_lines(addr) + long addr; +{ + line_t *b1, *a1, *b2, *a2; + long n = INC_MOD(second_addr, addr_last); + long p = first_addr - 1; + int done = (addr == first_addr - 1 || addr == second_addr); + + SPL1(); + if (done) { + a2 = get_addressed_line_node(n); + b2 = get_addressed_line_node(p); + current_addr = second_addr; + } else if (push_undo_stack(UMOV, p, n) == NULL || + push_undo_stack(UMOV, addr, INC_MOD(addr, addr_last)) == NULL) { + SPL0(); + return ERR; + } else { + a1 = get_addressed_line_node(n); + if (addr < first_addr) { + b1 = get_addressed_line_node(p); + b2 = get_addressed_line_node(addr); + /* this get_addressed_line_node last! */ + } else { + b2 = get_addressed_line_node(addr); + b1 = get_addressed_line_node(p); + /* this get_addressed_line_node last! */ + } + a2 = b2->q_forw; + REQUE(b2, b1->q_forw); + REQUE(a1->q_back, a2); + REQUE(b1, a1); + current_addr = addr + ((addr < first_addr) ? + second_addr - first_addr + 1 : 0); + } + if (isglobal) + unset_active_nodes(b2->q_forw, a2); + modified = 1; + SPL0(); + return 0; +} + + +/* copy_lines: copy a range of lines; return status */ +int +copy_lines(addr) + long addr; +{ + line_t *lp, *np = get_addressed_line_node(first_addr); + undo_t *up = NULL; + long n = second_addr - first_addr + 1; + long m = 0; + + current_addr = addr; + if (first_addr <= addr && addr < second_addr) { + n = addr - first_addr + 1; + m = second_addr - addr; + } + for (; n > 0; n=m, m=0, np = get_addressed_line_node(current_addr + 1)) + for (; n-- > 0; np = np->q_forw) { + SPL1(); + if ((lp = dup_line_node(np)) == NULL) { + SPL0(); + return ERR; + } + add_line_node(lp); + if (up) + up->t = lp; + else if ((up = push_undo_stack(UADD, current_addr, + current_addr)) == NULL) { + SPL0(); + return ERR; + } + modified = 1; + SPL0(); + } + return 0; +} + + +/* delete_lines: delete a range of lines */ +int +delete_lines(from, to) + long from, to; +{ + line_t *n, *p; + + SPL1(); + if (push_undo_stack(UDEL, from, to) == NULL) { + SPL0(); + return ERR; + } + n = get_addressed_line_node(INC_MOD(to, addr_last)); + p = get_addressed_line_node(from - 1); + /* this get_addressed_line_node last! */ + if (isglobal) + unset_active_nodes(p->q_forw, n); + REQUE(p, n); + addr_last -= to - from + 1; + current_addr = from - 1; + modified = 1; + SPL0(); + return 0; +} + + +/* display_lines: print a range of lines to stdout */ +int +display_lines(from, to, gflag) + long from; + long to; + int gflag; +{ + line_t *bp; + line_t *ep; + char *s; + + if (!from) { + sprintf(errmsg, "invalid address"); + return ERR; + } + ep = get_addressed_line_node(INC_MOD(to, addr_last)); + bp = get_addressed_line_node(from); + for (; bp != ep; bp = bp->q_forw) { + if ((s = get_sbuf_line(bp)) == NULL) + return ERR; + if (put_tty_line(s, bp->len, current_addr = from++, gflag) < 0) + return ERR; + } + return 0; +} + + +#define MAXMARK 26 /* max number of marks */ + +line_t *mark[MAXMARK]; /* line markers */ +int markno; /* line marker count */ + +/* mark_line_node: set a line node mark */ +int +mark_line_node(lp, n) + line_t *lp; + int n; +{ + if (!islower(n)) { + sprintf(errmsg, "invalid mark character"); + return ERR; + } else if (mark[n - 'a'] == NULL) + markno++; + mark[n - 'a'] = lp; + return 0; +} + + +/* get_marked_node_addr: return address of a marked line */ +long +get_marked_node_addr(n) + int n; +{ + if (!islower(n)) { + sprintf(errmsg, "invalid mark character"); + return ERR; + } + return get_line_node_addr(mark[n - 'a']); +} + + +/* unmark_line_node: clear line node mark */ +void +unmark_line_node(lp) + line_t *lp; +{ + int i; + + for (i = 0; markno && i < MAXMARK; i++) + if (mark[i] == lp) { + mark[i] = NULL; + markno--; + } +} + + +/* dup_line_node: return a pointer to a copy of a line node */ +line_t * +dup_line_node(lp) + line_t *lp; +{ + line_t *np; + + if ((np = (line_t *) malloc(sizeof(line_t))) == NULL) { + fprintf(stderr, "%s\n", strerror(errno)); + sprintf(errmsg, "out of memory"); + return NULL; + } + np->seek = lp->seek; + np->len = lp->len; + return np; +} + + +/* has_trailing_escape: return the parity of escapes preceding a character + in a string */ +int +has_trailing_escape(s, t) + char *s; + char *t; +{ + return (s == t || *(t - 1) != '\\') ? 0 : !has_trailing_escape(s, t - 1); +} + + +/* strip_escapes: return copy of escaped string of at most length MAXPATHLEN */ +char * +strip_escapes(s) + char *s; +{ + static char *file = NULL; + static int filesz = 0; + + int i = 0; + + REALLOC(file, filesz, MAXPATHLEN + 1, NULL); + /* assert: no trailing escape */ + while (file[i++] = (*s == '\\') ? *++s : *s) + s++; + return file; +} + + +void +signal_hup(signo) + int signo; +{ + if (mutex) + sigflags |= (1 << (signo - 1)); + else handle_hup(signo); +} + + +void +signal_int(signo) + int signo; +{ + if (mutex) + sigflags |= (1 << (signo - 1)); + else handle_int(signo); +} + + +void +handle_hup(signo) + int signo; +{ + char *hup = NULL; /* hup filename */ + char *s; + int n; + + if (!sigactive) + quit(1); + sigflags &= ~(1 << (signo - 1)); + if (addr_last && write_file("ed.hup", "w", 1, addr_last) < 0 && + (s = getenv("HOME")) != NULL && + (n = strlen(s)) + 8 <= MAXPATHLEN && /* "ed.hup" + '/' */ + (hup = (char *) malloc(n + 10)) != NULL) { + strcpy(hup, s); + if (hup[n - 1] != '/') + hup[n] = '/', hup[n+1] = '\0'; + strcat(hup, "ed.hup"); + write_file(hup, "w", 1, addr_last); + } + quit(2); +} + + +void +handle_int(signo) + int signo; +{ + if (!sigactive) + quit(1); + sigflags &= ~(1 << (signo - 1)); +#ifdef _POSIX_SOURCE + siglongjmp(env, -1); +#else + longjmp(env, -1); +#endif +} + + +int cols = 72; /* wrap column */ + +void +handle_winch(signo) + int signo; +{ + struct winsize ws; /* window size structure */ + + sigflags &= ~(1 << (signo - 1)); + if (ioctl(0, TIOCGWINSZ, (char *) &ws) >= 0) { + if (ws.ws_row > 2) rows = ws.ws_row - 2; + if (ws.ws_col > 8) cols = ws.ws_col - 8; + } +} + + +/* is_legal_filename: return a legal filename */ +int +is_legal_filename(s) + char *s; +{ + if (red && (*s == '!' || !strcmp(s, "..") || strchr(s, '/'))) { + sprintf(errmsg, "shell access restricted"); + return 0; + } + return 1; +} diff --git a/bin/ed/re.c b/bin/ed/re.c index 7553d5f2e332..f4b9f292944b 100644 --- a/bin/ed/re.c +++ b/bin/ed/re.c @@ -1,12 +1,9 @@ /* re.c: This file contains the regular expression interface routines for the ed line editor. */ /*- - * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1993 Andrew Moore, Talke Studio. * All rights reserved. * - * This code is derived from software contributed to Berkeley - * by Andrew Moore, Talke Studio. - * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -15,18 +12,11 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -37,40 +27,34 @@ */ #ifndef lint -static char sccsid[] = "@(#)re.c 5.5 (Berkeley) 3/28/93"; +static char *rcsid = "@(#)$Id: re.c,v 1.6 1994/02/01 00:34:43 alm Exp $"; #endif /* not lint */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - #include "ed.h" -extern char *lhbuf; -extern int lhbufsz; -extern char *ibufp; -extern int ibufsz; + extern int patlock; -char errmsg[MAXFNAME + 40] = ""; +char errmsg[MAXPATHLEN + 40] = ""; -/* optpat: return pointer to compiled pattern from command buffer */ +/* get_compiled_pattern: return pointer to compiled pattern from command + buffer */ pattern_t * -optpat() +get_compiled_pattern() { static pattern_t *exp = NULL; char *exps; - char delim; + char delimiter; int n; - if ((delim = *ibufp) == ' ') { + if ((delimiter = *ibufp) == ' ') { sprintf(errmsg, "invalid pattern delimiter"); return NULL; - } else if (delim == '\n' || *++ibufp == '\n' || *ibufp == delim) { + } else if (delimiter == '\n' || *++ibufp == '\n' || *ibufp == delimiter) { if (!exp) sprintf(errmsg, "no previous pattern"); return exp; - } else if ((exps = getlhs(delim)) == NULL) + } else if ((exps = extract_pattern(delimiter)) == NULL) return NULL; /* buffer alloc'd && not reserved */ if (exp && !patlock) @@ -90,23 +74,24 @@ optpat() } -extern int isbinary; - -/* getlhs: copy a pattern string from the command buffer; return pointer - to the copy */ +/* extract_pattern: copy a pattern string from the command buffer; return + pointer to the copy */ char * -getlhs(delim) - int delim; +extract_pattern(delimiter) + int delimiter; { + static char *lhbuf = NULL; /* buffer */ + static int lhbufsz = 0; /* buffer size */ + char *nd; int len; - for (nd = ibufp; *nd != delim && *nd != '\n'; nd++) + for (nd = ibufp; *nd != delimiter && *nd != '\n'; nd++) switch (*nd) { default: break; case '[': - if ((nd = ccl(++nd)) == NULL) { + if ((nd = parse_char_class(++nd)) == NULL) { sprintf(errmsg, "unbalanced brackets ([])"); return NULL; } @@ -119,17 +104,17 @@ getlhs(delim) break; } len = nd - ibufp; - CKBUF(lhbuf, lhbufsz, len + 1, NULL); + REALLOC(lhbuf, lhbufsz, len + 1, NULL); memcpy(lhbuf, ibufp, len); lhbuf[len] = '\0'; ibufp = nd; - return (isbinary) ? nultonl(lhbuf, len) : lhbuf; + return (isbinary) ? NUL_TO_NEWLINE(lhbuf, len) : lhbuf; } -/* ccl: expand a POSIX character class */ +/* parse_char_class: expand a POSIX character class */ char * -ccl(s) +parse_char_class(s) char *s; { int c, d; diff --git a/bin/ed/sub.c b/bin/ed/sub.c new file mode 100644 index 000000000000..c93d258c8cd2 --- /dev/null +++ b/bin/ed/sub.c @@ -0,0 +1,263 @@ +/* sub.c: This file contains the substitution routines for the ed + line editor */ +/*- + * Copyright (c) 1993 Andrew Moore, Talke Studio. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char *rcsid = "@(#)$Id: sub.c,v 1.1 1994/02/01 00:34:44 alm Exp $"; +#endif /* not lint */ + +#include "ed.h" + + +char *rhbuf; /* rhs substitution buffer */ +int rhbufsz; /* rhs substitution buffer size */ +int rhbufi; /* rhs substitution buffer index */ + +/* extract_subst_tail: extract substitution tail from the command buffer */ +int +extract_subst_tail(flagp, np) + int *flagp; + int *np; +{ + char delimiter; + + *flagp = *np = 0; + if ((delimiter = *ibufp) == '\n') { + rhbufi = 0; + *flagp = GPR; + return 0; + } else if (extract_subst_template() == NULL) + return ERR; + else if (*ibufp == '\n') { + *flagp = GPR; + return 0; + } else if (*ibufp == delimiter) + ibufp++; + if ('1' <= *ibufp && *ibufp <= '9') { + STRTOL(*np, ibufp); + return 0; + } else if (*ibufp == 'g') { + ibufp++; + *flagp = GSG; + return 0; + } + return 0; +} + + +/* extract_subst_template: return pointer to copy of substitution template + in the command buffer */ +char * +extract_subst_template() +{ + int n = 0; + int i = 0; + char c; + char delimiter = *ibufp++; + + if (*ibufp == '%' && *(ibufp + 1) == delimiter) { + ibufp++; + if (!rhbuf) sprintf(errmsg, "no previous substitution"); + return rhbuf; + } + while (*ibufp != delimiter) { + REALLOC(rhbuf, rhbufsz, i + 2, NULL); + if ((c = rhbuf[i++] = *ibufp++) == '\n' && *ibufp == '\0') { + i--, ibufp--; + break; + } else if (c != '\\') + ; + else if ((rhbuf[i++] = *ibufp++) != '\n') + ; + else if (!isglobal) { + while ((n = get_tty_line()) == 0 || + n > 0 && ibuf[n - 1] != '\n') + clearerr(stdin); + if (n < 0) + return NULL; + } + } + REALLOC(rhbuf, rhbufsz, i + 1, NULL); + rhbuf[rhbufi = i] = '\0'; + return rhbuf; +} + + +char *rbuf; /* substitute_matching_text buffer */ +int rbufsz; /* substitute_matching_text buffer size */ + +/* search_and_replace: for each line in a range, change text matching a pattern + according to a substitution template; return status */ +int +search_and_replace(pat, gflag, kth) + pattern_t *pat; + int gflag; + int kth; +{ + undo_t *up; + char *txt; + char *eot; + long lc; + int nsubs = 0; + line_t *lp; + int len; + + current_addr = first_addr - 1; + for (lc = 0; lc <= second_addr - first_addr; lc++) { + lp = get_addressed_line_node(++current_addr); + if ((len = substitute_matching_text(pat, lp, gflag, kth)) < 0) + return ERR; + else if (len) { + up = NULL; + if (delete_lines(current_addr, current_addr) < 0) + return ERR; + txt = rbuf; + eot = rbuf + len; + SPL1(); + do { + if ((txt = put_sbuf_line(txt)) == NULL) { + SPL0(); + return ERR; + } else if (up) + up->t = get_addressed_line_node(current_addr); + else if ((up = push_undo_stack(UADD, + current_addr, current_addr)) == NULL) { + SPL0(); + return ERR; + } + } while (txt != eot); + SPL0(); + nsubs++; + } + } + if (nsubs == 0 && !(gflag & GLB)) { + sprintf(errmsg, "no match"); + return ERR; + } else if ((gflag & (GPR | GLS | GNP)) && + display_lines(current_addr, current_addr, gflag) < 0) + return ERR; + return 0; +} + + +/* substitute_matching_text: replace text matched by a pattern according to + a substitution template; return pointer to the modified text */ +int +substitute_matching_text(pat, lp, gflag, kth) + pattern_t *pat; + line_t *lp; + int gflag; + int kth; +{ + int off = 0; + int changed = 0; + int matchno = 0; + int i = 0; + regmatch_t rm[SE_MAX]; + char *txt; + char *eot; + + if ((txt = get_sbuf_line(lp)) == NULL) + return ERR; + if (isbinary) + NUL_TO_NEWLINE(txt, lp->len); + eot = txt + lp->len; + if (!regexec(pat, txt, SE_MAX, rm, 0)) { + do { + if (!kth || kth == ++matchno) { + changed++; + i = rm[0].rm_so; + REALLOC(rbuf, rbufsz, off + i, ERR); + if (isbinary) + NEWLINE_TO_NUL(txt, rm[0].rm_eo); + memcpy(rbuf + off, txt, i); + off += i; + if ((off = apply_subst_template(txt, rm, off, + pat->re_nsub)) < 0) + return ERR; + } else { + i = rm[0].rm_eo; + REALLOC(rbuf, rbufsz, off + i, ERR); + if (isbinary) + NEWLINE_TO_NUL(txt, i); + memcpy(rbuf + off, txt, i); + off += i; + } + txt += rm[0].rm_eo; + } while (*txt && (!changed || (gflag & GSG) && rm[0].rm_eo) && + !regexec(pat, txt, SE_MAX, rm, REG_NOTBOL)); + i = eot - txt; + REALLOC(rbuf, rbufsz, off + i + 2, ERR); + if (i > 0 && !rm[0].rm_eo && (gflag & GSG)) { + sprintf(errmsg, "infinite substitution loop"); + return ERR; + } + if (isbinary) + NEWLINE_TO_NUL(txt, i); + memcpy(rbuf + off, txt, i); + memcpy(rbuf + off + i, "\n", 2); + } + return changed ? off + i + 1 : 0; +} + + +/* apply_subst_template: modify text according to a substitution template; + return offset to end of modified text */ +int +apply_subst_template(boln, rm, off, re_nsub) + char *boln; + regmatch_t *rm; + int off; + int re_nsub; +{ + int j = 0; + int k = 0; + int n; + char *sub = rhbuf; + + for (; sub - rhbuf < rhbufi; sub++) + if (*sub == '&') { + j = rm[0].rm_so; + k = rm[0].rm_eo; + REALLOC(rbuf, rbufsz, off + k - j, ERR); + while (j < k) + rbuf[off++] = boln[j++]; + } else if (*sub == '\\' && '1' <= *++sub && *sub <= '9' && + (n = *sub - '0') <= re_nsub) { + j = rm[n].rm_so; + k = rm[n].rm_eo; + REALLOC(rbuf, rbufsz, off + k - j, ERR); + while (j < k) + rbuf[off++] = boln[j++]; + } else { + REALLOC(rbuf, rbufsz, off + 1, ERR); + rbuf[off++] = *sub; + } + REALLOC(rbuf, rbufsz, off + 1, ERR); + rbuf[off] = '\0'; + return off; +} diff --git a/bin/ed/test/Makefile b/bin/ed/test/Makefile index ca45a5183ebe..84166c141679 100644 --- a/bin/ed/test/Makefile +++ b/bin/ed/test/Makefile @@ -1,17 +1,23 @@ +SHELL= /bin/sh ED= ../obj/ed -all: build test - @echo done +all: check + @: + +check: build test + @if grep -h '\*\*\*' errs.o scripts.o; then :; else \ + echo "tests completed successfully."; \ + fi build: mkscripts.sh - @echo building test scripts... - @chmod +x mkscripts.sh - @./mkscripts.sh ${ED} + @if [ -f errs.o ]; then :; else \ + echo "building test scripts for $(ED) ..."; \ + $(SHELL) mkscripts.sh $(ED); \ + fi test: build ckscripts.sh - @echo running test scripts... - @chmod +x ckscripts.sh - @./ckscripts.sh ${ED} + @echo testing $(ED) ... + @$(SHELL) ckscripts.sh $(ED) clean: - rm -f *.ed *.[oz] *~ + rm -f *.ed *.red *.[oz] *~ diff --git a/bin/ed/test/README b/bin/ed/test/README index 8917f36acec8..ab66b9228cd5 100644 --- a/bin/ed/test/README +++ b/bin/ed/test/README @@ -19,14 +19,6 @@ which look like: or: *** Output u.o of script u.ed is incorrect *** -It is assumed that the ed being tested processes escapes (\) in file names. -This is so that a name starting with bang (!) can be read, via: - r \!file -Without the escape, a POSIX ed would attempt to read the output of -the shell command `file'. If the ed being tested does not support escape -processing on file names, then the script `mkscripts.sh' should be modified -accordingly. - The POSIX requirement that an address range not be used where at most a single address is expected has been relaxed in this version of ed. Therefore, the following scripts which test for compliance with this @@ -36,6 +28,3 @@ a1-err.ed i1-err.ed k1-err.ed r1-err.ed - -In addition, one of bang1-err.ed or bang2.ed will fail, depending on whether or -not ed was compiled with the VI_BANG directive. diff --git a/bin/ed/test/addr.d b/bin/ed/test/addr.d new file mode 100644 index 000000000000..8f7ba1b5d359 --- /dev/null +++ b/bin/ed/test/addr.d @@ -0,0 +1,9 @@ +line 1 +line 2 +line 3 +line 4 +line5 +1ine6 +line7 +line8 +line9 diff --git a/bin/ed/test/addr.r b/bin/ed/test/addr.r new file mode 100644 index 000000000000..04caf17f4228 --- /dev/null +++ b/bin/ed/test/addr.r @@ -0,0 +1,2 @@ +line 2 +line9 diff --git a/bin/ed/test/addr.t b/bin/ed/test/addr.t new file mode 100644 index 000000000000..750b224ed888 --- /dev/null +++ b/bin/ed/test/addr.t @@ -0,0 +1,5 @@ +1 d +1 1 d +1,2,d +1;+ + ,d +1,2;., + 2d diff --git a/bin/ed/test/bang2.r b/bin/ed/test/bang2.r deleted file mode 100644 index 65f58a262a1b..000000000000 --- a/bin/ed/test/bang2.r +++ /dev/null @@ -1,4 +0,0 @@ -line 1 -hello world! -line 4 -hello world diff --git a/bin/ed/test/bang2.t b/bin/ed/test/bang2.t deleted file mode 100644 index 14c681d44ade..000000000000 --- a/bin/ed/test/bang2.t +++ /dev/null @@ -1,2 +0,0 @@ -.!echo hello world -2,3!echo hello world! diff --git a/bin/ed/test/ckscripts.sh b/bin/ed/test/ckscripts.sh index 87a7e9beb560..edc935d28701 100644 --- a/bin/ed/test/ckscripts.sh +++ b/bin/ed/test/ckscripts.sh @@ -5,26 +5,24 @@ PATH="/bin:/usr/bin:/usr/local/bin/:." ED=$1 -[ X"$ED" = X -o ! -x $ED ] && ED="../ed" [ ! -x $ED ] && { echo "$ED: cannot execute"; exit 1; } -# Run the *-err.ed scripts first, since these don't generate output; -# rename then to *-err.ed~; they exit with non-zero status -for i in *-err.ed; do - echo $i~ +# Run the *.red scripts first, since these don't generate output; +# they exit with non-zero status +for i in *.red; do + echo $i if $i; then - echo "*** The script $i~ exited abnormally ***" + echo "*** The script $i exited abnormally ***" fi - mv $i $i~ done >errs.o 2>&1 # Run the remainding scripts; they exit with zero status for i in *.ed; do - base=`expr $i : '\([^.]*\)'` +# base=`expr $i : '\([^.]*\)'` # base=`echo $i | sed 's/\..*//'` -# base=`$ED - \!"echo \\\\$i" <<-EOF -# s/\..* -# EOF` + base=`$ED - \!"echo $i" <<-EOF + s/\..* + EOF` if $base.ed; then if cmp -s $base.o $base.r; then :; else echo "*** Output $base.o of script $i is incorrect ***" diff --git a/bin/ed/test/bang2.d b/bin/ed/test/g5.d index 92f337e977f2..a92d664bc20a 100644 --- a/bin/ed/test/bang2.d +++ b/bin/ed/test/g5.d @@ -1,5 +1,3 @@ line 1 line 2 line 3 -line 4 -line5 diff --git a/bin/ed/test/g5.r b/bin/ed/test/g5.r new file mode 100644 index 000000000000..15a26758bac2 --- /dev/null +++ b/bin/ed/test/g5.r @@ -0,0 +1,9 @@ +line 1 +line 2 +line 3 +line 2 +line 3 +line 1 +line 3 +line 1 +line 2 diff --git a/bin/ed/test/g5.t b/bin/ed/test/g5.t new file mode 100644 index 000000000000..e213481d54ce --- /dev/null +++ b/bin/ed/test/g5.t @@ -0,0 +1,2 @@ +g/./1,3t$\ +1d diff --git a/bin/ed/test/mkscripts.sh b/bin/ed/test/mkscripts.sh index 724db0cc05a9..fa3147f56328 100644 --- a/bin/ed/test/mkscripts.sh +++ b/bin/ed/test/mkscripts.sh @@ -3,69 +3,71 @@ PATH="/bin:/usr/bin:/usr/local/bin/:." ED=$1 -[ X"$ED" = X -o ! -x $ED ] && ED="../ed" [ ! -x $ED ] && { echo "$ED: cannot execute"; exit 1; } for i in *.t; do # base=${i%.*} # base=`echo $i | sed 's/\..*//'` - base=`expr $i : '\([^.]*\)'` - ( - echo "#!/bin/sh -" - echo "$ED - <<\EOT" - echo "r \\$base.d" - cat $i - echo "w \\$base.o" - echo EOT - ) >$base.ed - chmod +x $base.ed -# The following is pretty ugly and not appropriate use of ed -# but the point is that it can be done... -# base=`$ED - \!"echo \\\\$i" <<-EOF -# s/\..* -# EOF` -# $ED - <<-EOF -# a -# #!/bin/sh - -# $ED - <<\EOT -# r \\$base.d -# w \\$base.o -# EOT -# . -# -2r \\$i -# w \\$base.ed -# !chmod +x \\$base.ed -# EOF +# base=`expr $i : '\([^.]*\)'` +# ( +# echo "#!/bin/sh -" +# echo "$ED - <<\EOT" +# echo "r $base.d" +# cat $i +# echo "w $base.o" +# echo EOT +# ) >$base.ed +# chmod +x $base.ed +# The following is pretty ugly way of doing the above, and not appropriate +# use of ed but the point is that it can be done... + base=`$ED - \!"echo $i" <<-EOF + s/\..* + EOF` + $ED - <<-EOF + a + #!/bin/sh - + $ED - <<\EOT + H + r $base.d + w $base.o + EOT + . + -2r $i + w $base.ed + !chmod +x $base.ed + EOF done for i in *.err; do # base=${i%.*} # base=`echo $i | sed 's/\..*//'` - base=`expr $i : '\([^.]*\)'` - ( - echo "#!/bin/sh -" - echo "$ED - <<\EOT" - echo H - echo "r \\$base.err" - cat $i - echo "w \\$base.o" - echo EOT - ) >$base-err.ed - chmod +x $base-err.ed -# base=`$ED - \!"echo \\\\$i" <<-EOF -# s/\..* -# EOF` -# $ED - <<-EOF -# a -# #!/bin/sh - -# $ED - <<\EOT -# H -# r \\$base.err -# w \\$base.o -# EOT -# . -# -2r \\$i -# w \\${base}-err.ed -# !chmod +x ${base}-err.ed -# EOF +# base=`expr $i : '\([^.]*\)'` +# ( +# echo "#!/bin/sh -" +# echo "$ED - <<\EOT" +# echo H +# echo "r $base.err" +# cat $i +# echo "w $base.o" +# echo EOT +# ) >$base-err.ed +# chmod +x $base-err.ed +# The following is pretty ugly way of doing the above, and not appropriate +# use of ed but the point is that it can be done... + base=`$ED - \!"echo $i" <<-EOF + s/\..* + EOF` + $ED - <<-EOF + a + #!/bin/sh - + $ED - <<\EOT + H + r $base.err + w $base.o + EOT + . + -2r $i + w ${base}.red + !chmod +x ${base}.red + EOF done diff --git a/bin/ed/undo.c b/bin/ed/undo.c new file mode 100644 index 000000000000..a12e1c48e753 --- /dev/null +++ b/bin/ed/undo.c @@ -0,0 +1,154 @@ +/* undo.c: This file contains the undo routines for the ed line editor */ +/*- + * Copyright (c) 1993 Andrew Moore, Talke Studio. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char *rcsid = "@(#)$Id: undo.c,v 1.1 1994/02/01 00:34:44 alm Exp $"; +#endif /* not lint */ + +#include "ed.h" + + +#define USIZE 100 /* undo stack size */ +undo_t *ustack = NULL; /* undo stack */ +long usize = 0; /* stack size variable */ +long u_p = 0; /* undo stack pointer */ + +/* push_undo_stack: return pointer to intialized undo node */ +undo_t * +push_undo_stack(type, from, to) + int type; + long from; + long to; +{ + undo_t *t; + +#if defined(sun) || defined(NO_REALLOC_NULL) + if (ustack == NULL && + (ustack = (undo_t *) malloc((usize = USIZE) * sizeof(undo_t))) == NULL) { + fprintf(stderr, "%s\n", strerror(errno)); + sprintf(errmsg, "out of memory"); + return NULL; + } +#endif + t = ustack; + if (u_p < usize || + (t = (undo_t *) realloc(ustack, (usize += USIZE) * sizeof(undo_t))) != NULL) { + ustack = t; + ustack[u_p].type = type; + ustack[u_p].t = get_addressed_line_node(to); + ustack[u_p].h = get_addressed_line_node(from); + return ustack + u_p++; + } + /* out of memory - release undo stack */ + fprintf(stderr, "%s\n", strerror(errno)); + sprintf(errmsg, "out of memory"); + clear_undo_stack(); + free(ustack); + ustack = NULL; + usize = 0; + return NULL; +} + + +/* USWAP: swap undo nodes */ +#define USWAP(x,y) { \ + undo_t utmp; \ + utmp = x, x = y, y = utmp; \ +} + + +long u_current_addr = -1; /* if >= 0, undo enabled */ +long u_addr_last = -1; /* if >= 0, undo enabled */ + +/* pop_undo_stack: undo last change to the editor buffer */ +int +pop_undo_stack() +{ + long n; + long o_current_addr = current_addr; + long o_addr_last = addr_last; + + if (u_current_addr == -1 || u_addr_last == -1) { + sprintf(errmsg, "nothing to undo"); + return ERR; + } else if (u_p) + modified = 1; + get_addressed_line_node(0); /* this get_addressed_line_node last! */ + SPL1(); + for (n = u_p; n-- > 0;) { + switch(ustack[n].type) { + case UADD: + REQUE(ustack[n].h->q_back, ustack[n].t->q_forw); + break; + case UDEL: + REQUE(ustack[n].h->q_back, ustack[n].h); + REQUE(ustack[n].t, ustack[n].t->q_forw); + break; + case UMOV: + case VMOV: + REQUE(ustack[n - 1].h, ustack[n].h->q_forw); + REQUE(ustack[n].t->q_back, ustack[n - 1].t); + REQUE(ustack[n].h, ustack[n].t); + n--; + break; + default: + /*NOTREACHED*/ + ; + } + ustack[n].type ^= 1; + } + /* reverse undo stack order */ + for (n = u_p; n-- > (u_p + 1)/ 2;) + USWAP(ustack[n], ustack[u_p - 1 - n]); + if (isglobal) + clear_active_list(); + current_addr = u_current_addr, u_current_addr = o_current_addr; + addr_last = u_addr_last, u_addr_last = o_addr_last; + SPL0(); + return 0; +} + + +/* clear_undo_stack: clear the undo stack */ +void +clear_undo_stack() +{ + line_t *lp, *ep, *tl; + + while (u_p--) + if (ustack[u_p].type == UDEL) { + ep = ustack[u_p].t->q_forw; + for (lp = ustack[u_p].h; lp != ep; lp = tl) { + unmark_line_node(lp); + tl = lp->q_forw; + free(lp); + } + } + u_p = 0; + u_current_addr = current_addr; + u_addr_last = addr_last; +} diff --git a/bin/expr/Makefile b/bin/expr/Makefile index c2db2b639aad..416707e76b98 100644 --- a/bin/expr/Makefile +++ b/bin/expr/Makefile @@ -3,8 +3,6 @@ PROG= expr SRCS= expr.c CLEANFILES+= expr.c y.tab.h -LDADD+= -lgnuregex -DPADD+= /usr/lib/libgnuregex.a expr.c: ${YACC} -d ${.IMPSRC} diff --git a/bin/expr/expr.1 b/bin/expr/expr.1 index 8514d9dd64cc..3cfa19b8f589 100644 --- a/bin/expr/expr.1 +++ b/bin/expr/expr.1 @@ -28,7 +28,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $Id: expr.1,v 1.2 1993/10/04 22:07:27 jtc Exp $ +.\" $Id: expr.1,v 1.2.2.1 1994/05/01 15:59:55 jkh Exp $ .\" .Dd July 3, 1993 .Dt EXPR 1 @@ -83,7 +83,7 @@ operator matches against .Ar expr2 , which must be a regular expression. The regular expression is anchored -to the begining of the string with an implicit +to the beginning of the string with an implicit .Dq ^ . .Pp If the match succeeds and the pattern contains at least one regular diff --git a/bin/kill/kill.1 b/bin/kill/kill.1 index e61eb2f1bb93..8309a2031a5c 100644 --- a/bin/kill/kill.1 +++ b/bin/kill/kill.1 @@ -89,7 +89,7 @@ Some of the more commonly used signals: .Bd -ragged -offset indent -compact .Bl -column XXX TERM .It 1 HUP (hang up) -.It 2 INT (interupt) +.It 2 INT (interrupt) .It 3 QUIT (quit) .It 6 ABRT (abort) .It 9 KILL (non-catchable, non-ignorable kill) diff --git a/bin/ls/cmp.c b/bin/ls/cmp.c index bb3edf1294bb..17c2eb2dcd96 100644 --- a/bin/ls/cmp.c +++ b/bin/ls/cmp.c @@ -36,7 +36,7 @@ #ifndef lint static char sccsid[] = "@(#)cmp.c 5.4 (Berkeley) 3/8/91"; -static char rcsid[] = "$Header: /a/cvs/386BSD/src/bin/ls/cmp.c,v 1.2 1993/06/29 02:59:30 nate Exp $"; +static char rcsid[] = "$Header: /home/cvs/386BSD/src/bin/ls/cmp.c,v 1.2 1993/06/29 02:59:30 nate Exp $"; #endif /* not lint */ #include <sys/types.h> diff --git a/bin/ls/ls.1 b/bin/ls/ls.1 index 25c7e2005770..1363d00f80ae 100644 --- a/bin/ls/ls.1 +++ b/bin/ls/ls.1 @@ -34,7 +34,7 @@ .\" .\" @(#)ls.1 6.18 (Berkeley) 6/27/91 .\" -.\" $Header: /a/cvs/386BSD/src/bin/ls/ls.1,v 1.2 1993/06/29 02:59:31 nate Exp $ +.\" $Header: /home/cvs/386BSD/src/bin/ls/ls.1,v 1.2.2.1 1994/05/01 16:00:04 jkh Exp $ .\" .Dd June 27, 1991 .Dt LS 1 @@ -260,7 +260,7 @@ and setgroup-ID mode is set. The file is executable or the directory is searchable. .It Sy \- -The file is neither readable, writeable, exectutable, +The file is neither readable, writeable, executable, or set-user-ID or set-group-ID mode nor sticky. (See below.) .El .Pp @@ -278,7 +278,7 @@ or .It Sy t The sticky bit is set (mode .Li 1000 ) , -and is searcheable or executable. +and is searchable or executable. (See .Xr chmod 1 or diff --git a/bin/ls/ls.c b/bin/ls/ls.c index e4ba06a8e340..4c7cf5826c03 100644 --- a/bin/ls/ls.c +++ b/bin/ls/ls.c @@ -42,7 +42,7 @@ char copyright[] = #ifndef lint static char sccsid[] = "@(#)ls.c 5.48 (Berkeley) 4/3/91"; -static char rcsid[] = "$Header: /a/cvs/386BSD/src/bin/ls/ls.c,v 1.2 1993/06/29 02:59:32 nate Exp $"; +static char rcsid[] = "$Header: /home/cvs/386BSD/src/bin/ls/ls.c,v 1.2 1993/06/29 02:59:32 nate Exp $"; #endif /* not lint */ #include <sys/param.h> diff --git a/bin/ls/ls.h b/bin/ls/ls.h index 2b6ae3122beb..f1afc50514fa 100644 --- a/bin/ls/ls.h +++ b/bin/ls/ls.h @@ -35,7 +35,7 @@ * * @(#)ls.h 5.11 (Berkeley) 7/22/90 * - * $Header: /a/cvs/386BSD/src/bin/ls/ls.h,v 1.2 1993/06/29 02:59:32 nate Exp $ + * $Header: /home/cvs/386BSD/src/bin/ls/ls.h,v 1.2 1993/06/29 02:59:32 nate Exp $ */ typedef struct _lsstruct { diff --git a/bin/ls/print.c b/bin/ls/print.c index e63ca3055aac..605fd95fc906 100644 --- a/bin/ls/print.c +++ b/bin/ls/print.c @@ -36,7 +36,7 @@ #ifndef lint static char sccsid[] = "@(#)print.c 5.24 (Berkeley) 10/19/90"; -static char rcsid[] = "$Header: /a/cvs/386BSD/src/bin/ls/print.c,v 1.3 1993/10/14 17:26:38 jtc Exp $"; +static char rcsid[] = "$Header: /home/cvs/386BSD/src/bin/ls/print.c,v 1.3 1993/10/14 17:26:38 jtc Exp $"; #endif /* not lint */ #include <sys/param.h> diff --git a/bin/ls/util.c b/bin/ls/util.c index 0fa5ea55bf94..c638979a3239 100644 --- a/bin/ls/util.c +++ b/bin/ls/util.c @@ -36,7 +36,7 @@ #ifndef lint static char sccsid[] = "@(#)util.c 5.8 (Berkeley) 7/22/90"; -static char rcsid[] = "$Header: /a/cvs/386BSD/src/bin/ls/util.c,v 1.2 1993/06/29 02:59:34 nate Exp $"; +static char rcsid[] = "$Header: /home/cvs/386BSD/src/bin/ls/util.c,v 1.3 1993/11/13 01:40:24 ache Exp $"; #endif /* not lint */ #include <sys/types.h> @@ -47,11 +47,18 @@ prcopy(src, dest, len) register char *src, *dest; register int len; { - register int ch; + register unsigned char ch; while(len--) { ch = *src++; - *dest++ = isprint(ch) ? ch : '?'; + /* XXX: + * because *BSD don't have setlocale() (yet) + * here simple hack that allows ISO8859-x + * and koi8-r charsets in terminal mode. + * Note: range 0x80-0x9F skipped to avoid + * some kinda security hole on poor DEC VTs + */ + *dest++ = (ch >= 0xA0 || isprint(ch)) ? ch : '?'; } } diff --git a/bin/mkdir/mkdir.1 b/bin/mkdir/mkdir.1 index ca4d6251638b..d8d598e4b4d2 100644 --- a/bin/mkdir/mkdir.1 +++ b/bin/mkdir/mkdir.1 @@ -34,7 +34,7 @@ .\" .\" @(#)mkdir.1 6.9 (Berkeley) 6/27/91 .\" -.\" $Header: /a/cvs/386BSD/src/bin/mkdir/mkdir.1,v 1.2 1993/07/21 22:54:08 conklin Exp $ +.\" $Header: /home/cvs/386BSD/src/bin/mkdir/mkdir.1,v 1.2.2.1 1994/05/01 16:00:13 jkh Exp $ .\" .Dd June 27, 1991 .Dt MKDIR 1 diff --git a/bin/mkdir/mkdir.c b/bin/mkdir/mkdir.c index b824fdad1398..b4ec95857c9e 100644 --- a/bin/mkdir/mkdir.c +++ b/bin/mkdir/mkdir.c @@ -39,7 +39,7 @@ char copyright[] = #ifndef lint static char sccsid[] = "@(#)mkdir.c 5.7 (Berkeley) 5/31/90"; -static char rcsid[] = "$Header: /a/cvs/386BSD/src/bin/mkdir/mkdir.c,v 1.2 1993/07/21 22:54:09 conklin Exp $"; +static char rcsid[] = "$Header: /home/cvs/386BSD/src/bin/mkdir/mkdir.c,v 1.2 1993/07/21 22:54:09 conklin Exp $"; #endif /* not lint */ #include <sys/types.h> diff --git a/bin/mv/Makefile b/bin/mv/Makefile index 4c5c8e0c7d6d..d0f6f80e1633 100644 --- a/bin/mv/Makefile +++ b/bin/mv/Makefile @@ -1,4 +1,5 @@ -# @(#)Makefile 5.4 (Berkeley) 5/11/90 +# from: @(#)Makefile 5.4 (Berkeley) 5/11/90 +# $Id: Makefile,v 1.2 1993/11/22 23:54:22 jtc Exp $ PROG= mv diff --git a/bin/mv/mv.1 b/bin/mv/mv.1 index d338db0924de..392947a21562 100644 --- a/bin/mv/mv.1 +++ b/bin/mv/mv.1 @@ -32,7 +32,8 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" @(#)mv.1 6.9 (Berkeley) 7/27/91 +.\" from: @(#)mv.1 6.9 (Berkeley) 7/27/91 +.\" $Id: mv.1,v 1.2 1993/11/22 23:54:23 jtc Exp $ .\" .Dd July 27, 1991 .Dt MV 1 @@ -42,13 +43,12 @@ .Nd move files .Sh SYNOPSIS .Nm mv -.Op Fl f | Fl i +.Op Fl fi .Ar source target .Nm mv -.Op Fl f | Fl i -.Ar source ... source directory +.Op Fl fi +.Ar source ... target .Sh DESCRIPTION -.Pp In its first form, the .Nm mv utility renames the file named by the @@ -73,20 +73,15 @@ component of the named file. The following options are available: .Bl -tag -width flag .It Fl f -Do not prompt for confirmation before overwriting the destination -path. -(The +Do not prompt for confirmation if the destination path exists. +Any previous occurances of the .Fl i -option is ignored if the -.Fl f -option is specified.) +option will be ignored. .It Fl i -Causes -.Nm mv -to write a prompt to standard error before moving a file that would -overwrite an existing file. -If the response from the standard input begins with the character ``y'', -the move is attempted. +Prompt for confirmation if the destination path exists. +Any previous occurances of the +.Fl f +option will be ignored. .El .Pp It is an error for either the @@ -95,9 +90,10 @@ operand or the destination path to specify a directory unless both do. .Pp If the destination path does not have a mode which permits writing, .Nm mv -prompts the user for confirmation as specified for the -.Fl i -option. +prompts the user for confirmation. If the response from the +standard input begins with the character +.Sq y , +the move is attempted. .Pp As the .Xr rename 2 @@ -123,6 +119,5 @@ utility exits 0 on success, and >0 if an error occurs. .Sh STANDARDS The .Nm mv -utility is expected to be -.St -p1003.2 -compatible. +utility conforms to +.St -p1003.2-92 . diff --git a/bin/mv/mv.c b/bin/mv/mv.c index ca387b75fd3e..aa37d0229f72 100644 --- a/bin/mv/mv.c +++ b/bin/mv/mv.c @@ -41,7 +41,8 @@ char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)mv.c 5.11 (Berkeley) 4/3/91"; +/*static char sccsid[] = "from: @(#)mv.c 5.11 (Berkeley) 4/3/91";*/ +static char rcsid[] = "$Id: mv.c,v 1.2 1993/11/22 23:54:24 jtc Exp $"; #endif /* not lint */ #include <sys/param.h> @@ -57,6 +58,7 @@ static char sccsid[] = "@(#)mv.c 5.11 (Berkeley) 4/3/91"; #include "pathnames.h" int fflg, iflg; +int stdin_ok; main(argc, argv) int argc; @@ -70,26 +72,28 @@ main(argc, argv) int ch; char path[MAXPATHLEN + 1]; - while (((ch = getopt(argc, argv, "-if")) != EOF)) + while (((ch = getopt(argc, argv, "if")) != -1)) switch((char)ch) { case 'i': + fflg = 0; iflg = 1; break; case 'f': + iflg = 0; fflg = 1; break; - case '-': /* undocumented; for compatibility */ - goto endarg; case '?': default: usage(); } -endarg: argc -= optind; + argc -= optind; argv += optind; if (argc < 2) usage(); + stdin_ok = isatty(STDIN_FILENO); + /* * If the stat on the target fails or the target isn't a directory, * try the move. More than 2 arguments is an error in this case. @@ -126,20 +130,27 @@ do_move(from, to) char *from, *to; { struct stat sb; - int ask, ch; - /* - * Check access. If interactive and file exists, ask user if it - * should be replaced. Otherwise if file exists but isn't writable - * make sure the user wants to clobber it. + /* (1) If the destination path exists, the -f option is not specified + * and either of the following conditions are true: + * + * (a) The perimissions of the destination path do not permit + * writing and the standard input is a terminal. + * (b) The -i option is specified. + * + * the mv utility shall write a prompt to standard error and + * read a line from standard input. If the response is not + * affirmative, mv shall do nothing more with the current + * source file... */ if (!fflg && !access(to, F_OK)) { - ask = 0; + int ask = 0; + int ch; + if (iflg) { (void)fprintf(stderr, "overwrite %s? ", to); ask = 1; - } - else if (access(to, W_OK) && !stat(to, &sb)) { + } else if (stdin_ok && access(to, W_OK) && !stat(to, &sb)) { (void)fprintf(stderr, "override mode %o on %s? ", sb.st_mode & 07777, to); ask = 1; @@ -147,10 +158,24 @@ do_move(from, to) if (ask) { if ((ch = getchar()) != EOF && ch != '\n') while (getchar() != '\n'); - if (ch != 'y') + if (ch != 'y' && ch != 'Y') return(0); } } + + + /* (2) If rename() succeeds, mv shall do nothing more with the + * current source file. If it fails for any other reason than + * EXDEV, mv shall write a diagnostic message to the standard + * error and do nothing more with the current source file. + * + * (3) If the destination path exists, and it is a file of type + * directory and source_file is not a file of type directory, + * or it is a file not of type directory, and source file is + * a file of type directory, mv shall write a diagnostic + * message to standard error, and do nothing more with the + * current source file... + */ if (!rename(from, to)) return(0); @@ -160,9 +185,23 @@ do_move(from, to) return(1); } - /* - * If rename fails, and it's a regular file, do the copy internally; - * otherwise, use cp and rm. + + /* (4) If the destination path exists, mv shall attempt to remove it. + * If this fails for any reason, mv shall write a diagnostic + * message to the standard error and do nothing more with the + * current source file... + */ + if (!stat(to, &sb)) { + if ((S_ISDIR(sb.st_mode)) ? rmdir(to) : unlink(to)) { + (void) fprintf(stderr, + "mv: can't remove %s: %s\n", to, strerror(errno)); + return (1); + } + } + + + /* (5) The file hierarchy rooted in source_file shall be duplicated + * as a file hiearchy rooted in the destination path... */ if (stat(from, &sb)) { (void)fprintf(stderr, "mv: %s: %s\n", from, strerror(errno)); @@ -253,7 +292,8 @@ error(s) usage() { - (void)fprintf(stderr, -"usage: mv [-if] src target;\n or: mv [-if] src1 ... srcN directory\n"); + (void)fprintf(stderr, + "usage: mv [-fi] source_file target_file\n" + " mv [-fi] source_file ... target_dir\n"); exit(1); } diff --git a/bin/mv/pathnames.h b/bin/mv/pathnames.h index 584454d58d66..32d63cf9d666 100644 --- a/bin/mv/pathnames.h +++ b/bin/mv/pathnames.h @@ -30,7 +30,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)pathnames.h 5.2 (Berkeley) 5/31/90 + * from: @(#)pathnames.h 5.2 (Berkeley) 5/31/90 + * $Id: pathnames.h,v 1.2 1993/11/22 23:54:24 jtc Exp $ */ #define _PATH_RM "/bin/rm" diff --git a/bin/ps/print.c b/bin/ps/print.c index ce4be52cbd7b..5ef075c20da2 100644 --- a/bin/ps/print.c +++ b/bin/ps/print.c @@ -141,7 +141,7 @@ state(k, v) if (flag & SSINTR) /* interuptable (long) */ *cp = p->p_slptime >= MAXSLP ? 'I' : 'S'; else - *cp = (flag & SPAGE) ? 'P' : 'D'; + *cp = /* (flag & SPAGE) ? 'P' : */ 'D'; break; case SRUN: @@ -190,6 +190,8 @@ state(k, v) if (flag & (SSYS|SLOCK|SULOCK|SKEEP|SPHYSIO)) #endif *cp++ = 'L'; + if (flag & SUGID) + *cp++ = 'U'; if (k->ki_e->e_flag & EPROC_SLEADER) *cp++ = 's'; if ((flag & SCTTY) && k->ki_e->e_pgid == k->ki_e->e_tpgid) @@ -256,7 +258,8 @@ tname(k, v) if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) (void) printf("%-*s", v->width, "??"); else { - if (strncmp(ttname, "tty", 3) == 0) + if (strncmp(ttname, "tty", 3) == 0 || + strncmp(ttname, "cua", 3) == 0) ttname += 3; (void) printf("%*.*s%c", v->width-1, v->width-1, ttname, k->ki_e->e_flag & EPROC_CTTY ? ' ' : '-'); diff --git a/bin/ps/ps.1 b/bin/ps/ps.1 index bfb3fe5312bc..bf52964b9952 100644 --- a/bin/ps/ps.1 +++ b/bin/ps/ps.1 @@ -99,7 +99,7 @@ Extract the name list from the specified system instead of the default .Dq Pa /386bsd . .It Fl O Add the information associated with the space or comma separated list -of keywords specifed, after the process +of keywords specified, after the process .Tn ID , in the default information display. @@ -108,7 +108,7 @@ This causes the printed header to use the specified string instead of the standard header. .It Fl o Display information associated with the space or comma separated list -of keywords specifed. +of keywords specified. Keywords may be appended with an equals (``='') sign and a string. This causes the printed header to use the specified string instead of the standard header. @@ -161,7 +161,7 @@ Display information about processes without controlling terminals. .El .Pp A complete list of the available keywords are listed below. -Some of these keywords are further specifed as follows: +Some of these keywords are further specified as follows: .Bl -tag -width indent .It %cpu The cpu utilization of the process; this is a decaying average over up to @@ -176,44 +176,34 @@ The percentage of real memory used by this process. The flags (in hexadecimal) associated with the process as in the include file .Aq Pa sys/proc.h : -.Bl -column SNOCLDSTOP SNOCLDSTOP -.It Dv "SLOAD" Ta No "0x0000001 in core" -.It Dv "SSYS" Ta No "0x0000002 swapper or pager process" -.It Dv "SLOCK" Ta No "0x0000004 process being swapped out" -.It Dv "SSWAP" Ta No "0x0000008 save area flag" -.It Dv "STRC" Ta No "0x0000010 process is being traced" -.It Dv "SWTED" Ta No "0x0000020 another tracing flag" -.It Dv "SSINTR" Ta No "0x0000040 sleep is interruptible" -.It Dv "SPAGE" Ta No "0x0000080 process in page wait state" -.It Dv "SKEEP" Ta No "0x0000100 another flag to prevent swap out" -.It Dv "SOMASK" Ta No "0x0000200 restore old mask after taking signal" -.It Dv "SWEXIT" Ta No "0x0000400 working on exiting" -.It Dv "SPHYSIO" Ta No "0x0000800 doing physical" -.Tn I/O -.It Dv "SVFORK" Ta No "0x0001000 process resulted from" -.Xr vfork 2 -.It Dv "SVFDONE" Ta No "0x0002000 another" -.Xr vfork -flag -.It Dv "SNOVM" Ta No "0x0004000 no vm, parent in a" -.Xr vfork -.It Dv "SPAGV" Ta No "0x0008000 init data space on demand, from vnode" -.It Dv "SSEQL" Ta No "0x0010000 user warned of sequential vm behavior" -.It Dv "SUANOM" Ta No "0x0020000 user warned of random vm behavior" -.It Dv "STIMO" Ta No "0x0040000 timing out during sleep" -.It Dv "SNOCLDSTOP" Ta No "0x0080000 no" +.Bl -column SPAGEDAEMON SPAGEDAEMON +.It Dv "SLOAD" Ta No "0x00000001 in core" +.It Dv "SSYS" Ta No "0x00000002 swapper or pager process" +.It Dv "SSINTR" Ta No "0x00000004 process is in interruuptible sleep" +.It Dv "SCTTY" Ta No "0x00000008 process has a controlling terminal" +.It Dv "SPPWAIT" Ta No "0x00000010 waiting for child to exec or exit" +.It Dv "SEXEC" Ta No "0x00000020 process called" +.Xr exec 2 +.It Dv "STIMO" Ta No "0x00000040 sleep timed out" +.It Dv "SSEL" Ta No "0x00000080 selecting; wakeup/waiting danger" +.It Dv "SWEXIT" Ta No "0x00000100 process in" +.Xr exit 2 +.It Dv "SNOCLDSTOP" Ta No "0x00000200 no" .Dv SIGCHLD when children stop -.It Dv "SCTTY" Ta No "0x0100000 has a controlling terminal" -.It Dv "SOWEUPC" Ta No "0x0200000 owe process an addupc() call at next ast" -.\" the routine addupc is not documented in the man pages -.It Dv "SSEL" Ta No "0x0400000 selecting; wakeup/waiting danger" -.It Dv "SEXEC" Ta No "0x0800000 process called" -.Xr exec 2 -.It Dv "SHPUX" Ta No "0x1000000 \\*(tNHP-UX\\*(sP process -.Pq Dv HPUXCOMPAT -.It Dv "SULOCK" Ta No "0x2000000 locked in core after swap error" -.It Dv "SPTECHG" Ta No "0x4000000 pte's for process have changed" +.It Dv "SLOCK" Ta No "0x00000400 process is being swapped out" +.It Dv "SKEEP" Ta No "0x00000800 process canot be swapped out" +.It Dv "SPHYSIO" Ta No "0x00001000 process is performing physical" +.Tn I/O +.It Dv "SOWEUPC" Ta No "0x00002000 process is owed an addupc() call" +.It Dv "STRC" Ta No "0x00004000 process is being traced" +.It Dv "SWTED" Ta No "0x00008000 another tracing flag" +.It Dv "SUGID" Ta No "0x00020000 process changed uid/gid since last exec" +.It Dv "SADVLCK" Ta No "0x00040000 process may hold a" +.Tn POSIX +advisory lock +.It Dv "SPAGEDAEMON" Ta No "0x00080000 process has been scanned by pageout" +daemon .El .It lim The soft limit on memory used, specified via a call to @@ -244,8 +234,8 @@ The first letter indicates the run state of the process: Marks a process in disk (or other short term, uninterruptable) wait. .It I Marks a process that is idle (sleeping for longer than about 20 seconds). -.It P -Marks a process in page wait. +.\" .It P +.\" Marks a process in page wait. .It R Marks a runnable process. .It S @@ -270,14 +260,14 @@ scheduling priority. The process has specified a soft limit on memory requirements and is currently exceeding that limit; such a process is (necessarily) not swapped. -.It A -the process has asked for random page replacement -.Pf ( Dv VA_ANOM , -from -.Xr vadvise 2 , -for example, -.Xr lisp 1 -in a garbage collect). +.\" .It A +.\" the process has asked for random page replacement +.\" .Pf ( Dv VA_ANOM , +.\" from +.\" .Xr vadvise 2 , +.\" for example, +.\" .Xr lisp 1 +.\" in a garbage collect). .It E The process is trying to exit. .It L @@ -288,15 +278,15 @@ The process has reduced .Tn CPU scheduling priority (see .Xr setpriority 2 ) . -.It S -The process has asked for -.Tn FIFO -page replacement -.Pf ( Dv VA_SEQL , -from -.Xr vadvise 2 , -for example, a large image processing program using virtual memory to -sequentially address voluminous data). +.\" .It S +.\" The process has asked for +.\" .Tn FIFO +.\" page replacement +.\" .Pf ( Dv VA_SEQL , +.\" from +.\" .Xr vadvise 2 , +.\" for example, a large image processing program using virtual memory to +.\" sequentially address voluminous data). .It s The process is a session leader. .It V @@ -306,6 +296,18 @@ The process is suspended during a The process is swapped out. .It X The process is being traced or debugged. +.It U +The process has changed its uid or gid (with a call to +.Xr setuid 2 , +.Xr setgid 2 , +.Xr seteuid 2 , +.Xr setegid 2 , +.Xr setreuid 2 , +or +.Xr setregid 2 ) +since it last called +.Xr execve 2 . +This flag is also set when a set-uid or set-gid executable is loaded. .El .It tt An abbreviation for the pathname of the controlling terminal, if any. diff --git a/bin/rm/Makefile b/bin/rm/Makefile index f34f55214399..f2971f4fae95 100644 --- a/bin/rm/Makefile +++ b/bin/rm/Makefile @@ -1,4 +1,5 @@ -# @(#)Makefile 5.3 (Berkeley) 12/8/90 +# from: @(#)Makefile 5.3 (Berkeley) 12/8/90 +# $Id: Makefile,v 1.2 1993/11/22 23:53:15 jtc Exp $ PROG= rm LDADD= -lutil diff --git a/bin/rm/rm.1 b/bin/rm/rm.1 index ed4b10995fdd..750d63ed288c 100644 --- a/bin/rm/rm.1 +++ b/bin/rm/rm.1 @@ -32,7 +32,8 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" @(#)rm.1 6.9 (Berkeley) 7/27/91 +.\" from: @(#)rm.1 6.9 (Berkeley) 7/27/91 +.\" $Id: rm.1,v 1.2 1993/11/22 23:53:16 jtc Exp $ .\" .Dd July 27, 1991 .Dt RM 1 diff --git a/bin/rm/rm.c b/bin/rm/rm.c index 6b65b0ce2842..45d74488b7fd 100644 --- a/bin/rm/rm.c +++ b/bin/rm/rm.c @@ -38,17 +38,26 @@ char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)rm.c 4.27 (Berkeley) 1/27/92"; +/*static char sccsid[] = "from: @(#)rm.c 4.26 (Berkeley) 3/10/91";*/ +static char rcsid[] = "$Id: rm.c,v 1.6.2.1 1994/03/07 02:25:28 rgrimes Exp $"; #endif /* not lint */ -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/errno.h> -#include <fts.h> -#include <unistd.h> #include <stdio.h> #include <string.h> #include <stdlib.h> +#include <locale.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fts.h> + +int check __P((char *, char *, struct stat *)); +void checkdot __P((char **)); +void error __P((char *, int)); +void rmtree __P((char **)); +void rmfile __P((char **)); +void usage __P((void)); int dflag, fflag, iflag, retval, stdin_ok; @@ -60,16 +69,17 @@ int dflag, fflag, iflag, retval, stdin_ok; * file removal. */ +int main(argc, argv) int argc; char **argv; { - extern char *optarg; - extern int optind; int ch, rflag; + setlocale(LC_ALL, ""); + rflag = 0; - while ((ch = getopt(argc, argv, "dfiRr")) != EOF) + while ((ch = getopt(argc, argv, "dfiRr")) != -1) switch(ch) { case 'd': dflag = 1; @@ -97,25 +107,26 @@ main(argc, argv) usage(); checkdot(argv); - if (!*argv) - exit(retval); - stdin_ok = isatty(STDIN_FILENO); + if (*argv) { + stdin_ok = isatty(STDIN_FILENO); + + if (rflag) + rmtree(argv); + else + rmfile(argv); + } - if (rflag) - rmtree(argv); - else - rmfile(argv); exit(retval); } +void rmtree(argv) char **argv; { register FTS *fts; register FTSENT *p; register int needstat; - struct stat sb; /* * Remove a file hierarchy. If forcing removal (-f), or interactive @@ -129,18 +140,20 @@ rmtree(argv) */ #define SKIPPED 1 - if (!(fts = fts_open(argv, - needstat ? FTS_PHYSICAL : FTS_PHYSICAL|FTS_NOSTAT, - (int (*)())NULL))) { - (void)fprintf(stderr, "rm: %s.\n", strerror(errno)); - exit(1); + if (!(fts = fts_open(argv, needstat ? FTS_PHYSICAL|FTS_NOCHDIR : + FTS_PHYSICAL|FTS_NOCHDIR|FTS_NOSTAT, + (int (*)())NULL))) { + if (!fflag) + (void)fprintf(stderr, "rm: %s.\n", strerror(errno)); + exit (1); } - while (p = fts_read(fts)) { + + while ((p = fts_read(fts)) != NULL) { switch(p->fts_info) { case FTS_DNR: case FTS_ERR: error(p->fts_path, errno); - exit(1); + continue; /* * FTS_NS: assume that if can't stat the file, it can't be * unlinked. @@ -153,7 +166,7 @@ rmtree(argv) continue; /* Pre-order: give user chance to skip. */ case FTS_D: - if (iflag && !check(p->fts_path, p->fts_accpath, + if (!fflag && !check(p->fts_path, p->fts_accpath, p->fts_statp)) { (void)fts_set(fts, p, FTS_SKIP); p->fts_number = SKIPPED; @@ -164,11 +177,12 @@ rmtree(argv) if (p->fts_number == SKIPPED) continue; break; - } - if (!fflag && - !check(p->fts_path, p->fts_accpath, p->fts_statp)) - continue; + default: + if (!fflag && !check(p->fts_path, p->fts_accpath, + p->fts_statp)) + continue; + } /* * If we can't read or search the directory, may still be @@ -181,7 +195,7 @@ rmtree(argv) if (errno == ENOENT) { if (fflag) continue; - } else if (p->fts_info != FTS_DP) + } else if (p->fts_info != FTS_DP && !fflag) (void)fprintf(stderr, "rm: unable to read %s.\n", p->fts_path); } else if (!unlink(p->fts_accpath) || fflag && errno == ENOENT) @@ -190,38 +204,52 @@ rmtree(argv) } } +void rmfile(argv) char **argv; { - register int df; register char *f; struct stat sb; - df = dflag; /* * Remove a file. POSIX 1003.2 states that, by default, attempting * to remove a directory is an error, so must always stat the file. */ - while (f = *argv++) { - /* Assume if can't stat the file, can't unlink it. */ + while ((f = *argv++) != NULL) { + /* If the file does not exist: + * If the -f option was not specified, write a diagnostic + * to the standard error... + */ if (lstat(f, &sb)) { - if (!fflag || errno != ENOENT) + if (!fflag || errno != ENOENT) { error(f, errno); + } continue; } - if (S_ISDIR(sb.st_mode) && !df) { - (void)fprintf(stderr, "rm: %s: is a directory\n", f); - retval = 1; + + /* If the file is of type directory and neither the -r or -R + * (or -d) options are specified, write a diagnostic to the + * standard error... + */ + if (S_ISDIR(sb.st_mode) && !dflag) { + error (f, EISDIR); continue; } - if (!fflag && !check(f, f, &sb)) + + if (!fflag && !check(f, f, &sb)) { continue; - if ((S_ISDIR(sb.st_mode) ? rmdir(f) : unlink(f)) && - (!fflag || errno != ENOENT)) + } + + /* + * rmdir() directories, unlink() files... + */ + if ((S_ISDIR(sb.st_mode) ? rmdir(f) : unlink(f))) { error(f, errno); + } } } +int check(path, name, sp) char *path, *name; struct stat *sp; @@ -238,7 +266,7 @@ check(path, name, sp) * talking to a terminal, ask. Symbolic links are excluded * because their permissions are meaningless. */ - if (S_ISLNK(sp->st_mode) || !stdin_ok || !access(name, W_OK)) + if (!stdin_ok || S_ISLNK(sp->st_mode) || !access(name, W_OK)) return(1); strmode(sp->st_mode, modep); (void)fprintf(stderr, "override %s%s%s/%s for %s? ", @@ -251,10 +279,11 @@ check(path, name, sp) first = ch = getchar(); while (ch != '\n' && ch != EOF) ch = getchar(); - return(first == 'y'); + return(first == 'y' || first == 'Y'); } #define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || (a)[1] == '.' && !(a)[2])) +void checkdot(argv) char **argv; { @@ -263,7 +292,7 @@ checkdot(argv) complained = 0; for (t = argv; *t;) { - if (p = rindex(*t, '/')) + if ((p = rindex(*t, '/')) != NULL) ++p; else p = *t; @@ -279,14 +308,17 @@ checkdot(argv) } } +void error(name, val) char *name; int val; { - (void)fprintf(stderr, "rm: %s: %s.\n", name, strerror(val)); + if (!fflag) + (void)fprintf(stderr, "rm: %s: %s.\n", name, strerror(val)); retval = 1; } +void usage() { (void)fprintf(stderr, "usage: rm [-dfiRr] file ...\n"); diff --git a/bin/rmdir/rmdir.1 b/bin/rmdir/rmdir.1 index b0207e59388a..73f5862e6691 100644 --- a/bin/rmdir/rmdir.1 +++ b/bin/rmdir/rmdir.1 @@ -32,7 +32,8 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" @(#)rmdir.1 6.5 (Berkeley) 6/27/91 +.\" from: @(#)rmdir.1 6.5 (Berkeley) 6/27/91 +.\" $Id: rmdir.1,v 1.4 1993/11/23 00:13:54 jtc Exp $ .\" .Dd June 27, 1991 .Dt RMDIR 1 @@ -87,6 +88,5 @@ An error occurred. .Sh STANDARDS The .Nm rmdir -utility is expected to be -.St -p1003.2 -compatible. +utility conforms to +.St -p1003.2-92 . diff --git a/bin/rmdir/rmdir.c b/bin/rmdir/rmdir.c index 5ed79190019c..b67393827094 100644 --- a/bin/rmdir/rmdir.c +++ b/bin/rmdir/rmdir.c @@ -38,7 +38,8 @@ char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)rmdir.c 5.3 (Berkeley) 5/31/90"; +/*static char sccsid[] = "from: @(#)rmdir.c 5.3 (Berkeley) 5/31/90";*/ +static char rcsid[] = "$Id: rmdir.c,v 1.3 1993/11/23 00:13:55 jtc Exp $"; #endif /* not lint */ /* @@ -47,8 +48,14 @@ static char sccsid[] = "@(#)rmdir.c 5.3 (Berkeley) 5/31/90"; #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> #include <errno.h> +#include <err.h> +static int rmdirp __P((char *)); +static void usage __P((void)); + +int main(argc, argv) int argc; char **argv; @@ -57,7 +64,7 @@ main(argc, argv) int ch; int delete_parent_directories = 0; - while ((ch = getopt (argc, argv, "p")) != EOF) { + while ((ch = getopt (argc, argv, "p")) != -1) { switch (ch) { case 'p': delete_parent_directories = 1; @@ -76,13 +83,12 @@ main(argc, argv) for (errors = 0; *argv; argv++) { if (!delete_parent_directories) { - if (rmdir(*argv) < 0) { - fprintf(stderr, "rmdir: %s: %s\n", - *argv, strerror(errno)); + if (rmdir(*argv)) { + warn ("%s", *argv); errors = 1; - } + } } else { - if (rmdirp(*argv) < 0) { + if (rmdirp(*argv)) { errors = 1; } } @@ -91,37 +97,38 @@ main(argc, argv) exit(errors); } -int -rmdirp (char *path) +static int +rmdirp (path) + char *path; { char *slash; - /* point slash at last slash */ - slash = strrchr (path, '/'); + if (rmdir (path)) { + warn ("%s", path); + return -1; + } - while (slash != NULL) { - if (rmdir (path) < 0) { - fprintf(stderr, "rmdir: %s: %s\n", - path, strerror(errno)); - return -1; + for (;;) { + slash = strrchr (path, '/'); + if (slash == NULL) { + return 0; } /* skip trailing slash characters */ while (slash > path && *slash == '/') slash--; - *++slash = '\0'; - slash = strrchr (path, '/'); - } - if (rmdir (path) < 0) { - fprintf(stderr, "rmdir: %s: %s\n", path, strerror(errno)); - return -1; + if (rmdir (path)) { + warn ("%s", path); + return -1; + } } - return 0; + /* NOTREACHED */ } +static void usage() { fprintf(stderr, "usage: rmdir [-p] directory ...\n"); diff --git a/bin/sh/TOUR b/bin/sh/TOUR index 7cc0f226a379..aa593346f337 100644 --- a/bin/sh/TOUR +++ b/bin/sh/TOUR @@ -325,7 +325,7 @@ put structures allocated. "Output" represents the standard out- put, "errout" the standard error, and "memout" contains output which is to be stored in memory. This last is used when a buil- tin command appears in backquotes, to allow its output to be col- -lected without doing any I/O through the UNIX operating system. +lected without doing any I/O through the operating system. The variables out1 and out2 normally point to output and errout, respectively, but they are set to point to memout when appropri- ate inside backquotes. diff --git a/bin/sh/b.c b/bin/sh/b.c deleted file mode 100644 index 9b7f568ecdff..000000000000 --- a/bin/sh/b.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * This file was generated by the mkbuiltins program. - */ - -#ifndef lint -static char rcsid[] = "b.c,v 1.2 1993/08/02 17:15:45 mycroft Exp"; -#endif /* not lint */ - -#include "shell.h" -#include "builtins.h" - -int bltincmd(); -int bgcmd(); -int breakcmd(); -int cdcmd(); -int dotcmd(); -int echocmd(); -int evalcmd(); -int execcmd(); -int exitcmd(); -int exportcmd(); -int fgcmd(); -int getoptscmd(); -int hashcmd(); -int jobidcmd(); -int jobscmd(); -int lccmd(); -int localcmd(); -int pwdcmd(); -int readcmd(); -int returncmd(); -int setcmd(); -int setvarcmd(); -int shiftcmd(); -int trapcmd(); -int truecmd(); -int umaskcmd(); -int unsetcmd(); -int waitcmd(); - -int (*const builtinfunc[])() = { - bltincmd, - bgcmd, - breakcmd, - cdcmd, - dotcmd, - echocmd, - evalcmd, - execcmd, - exitcmd, - exportcmd, - fgcmd, - getoptscmd, - hashcmd, - jobidcmd, - jobscmd, - lccmd, - localcmd, - pwdcmd, - readcmd, - returncmd, - setcmd, - setvarcmd, - shiftcmd, - trapcmd, - truecmd, - umaskcmd, - unsetcmd, - waitcmd, -}; - -const struct builtincmd builtincmd[] = { - "command", 0, - "bg", 1, - "break", 2, - "continue", 2, - "cd", 3, - "chdir", 3, - ".", 4, - "echo", 5, - "eval", 6, - "exec", 7, - "exit", 8, - "export", 9, - "readonly", 9, - "fg", 10, - "getopts", 11, - "hash", 12, - "jobid", 13, - "jobs", 14, - "lc", 15, - "local", 16, - "pwd", 17, - "read", 18, - "return", 19, - "set", 20, - "setvar", 21, - "shift", 22, - "trap", 23, - ":", 24, - "true", 24, - "umask", 25, - "unset", 26, - "wait", 27, - NULL, 0 -}; diff --git a/bin/sh/error.c b/bin/sh/error.c index 430de28465a8..6b1c010db085 100644 --- a/bin/sh/error.c +++ b/bin/sh/error.c @@ -178,55 +178,55 @@ struct errname { #define ALL (E_OPEN|E_CREAT|E_EXEC) STATIC const struct errname errormsg[] = { - EINTR, ALL, "interrupted", - EACCES, ALL, "permission denied", + EINTR, ALL, "interrupted", + EACCES, ALL, "permission denied", EIO, ALL, "I/O error", - ENOENT, E_OPEN, "no such file", + ENOENT, E_OPEN, "no such file", ENOENT, E_CREAT, "directory nonexistent", - ENOENT, E_EXEC, "not found", + ENOENT, E_EXEC, "not found", ENOTDIR, E_OPEN, "no such file", ENOTDIR, E_CREAT, "directory nonexistent", ENOTDIR, E_EXEC, "not found", - EISDIR, ALL, "is a directory", -/* EMFILE, ALL, "too many open files", */ - ENFILE, ALL, "file table overflow", - ENOSPC, ALL, "file system full", + EISDIR, ALL, "is a directory", +/* EMFILE, ALL, "too many open files", */ + ENFILE, ALL, "file table overflow", + ENOSPC, ALL, "file system full", #ifdef EDQUOT - EDQUOT, ALL, "disk quota exceeded", + EDQUOT, ALL, "disk quota exceeded", #endif #ifdef ENOSR - ENOSR, ALL, "no streams resources", + ENOSR, ALL, "no streams resources", #endif - ENXIO, ALL, "no such device or address", - EROFS, ALL, "read-only file system", - ETXTBSY, ALL, "text busy", + ENXIO, ALL, "no such device or address", + EROFS, ALL, "read-only file system", + ETXTBSY, ALL, "text busy", #ifdef SYSV - EAGAIN, E_EXEC, "not enough memory", + EAGAIN, E_EXEC, "not enough memory", #endif - ENOMEM, ALL, "not enough memory", + ENOMEM, ALL, "not enough memory", #ifdef ENOLINK - ENOLINK, ALL, "remote access failed", + ENOLINK, ALL, "remote access failed", #endif #ifdef EMULTIHOP - EMULTIHOP, ALL, "remote access failed", + EMULTIHOP, ALL, "remote access failed", #endif #ifdef ECOMM - ECOMM, ALL, "remote access failed", + ECOMM, ALL, "remote access failed", #endif #ifdef ESTALE - ESTALE, ALL, "remote access failed", + ESTALE, ALL, "remote access failed", #endif #ifdef ETIMEDOUT - ETIMEDOUT, ALL, "remote access failed", + ETIMEDOUT, ALL, "remote access failed", #endif #ifdef ELOOP - ELOOP, ALL, "symbolic link loop", + ELOOP, ALL, "symbolic link loop", #endif - E2BIG, E_EXEC, "argument list too long", + E2BIG, E_EXEC, "argument list too long", #ifdef ELIBACC ELIBACC, E_EXEC, "shared library missing", #endif - 0, 0, NULL + 0, 0, NULL }; diff --git a/bin/sh/eval.c b/bin/sh/eval.c index 718876e95b50..d6bd1296291d 100644 --- a/bin/sh/eval.c +++ b/bin/sh/eval.c @@ -521,7 +521,10 @@ evalbackcmd(n, result) result->buf = NULL; result->nleft = 0; result->jp = NULL; - if (n->type == NCMD) { + /* No command inside the backqotes, so do nothing. */ + if (n == NULL) + ; + else if (n->type == NCMD) { evalcommand(n, EV_BACKCMD, result); } else { if (pipe(pip) < 0) diff --git a/bin/sh/expand.c b/bin/sh/expand.c index 1d5864d233bf..95d2e504cd70 100644 --- a/bin/sh/expand.c +++ b/bin/sh/expand.c @@ -664,8 +664,10 @@ expandmeta(str) savelastp = exparg.lastp; INTOFF; if (expdir == NULL) - expdir = ckmalloc(1024); /* I hope this is big enough */ + expdir = ckmalloc(8192); /* I hope this is big enough */ expmeta(expdir, str->text); + if(strlen(expdir) >= 8192) + error("malloc overflow in sh:expand.c in ckmalloc(8192)\n"); ckfree(expdir); expdir = NULL; INTON; diff --git a/bin/sh/mknodes.c b/bin/sh/mknodes.c index 53c8508ee1ec..083138b0147c 100644 --- a/bin/sh/mknodes.c +++ b/bin/sh/mknodes.c @@ -99,13 +99,16 @@ char *savestr(); #define equal(s1, s2) (strcmp(s1, s2) == 0) -main(argc, argv) - char **argv; - { - if (argc != 3) +main(int argc, char **argv) +{ + if (argc != 3) { error("usage: mknodes file\n"); - if ((infp = fopen(argv[1], "r")) == NULL) + return(1); + } + if ((infp = fopen(argv[1], "r")) == NULL) { error("Can't open %s", argv[1]); + return(1); + } while (readline()) { if (line[0] == ' ' || line[0] == '\t') parsefield(); @@ -113,7 +116,7 @@ main(argc, argv) parsenode(); } output(argv[2]); - return 0; + return(0); } diff --git a/bin/sh/mt b/bin/sh/mt deleted file mode 100644 index f07a32e28d7c..000000000000 --- a/bin/sh/mt +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/sh - -# -# Copyright (c) 1991 The Regents of the University of California. -# All rights reserved. -# -# This code is derived from software contributed to Berkeley by -# Kenneth Almquist. -# -# 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. -# -# @(#)mktokens 5.1 (Berkeley) 3/7/91 -# -# /b/source/CVS/src/bin/sh/mt,v 1.3 1993/03/23 00:28:48 cgd Exp - -# The following is a list of tokens. The second column is nonzero if the -# token marks the end of a list. The third column is the name to print in -# error messages. - -cat > /tmp/ka$$ <<\! -TEOF 1 end of file -TNL 0 newline -TSEMI 0 ";" -TBACKGND 0 "&" -TAND 0 "&&" -TOR 0 "||" -TPIPE 0 "|" -TLP 0 "(" -TRP 1 ")" -TENDCASE 1 ";;" -TENDBQUOTE 1 "`" -TREDIR 0 redirection -TWORD 0 word -TIF 0 "if" -TTHEN 1 "then" -TELSE 1 "else" -TELIF 1 "elif" -TFI 1 "fi" -TWHILE 0 "while" -TUNTIL 0 "until" -TFOR 0 "for" -TDO 1 "do" -TDONE 1 "done" -TBEGIN 0 "{" -TEND 1 "}" -TCASE 0 "case" -TESAC 1 "esac" -! -nl=`wc -l /tmp/ka$$` -exec -awk "-F " '{print $1 "#define " NR-1}' /tmp/ka$$ - -rm /tmp/ka$$ diff --git a/bin/sh/parser.c b/bin/sh/parser.c index dc0e046ea171..1ab8751d0c7e 100644 --- a/bin/sh/parser.c +++ b/bin/sh/parser.c @@ -352,10 +352,11 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); n2->narg.backquote = NULL; n2->narg.next = NULL; n1->nfor.args = n2; - /* A newline or semicolon is optional here. Anything - else gets pushed back so we can read it again. */ - if (lasttoken != TNL && lasttoken != TSEMI) - tokpushback++; + /* Many shells accept an optional semicolon here, but + POSIX says we should not, so we don't. An optional + newline is OK here, but that is handled by the + checkkwd = 2 assignment below. */ + tokpushback++; } checkkwd = 2; if ((t = readtoken()) == TDO) @@ -429,7 +430,10 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); checkkwd = 1; break; /* Handle an empty command like other simple commands. */ + case TSEMI: case TNL: + /* Handle EOF like other simple commands, too. */ + case TEOF: case TWORD: tokpushback++; return simplecmd(rpp, redir); diff --git a/bin/sh/sh.1 b/bin/sh/sh.1 index 415aa0e42fc3..e5498959ecc9 100644 --- a/bin/sh/sh.1 +++ b/bin/sh/sh.1 @@ -372,7 +372,7 @@ will be as if a new shell had been invoked to handle the shell procedure, except that the location of commands located in the parent shell will be remembered by the child. If the program is a file beginning with ``#!'', the remainder of the first line specifies an interpreter for -the program. The shell (or the operating system, under Berkeley UNIX) +the program. The operating system will run the interpreter in this case. The arguments to the interpreter will consist of any arguments given on the first line of the program, followed by the name of the program, followed by the arguments passed @@ -486,7 +486,7 @@ fields separated by a separator character, is used. When performing splitting, the shell scans the replacement text looking for a character (when IFS does not begin with a space) or a sequence of characters (when IFS does begin with a space), deletes the character or -sequence of characters, and spits the word into two strings at that +sequence of characters, and splits the word into two strings at that point. When IFS begins with a space, the shell deletes either of the strings if they are null. As a special case, if the word containing the replacement text is the null string, the word is deleted. diff --git a/bin/stty/cchar.c b/bin/stty/cchar.c index 458867c7ffc4..b8e6206cfa59 100644 --- a/bin/stty/cchar.c +++ b/bin/stty/cchar.c @@ -36,6 +36,7 @@ static char sccsid[] = "@(#)cchar.c 5.4 (Berkeley) 6/10/91"; #endif /* not lint */ #include <sys/types.h> +#include <machine/limits.h> #include <stddef.h> #include <stdlib.h> #include <string.h> @@ -85,7 +86,8 @@ csearch(argvp, ip) extern char *usage; register struct cchar *cp; struct cchar tmp; - char *arg, *name; + long val; + char *arg, *ep, *name; static int c_cchar __P((const void *, const void *)); name = **argvp; @@ -102,10 +104,24 @@ csearch(argvp, ip) if (!arg) err("option requires an argument -- %s\n%s", name, usage); -#define CHK(s) (*name == s[0] && !strcmp(name, s)) +#define CHK(s) (*arg == s[0] && !strcmp(arg, s)) if (CHK("undef") || CHK("<undef>")) ip->t.c_cc[cp->sub] = _POSIX_VDISABLE; - else if (arg[0] == '^') + else if (cp->sub == VMIN || cp->sub == VTIME) { + val = strtol(arg, &ep, 10); + if (val == _POSIX_VDISABLE) { + warnx("value of %ld would disable the option -- %s", + val, name); + } + if (val > UCHAR_MAX) { + warnx("maximum option value is %d -- %s", + UCHAR_MAX, name); + } + if (*ep != '\0') { + warnx("option requires a numeric argument -- %s", name); + } + ip->t.c_cc[cp->sub] = val; + } else if (arg[0] == '^') ip->t.c_cc[cp->sub] = (arg[1] == '?') ? 0177 : (arg[1] == '-') ? _POSIX_VDISABLE : arg[1] & 037; else diff --git a/bin/stty/gfmt.c b/bin/stty/gfmt.c index 3953e647ca91..d909131ee32c 100644 --- a/bin/stty/gfmt.c +++ b/bin/stty/gfmt.c @@ -163,6 +163,16 @@ gread(tp, s) tp->c_cc[VSUSP] = tmp; continue; } + if (CHK("vmin")) { + (void)sscanf(ep, "%ld", &tmp); + tp->c_cc[VMIN] = tmp; + continue; + } + if (CHK("vtime")) { + (void)sscanf(ep, "%ld", &tmp); + tp->c_cc[VTIME] = tmp; + continue; + } if (CHK("werase")) { tp->c_cc[VWERASE] = tmp; continue; diff --git a/bin/stty/modes.c b/bin/stty/modes.c index 4b5f854103b2..2ab4a26f082b 100644 --- a/bin/stty/modes.c +++ b/bin/stty/modes.c @@ -78,6 +78,14 @@ struct modes cmodes[] = { "-clocal", 0, CLOCAL, "crtscts", CRTSCTS, 0, "-crtscts", 0, CRTSCTS, + "ctsflow", CCTS_OFLOW, 0, + "-ctsflow", 0, CCTS_OFLOW, + "dsrflow", CDSR_OFLOW, 0, + "-dsrflow", 0, CDSR_OFLOW, + "dtrflow", CDTR_IFLOW, 0, + "-dtrflow", 0, CDTR_IFLOW, + "rtsflow", CRTS_IFLOW, 0, + "-rtsflow", 0, CRTS_IFLOW, NULL }; diff --git a/bin/stty/print.c b/bin/stty/print.c index c2f7a8e51864..a3ef040efbec 100644 --- a/bin/stty/print.c +++ b/bin/stty/print.c @@ -44,7 +44,7 @@ static char sccsid[] = "@(#)print.c 5.4 (Berkeley) 6/10/91"; static void binit __P((char *)); static void bput __P((char *)); -static char *ccval __P((int)); +static char *ccval __P((struct cchar *, int)); void print(tp, wp, ldisc, fmt) @@ -71,6 +71,9 @@ print(tp, wp, ldisc, fmt) case SLIPDISC: cnt += printf("slip disc; "); break; + case NTTYDISC: + cnt += printf("new tty disc; "); + break; default: cnt += printf("#%d disc; ", ldisc); break; @@ -90,10 +93,10 @@ print(tp, wp, ldisc, fmt) if (cnt) (void)printf("\n"); -#define on(f) ((tmp&f) != 0) +#define on(f) ((tmp & (f)) != 0) #define put(n, f, d) \ - if (fmt >= BSD || on(f) != d) \ - bput(n + on(f)); + if (fmt >= BSD || on(f) != (d)) \ + bput((n) + on(f)); /* "local" flags */ tmp = tp->c_lflag; @@ -164,7 +167,19 @@ print(tp, wp, ldisc, fmt) put("-hupcl", HUPCL, 1); put("-clocal", CLOCAL, 0); put("-cstopb", CSTOPB, 0); - put("-crtscts", CRTSCTS, 0); + switch(tmp & (CCTS_OFLOW | CRTS_IFLOW)) { + case CCTS_OFLOW: + bput("ctsflow"); + break; + case CRTS_IFLOW: + bput("rtsflow"); + break; + default: + put("-crtscts", CCTS_OFLOW | CRTS_IFLOW, 0); + break; + } + put("-dsrflow", CDSR_OFLOW, 0); + put("-dtrflow", CDTR_IFLOW, 0); /* special control characters */ cc = tp->c_cc; @@ -172,7 +187,7 @@ print(tp, wp, ldisc, fmt) binit("cchars"); for (p = cchars1; p->name; ++p) { (void)snprintf(buf1, sizeof(buf1), "%s = %s;", - p->name, ccval(cc[p->sub])); + p->name, ccval(p, cc[p->sub])); bput(buf1); } binit(NULL); @@ -183,7 +198,7 @@ print(tp, wp, ldisc, fmt) continue; #define WD "%-8s" (void)sprintf(buf1 + cnt * 8, WD, p->name); - (void)sprintf(buf2 + cnt * 8, WD, ccval(cc[p->sub])); + (void)sprintf(buf2 + cnt * 8, WD, ccval(p, cc[p->sub])); if (++cnt == LINELENGTH / 8) { cnt = 0; (void)printf("%s\n", buf1); @@ -228,7 +243,8 @@ bput(s) } static char * -ccval(c) +ccval(p, c) + struct cchar *p; int c; { static char buf[5]; @@ -237,6 +253,10 @@ ccval(c) if (c == _POSIX_VDISABLE) return("<undef>"); + if (p->sub == VMIN || p->sub == VTIME) { + (void)snprintf(buf, sizeof(buf), "%d", c); + return (buf); + } bp = buf; if (c & 0200) { *bp++ = 'M'; diff --git a/bin/stty/stty.c b/bin/stty/stty.c index 99765e386f61..4b19b64d7f4a 100644 --- a/bin/stty/stty.c +++ b/bin/stty/stty.c @@ -66,7 +66,8 @@ main(argc, argv) i.fd = STDIN_FILENO; opterr = 0; - while (strspn(argv[optind], "-aefg") == strlen(argv[optind]) && + while (argv[optind] && + strspn(argv[optind], "-aefg") == strlen(argv[optind]) && (ch = getopt(argc, argv, "aef:g")) != EOF) switch(ch) { case 'a': /* undocumented: POSIX compatibility */ diff --git a/bin/stty/util.c b/bin/stty/util.c index 459181c71536..e1e20b0491fa 100644 --- a/bin/stty/util.c +++ b/bin/stty/util.c @@ -59,53 +59,3 @@ checkredirect() (sb1.st_rdev != sb2.st_rdev)) warn("stdout appears redirected, but stdin is the control descriptor"); } - -#if __STDC__ -#include <stdarg.h> -#else -#include <varargs.h> -#endif - -void -#if __STDC__ -err(const char *fmt, ...) -#else -err(fmt, va_alist) - char *fmt; - va_dcl -#endif -{ - va_list ap; -#if __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - (void)fprintf(stderr, "stty: "); - (void)vfprintf(stderr, fmt, ap); - va_end(ap); - (void)fprintf(stderr, "\n"); - exit(1); - /* NOTREACHED */ -} - -void -#if __STDC__ -warn(const char *fmt, ...) -#else -warn(fmt, va_alist) - char *fmt; - va_dcl -#endif -{ - va_list ap; -#if __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - (void)fprintf(stderr, "stty: "); - (void)vfprintf(stderr, fmt, ap); - va_end(ap); - (void)fprintf(stderr, "\n"); -} |
