meillo@0: /* meillo@0: * Editor meillo@0: */ meillo@0: meillo@0: /* meillo@0: * Changes by Gunnar Ritter, Freiburg i. Br., Germany, July 2003. meillo@0: */ meillo@0: /* from Unix 32V /usr/src/cmd/ed.c */ meillo@0: /* meillo@0: * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. meillo@0: * meillo@0: * Redistribution and use in source and binary forms, with or without meillo@0: * modification, are permitted provided that the following conditions meillo@0: * are met: meillo@0: * Redistributions of source code and documentation must retain the meillo@0: * above copyright notice, this list of conditions and the following meillo@0: * disclaimer. meillo@0: * Redistributions in binary form must reproduce the above copyright meillo@0: * notice, this list of conditions and the following disclaimer in the meillo@0: * documentation and/or other materials provided with the distribution. meillo@0: * All advertising materials mentioning features or use of this software meillo@0: * must display the following acknowledgement: meillo@0: * This product includes software developed or owned by Caldera meillo@0: * International, Inc. meillo@0: * Neither the name of Caldera International, Inc. nor the names of meillo@0: * other contributors may be used to endorse or promote products meillo@0: * derived from this software without specific prior written permission. meillo@0: * meillo@0: * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA meillo@0: * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR meillo@0: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED meillo@0: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE meillo@0: * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE meillo@0: * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR meillo@0: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF meillo@0: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR meillo@0: * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, meillo@0: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE meillo@0: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, meillo@0: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. meillo@0: */ meillo@0: meillo@0: #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4 meillo@0: #define USED __attribute__ ((used)) meillo@0: #elif defined __GNUC__ meillo@0: #define USED __attribute__ ((unused)) meillo@0: #else meillo@0: #define USED meillo@0: #endif meillo@0: #if defined (SU3) meillo@0: static const char sccsid[] USED = "@(#)ed_su3.sl 1.99 (gritter) 7/27/06"; meillo@0: #elif defined (SUS) meillo@0: static const char sccsid[] USED = "@(#)ed_sus.sl 1.99 (gritter) 7/27/06"; meillo@0: #elif defined (S42) meillo@0: static const char sccsid[] USED = "@(#)ed_s42.sl 1.99 (gritter) 7/27/06"; meillo@0: #else /* !SU3, !SUS, !S42 */ meillo@0: static const char sccsid[] USED = "@(#)ed.sl 1.99 (gritter) 7/27/06"; meillo@0: #endif /* !SU3, !SUS, !S42 */ meillo@0: meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include "sigset.h" meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: static int FNSIZE; meillo@0: static int LBSIZE; meillo@0: static int RHSIZE; meillo@0: #define ESIZE 2048 meillo@0: static int GBSIZE; meillo@0: #undef EOF meillo@0: #define EOF -1 meillo@0: #define puts(s) xxputs(s) meillo@0: #define getline(t, n) xxgetline(t, n) meillo@0: meillo@0: #if (LONG_MAX > 017777777777L) meillo@0: #define MAXCNT 0777777777777777777777L /* 2^63-1 */ meillo@0: #else meillo@0: #define MAXCNT 017777777777L /* 2^31-1 */ meillo@0: #endif meillo@0: #define BLKMSK (MAXCNT>>8) /* was 0377 */ meillo@0: meillo@0: #define READ 0 meillo@0: #define WRITE 1 meillo@0: #define EXIST 2 meillo@0: meillo@0: struct tabulator { meillo@0: struct tabulator *t_nxt; /* next list element */ meillo@0: const char *t_str; /* tabulator string */ meillo@0: int t_tab; /* tab stop position */ meillo@0: int t_rep; /* repetitive tab count */ meillo@0: }; meillo@0: meillo@0: static int peekc; meillo@0: static int lastc; meillo@0: static char *savedfile; meillo@0: static char *file; meillo@0: static struct stat fstbuf; meillo@0: static char *linebuf; meillo@0: static char *rhsbuf; meillo@0: static char expbuf[ESIZE + 4]; meillo@0: static long *zero; meillo@0: static long *undzero; meillo@0: static long *dot; meillo@0: static long *unddot; meillo@0: static long *dol; meillo@0: static long *unddol; meillo@0: static long *addr1; meillo@0: static long *addr2; meillo@0: static char *genbuf; meillo@0: static long count; meillo@0: static char *linebp; meillo@0: static int ninbuf; meillo@0: static int io; meillo@0: static int ioeof; meillo@0: static int pflag; meillo@0: static char *wrtemp; meillo@0: static uid_t myuid; meillo@0: static void (*oldhup)(int); meillo@0: static void (*oldquit)(int); meillo@0: static void (*oldpipe)(int); meillo@0: static int vflag = 1; meillo@0: static int listf; meillo@0: static int numbf; meillo@0: static char *globp; meillo@0: static int tfile = -1; meillo@0: static long tline; meillo@0: static char tfname[64]; meillo@0: static char ibuff[512]; meillo@0: static int iblock = -1; meillo@0: static char obuff[512]; meillo@0: static int oblock = -1; meillo@0: static int ichanged; meillo@0: static int nleft; meillo@0: static long *names; meillo@0: static long *undnames; meillo@0: static int anymarks; meillo@0: static int subnewa; meillo@0: static int fchange; meillo@0: static int wrapp; meillo@0: static unsigned nlall = 128; meillo@0: static const char *progname; meillo@0: static const char *prompt = "*"; meillo@0: static int Pflag; meillo@0: static int prhelp; meillo@0: static const char *prvmsg; meillo@0: static int lastsig; meillo@0: static int pipid = -1; meillo@0: static int readop; meillo@0: static int status; meillo@0: static int mb_cur_max; meillo@0: static int needsub; meillo@0: static int insub; meillo@0: static struct tabulator *tabstops; meillo@0: static int maxlength; meillo@0: static int rspec; meillo@0: static int Nflag; meillo@0: static int bcount = 22; meillo@0: static int ocount = 11; meillo@0: meillo@0: static jmp_buf savej; meillo@0: meillo@0: static void usage(char, int); meillo@0: static void commands(void); meillo@0: static long *address(void); meillo@0: static void setdot(void); meillo@0: static void setall(void); meillo@0: static void setnoaddr(void); meillo@0: static void nonzero(void); meillo@0: static void newline(void); meillo@0: static void filename(int); meillo@0: static void exfile(void); meillo@0: static void onintr(int); meillo@0: static void onhup(int); meillo@0: static void onpipe(int); meillo@0: static void error(const char *); meillo@0: static void error2(const char *, const char *); meillo@0: static void errput(const char *, const char *); meillo@0: static int getchr(void); meillo@0: static int gettty(void); meillo@0: static long getnum(void); meillo@0: static int getfile(void); meillo@0: static void putfile(void); meillo@0: static int append(int (*)(void), long *); meillo@0: static void callunix(void); meillo@0: static char *readcmd(void); meillo@0: static void quit(int); meillo@0: static void delete(void); meillo@0: static void rdelete(long *, long *); meillo@0: static void gdelete(void); meillo@0: static char *getline(long, int); meillo@0: static int putline(void); meillo@0: static char *getblock(long, long); meillo@0: static void blkio(long, char *, int); meillo@0: static void init(void); meillo@0: static void global(int, int); meillo@0: static void globrd(char **, int); meillo@0: static void join(void); meillo@0: static void substitute(int); meillo@0: static int compsub(void); meillo@0: static int getsub(void); meillo@0: static int dosub(int); meillo@0: static int place(int, const char *, const char *); meillo@0: static void move(int); meillo@0: static void reverse(long *, long *); meillo@0: static int getcopy(void); meillo@0: static int execute(int, long *, int); meillo@0: static void cmplerr(int); meillo@0: static void doprnt(long *, long *); meillo@0: static void putd(long); meillo@0: static void puts(const char *); meillo@0: static void nlputs(const char *); meillo@0: static void list(const char *); meillo@0: static int lstchr(int); meillo@0: static void putstr(const char *); meillo@0: static void putchr(int); meillo@0: static void checkpoint(void); meillo@0: static void undo(void); meillo@0: static int maketf(int); meillo@0: static int creatf(const char *); meillo@0: static int sopen(const char *, int); meillo@0: static void sclose(int); meillo@0: static void fspec(const char *); meillo@0: static const char *ftok(const char **); meillo@0: static struct tabulator *tabstring(const char *); meillo@0: static void freetabs(void); meillo@0: static void expand(const char *); meillo@0: static void growlb(const char *); meillo@0: static void growrhs(const char *); meillo@0: static void growfn(const char *); meillo@0: static void help(void); meillo@0: meillo@0: #define INIT meillo@0: #define GETC() getchr() meillo@0: #define UNGETC(c) (peekc = c) meillo@0: #define PEEKC() (peekc = getchr()) meillo@0: #define RETURN(c) return c meillo@0: #define ERROR(c) cmplerr(c) meillo@0: static wint_t GETWC(char *); meillo@0: meillo@0: #if defined (SUS) || defined (S42) || defined (SU3) meillo@0: meillo@0: #include meillo@0: meillo@0: #define NBRA 9 meillo@0: meillo@0: static char *braslist[NBRA]; meillo@0: static char *braelist[NBRA]; meillo@0: static char *loc1, *loc2, *locs; meillo@0: static int nbra; meillo@0: static int circf; meillo@0: static int nodelim; meillo@0: meillo@0: static char *compile(char *, char *, const char *, int); meillo@0: static int step(const char *, const char *); meillo@0: meillo@0: #else /* !SUS, !S42, !SU3 */ meillo@0: meillo@0: #include meillo@0: meillo@0: #endif /* !SUS, !S42, !SU3 */ meillo@0: meillo@0: int meillo@0: main(int argc, char **argv) meillo@0: { meillo@0: register int i; meillo@0: void (*oldintr)(int); meillo@0: meillo@0: progname = basename(argv[0]); meillo@0: #if defined (SUS) || defined (S42) || defined (SU3) meillo@0: setlocale(LC_COLLATE, ""); meillo@0: #endif meillo@0: setlocale(LC_CTYPE, ""); meillo@0: mb_cur_max = MB_CUR_MAX; meillo@0: myuid = getuid(); meillo@0: oldquit = sigset(SIGQUIT, SIG_IGN); meillo@0: oldhup = sigset(SIGHUP, SIG_IGN); meillo@0: oldintr = sigset(SIGINT, SIG_IGN); meillo@0: if (sigset(SIGTERM, SIG_IGN) != SIG_IGN) meillo@0: sigset(SIGTERM, quit); meillo@0: oldpipe = sigset(SIGPIPE, onpipe); meillo@0: argv++; meillo@0: while (argc > 1 && **argv=='-') { meillo@0: if ((*argv)[1] == '\0') { meillo@0: vflag = 0; meillo@0: goto next; meillo@0: } else if ((*argv)[1] == '-' && (*argv)[2] == '\0') { meillo@0: argv++; meillo@0: argc--; meillo@0: break; meillo@0: } meillo@0: letter: switch((*argv)[1]) { meillo@0: meillo@0: case 's': meillo@0: vflag = 0; meillo@0: break; meillo@0: meillo@0: case 'q': meillo@0: sigset(SIGQUIT, SIG_DFL); meillo@0: vflag = 1; meillo@0: break; meillo@0: meillo@0: case 'p': meillo@0: if ((*argv)[2]) meillo@0: prompt = &(*argv)[2]; meillo@0: else if (argv[1]) { meillo@0: prompt = argv[1]; meillo@0: argv++; meillo@0: argc--; meillo@0: } else meillo@0: usage((*argv)[1], 1); meillo@0: Pflag = 1; meillo@0: goto next; meillo@0: meillo@0: default: meillo@0: usage((*argv)[1], 0); meillo@0: } meillo@0: if ((*argv)[2]) { meillo@0: (*argv)++; meillo@0: goto letter; meillo@0: } meillo@0: next: argv++; meillo@0: argc--; meillo@0: } meillo@0: meillo@0: growfn("no space"); meillo@0: if (argc>1) { meillo@0: i = -1; meillo@0: do meillo@0: if (++i >= FNSIZE) meillo@0: growfn("maximum of characters in " meillo@0: "file names reached"); meillo@0: while (savedfile[i] = (*argv)[i]); meillo@0: globp = "e"; meillo@0: } meillo@0: names = malloc(26*sizeof *names); meillo@0: undnames = malloc(26*sizeof *undnames); meillo@0: zero = malloc(nlall*sizeof *zero); meillo@0: if ((undzero = malloc(nlall*sizeof *undzero)) == NULL) meillo@0: puts("no memory for undo"); meillo@0: growlb("no space"); meillo@0: growrhs("no space"); meillo@0: init(); meillo@0: if (oldintr != SIG_IGN) meillo@0: sigset(SIGINT, onintr); meillo@0: if (oldhup != SIG_IGN) meillo@0: sigset(SIGHUP, onhup); meillo@0: setjmp(savej); meillo@0: if (lastsig) { meillo@0: sigrelse(lastsig); meillo@0: lastsig = 0; meillo@0: } meillo@0: commands(); meillo@0: quit(0); meillo@0: /*NOTREACHED*/ meillo@0: return 0; meillo@0: } meillo@0: meillo@0: static void meillo@0: usage(char c, int misarg) meillo@0: { meillo@0: if (c) { meillo@0: write(2, progname, strlen(progname)); meillo@0: if (misarg) meillo@0: write(2, ": option requires an argument -- ", 33); meillo@0: else meillo@0: write(2, ": illegal option -- ", 20); meillo@0: write(2, &c, 1); meillo@0: write(2, "\n", 1); meillo@0: } meillo@0: write(2, "usage: ", 7); meillo@0: write(2, progname, strlen(progname)); meillo@0: write(2, " [- | -s] [-p string] [file]\n", 29); meillo@0: exit(2); meillo@0: } meillo@0: meillo@0: static void meillo@0: commands(void) meillo@0: { meillo@0: register long *a1; meillo@0: register int c; meillo@0: int n; meillo@0: meillo@0: for (;;) { meillo@0: if (pflag) { meillo@0: pflag = 0; meillo@0: addr1 = addr2 = dot; meillo@0: goto print; meillo@0: } meillo@0: if (Pflag && globp == NULL) meillo@0: write(1, prompt, strlen(prompt)); meillo@0: addr1 = 0; meillo@0: addr2 = 0; meillo@0: switch (c = getchr()) { meillo@0: case ',': meillo@0: case ';': meillo@0: addr2 = c == ',' ? zero+1 : dot; meillo@0: if (((peekc = getchr()) < '0' || peekc > '9') && meillo@0: peekc != ' ' && peekc != '\t' && meillo@0: peekc != '+' && peekc != '-' && meillo@0: peekc != '^' && peekc != '?' && meillo@0: peekc != '/' && peekc != '$' && meillo@0: peekc != '.' && peekc != '\'') { meillo@0: addr1 = addr2; meillo@0: a1 = dol; meillo@0: goto loop; meillo@0: } meillo@0: break; meillo@0: default: meillo@0: peekc = c; meillo@0: } meillo@0: do { meillo@0: addr1 = addr2; meillo@0: if ((a1 = address())==0) { meillo@0: c = getchr(); meillo@0: break; meillo@0: } meillo@0: loop: addr2 = a1; meillo@0: if ((c=getchr()) == ';') { meillo@0: c = ','; meillo@0: dot = a1; meillo@0: } meillo@0: } while (c==','); meillo@0: if (addr1==0) meillo@0: addr1 = addr2; meillo@0: switch(c) { meillo@0: meillo@0: case 'a': meillo@0: setdot(); meillo@0: newline(); meillo@0: checkpoint(); meillo@0: append(gettty, addr2); meillo@0: continue; meillo@0: meillo@0: case 'c': meillo@0: #if defined (SU3) meillo@0: if (addr1 == zero && addr1+1 <= dol) { meillo@0: if (addr1 == addr2) meillo@0: addr2++; meillo@0: addr1++; meillo@0: } meillo@0: #endif /* SU3 */ meillo@0: delete(); meillo@0: append(gettty, addr1-1); meillo@0: #if defined (SUS) || defined (SU3) meillo@0: if (dot == addr1-1 && addr1 <= dol) meillo@0: dot = addr1; meillo@0: #endif /* SUS || SU3 */ meillo@0: continue; meillo@0: meillo@0: case 'd': meillo@0: delete(); meillo@0: continue; meillo@0: meillo@0: case 'E': meillo@0: fchange = 0; meillo@0: c = 'e'; meillo@0: case 'e': meillo@0: setnoaddr(); meillo@0: if (vflag && fchange) { meillo@0: fchange = 0; meillo@0: error("warning: expecting `w'"); meillo@0: } meillo@0: filename(c); meillo@0: init(); meillo@0: addr2 = zero; meillo@0: goto caseread; meillo@0: meillo@0: case 'f': meillo@0: setnoaddr(); meillo@0: filename(c); meillo@0: puts(savedfile); meillo@0: continue; meillo@0: meillo@0: case 'g': meillo@0: global(1, 0); meillo@0: continue; meillo@0: meillo@0: case 'G': meillo@0: global(1, 1); meillo@0: continue; meillo@0: meillo@0: case 'H': meillo@0: prhelp = !prhelp; meillo@0: /*FALLTHRU*/ meillo@0: meillo@0: case 'h': meillo@0: if ((peekc = getchr()) == 'e') { meillo@0: peekc = 0; meillo@0: if (getchr() != 'l' || getchr() != 'p' || meillo@0: getchr() != '\n') meillo@0: error("illegal suffix"); meillo@0: setnoaddr(); meillo@0: help(); meillo@0: continue; meillo@0: } meillo@0: newline(); meillo@0: setnoaddr(); meillo@0: if (prvmsg) meillo@0: puts(prvmsg); meillo@0: continue; meillo@0: meillo@0: case 'i': meillo@0: setdot(); meillo@0: #if defined (SU3) meillo@0: if (addr1 == zero) { meillo@0: if (addr1 == addr2) meillo@0: addr2++; meillo@0: addr1++; meillo@0: if (dol != zero) meillo@0: nonzero(); meillo@0: } else meillo@0: #endif /* SU3 */ meillo@0: nonzero(); meillo@0: newline(); meillo@0: checkpoint(); meillo@0: append(gettty, addr2-1); meillo@0: if (dot == addr2-1) meillo@0: dot++; meillo@0: continue; meillo@0: meillo@0: meillo@0: case 'j': meillo@0: if (addr2==0) { meillo@0: addr1 = dot; meillo@0: addr2 = dot+1; meillo@0: } meillo@0: setdot(); meillo@0: newline(); meillo@0: nonzero(); meillo@0: checkpoint(); meillo@0: if (addr1 != addr2) meillo@0: join(); meillo@0: continue; meillo@0: meillo@0: case 'k': meillo@0: if ((c = getchr()) < 'a' || c > 'z') meillo@0: error("mark not lower case"); meillo@0: newline(); meillo@0: setdot(); meillo@0: nonzero(); meillo@0: names[c-'a'] = *addr2 & ~01; meillo@0: anymarks |= 01; meillo@0: continue; meillo@0: meillo@0: case 'm': meillo@0: move(0); meillo@0: continue; meillo@0: meillo@0: case '\n': meillo@0: if (addr2==0) meillo@0: addr2 = dot+1; meillo@0: addr1 = addr2; meillo@0: goto print; meillo@0: meillo@0: case 'n': meillo@0: numbf = 1; meillo@0: newline(); meillo@0: goto print; meillo@0: meillo@0: case 'N': meillo@0: newline(); meillo@0: setnoaddr(); meillo@0: Nflag = !Nflag; meillo@0: continue; meillo@0: meillo@0: case 'b': meillo@0: case 'o': meillo@0: n = getnum(); meillo@0: newline(); meillo@0: setdot(); meillo@0: nonzero(); meillo@0: if (n >= 0) { meillo@0: if (c == 'b') meillo@0: bcount = n; meillo@0: else meillo@0: ocount = n; meillo@0: } meillo@0: if (c == 'b') { meillo@0: a1 = addr2+bcount > dol ? dol : addr2 + bcount; meillo@0: doprnt(addr1, a1); meillo@0: dot = a1; meillo@0: } else { meillo@0: a1 = addr2+ocount > dol ? dol : addr2 + ocount; meillo@0: doprnt(addr2-ocount wrtemp && tp[-1] != '/') meillo@0: tp--; meillo@0: for (cp = "\7XXXXXX"; *cp; cp++) meillo@0: *tp++ = *cp; meillo@0: *tp = '\0'; meillo@0: if ((nio = mkstemp(wrtemp)) < 0) { meillo@0: free(wrtemp); meillo@0: wrtemp = NULL; meillo@0: ftruncate(io, 0); meillo@0: } else { meillo@0: close(io); meillo@0: io = nio; meillo@0: } meillo@0: } else { meillo@0: if ((io = sopen(file, WRITE)) < 0) meillo@0: error("cannot create output file"); meillo@0: } meillo@0: } meillo@0: if (zero != dol) { meillo@0: ioeof = 0; meillo@0: wrapp = 0; meillo@0: putfile(); meillo@0: } meillo@0: exfile(); meillo@0: if (addr1==zero+1 && addr2==dol || addr1==addr2 && dol==zero) meillo@0: fchange = 0; meillo@0: if (c == 'z') meillo@0: quit(0); meillo@0: continue; meillo@0: meillo@0: case 'z': meillo@0: if ((peekc=getchr()) != '\n') meillo@0: error("illegal suffix"); meillo@0: setnoaddr(); meillo@0: goto write; meillo@0: meillo@0: case '=': meillo@0: setall(); meillo@0: newline(); meillo@0: putd((addr2-zero)&MAXCNT); meillo@0: putchr('\n'); meillo@0: continue; meillo@0: meillo@0: case '!': meillo@0: callunix(); meillo@0: continue; meillo@0: meillo@0: case EOF: meillo@0: return; meillo@0: meillo@0: } meillo@0: error("unknown command"); meillo@0: } meillo@0: } meillo@0: meillo@0: static long * meillo@0: address(void) meillo@0: { meillo@0: register long *a1; meillo@0: register int minus, c; meillo@0: int n, relerr; meillo@0: meillo@0: minus = 0; meillo@0: a1 = 0; meillo@0: for (;;) { meillo@0: c = getchr(); meillo@0: if ('0'<=c && c<='9') { meillo@0: n = 0; meillo@0: do { meillo@0: n *= 10; meillo@0: n += c - '0'; meillo@0: } while ((c = getchr())>='0' && c<='9'); meillo@0: peekc = c; meillo@0: if (a1==0) meillo@0: a1 = zero; meillo@0: if (minus<0) meillo@0: n = -n; meillo@0: a1 += n; meillo@0: minus = 0; meillo@0: continue; meillo@0: } meillo@0: relerr = 0; meillo@0: if (a1 || minus) meillo@0: relerr++; meillo@0: switch(c) { meillo@0: case ' ': meillo@0: case '\t': meillo@0: continue; meillo@0: meillo@0: case '+': meillo@0: minus++; meillo@0: if (a1==0) meillo@0: a1 = dot; meillo@0: continue; meillo@0: meillo@0: case '-': meillo@0: case '^': meillo@0: minus--; meillo@0: if (a1==0) meillo@0: a1 = dot; meillo@0: continue; meillo@0: meillo@0: case '?': meillo@0: case '/': meillo@0: compile(NULL, expbuf, &expbuf[ESIZE], c); meillo@0: a1 = dot; meillo@0: for (;;) { meillo@0: if (c=='/') { meillo@0: a1++; meillo@0: if (a1 > dol) meillo@0: a1 = zero; meillo@0: } else { meillo@0: a1--; meillo@0: if (a1 < zero) meillo@0: a1 = dol; meillo@0: } meillo@0: if (execute(0, a1, 0)) meillo@0: break; meillo@0: if (a1==dot) meillo@0: error("search string not found"); meillo@0: } meillo@0: break; meillo@0: meillo@0: case '$': meillo@0: a1 = dol; meillo@0: break; meillo@0: meillo@0: case '.': meillo@0: a1 = dot; meillo@0: break; meillo@0: meillo@0: case '\'': meillo@0: if ((c = getchr()) < 'a' || c > 'z') meillo@0: error("mark not lower case"); meillo@0: for (a1=zero; a1<=dol; a1++) meillo@0: if (names[c-'a'] == (*a1 & ~01)) meillo@0: break; meillo@0: break; meillo@0: meillo@0: default: meillo@0: peekc = c; meillo@0: if (a1==0) meillo@0: return(0); meillo@0: a1 += minus; meillo@0: if (a1dol) meillo@0: error("line out of range"); meillo@0: return(a1); meillo@0: } meillo@0: if (relerr) meillo@0: error("bad number"); meillo@0: } meillo@0: } meillo@0: meillo@0: static void meillo@0: setdot(void) meillo@0: { meillo@0: if (addr2 == 0) meillo@0: addr1 = addr2 = dot; meillo@0: if (addr1 > addr2) meillo@0: error("bad range"); meillo@0: } meillo@0: meillo@0: static void meillo@0: setall(void) meillo@0: { meillo@0: if (addr2==0) { meillo@0: addr1 = zero+1; meillo@0: addr2 = dol; meillo@0: if (dol==zero) meillo@0: addr1 = zero; meillo@0: } meillo@0: setdot(); meillo@0: } meillo@0: meillo@0: static void meillo@0: setnoaddr(void) meillo@0: { meillo@0: if (addr2) meillo@0: error("Illegal address count"); meillo@0: } meillo@0: meillo@0: static void meillo@0: nonzero(void) meillo@0: { meillo@0: if (addr1<=zero || addr2>dol) meillo@0: error("line out of range"); meillo@0: } meillo@0: meillo@0: static void meillo@0: newline(void) meillo@0: { meillo@0: register int c; meillo@0: meillo@0: if ((c = getchr()) == '\n') meillo@0: return; meillo@0: if (c=='p' || c=='l' || c=='n') { meillo@0: pflag++; meillo@0: if (c=='l') meillo@0: listf++; meillo@0: else if (c=='n') meillo@0: numbf = 1; meillo@0: if (getchr() == '\n') meillo@0: return; meillo@0: } meillo@0: error("illegal suffix"); meillo@0: } meillo@0: meillo@0: static void meillo@0: filename(int comm) meillo@0: { meillo@0: register char *p1, *p2; meillo@0: register int c, i; meillo@0: meillo@0: count = 0; meillo@0: c = getchr(); meillo@0: if (c=='\n' || c==EOF) { meillo@0: p1 = savedfile; meillo@0: if (*p1==0 && comm!='f') meillo@0: error("illegal or missing filename"); meillo@0: p2 = file; meillo@0: while (*p2++ = *p1++) meillo@0: ; meillo@0: return; meillo@0: } meillo@0: if (c!=' ') meillo@0: error("no space after command"); meillo@0: while ((c = getchr()) == ' ') meillo@0: ; meillo@0: if (c=='\n') meillo@0: error("illegal or missing filename"); meillo@0: i = 0; meillo@0: do { meillo@0: if (i >= FNSIZE) meillo@0: growfn("maximum of characters in file names reached"); meillo@0: file[i++] = c; meillo@0: if (c==' ' && file[0] != '!' || c==EOF) meillo@0: error("illegal or missing filename"); meillo@0: } while ((c = getchr()) != '\n'); meillo@0: file[i++] = 0; meillo@0: if ((savedfile[0]==0 || comm=='e' || comm=='f') && file[0] != '!') { meillo@0: p1 = savedfile; meillo@0: p2 = file; meillo@0: while (*p1++ = *p2++) meillo@0: ; meillo@0: } meillo@0: } meillo@0: meillo@0: static void meillo@0: exfile(void) meillo@0: { meillo@0: sclose(io); meillo@0: io = -1; meillo@0: if (wrtemp) { meillo@0: extern int rename(const char *, const char *); meillo@0: if (rename(wrtemp, file) < 0) meillo@0: error("cannot create output file"); meillo@0: if (myuid == 0) meillo@0: chown(file, fstbuf.st_uid, fstbuf.st_gid); meillo@0: chmod(file, fstbuf.st_mode & 07777); meillo@0: free(wrtemp); meillo@0: wrtemp = NULL; meillo@0: } meillo@0: if (vflag) { meillo@0: putd(count); meillo@0: putchr('\n'); meillo@0: } meillo@0: } meillo@0: meillo@0: static void meillo@0: onintr(int signo) meillo@0: { meillo@0: lastsig = signo; meillo@0: putchr('\n'); meillo@0: lastc = '\n'; meillo@0: if (readop) { meillo@0: puts("\007read may be incomplete - beware!\007"); meillo@0: fchange = 0; meillo@0: } meillo@0: error("interrupt"); meillo@0: } meillo@0: meillo@0: static void meillo@0: onhup(int signo) meillo@0: { meillo@0: if (dol > zero && fchange) { meillo@0: addr1 = zero+1; meillo@0: addr2 = dol; meillo@0: io = creat("ed.hup", 0666); meillo@0: if (io < 0) { meillo@0: char *home = getenv("HOME"); meillo@0: if (home) { meillo@0: char *fn = malloc(strlen(home) + 10); meillo@0: if (fn) { meillo@0: strcpy(fn, home); meillo@0: strcat(fn, "/ed.hup"); meillo@0: io = creat(fn, 0666); meillo@0: } meillo@0: } meillo@0: } meillo@0: if (io >= 0) meillo@0: putfile(); meillo@0: } meillo@0: fchange = 0; meillo@0: status = 0200 | signo; meillo@0: quit(0); meillo@0: } meillo@0: meillo@0: static void meillo@0: onpipe(int signo) meillo@0: { meillo@0: lastsig = signo; meillo@0: error("write or open on pipe failed"); meillo@0: } meillo@0: meillo@0: static void meillo@0: error(const char *s) meillo@0: { meillo@0: error2(s, NULL); meillo@0: } meillo@0: meillo@0: static void meillo@0: error2(const char *s, const char *fn) meillo@0: { meillo@0: register int c; meillo@0: meillo@0: wrapp = 0; meillo@0: listf = 0; meillo@0: numbf = 0; meillo@0: errput(s, fn); meillo@0: count = 0; meillo@0: if (lseek(0, 0, SEEK_END) > 0) meillo@0: status = 2; meillo@0: pflag = 0; meillo@0: if (globp) meillo@0: lastc = '\n'; meillo@0: globp = 0; meillo@0: peekc = lastc; meillo@0: if(lastc) meillo@0: while ((c = getchr()) != '\n' && c != EOF) meillo@0: ; meillo@0: if (io > 0) { meillo@0: sclose(io); meillo@0: io = -1; meillo@0: } meillo@0: if (wrtemp) { meillo@0: unlink(wrtemp); meillo@0: free(wrtemp); meillo@0: wrtemp = NULL; meillo@0: } meillo@0: longjmp(savej, 1); meillo@0: } meillo@0: meillo@0: static void meillo@0: errput(const char *s, const char *fn) meillo@0: { meillo@0: prvmsg = s; meillo@0: if (fn) { meillo@0: putchr('?'); meillo@0: puts(fn); meillo@0: } else meillo@0: puts("?"); meillo@0: if (prhelp) meillo@0: puts(s); meillo@0: } meillo@0: meillo@0: static int meillo@0: getchr(void) meillo@0: { meillo@0: char c; meillo@0: if (lastc=peekc) { meillo@0: peekc = 0; meillo@0: return(lastc); meillo@0: } meillo@0: if (globp) { meillo@0: if ((lastc = *globp++) != 0) meillo@0: return(lastc); meillo@0: globp = 0; meillo@0: return(EOF); meillo@0: } meillo@0: if (read(0, &c, 1) <= 0) meillo@0: return(lastc = EOF); meillo@0: lastc = c; meillo@0: return(lastc); meillo@0: } meillo@0: meillo@0: static int meillo@0: gettty(void) meillo@0: { meillo@0: register int c, i; meillo@0: register char *gf; meillo@0: meillo@0: i = 0; meillo@0: gf = globp; meillo@0: while ((c = getchr()) != '\n') { meillo@0: if (c==EOF) { meillo@0: if (gf) meillo@0: peekc = c; meillo@0: return(c); meillo@0: } meillo@0: if (c == 0) meillo@0: continue; meillo@0: if (i >= LBSIZE) meillo@0: growlb("line too long"); meillo@0: linebuf[i++] = c; meillo@0: } meillo@0: if (i >= LBSIZE-2) meillo@0: growlb("line too long"); meillo@0: linebuf[i++] = 0; meillo@0: if (linebuf[0]=='.' && linebuf[1]==0) meillo@0: return(EOF); meillo@0: #if !defined (SUS) && !defined (SU3) meillo@0: if (linebuf[0]=='\\' && linebuf[1]=='.' && linebuf[2]==0) meillo@0: linebuf[0]='.', linebuf[1]=0; meillo@0: #endif meillo@0: return(0); meillo@0: } meillo@0: meillo@0: static long meillo@0: getnum(void) meillo@0: { meillo@0: char scount[20]; meillo@0: int i; meillo@0: meillo@0: i = 0; meillo@0: while ((peekc=getchr()) >= '0' && peekc <= '9' && i < sizeof scount) { meillo@0: scount[i++] = peekc; meillo@0: peekc = 0; meillo@0: } meillo@0: scount[i] = '\0'; meillo@0: return i ? atol(scount) : -1; meillo@0: } meillo@0: meillo@0: static int meillo@0: getfile(void) meillo@0: { meillo@0: register int c, i, j; meillo@0: static int nextj; meillo@0: meillo@0: i = 0; meillo@0: j = nextj; meillo@0: do { meillo@0: if (--ninbuf < 0) { meillo@0: if (ioeof || (ninbuf=read(io, genbuf, LBSIZE)-1) < 0) { meillo@0: if (ioeof == 0 && ninbuf < -1) { meillo@0: puts("input error"); meillo@0: status = 1; meillo@0: } meillo@0: if (i > 0) { meillo@0: puts("'\\n' appended"); meillo@0: c = '\n'; meillo@0: ioeof = 1; meillo@0: goto wrc; meillo@0: } meillo@0: return(EOF); meillo@0: } meillo@0: j = 0; meillo@0: } meillo@0: c = genbuf[j++]&0377; meillo@0: wrc: if (i >= LBSIZE) { meillo@0: lastc = '\n'; meillo@0: growlb("line too long"); meillo@0: } meillo@0: linebuf[i++] = c ? c : '\n'; meillo@0: count++; meillo@0: } while (c != '\n'); meillo@0: linebuf[--i] = 0; meillo@0: nextj = j; meillo@0: if (rspec && dot == zero) meillo@0: fspec(linebuf); meillo@0: if (maxlength && i > maxlength) { meillo@0: putstr("line too long: lno = "); meillo@0: putd((dot - zero+1)&MAXCNT); meillo@0: putchr('\n'); meillo@0: } meillo@0: return(0); meillo@0: } meillo@0: meillo@0: static void meillo@0: putfile(void) meillo@0: { meillo@0: long *a1; meillo@0: int n; meillo@0: register char *fp, *lp; meillo@0: register int nib; meillo@0: meillo@0: nib = 512; meillo@0: fp = genbuf; meillo@0: a1 = addr1; meillo@0: do { meillo@0: lp = getline(*a1++, 0); meillo@0: if (maxlength) { meillo@0: for (n = 0; lp[n]; n++); meillo@0: if (n > maxlength) { meillo@0: putstr("line too long: lno = "); meillo@0: putd((a1-1 - zero)&MAXCNT); meillo@0: putchr('\n'); meillo@0: } meillo@0: } meillo@0: for (;;) { meillo@0: if (--nib < 0) { meillo@0: n = fp-genbuf; meillo@0: if(write(io, genbuf, n) != n) meillo@0: error("write error"); meillo@0: nib = 511; meillo@0: fp = genbuf; meillo@0: } meillo@0: count++; meillo@0: if ((*fp++ = *lp++) == 0) { meillo@0: fp[-1] = '\n'; meillo@0: break; meillo@0: } else if (fp[-1] == '\n') meillo@0: fp[-1] = '\0'; meillo@0: } meillo@0: } while (a1 <= addr2); meillo@0: n = fp-genbuf; meillo@0: if(write(io, genbuf, n) != n) meillo@0: error("write error"); meillo@0: } meillo@0: meillo@0: static int meillo@0: append(int (*f)(void), long *a) meillo@0: { meillo@0: register long *a1, *a2, *rdot; meillo@0: int nline, tl; meillo@0: meillo@0: nline = 0; meillo@0: dot = a; meillo@0: while ((*f)() == 0) { meillo@0: if ((dol-zero)+1 >= nlall) { meillo@0: long *ozero = zero; meillo@0: nlall += 512; meillo@0: if ((zero = realloc(zero, nlall*sizeof *zero))==NULL) { meillo@0: lastc = '\n'; meillo@0: zero = ozero; meillo@0: error("out of memory for append"); meillo@0: } meillo@0: dot += zero - ozero; meillo@0: dol += zero - ozero; meillo@0: addr1 += zero - ozero; meillo@0: addr2 += zero - ozero; meillo@0: if (unddot) { meillo@0: unddot += zero - ozero; meillo@0: unddol += zero - ozero; meillo@0: } meillo@0: if (undzero) { meillo@0: ozero = undzero; meillo@0: if ((undzero = realloc(undzero, meillo@0: nlall*sizeof *undzero)) == 0) { meillo@0: puts("no memory for undo"); meillo@0: free(ozero); meillo@0: } meillo@0: } meillo@0: } meillo@0: tl = putline(); meillo@0: nline++; meillo@0: a1 = ++dol; meillo@0: a2 = a1+1; meillo@0: rdot = ++dot; meillo@0: while (a1 > rdot) meillo@0: *--a2 = *--a1; meillo@0: *rdot = tl; meillo@0: } meillo@0: return(nline); meillo@0: } meillo@0: meillo@0: static void meillo@0: callunix(void) meillo@0: { meillo@0: char *line; meillo@0: void (*savint)(int); meillo@0: pid_t pid, rpid; meillo@0: int retcode; meillo@0: meillo@0: setnoaddr(); meillo@0: line = readcmd(); meillo@0: if ((pid = fork()) == 0) { meillo@0: sigset(SIGHUP, oldhup); meillo@0: sigset(SIGQUIT, oldquit); meillo@0: sigset(SIGPIPE, oldpipe); meillo@0: execl(SHELL, "sh", "-c", line, NULL); meillo@0: _exit(0100); meillo@0: } else if (pid < 0) meillo@0: error("fork failed - try again"); meillo@0: savint = sigset(SIGINT, SIG_IGN); meillo@0: while ((rpid = wait(&retcode)) != pid && rpid != -1) meillo@0: ; meillo@0: sigset(SIGINT, savint); meillo@0: if (vflag) meillo@0: puts("!"); meillo@0: } meillo@0: meillo@0: #define cmadd(c) ((i>=cmsize ? \ meillo@0: ((line=realloc(line,cmsize+=128)) == 0 ? \ meillo@0: (error("line too long"),0) : 0, 0) \ meillo@0: : 0), line[i++]=(c)) meillo@0: meillo@0: static char * meillo@0: readcmd(void) meillo@0: { meillo@0: static char *line, *prev; meillo@0: static int cmsize, pvsize; meillo@0: char *pp; meillo@0: int c, mod = 0, i; meillo@0: meillo@0: i = 0; meillo@0: if ((c = getchr()) == '!') { meillo@0: for (pp = prev; *pp; pp++) meillo@0: line[i++] = *pp; meillo@0: mod = 1; meillo@0: c = getchr(); meillo@0: } meillo@0: while (c != '\n' && c != EOF) { meillo@0: if (c == '\\') { meillo@0: c = getchr(); meillo@0: if (c != '%') meillo@0: cmadd('\\'); meillo@0: cmadd(c); meillo@0: } else if (c == '%') { meillo@0: for (pp = savedfile; *pp; pp++) meillo@0: cmadd(*pp); meillo@0: mod = 1; meillo@0: } else meillo@0: cmadd(c); meillo@0: c = getchr(); meillo@0: } meillo@0: cmadd('\0'); meillo@0: if (pvsize < cmsize && (prev = realloc(prev, pvsize=cmsize)) == 0) meillo@0: error("line too long"); meillo@0: strcpy(prev, line); meillo@0: if (mod) meillo@0: nlputs(line); meillo@0: return line; meillo@0: } meillo@0: meillo@0: static void meillo@0: quit(int signo) meillo@0: { meillo@0: lastsig = signo; meillo@0: if (vflag && fchange) { meillo@0: fchange = 0; meillo@0: error("warning: expecting `w'"); meillo@0: } meillo@0: if (wrtemp) meillo@0: unlink(wrtemp); meillo@0: unlink(tfname); meillo@0: exit(status); meillo@0: } meillo@0: meillo@0: static void meillo@0: delete(void) meillo@0: { meillo@0: setdot(); meillo@0: newline(); meillo@0: nonzero(); meillo@0: checkpoint(); meillo@0: rdelete(addr1, addr2); meillo@0: } meillo@0: meillo@0: static void meillo@0: rdelete(long *ad1, long *ad2) meillo@0: { meillo@0: register long *a1, *a2, *a3; meillo@0: meillo@0: a1 = ad1; meillo@0: a2 = ad2+1; meillo@0: a3 = dol; meillo@0: dol -= a2 - a1; meillo@0: do { meillo@0: *a1++ = *a2++; meillo@0: } while (a2 <= a3); meillo@0: a1 = ad1; meillo@0: if (a1 > dol) meillo@0: a1 = dol; meillo@0: dot = a1; meillo@0: fchange = 1; meillo@0: } meillo@0: meillo@0: static void meillo@0: gdelete(void) meillo@0: { meillo@0: register long *a1, *a2, *a3; meillo@0: meillo@0: a3 = dol; meillo@0: for (a1=zero+1; (*a1&01)==0; a1++) meillo@0: if (a1>=a3) meillo@0: return; meillo@0: for (a2=a1+1; a2<=a3;) { meillo@0: if (*a2&01) { meillo@0: a2++; meillo@0: dot = a1; meillo@0: } else meillo@0: *a1++ = *a2++; meillo@0: } meillo@0: dol = a1-1; meillo@0: if (dot>dol) meillo@0: dot = dol; meillo@0: fchange = 1; meillo@0: } meillo@0: meillo@0: static char * meillo@0: getline(long tl, int nulterm) meillo@0: { meillo@0: register char *bp, *lp; meillo@0: register long nl; meillo@0: meillo@0: lp = linebuf; meillo@0: bp = getblock(tl, READ); meillo@0: nl = nleft; meillo@0: tl &= ~0377; meillo@0: while (*lp++ = *bp++) { meillo@0: if (lp[-1] == '\n' && nulterm) { meillo@0: lp[-1] = '\0'; meillo@0: break; meillo@0: } meillo@0: if (--nl == 0) { meillo@0: bp = getblock(tl+=0400, READ); meillo@0: nl = nleft; meillo@0: } meillo@0: } meillo@0: return(linebuf); meillo@0: } meillo@0: meillo@0: static int meillo@0: putline(void) meillo@0: { meillo@0: register char *bp, *lp; meillo@0: register long nl; meillo@0: long tl; meillo@0: meillo@0: fchange = 1; meillo@0: lp = linebuf; meillo@0: tl = tline; meillo@0: bp = getblock(tl, WRITE); meillo@0: nl = nleft; meillo@0: tl &= ~0377; meillo@0: while (*bp = *lp++) { meillo@0: if (*bp++ == '\n' && insub) { meillo@0: *--bp = 0; meillo@0: linebp = lp; meillo@0: break; meillo@0: } meillo@0: if (--nl == 0) { meillo@0: bp = getblock(tl+=0400, WRITE); meillo@0: nl = nleft; meillo@0: } meillo@0: } meillo@0: nl = tline; meillo@0: tline += (((lp-linebuf)+03)>>1)&(MAXCNT-1); meillo@0: return(nl); meillo@0: } meillo@0: meillo@0: static char * meillo@0: getblock(long atl, long iof) meillo@0: { meillo@0: register long bno, off; meillo@0: meillo@0: bno = (atl>>8)&BLKMSK; meillo@0: off = (atl<<1)&0774; meillo@0: if (bno >= BLKMSK) { meillo@0: lastc = '\n'; meillo@0: error("temp file too big"); meillo@0: } meillo@0: nleft = 512 - off; meillo@0: if (bno==iblock) { meillo@0: ichanged |= iof; meillo@0: return(ibuff+off); meillo@0: } meillo@0: if (bno==oblock) meillo@0: return(obuff+off); meillo@0: if (iof==READ) { meillo@0: if (ichanged) meillo@0: blkio(iblock, ibuff, 1); meillo@0: ichanged = 0; meillo@0: iblock = bno; meillo@0: blkio(bno, ibuff, 0); meillo@0: return(ibuff+off); meillo@0: } meillo@0: if (oblock>=0) meillo@0: blkio(oblock, obuff, 1); meillo@0: oblock = bno; meillo@0: return(obuff+off); meillo@0: } meillo@0: meillo@0: static void meillo@0: blkio(long b, char *buf, int wr) meillo@0: { meillo@0: lseek(tfile, b<<9, SEEK_SET); meillo@0: if ((wr ? write(tfile, buf, 512) : read (tfile, buf, 512)) != 512) { meillo@0: status = 1; meillo@0: error("I/O error on temp file"); meillo@0: } meillo@0: } meillo@0: meillo@0: static void meillo@0: init(void) meillo@0: { meillo@0: register long *markp; meillo@0: meillo@0: tline = 2; meillo@0: for (markp = names; markp < &names[26]; markp++) meillo@0: *markp = 0; meillo@0: for (markp = undnames; markp < &undnames[26]; markp++) meillo@0: *markp = 0; meillo@0: subnewa = 0; meillo@0: anymarks = 0; meillo@0: iblock = -1; meillo@0: oblock = -1; meillo@0: ichanged = 0; meillo@0: tfile = maketf(tfile); meillo@0: dot = dol = zero; meillo@0: unddot = NULL; meillo@0: } meillo@0: meillo@0: static void meillo@0: global(int k, int ia) meillo@0: { meillo@0: register int c; meillo@0: register long *a1; meillo@0: static char *globuf; meillo@0: char mb[MB_LEN_MAX+1]; meillo@0: int spflag = 0; meillo@0: meillo@0: if (globp) meillo@0: error("multiple globals not allowed"); meillo@0: setall(); meillo@0: nonzero(); meillo@0: if ((c=GETWC(mb))=='\n') meillo@0: error("incomplete global expression"); meillo@0: compile(NULL, expbuf, &expbuf[ESIZE], c); meillo@0: if (!ia) { meillo@0: globrd(&globuf, EOF); meillo@0: if (globuf[0] == '\n') meillo@0: globuf[0] = 'p', globuf[1] = '\n', globuf[2] = '\0'; meillo@0: } else { meillo@0: newline(); meillo@0: spflag = pflag; meillo@0: pflag = 0; meillo@0: } meillo@0: checkpoint(); meillo@0: for (a1=zero; a1<=dol; a1++) { meillo@0: *a1 &= ~01; meillo@0: if (a1>=addr1 && a1<=addr2 && execute(0, a1, 0)==k) meillo@0: *a1 |= 01; meillo@0: } meillo@0: /* meillo@0: * Special case: g/.../d (avoid n^2 algorithm) meillo@0: */ meillo@0: if (!ia && globuf[0]=='d' && globuf[1]=='\n' && globuf[2]=='\0') { meillo@0: gdelete(); meillo@0: return; meillo@0: } meillo@0: for (a1=zero; a1<=dol; a1++) { meillo@0: if (*a1 & 01) { meillo@0: *a1 &= ~01; meillo@0: dot = a1; meillo@0: if (ia) { meillo@0: puts(getline(*a1, 0)); meillo@0: if ((c = getchr()) == EOF) meillo@0: error("command expected"); meillo@0: if (c == 'a' || c == 'c' || c == 'i') meillo@0: error("a, i, or c not allowed in G"); meillo@0: else if (c == '&') { meillo@0: if ((c = getchr()) != '\n') meillo@0: error("end of line expected"); meillo@0: if (globuf == 0 || *globuf == 0) meillo@0: error("no remembered command"); meillo@0: } else if (c == '\n') { meillo@0: a1 = zero; meillo@0: continue; meillo@0: } else meillo@0: globrd(&globuf, c); meillo@0: } meillo@0: globp = globuf; meillo@0: commands(); meillo@0: globp = NULL; meillo@0: a1 = zero; meillo@0: } meillo@0: } meillo@0: if (ia) meillo@0: pflag = spflag; meillo@0: } meillo@0: meillo@0: static void meillo@0: globrd(char **globuf, register int c) meillo@0: { meillo@0: register int i; meillo@0: meillo@0: if (*globuf == 0 && (*globuf = malloc(GBSIZE=256)) == 0) meillo@0: error("global too long"); meillo@0: i = 0; meillo@0: if (c != EOF) meillo@0: (*globuf)[i++] = c; meillo@0: while ((c = getchr()) != '\n') { meillo@0: if (c==EOF) meillo@0: error("incomplete global expression"); meillo@0: if (c=='\\') { meillo@0: c = getchr(); meillo@0: if (c!='\n') meillo@0: (*globuf)[i++] = '\\'; meillo@0: } meillo@0: (*globuf)[i++] = c; meillo@0: if (i>=GBSIZE-4 && (*globuf=realloc(*globuf,GBSIZE+=256)) == 0) meillo@0: error("global too long"); meillo@0: } meillo@0: (*globuf)[i++] = '\n'; meillo@0: (*globuf)[i++] = 0; meillo@0: } meillo@0: meillo@0: static void meillo@0: join(void) meillo@0: { meillo@0: register int i, j; meillo@0: register long *a1; meillo@0: meillo@0: j = 0; meillo@0: for (a1=addr1; a1<=addr2; a1++) { meillo@0: i = getline(*a1, 0) - linebuf; meillo@0: while (genbuf[j] = linebuf[i++]) meillo@0: if (j++ >= LBSIZE-2) meillo@0: growlb("line too long"); meillo@0: } meillo@0: i = 0; meillo@0: j = 0; meillo@0: while (linebuf[i++] = genbuf[j++]) meillo@0: ; meillo@0: *addr1 = putline(); meillo@0: if (addr1= RHSIZE-2) meillo@0: growrhs("replacement string too long"); meillo@0: rhsbuf[i++] = c; meillo@0: c = GETWC(mb); meillo@0: } else if (c=='\n') { meillo@0: if (globp && *globp) { meillo@0: if (i >= RHSIZE-2) meillo@0: growrhs("replacement string too long"); meillo@0: rhsbuf[i++] = '\\'; meillo@0: } meillo@0: else if (nodelim) meillo@0: error("illegal or missing delimiter"); meillo@0: else { meillo@0: peekc = c; meillo@0: pflag++; meillo@0: break; meillo@0: } meillo@0: } else if (c==seof) meillo@0: break; meillo@0: for (c = 0; c==0 || mb[c]; c++) { meillo@0: if (i >= RHSIZE-2) meillo@0: growrhs("replacement string too long"); meillo@0: rhsbuf[i++] = mb[c]; meillo@0: } meillo@0: } meillo@0: rhsbuf[i++] = 0; meillo@0: if (rhsbuf[0] == '%' && rhsbuf[1] == 0) { meillo@0: if (orhssz == 0) meillo@0: error("no remembered replacement string"); meillo@0: strcpy(rhsbuf, oldrhs); meillo@0: } else { meillo@0: if (orhssz < RHSIZE && meillo@0: (oldrhs = realloc(oldrhs, orhssz=RHSIZE)) == 0) meillo@0: error("replacement string too long"); meillo@0: strcpy(oldrhs, rhsbuf); meillo@0: } meillo@0: if ((peekc = getchr()) == 'g') { meillo@0: peekc = 0; meillo@0: newline(); meillo@0: return(-1); meillo@0: } else if (peekc >= '0' && peekc <= '9') { meillo@0: c = getnum(); meillo@0: if (c < 1 || c > LBSIZE) meillo@0: error("invalid count"); meillo@0: newline(); meillo@0: return c; meillo@0: } meillo@0: newline(); meillo@0: return(0); meillo@0: } meillo@0: meillo@0: static int meillo@0: getsub(void) meillo@0: { meillo@0: register char *p1, *p2; meillo@0: meillo@0: p1 = linebuf; meillo@0: if ((p2 = linebp) == 0) meillo@0: return(EOF); meillo@0: while (*p1++ = *p2++) meillo@0: ; meillo@0: linebp = 0; meillo@0: return(0); meillo@0: } meillo@0: meillo@0: static int meillo@0: dosub(int really) meillo@0: { meillo@0: register char *lp, *sp; meillo@0: register int i, j, k; meillo@0: int c; meillo@0: meillo@0: if (!really) meillo@0: goto copy; meillo@0: i = 0; meillo@0: j = 0; meillo@0: k = 0; meillo@0: while (&linebuf[i] < loc1) meillo@0: genbuf[j++] = linebuf[i++]; meillo@0: while (c = rhsbuf[k++]&0377) { meillo@0: if (c=='&') { meillo@0: j = place(j, loc1, loc2); meillo@0: continue; meillo@0: } else if (c == '\\') { meillo@0: c = rhsbuf[k++]&0377; meillo@0: if (c >='1' && c < nbra+'1') { meillo@0: j = place(j, braslist[c-'1'], braelist[c-'1']); meillo@0: continue; meillo@0: } meillo@0: } meillo@0: if (j >= LBSIZE) meillo@0: growlb("line too long"); meillo@0: genbuf[j++] = c; meillo@0: } meillo@0: i = loc2 - linebuf; meillo@0: loc2 = j + linebuf; meillo@0: #if defined (SUS) || defined (SU3) || defined (S42) meillo@0: if (loc1 == &linebuf[i]) { meillo@0: int n; meillo@0: wchar_t wc; meillo@0: if (mb_cur_max > 1 && (n = mbtowc(&wc, loc2, mb_cur_max)) > 0) meillo@0: loc2 += n; meillo@0: else meillo@0: loc2++; meillo@0: } meillo@0: #endif /* SUS || SU3 || S42 */ meillo@0: while (genbuf[j++] = linebuf[i++]) meillo@0: if (j >= LBSIZE) meillo@0: growlb("line too long"); meillo@0: if (really) { meillo@0: lp = linebuf; meillo@0: sp = genbuf; meillo@0: } else { meillo@0: copy: sp = linebuf; meillo@0: lp = genbuf; meillo@0: } meillo@0: while (*lp++ = *sp++) meillo@0: ; meillo@0: return really; meillo@0: } meillo@0: meillo@0: static int meillo@0: place(register int j, register const char *l1, register const char *l2) meillo@0: { meillo@0: meillo@0: while (l1 < l2) { meillo@0: genbuf[j++] = *l1++; meillo@0: if (j >= LBSIZE) meillo@0: growlb("line too long"); meillo@0: } meillo@0: return(j); meillo@0: } meillo@0: meillo@0: static void meillo@0: move(int cflag) meillo@0: { meillo@0: register long *adt, *ad1, *ad2; meillo@0: meillo@0: setdot(); meillo@0: nonzero(); meillo@0: if ((adt = address())==0) meillo@0: error("illegal move destination"); meillo@0: newline(); meillo@0: checkpoint(); meillo@0: if (cflag) { meillo@0: long *ozero; meillo@0: intptr_t delta; meillo@0: ad1 = dol; meillo@0: ozero = zero; meillo@0: append(getcopy, ad1++); meillo@0: ad2 = dol; meillo@0: delta = zero - ozero; meillo@0: ad1 += delta; meillo@0: adt += delta; meillo@0: } else { meillo@0: ad2 = addr2; meillo@0: for (ad1 = addr1; ad1 <= ad2;) meillo@0: *ad1++ &= ~01; meillo@0: ad1 = addr1; meillo@0: } meillo@0: ad2++; meillo@0: if (adt= ad2) { meillo@0: dot = adt++; meillo@0: reverse(ad1, ad2); meillo@0: reverse(ad2, adt); meillo@0: reverse(ad1, adt); meillo@0: } else meillo@0: error("illegal move destination"); meillo@0: fchange = 1; meillo@0: } meillo@0: meillo@0: static void meillo@0: reverse(register long *a1, register long *a2) meillo@0: { meillo@0: register int t; meillo@0: meillo@0: for (;;) { meillo@0: t = *--a2; meillo@0: if (a2 <= a1) meillo@0: return; meillo@0: *a2 = *a1; meillo@0: *a1++ = t; meillo@0: } meillo@0: } meillo@0: meillo@0: static int meillo@0: getcopy(void) meillo@0: { meillo@0: if (addr1 > addr2) meillo@0: return(EOF); meillo@0: getline(*addr1++, 0); meillo@0: return(0); meillo@0: } meillo@0: meillo@0: static int meillo@0: execute(int gf, long *addr, int subst) meillo@0: { meillo@0: register char *p1, *p2, c; meillo@0: meillo@0: for (c=0; c 1 && *lp&0200) meillo@0: n = mbtowc(&c, lp, mb_cur_max); meillo@0: else { meillo@0: n = 1; meillo@0: c = *lp&0377; meillo@0: } meillo@0: if (col+1 >= 72) { meillo@0: col = 0; meillo@0: putchr('\\'); meillo@0: putchr('\n'); meillo@0: } meillo@0: if (n<0 || meillo@0: #if defined (SUS) || defined (S42) || defined (SU3) meillo@0: c == '\\' || meillo@0: #endif /* SUS || S42 || SU3 */ meillo@0: !(mb_cur_max>1 ? iswprint(c) : isprint(c))) { meillo@0: if (n<0) meillo@0: n = 1; meillo@0: while (n--) meillo@0: col += lstchr(*lp++&0377); meillo@0: } else if (mb_cur_max>1) { meillo@0: col += wcwidth(c); meillo@0: while (n--) meillo@0: putchr(*lp++&0377); meillo@0: } else { meillo@0: putchr(*lp++&0377); meillo@0: col++; meillo@0: } meillo@0: } meillo@0: #if defined (SUS) || defined (S42) || defined (SU3) meillo@0: putchr('$'); meillo@0: #endif meillo@0: putchr('\n'); meillo@0: } meillo@0: meillo@0: static int meillo@0: lstchr(int c) meillo@0: { meillo@0: int cad = 1, d; meillo@0: meillo@0: #if !defined (SUS) && !defined (S42) && !defined (SU3) meillo@0: if (c=='\t') { meillo@0: c = '>'; meillo@0: goto esc; meillo@0: } meillo@0: if (c=='\b') { meillo@0: c = '<'; meillo@0: esc: meillo@0: putchr('-'); meillo@0: putchr('\b'); meillo@0: putchr(c); meillo@0: } else if (c == '\n') { meillo@0: putchr('\\'); meillo@0: putchr('0'); meillo@0: putchr('0'); meillo@0: putchr('0'); meillo@0: cad = 4; meillo@0: #else /* !SUS, !S42, !SU3 */ meillo@0: if (c == '\n') meillo@0: c = '\0'; meillo@0: if (c == '\\') { meillo@0: putchr('\\'); meillo@0: putchr('\\'); meillo@0: cad = 2; meillo@0: } else if (c == '\a') { meillo@0: putchr('\\'); meillo@0: putchr('a'); meillo@0: cad = 2; meillo@0: } else if (c == '\b') { meillo@0: putchr('\\'); meillo@0: putchr('b'); meillo@0: cad = 2; meillo@0: } else if (c == '\f') { meillo@0: putchr('\\'); meillo@0: putchr('f'); meillo@0: cad = 2; meillo@0: } else if (c == '\r') { meillo@0: putchr('\\'); meillo@0: putchr('r'); meillo@0: cad = 2; meillo@0: } else if (c == '\t') { meillo@0: putchr('\\'); meillo@0: putchr('t'); meillo@0: cad = 2; meillo@0: } else if (c == '\v') { meillo@0: putchr('\\'); meillo@0: putchr('v'); meillo@0: cad = 2; meillo@0: #endif /* !SUS, !S42, !SU3 */ meillo@0: } else { meillo@0: putchr('\\'); meillo@0: putchr(((c&~077)>>6)+'0'); meillo@0: c &= 077; meillo@0: d = c & 07; meillo@0: putchr(c > d ? ((c-d)>>3)+'0' : '0'); meillo@0: putchr(d+'0'); meillo@0: cad = 4; meillo@0: } meillo@0: return cad; meillo@0: } meillo@0: meillo@0: static void meillo@0: putstr(const char *s) meillo@0: { meillo@0: while (*s) meillo@0: putchr(*s++); meillo@0: } meillo@0: meillo@0: static char line[70]; meillo@0: static char *linp = line; meillo@0: meillo@0: static void meillo@0: putchr(int ac) meillo@0: { meillo@0: register char *lp; meillo@0: register int c; meillo@0: meillo@0: lp = linp; meillo@0: c = ac; meillo@0: *lp++ = c; meillo@0: if(c == '\n' || lp >= &line[64]) { meillo@0: linp = line; meillo@0: write(1, line, lp-line); meillo@0: return; meillo@0: } meillo@0: linp = lp; meillo@0: } meillo@0: meillo@0: static void meillo@0: checkpoint(void) meillo@0: { meillo@0: long *a1, *a2; meillo@0: meillo@0: if (undzero && globp == NULL) { meillo@0: for (a1 = zero+1, a2 = undzero+1; a1 <= dol; a1++, a2++) meillo@0: *a2 = *a1; meillo@0: unddot = &undzero[dot-zero]; meillo@0: unddol = &undzero[dol-zero]; meillo@0: for (a1 = names, a2 = undnames; a1 < &names[26]; a1++, a2++) meillo@0: *a2 = *a1; meillo@0: } meillo@0: } meillo@0: meillo@0: #define swap(a, b) (t = a, a = b, b = t) meillo@0: meillo@0: static void meillo@0: undo(void) meillo@0: { meillo@0: long *t; meillo@0: meillo@0: if (undzero == NULL) meillo@0: error("no undo information saved"); meillo@0: swap(zero, undzero); meillo@0: swap(dot, unddot); meillo@0: swap(dol, unddol); meillo@0: swap(names, undnames); meillo@0: } meillo@0: meillo@0: static int meillo@0: maketf(int fd) meillo@0: { meillo@0: char *tmpdir; meillo@0: meillo@0: if (fd == -1) { meillo@0: if ((tmpdir = getenv("TMPDIR")) == NULL || meillo@0: (fd = creatf(tmpdir)) < 0) meillo@0: if ((fd = creatf("/var/tmp")) < 0 && meillo@0: (fd = creatf("/tmp")) < 0) meillo@0: error("cannot create temporary file"); meillo@0: } else meillo@0: ftruncate(fd, 0); /* blkio() will seek to 0 anyway */ meillo@0: return fd; meillo@0: } meillo@0: meillo@0: static int meillo@0: creatf(const char *tmpdir) meillo@0: { meillo@0: if (strlen(tmpdir) >= sizeof tfname - 9) meillo@0: return -1; meillo@0: strcpy(tfname, tmpdir); meillo@0: strcat(tfname, "/eXXXXXX"); meillo@0: return mkstemp(tfname); meillo@0: } meillo@0: meillo@0: static int meillo@0: sopen(const char *fn, int rdwr) meillo@0: { meillo@0: int pf[2], fd = -1; meillo@0: meillo@0: if (fn[0] == '!') { meillo@0: fn++; meillo@0: if (pipe(pf) < 0) meillo@0: error("write or open on pipe failed"); meillo@0: switch (pipid = fork()) { meillo@0: case 0: meillo@0: if (rdwr == READ) meillo@0: dup2(pf[1], 1); meillo@0: else meillo@0: dup2(pf[0], 0); meillo@0: close(pf[0]); meillo@0: close(pf[1]); meillo@0: sigset(SIGHUP, oldhup); meillo@0: sigset(SIGQUIT, oldquit); meillo@0: sigset(SIGPIPE, oldpipe); meillo@0: execl(SHELL, "sh", "-c", fn, NULL); meillo@0: _exit(0100); meillo@0: default: meillo@0: close(pf[rdwr == READ ? 1 : 0]); meillo@0: fd = pf[rdwr == READ ? 0 : 1]; meillo@0: break; meillo@0: case -1: meillo@0: error("fork failed - try again"); meillo@0: } meillo@0: } else if (rdwr == READ) meillo@0: fd = open(fn, O_RDONLY); meillo@0: else if (rdwr == EXIST) meillo@0: fd = open(fn, O_WRONLY); meillo@0: else /*if (rdwr == WRITE)*/ meillo@0: fd = creat(fn, 0666); meillo@0: if (fd >= 0 && rdwr == READ) meillo@0: readop = 1; meillo@0: if (fd >= 0) meillo@0: fstat(fd, &fstbuf); meillo@0: return fd; meillo@0: } meillo@0: meillo@0: static void meillo@0: sclose(int fd) meillo@0: { meillo@0: int status; meillo@0: meillo@0: close(fd); meillo@0: if (pipid >= 0) { meillo@0: while (wait(&status) != pipid); meillo@0: pipid = -1; meillo@0: } meillo@0: readop = 0; meillo@0: } meillo@0: meillo@0: static void meillo@0: fspec(const char *lp) meillo@0: { meillo@0: struct termios ts; meillo@0: const char *cp; meillo@0: meillo@0: freetabs(); meillo@0: maxlength = 0; meillo@0: if (tcgetattr(1, &ts) < 0 meillo@0: #ifdef TAB3 meillo@0: || (ts.c_oflag&TAB3) == 0 meillo@0: #endif meillo@0: ) meillo@0: return; meillo@0: while (lp[0]) { meillo@0: if (lp[0] == '<' && lp[1] == ':') meillo@0: break; meillo@0: lp++; meillo@0: } meillo@0: if (lp[0]) { meillo@0: lp += 2; meillo@0: while ((cp = ftok(&lp)) != NULL) { meillo@0: switch (*cp) { meillo@0: case 't': meillo@0: freetabs(); meillo@0: if ((tabstops = tabstring(&cp[1])) == NULL) meillo@0: goto err; meillo@0: break; meillo@0: case 's': meillo@0: maxlength = atoi(&cp[1]); meillo@0: break; meillo@0: case 'm': meillo@0: case 'd': meillo@0: case 'e': meillo@0: break; meillo@0: case ':': meillo@0: if (cp[1] == '>') { meillo@0: if (tabstops == NULL) meillo@0: if ((tabstops = tabstring("0")) meillo@0: == NULL) meillo@0: goto err; meillo@0: return; meillo@0: } meillo@0: /*FALLTHRU*/ meillo@0: default: meillo@0: err: freetabs(); meillo@0: maxlength = 0; meillo@0: errput("PWB spec problem", NULL); meillo@0: return; meillo@0: } meillo@0: } meillo@0: } meillo@0: } meillo@0: meillo@0: static const char * meillo@0: ftok(const char **lp) meillo@0: { meillo@0: const char *cp; meillo@0: meillo@0: while (**lp && **lp != ':' && (**lp == ' ' || **lp == '\t')) meillo@0: (*lp)++; meillo@0: cp = *lp; meillo@0: while (**lp && **lp != ':' && **lp != ' ' && **lp != '\t') meillo@0: (*lp)++; meillo@0: return cp; meillo@0: } meillo@0: meillo@0: static struct tabulator * meillo@0: repetitive(int repetition) meillo@0: { meillo@0: struct tabulator *tp, *tabspec; meillo@0: int col, i; meillo@0: meillo@0: if ((tp = tabspec = calloc(1, sizeof *tp)) == NULL) meillo@0: return NULL; meillo@0: tp->t_rep = repetition; meillo@0: if (repetition > 0) { meillo@0: for (col = 1+repetition, i = 0; i < 22; col += repetition) { meillo@0: if ((tp->t_nxt = calloc(1, sizeof *tp)) == NULL) meillo@0: return NULL; meillo@0: tp = tp->t_nxt; meillo@0: tp->t_tab = col; meillo@0: } meillo@0: } meillo@0: return tabspec; meillo@0: } meillo@0: meillo@0: #define blank(c) ((c) == ' ' || (c) == '\t') meillo@0: meillo@0: static struct tabulator * meillo@0: tablist(const char *s) meillo@0: { meillo@0: struct tabulator *tp, *tabspec; meillo@0: char *x; meillo@0: int prev = 0, val; meillo@0: meillo@0: if ((tp = tabspec = calloc(1, sizeof *tp)) == NULL) meillo@0: return NULL; meillo@0: for (;;) { meillo@0: while (*s == ',') meillo@0: s++; meillo@0: if (*s == '\0' || blank(*s) || *s == ':') meillo@0: break; meillo@0: val = strtol(s, &x, 10); meillo@0: if (*s == '+') meillo@0: val += prev; meillo@0: prev = val; meillo@0: if (*s == '-' || (*x != ',' && !blank(*x) && *x != ':' && meillo@0: *x != '\0')) meillo@0: return NULL; meillo@0: s = x; meillo@0: if ((tp->t_nxt = calloc(1, sizeof *tp)) == NULL) meillo@0: return NULL; meillo@0: tp = tp->t_nxt; meillo@0: tp->t_tab = val; meillo@0: } meillo@0: return tabspec; meillo@0: } meillo@0: meillo@0: static struct tabulator * meillo@0: tabstring(const char *s) meillo@0: { meillo@0: const struct { meillo@0: const char *c_nam; meillo@0: const char *c_str; meillo@0: } canned[] = { meillo@0: { "a", "1,10,16,36,72" }, meillo@0: { "a2", "1,10,16,40,72" }, meillo@0: { "c", "1,8,12,16,20,55" }, meillo@0: { "c2", "1,6,10,14,49" }, meillo@0: { "c3", "1,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62,67" }, meillo@0: { "f", "1,7,11,15,19,23" }, meillo@0: { "p", "1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61" }, meillo@0: { "s", "1,10,55" }, meillo@0: { "u", "1,12,20,44" }, meillo@0: { 0, 0 } meillo@0: }; meillo@0: meillo@0: int i, j; meillo@0: meillo@0: if (s[0] == '-') { meillo@0: if (s[1] >= '0' && s[1] <= '9' && ((i = atoi(&s[1])) != 0)) meillo@0: return repetitive(i); meillo@0: for (i = 0; canned[i].c_nam; i++) { meillo@0: for (j = 0; canned[i].c_nam[j]; j++) meillo@0: if (s[j+1] != canned[i].c_nam[j]) meillo@0: break; meillo@0: if ((s[j+1]=='\0' || s[j+1]==':' || blank(s[j+1])) && meillo@0: canned[i].c_nam[j] == '\0') meillo@0: return tablist(canned[i].c_str); meillo@0: } meillo@0: return NULL; meillo@0: } else meillo@0: return tablist(s); meillo@0: } meillo@0: meillo@0: static void meillo@0: freetabs(void) meillo@0: { meillo@0: struct tabulator *tp; meillo@0: meillo@0: tp = tabstops; meillo@0: while (tp) { meillo@0: tabstops = tp->t_nxt; meillo@0: free(tp); meillo@0: tp = tabstops; meillo@0: } meillo@0: } meillo@0: meillo@0: static void meillo@0: expand(const char *s) meillo@0: { meillo@0: struct tabulator *tp = tabstops; meillo@0: int col = 0, n = 1, m, tabcnt = 0, nspc; meillo@0: wchar_t wc; meillo@0: meillo@0: while (*s) { meillo@0: nspc = 0; meillo@0: switch (*s) { meillo@0: case '\n': meillo@0: putchr('\0'); meillo@0: s++; meillo@0: continue; meillo@0: case '\t': meillo@0: if (tp) { meillo@0: if (tp->t_rep) { meillo@0: if (col % tp->t_rep == 0) { meillo@0: nspc++; meillo@0: col++; meillo@0: } meillo@0: while (col % tp->t_rep) { meillo@0: nspc++; meillo@0: col++; meillo@0: } meillo@0: break; meillo@0: } meillo@0: while (tp && (col>tp->t_tab || tp->t_tab == 0)) meillo@0: tp = tp->t_nxt; meillo@0: if (tp && col == tp->t_tab) { meillo@0: nspc++; meillo@0: col++; meillo@0: tp = tp->t_nxt; meillo@0: } meillo@0: if (tp) { meillo@0: while (col < tp->t_tab) { meillo@0: nspc++; meillo@0: col++; meillo@0: } meillo@0: tp = tp->t_nxt; meillo@0: break; meillo@0: } meillo@0: } meillo@0: tabcnt = 1; meillo@0: nspc++; meillo@0: break; meillo@0: default: meillo@0: if (mb_cur_max>1 && (n=mbtowc(&wc, s, mb_cur_max))>0) { meillo@0: if ((m = wcwidth(wc)) > 0) meillo@0: col += m; meillo@0: } else { meillo@0: col++; meillo@0: n = 1; meillo@0: } meillo@0: } meillo@0: if (maxlength && col > maxlength) { meillo@0: putstr("\ntoo long"); meillo@0: break; meillo@0: } meillo@0: if (nspc) { meillo@0: while (nspc--) meillo@0: putchr(' '); meillo@0: s++; meillo@0: } else meillo@0: while (n--) meillo@0: putchr(*s++); meillo@0: } meillo@0: if (tabcnt) meillo@0: putstr("\ntab count"); meillo@0: putchr('\n'); meillo@0: } meillo@0: meillo@0: static wint_t meillo@0: GETWC(char *mb) meillo@0: { meillo@0: int c, n; meillo@0: meillo@0: n = 1; meillo@0: mb[0] = c = GETC(); meillo@0: mb[1] = '\0'; meillo@0: if (mb_cur_max > 1 && c&0200 && c != EOF) { meillo@0: int m; meillo@0: wchar_t wc; meillo@0: meillo@0: while ((m = mbtowc(&wc, mb, mb_cur_max)) < 0 && n=LBSIZE ? (growlb("regular expression overflow"),0) : 0), \ meillo@0: genbuf[i++] = (c)) meillo@0: meillo@0: #define copy(s) { \ meillo@0: int m; \ meillo@0: for (m = 0; m==0 || s[m]; m++) \ meillo@0: add(s[m]); \ meillo@0: } meillo@0: meillo@0: static char * meillo@0: compile(char *unused, char *ep, const char *endbuf, int seof) meillo@0: { meillo@0: INIT meillo@0: int c, d, i; meillo@0: regex_t *rp; meillo@0: char *op; meillo@0: char mb[MB_LEN_MAX+1]; meillo@0: meillo@0: op = ep; meillo@0: ep += 2; meillo@0: if ((rp = fetchptr(ep)) == NULL) { meillo@0: if ((rp = calloc(1, sizeof *rp)) == NULL) meillo@0: ERROR(50); meillo@0: storeptr(rp, ep); meillo@0: } meillo@0: ep += sizeof (void *); meillo@0: i = 0; meillo@0: nbra = 0; meillo@0: do { meillo@0: if ((c = GETWC(mb)) == seof) meillo@0: add('\0'); meillo@0: else if (c == '\\') { meillo@0: copy(mb); meillo@0: c = GETWC(mb); meillo@0: if (c == '(') meillo@0: nbra++; meillo@0: goto normchar; meillo@0: } else if (c == '[') { meillo@0: add(c); meillo@0: d = EOF; meillo@0: do { meillo@0: c = GETWC(mb); meillo@0: if (c == EOF || c == '\n') meillo@0: ERROR(49); meillo@0: copy(mb); meillo@0: if (d=='[' && (c==':' || c=='.' || c=='=')) { meillo@0: d = c; meillo@0: do { meillo@0: c = GETWC(mb); meillo@0: if (c == EOF || c == '\n') meillo@0: ERROR(49); meillo@0: copy(mb); meillo@0: } while (c != d || PEEKC() != ']'); meillo@0: c = GETWC(mb); meillo@0: copy(mb); meillo@0: c = EOF; meillo@0: } meillo@0: d = c; meillo@0: } while (c != ']'); meillo@0: } else { meillo@0: if (c == EOF || c == '\n') { meillo@0: if (c == '\n') meillo@0: UNGETC(c); meillo@0: mb[0] = c = '\0'; meillo@0: } meillo@0: if (c == '\0') meillo@0: nodelim = 1; meillo@0: normchar: copy(mb); meillo@0: } meillo@0: } while (genbuf[i-1] != '\0'); meillo@0: if (genbuf[0]) { meillo@0: int reflags = 0; meillo@0: meillo@0: #ifdef REG_ANGLES meillo@0: reflags |= REG_ANGLES; meillo@0: #endif meillo@0: #if defined (SU3) && defined (REG_AVOIDNULL) meillo@0: reflags |= REG_AVOIDNULL; meillo@0: #endif meillo@0: if (op[0]) meillo@0: regfree(rp); meillo@0: op[0] = 0; meillo@0: switch (regcomp(rp, genbuf, reflags)) { meillo@0: case 0: meillo@0: break; meillo@0: case REG_ESUBREG: meillo@0: ERROR(25); meillo@0: /*NOTREACHED*/ meillo@0: case REG_EBRACK: meillo@0: ERROR(49); meillo@0: /*NOTREACHED*/ meillo@0: case REG_EPAREN: meillo@0: ERROR(42); meillo@0: /*NOTREACHED*/ meillo@0: case REG_BADBR: meillo@0: case REG_EBRACE: meillo@0: ERROR(45); meillo@0: /*NOTREACHED*/ meillo@0: case REG_ERANGE: meillo@0: ERROR(11); meillo@0: /*NOTREACHED*/ meillo@0: case REG_ESPACE: meillo@0: ERROR(50); meillo@0: /*NOTREACHED*/ meillo@0: default: meillo@0: ERROR(-1); meillo@0: } meillo@0: op[0] = 1; meillo@0: circf = op[1] = genbuf[0] == '^'; meillo@0: } else if (op[0]) { meillo@0: circf = op[1]; meillo@0: } else meillo@0: ERROR(41); meillo@0: return ep + sizeof (void *); meillo@0: } meillo@0: meillo@0: static int meillo@0: step(const char *lp, const char *ep) meillo@0: { meillo@0: regex_t *rp; meillo@0: regmatch_t bralist[NBRA+1]; meillo@0: int eflag = 0; meillo@0: int res; meillo@0: int i; meillo@0: meillo@0: rp = fetchptr(&ep[2]); meillo@0: if (ep[0] == 0) meillo@0: return 0; meillo@0: if (locs) meillo@0: eflag |= REG_NOTBOL; meillo@0: if ((res = regexec(rp, lp, needsub? NBRA+1 : 0, bralist, eflag)) == 0 && meillo@0: needsub) { meillo@0: loc1 = (char *)lp + bralist[0].rm_so; meillo@0: loc2 = (char *)lp + bralist[0].rm_eo; meillo@0: for (i = 1; i <= NBRA; i++) { meillo@0: if (bralist[i].rm_so != -1) { meillo@0: braslist[i-1] = (char *)lp + bralist[i].rm_so; meillo@0: braelist[i-1] = (char *)lp + bralist[i].rm_eo; meillo@0: } else meillo@0: braslist[i-1] = braelist[i-1] = NULL; meillo@0: } meillo@0: } meillo@0: return res == 0; meillo@0: } meillo@0: #endif /* SUS || S42 || SU3 */ meillo@0: meillo@0: static void meillo@0: help(void) meillo@0: { meillo@0: const char *desc[] = { meillo@0: "(.)a append up to .", meillo@0: "(.)b[n] browse n lines", meillo@0: "(.,.)c change up to .", meillo@0: "(.,.)d delete lines", meillo@0: "e [file] edit file", meillo@0: "E [file] force edit", meillo@0: "f [file] print or set file", meillo@0: "(1,$)g/RE/cmd global cmd", meillo@0: "(1,$)G/RE/ interactive global", meillo@0: "h print last error", meillo@0: "H toggle error messages", meillo@0: "help print this screen", meillo@0: "(.)i insert up to .", meillo@0: "(.,.+1)j join lines", meillo@0: "(.)kx mark line with x", meillo@0: "(.,.)l list lines", meillo@0: "(.,.)ma move lines to a", meillo@0: "(.,.)n number lines", meillo@0: "N revert n and p", meillo@0: "(.)o[n] show n lines of context", meillo@0: "(.,.)p print lines", meillo@0: "P toggle prompt", meillo@0: "q quit", meillo@0: "Q force quit", meillo@0: "($)r read file", meillo@0: "(.,.)s/RE/repl/ search and replace", meillo@0: "(.,.)s/RE/rp/g replace all occurrences", meillo@0: "(.,.)s/RE/rp/n replace n-th occurrence", meillo@0: "(.,.)ta transfer lines to a", meillo@0: "u undo last change", meillo@0: "(1,$)v/RE/cmd reverse global", meillo@0: "(1,$)V/RE/ reverse i/a global", meillo@0: "(1,$)w [file] write file", meillo@0: "(1,$)W [file] append to file", meillo@0: "z write buffer and quit", meillo@0: "($)= print line number", meillo@0: "!command execute shell command", meillo@0: "(.+1) print one line", meillo@0: "/RE find RE forwards", meillo@0: "?RE find RE backwards", meillo@0: "1 first line", meillo@0: ". current line", meillo@0: "$ last line", meillo@0: ", 1,$", meillo@0: "; .,$", meillo@0: NULL meillo@0: }; meillo@0: char line[100]; meillo@0: int c, half, i, k; meillo@0: meillo@0: half = (sizeof desc / sizeof *desc) / 2; meillo@0: for (i = 0; i < half && desc[i]; i++) { meillo@0: c = 0; meillo@0: for (k = 0; desc[i][k]; k++) meillo@0: line[c++] = desc[i][k]; meillo@0: if (desc[i+half]) { meillo@0: while (c < 40) meillo@0: line[c++] = ' '; meillo@0: for (k = 0; desc[i+half][k]; k++) meillo@0: line[c++] = desc[i+half][k]; meillo@0: } meillo@0: line[c] = 0; meillo@0: puts(line); meillo@0: } meillo@0: }