summaryrefslogtreecommitdiff
path: root/usr/src/cmd/ed
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/ed
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/ed')
-rw-r--r--usr/src/cmd/ed/Makefile115
-rw-r--r--usr/src/cmd/ed/ed.c3170
-rw-r--r--usr/src/cmd/ed/ed.xcl38
-rw-r--r--usr/src/cmd/ed/inc.flg32
4 files changed, 3355 insertions, 0 deletions
diff --git a/usr/src/cmd/ed/Makefile b/usr/src/cmd/ed/Makefile
new file mode 100644
index 0000000000..96b1018a31
--- /dev/null
+++ b/usr/src/cmd/ed/Makefile
@@ -0,0 +1,115 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+PROG= ed
+XPG4PROG= ed
+XPG6PROG= ed
+
+EDOBJ= ed.o compile.o
+XPG4EDOBJ= edobjs.xpg4/ed.o edobjs.xpg4/compile.o values-xpg4.o
+XPG6EDOBJ= edobjs.xpg6/ed.o edobjs.xpg6/compile.o values-xpg6.o
+OBJS= $(EDOBJ) $(XPG4EDOBJ) $(XPG6EDOBJ)
+SRCS= ./ed.c ../expr/compile.c
+
+POFILES= $(EDOBJ:%.o=%.po)
+
+include ../Makefile.cmd
+
+CFLAGS += $(CCVERBOSE)
+$(XPG4) := CFLAGS += -DXPG4
+$(XPG6) := CFLAGS += -DXPG6 -I$(SRC)/lib/libc/inc
+LAZYLIBS = $(ZLAZYLOAD) -lgen -lcrypt_i $(ZNOLAZYLOAD)
+lint := LAZYLIBS = -lgen -lcrypt
+LDLIBS += -lmapmalloc $(LAZYLIBS)
+XGETFLAGS += -a -x ed.xcl
+
+POFILE= ed_cmd.po
+
+%.po: ../expr/%.c
+ $(COMPILE.cpp) $< > $*.c.i
+ $(XGETTEXT) $(XGETFLAGS) $*.c.i
+ $(MV) messages.po $@
+
+.KEEP_STATE:
+
+all: $(PROG) $(XPG4) $(XPG6)
+
+$(PROG): $(EDOBJ)
+ $(LINK.c) $(EDOBJ) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+$(XPG4): edobjs.xpg4 $(XPG4EDOBJ)
+ $(LINK.c) $(XPG4EDOBJ) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+$(XPG6): edobjs.xpg6 $(XPG6EDOBJ)
+ $(LINK.c) $(XPG6EDOBJ) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+compile.o: ../expr/compile.c
+ $(COMPILE.c) -o $@ ../expr/compile.c
+
+edobjs.xpg4/%.o: %.c
+ $(COMPILE.c) -o $@ $<
+
+edobjs.xpg4/%.o: ../expr/compile.c
+ $(COMPILE.c) -o $@ $<
+
+edobjs.xpg6/%.o: %.c
+ $(COMPILE.c) -o $@ $<
+
+edobjs.xpg6/%.o: ../expr/compile.c
+ $(COMPILE.c) -o $@ $<
+
+edobjs.xpg4:
+ -@mkdir -p $@
+
+edobjs.xpg6:
+ -@mkdir -p $@
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ cat $(POFILES) > $@
+
+install: all $(ROOTPROG) $(ROOTXPG4PROG) $(ROOTXPG6PROG)
+ $(RM) $(ROOTBIN)/red
+ $(LN) $(ROOTBIN)/ed $(ROOTBIN)/red
+
+values-xpg4.o: ../../lib/common/common/values-xpg4.c
+ $(COMPILE.c) -o $@ ../../lib/common/common/values-xpg4.c
+
+values-xpg6.o: ../../lib/common/common/values-xpg6.c
+ $(COMPILE.c) -o $@ ../../lib/common/common/values-xpg6.c
+
+clean:
+ -@rm -rf $(OBJS) $(XPG4) $(XPG6) edobjs.xpg4 edobjs.xpg6 \
+ compile.c.i
+
+lint: lint_PROG
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/ed/ed.c b/usr/src/cmd/ed/ed.c
new file mode 100644
index 0000000000..48fe227631
--- /dev/null
+++ b/usr/src/cmd/ed/ed.c
@@ -0,0 +1,3170 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Editor
+ */
+
+#include <crypt.h>
+#include <libgen.h>
+#include <wait.h>
+#include <string.h>
+#include <sys/types.h>
+#include <locale.h>
+#include <regexpr.h>
+#include <regex.h>
+#include <errno.h>
+
+static const char *msgtab[] =
+{
+ "write or open on pipe failed", /* 0 */
+ "warning: expecting `w'", /* 1 */
+ "mark not lower case ascii", /* 2 */
+ "Cannot open input file", /* 3 */
+ "PWB spec problem", /* 4 */
+ "nothing to undo", /* 5 */
+ "restricted shell", /* 6 */
+ "cannot create output file", /* 7 */
+ "filesystem out of space!", /* 8 */
+ "cannot open file", /* 9 */
+ "cannot link", /* 10 */
+ "Range endpoint too large", /* 11 */
+ "unknown command", /* 12 */
+ "search string not found", /* 13 */
+ "-", /* 14 */
+ "line out of range", /* 15 */
+ "bad number", /* 16 */
+ "bad range", /* 17 */
+ "Illegal address count", /* 18 */
+ "incomplete global expression", /* 19 */
+ "illegal suffix", /* 20 */
+ "illegal or missing filename", /* 21 */
+ "no space after command", /* 22 */
+ "fork failed - try again", /* 23 */
+ "maximum of 64 characters in file names", /* 24 */
+ "`\\digit' out of range", /* 25 */
+ "interrupt", /* 26 */
+ "line too long", /* 27 */
+ "illegal character in input file", /* 28 */
+ "write error", /* 29 */
+ "out of memory for append", /* 30 */
+ "temp file too big", /* 31 */
+ "I/O error on temp file", /* 32 */
+ "multiple globals not allowed", /* 33 */
+ "global too long", /* 34 */
+ "no match", /* 35 */
+ "illegal or missing delimiter", /* 36 */
+ "-", /* 37 */
+ "replacement string too long", /* 38 */
+ "illegal move destination", /* 39 */
+ "-", /* 40 */
+ "no remembered search string", /* 41 */
+ "'\\( \\)' imbalance", /* 42 */
+ "Too many `\\(' s", /* 43 */
+ "more than 2 numbers given", /* 44 */
+ "'\\}' expected", /* 45 */
+ "first number exceeds second", /* 46 */
+ "incomplete substitute", /* 47 */
+ "newline unexpected", /* 48 */
+ "'[ ]' imbalance", /* 49 */
+ "regular expression overflow", /* 50 */
+ "regular expression error", /* 51 */
+ "command expected", /* 52 */
+ "a, i, or c not allowed in G", /* 53 */
+ "end of line expected", /* 54 */
+ "no remembered replacement string", /* 55 */
+ "no remembered command", /* 56 */
+ "illegal redirection", /* 57 */
+ "possible concurrent update", /* 58 */
+ "-", /* 59 */
+ "the x command has become X (upper case)", /* 60 */
+ "Warning: 'w' may destroy input file "
+ "(due to `illegal char' read earlier)",
+ /* 61 */
+ "Caution: 'q' may lose data in buffer;"
+ " 'w' may destroy input file",
+ /* 62 */
+ "Encryption of string failed", /* 63 */
+ "Encryption facility not available", /* 64 */
+ "Cannot encrypt temporary file", /* 65 */
+ "Enter key:", /* 66 */
+ "Illegal byte sequence", /* 67 */
+ "File does not exist", /* 68 */
+ "tempnam failed", /* 69 */
+ "Cannot open temporary file", /* 70 */
+ 0
+};
+
+#include <stdlib.h>
+#include <limits.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <unistd.h>
+#include <termio.h>
+#include <ctype.h>
+#include <setjmp.h>
+#include <fcntl.h>
+#include <wchar.h> /* I18N */
+#include <wctype.h> /* I18N */
+#include <widec.h> /* I18N */
+
+#define FTYPE(A) (A.st_mode)
+#define FMODE(A) (A.st_mode)
+#define IDENTICAL(A, B) (A.st_dev == B.st_dev && A.st_ino == B.st_ino)
+#define ISBLK(A) ((A.st_mode & S_IFMT) == S_IFBLK)
+#define ISCHR(A) ((A.st_mode & S_IFMT) == S_IFCHR)
+#define ISDIR(A) ((A.st_mode & S_IFMT) == S_IFDIR)
+#define ISFIFO(A) ((A.st_mode & S_IFMT) == S_IFIFO)
+#define ISREG(A) ((A.st_mode & S_IFMT) == S_IFREG)
+
+#define PUTM() if (xcode >= 0) puts(gettext(msgtab[xcode]))
+#define UNGETC(c) (peekc = c)
+#define FNSIZE PATH_MAX
+#define LBSIZE LINE_MAX
+
+/* size of substitution replacement pattern buffer */
+#define RHSIZE (LINE_MAX*2)
+
+#define KSIZE 8
+
+#define READ 0
+#define WRITE 1
+
+extern char *optarg; /* Value of argument */
+extern int optind; /* Indicator of argument */
+extern int __xpg4; /* defined in xpg4.c; 0 if not xpg4-compiled program */
+
+struct Fspec {
+ char Ftabs[22];
+ char Fdel;
+ unsigned char Flim;
+ char Fmov;
+ char Ffill;
+};
+static struct Fspec fss;
+
+static char *fsp;
+static int fsprtn;
+static char line[70];
+static char *linp = line;
+static int sig;
+static int Xqt = 0;
+static int lastc;
+static char savedfile[FNSIZE];
+static char file[FNSIZE];
+static char funny[FNSIZE];
+static int funlink = 0;
+static char linebuf[LBSIZE];
+static char *tstring = linebuf;
+
+static char *expbuf;
+
+static char rhsbuf[RHSIZE];
+struct lin {
+ long cur;
+ long sav;
+};
+typedef struct lin *LINE;
+static LINE zero;
+static LINE dot;
+static LINE dol;
+static LINE endcore;
+static LINE fendcore;
+static LINE addr1;
+static LINE addr2;
+static LINE savdol, savdot;
+static int globflg;
+static int initflg;
+static char genbuf[LBSIZE];
+static long count;
+static int numpass; /* Number of passes thru dosub(). */
+static int gsubf; /* Occurrence value. LBSIZE-1=all. */
+static int ocerr1; /* Allows lines NOT changed by dosub() to NOT be put */
+ /* out. Retains last line changed as current line. */
+static int ocerr2; /* Flags if ANY line changed by substitute(). 0=nc. */
+static char *nextip;
+static char *linebp;
+static int ninbuf;
+static int peekc;
+static int io;
+static void (*oldhup)(), (*oldintr)();
+static void (*oldquit)(), (*oldpipe)();
+static void quit(int);
+static int vflag = 1;
+static int xflag;
+static int xtflag;
+static int kflag;
+static int crflag;
+ /* Flag for determining if file being read is encrypted */
+static int hflag;
+static int xcode = -1;
+static char crbuf[LBSIZE];
+static int perm[2];
+static int tperm[2];
+static int permflag;
+static int tpermflag;
+static int col;
+static char *globp;
+static int tfile = -1;
+static int tline;
+static char *tfname;
+extern char *locs;
+static char ibuff[LBSIZE];
+static int iblock = -1;
+static char obuff[LBSIZE];
+static int oblock = -1;
+static int ichanged;
+static int nleft;
+static long savnames[26], names[26];
+static int anymarks;
+static long subnewa;
+static int fchange;
+static int nline;
+static int fflg, shflg;
+static char prompt[16] = "*";
+static int rflg;
+static int readflg;
+static int eflg;
+static int qflg = 0;
+static int ncflg;
+static int listn;
+static int listf;
+static int pflag;
+static int flag28 = 0; /* Prevents write after a partial read */
+static int save28 = 0; /* Flag whether buffer empty at start of read */
+static long savtime;
+static char *name = "SHELL";
+static char *rshell = "/usr/lib/rsh";
+static char *shpath; /* pointer to correct shell for execution */
+ /* of execlp() */
+static char *val;
+static char *home;
+static int nodelim;
+
+int makekey(int *);
+int _mbftowc(char *, wchar_t *, int (*)(), int *);
+static int error(int code);
+static void tlist(struct Fspec *);
+static void tstd(struct Fspec *);
+static void gdelete(void);
+static void delete(void);
+static void exfile(void);
+static void filename(int comm);
+static void newline(void);
+static int gettty(void);
+static void commands(void);
+static void undo(void);
+static void save(void);
+static void strcopy(char *source, char *dest);
+static int strequal(char **scan1, char *str);
+static int stdtab(char *, char *);
+static int lenchk(char *, struct Fspec *);
+static void clear(struct Fspec *);
+static int expnd(char *, char *, int *, struct Fspec *);
+static void tincr(int, struct Fspec *);
+static void targ(struct Fspec *);
+static int numb(void);
+static int fspec(char *, struct Fspec *, int);
+static void red(char *);
+static void newtime(void);
+static void chktime(void);
+static void getime(void);
+static void mkfunny(void);
+static int eopen(char *, int);
+static void eclose(int f);
+static void globaln(int);
+static char *getkey(const char *);
+static int execute(int, LINE);
+static void error1(int);
+static int getcopy(void);
+static void move(int);
+static void dosub(void);
+static int getsub(void);
+static int compsub(void);
+static void substitute(int);
+static void join(void);
+static void global(int);
+static void init(void);
+static void rdelete(LINE, LINE);
+static void append(int (*)(void), LINE);
+static int getfile(void);
+static void putfile(void);
+static void onpipe(int);
+static void onhup(int);
+static void onintr(int);
+static void setdot(void);
+static void setall(void);
+static void setnoaddr(void);
+static void nonzero(void);
+static void setzeroasone(void);
+static long putline(void);
+static LINE address(void);
+static char *getline(long);
+static char *getblock(long, long);
+static char *place(char *, char *, char *);
+static void comple(wchar_t);
+static void putchr(unsigned char);
+static void putwchr(wchar_t);
+static int getchr(void);
+static void unixcom(void);
+static void blkio(int, char *, ssize_t (*)());
+static void reverse(LINE, LINE);
+static void putd();
+static wchar_t get_wchr(void);
+
+static struct stat Fl, Tf;
+#ifndef RESEARCH
+static struct statvfs U;
+static int Short = 0;
+static mode_t oldmask; /* No umask while writing */
+#endif
+static jmp_buf savej;
+
+#ifdef NULLS
+int nulls; /* Null count */
+#endif
+static long ccount;
+
+static int errcnt = 0;
+
+
+static void
+onpipe(int sig)
+{
+ (int)error(0);
+}
+
+int
+main(int argc, char **argv)
+{
+ char *p1, *p2;
+ int c;
+
+ (void) setlocale(LC_ALL, "");
+#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
+#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ oldquit = signal(SIGQUIT, SIG_IGN);
+ oldhup = signal(SIGHUP, SIG_IGN);
+ oldintr = signal(SIGINT, SIG_IGN);
+ oldpipe = signal(SIGPIPE, onpipe);
+ if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
+ signal(SIGTERM, quit);
+ p1 = *argv;
+ while (*p1++);
+ while (--p1 >= *argv)
+ if (*p1 == '/')
+ break;
+ *argv = p1 + 1;
+ /* if SHELL set in environment and is /usr/lib/rsh, set rflg */
+ if ((val = getenv(name)) != NULL)
+ if (strcmp(val, rshell) == 0)
+ rflg++;
+ if (**argv == 'r')
+ rflg++;
+ home = getenv("HOME");
+ while (1) {
+ while ((c = getopt(argc, argv, "sp:qxC")) != EOF) {
+ switch (c) {
+
+ case 's':
+ vflag = 0;
+ break;
+
+ case 'p':
+ strncpy(prompt, optarg, sizeof (prompt)-1);
+ shflg = 1;
+ break;
+
+ case 'q':
+ signal(SIGQUIT, SIG_DFL);
+ vflag = 1;
+ break;
+
+ case 'x':
+ crflag = -1;
+ xflag = 1;
+ break;
+
+ case 'C':
+ crflag = 1;
+ xflag = 1;
+ break;
+
+ case '?':
+ (void) fprintf(stderr, gettext(
+ "Usage: ed [- | -s] [-p string] [-x] [-C] [file]\n"
+ " red [- | -s] [-p string] [-x] [-C] [file]\n"));
+ exit(2);
+ }
+ }
+ if (argv[optind] && strcmp(argv[optind], "-") == 0 &&
+ strcmp(argv[optind-1], "--") != 0) {
+ vflag = 0;
+ optind++;
+ continue;
+ }
+ break;
+ }
+ argc = argc - optind;
+ argv = &argv[optind];
+
+ if (xflag) {
+ if (permflag)
+ crypt_close(perm);
+ permflag = 1;
+ if ((kflag = run_setkey(&perm[0], getkey(msgtab[66])))
+ == -1) {
+ puts(gettext(msgtab[64]));
+ xflag = 0;
+ kflag = 0;
+ }
+ if (kflag == 0)
+ crflag = 0;
+ }
+
+ if (argc > 0) {
+ p1 = *argv;
+ if (strlen(p1) >= (size_t)FNSIZE) {
+ puts(gettext("file name too long"));
+ if (kflag)
+ crypt_close(perm);
+ exit(2);
+ }
+ p2 = savedfile;
+ while (*p2++ = *p1++);
+ globp = "e";
+ fflg++;
+ } else /* editing with no file so set savtime to 0 */
+ savtime = 0;
+ eflg++;
+ if ((tfname = tempnam("", "ea")) == NULL) {
+ puts(gettext(msgtab[69]));
+ exit(2);
+ }
+
+ fendcore = (LINE)sbrk(0);
+ init();
+ if (oldintr != SIG_IGN)
+ signal(SIGINT, onintr);
+ if (oldhup != SIG_IGN)
+ signal(SIGHUP, onhup);
+ setjmp(savej);
+ commands();
+ quit(sig);
+ return (0);
+}
+
+static void
+commands(void)
+{
+ LINE a1;
+ int c;
+ char *p1, *p2;
+ int fsave, m, n;
+
+ for (;;) {
+ nodelim = 0;
+ if (pflag) {
+ pflag = 0;
+ addr1 = addr2 = dot;
+ goto print;
+ }
+ if (shflg && globp == 0)
+ write(1, gettext(prompt), strlen(gettext(prompt)));
+ addr1 = 0;
+ addr2 = 0;
+ if ((c = getchr()) == ',') {
+ addr1 = zero + 1;
+ addr2 = dol;
+#ifdef XPG6
+ /* XPG4 - it was an error if the second address was */
+ /* input and the first address was ommitted */
+ /* Parse second address */
+ if ((a1 = address()) != 0) {
+ addr2 = a1;
+ }
+#endif
+ c = getchr();
+ goto swch;
+ } else if (c == ';') {
+ addr1 = dot;
+ addr2 = dol;
+#ifdef XPG6
+ /* XPG4 - it was an error if the second address was */
+ /* input and the first address was ommitted */
+ /* Parse second address */
+ if ((a1 = address()) != 0) {
+ addr2 = a1;
+ }
+#endif
+ c = getchr();
+ goto swch;
+ } else
+ peekc = c;
+ do {
+ addr1 = addr2;
+ if ((a1 = address()) == 0) {
+ c = getchr();
+ break;
+ }
+ addr2 = a1;
+ if ((c = getchr()) == ';') {
+ c = ',';
+ dot = a1;
+ }
+ } while (c == ',');
+ if (addr1 == 0)
+ addr1 = addr2;
+swch:
+ switch (c) {
+
+ case 'a':
+ setdot();
+ newline();
+ if (!globflg) save();
+ append(gettty, addr2);
+ continue;
+
+ case 'c':
+#ifdef XPG6
+ setzeroasone();
+#endif
+ delete();
+ append(gettty, addr1-1);
+
+ /* XPG4 - If no new lines are inserted, then the current */
+ /* line becomes the line after the lines deleted. */
+
+ if (((linebuf[0] != '.') || (dot == (addr1-1))) &&
+ (addr2 <= dol))
+ dot = addr1;
+ continue;
+
+ case 'd':
+ delete();
+ continue;
+
+ case 'E':
+ fchange = 0;
+ c = 'e';
+ case 'e':
+ fflg++;
+ setnoaddr();
+ if (vflag && fchange) {
+ fchange = 0;
+ (void) error(1);
+ }
+ filename(c);
+ eflg++;
+ init();
+ addr2 = zero;
+ goto caseread;
+
+ case 'f':
+ setnoaddr();
+ filename(c);
+ if (!ncflg) /* there is a filename */
+ getime();
+ else
+ ncflg--;
+ puts(savedfile);
+ continue;
+
+ case 'g':
+ global(1);
+ continue;
+ case 'G':
+ globaln(1);
+ continue;
+
+ case 'h':
+ newline();
+ setnoaddr();
+ PUTM();
+ continue;
+
+ case 'H':
+ newline();
+ setnoaddr();
+ if (!hflag) {
+ hflag = 1;
+ PUTM();
+ }
+ else
+ hflag = 0;
+ continue;
+
+ case 'i':
+#ifdef XPG6
+ setzeroasone();
+#endif
+ setdot();
+ nonzero();
+ newline();
+ if (!globflg) save();
+ append(gettty, addr2-1);
+ if (dot == addr2-1)
+ dot += 1;
+ continue;
+
+ case 'j':
+ if (addr2 == 0) {
+ addr1 = dot;
+ addr2 = dot+1;
+ }
+ setdot();
+ newline();
+ nonzero();
+ if (!globflg) save();
+ join();
+ continue;
+
+ case 'k':
+ if ((c = getchr()) < 'a' || c > 'z')
+ (void) error(2);
+ newline();
+ setdot();
+ nonzero();
+ names[c-'a'] = addr2->cur & ~01;
+ anymarks |= 01;
+ continue;
+
+ case 'm':
+ move(0);
+ continue;
+
+ case '\n':
+ if (addr2 == 0)
+ addr2 = dot+1;
+ addr1 = addr2;
+ goto print;
+
+ case 'n':
+ listn++;
+ newline();
+ goto print;
+
+ case 'l':
+ listf++;
+ case 'p':
+ newline();
+ print:
+ setdot();
+ nonzero();
+ a1 = addr1;
+ do {
+ if (listn) {
+ count = a1 - zero;
+ putd();
+ putchr('\t');
+ }
+ puts(getline((a1++)->cur));
+ }
+ while (a1 <= addr2);
+ dot = addr2;
+ pflag = 0;
+ listn = 0;
+ listf = 0;
+ continue;
+
+ case 'Q':
+ fchange = 0;
+ case 'q':
+ setnoaddr();
+ newline();
+ quit(sig);
+
+ case 'r':
+ filename(c);
+ caseread:
+ readflg = 1;
+ save28 = (dol != fendcore);
+ if (crflag == 2 || crflag == -2)
+ crflag = -1; /* restore crflag for next file */
+ errno = 0;
+ if ((io = eopen(file, O_RDONLY)) < 0) {
+ lastc = '\n';
+ /* if first entering editor and file does not exist */
+ /* set saved access time to 0 */
+ if (eflg) {
+ savtime = 0;
+ eflg = 0;
+ if (c == 'e' && vflag == 0)
+ qflg = 1;
+ }
+ if (errno == ENOENT) {
+ (void) error(68);
+ } else {
+ (void) error(3);
+ }
+ }
+ /* get last mod time of file */
+ /* eflg - entered editor with ed or e */
+ if (eflg) {
+ eflg = 0;
+ getime();
+ }
+ setall();
+ ninbuf = 0;
+ n = zero != dol;
+#ifdef NULLS
+ nulls = 0;
+#endif
+ if (!globflg && (c == 'r')) save();
+ append(getfile, addr2);
+ exfile();
+ readflg = 0;
+ fchange = n;
+ continue;
+
+ case 's':
+ setdot();
+ nonzero();
+ if (!globflg) save();
+ substitute(globp != 0);
+ continue;
+
+ case 't':
+ move(1);
+ continue;
+
+ case 'u':
+ setdot();
+ newline();
+ if (!initflg)
+ undo();
+ else
+ (void) error(5);
+ fchange = 1;
+ continue;
+
+ case 'v':
+ global(0);
+ continue;
+ case 'V':
+ globaln(0);
+ continue;
+
+ case 'W':
+ case 'w':
+ if (flag28) {
+ flag28 = 0;
+ fchange = 0;
+ (void) error(61);
+ }
+ setall();
+
+ /* on NULL-RE condition do not generate error */
+
+ if ((linebuf[0] != '.') && (zero != dol) &&
+ (addr1 <= zero || addr2 > dol))
+ (void) error(15);
+ filename(c);
+ if (Xqt) {
+ io = eopen(file, O_WRONLY);
+ n = 1; /* set n so newtime will not execute */
+ } else {
+ struct stat lFl;
+ fstat(tfile, &Tf);
+ if (stat(file, &Fl) < 0) {
+ if ((io = creat(file, S_IRUSR|S_IWUSR|S_IRGRP
+ |S_IWGRP|S_IROTH|S_IWOTH)) < 0)
+ (void) error(7);
+ fstat(io, &Fl);
+ Fl.st_mtime = 0;
+ lFl = Fl;
+ close(io);
+ } else {
+#ifndef RESEARCH
+ oldmask = umask(0);
+ /*
+ * Must determine if file is
+ * a symbolic link
+ */
+ lstat(file, &lFl);
+#endif
+ }
+#ifndef RESEARCH
+ /*
+ * Determine if there are enough free blocks on system
+ */
+ if (!Short && statvfs(file, &U) == 0 &&
+ U.f_bfree < ((Tf.st_size/U.f_frsize) + 100)) {
+ Short = 1;
+ (void) error(8);
+ }
+ Short = 0;
+#endif
+ p1 = savedfile; /* The current filename */
+ p2 = file;
+ m = strcmp(p1, p2);
+ if (c == 'w' && Fl.st_nlink == 1 && ISREG(lFl)) {
+ if (close(open(file, O_WRONLY)) < 0)
+ (void) error(9);
+ if (!(n = m))
+ chktime();
+ mkfunny();
+ /*
+ * If funlink equals one it means that
+ * funny points to a valid file which must
+ * be unlinked when interrupted.
+ */
+
+ funlink = 1;
+ if ((io = creat(funny, FMODE(Fl))) >= 0) {
+ chown(funny, Fl.st_uid, Fl.st_gid);
+ chmod(funny, FMODE(Fl));
+ putfile();
+ exfile();
+
+ if (rename(funny, file))
+ (void) error(10);
+ funlink = 0;
+ /* if filenames are the same */
+ if (!n)
+ newtime();
+ /* check if entire buffer was written */
+ fsave = fchange;
+ fchange = (((addr1 == zero) || (addr1 == (zero + 1))) &&
+ (addr2 == dol)) ? 0 : 1;
+ if (fchange == 1 && m != 0) fchange = fsave;
+ continue;
+ }
+ } else
+ n = 1; /* set n so newtime will not execute */
+ if ((io = open(file,
+ (c == 'w') ? O_WRONLY|O_CREAT|O_TRUNC
+ : O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR
+ |S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0)
+ (void) error(7);
+ }
+ putfile();
+ exfile();
+ if (!n) newtime();
+ fsave = fchange;
+ fchange = (((addr1 == zero) || (addr1 == (zero + 1))) &&
+ (addr2 == dol)) ? 0 : 1;
+ /* Leave fchange alone if partial write was to another file */
+ if (fchange == 1 && m != 0) fchange = fsave;
+ continue;
+
+ case 'C':
+ crflag = 1;
+ /*
+ * C is same as X, but always assume input files are
+ * ciphertext
+ */
+ goto encrypt;
+
+ case 'X':
+ crflag = -1;
+encrypt:
+ setnoaddr();
+ newline();
+ xflag = 1;
+ if (permflag)
+ (void) crypt_close(perm);
+ permflag = 1;
+ if ((kflag = run_setkey(&perm[0], getkey(msgtab[66])))
+ == -1) {
+ xflag = 0;
+ kflag = 0;
+ crflag = 0;
+ (void) error(64);
+ }
+ if (kflag == 0)
+ crflag = 0;
+ continue;
+
+ case '=':
+ setall();
+ newline();
+ count = (addr2-zero)&077777;
+ putd();
+ putchr('\n');
+ continue;
+
+ case '!':
+ unixcom();
+ continue;
+
+ case EOF:
+ return;
+
+ case 'P':
+ setnoaddr();
+ newline();
+ if (shflg)
+ shflg = 0;
+ else
+ shflg++;
+ continue;
+ }
+ if (c == 'x')
+ (void) error(60);
+ else
+ (void) error(12);
+ }
+}
+
+LINE
+address(void)
+{
+ int minus, c;
+ LINE a1;
+ int n, relerr, retval;
+
+ minus = 0;
+ a1 = 0;
+ for (;;) {
+ c = getchr();
+ if ('0' <= c && c <= '9') {
+ n = 0;
+ do {
+ n *= 10;
+ n += c - '0';
+ } while ((c = getchr()) >= '0' && c <= '9');
+ peekc = c;
+ if (a1 == 0)
+ a1 = zero;
+ if (minus < 0)
+ n = -n;
+ a1 += n;
+ minus = 0;
+ continue;
+ }
+ relerr = 0;
+ if (a1 || minus)
+ relerr++;
+ switch (c) {
+ case ' ':
+ case '\t':
+ continue;
+
+ case '+':
+ minus++;
+ if (a1 == 0)
+ a1 = dot;
+ continue;
+
+ case '-':
+ case '^':
+ minus--;
+ if (a1 == 0)
+ a1 = dot;
+ continue;
+
+ case '?':
+ case '/':
+ comple(c);
+ a1 = dot;
+ for (;;) {
+ if (c == '/') {
+ a1++;
+ if (a1 > dol)
+ a1 = zero;
+ } else {
+ a1--;
+ if (a1 < zero)
+ a1 = dol;
+ }
+
+ if (execute(0, a1))
+ break;
+ if (a1 == dot)
+ (void) error(13);
+ }
+ break;
+
+ case '$':
+ a1 = dol;
+ break;
+
+ case '.':
+ a1 = dot;
+ break;
+
+ case '\'':
+ if ((c = getchr()) < 'a' || c > 'z')
+ (void) error(2);
+ for (a1 = zero; a1 <= dol; a1++)
+ if (names[c-'a'] == (a1->cur & ~01))
+ break;
+ break;
+
+ default:
+ peekc = c;
+ if (a1 == 0)
+ return (0);
+ a1 += minus;
+
+ /* on NULL-RE condition do not generate error */
+
+ if ((linebuf[0] != '.') && (a1 < zero || a1 > dol))
+ (void) error(15);
+ return (a1);
+ }
+ if (relerr)
+ (void) error(16);
+ }
+}
+
+static void
+setdot(void)
+{
+ if (addr2 == 0)
+ addr1 = addr2 = dot;
+ if (addr1 > addr2)
+ (void) error(17);
+}
+
+static void
+setall(void)
+{
+ if (addr2 == 0) {
+ addr1 = zero+1;
+ addr2 = dol;
+ if (dol == zero)
+ addr1 = zero;
+ }
+ setdot();
+}
+
+static void
+setnoaddr(void)
+{
+ if (addr2)
+ (void) error(18);
+}
+
+static void
+nonzero(void)
+{
+ /* on NULL-RE condition do not generate error */
+
+ if ((linebuf[0] != '.') && (addr1 <= zero || addr2 > dol))
+ (void) error(15);
+}
+
+static void
+setzeroasone(void)
+{
+/* for the c and i commands 0 equal to 1 address */
+ if (addr1 == zero) {
+ addr1 = zero+1;
+ }
+ if (addr2 == zero) {
+ addr2 = zero+1;
+ }
+}
+
+
+static void
+newline(void)
+{
+ int c;
+
+ if ((c = getchr()) == '\n')
+ return;
+ if (c == 'p' || c == 'l' || c == 'n') {
+ pflag++;
+ if (c == 'l') listf++;
+ if (c == 'n') listn++;
+ if ((c = getchr()) == '\n')
+ return;
+ }
+ (void) error(20);
+}
+
+static void
+filename(int comm)
+{
+ char *p1, *p2;
+ int c;
+ int i = 0;
+
+ count = 0;
+ c = getchr();
+ if (c == '\n' || c == EOF) {
+ p1 = savedfile;
+ if (*p1 == 0 && comm != 'f')
+ (void) error(21);
+ /* ncflg set means do not get mod time of file */
+ /* since no filename followed f */
+ if (comm == 'f')
+ ncflg++;
+ p2 = file;
+ while (*p2++ = *p1++);
+ red(savedfile);
+ return;
+ }
+ if (c != ' ')
+ (void) error(22);
+ while ((c = getchr()) == ' ');
+ if (c == '!')
+ ++Xqt, c = getchr();
+ if (c == '\n')
+ (void) error(21);
+ p1 = file;
+ do {
+ if (++i >= FNSIZE)
+ (void) error(24);
+ *p1++ = c;
+ if (c == EOF || (c == ' ' && !Xqt))
+ (void) error(21);
+ } while ((c = getchr()) != '\n');
+ *p1++ = 0;
+ if (Xqt)
+ if (comm == 'f') {
+ --Xqt;
+ (void) error(57);
+ }
+ else
+ return;
+ if (savedfile[0] == 0 || comm == 'e' || comm == 'f') {
+ p1 = savedfile;
+ p2 = file;
+ while (*p1++ = *p2++);
+ }
+ red(file);
+}
+
+
+static void
+exfile(void)
+{
+#ifdef NULLS
+ int c;
+#endif
+
+#ifndef RESEARCH
+ if (oldmask) {
+ umask(oldmask);
+ oldmask = 0;
+ }
+#endif
+ eclose(io);
+ io = -1;
+ if (vflag) {
+ putd();
+ putchr('\n');
+#ifdef NULLS
+ if (nulls) {
+ c = count;
+ count = nulls;
+ nulls = 0;
+ putd();
+ puts(gettext(" nulls replaced by '\\0'"));
+ count = c;
+ }
+#endif
+ }
+}
+
+static void
+onintr(int sig)
+{
+ signal(SIGINT, onintr);
+ putchr('\n');
+ lastc = '\n';
+ globflg = 0;
+ if (funlink) unlink(funny); /* remove tmp file */
+ /* if interrupted a read, only part of file may be in buffer */
+ if (readflg) {
+ sprintf(tstring, "\007read may be incomplete - beware!\007");
+ puts(gettext(tstring));
+ fchange = 0;
+ }
+ (void) error(26);
+}
+
+static void
+onhup(int sig)
+{
+ signal(SIGINT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ /*
+ * if there are lines in file and file was not written
+ * since last update, save in ed.hup, or $HOME/ed.hup
+ */
+ if (dol > zero && fchange == 1) {
+ addr1 = zero+1;
+ addr2 = dol;
+ io = creat("ed.hup",
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+ if (io < 0 && home) {
+ char *fn;
+
+ fn = (char *)calloc(strlen(home) + 8, sizeof (char));
+ if (fn) {
+ strcpy(fn, home);
+ strcat(fn, "/ed.hup");
+ io = creat(fn, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
+ |S_IROTH|S_IWOTH);
+ free(fn);
+ }
+ }
+ if (io > 0)
+ putfile();
+ }
+ fchange = 0;
+ ++errcnt;
+ quit(sig);
+}
+
+static int
+error(int code)
+{
+ int c;
+
+ if (code == 28 && save28 == 0) {
+ fchange = 0;
+ flag28++;
+ }
+ readflg = 0;
+ ++errcnt;
+ listf = listn = 0;
+ pflag = 0;
+#ifndef RESEARCH
+ if (oldmask) {
+ umask(oldmask);
+ oldmask = 0;
+ }
+#endif
+#ifdef NULLS /* Not really nulls, but close enough */
+ /* This is a bug because of buffering */
+ if (code == 28) /* illegal char. */
+ putd();
+#endif
+ /* Cant open file or file does not exist */
+ if ((code == 3) || (code == 68)) {
+ if (qflg == 0) {
+ putchr('?');
+ puts(file);
+ }
+ else
+ qflg = 0;
+ }
+ else
+ {
+ putchr('?');
+ putchr('\n');
+ }
+ count = 0;
+ lseek(0, (long)0, 2);
+ if (globp)
+ lastc = '\n';
+ globp = 0;
+ peekc = lastc;
+ if (lastc)
+ while ((c = getchr()) != '\n' && c != EOF);
+ if (io) {
+ eclose(io);
+ io = -1;
+ }
+ xcode = code;
+ if (hflag)
+ PUTM();
+ if (code == 4)
+ return (0); /* Non-fatal error. */
+ longjmp(savej, 1);
+ /* NOTREACHED */
+}
+
+static int
+getchr(void)
+{
+ char c;
+ if (lastc = peekc) {
+ peekc = 0;
+ return (lastc);
+ }
+ if (globp) {
+ if ((lastc = (unsigned char)*globp++) != 0)
+ return (lastc);
+ globp = 0;
+ return (EOF);
+ }
+ if (read(0, &c, 1) <= 0)
+ return (lastc = EOF);
+ lastc = (unsigned char)c;
+ return (lastc);
+}
+
+static int
+gettty(void)
+{
+ int c;
+ char *gf;
+ char *p;
+
+ p = linebuf;
+ gf = globp;
+ while ((c = getchr()) != '\n') {
+ if (c == EOF) {
+ if (gf)
+ peekc = c;
+ return (c);
+ }
+ if (c == 0)
+ continue;
+ *p++ = c;
+
+ if (p > &linebuf[LBSIZE-1])
+ (void) error(27);
+ }
+ *p++ = 0;
+ if (linebuf[0] == '.' && linebuf[1] == 0)
+ return (EOF);
+
+ /*
+ * POSIX.2/XPG4 explicitly says no to this:
+ *
+ * in Solaris backslash followed by special character "." is
+ * special character "." itself; (so terminating input mode can be
+ * "\.\n").
+ *
+ * however, POSIX2/XPG4 says, input mode is terminated by
+ * entering line consisting of only 2 characters: ".\n"
+ *
+ * if (linebuf[0]=='\\' && linebuf[1]=='.' && linebuf[2]==0) {
+ * linebuf[0] = '.';
+ * linebuf[1] = 0;
+ * }
+ */
+ return (0);
+}
+
+static int
+getfile(void)
+{
+ char c;
+ char *lp, *fp;
+
+ lp = linebuf;
+ fp = nextip;
+ do {
+ if (--ninbuf < 0) {
+ if ((ninbuf = read(io, genbuf, LBSIZE)-1) < 0)
+ if (lp > linebuf) {
+ puts(gettext("'\\n' appended"));
+ *genbuf = '\n';
+ }
+ else
+ return (EOF);
+ if (crflag == -1) {
+ if (isencrypt(genbuf, ninbuf + 1))
+ crflag = 2;
+ else
+ crflag = -2;
+ }
+ fp = genbuf;
+ if (crflag > 0)
+ if (run_crypt(count, genbuf, ninbuf+1, perm) == -1)
+ (void) error(63);
+ }
+ if (lp >= &linebuf[LBSIZE]) {
+ lastc = '\n';
+ (void) error(27);
+ }
+ if ((*lp++ = c = *fp++) == 0) {
+#ifdef NULLS
+ lp[-1] = '\\';
+ *lp++ = '0';
+ nulls++;
+#else
+ lp--;
+ continue;
+#endif
+ }
+ count++;
+ } while (c != '\n');
+ *--lp = 0;
+ nextip = fp;
+ if (fss.Ffill && fss.Flim && lenchk(linebuf, &fss) < 0) {
+ write(1, gettext("line too long: lno = "),
+ strlen(gettext("line too long: lno = ")));
+ ccount = count;
+ count = (++dot-zero)&077777;
+ dot--;
+ putd();
+ count = ccount;
+ putchr('\n');
+ }
+ return (0);
+}
+
+static void
+putfile(void)
+{
+ int n;
+ LINE a1;
+ char *fp, *lp;
+ int nib;
+
+ nib = LBSIZE;
+ fp = genbuf;
+ a1 = addr1;
+ do {
+ lp = getline(a1++->cur);
+ if (fss.Ffill && fss.Flim && lenchk(linebuf, &fss) < 0) {
+ write(1, gettext("line too long: lno = "),
+ strlen(gettext("line too long: lno = ")));
+ ccount = count;
+ count = (a1-zero-1)&077777;
+ putd();
+ count = ccount;
+ putchr('\n');
+ }
+ for (;;) {
+ if (--nib < 0) {
+ n = fp-genbuf;
+ if (kflag)
+ if (run_crypt(count-n, genbuf, n, perm) == -1)
+ (void) error(63);
+ if (write(io, genbuf, n) != n)
+ (void) error(29);
+ nib = LBSIZE - 1;
+ fp = genbuf;
+ }
+ if (dol->cur == 0L)break; /* Allow write of null file */
+ count++;
+ if ((*fp++ = *lp++) == 0) {
+ fp[-1] = '\n';
+ break;
+ }
+ }
+ } while (a1 <= addr2);
+ n = fp-genbuf;
+ if (kflag)
+ if (run_crypt(count-n, genbuf, n, perm) == -1)
+ (void) error(63);
+ if (write(io, genbuf, n) != n)
+ (void) error(29);
+}
+
+static void
+append(int (*f)(void), LINE a)
+{
+ LINE a1, a2, rdot;
+ long tl;
+
+ nline = 0;
+ dot = a;
+ while ((*f)() == 0) {
+ if (dol >= endcore) {
+ if ((int)sbrk(512 * sizeof (struct lin)) == -1) {
+ lastc = '\n';
+ (void) error(30);
+ }
+ endcore += 512;
+ }
+ tl = putline();
+ nline++;
+ a1 = ++dol;
+ a2 = a1+1;
+ rdot = ++dot;
+ while (a1 > rdot)
+ (--a2)->cur = (--a1)->cur;
+ rdot->cur = tl;
+ }
+}
+
+static void
+unixcom(void)
+{
+ void (*savint)();
+ pid_t pid, rpid;
+ int retcode;
+ static char savcmd[LBSIZE]; /* last command */
+ char curcmd[LBSIZE]; /* current command */
+ char *psavcmd, *pcurcmd, *psavedfile;
+ int endflg = 1, shflg = 0;
+ wchar_t c;
+ int len;
+
+ setnoaddr();
+ if (rflg)
+ (void) error(6);
+ pcurcmd = curcmd;
+ /* read command til end */
+
+ /*
+ * a '!' found in beginning of command is replaced with the saved
+ * command. a '%' found in command is replaced with the current
+ * filename
+ */
+
+ c = getchr();
+ if (c == '!') {
+ if (savcmd[0] == 0)
+ (void) error(56);
+ else {
+ psavcmd = savcmd;
+ while (*pcurcmd++ = *psavcmd++);
+ --pcurcmd;
+ shflg = 1;
+ }
+ } else
+ UNGETC(c); /* put c back */
+ while (endflg == 1) {
+ while ((c = get_wchr()) != '\n' && c != '%' && c != '\\') {
+ if ((len = wctomb(pcurcmd, c)) <= 0) {
+ *pcurcmd = (unsigned char)c;
+ len = 1;
+ }
+ pcurcmd += len;
+ }
+
+ if (c == '%') {
+ if (savedfile[0] == 0)
+ (void) error(21);
+ else {
+ psavedfile = savedfile;
+ while (pcurcmd < curcmd + LBSIZE &&
+ (*pcurcmd++ = *psavedfile++));
+ --pcurcmd;
+ shflg = 1;
+ }
+ } else if (c == '\\') {
+ c = get_wchr();
+ if (c != '%')
+ *pcurcmd++ = '\\';
+ if ((len = wctomb(pcurcmd, c)) <= 0) {
+ *pcurcmd = (unsigned char)c;
+ len = 1;
+ }
+ pcurcmd += len;
+ }
+ else
+ /* end of command hit */
+ endflg = 0;
+ }
+ *pcurcmd++ = 0;
+ if (shflg == 1)
+ puts(curcmd);
+ /* save command */
+ strcpy(savcmd, curcmd);
+
+ if ((pid = fork()) == 0) {
+ signal(SIGHUP, oldhup);
+ signal(SIGQUIT, oldquit);
+ close(tfile);
+ if (__xpg4 == 0) { /* not XPG4 */
+ shpath = "/usr/bin/sh";
+ } else {
+ /* XPG4 */
+ shpath = "/usr/xpg4/bin/sh";
+ }
+ execlp((const char *)shpath, "sh", "-c", curcmd, (char *)0);
+ exit(0100);
+ }
+ savint = signal(SIGINT, SIG_IGN);
+ while ((rpid = wait(&retcode)) != pid && rpid != (pid_t)-1);
+ signal(SIGINT, savint);
+ if (vflag) puts("!");
+}
+
+static void
+quit(int sig)
+{
+ if (vflag && fchange) {
+ fchange = 0;
+ if (flag28) {
+ flag28 = 0;
+ (void) error(62);
+ }
+
+ /*
+ * For case where user reads in BOTH a good
+ * file & a bad file
+ */
+ (void) error(1);
+ }
+ unlink(tfname);
+ if (kflag)
+ crypt_close(perm);
+ if (xtflag)
+ crypt_close(tperm);
+ exit(errcnt? 2: 0);
+}
+
+static void
+delete(void)
+{
+ setdot();
+ newline();
+ nonzero();
+ if (!globflg) save();
+ rdelete(addr1, addr2);
+}
+
+static void
+rdelete(LINE ad1, LINE ad2)
+{
+ LINE a1, a2, a3;
+
+ a1 = ad1;
+ a2 = ad2+1;
+ a3 = dol;
+ dol -= a2 - a1;
+ do
+ (a1++)->cur = (a2++)->cur;
+ while (a2 <= a3);
+ a1 = ad1;
+ if (a1 > dol)
+ a1 = dol;
+ dot = a1;
+ fchange = 1;
+}
+
+static void
+gdelete(void)
+{
+ LINE a1, a2, a3;
+
+ a3 = dol;
+ for (a1 = zero+1; (a1->cur&01) == 0; a1++)
+ if (a1 >= a3)
+ return;
+ for (a2 = a1 + 1; a2 <= a3; ) {
+ if (a2->cur & 01) {
+ a2++;
+ dot = a1;
+ } else
+ (a1++)->cur = (a2++)->cur;
+ }
+ dol = a1-1;
+ if (dot > dol)
+ dot = dol;
+ fchange = 1;
+}
+
+static char *
+getline(long tl)
+{
+ char *bp, *lp;
+ int nl;
+
+ lp = linebuf;
+ bp = getblock(tl, READ);
+ nl = nleft;
+ tl &= ~0377;
+ while (*lp++ = *bp++)
+ if (--nl == 0) {
+ bp = getblock(tl += 0400, READ);
+ nl = nleft;
+ }
+ return (linebuf);
+}
+
+static long
+putline(void)
+{
+ char *bp, *lp;
+ int nl;
+ long tl;
+
+ fchange = 1;
+ lp = linebuf;
+ tl = tline;
+ bp = getblock(tl, WRITE);
+ nl = nleft;
+ tl &= ~0377;
+ while (*bp = *lp++) {
+ if (*bp++ == '\n') {
+ *--bp = 0;
+ linebp = lp;
+ break;
+ }
+ if (--nl == 0) {
+ bp = getblock(tl += 0400, WRITE);
+ nl = nleft;
+ }
+ }
+ nl = tline;
+ tline += (((lp-linebuf)+03)>>1)&077776;
+ return (nl);
+}
+
+static char *
+getblock(long atl, long iof)
+{
+ int bno, off;
+ char *p1, *p2;
+ int n;
+
+ bno = atl >> 8;
+ off = (atl<<1)&0774;
+
+ /* bno is limited to 16 bits */
+ if (bno >= 65535) {
+ lastc = '\n';
+ (void) error(31);
+ }
+ nleft = 512 - off;
+ if (bno == iblock) {
+ ichanged |= iof;
+ return (ibuff+off);
+ }
+ if (bno == oblock)
+ return (obuff+off);
+ if (iof == READ) {
+ if (ichanged) {
+ if (xtflag)
+ if (run_crypt(0L, ibuff, 512, tperm) == -1)
+ (void) error(63);
+ blkio(iblock, ibuff, write);
+ }
+ ichanged = 0;
+ iblock = bno;
+ blkio(bno, ibuff, read);
+ if (xtflag)
+ if (run_crypt(0L, ibuff, 512, tperm) == -1)
+ (void) error(63);
+ return (ibuff+off);
+ }
+ if (oblock >= 0) {
+ if (xtflag) {
+ p1 = obuff;
+ p2 = crbuf;
+ n = 512;
+ while (n--)
+ *p2++ = *p1++;
+ if (run_crypt(0L, crbuf, 512, tperm) == -1)
+ (void) error(63);
+ blkio(oblock, crbuf, write);
+ } else
+ blkio(oblock, obuff, write);
+ }
+ oblock = bno;
+ return (obuff+off);
+}
+
+static void
+blkio(int b, char *buf, ssize_t (*iofcn)())
+{
+ lseek(tfile, (long)b<<9, 0);
+ if ((*iofcn)(tfile, buf, 512) != 512) {
+ if (dol != zero)
+ (void) error(32); /* Bypass this if writing null file */
+ }
+}
+
+static void
+init(void)
+{
+ long *markp;
+ mode_t omask;
+
+ if (tfile != -1) {
+ (void) close(tfile);
+ (void) unlink(tfname);
+ }
+
+ tline = 2;
+ for (markp = names; markp < &names[26]; )
+ *markp++ = 0L;
+ subnewa = 0L;
+ anymarks = 0;
+ iblock = -1;
+ oblock = -1;
+ ichanged = 0;
+ initflg = 1;
+ omask = umask(0);
+
+ if ((tfile = open(tfname, O_CREAT|O_EXCL|O_RDWR,
+ S_IRUSR|S_IWUSR)) < 0) {
+ puts(gettext(msgtab[70]));
+ exit(2);
+ }
+
+ umask(omask);
+ if (xflag) {
+ xtflag = 1;
+ if (tpermflag)
+ (void) crypt_close(tperm);
+ tpermflag = 1;
+ if (makekey(tperm)) {
+ xtflag = 0;
+ puts(gettext(msgtab[65]));
+ }
+ }
+ brk((char *)fendcore);
+ dot = zero = dol = savdot = savdol = fendcore;
+ flag28 = save28 = 0;
+ endcore = fendcore - sizeof (struct lin);
+}
+
+static void
+global(int k)
+{
+ char *gp;
+ wchar_t l;
+ char multic[MB_LEN_MAX];
+ wchar_t c;
+ LINE a1;
+ char globuf[LBSIZE];
+ int n;
+ int len;
+
+ if (globp)
+ (void) error(33);
+ setall();
+ nonzero();
+ if ((n = _mbftowc(multic, &l, getchr, &peekc)) <= 0)
+ (void) error(67);
+ if (l == '\n')
+ (void) error(19);
+ save();
+ comple(l);
+ gp = globuf;
+ while ((c = get_wchr()) != '\n') {
+ if (c == EOF)
+ (void) error(19);
+
+ /* '\\' has special meaning only if preceding a '\n' */
+ if (c == '\\') {
+ c = get_wchr();
+ if (c != '\n')
+ *gp++ = '\\';
+ }
+ if ((gp + (unsigned int)MB_CUR_MAX) >= &globuf[LBSIZE-1])
+ (void) error(34);
+ if ((len = wctomb(gp, c)) <= 0) {
+ *gp = (unsigned char)c;
+ len = 1;
+ }
+ gp += len;
+ }
+ if (gp == globuf)
+ *gp++ = 'p';
+ *gp++ = '\n';
+ *gp++ = 0;
+ for (a1 = zero; a1 <= dol; a1++) {
+ a1->cur &= ~01;
+ if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k)
+ a1->cur |= 01;
+ }
+ /*
+ * Special case: g/.../d (avoid n^2 algorithm)
+ */
+ if (globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == '\0') {
+ gdelete();
+ return;
+ }
+ for (a1 = zero; a1 <= dol; a1++) {
+ if (a1->cur & 01) {
+ a1->cur &= ~01;
+ dot = a1;
+ globp = globuf;
+ globflg = 1;
+ commands();
+ globflg = 0;
+ a1 = zero;
+ }
+ }
+}
+
+static void
+join(void)
+{
+ char *gp, *lp;
+ LINE a1;
+
+ if (addr1 == addr2)
+ return;
+ gp = genbuf;
+ for (a1 = addr1; a1 <= addr2; a1++) {
+ lp = getline(a1->cur);
+ while (*gp = *lp++)
+ if (gp++ > &genbuf[LBSIZE-1])
+ (void) error(27);
+ }
+ lp = linebuf;
+ gp = genbuf;
+ while (*lp++ = *gp++);
+ addr1->cur = putline();
+ if (addr1 < addr2)
+ rdelete(addr1+1, addr2);
+ dot = addr1;
+}
+
+static void
+substitute(int inglob)
+{
+ int nl;
+ LINE a1;
+ long *markp;
+ int ingsav; /* For saving arg. */
+
+ ingsav = inglob;
+ ocerr2 = 0;
+ gsubf = compsub();
+ for (a1 = addr1; a1 <= addr2; a1++) {
+ if (execute(0, a1) == 0)
+ continue;
+ numpass = 0;
+ ocerr1 = 0;
+ inglob |= 01;
+ dosub();
+ if (gsubf) {
+ while (*loc2) {
+ if (execute(1, (LINE)0) == 0)
+ break;
+ dosub();
+ }
+ }
+ if (ocerr1 == 0)continue; /* Don't put out-not changed. */
+ subnewa = putline();
+ a1->cur &= ~01;
+ if (anymarks) {
+ for (markp = names; markp < &names[26]; markp++)
+ if (*markp == a1->cur)
+ *markp = subnewa;
+ }
+ a1->cur = subnewa;
+ append(getsub, a1);
+ nl = nline;
+ a1 += nl;
+ addr2 += nl;
+ }
+ if (ingsav)
+ return; /* Was in global-no error msg allowed. */
+ if (inglob == 0)
+ (void) error(35); /* Not in global, but not found. */
+ if (ocerr2 == 0)
+ (void) error(35); /* RE found, but occurrence match failed. */
+}
+
+static int
+compsub(void)
+{
+ int c;
+ wchar_t seof;
+ char *p;
+ char multic[MB_LEN_MAX];
+ int n;
+ static char remem[RHSIZE];
+ static int remflg = -1;
+ int i;
+
+ if ((n = _mbftowc(multic, &seof, getchr, &peekc)) <= 0)
+ (void) error(67);
+ if (seof == '\n' || seof == ' ')
+ (void) error(36);
+ comple(seof);
+ p = rhsbuf;
+ for (;;) {
+ wchar_t cl;
+ if ((n = _mbftowc(multic, &cl, getchr, &peekc)) <= 0)
+ (void) error(67);
+ if (cl == '\\') {
+ *p++ = '\\';
+ if (p >= &rhsbuf[RHSIZE])
+ (void) error(38);
+ if ((n = _mbftowc(multic, &cl, getchr, &peekc)) <= 0)
+ (void) error(67);
+ } else if (cl == '\n') {
+ if (nodelim == 1) {
+ nodelim = 0;
+ (void) error(36);
+ }
+ if (!(globp && globp[0])) {
+ UNGETC('\n');
+ pflag++;
+ break;
+ }
+ } else if (cl == seof)
+ break;
+ if (p + n > &rhsbuf[RHSIZE])
+ (void) error(38);
+ (void) strncpy(p, multic, n);
+ p += n;
+ }
+ *p++ = 0;
+ if (rhsbuf[0] == '%' && rhsbuf[1] == 0)
+ /*
+ * If there isn't a remembered string, it is an error;
+ * otherwise the right hand side is the previous right
+ * hand side.
+ */
+
+ if (remflg == -1)
+ (void) error(55);
+ else
+ strcpy(rhsbuf, remem);
+ else {
+ strcpy(remem, rhsbuf);
+ remflg = 0;
+ }
+ c = 0;
+ peekc = getchr(); /* Gets char after third delimiter. */
+ if (peekc == 'g') {
+ c = LBSIZE; peekc = 0;
+ }
+ if (peekc >= '1' && peekc <= '9') {
+ c = peekc-'0';
+ peekc = 0; /* Allows getchr() to get next char. */
+ while (1) {
+ i = getchr();
+ if (i < '0' || i > '9')
+ break;
+ c = c*10 + i-'0';
+ if (c > LBSIZE-1)
+ (void) error(20); /* "Illegal suffix" */
+ }
+ peekc = i; /* Effectively an unget. */
+ }
+ newline();
+ return (c);
+
+ /*
+ * Returns occurrence value. 0 & 1 both do first occurrence
+ * only: c = 0 if ordinary substitute; c = 1
+ * if use 1 in global sub(s/a/b/1). 0 in global form is illegal.
+ */
+}
+
+static int
+getsub(void)
+{
+ char *p1, *p2;
+
+ p1 = linebuf;
+ if ((p2 = linebp) == 0)
+ return (EOF);
+ while (*p1++ = *p2++);
+ linebp = 0;
+ return (0);
+}
+
+static void
+dosub(void)
+{
+ char *lp, *sp, *rp;
+ int c;
+
+ if (gsubf > 0 && gsubf < LBSIZE) {
+ numpass++;
+ if (gsubf != numpass)
+ return;
+ }
+ ocerr1++;
+ ocerr2++;
+ lp = linebuf;
+ sp = genbuf;
+ rp = rhsbuf;
+ while (lp < loc1)
+ *sp++ = *lp++;
+ while (c = *rp++) {
+ if (c == '&') {
+ sp = place(sp, loc1, loc2);
+ continue;
+ } else if (c == '\\') {
+ c = *rp++;
+ if (c >= '1' && c < nbra + '1') {
+ sp = place(sp, braslist[c-'1'], braelist[c-'1']);
+ continue;
+ }
+ }
+ *sp++ = c;
+ if (sp >= &genbuf[LBSIZE])
+ (void) error(27);
+ }
+ lp = loc2;
+ loc2 = sp - genbuf + linebuf;
+ while (*sp++ = *lp++)
+ if (sp >= &genbuf[LBSIZE])
+ (void) error(27);
+ lp = linebuf;
+ sp = genbuf;
+ while (*lp++ = *sp++);
+}
+
+static char *
+place(char *sp, char *l1, char *l2)
+{
+
+ while (l1 < l2) {
+ *sp++ = *l1++;
+ if (sp >= &genbuf[LBSIZE])
+ (void) error(27);
+ }
+ return (sp);
+}
+
+static void
+comple(wchar_t seof)
+{
+ int cclass = 0;
+ wchar_t c;
+ int n;
+ char *cp = genbuf;
+ char multic[MB_LEN_MAX];
+
+ while (1) {
+ if ((n = _mbftowc(multic, &c, getchr, &peekc)) < 0)
+ error1(67);
+ if (n == 0 || c == '\n') {
+ if (cclass)
+ error1(49);
+ else
+ break;
+ }
+ if (c == seof && !cclass)
+ break;
+ if (cclass && c == ']') {
+ cclass = 0;
+ if (cp > &genbuf[LBSIZE-1])
+ error1(50);
+ *cp++ = ']';
+ continue;
+ }
+ if (c == '[' && !cclass) {
+ cclass = 1;
+ if (cp > &genbuf[LBSIZE-1])
+ error1(50);
+ *cp++ = '[';
+ if ((n = _mbftowc(multic, &c, getchr, &peekc)) < 0)
+ error1(67);
+ if (n == 0 || c == '\n')
+ error1(49);
+ }
+ if (c == '\\' && !cclass) {
+ if (cp > &genbuf[LBSIZE-1])
+ error1(50);
+ *cp++ = '\\';
+ if ((n = _mbftowc(multic, &c, getchr, &peekc)) < 0)
+ error1(67);
+ if (n == 0 || c == '\n')
+ error1(36);
+ }
+ if (cp + n > &genbuf[LBSIZE-1])
+ error1(50);
+ (void) strncpy(cp, multic, n);
+ cp += n;
+ }
+ *cp = '\0';
+ if (n != 0 && c == '\n')
+ UNGETC('\n');
+ if (n == 0 || c == '\n')
+ nodelim = 1;
+
+ /*
+ * NULL RE: do not compile a null regular expression; but process
+ * input with last regular expression encountered
+ */
+
+ if (genbuf[0] != '\0') {
+ if (expbuf)
+ free(expbuf);
+ expbuf = compile(genbuf, (char *)0, (char *)0);
+ }
+ if (regerrno)
+ error1(regerrno);
+}
+
+static void
+move(int cflag)
+{
+ LINE adt, ad1, ad2;
+
+ setdot();
+ nonzero();
+ if ((adt = address()) == 0)
+ (void) error(39);
+ newline();
+ if (!globflg) save();
+ if (cflag) {
+ ad1 = dol;
+ append(getcopy, ad1++);
+ ad2 = dol;
+ } else {
+ ad2 = addr2;
+ for (ad1 = addr1; ad1 <= ad2; )
+ (ad1++)->cur &= ~01;
+ ad1 = addr1;
+ }
+ ad2++;
+ if (adt < ad1) {
+ dot = adt + (ad2-ad1);
+ if ((++adt) == ad1)
+ return;
+ reverse(adt, ad1);
+ reverse(ad1, ad2);
+ reverse(adt, ad2);
+ } else if (adt >= ad2) {
+ dot = adt++;
+ reverse(ad1, ad2);
+ reverse(ad2, adt);
+ reverse(ad1, adt);
+ } else
+ (void) error(39);
+ fchange = 1;
+}
+
+static void
+reverse(LINE a1, LINE a2)
+{
+ long t;
+
+ for (;;) {
+ t = (--a2)->cur;
+ if (a2 <= a1)
+ return;
+ a2->cur = a1->cur;
+ (a1++)->cur = t;
+ }
+}
+
+static int
+getcopy(void)
+{
+
+ if (addr1 > addr2)
+ return (EOF);
+ (void) getline((addr1++)->cur);
+ return (0);
+}
+
+
+/*
+ * Handles error code returned from comple() routine: regular expression
+ * compile and match routines
+ */
+
+static void
+error1(int code)
+{
+ nbra = 0;
+ (void) error(code);
+}
+
+
+static int
+execute(int gf, LINE addr)
+{
+ char *p1;
+ int c;
+
+ for (c = 0; c < nbra; c++) {
+ braslist[c] = 0;
+ braelist[c] = 0;
+ }
+ if (gf)
+ locs = p1 = loc2;
+ else {
+ if (addr == zero)
+ return (0);
+ p1 = getline(addr->cur);
+ locs = 0;
+ }
+ return (step(p1, expbuf));
+}
+
+
+static void
+putd()
+{
+ int r;
+
+ r = (int)(count%10);
+ count /= 10;
+ if (count)
+ putd();
+ putchr(r + '0');
+}
+
+
+int
+puts(const char *sp)
+{
+ int n;
+ wchar_t c;
+ int sz, i;
+ if (fss.Ffill && (listf == 0)) {
+
+ /* deliberate attempt to remove constness of sp because */
+ /* it needs to be expanded */
+
+ if ((i = expnd((char *)sp, funny, &sz, &fss)) == -1) {
+ write(1, funny, fss.Flim & 0377);
+ putchr('\n');
+ write(1, gettext("too long"),
+ strlen(gettext("too long")));
+ }
+ else
+ write(1, funny, sz);
+ putchr('\n');
+ if (i == -2)
+ write(1, gettext("tab count\n"),
+ strlen(gettext("tab count\n")));
+ return (0);
+ }
+ col = 0;
+ while (*sp) {
+ n = mbtowc(&c, sp, MB_LEN_MAX);
+ if (listf) {
+ if (n < 1)
+ (void) error(28);
+ else if (n == 1)
+ putchr((unsigned char)*sp++);
+ else {
+ sp += n;
+ putwchr(c);
+ }
+ } else {
+ putchr((unsigned char)*sp++);
+ }
+ }
+#ifndef XPG6
+ if (listf)
+ putchr('$'); /* end of line is marked with a $ */
+#else
+ if (listf) {
+ /* xpg6 - ensure that the end of line $ is not preceeded with a "\" */
+ /* by doing a putchr() with listf=0, thereby avoiding the $ case */
+ /* statement in putchr() */
+ listf = 0;
+ putchr('$'); /* end of line is marked with a $ */
+ listf++;
+ }
+#endif
+ putchr('\n');
+ return (1);
+}
+
+
+static void
+putwchr(wchar_t ac)
+{
+ char buf[MB_LEN_MAX], *p;
+ char *lp;
+ wchar_t c;
+ short len;
+
+ lp = linp;
+ c = ac;
+ if (listf) {
+ if (!iswprint(c)) {
+ p = &buf[0];
+ if ((len = wctomb(p, c)) <= 0) {
+ *p = (unsigned char)c;
+ len = 1;
+ };
+ while (len--) {
+ if (col + 4 >= 72) {
+ col = 0;
+ *lp++ = '\\';
+ *lp++ = '\n';
+ }
+ (void) sprintf(lp, "\\%03o",
+ *(unsigned char *)p++);
+ col += 4;
+ lp += 4;
+ }
+ } else {
+ if ((len = wcwidth(c)) <= 0)
+ len = 0;
+ if (col + len >= 72) {
+ col = 0;
+ *lp++ = '\\';
+ *lp++ = '\n';
+ }
+ col += len;
+ if ((len = wctomb(lp, c)) <= 0) {
+ *lp = (unsigned char)c;
+ len = 1;
+ }
+ lp += len;
+ }
+ } else {
+ if ((len = wctomb(lp, c)) <= 0) {
+ *lp = (unsigned char)c;
+ len = 1;
+ }
+ lp += len;
+ }
+ if (c == '\n' || lp >= &line[64]) {
+ linp = line;
+ len = lp - line;
+ write(1, line, len);
+ return;
+ }
+ linp = lp;
+}
+
+
+static void
+putchr(unsigned char c)
+{
+ char *lp;
+ int len;
+
+ lp = linp;
+ if (listf && c != '\n') {
+ switch (c) {
+ case '\\' :
+ *lp++ = '\\';
+ *lp++ = '\\';
+ col += 2;
+ break;
+ case '\007' :
+ *lp++ = '\\';
+ *lp++ = 'a';
+ col += 2;
+ break;
+ case '\b' :
+ *lp++ = '\\';
+ *lp++ = 'b';
+ col += 2;
+ break;
+ case '\f' :
+ *lp++ = '\\';
+ *lp++ = 'f';
+ col += 2;
+ break;
+ case '\r' :
+ *lp++ = '\\';
+ *lp++ = 'r';
+ col += 2;
+ break;
+ case '\t' :
+ *lp++ = '\\';
+ *lp++ = 't';
+ col += 2;
+ break;
+ case '\v' :
+ *lp++ = '\\';
+ *lp++ = 'v';
+ col += 2;
+ break;
+#ifdef XPG6
+ /* if $ characters are within the line preceed with \ */
+ case '$' :
+ *lp++ = '\\';
+ *lp++ = '$';
+ col += 2;
+ break;
+#endif
+ default:
+ if (isprint(c)) {
+ *lp++ = c;
+ col += 1;
+ } else {
+ (void) sprintf(lp, "\\%03o", c);
+ col += 4;
+ lp += 4;
+ }
+ break;
+ }
+
+ /*
+ * long lines are folded w/ pt of folding indicated by writing
+ * backslash/newline character
+ */
+
+ if (col + 1 >= 72) {
+ col = 0;
+ *lp++ = '\\';
+ *lp++ = '\n';
+ }
+ } else
+ *lp++ = c;
+ if (c == '\n' || lp >= &line[64]) {
+ linp = line;
+ len = lp - line;
+ (void) write(1, line, len);
+ return;
+ }
+ linp = lp;
+}
+
+
+static char *
+getkey(const char *prompt)
+{
+ struct termio b;
+ int save;
+ void (*sig)();
+ static char key[KSIZE+1];
+ char *p;
+ int c;
+
+ sig = signal(SIGINT, SIG_IGN);
+ ioctl(0, TCGETA, &b);
+ save = b.c_lflag;
+ b.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+ ioctl(0, TCSETAW, &b);
+ write(1, gettext(prompt), strlen(gettext(prompt)));
+ p = key;
+ while (((c = getchr()) != EOF) && (c != '\n')) {
+ if (p < &key[KSIZE])
+ *p++ = c;
+ }
+ *p = 0;
+ write(1, "\n", 1);
+ b.c_lflag = save;
+ ioctl(0, TCSETAW, &b);
+ signal(SIGINT, sig);
+ return (key);
+}
+
+
+static void
+globaln(int k)
+{
+ char *gp;
+ int c;
+ int n;
+ wchar_t cl;
+ LINE a1;
+ int nfirst;
+ char globuf[LBSIZE];
+ char multic[MB_LEN_MAX];
+ int len;
+ int pflag_save = 0;
+ int listf_save = 0;
+ int listn_save = 0;
+
+ if (globp)
+ (void) error(33);
+ setall();
+ nonzero();
+ if ((n = _mbftowc(multic, &cl, getchr, &peekc)) <= 0)
+ (void) error(67);
+ if (cl == '\n')
+ (void) error(19);
+ save();
+ comple(cl);
+ for (a1 = zero; a1 <= dol; a1++) {
+ a1->cur &= ~01;
+ if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k)
+ a1->cur |= 01;
+ }
+ nfirst = 0;
+ newline();
+ /*
+ * preserve the p, l, and n suffix commands of the G and V
+ * commands during the interactive section and restore
+ * on completion of the G and V command.
+ */
+ pflag_save = pflag;
+ listf_save = listf;
+ listn_save = listn;
+ pflag = 0;
+ listf = 0;
+ listn = 0;
+ for (a1 = zero; a1 <= dol; a1++) {
+ if (a1->cur & 01) {
+ a1->cur &= ~01;
+ dot = a1;
+ puts(getline(a1->cur));
+ if ((c = get_wchr()) == EOF)
+ (void) error(52);
+ if (c == 'a' || c == 'i' || c == 'c')
+ (void) error(53);
+ if (c == '\n') {
+ a1 = zero;
+ continue;
+ }
+ if (c != '&') {
+ gp = globuf;
+ if ((len = wctomb(gp, c)) <= 0) {
+ *gp = (unsigned char)c;
+ len = 1;
+ }
+ gp += len;
+ while ((c = get_wchr()) != '\n') {
+
+ /* '\\' has special meaning only if preceding a '\n' */
+ if (c == '\\') {
+ c = get_wchr();
+ if (c != '\n')
+ *gp++ = '\\';
+ }
+ if ((gp + (unsigned int)MB_CUR_MAX) >=
+ &globuf[LBSIZE-1])
+ (void) error(34);
+
+ if ((len = wctomb(gp, c)) <= 0) {
+ *gp = (unsigned char)c;
+ len = 1;
+ }
+ gp += len;
+ }
+ *gp++ = '\n';
+ *gp++ = 0;
+ nfirst = 1;
+ } else if ((c = get_wchr()) != '\n')
+ (void) error(54);
+ globp = globuf;
+ if (nfirst) {
+ globflg = 1;
+ commands();
+ globflg = 0;
+ } else
+ (void) error(56);
+ globp = 0;
+ a1 = zero;
+ }
+ }
+ pflag = pflag_save;
+ listf = listf_save;
+ listn = listn_save;
+}
+
+
+static int
+eopen(char *string, int rw)
+{
+#define w_or_r(a, b) (rw ? a : b)
+ int pf[2];
+ pid_t i;
+ int io;
+ int chcount; /* # of char read. */
+
+ if (rflg) { /* restricted shell */
+ if (Xqt) {
+ Xqt = 0;
+ (void) error(6);
+ }
+ }
+ if (!Xqt) {
+ if ((io = open(string, rw)) >= 0) {
+ if (fflg) {
+ chcount = read(io, crbuf, LBSIZE);
+ if (crflag == -1) {
+ if (isencrypt(crbuf, chcount))
+ crflag = 2;
+ else
+ crflag = -2;
+ }
+ if (crflag > 0)
+ if (run_crypt(0L, crbuf, chcount, perm) == -1)
+ (void) error(63);
+ if (fspec(crbuf, &fss, 0) < 0) {
+ fss.Ffill = 0;
+ fflg = 0;
+ (void) error(4);
+ }
+ lseek(io, 0L, 0);
+ }
+ }
+ fflg = 0;
+ return (io);
+ }
+ if (pipe(pf) < 0)
+xerr: (void) error(0);
+ if ((i = fork()) == 0) {
+ signal(SIGHUP, oldhup);
+ signal(SIGQUIT, oldquit);
+ signal(SIGPIPE, oldpipe);
+ signal(SIGINT, (void (*)()) 0);
+ close(w_or_r(pf[1], pf[0]));
+ close(w_or_r(0, 1));
+ dup(w_or_r(pf[0], pf[1]));
+ close(w_or_r(pf[0], pf[1]));
+ if (__xpg4 == 0) { /* not XPG4 */
+ shpath = "/usr/bin/sh";
+ } else {
+ /* XPG4 */
+ shpath = "/usr/xpg4/bin/sh";
+ }
+ execlp((const char *)shpath, "sh", "-c", string, (char *)0);
+ exit(1);
+ }
+ if (i == (pid_t)-1)
+ goto xerr;
+ close(w_or_r(pf[0], pf[1]));
+ return (w_or_r(pf[1], pf[0]));
+}
+
+
+static void
+eclose(int f)
+{
+ close(f);
+ if (Xqt)
+ Xqt = 0, wait((int *)0);
+}
+
+
+static void
+mkfunny(void)
+{
+ char *p, *p1, *p2;
+
+ p2 = p1 = funny;
+ p = file;
+ /*
+ * Go to end of file name
+ */
+ while (*p)
+ p++;
+ while (*--p == '/') /* delete trailing slashes */
+ *p = '\0';
+ /*
+ * go back to beginning of file
+ */
+ p = file;
+ /*
+ * Copy file name to funny setting p2 at
+ * basename of file.
+ */
+ while (*p1++ = *p)
+ if (*p++ == '/') p2 = p1;
+ /*
+ * Set p1 to point to basename of tfname.
+ */
+ p1 = strrchr(tfname, '/');
+ if (strlen(tfname) > (size_t)6)
+ p1 = &tfname[strlen(tfname)-6];
+ p1++;
+ *p2 = '\007'; /* add unprintable char for funny a unique name */
+ /*
+ * Copy tfname to file.
+ */
+ while (*++p2 = *p1++);
+}
+
+
+static void
+getime(void) /* get modified time of file and save */
+{
+ if (stat(file, &Fl) < 0)
+ savtime = 0;
+ else
+ savtime = Fl.st_mtime;
+}
+
+
+static void
+chktime(void) /* check saved mod time against current mod time */
+{
+ if (savtime != 0 && Fl.st_mtime != 0) {
+ if (savtime != Fl.st_mtime)
+ (void) error(58);
+ }
+}
+
+
+static void
+newtime(void) /* get new mod time and save */
+{
+ stat(file, &Fl);
+ savtime = Fl.st_mtime;
+}
+
+
+static void
+red(char *op) /* restricted - check for '/' in name */
+ /* and delete trailing '/' */
+{
+ char *p;
+
+ p = op;
+ while (*p)
+ if (*p++ == '/'&& rflg) {
+ *op = 0;
+ (void) error(6);
+ }
+ /* delete trailing '/' */
+ while (p > op) {
+ if (*--p == '/')
+ *p = '\0';
+ else break;
+ }
+}
+
+
+/*
+ * Searches thru beginning of file looking for a string of the form
+ * <: values... :>
+ *
+ * where "values" are
+ *
+ * \b ignored
+ * s<num> sets the Flim to <num>
+ * t??? sets tab stop stuff
+ * d ignored
+ * m<num> ignored
+ * e ignored
+ */
+
+static int
+fspec(char line[], struct Fspec *f, int up)
+{
+ struct termio arg;
+ int havespec, n;
+ int len;
+
+ if (!up) clear(f);
+
+ havespec = fsprtn = 0;
+ for (fsp = line; *fsp && *fsp != '\n'; fsp += len) {
+ if ((len = mblen(fsp, MB_CUR_MAX)) <= 0)
+ len = 1;
+ switch (*fsp) {
+
+ case '<': if (havespec)
+ return (-1);
+ if (*(fsp+1) == ':') {
+ havespec = 1;
+ clear(f);
+ if (!ioctl(1, TCGETA, &arg) &&
+ ((arg.c_oflag&TAB3) == TAB3))
+ f->Ffill = 1;
+ fsp++;
+ continue;
+ }
+
+ case ' ': continue;
+
+ case 's': if (havespec && (n = numb()) >= 0)
+ f->Flim = n;
+ continue;
+
+ case 't': if (havespec) targ(f);
+ continue;
+
+ case 'd': continue;
+
+ case 'm': if (havespec) n = numb();
+ continue;
+
+ case 'e': continue;
+ case ':': if (!havespec) continue;
+ if (*(fsp+1) != '>') fsprtn = -1;
+ return (fsprtn);
+
+ default: if (!havespec) continue;
+ return (-1);
+ }
+ }
+ return (1);
+}
+
+
+static int
+numb(void)
+{
+ int n;
+
+ n = 0;
+ while (*++fsp >= '0' && *fsp <= '9')
+ n = 10*n + *fsp-'0';
+ fsp--;
+ return (n);
+}
+
+
+static void
+targ(struct Fspec *f)
+{
+
+ if (*++fsp == '-') {
+ if (*(fsp + 1) >= '0' && *(fsp+1) <= '9') tincr(numb(), f);
+ else tstd(f);
+ return;
+ }
+ if (*fsp >= '0' && *fsp <= '9') {
+ tlist(f);
+ return;
+ }
+ fsprtn = -1;
+ fsp--;
+}
+
+
+static void
+tincr(int n, struct Fspec *f)
+{
+ int l, i;
+
+ l = 1;
+ for (i = 0; i < 20; i++)
+ f->Ftabs[i] = l += n;
+ f->Ftabs[i] = 0;
+}
+
+
+static void
+tstd(struct Fspec *f)
+{
+ char std[3];
+
+ std[0] = *++fsp;
+ if (*(fsp+1) >= '0' && *(fsp+1) <= '9') {
+ std[1] = *++fsp;
+ std[2] = '\0';
+ } else std[1] = '\0';
+ fsprtn = stdtab(std, f->Ftabs);
+}
+
+
+static void
+tlist(struct Fspec *f)
+{
+ int n, last, i;
+
+ fsp--;
+ last = i = 0;
+
+ do {
+ if ((n = numb()) <= last || i >= 20) {
+ fsprtn = -1;
+ return;
+ }
+ f->Ftabs[i++] = last = n;
+ } while (*++fsp == ',');
+
+ f->Ftabs[i] = 0;
+ fsp--;
+}
+
+
+static int
+expnd(char line[], char buf[], int *sz, struct Fspec *f)
+{
+ char *l, *t;
+ int b;
+
+ l = line - 1;
+ b = 1;
+ t = f->Ftabs;
+ fsprtn = 0;
+
+ while (*++l && *l != '\n' && b < 511) {
+ if (*l == '\t') {
+ while (*t && b >= *t) t++;
+ if (*t == 0) fsprtn = -2;
+ do buf[b-1] = ' '; while (++b < *t);
+ } else buf[b++ - 1] = *l;
+ }
+
+ buf[b] = '\0';
+ *sz = b;
+ if (*l != '\0' && *l != '\n') {
+ buf[b-1] = '\n';
+ return (-1);
+ }
+ buf[b-1] = *l;
+ if (f->Flim && (b-1 > (int)f->Flim))
+ return (-1);
+ return (fsprtn);
+}
+
+
+static void
+clear(struct Fspec *f)
+{
+ f->Ftabs[0] = f->Fdel = f->Fmov = f->Ffill = 0;
+ f->Flim = 0;
+}
+
+
+static int
+lenchk(char line[], struct Fspec *f)
+{
+ char *l, *t;
+ int b;
+
+ l = line - 1;
+ b = 1;
+ t = f->Ftabs;
+
+ while (*++l && *l != '\n' && b < 511) {
+ if (*l == '\t') {
+ while (*t && b >= *t) t++;
+ while (++b < *t);
+ } else b++;
+ }
+
+ if ((*l != '\0' && *l != '\n') || (f->Flim && (b-1 > (int)f->Flim)))
+ return (-1);
+ return (0);
+}
+#define NTABS 21
+
+
+/*
+ * stdtabs: standard tabs table
+ * format: option code letter(s), null, tabs, null
+ */
+
+static char stdtabs[] = {
+'a', 0, 1, 10, 16, 36, 72, 0, /* IBM 370 Assembler */
+'a', '2', 0, 1, 10, 16, 40, 72, 0, /* IBM Assembler alternative */
+'c', 0, 1, 8, 12, 16, 20, 55, 0, /* COBOL, normal */
+'c', '2', 0, 1, 6, 10, 14, 49, 0, /* COBOL, crunched */
+'c', '3', 0, 1, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50,
+ 54, 58, 62, 67, 0,
+'f', 0, 1, 7, 11, 15, 19, 23, 0, /* FORTRAN */
+'p', 0, 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 0,
+ /* PL/I */
+'s', 0, 1, 10, 55, 0, /* SNOBOL */
+'u', 0, 1, 12, 20, 44, 0, /* UNIVAC ASM */
+0 };
+
+
+/*
+ * stdtab: return tab list for any "canned" tab option.
+ * entry: option points to null-terminated option string
+ * tabvect points to vector to be filled in
+ * exit: return (0) if legal, tabvect filled, ending with zero
+ * return (-1) if unknown option
+ */
+
+
+static int
+stdtab(char option[], char tabvect[NTABS])
+{
+ char *scan;
+ tabvect[0] = 0;
+ scan = stdtabs;
+ while (*scan) {
+ if (strequal(&scan, option)) {
+ strcopy(scan, tabvect);
+ break;
+ } else
+ while (*scan++); /* skip over tab specs */
+ }
+
+/* later: look up code in /etc/something */
+ return (tabvect[0] ? 0 : -1);
+}
+
+
+/*
+ * strequal: checks strings for equality
+ * entry: scan1 points to scan pointer, str points to string
+ * exit: return (1) if equal, return (0) if not
+ * *scan1 is advanced to next nonzero byte after null
+ */
+
+
+static int
+strequal(char **scan1, char *str)
+{
+ char c, *scan;
+ scan = *scan1;
+ while ((c = *scan++) == *str && c) str++;
+ *scan1 = scan;
+ if (c == 0 && *str == 0)
+ return (1);
+ if (c)
+ while (*scan++);
+ *scan1 = scan;
+ return (0);
+}
+
+
+/* strcopy: copy source to destination */
+
+
+static void
+strcopy(char *source, char *dest)
+{
+ while (*dest++ = *source++);
+}
+
+
+/* This is called before a buffer modifying command so that the */
+/* current array of line ptrs is saved in sav and dot and dol are saved */
+
+
+static void
+save(void) {
+ LINE i;
+ int j;
+
+ savdot = dot;
+ savdol = dol;
+ for (j = 0; j <= 25; j++)
+ savnames[j] = names[j];
+
+ for (i = zero + 1; i <= dol; i++)
+ i->sav = i->cur;
+ initflg = 0;
+}
+
+
+/* The undo command calls this to restore the previous ptr array sav */
+/* and swap with cur - dot and dol are swapped also. This allows user to */
+/* undo an undo */
+
+
+static void
+undo(void) {
+ int j;
+ long tmp;
+ LINE i, tmpdot, tmpdol;
+
+ tmpdot = dot; dot = savdot; savdot = tmpdot;
+ tmpdol = dol; dol = savdol; savdol = tmpdol;
+ /* swap arrays using the greater of dol or savdol as upper limit */
+ for (i = zero + 1; i <= ((dol > savdol) ? dol : savdol); i++) {
+ tmp = i->cur;
+ i->cur = i->sav;
+ i->sav = tmp;
+ }
+ /*
+ * If the current text lines are swapped with the
+ * text lines in the save buffer, then swap the current
+ * marks with those in the save area.
+ */
+
+ for (j = 0; j <= 25; j++) {
+ tmp = names[j];
+ names[j] = savnames[j];
+ savnames[j] = tmp;
+ }
+}
+
+static wchar_t
+get_wchr()
+{
+ wchar_t wc;
+ char multi[MB_LEN_MAX];
+
+ if (_mbftowc(multi, &wc, getchr, &peekc) <= 0)
+ wc = getchr();
+ return (wc);
+}
diff --git a/usr/src/cmd/ed/ed.xcl b/usr/src/cmd/ed/ed.xcl
new file mode 100644
index 0000000000..6da50f7107
--- /dev/null
+++ b/usr/src/cmd/ed/ed.xcl
@@ -0,0 +1,38 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+msgid "-"
+msgid "*"
+msgid "SHELL"
+msgid "/usr/bin/rsh"
+msgid ""
+msgid "HOME"
+msgid "sp:qxC"
+msgid "--"
+msgid "e"
+msgid "ea"
+msgid "ed.hup"
+msgid "/ed.hup"
+msgid "/usr/bin/sh"
+msgid "sh"
+msgid "-c"
+msgid "!"
+msgid "\n"
diff --git a/usr/src/cmd/ed/inc.flg b/usr/src/cmd/ed/inc.flg
new file mode 100644
index 0000000000..cecf1a77dc
--- /dev/null
+++ b/usr/src/cmd/ed/inc.flg
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+echo_file usr/src/cmd/expr/compile.c
+echo_file usr/src/lib/common/common/values-xpg4.c
+echo_file usr/src/lib/common/common/values-xpg6.c