Commits

Alex Bolotov  committed bd0c5d5

Version 3.4o compiles (somewhere, I haven't tried) cleanly with cc -Wall

  • Participants
  • Parent commits 1432b98
  • Tags 3.4o

Comments (0)

Files changed (36)

+# makefile for Levee
+
+CFLAGS = -O -DSIZE=256000L -Wall
+#LIBES=-lncurses
+LIBES=-ltermcap
+
+OBJS = blockio.o display.o editcor.o exec.o find.o \
+    unixcall.o globals.o insert.o main.o misc.o \
+    modify.o move.o ucsd.o undo.o wildargs.o
+
+lev: $(OBJS)
+	$(CC) $(CFLAGS) -o lev $(OBJS) $(LIBES)
+
+clean:
+	rm -f *.o lev
+
+# Dependencies
+
+blockio.o    : levee.h extern.h blockio.c
+display.o    : levee.h extern.h termcap.i display.c
+editcor.o    : levee.h extern.h editcor.c
+exec.o       : levee.h extern.h exec.c
+find.o       : levee.h extern.h grep.h find.c
+globals.o    : levee.h globals.c
+insert.o     : levee.h extern.h insert.c
+main.o       : levee.h extern.h main.c
+misc.o       : levee.h extern.h misc.c
+modify.o     : levee.h extern.h grep.h modify.c
+move.o       : levee.h extern.h move.c
+rmxcall.o    : levee.h rmxcall.c
+ucsd.o       : levee.h extern.h ucsd.c
+undo.o       : levee.h extern.h undo.c

File Mastodon.build

+#! /bin/sh
+#
+# Mastodon buildfile for Levee (3.4m)
+#
+
+. ./Mastodon.inc
+exedir BIN
+
+make clean
+CC="$SYSCC" make || exit 1
+
+install -d $BIN/usr/bin
+install -d -o man -g man $BIN/usr/man/man1
+
+install -m 511 -o bin -g bin -s -c lev $BIN/usr/bin/levee
+install -m 444 -o man -g man -c lv.1 $BIN/usr/man/man1/levee.1
+
+(   cd $BIN/usr/bin
+#    ln -fs levee vi
+    ln levee lv
+)
+(   cd $BIN/usr/man/man1
+#    ln -fs levee.1 vi.1
+    ln levee.1 lv.1
+)
+exit 0

File Mastodon.inc

+/Mastodon/Mastodon.inc
+3.4o
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, without or
+ * without modification, are permitted provided that the above
+ * copyright notice and this paragraph are duplicated in all such
+ * forms and that any documentation, advertising materials, and
+ * other materials related to such distribution and use acknowledge
+ * that the software was developed by David L Parsons (orc@pell.chi.il.us).
+ * My name may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+#include "levee.h"
+
+#if ST
+#include <atari\osbind.h>
+
+char sound[] = {
+	0xA8,0x01,0xA9,0x01,0xAA,0x01,0x00,
+	0xF8,0x10,0x10,0x10,0x00,0x20,0x03
+};
+
+#define SADDR	0xFF8800L
+
+typedef char srdef[4];
+
+srdef *SOUND = (srdef *)SADDR;
+
+main()
+{
+    register i;
+    long ssp;
+
+    ssp = Super(0L);
+    for (i=0; i<sizeof(sound); i++) {
+	(*SOUND)[0] = i;
+	(*SOUND)[2] = sound[i];
+    }
+    Super(ssp);
+}
+#endif /*ST*/
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, without or
+ * without modification, are permitted provided that the above
+ * copyright notice and this paragraph are duplicated in all such
+ * forms and that any documentation, advertising materials, and
+ * other materials related to such distribution and use acknowledge
+ * that the software was developed by David L Parsons (orc@pell.chi.il.us).
+ * My name may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+#include "levee.h"
+#include "extern.h"
+
+/* read in a file -- return TRUE -- read file
+			    FALSE-- file too big
+*/
+
+int PROC
+addfile(f, start, endd, size)
+FILE *f;
+int start;
+int endd, *size;
+{
+    register int chunk;
+
+    chunk = read(fileno(f), core+start, (endd-start)-1);
+
+    *size = chunk;
+    return chunk < (endd-start)-1;
+}
+
+
+/* write out a file -- return TRUE if ok. */
+
+bool PROC
+putfile(f, start, endd)
+register FILE *f;
+register start, endd;
+{
+    return write(fileno(f), core+start, endd-start) == (endd-start);
+}
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, without or
+ * without modification, are permitted provided that the above
+ * copyright notice and this paragraph are duplicated in all such
+ * forms and that any documentation, advertising materials, and
+ * other materials related to such distribution and use acknowledge
+ * that the software was developed by David L Parsons (orc@pell.chi.il.us).
+ * My name may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+#include "levee.h"
+#include "extern.h"
+
+/* do a gotoXY -- allowing -1 for same row/column */
+
+#if TERMCAP | ST
+
+#define MAXCOLS 160
+
+#if TERMCAP
+#include "termcap.i"
+#endif
+
+#else /*!(TERMCAP | ST)*/
+
+#define MAXCOLS COLS
+
+#endif
+
+VOID PROC
+mvcur(y,x)
+int y,x;
+{
+#if TERMCAP_EMULATION || ANSI
+    static char gt[30];
+#endif
+   
+    if (y == -1)
+	y = curpos.y;
+    else
+	curpos.y = y;
+    if (y >= LINES)
+	y = LINES-1;
+    if (x == -1)
+	x = curpos.x;
+    else
+	curpos.x = x;
+    if (x >= COLS)
+	x = COLS-1;
+
+#if TERMCAP
+#if TERMCAP_EMULATION
+    tgoto(gt,y,x);
+    strput(gt);
+#else
+    strput( tgoto(CM, x, y) );
+#endif
+#elif ZTERM
+    zgoto(x,y);
+#elif ANSI
+    {	register char *p = gt;		/* make a ansi gotoXY string */
+	*p++ = 033;
+	*p++ = '[';
+	numtoa(p,1+y); p += strlen(p);
+	*p++ = ';';
+	numtoa(p,1+x); p += strlen(p);
+	*p++ = 'H';
+	WRITE_TEXT(1, gt, (p-gt));
+    }
+#elif VT52
+    CM[2] = y+32;
+    CM[3] = x+32;
+    strput(CM);
+#endif
+}
+
+VOID PROC
+numtoa(str,num)
+char *str;
+int num;
+{
+    int i = 10;			/* I sure hope that str is 10 bytes long... */
+    bool neg = (num < 0);
+
+    if (neg)
+	num = -num;
+
+    str[--i] = 0;
+    do{
+	str[--i] = (num%10)+'0';
+	num /= 10;
+    }while (num > 0);
+    if (neg)
+	str[--i] = '-';
+    moveleft(&str[i], str, 10-i);
+}
+
+VOID PROC
+printi(num)
+int num;
+{
+    char nb[10];
+    register int size;
+    
+    numtoa(nb,num);
+    size = min(strlen(nb),COLS-curpos.x);
+    if (size > 0) {
+	nb[size] = 0;
+	zwrite(nb, size);
+	curpos.x += size;
+    }
+}
+
+VOID PROC
+println()
+{
+    zwrite("\r\n", 2);
+    curpos.x = 0;
+    curpos.y = min(curpos.y+1, LINES-1);
+}
+
+/* print a character out in a readable form --
+ *    ^<x> for control-<x>
+ *    spaces for <tab>
+ *    normal for everything else
+ */
+
+static char hexdig[] = "0123456789ABCDEF";
+
+int PROC
+format(out,c)
+/* format: put a displayable version of c into out */
+register char *out;
+register unsigned c;
+{
+    if (c >= ' ' && c < '') {
+    	out[0] = c;
+    	return 1;
+    }
+    else if (c == '\t' && !list) {
+	register int i;
+	int size;
+
+	for (i = size = tabsize - (curpos.x % tabsize);i > 0;)
+	    out[--i] = ' ';
+	return size;
+    }
+    else if (c < 128) {
+    	out[0] = '^';
+    	out[1] = c^64;
+    	return 2;
+    }
+    else {
+#if MSDOS
+	out[0] = c;
+	return 1;
+#else
+	out[0] = '\\';
+	out[1] = hexdig[(c>>4)&017];
+	out[2] = hexdig[c&017];
+	return 3;
+#endif
+    }
+}
+
+VOID PROC
+printch(c)
+char c;
+{
+    register int size;
+    char buf[MAXCOLS];
+
+    size = min(format(buf,c),COLS-curpos.x);
+    if (size > 0) {
+	buf[size] = 0;
+	zwrite(buf, size);
+	curpos.x += size;
+    }
+}
+
+VOID PROC
+prints(s)
+char *s;
+{
+    int size,oxp = curpos.x;
+    char buf[MAXCOLS+1];
+    register bi = 0;
+
+    while (*s && curpos.x < COLS) {
+    	size = format(&buf[bi],*s++);
+    	bi += size;
+    	curpos.x += size;
+    }
+    size = min(bi,COLS-oxp);
+    if (size > 0) {
+	buf[size] = 0;
+	zwrite(buf, size);
+    }
+}
+
+VOID PROC
+writeline(y,x,start)
+int y,x,start;
+{
+    int endd,oxp;
+    register size;
+    char buf[MAXCOLS+1];
+    register bi = 0;
+    
+    endd = fseekeol(start);
+    if (start==0 || core[start-1] == EOL)
+	mvcur(y, 0);
+    else
+	mvcur(y, x);
+    oxp = curpos.x;
+
+    while (start < endd && curpos.x < COLS) {
+    	size = format(&buf[bi],core[start++]);
+    	bi += size;
+    	curpos.x += size;
+    }
+    if (list) {
+    	buf[bi++] = '$';
+    	curpos.x++;
+    }
+    size = min(bi,COLS-oxp);
+    if (size > 0) {
+	buf[size] = 0;
+	zwrite(buf, size);
+    }
+    if (curpos.x < COLS)
+	strput(CE);
+}
+
+/* redraw && refresh the screen */
+
+VOID PROC
+refresh(y,x,start,endd,rest)
+int y,x,start,endd;
+bool rest;
+{
+    int sp;
+    
+#if ST
+    /* turn the cursor off */
+    asm(" clr.l  -(sp)     ");
+    asm(" move.w #21,-(sp) ");
+    asm(" trap   #14       ");
+    asm(" addq.l #6,sp     ");
+#endif
+    sp = start;
+    while (sp <= endd) {
+	writeline(y, x, sp);
+	sp = 1+fseekeol(sp);
+	y++;
+	x = 0;
+    }
+    if (rest && sp >= bufmax)
+	while (y<LINES-1) { /* fill screen with ~ */
+	    mvcur(y, 0);
+	    printch('~'); strput(CE);
+	    y++;
+	}
+#if ST
+    /* turn the cursor back on */
+    asm(" clr.w  -(sp)     ");
+    asm(" move.w #1,-(sp)  ");
+    asm(" move.w #21,-(sp) ");
+    asm(" trap   #14       ");
+    asm(" addq.l #6,sp     ");
+#endif
+}
+
+/* redraw everything */
+
+VOID PROC
+redisplay(flag)
+bool flag;
+{
+    if (flag)
+	clrprompt();
+    refresh(0, 0, ptop, pend, TRUE);
+}
+    
+VOID PROC
+scrollback(curr)
+int curr;
+{
+    mvcur(0,0);		/* move to the top line */
+    do {
+	ptop = bseekeol(ptop-1);
+	strput(UpS);
+	writeline(0, 0, ptop);
+    } while (ptop > curr);
+    setend();
+}
+
+VOID PROC
+scrollforward(curr)
+int curr;
+{
+    do {
+	writeline(LINES-1, 0, pend+1);
+	zwrite("\n", 1);
+	pend = fseekeol(pend+1);
+	ptop = fseekeol(ptop)+1;
+    } while (pend < curr);
+}
+
+/* find if the number of lines between top && bottom is less than dofscroll */
+
+bool PROC
+ok_to_scroll(top,bottom)
+int top,bottom;
+{
+    int nl, i;
+    
+    nl = dofscroll;
+    i = top;
+    do
+	i += 1+scan(bufmax-i,'=',EOL, &core[i]);
+    while (--nl > 0 && i < bottom);
+    return(nl>0);
+}
+
+VOID PROC
+clrprompt()
+{
+    mvcur(LINES-1,0);
+    strput(CE);
+}
+
+VOID PROC
+prompt(toot,s)
+bool toot;
+char *s;
+{
+    if (toot)
+	error();
+    clrprompt();
+    prints(s);
+}
+	name	dos
+	page	55,80
+	title	'DOS.ASM -- assembly routines for the teeny-shell under DOS'
+
+_TEXT	segment byte public 'CODE'
+
+        assume  cs:_TEXT
+
+public	_fail_criterr
+;
+; If we get a critical error, just fail it - dos 3.0 and up only, please!
+;
+_fail_criterr proc far
+	mov	al, 3
+	iret
+_fail_criterr endp
+
+public _ignore_ctrlc
+;
+; If the user presses ^C, don't do any special handling of it.
+;
+_ignore_ctrlc proc far
+	iret
+_ignore_ctrlc endp
+_pexec	endp
+
+public _intr_on_ctrlc
+;
+; If the user presses ^C, terminate the current process.
+;
+_intr_on_ctrlc proc far
+	mov	ah, 4ch
+	mov	al, 0ffh
+	int	21h
+_intr_on_ctrlc endp
+
+public _crawcin
+;
+; get a character from standard input without any sort of magical
+; processing.
+;
+_crawcin proc far
+	mov	ah, 07h
+	int	21h
+	ret
+_crawcin endp
+
+_TEXT	ends
+
+	end
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, without or
+ * without modification, are permitted provided that the above
+ * copyright notice and this paragraph are duplicated in all such
+ * forms and that any documentation, advertising materials, and
+ * other materials related to such distribution and use acknowledge
+ * that the software was developed by David L Parsons (orc@pell.chi.il.us).
+ * My name may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+/*
+ * dos interface for levee (Microsoft C)
+ */
+#include "levee.h"
+
+#if MSDOS
+#include <glob.h>
+#include <dos.h>
+
+int PROC
+min(a,b)
+int a,b;
+{
+    return (a>b) ? b : a;
+}
+
+int PROC
+max(a,b)
+int a,b;
+{
+    return (a<b) ? b : a;
+}
+
+PROC
+strput(s)
+char *s;
+{
+    write(1, s, strlen(s));
+}
+
+/* get a key, mapping certain control sequences
+ */
+PROC
+getKey()
+{
+    register c;
+    extern char _far crawcin();
+
+    c = crawcin();
+
+    if (c == 0 || c == 0xe0)
+	switch (c=crawcin()) {
+	case 'K': return LTARROW;
+	case 'M': return RTARROW;
+	case 'H': return UPARROW;
+	case 'P': return DNARROW;
+	case 'I': return 'U'-'@';	/* page-up */
+	case 'Q': return 'D'-'@';	/* page-down */
+	default : return 0;
+	}
+    return c;
+}
+
+
+/* don't allow interruptions to happen
+ */
+PROC
+nointr()
+{
+    extern void _cdecl _interrupt _far ignore_ctrlc();
+    _dos_setvect(0x23, ignore_ctrlc);
+} /* nointr */
+
+
+/* have ^C do what it usually does
+ */
+PROC
+allowintr()
+{
+    extern void _cdecl _interrupt _far intr_on_ctrlc();
+    _dos_setvect(0x23, intr_on_ctrlc);
+} /* allowintr */
+
+
+/*
+ * basename() returns the filename part of a pathname
+ */
+char *
+basename(s)
+register char *s;
+{
+    register char *p = s;
+    
+    for (p = s+strlen(s); p > s; --p)
+	if (p[-1] == '/' || p[-1] == '\\' || p[-1] == ':')
+	    return p;
+    return s;
+} /* basename */
+
+
+/*
+ * glob() expands a wildcard, via calls to _dos_findfirst/_next()
+ * and pathname retention.
+ */
+char *
+glob(path, dta)
+char *path;
+struct glob_t *dta;
+{
+    static char path_bfr[256];		/* full pathname to return */
+    static char *file_part;		/* points at file - for filling */
+    static char isdotpattern;		/* looking for files starting with . */
+    static char isdotordotdot;		/* special case . or .. */
+    static struct glob_t *dta_bfr;	/* pointer to desired dta */
+    static struct find_t dird;		/* DOS dta */
+
+    register st;			/* status from _dos_findxxx */
+
+    if (path) {
+	/* when we start searching, save the path part of the filename in
+	 * a safe place.
+	 */
+	strcpy(path_bfr, path);
+	file_part = basename(path_bfr);
+
+	/* set up initial parameters for DosFindFirst()
+	 */
+	dta_bfr = dta;
+	
+	if (isdotpattern = (*file_part == '.'))
+	    /* _dos_findfirst() magically expands . and .. into their
+	     * directory names.  Admittedly, there are cases where
+	     * this can be useful, but this is not one of them. So,
+	     * if we find that we're matching . and .., we just
+	     * special-case ourselves into oblivion to get around
+	     * this particular bit of DOS silliness.
+	     */
+	    isdotordotdot = (file_part[1] == 0 || file_part[1] == '.');
+	else
+	    isdotordotdot = 0;
+
+	st = _dos_findfirst(path, 0x16, &dird);
+    }
+    else
+	st = _dos_findnext(&dird);
+
+    while (st == 0) {
+	/* Unless the pattern has a leading ., don't include any file
+	 * that starts with .
+	 */
+	if (dird.name[0] == '.' && !isdotpattern)
+	    st = _dos_findnext(&dird);
+	else {
+	    /* found a file - affix the path leading to it, then return
+	     * a pointer to the (static) buffer holding the path+the name.
+	     */
+	    strlwr(dird.name);		/* DOS & OS/2 are case-insensitive */
+
+	    if (dta_bfr) {
+		dta_bfr->wr_time = dird.wr_time;
+		dta_bfr->wr_date = dird.wr_date;
+		if (isdotordotdot)
+		    strcpy(dta_bfr->name, file_part);
+		else {
+		    strncpy(dta_bfr->name, dird.name, sizeof(dta_bfr->name)-1);
+		    dta_bfr->name[sizeof(dta_bfr->name)-1] = 0;
+		}
+		dta_bfr->size   = dird.size;
+		dta_bfr->attrib = dird.attrib;
+	    }
+	    if (!isdotordotdot)
+		strcpy(file_part, dird.name);
+	    return path_bfr;
+	}
+    }
+    /* nothing matched
+     */
+    if (path && isdotordotdot) {
+	/* must be at root, so statting dot will most likely fail.  Fake a
+	 * dta.
+	 */
+	if (dta_bfr) {
+	    memset(dta_bfr, 0, sizeof *dta_bfr);
+	    dta_bfr->attrib = 0x10;
+	    dta_bfr->name[0] = '.';
+	}
+	return path_bfr;
+    }
+    return (char*)0;
+} /* glob */
+#endif /*MSDOS*/
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, without or
+ * without modification, are permitted provided that the above
+ * copyright notice and this paragraph are duplicated in all such
+ * forms and that any documentation, advertising materials, and
+ * other materials related to such distribution and use acknowledge
+ * that the software was developed by David L Parsons (orc@pell.chi.il.us).
+ * My name may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+#include "levee.h"
+#include "extern.h"
+    
+/* do some undoable modification */
+
+/* These variables make docommand nonrecursive */
+
+bool	ok;
+int	newend,		/* end position after change */
+	disp,		/* start redisplay here */
+	newc,		/* new cursor position for wierd cmds */
+	endY;		/* final yp for endp */
+
+/* move a line of text right || left */
+
+VOID PROC
+adjuster(sleft, endd, sw)
+bool sleft;
+int endd, sw;
+{
+    bool noerror;
+    int np, ts,
+	ip,
+	ss, adjp,
+	DLEnum;
+
+    if (sw == -1)
+	sw = shiftwidth;
+    if (sleft)
+	sw = -sw;
+    curr = bseekeol(curr);
+    ip = curr;
+    noerror = TRUE;
+    do {
+	DLEnum = sw + findDLE(ip, &np, bufmax,0);
+	if (DLEnum >= 0 && DLEnum <= COLS && core[np] != EOL && np < bufmax) {
+	    ts = DLEnum / tabsize;
+	    ss = DLEnum % tabsize;
+	    adjp = ts+ss+ip;
+	    if (np-adjp < 0) {	/* expand the buf */
+		moveright(&core[np], &core[adjp], bufmax-np);
+		insert_to_undo(&undo, adjp, adjp - np);
+	    }
+	    else
+		delete_to_undo(&undo, adjp, np - adjp);
+
+	    endd += (adjp-np);
+	    noerror = move_to_undo(&undo, ip, ts+ss);
+	    fillchar(&core[ip], ts, TAB);
+	    fillchar(&core[ip+ts], ss, 32);
+	}
+	else if (np > ip) {	/* remove the indent code */
+	    noerror = delete_to_undo(&undo, ip, np-ip);
+	    endd += (ip - np);
+	}
+	ip = 1 + fseekeol(ip);
+    } while (noerror && ip < endd);
+    if (!noerror)
+	error();
+    newc = skipws(curr);
+    disp = curr;
+    newend = endd;
+    endY = setY(min(newend, pend));
+}
+
+/* join <count> lines together */
+
+VOID PROC
+join(count)
+int count;
+{
+    bool ok;
+    int lp, first;
+    
+    if (lend < bufmax) {	/* are we in the buffer? */
+	disp = lend;				/* start redraw here */
+	newc = lend;
+	do {					/* join until.. */
+	    first = lend;
+	    lp = skipws(1+first);
+	    ok = delete_to_undo(&undo, 1+first, lp-(1+first));
+	    if (ok) {
+		ok = move_to_undo(&undo, first, 1);
+		core[first] = ' ';		/* spaces between lines */
+	    }
+	    count--;
+	    lend = fseekeol(first);
+	} while (ok && count > 0);
+	endY = MAGICNUMBER;
+	newend = lend;
+	if (!ok)
+	    error();
+    }
+    else
+	error();
+}
+
+VOID PROC
+squiggle(endp, c, dorepl)
+int endp;
+char c;
+bool dorepl;
+{
+    int i;
+    
+    if (endp >= curr) {
+	ok = move_to_undo(&undo,curr,endp-curr+1);
+	if (ok) {
+	    for (i = curr;i<=endp;i++) {
+		if (!dorepl) {		/* squiggle it to uc - lc */
+		    if (core[i] >='A' && core[i] <='Z')
+			core[i] += 32;
+		    else if (core[i]>='a' && core[i]<='z')
+			core[i] -= 32;
+		}
+		else
+		    core[i] = c;
+	    }
+	    newend = min(endp+1,lend);
+	}
+    }
+}
+
+VOID PROC
+bigreplace()
+{
+    int len, tsiz;
+    
+    tsiz = lend-curr;
+    if (move_to_undo(&undo, curr, tsiz))
+	if (SIZE - bufmax > tsiz) {	/* enough room for temp copy? */
+	    moveleft(&core[curr], &core[bufmax],lend-curr);
+	    if (line(core, curr, lend, &len) != ESC)
+		error();
+	    newend = curr+len;
+	    moveright(&core[bufmax+len], &core[newend], lend-newend);
+	}
+}
+
+bool PROC
+put(before)
+bool before;
+{
+    endY = setY(curr);
+    if (!before)
+	if (yank.lines)
+	    curr = min(lend+1,bufmax);
+	else
+	    curr = min(curr+1, lend);
+    else if (yank.lines)
+	curr = lstart;
+    newc = disp = curr;
+    return(putback(curr, &newend));
+}
+
+VOID PROC
+gcount()
+{
+    count = 0;
+    while (count>=0 && ch >= '0' && ch <='9') {
+	count = (count*10) + (ch-'0');
+	readchar();		/* get a char to replace the one we dumped */
+    }
+}
+
+VOID PROC
+docommand(cmd)
+cmdtype cmd;
+{
+    cmdtype movecmd;	/* movement command for y, d, c */
+    char    cmdch;
+    int     oldc;	/* old count */
+    int     endp;	/* end position before change */
+    extern bool s_wrapped;
+
+    resetX();				/* un-derange the cursor */
+    oldc = newc = -1;
+    endY = yp;
+    newend = disp = curr;
+    ok = TRUE;				/* so far everything is working */
+    cmdch = ch;
+    if (cmd != UNDO_C && cmd != YANK_C) {
+	if (macro<0)
+	    zerostack(&undo);
+	if (redoing != TRUE) {
+	    rcp = rcb;		/* point at start of redo buffer */
+	    if (count > 1) {	/* put in a count? */
+		numtoa(rcb,count);
+		rcp += strlen(rcb);
+	    }
+	    *rcp++ = cmdch;	/* the command char goes in... */
+	    xerox = TRUE;	/* hoist the magical flags */
+	}
+    }
+
+    if (cmd <= YANK_C) {
+	readchar();
+	if (ch >= '0' && ch <= '9') {
+	    oldc = count;
+	    gcount();				/* get a new count */
+	    if (cmd == ADJUST_C)		/* special for >>,<< wierdness */
+		swap(&count, &oldc);		/* reverse sw & count */
+	    else
+		count = count*max(oldc,1);	/* combine them */
+	}
+	if (ch == cmdch) {		/* diddle lines */
+	    yank.lines = TRUE;
+	    endp = nextline(TRUE, curr, count);
+	    curr = bseekeol(curr);
+	    disp = curr;
+	}
+	else {				/* diddle 'things' */
+	    yank.lines = FALSE;
+	    movecmd = movemap[(unsigned int)ch];
+
+	    if ( (ok = (findCP(curr,&endp,movecmd) == LEGALMOVE)) ) {
+		if (curr > endp) {
+		    swap(&curr,&endp);
+		    ok = (cmd != CHANGE_C);
+		}
+		if (adjcurr[(unsigned int)movecmd])
+		    curr++;
+		if (adjendp[(unsigned int)movecmd])
+		    endp++;
+	    }
+	    if (!ok) {
+		if (ch != ESC)
+		    error();
+		goto killredo;
+	    }
+	}
+	
+	endY = setY(endp);
+	newend = curr;
+	disp = curr;
+	switch (cmd) {
+	    case DELETE_C:
+		ok = deletion(curr, endp);
+		break;
+	    case ADJUST_C:
+		adjuster((cmdch == '<'), endp-1, oldc);
+		break;
+	    case CHANGE_C:
+		if (endp <= pend+1) {
+		    mvcur(setY(endp-1), setX(endp-1));
+		    printch('$');
+		    mvcur(yp, xp);
+		}
+		if (deletion(curr, endp))
+		    ok = ((newend = insertion(1, 0, &disp, &endY, TRUE)) >= 0);
+		else
+		    ok = FALSE;
+		break;
+	    case YANK_C:
+		if (!doyank(curr, endp))
+		    error();
+		return;	/* xerox will not be true, nor will redoing */
+	}
+
+    }
+    else {
+	endp = curr;
+	endY = yp;
+
+	switch (cmd) {
+	    case I_AT_NONWHITE:
+	    case A_AT_END:
+	    case APPEND_C:
+	    case INSERT_C:		/* variations on insert */
+		if (cmd != INSERT_C) {
+		    if (cmd == APPEND_C)
+			curr = min(curr+1, lend);
+		    else if (cmd == A_AT_END)
+			curr = lend;
+		    else /* if (cmd == I_AT_NONWHITE) */
+			curr = skipws(lstart);
+		    xp = setX(curr);
+		    mvcur(yp,xp);
+		}
+		newend = insertion(count, 0, &disp, &endY, TRUE);
+		ok = (newend >= 0);
+		break;
+	    case OPEN_C:
+	    case OPENUP_C:
+		newend = insertion(1,setstep[ (cmd==OPENUP_C)&1 ],
+						&disp,&endY,TRUE)-1;
+		ok = (newend >= 0);
+		break;
+	    case REPLACE_C:
+	    case TWIDDLE_C:
+		if (cmd == REPLACE_C) {
+		    if ((cmdch = readchar()) == ESC)
+			goto killredo;
+		}
+		if (findCP(curr, &endp, GO_RIGHT) == LEGALMOVE)
+		    squiggle(endp-1, cmdch, (cmd==REPLACE_C));
+		break;
+	    case PUT_BEFORE:
+	    case PUT_AFTER:
+		ok = put(cmd==PUT_AFTER);
+		break;
+	    case BIG_REPL_C:
+		bigreplace();
+		break;
+	    case RESUBST_C:
+		ok = FALSE;
+		if (dst[0] != 0) {
+		    newend = chop(curr, &lend, TRUE, &ok);
+		    if (newend >= 0) {
+			endY = setY(newend+strlen(dst));
+			ok = TRUE;
+		    }
+		}
+		break;
+	    case JOIN_C:
+		join(count);		/* join lines */
+		break;
+	    case UNDO_C:			/* undo last modification */
+		ok = fixcore(&newend) >= 0;
+		disp = newend;
+		endY = MAGICNUMBER;
+		break;
+	}
+    }
+
+    if (ok) {
+	setpos((newc<0)?newend:newc);
+	setend();
+	if (curr < ptop || curr > pend) {
+	    yp = settop(12);
+	    redisplay(TRUE);
+	}
+	else {
+	    yp = setY(curr);
+	    if (endY != setY(newend))	/* shuffled lines */
+		refresh(setY(disp), setX(disp), disp, pend, TRUE);
+	    else			/* refresh to end position */
+		refresh(setY(disp), setX(disp), disp, newend, FALSE);
+	}
+	if (curr >= bufmax && bufmax > 0) {	/* adjust off end of buffer */
+	    setpos(bufmax-1);
+	    yp = setY(curr);
+	}
+	if (s_wrapped) {
+	    prompt(FALSE, "search wrapped around end of buffer");
+	    s_wrapped = 0;
+	}
+	else
+	    clrprompt();
+	modified = TRUE;
+    }
+    else {
+	error();
+killredo:
+	rcb[0] = 0;
+    }
+    mvcur(yp, xp);
+    if (xerox)
+	*rcp = 0;	/* terminate the redo */
+    redoing = FALSE;
+    xerox = FALSE;
+    core[bufmax] = EOL;
+}
+
+/* Initialize && execute a macro */
+
+VOID PROC
+exmacro()
+{
+    int mp;
+
+    mp = lookup(ch);
+    if (mp > 0) {
+	if (macro<0)
+	    zerostack(&undo);
+	insertmacro(mbuffer[mp].m_text, count);
+    }
+    else
+	error();
+}
+
+/* redraw the screen w.r.t. the cursor */
+
+VOID PROC
+zdraw(code)
+unsigned char code;
+{
+    int nl = ERR,
+	np = (count>0)?to_index(count):curr;
+
+    if (movemap[code] == CR_FWD)
+	nl = 0;
+    else if (movemap[code] == CR_BACK)
+	nl = LINES-1;
+    else if (code == '.')
+	nl = LINES / 2;
+    if (nl >= 0) {
+	curr = np;
+	yp = settop(nl);
+	redisplay(TRUE);
+	mvcur(yp,xp);
+    }
+    else
+	error();
+}
+
+/* start up a built-in macro */
+
+VOID PROC
+macrocommand()
+{
+    if (count > 1)
+	numtoa(gcb,count);
+    else
+	gcb[0] = 0;
+    switch (ch) { /* which macro? */
+	case 'x':			/* x out characters */
+	    strcat(gcb,"dl"); break;
+	case 'X':			/* ... backwards */
+	    strcat(gcb,"dh"); break;
+	case 's':			/* substitute over chars */
+	    strcat(gcb,"cl"); break;
+	case 'D':			/* delete to end of line */
+	    strcat(gcb,"d$"); break;
+	case 'C':			/* change ... */
+	    strcat(gcb,"c$"); break;
+	case 'Y':			/* yank ... */
+	    strcat(gcb,"y$"); break;
+	case '':			/* scroll up one page */
+	    strcpy(gcb,"22"); break;
+	case '':			/* ... down one page */
+	    strcpy(gcb,"22"); break;
+	case '':			/* scroll up one line */
+	    strcpy(gcb,"1"); break;
+	case '':			/* ... down one line */
+	    strcpy(gcb,"1"); break;
+	default:
+            error();
+            return;
+	break;
+    }
+    if (macro<0)
+	zerostack(&undo);
+    insertmacro(gcb, 1);
+}
+
+/* scroll the window up || down */
+
+VOID PROC
+scroll(down)
+bool down;
+{
+    int i;
+
+    if (count <= 0)
+	count = dofscroll;
+    strput(CURoff);
+    if (down) {
+	curr = min(bufmax-1, nextline(TRUE, curr, count));
+	i = min(bufmax-1, nextline(TRUE, pend, count));
+	if (i > pend)
+	    scrollforward(i);
+    }
+    else {
+	curr = bseekeol(max(0,nextline(FALSE, curr, count)));
+	i = bseekeol(max(0,nextline(FALSE, ptop, count)));
+	if (i < ptop)
+	    if (canUPSCROLL)
+		scrollback(i);
+	    else {
+		ptop = i;
+		setend();
+		redisplay(TRUE);
+	    }
+    }
+    strput(CURon);
+    setpos(skipws(curr));	/* initialize new position - first nonwhite */
+    yp = setY(curr);
+    mvcur(yp, xp);		/* go there */
+}
+
+exec_type PROC
+editcore()
+{
+    cmdtype cmd;
+    extern bool s_wrapped;
+    
+    /* rcb[0] = 0; rcp = rcb; */
+
+    if (diddled) {
+	setpos(skipws(curr));		/* set cursor x position.. */
+	yp = settop(LINES / 2);		/* Y position */
+    }
+    if (diddled || zotscreen)		/* redisplay? */
+	redisplay(FALSE);
+    mvcur(yp, xp);			/* and move the cursor */
+
+    for (;;) {
+	s_wrapped = 0;
+	ch = readchar();			/* get a char */
+	gcount();			/* ... a possible count */
+	switch (cmd = movemap[(unsigned int)ch]) {
+	  case FILE_C:
+	    wr_stat();			/* write file stats */
+	    mvcur(yp, xp);
+	    break;
+
+	  case WINDOW_UP:
+	  case WINDOW_DOWN:
+	    scroll(cmd==WINDOW_UP);		/* scroll the window */
+	    break;
+
+	  case REDRAW_C:			/* redraw the window */
+	    redisplay(TRUE);
+	    mvcur(yp, xp);
+	    break;
+
+	  case MARKER_C:			/* set a marker */
+	    ch = tolower(readchar());
+	    if (ch >= 'a' && ch <= 'z')
+		contexts[ch-'`'] = curr;
+	    else if (ch != ESC)
+		error();
+	    break;
+
+	  case REDO_C:
+	    if (rcb[0] != 0) {
+		zerostack(&undo);
+		insertmacro(rcb, 1);
+		redoing = TRUE;
+	    }
+	    break;
+
+	  case REWINDOW:
+	    zdraw(readchar());		/* shift the window */
+	    break;
+
+	  case DEBUG_C:			/* debugging stuff -- unused */
+	    break;
+
+	  case ZZ_C:			/* shortcut for :xit */
+	    ch = readchar();
+	    if (ch == 'Z')
+		insertmacro(":x\r", 1);
+	    else if (ch != ESC)
+		error();
+	    break;
+
+	  case EDIT_C:		/* drop into line mode */
+	    return E_EDIT;
+
+	  case COLIN_C:		/* do one exec mode command */
+	    return E_VISUAL;
+
+	  case HARDMACRO:
+	    macrocommand();		/* 'hard-wired' macros */
+	    break;
+
+	  case SOFTMACRO:
+	    exmacro();		/* run a macro */
+	    break;
+
+	  case INSMACRO:		/* macro for insert mode */
+	  case BAD_COMMAND:
+	    error();
+	    break;
+
+	  default:
+	    if (cmd < DELETE_C)
+		movearound(cmd);
+	    else /*if (cmd < HARDMACRO)*/
+		docommand(cmd);
+	    break;
+	}
+	lastexec = 0;
+    }
+    /* never exits here */
+}
+/*
+ * LEVEE, or Captain Video;  A vi clone
+ *
+ * Copyright (c) 1982-1997 David L Parsons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, without or
+ * without modification, are permitted provided that the above
+ * copyright notice and this paragraph are duplicated in all such
+ * forms and that any documentation, advertising materials, and
+ * other materials related to such distribution and use acknowledge
+ * that the software was developed by David L Parsons (orc@pell.chi.il.us).
+ * My name may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+#include "levee.h"
+#include "extern.h"
+#include <string.h>
+#include <stdlib.h>
+
+VOID PROC undefine();
+VOID PROC fixupline();
+VOID PROC doinput();
+
+/*
+ * do a newline and set flags.
+ */
+#define exprintln()	(zotscreen=YES),println()
+
+VOID PROC
+plural(num,string)
+int num;
+char *string;
+{
+    printi(num);
+    prints(string);
+    if (num != 1)
+	printch('s');
+} /* plural */
+
+
+VOID PROC
+clrmsg()
+{
+    mvcur(-1,0);
+    strput(CE);
+} /* clrmsg */
+
+
+VOID PROC
+errmsg(msg)
+char *msg;
+{
+    mvcur(-1,0);
+    prints(msg);
+    strput(CE);
+} /* errmsg */
+
+
+/* get a space-delimited token */
+char *execstr;			/* if someone calls getarg in the	*/
+				/* wrong place, death will come...	*/
+char *PROC
+getarg()
+{
+    char *rv;
+    rv = execstr;
+    while (*execstr && !isspace(*execstr))
+	++execstr;
+    if (*execstr) {
+	*execstr++ = 0;
+	while (isspace(*execstr))
+	    ++execstr;
+    }
+    return (*rv) ? rv : NULL;
+} /* getarg */
+
+
+VOID PROC
+version()
+/* version: print which version of levee we are... */
+{
+    errmsg("levee ");prints(ED_NOTICE);printch(ED_REVISION);
+} /* version */
+
+
+VOID PROC
+args()
+/* args: print the argument list */
+{
+    register i;
+    mvcur(-1,0);
+    for (i=0; i < argc; i++) {
+	if (curpos.x+strlen(argv[i]) >= COLS)
+	    exprintln();
+	else if (i > 0)
+	    printch(' ');
+	if (pc == i) {			/* highlight the current filename.. */
+#if ST|FLEXOS
+	    strput("\033p");
+#else
+	    printch('[');
+#endif
+	    prints(argv[i]);
+#if ST|FLEXOS
+	    strput("\033q");
+#else
+	    printch(']');
+#endif
+	}
+	else
+	    prints(argv[i]);
+    }
+} /* args */
+    
+VOID PROC
+setcmd()
+{
+    bool no = NO,b;
+#if 0
+    int len,i;
+#endif
+    char *arg, *num;
+    struct variable *vp;
+    
+    if ( (arg = getarg()) ) {
+	do {
+	    if (*arg != 0) {
+		if ( (num = strchr(arg, '=')) ) {
+		    b = NO;
+		    *num++ = 0;
+		}
+		else {				/* set [no]opt */
+		    b = YES;
+		    if (arg[0]=='n' && arg[1]=='o') {
+			arg += 2;
+			no = NO;
+		    }
+		    else
+			no = YES;
+		}
+		for(vp=vars;vp->u && strcmp(arg,vp->v_name)
+				  && strcmp(arg,vp->v_abbr); vp++)
+		    ;
+		if (!vp->u || vp->v_flags & V_CONST) {
+		    errmsg("Can't set ");
+		    prints(arg);
+		}
+		else {
+		    int j;
+                    
+                    if (b)
+			if (vp->v_tipe == VBOOL)
+			    vp->u->valu = no;
+			else
+			    goto badsettype;
+		    else if (vp->v_tipe == VSTR) {
+			if (vp->u->strp)
+			    free(vp->u->strp);
+			vp->u->strp = (*num) ? strdup(num) : NULL;
+		    }
+		    else
+			if (*num && (j=atoi(num)) >= 0)
+			    vp->u->valu = j;
+			else {
+		  badsettype:
+			    errmsg("bad set type");
+			    continue;
+			}
+		    diddled |= vp->v_flags & V_DISPLAY;
+		}
+	    }
+	} while ( (arg = getarg()) );
+    }
+    else {
+	version(); exprintln();
+	for(vp=vars;vp->u;vp++) {
+	    switch (vp->v_tipe) {
+		case VBOOL:
+		    if (!vp->u->valu)
+			prints("no");
+		    prints(vp->v_name);
+		    break;
+		case VSTR:
+		    if (!vp->u->strp)
+			prints("no ");
+		    prints(vp->v_name);
+		    if (vp->u->strp) {
+			mvcur(-1,10);
+			prints("= ");
+			prints(vp->u->strp);
+		    }
+		    break;
+		default:
+		    prints(vp->v_name);
+		    mvcur(-1,10);
+		    prints("= ");
+		    printi(vp->u->valu);
+		    break;
+	    }
+	    exprintln();
+	}
+    }
+} /* setcmd */
+
+
+/* print a macro */
+VOID PROC
+printone(i)
+int i;
+{
+    if (i >= 0) {
+	exprintln();
+	printch(mbuffer[i].token);
+	mvcur(-1,3);
+	if (movemap[(unsigned int)(mbuffer[i].token)] == INSMACRO)
+	    prints("!= ");
+	else
+	    prints(" = ");
+	prints(mbuffer[i].m_text);
+    }
+} /* printone */
+
+
+/* print all the macros */
+VOID PROC
+printall()
+{
+    int i;
+    for (i = 0; i < MAXMACROS; i++)
+	if (mbuffer[i].token != 0)
+	    printone(i);
+} /* printall */
+
+
+/* :map ch text */
+VOID PROC
+map(insert)
+bool insert;
+{
+    char *macro, c;
+    int i;
+    		/* get the macro */
+    if ((macro=getarg()) == NULL) {
+	printall();
+	return;
+    }
+    if (strlen(macro) > 1) {
+	errmsg("macros must be one character");
+	return;
+    }
+    c = macro[0];
+    if (*execstr == 0)
+	printone(lookup(c));
+    else {
+	if ((i = lookup(0)) < 0)
+	    errmsg("macro table full");
+	else if (c == ESC || c == ':') {
+	    errmsg("can't map ");
+	    printch(c);
+	}
+	else if (*execstr != 0) {
+	    undefine(lookup(c));
+	    mbuffer[i].token = c;
+	    mbuffer[i].m_text = strdup(execstr);
+	    mbuffer[i].oldmap = movemap[(unsigned int)c];
+	    if (insert)
+		movemap[(unsigned int)c] = INSMACRO;
+	    else
+		movemap[(unsigned int)c] = SOFTMACRO;
+	}
+    }
+} /* map */
+
+
+VOID PROC
+undefine(i)
+int i;
+{
+    char *p;
+    if (i >= 0) {
+	movemap[(unsigned int)(mbuffer[i].token)] = mbuffer[i].oldmap;
+	mbuffer[i].token = 0;
+	p = mbuffer[i].m_text;
+	free(p);
+	mbuffer[i].m_text = 0;
+    }
+} /* undefine */
+
+
+int PROC
+unmap()
+{
+    int i;
+    char *arg;
+    
+    if ( (arg=getarg()) ) {
+	if (strlen(arg) == 1) {
+	    undefine(lookup(*arg));
+	    return YES;
+	}
+	if (strcmp(arg,"all") == 0) {
+	    for (i = 0; i < MAXMACROS; i++)
+		if (mbuffer[i].token != 0)
+			undefine(i);
+	    return YES;
+	}
+    }
+    return NO;
+} /* unmap */
+
+
+/* return argument # of a filename */
+int PROC
+findarg(name)
+register char *name;
+{
+    int j;
+    for (j = 0; j < argc; j++)
+	if (strcmp(argv[j],name) == 0)
+	    return j;
+    return -1;
+} /* findarg */
+
+
+/* add a filename to the arglist */
+int PROC
+addarg(name)
+register char *name;
+{
+    int where;
+    if ((where = findarg(name)) < 0)
+	return doaddwork(name, &argc, &argv);
+    return where;
+} /* addarg */
+
+
+/* get a file name argument (substitute alt file for #) */
+char * PROC
+getname()
+{
+    extern int wilderr;
+#if ST
+    extern int mapslash;
+    register char *p;
+#endif
+    register char *name;
+
+    if ( (name = getarg()) ) {
+	if (strcmp(name,"#") == 0)
+	    if (*altnm)
+		name = altnm;
+	    else {
+		errmsg("no alt name");
+		wilderr++;
+		return NULL;
+	    }
+#if ST
+	if (mapslash)
+	    for (p=name; *p; p++)
+		if (*p == '/')
+		    *p = '\\';
+#endif
+    }
+    return name;
+} /* getname */
+
+
+/* CAUTION: these make exec not quite recursive */
+int  high,low;		/* low && high end of command range */
+bool affirm;		/* cmd! */
+/* s/[src]/dst[/options] */
+/* s& */
+VOID PROC
+cutandpaste()
+{
+    bool askme  = NO,
+	 printme= NO,
+	 glob   = NO;
+    int newcurr = -1;
+    int oldcurr = curr;
+    int  num;
+    char delim;
+    register char *ip;
+    register char *dp;
+    
+    zerostack(&undo);
+    ip = execstr;
+    if (*ip != '&') {
+	delim = *ip;
+	ip = makepat(1+ip,delim);			/* get search */
+	if (ip == NULL)
+	    goto splat;
+	dp = dst;
+	while (*ip && *ip != delim) {
+	    if (*ip == '\\' && ip[1] != 0)
+		*dp++ = *ip++;
+	    *dp++ = *ip++;
+	}
+	*dp = 0;
+	if (*ip == delim) {
+	    while (*++ip)
+		switch (*ip) {
+		    case 'q':
+		    case 'c': askme = YES;	break;
+		    case 'g': glob = YES;	break;
+		    case 'p': printme= YES;	break;
+		}
+	}
+    }
+    if (*lastpatt == 0) {
+splat:	errmsg("bad substitute");
+	return;
+    }
+    fixupline(bseekeol(curr));
+    num = 0;
+    do {
+	low = chop(low, &high, NO, &askme);
+	if (low > -1) {
+	    diddled = YES;
+	    num++;
+	    if (printme) {
+		exprintln();
+		writeline(-1,-1,bseekeol(low));
+	    }
+	    if (newcurr < 0)
+		newcurr = low;
+	    if (!glob)
+		low = 1+fseekeol(low);
+	}
+    } while (low >= 0);
+    if (num > 0) {
+	exprintln();
+	plural(num," substitution");
+    }
+    fixupline((newcurr > -1) ? newcurr : oldcurr);
+} /* cutandpaste */
+
+
+VOID PROC
+inputf(fname, newbuf)
+register char *fname;
+bool newbuf;
+{
+    int onright = 0,	/* text moved right for :read */
+	fsize;		/* bytes read in */
+    FILE *f;
+
+
+    if (newbuf)
+	readonly = NO;
+
+    zerostack(&undo);
+    if (newbuf) {
+	modified = NO;
+	low = 0;
+	high = SIZE;
+    }
+    else {		/* append stuff to the buffer */
+	fixupline(bseekeol(curr));
+	onright = bufmax-low;
+#if MSDOS
+	high = SIZE;
+	high -= onright;
+#else
+	high = (SIZE-onright);
+#endif
+	if (onright > 0)
+	    moveright(&core[low], &core[high], onright);
+    }
+    printch('"');
+    prints(fname);
+    prints("\" ");
+    if ((f=fopen(fname, "r")) == NULL) {
+	prints("[No such file]");
+	fsize = 0;
+	if (newbuf)
+	    newfile = YES;
+    }
+    else {
+	if (addfile(f, low, high, &fsize))
+	    plural(fsize," byte");
+	else if (fsize < 0) {
+	    prints("[read error]");
+	    fsize = 0;
+	}
+	else {
+	    prints("[overflow]");
+	    readonly = YES;
+	}
+	fclose(f);
+	if (newbuf)
+	    newfile = NO;
+    }
+    if (newbuf) {
+	fillchar(contexts, sizeof(contexts), -1);
+	bufmax = fsize;
+    }
+    else {
+	insert_to_undo(&undo, low, fsize);
+	modified = YES;
+	if (onright > 0)
+	    moveleft(&core[high], &core[low+fsize], onright);
+    }
+    if (*startcmd) {
+	count = 1;
+	if (*findparse(startcmd,&curr,low) != 0 || curr < 0)
+	    curr = low;
+	*startcmd = 0;
+    }
+    else
+	curr = low;
+    diddled = YES;
+} /* inputf */
+
+
+/* Change a file's name (for autocopy). */
+VOID PROC
+backup(name)
+char *name;
+{
+    char back[80];
+#if !UNIX
+    char *p;
+#endif
+
+    strcpy(back, name);
+#if UNIX
+    strcat(back, "~");
+#else
+    p = strrchr(basename(back), '.');
+    if (p)
+	strcpy(1+p, ",bkp");
+    else
+	strcat(back, ".bkp");
+#endif
+    
+    unlink(back);
+    rename(name, back);
+} /* backup */
+
+
+bool PROC
+outputf(fname)
+char *fname;
+{
+    bool whole;
+    FILE *f;
+    int status;
+    zerostack(&undo);		/* undo doesn't survive past write */
+    if (high < 0)
+	high = (low < 0) ? bufmax : (1+fseekeol(low));
+    if (low < 0)
+	low  = 0;
+    printch('"');
+    prints(fname);
+    prints("\" ");
+    whole = (low == 0 && high >= bufmax-1);
+    if (whole && autocopy)
+	backup(fname);
+    if ( (f=fopen(fname, "w")) ) {
+	status = putfile(f, low, high);
+	fclose(f);
+	if (status) {
+	    plural(high-low," byte");
+	    if (whole)
+		modified = NO;
+	    return(YES);
+	}
+	else {
+	    prints("[write error]");
+	    unlink(fname);
+	}
+    }
+    else
+	prints(fisro);
+    return(NO);
+} /* outputf */
+
+
+int PROC
+oktoedit(writeold)
+/* check and see if it is ok to edit a new file */
+int writeold;	/* automatically write out changes? */
+{
+    if (modified && !affirm)
+	if (readonly) {
+	    errmsg(fisro);
+	    return NO;
+	}
+	else if (writeold && *filenm) {
+	    if (!outputf(filenm))
+		return NO;
+	    printch(',');
+	}
+	else {
+	    errmsg(fismod);
+	    return NO;
+	}
+    return YES;
+} /* oktoedit */
+
+
+/* write out all || part of a file */
+bool PROC
+writefile()
+{
+    char *name;
+    
+    if ((name=getname()) == NULL)
+	name = filenm;
+    if (*name) {
+	if (outputf(name)) {
+	    addarg(name);
+	    return YES;
+	}
+	else
+	    strcpy(altnm, name);
+    }
+    else
+	errmsg("no file to write");
+    return NO;
+}
+
+
+VOID PROC
+editfile()
+{
+    char *name = NULL;	/* file to edit */
+    char **myargv;
+    int myargc;
+    int i, newpc;
+    if ((name = getarg()) && *name == '+') {
+	strcpy(startcmd, (name[1])?(1+name):"$");
+	name = getarg();
+    }
+    myargc=0;
+    if (name)
+	do {
+	    if (!expandargs(name, &myargc, &myargv))
+		return;
+	} while ( (name=getarg()) );
+    if (myargc == 0) {
+	if (*filenm)
+	    name = filenm;
+	else
+	    errmsg("no file to edit");
+    }
+    else if ((newpc = addarg(myargv[0])) >= 0) {
+	name = argv[pc = newpc];
+	for (i=1; i < myargc && doaddwork(myargv[i], &argc, &argv) >= 0; i++)
+	    ;
+    }
+    killargs(&myargc, &myargv);
+    if (name && oktoedit(NO))
+	doinput(name);
+}
+
+
+VOID PROC
+doinput(name)
+char *name;
+{
+    inputf(name, YES);
+    strcpy(altnm, filenm);
+    strcpy(filenm, name);
+}
+
+
+VOID PROC
+toedit(count)
+int count;
+{
+    if (count > 1) {
+	printi(count);
+	prints(" files to edit; ");
+    }
+}
+
+
+VOID PROC
+readfile()
+{
+    char *name;
+    
+    if ( (name=getarg()) )
+	inputf(name,NO);
+    else
+	errmsg("no file to read");
+}
+
+
+VOID PROC
+nextfile(prev)
+bool prev;
+{
+    char *name = NULL;
+    int newpc=pc,
+	myargc=0;
+    char **myargv;
+    bool newlist = NO;
+    
+    if (prev == 0)
+	while ( (name=getarg()) )
+	    if (!expandargs(name, &myargc, &myargv))
+		return;
+    
+    if (oktoedit(autowrite)) {
+	if (prev || (myargc == 1 && strcmp(myargv[0],"-") == 0)) {
+	    if (pc > 0) {
+		newpc = pc-1;
+	    }
+	    else {
+		prints("(no prev files)");
+		goto killem;
+	    }
+	}
+	else if (myargc == 0) {
+	    if (pc < argc-1) {
+		newpc = 1+pc;
+	    }
+	    else {
+		prints("(no more files)");
+		goto killem;
+	    }
+	}
+	else if (myargc > 1 || (newpc = findarg(myargv[0])) < 0) {
+	    toedit(myargc);
+	    newpc = 0;
+	    newlist++;
+	}
+	doinput(newlist ? myargv[0] : argv[newpc]);
+	pc = newpc;
+	if (newlist) {
+	    killargs(&argc, &argv);
+	    argc = myargc;
+	    argv = myargv;
+	}
+	else
+    killem: if (!prev)
+		killargs(&myargc, &myargv);
+    }
+}
+
+
+/*
+ * set up low, high; set dot to low
+ */
+VOID PROC
+fixupline(dft)
+int dft;
+{
+    if (low < 0)
+	low = dft;
+    if (high < 0)
+	high = fseekeol(low)+1;
+    else if (high < low) {		/* flip high & low */
+	int tmp;
+	tmp = high;
+	high = low;
+	low = tmp;
+    }
+    if (low >= ptop && low < pend) {
+	setpos(skipws(low));
+	yp = setY(curr);
+    }
+    else {
+	curr = low;
+	diddled = YES;
+    }
+}
+
+
+VOID PROC
+whatline()
+{
+    printi(to_line((low < 0) ? (bufmax-1) : low));
+    if (high >= 0) {
+	printch(',');
+	printi(to_line(high));
+    }
+}
+
+
+VOID PROC
+print()
+{
+    do {
+	exprintln();
+	writeline(-1, 0, low);
+	low = fseekeol(low) + 1;
+    } while (low < high);
+    exprintln();
+}
+
+/* move to different line */
+/* execute lines from a :sourced || .lvrc file */
+
+
+bool PROC
+do_file(fname,mode,noquit)
+char *fname;
+exec_type *mode;
+bool *noquit;
+{
+    char line[120];
+    FILE *fp, *fopen();
+    
+    if ((fp = fopen(fname,"r")) != NULL) {
+	indirect = YES;
+	while (fgets(line,120,fp) && indirect) {
+	    strtok(line, "\n");
+	    if (*line != 0)
+		exec(line,mode,noquit);
+	}
+	indirect = YES;
+	fclose(fp);
+	return YES;
+    }
+    return NO;
+}
+
+
+VOID PROC
+doins(flag)
+bool flag;
+{
+    int i;
+    curr = low;
+    exprintln();
+    low = insertion(1,setstep[flag],&i,&i,NO)-1;
+    if (low >= 0)
+	curr = low;
+    diddled = YES;
+}
+
+
+/* figure out a address range for a command */
+char * PROC
+findbounds(ip)
+char *ip;
+{
+    ip = findparse(ip, &low, curr);	/* get the low address */
+    if (low >= 0) {
+	low = bseekeol(low);		/* at start of line */
+	if (*ip == ',') {		/* high address? */
+	    ip++;
+	    count = 0;
+	    ip = findparse(ip, &high, curr);
+	    if (high >= 0) {
+		high = fseekeol(high);
+		return(ip);
+	    }
+	}
+	else
+	    return(ip);
+    }
+    return(0);
+}
+
+
+/* parse the command line for lineranges && a command */
+int PROC
+parse(inp)
+char *inp;
+{
+    int j,k;
+    char cmd[80];
+    low = high = ERR;
+    affirm = 0;
+    if (*inp == '%') {
+	moveright(inp, 2+inp, 1+strlen(inp));
+	inp[0]='1';
+	inp[1]=',';
+	inp[2]='$';
+    }
+    while (isspace(*inp))
+	++inp;
+    if (strchr(".$-+0123456789?/`'", *inp))
+	if (!(inp=findbounds(inp))) {
+	    errmsg("bad address");
+	    return ERR;
+	}
+    while (isspace(*inp))
+	++inp;
+    j = 0;
+    while (isalpha(*inp))
+	cmd[j++] = *inp++;
+    if (*inp == '!') {
+	if (j == 0)
+	    cmd[j++] = '!';
+	else
+	    affirm++;
+	inp++;
+    }
+    else if (*inp == '=' && j == 0)
+	cmd[j++] = '=';
+    while (isspace(*inp))
+	++inp;
+    execstr = inp;
+    if (j==0)
+	return EX_CR;
+    for (k=0; excmds[k]; k++)
+	if (strncmp(cmd, excmds[k], j) == 0)
+	    return k;
+    return ERR;
+}
+
+
+/* inner loop of execmode */
+VOID PROC
+exec(cmd, mode, noquit)
+char *cmd;
+exec_type *mode;
+bool *noquit;
+{
+    int  what;