diff options
| author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
|---|---|---|
| committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
| commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
| tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/ed | |
| download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz | |
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/ed')
| -rw-r--r-- | usr/src/cmd/ed/Makefile | 115 | ||||
| -rw-r--r-- | usr/src/cmd/ed/ed.c | 3170 | ||||
| -rw-r--r-- | usr/src/cmd/ed/ed.xcl | 38 | ||||
| -rw-r--r-- | usr/src/cmd/ed/inc.flg | 32 |
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 |
