[comp.sources.amiga] v89i043: stevie - vi-like text editor v35a, Part04/06

page@swan.ulowell.edu (Bob Page) (03/15/89)

Submitted-by: grwalter@watcgl.waterloo.edu (Fred Walter)
Posting-number: Volume 89, Issue 43
Archive-name: editors/stevie35a.4

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	cmdline.c
#	regexp.cat.uu
#	stevie.doc
# This archive created: Tue Mar 14 14:42:06 1989
cat << \SHAR_EOF > cmdline.c
/*
 * STEVIE - Simply Try this Editor for VI Enthusiasts
 *
 * Code Contributions By : Tim Thompson           twitch!tjt
 *                         Tony Andrews           onecom!wldrdg!tony 
 *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
 */

#include "stevie.h"

static char    *altfile = NULL;	/* alternate file */
static int      altline;	/* line # in alternate file */

static char    *nowrtmsg = "No write since last change (use ! to override)";

extern char   **files;		/* used for "n" and "rew" */
extern int      curfile;
extern int      numfiles;

/*
 * The next two variables contain the bounds of any range given in a command.
 * If no range was given, both contain null line pointers. If only a single
 * line was given, u_pos will contain a null line pointer. 
 */
static LPtr     l_pos, u_pos;

static bool_t   interactive;	/* TRUE if we're reading a real command line */

static bool_t   doecmd();
static void
badcmd(), doshell(), get_range();
static LPtr    *get_line();

#ifdef	MEGAMAX
overlay "cmdline"
#endif

/*
 * readcmdline() - accept a command line starting with ':', '/', or '?' 
 *
 * readcmdline() accepts and processes colon commands and searches. If
 * 'cmdline' is null, the command line is read here. Otherwise, cmdline
 * points to a complete command line that should be used. This is used in
 * main() to handle initialization commands in the environment variable
 * "EXINIT". 
 */
void
readcmdline(firstc, cmdline)
    char            firstc;	/* either ':', '/', or '?' */
    char           *cmdline;	/* optional command string */
{
    char            c;
    char            buff[CMDBUFFSIZE];
    char            cmdbuf[CMDBUFFSIZE];
    char            argbuf[CMDBUFFSIZE];
    char           *p, *q, *cmd, *arg;
    bool_t          literal_next_flag = FALSE;

    /*
     * Clear the range variables. 
     */
    l_pos.linep = (LINE *) NULL;
    u_pos.linep = (LINE *) NULL;

    interactive = (cmdline == NULL);

    if (interactive)
	gotocmdline(YES, firstc);
    p = buff;
    if (firstc != ':')
	*p++ = firstc;

    if (interactive) {
	/* collect the command string, handling '\b' and @ */
	for (;;) {
	    c = vgetc();
	    if (c == CTRL('V') && !literal_next_flag) {
		literal_next_flag = TRUE;
		outchar('^');
		continue;
	    }
	    if (c == '\n' || ((c == '\r' || c == ESC) && (!literal_next_flag)))
		break;
	    if ((c == '\b') && (!literal_next_flag)) {
		if (p > buff + (firstc != ':')) {
		    p--;
		    /*
		     * this is gross, but it relies only on 'gotocmdline' 
		     */
		    gotocmdline(YES, firstc == ':' ? ':' : NUL);
		    for (q = buff; q < p; q++)
			outstr(chars[*q].ch_str);
		} else {
		    msg("");
		    return;	/* back to cmd mode */
		}
		continue;
	    }
	    if ((c == '@') && (!literal_next_flag)) {
		p = buff;
		gotocmdline(YES, firstc);
		continue;
	    }
	    if (literal_next_flag) {
		literal_next_flag = FALSE;
		outchar('\b');
	    }
	    outstr(chars[c].ch_str);
	    *p++ = c;
	}
	*p = '\0';
    } else {
	if (strlen(cmdline) > CMDBUFFSIZE - 2)	/* should really do something
						 * better here... */
	    return;
	strcpy(p, cmdline);
    }

    /* skip any initial white space */
    for (cmd = buff; *cmd != NUL && isspace(*cmd); cmd++);

    /* search commands */
    c = *cmd;
    if (c == '/' || c == '?') {
	cmd++;
	/* was the command was '//' or '??' (I.E. repeat last search) */
	if ((*cmd == c) || (*cmd == NUL)) {
	    if (c == '/')
		searchagain(FORWARD);
	    else
		searchagain(BACKWARD);
	    return;
	}
	/* If there is a matching '/' or '?' at the end, toss it */
	p = strchr(cmd, NUL);
	if (*(p - 1) == c && *(p - 2) != '\\')
	    *(p - 1) = NUL;
	dosearch((c == '/') ? FORWARD : BACKWARD, cmd);
	return;
    }
    /*
     * Parse a range, if present (and update the cmd pointer). 
     */
    get_range(&cmd);
    if (l_pos.linep != NULL) {
	if (LINEOF(&l_pos) > LINEOF(&u_pos)) {
	    emsg("Invalid range");
	    return;
	}
    }
    strcpy(cmdbuf, cmd);	/* save the unmodified command */

    /* isolate the command and find any argument */
    for (p = cmd; *p != NUL && !isspace(*p); p++);
    if (*p == NUL)
	arg = NULL;
    else {
	*p = NUL;
	for (p++; *p != NUL && isspace(*p); p++);
	if (*p == NUL) {
	    arg = NULL;
	} else {
	    strcpy(argbuf, p);
	    arg = argbuf;
	}
    }

    if (strcmp(cmd, "q!") == 0)
	getout(0);
    if (strcmp(cmd, "q") == 0) {
	if (Changed)
	    emsg(nowrtmsg);
	else
	    getout(0);
	return;
    }
    if (strcmp(cmd, "w") == 0) {
	if (arg == NULL) {
	    if (Filename != NULL) {
		writeit(Filename, &l_pos, &u_pos);
		UNCHANGED;
	    } else
		emsg("No output file");
	} else
	    writeit(arg, &l_pos, &u_pos);
	return;
    }
    if (strcmp(cmd, "wq") == 0) {
	if (Filename != NULL) {
	    if (writeit(Filename, (LPtr *) NULL, (LPtr *) NULL))
		getout(0);
	} else
	    emsg("No output file");
	return;
    }
    if (strcmp(cmd, "x") == 0) {
	if (Changed) {
	    if (Filename != NULL) {
		if (!writeit(Filename, (LPtr *) NULL, (LPtr *) NULL))
		    return;
	    } else {
		emsg("No output file");
		return;
	    }
	}
	getout(0);
    }
    if (strcmp(cmd, "f") == 0 && arg == NULL) {
	fileinfo();
	return;
    }
    if (*cmd == 'n') {
	if ((curfile + 1) < numfiles) {
	    /*
	     * stuff ":e[!] FILE\n" 
	     */
	    stuffReadbuff(":e");
	    if (cmd[1] == '!')
		stuffReadbuff("!");
	    stuffReadbuff(" ");
	    stuffReadbuff(files[++curfile]);
	    stuffReadbuff("\n");
	} else
	    emsg("No more files!");
	return;
    }
    if (*cmd == 'p') {
	if (curfile > 0) {
	    /*
	     * stuff ":e[!] FILE\n" 
	     */
	    stuffReadbuff(":e");
	    if (cmd[1] == '!')
		stuffReadbuff("!");
	    stuffReadbuff(" ");
	    stuffReadbuff(files[--curfile]);
	    stuffReadbuff("\n");
	} else
	    emsg("No more files!");
	return;
    }
    if (strncmp(cmd, "rew", 3) == 0) {
	if (numfiles <= 1)	/* nothing to rewind */
	    return;
	curfile = 0;
	/*
	 * stuff ":e[!] FILE\n" 
	 */
	stuffReadbuff(":e");
	if (cmd[3] == '!')
	    stuffReadbuff("!");
	stuffReadbuff(" ");
	stuffReadbuff(files[0]);
	stuffReadbuff("\n");
	return;
    }
    if (strcmp(cmd, "e") == 0 || strcmp(cmd, "e!") == 0) {
	doecmd(arg, cmd[1] == '!');
	return;
    }
    if (strcmp(cmd, "f") == 0) {
	Filename = strsave(arg);
	filemess("");
	return;
    }
    if (strcmp(cmd, "r") == 0 || strcmp(cmd, ".r") == 0) {
	if (arg == NULL) {
	    badcmd();
	    return;
	}
	if (readfile(arg, Curschar, 1)) {
	    emsg("Can't open file");
	    return;
	}
	updateNextscreen(NOT_VALID);
	CHANGED;
	return;
    }
    if (strcmp(cmd, ".=") == 0) {
	smsg("line %d", cntllines(Filemem, Curschar));
	return;
    }
    if (strcmp(cmd, "$=") == 0) {
	smsg("%d", cntllines(Filemem, Fileend) - 1);
	return;
    }
    if (strncmp(cmd, "ta", 2) == 0) {
	dotag(arg, cmd[2] == '!');
	return;
    }
    if (strcmp(cmd, "set") == 0) {
	doset(arg, interactive);
	return;
    }
    if (strcmp(cmd, "help") == 0) {
	if (help()) {
	    screenclear();
	    updateNextscreen(NOT_VALID);
	}
	return;
    }
    if (strcmp(cmd, "version") == 0) {
	extern char    *Version;

	msg(Version);
	return;
    }
    if (strcmp(cmd, "sh") == 0) {
	doshell();
	return;
    }
    if (strncmp(cmd, "d", 1) == 0) {
	LINE           *cp;
	int             n;

	if (l_pos.linep == NULL)
	    l_pos = *Curschar;
	if (u_pos.linep == NULL)
	    u_pos = l_pos;

	ResetBuffers();
	n = RowNumber(&l_pos);
	AppendPositionToUndoUndobuff(0, n);
	AppendPositionToUndobuff(0, n);
	if ((Filetop->linep->next == l_pos.linep) &&
	    (u_pos.linep->next == Fileend->linep))
	    AppendToUndobuff("a");
	else if (u_pos.linep->next == Fileend->linep)
	    AppendToUndobuff("o");
	else
	    AppendToUndobuff("O");

	n = 0;
	cp = l_pos.linep;
	for (; cp != NULL && cp != Fileend->linep; cp = cp->next) {
	    AppendToUndobuff(cp->s);
	    n++;
	    if (cp == u_pos.linep)
		break;
	    AppendToUndobuff(NL_STR);
	}
	AppendToUndobuff(ESC_STR);

	if (n > 1)
	    AppendNumberToUndoUndobuff(n);
	AppendToUndoUndobuff("dd");

	*Curschar = l_pos;
	delline(n, FALSE);
	updateNextscreen(NOT_VALID);
	MustRedrawScreen = TRUE;/* Shouldn't have to do this. */
	return;
    }
    if (strncmp(cmd, "s/", 2) == 0) {
	dosub(&l_pos, &u_pos, cmdbuf + 1);
	return;
    }
    if (strncmp(cmd, "g/", 2) == 0) {
	doglob(&l_pos, &u_pos, cmdbuf + 1);
	return;
    }
    /*
     * If we got a line, but no command, then go to the line. 
     */
    if (*cmd == NUL && l_pos.linep != NULL) {
	if (u_pos.linep != NULL)
	    *Curschar = u_pos;
	else
	    *Curschar = l_pos;
	cursupdate();
	return;
    }
    badcmd();
}

/*
 * get_range - parse a range specifier 
 *
 * Ranges are of the form: 
 *
 * addr[,addr] 
 *
 * where 'addr' is: 
 *
 * %          (entire file)
 * $  [+-NUM]
 * 'x [+-NUM] (where x denotes a currently defined mark)
 * .  [+-NUM]
 * NUM 
 *
 * The pointer *cp is updated to point to the first character following the
 * range spec. If an initial address is found, but no second, the upper bound
 * is equal to the lower. 
 */
static void
get_range(cp)
    char          **cp;
{
    LPtr           *l;
    char           *p;

    if (**cp == '%') {
	l_pos.index = 0;
	l_pos.linep = Filetop->linep->next;
	u_pos.index = 0;
	u_pos.linep = Fileend->linep->prev;
	(*cp)++;
	return;
    }
    if ((l = get_line(cp)) == NULL)
	return;

    l_pos = *l;

    for (p = *cp; *p != NUL && isspace(*p); p++);

    *cp = p;

    if (*p != ',') {		/* is there another line spec ? */
	u_pos = l_pos;
	return;
    }
    *cp = ++p;

    if ((l = get_line(cp)) == NULL) {
	u_pos = l_pos;
	return;
    }
    u_pos = *l;
}

static LPtr    *
get_line(cp)
    char          **cp;
{
    static LPtr     pos;
    LPtr           *lp;
    char           *p, c;
    int             lnum;

    pos.index = 0;		/* shouldn't matter... check back later */

    p = *cp;
    /*
     * Determine the basic form, if present. 
     */
    switch (c = *p++) {

      case '$':
	pos.linep = Fileend->linep->prev;
	break;

      case '.':
	pos.linep = Curschar->linep;
	break;

      case '\'':
	if ((lp = getmark(*p++)) == NULL) {
	    emsg("Unknown mark");
	    return (LPtr *) NULL;
	}
	pos = *lp;
	break;

      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
	for (lnum = c - '0'; isdigit(*p); p++)
	    lnum = (lnum * 10) + (*p - '0');

	if (lnum == 0)
	    lnum = 1;

	pos = *gotoline(lnum);
	break;

      default:
	return (LPtr *) NULL;
    }

    while (*p != NUL && isspace(*p))
	p++;

    if (*p == '-' || *p == '+') {
	bool_t          neg = (*p++ == '-');

	for (lnum = 0; isdigit(*p); p++)
	    lnum = (lnum * 10) + (*p - '0');

	if (neg)
	    lnum = -lnum;

	pos = *gotoline(cntllines(Filemem, &pos) + lnum);
    }
    *cp = p;
    return &pos;
}

static void
badcmd()
{
    if (interactive)
	emsg("Unrecognized command");
}

/*
 * dotag(tag, force) - goto tag 
 */
void
dotag(tag, force)
    char           *tag;
    bool_t          force;
{
    FILE           *tp, *fopen();
    char            lbuf[LSIZE];
    char           *fname, *str;

    if ((tp = fopen("tags", "r")) == NULL) {
	emsg("Can't open tags file");
	return;
    }
    while (fgets(lbuf, LSIZE, tp) != NULL) {

	if ((fname = strchr(lbuf, TAB)) == NULL) {
	    emsg("Format error in tags file");
	    return;
	}
	*fname++ = '\0';
	if ((str = strchr(fname, TAB)) == NULL) {
	    emsg("Format error in tags file");
	    return;
	}
	*str++ = '\0';

	if (strcmp(lbuf, tag) == 0) {
	    if (!force && Changed) {
		emsg(nowrtmsg);
		return;
	    }
	    if (doecmd(fname, force)) {
		stuffReadbuff(str);	/* str has \n at end */
		stuffReadbuff("\007");	/* CTRL('G') */
		fclose(tp);
		return;
	    }
	}
    }
    emsg("tag not found");
    fclose(tp);
}

static          bool_t
doecmd(arg, force)
    char           *arg;
    bool_t          force;
{
    int             line = 1;	/* line # to go to in new file */

    if (!force && Changed) {
	emsg(nowrtmsg);
	return FALSE;
    }
    if (arg != NULL) {
	/*
	 * First detect a ":e" on the current file. This is mainly for ":ta"
	 * commands where the destination is within the current file. 
	 */
	if (Filename != NULL && strcmp(arg, Filename) == 0) {
	    if (!Changed || (Changed && !force))
		return TRUE;
	}
	if (strcmp(arg, "#") == 0) {	/* alternate */
	    char           *s = Filename;

	    if (altfile == NULL) {
		emsg("No alternate file");
		return FALSE;
	    }
	    Filename = altfile;
	    altfile = s;
	    line = altline;
	    altline = cntllines(Filemem, Curschar);
	} else {
	    altfile = Filename;
	    altline = cntllines(Filemem, Curschar);
	    Filename = strsave(arg);
	}
    }
    if (Filename == NULL) {
	emsg("No filename");
	return FALSE;
    }
    /* clear mem and read file */
    freeall();
    filealloc();
    UNCHANGED;

    readfile(Filename, Filemem, 0);
    *Topchar = *Curschar;
    if (line != 1) {
	stuffnumReadbuff(line);
	stuffReadbuff("G");
    }
    setpcmark();
    updateNextscreen(NOT_VALID);
    return TRUE;
}

static void
doshell()
{
    char           *sh, *getenv();

    sh = getenv("SHELL");
    if (sh == NULL) {
	emsg("Shell variable not set");
	return;
    }
    gotocmdline(YES, NUL);

    if (system(sh) < 0) {
	emsg("Exec failed");
	return;
    }
    wait_return();
}

void
gotocmdline(clr, firstc)
    bool_t          clr;
    char            firstc;
{
    windgoto(Rows - 1, 0);
    if (clr)
	outstr(T_EL);		/* clear the bottom line */
    if (firstc)
	outchar(firstc);
}

/*
 * msg(s) - displays the string 's' on the status line 
 */
void
msg(s)
    char           *s;
{
    gotocmdline(YES, NUL);
    outstr(s);
#ifdef AMIGA
    flushbuf();
#endif
#ifdef BSD
    fflush(stdout);
#endif
}

/* VARARGS */
void
smsg(s, a1, a2, a3, a4, a5, a6, a7, a8, a9)
    char           *s;
    int             a1, a2, a3, a4, a5, a6, a7, a8, a9;
{
    char            sbuf[MAX_COLUMNS + 1];

    sprintf(sbuf, s, a1, a2, a3, a4, a5, a6, a7, a8, a9);
    msg(sbuf);
}

/*
 * emsg() - display an error message 
 *
 * Rings the bell, if appropriate, and calls message() to do the real work 
 */
void
emsg(s)
    char           *s;
{
    UndoInProgress = FALSE;
    RedrawingDisabled = FALSE;

    if (P(P_EB))
	beep();
    outstr(T_TI);
    msg(s);
    outstr(T_TP);
#ifdef AMIGA
    flushbuf();
#endif
#ifdef BSD
    fflush(stdout);
#endif
}

void
wait_return()
{
    char            c;

    outstr("Press RETURN to continue");
    do {
	c = vgetc();
    } while (c != '\r' && c != '\n');

    screenclear();
    updateNextscreen(NOT_VALID);
}
SHAR_EOF
cat << \SHAR_EOF > regexp.cat.uu

begin 644 regexp.cat
M"@H*"E)%1T584"@S*2`@("`@("`@("`@("`@("!,:6)R87)Y($9U;F-T:6]NR
M<R`@("`@("`@("`@("`@(%)%1T584"@S*0H*"@I."$Y!"$%-"$U%"$4*("`@6
M("!R96=C;VUP+"!R96=E>&5C+"!R96=S=6(L(')E9V5R<F]R("T@<F5G=6QA1
M<B!E>'!R97-S:6]N"B`@("`@:&%N9&QE<@H*4PA360A93@A.3PA/4`A04PA3&
M20A)4PA3"B`@("`@(P@C:0AI;@AN8PAC;`AL=0AU9`AD90AE(#P(/'((<F4(Y
M96<(9V4(97@(>'`(<"X(+F@(:#X(/@H*("`@("!R"')E"&5G"&=E"&5X"'APO
M"'`@*@@J<@AR90AE9PAG8PAC;PAO;0AM<`AP*`@H90AE>`AX<`AP*0@I"B`@T
M("`@8PAC:`AH80AA<@AR("H(*F4(97@(>'`(<#L(.PH*("`@("!I"&EN"&YT.
M"'0@<@AR90AE9PAG90AE>`AX90AE8PAC*`@H<`AP<@AR;PAO9PAG+`@L(',(]
M<W0(='((<FD(:6X(;F<(9RD(*0H@("`@('((<F4(96<(9V4(97@(>'`(<"`JW
M""IP"'!R"')O"&]G"&<["#L*("`@("!C"&-H"&AA"&%R"'(@*@@J<PAS=`AT@
M<@AR:0AI;@AN9PAG.P@["@H@("`@('((<F4(96<(9W,(<W4(=6((8B@(*'`("
M<'((<F\(;V<(9RP(+"!S"'-O"&]U"'5R"')C"&-E"&4L""P@9`AD90AE<PASZ
M=`AT*0@I"B`@("`@<@AR90AE9PAG90AE>`AX<`AP("H(*G`(<'((<F\(;V<(?
M9SL(.PH@("`@(&,(8V@(:&$(87((<B`J""IS"'-O"&]U"'5R"')C"&-E"&4[T
M"#L*("`@("!C"&-H"&AA"&%R"'(@*@@J9`AD90AE<PAS=`AT.P@["@H@("`@7
M('((<F4(96<(9V4(97((<G((<F\(;W((<B@(*&T(;7,(<V<(9RD(*0H@("`@2
M(&,(8V@(:&$(87((<B`J""IM"&US"'-G"&<["#L*"D0(1$4(15,(4T,(0U((H
M4DD(25`(4%0(5$D(24\(3TX(3@H@("`@(%1H97-E(&9U;F-T:6]N<R!I;7!L6
M96UE;G0*("`@("!?"&5?"&=?"')?"&5?"'`H,2DM<W1Y;&4*("`@("!R96=U6
M;&%R(&5X<')E<W-I;VYS(&%N9"!S=7!P;W)T:6YG(&9A8VEL:71I97,N"@H@/
M("`@(%\(4E\(95\(9U\(8U\(;U\(;5\(<`H@("`@(&-O;7!I;&5S(&$@<F5G#
M=6QA<B!E>'!R97-S:6]N(&EN=&\@82!S=')U8W1U<F4@;V8@='EP90H@("`@Q
M(%\(<E\(95\(9U\(95\(>%\(<"P*("`@("!A;F0@<F5T=7)N<R!A('!O:6YT<
M97(@=&\@:70N"B`@("`@5&AE('-P86-E(&AA<R!B965N(&%L;&]C871E9"!UP
M<VEN9PH@("`@(%\(;5\(85\(;%\(;%\(;U\(8R@S*0H@("`@(&%N9"!M87D@E
M8F4@<F5L96%S960@8GD*("`@("!?"&9?"')?"&5?"&4N"@H@("`@(%\(4E\(1
M95\(9U\(95\(>%\(95\(8PH@("`@(&UA=&-H97,@82!.54PM=&5R;6EN871E)
M9"!?"'-?"'1?"')?"&E?"&Y?"&<@86=A:6YS="!T:&4@8V]M<&EL960@<F5GX
M=6QA<B!E>'!R97-S:6]N"B`@("`@:6X@7PAP7PAR7PAO7PAG+@H@("`@($ETN
M(')E='5R;G,@,2!F;W(@<W5C8V5S<R!A;F0@,"!F;W(@9F%I;'5R92P@86YD5
M(&%D:G5S=',@=&AE(&-O;G1E;G1S(&]F"B`@("`@7PAP7PAR7PAO7PAG)W,@Z
M7PAS7PAT7PAA7PAR7PAT7PAP(&%N9"!?"&5?"&Y?"&1?"'`@*'-E92!B96QO%
M=RD@86-C;W)D:6YG;'DN"@H@("`@(%1H92!M96UB97)S(&]F(&$*("`@("!?<
M"')?"&5?"&=?"&5?"'A?"'`*("`@("!S=')U8W1U<F4@:6YC;'5D92!A="!LV
M96%S="!T:&4@9F]L;&]W:6YG("AN;W0@;F5C97-S87)I;'D@:6X@;W)D97(IV
M.@H*("`@("`@("`@(&-H87(@*G-T87)T<%M.4U5"15A073L*("`@("`@("`@6
M(&-H87(@*F5N9'!;3E-50D584%T["@H@("`@('=H97)E"B`@("`@7PA.7PA3O
M7PA57PA"7PA%7PA87PA0"B`@("`@:7,@9&5F:6YE9"`H87,@,3`I(&EN('1HU
M92!H96%D97(@9FEL92X*"@H*1F]R;6%T=&5D(#@X+S$R+S,P("`@("`@("`@^
M("`@;&]C86P@("`@("`@("`@("`@("`@("`@("`@("`@("`@(#$*#`H*"@I2,
M14=%6%`H,RD@("`@("`@("`@("`@("`@3&EB<F%R>2!&=6YC=&EO;G,@("`@K
M("`@("`@("`@("!214=%6%`H,RD*"@H*("`@("!/;F-E(&$@<W5C8V5S<V9UQ
M;"!?"')?"&5?"&=?"&5?"'A?"&5?"&,@:&%S(&)E96X@9&]N92!U<VEN9R!TV
M:&4@7PAR7PAE7PAG7PAE7PAX7PAP+`H@("`@(&5A8V@@7PAS7PAT7PAA7PAR_
M7PAT7PAP+5\(95\(;E\(9%\(<"!P86ER(&1E<V-R:6)E<R!O;F4@<W5B<W1RG
M:6YG"B`@("`@=VET:&EN('1H92!?"'-?"'1?"')?"&E?"&Y?"&<L"B`@("`@3
M=VET:"!T:&4@7PAS7PAT7PAA7PAR7PAT7PAP('!O:6YT:6YG('1O('1H92!FW
M:7)S="!C:&%R86-T97(@;V8@=&AE('-U8G-T<FEN9R!A;F0*("`@("!T:&4@$
M7PAE7PAN7PAD7PAP('!O:6YT:6YG('1O('1H92!F:7)S="!C:&%R86-T97(@D
M9F]L;&]W:6YG('1H92!S=6)S=')I;F<N"B`@("`@5&AE(#!T:"!S=6)S=')I$
M;F<@:7,@=&AE('-U8G-T<FEN9R!O9B!?"'-?"'1?"')?"&E?"&Y?"&<@=&AAF
M="!M871C:&5D('1H92!W:&]L90H@("`@(')E9W5L87(@97AP<F5S<VEO;BX*.
M("`@("!4:&4@;W1H97)S(&%R92!T:&]S92!S=6)S=')I;F=S('1H870@;6%TX
M8VAE9"!P87)E;G1H97-I>F5D(&5X<')E<W-I;VYS"B`@("`@=VET:&EN('1H&
M92!R96=U;&%R(&5X<')E<W-I;VXL('=I=&@@<&%R96YT:&5S:7IE9"!E>'!RD
M97-S:6]N<R!N=6UB97)E9`H@("`@(&EN(&QE9G0M=&\M<FEG:'0@;W)D97(@Y
M;V8@=&AE:7(@;W!E;FEN9R!P87)E;G1H97-E<RX*"B`@("`@7PA27PAE7PAG8
M7PAS7PAU7PAB"B`@("`@8V]P:65S(%\(<U\(;U\(=5\(<E\(8U\(92!T;R!?)
M"&1?"&5?"'-?"'0L(&UA:VEN9R!S=6)S=&ET=71I;VYS(&%C8V]R9&EN9R!T>
M;R!T:&4*("`@("!M;W-T(')E8V5N="!?"')?"&5?"&=?"&5?"'A?"&5?"&,@2
M<&5R9F]R;65D('5S:6YG(%\(<%\(<E\(;U\(9RX*("`@("!%86-H(&EN<W1A&
M;F-E(&]F(&`F)R!I;B!?"'-?"&]?"'5?"')?"&-?"&4@:7,@<F5P;&%C960@&
M8GD@=&AE('-U8G-T<FEN9PH@("`@(&EN9&EC871E9"!B>2!?"'-?"'1?"&%?#
M"')?"'1?"'!;7P@P72!A;F0*("`@("!?"&5?"&Y?"&1?"'!;7P@P72X*("`@B
M("!%86-H(&EN<W1A;F-E(&]F(&!<7PAN)RP@=VAE<F4@7PAN(&ES(&$@9&EG@
M:70L(&ES(')E<&QA8V5D(&)Y"B`@("`@=&AE('-U8G-T<FEN9R!I;F1I8V%T(
M960@8GD*("`@("!?"'-?"'1?"&%?"')?"'1?"'!;7PAN72!A;F0*("`@("!??
M"&5?"&Y?"&1?"'!;7PAN72X*("`@("!4;R!G970@82!L:71E<F%L(&`F)R!O6
M<B!@7%\(;B<@:6YT;R!?"&1?"&5?"'-?"'0L('!R969I>"!I="!W:71H(&!<?
M)SL*("`@("!T;R!G970@82!L:71E<F%L(&!<)R!P<F5C961I;F<@8"8G(&]R_
M(&!<7PAN)RP@<')E9FEX(&ET('=I=&@*("`@("!A;F]T:&5R(&!<)RX*"B`@K
M("`@7PA27PAE7PAG7PAE7PAR7PAR7PAO7PAR"B`@("`@:7,@8V%L;&5D('=HJ
M96YE=F5R(&%N(&5R<F]R(&ES(&1E=&5C=&5D(&EN(%\(<E\(95\(9U\(8U\(7
M;U\(;5\(<"P@7PAR7PAE7PAG7PAE7PAX7PAE7PAC+`H@("`@(&]R(%\(<E\(Q
M95\(9U\(<U\(=5\(8BX*("`@("!4:&4@9&5F875L="!?"')?"&5?"&=?"&5?N
M"')?"')?"&]?"'(@=W)I=&5S('1H92!S=')I;F<@7PAM7PAS7PAG+`H@("`@J
M('=I=&@@82!S=6ET86)L92!I;F1I8V%T;W(@;V8@;W)I9VEN+`H@("`@(&]N#
M('1H92!S=&%N9&%R9`H@("`@(&5R<F]R(&]U='!U=`H@("`@(&%N9"!I;G9OP
M:V5S(%\(95\(>%\(:5\(="@R*2X*("`@("!?"%)?"&5?"&=?"&5?"')?"')?$
M"&]?"'(*("`@("!C86X@8F4@<F5P;&%C960@8GD@=&AE('5S97(@:68@;W1H(
M97(@86-T:6]N<R!A<F4@9&5S:7)A8FQE+@H*4@A210A%1PA'50A53`A,00A!]
M4@A2($4(15@(6%`(4%((4D4(15,(4U,(4TD(24\(3TX(3B!3"%-9"%E."$Y4\
M"%1!"$%8"%@*("`@("!!(')E9W5L87(@97AP<F5S<VEO;B!I<R!Z97)O(&]RH
M(&UO<F4@7PAB7PAR7PAA7PAN7PAC7PAH7PAE7PAS+"!S97!A<F%T960@8GD@1
M8'PG+@H@("`@($ET(&UA=&-H97,@86YY=&AI;F<@=&AA="!M871C:&5S(&]NR
M92!O9B!T:&4@8G)A;F-H97,N"@H@("`@($$@8G)A;F-H(&ES('IE<F\@;W(@/
M;6]R92!?"'!?"&E?"&5?"&-?"&5?"',L(&-O;F-A=&5N871E9"X*("`@("!),
M="!M871C:&5S(&$@;6%T8V@@9F]R('1H92!F:7)S="P@9F]L;&]W960@8GD@Z
M82!M871C:"!F;W(@=&AE('-E8V]N9"P@971C+@H*("`@("!!('!I96-E(&ES_
M(&%N(%\(85\(=%\(;U\(;2!P;W-S:6)L>2!F;VQL;W=E9"!B>2!@*B<L(&`K0
M)RP@;W(@8#\G+@H@("`@($%N(&%T;VT@9F]L;&]W960@8GD@8"HG(&UA=&-H'
M97,@82!S97%U96YC92!O9B`P(&]R(&UO<F4@;6%T8VAE<R!O9B!T:&4@871OJ
M;2X*("`@("!!;B!A=&]M(&9O;&QO=V5D(&)Y(&`K)R!M871C:&5S(&$@<V5Q]
M=65N8V4@;V8@,2!O<B!M;W)E(&UA=&-H97,@;V8@=&AE(&%T;VTN"B`@("`@N
M06X@871O;2!F;VQL;W=E9"!B>2!@/R<@;6%T8VAE<R!A(&UA=&-H(&]F('1H!
M92!A=&]M+"!O<B!T:&4@;G5L;"!S=')I;F<N"@H@("`@($%N(&%T;VT@:7,@4
M82!R96=U;&%R(&5X<')E<W-I;VX@:6X@<&%R96YT:&5S97,@*&UA=&-H:6YGO
M(&$@;6%T8V@@9F]R('1H90H@("`@(')E9W5L87(@97AP<F5S<VEO;BDL(&$@X
M7PAR7PAA7PAN7PAG7PAE("AS964@8F5L;W<I+"!@+B<*("`@("`H;6%T8VAI`
M;F<@86YY('-I;F=L92!C:&%R86-T97(I+"!@7B<@*&UA=&-H:6YG('1H92!N(
M=6QL('-T<FEN9R!A="!T:&4*("`@("!B96=I;FYI;F<@;V8@=&AE(&EN<'5T;
M('-T<FEN9RDL(&`D)R`H;6%T8VAI;F<@=&AE(&YU;&P@<W1R:6YG(&%T('1H.
M90H*"@I&;W)M871T960@.#@O,3(O,S`@("`@("`@("`@("!L;V-A;"`@("`@2
M("`@("`@("`@("`@("`@("`@("`@("`@,@H,"@H*"E)%1T584"@S*2`@("`@?
M("`@("`@("`@("!,:6)R87)Y($9U;F-T:6]N<R`@("`@("`@("`@("`@(%)%%
M1T584"@S*0H*"@H@("`@(&5N9"!O9B!T:&4@:6YP=70@<W1R:6YG*2P@82!@J
M7"<@9F]L;&]W960@8GD@82!S:6YG;&4@8VAA<F%C=&5R("AM871C:&EN9PH@G
M("`@('1H870@8VAA<F%C=&5R*2P@;W(@82!S:6YG;&4@8VAA<F%C=&5R('=I$
M=&@@;F\@;W1H97(@<VEG;FEF:6-A;F-E"B`@("`@*&UA=&-H:6YG('1H870@L
M8VAA<F%C=&5R*2X*"B`@("`@02!?"')?"&%?"&Y?"&=?"&4@:7,@82!S97%U$
M96YC92!O9B!C:&%R86-T97)S(&5N8VQO<V5D(&EN(&!;72<N"B`@("`@270@(
M;F]R;6%L;'D@;6%T8VAE<R!A;GD@<VEN9VQE(&-H87)A8W1E<B!F<F]M('1H:
M92!S97%U96YC92X*("`@("!)9B!T:&4@<V5Q=65N8V4@8F5G:6YS('=I=&@@3
M8%XG+`H@("`@(&ET(&UA=&-H97,@86YY('-I;F=L92!C:&%R86-T97(@7PANI
M7PAO7PAT(&9R;VT@=&AE(')E<W0@;V8@=&AE('-E<75E;F-E+@H@("`@($EF:
M('1W;R!C:&%R86-T97)S(&EN('1H92!S97%U96YC92!A<F4@<V5P87)A=&5D\
M(&)Y(&`M)RP@=&AI<R!I<R!S:&]R=&AA;F0*("`@("!F;W(@=&AE(&9U;&P@_
M;&ES="!O9B!!4T-)22!C:&%R86-T97)S(&)E='=E96X@=&AE;0H@("`@("AE)
M+F<N(&!;,"TY72<@;6%T8VAE<R!A;GD@9&5C:6UA;"!D:6=I="DN"B`@("`@&
M5&\@:6YC;'5D92!A(&QI=&5R86P@8%TG(&EN('1H92!S97%U96YC92P@;6%KO
M92!I="!T:&4@9FER<W0@8VAA<F%C=&5R"B`@("`@*&9O;&QO=VEN9R!A('!O[
M<W-I8FQE(&!>)RDN"B`@("`@5&\@:6YC;'5D92!A(&QI=&5R86P@8"TG+"!MJ
M86ME(&ET('1H92!F:7)S="!O<B!L87-T(&-H87)A8W1E<BX*"D$(04T(34((Q
M0DD(24<(1U4(54D(250(5%D(60H@("`@($EF(&$@<F5G=6QA<B!E>'!R97-S^
M:6]N(&-O=6QD(&UA=&-H('1W;R!D:69F97)E;G0@<&%R=',@;V8@=&AE(&EN2
M<'5T('-T<FEN9RP*("`@("!I="!W:6QL(&UA=&-H('1H92!O;F4@=VAI8V@@>
M8F5G:6YS(&5A<FQI97-T+@H@("`@($EF(&)O=&@@8F5G:6X@:6X@=&AE('-AV
M;64@<&QA8V4@("`@8G5T(&UA=&-H(&1I9F9E<F5N="!L96YG=&AS+"!O<B!M5
M871C:`H@("`@('1H92!S86UE(&QE;F=T:"!I;B!D:69F97)E;G0@=V%Y<RP@Q
M;&EF92!G971S(&UE<W-I97(L(&%S(&9O;&QO=W,N"@H@("`@($EN(&=E;F5R;
M86PL('1H92!P;W-S:6)I;&ET:65S(&EN(&$@;&ES="!O9B!B<F%N8VAE<R!AM
M<F4@8V]N<VED97)E9"!I;@H@("`@(&QE9G0M=&\M<FEG:'0@;W)D97(L('1HB
M92!P;W-S:6)I;&ET:65S(&9O<B!@*B<L(&`K)RP@86YD(&`_)R!A<F4*("`@E
M("!C;VYS:61E<F5D(&QO;F=E<W0M9FER<W0L(&YE<W1E9"!C;VYS=')U8W1S8
M(&%R92!C;VYS:61E<F5D(&9R;VT@=&AE"B`@("`@;W5T97)M;W-T(&EN+"!A-
M;F0@8V]N8V%T96YA=&5D(&-O;G-T<G5C=',@87)E(&-O;G-I9&5R960@;&5F"
M=&UO<W0M9FER<W0N"B`@("`@5&AE(&UA=&-H('1H870@=VEL;"!B92!C:&]S/
M96X@:7,@=&AE(&]N92!T:&%T('5S97,@=&AE(&5A<FQI97-T"B`@("`@<&]S9
M<VEB:6QI='D@:6X@=&AE(&9I<G-T(&-H;VEC92!T:&%T(&AA<R!T;R!B92!MX
M861E+@H@("`@($EF('1H97)E(&ES(&UO<F4@=&AA;B!O;F4@8VAO:6-E+"!TP
M:&4@;F5X="!W:6QL(&)E(&UA9&4@:6X@=&AE('-A;64@;6%N;F5R"B`@("`@+
M*&5A<FQI97-T('!O<W-I8FEL:71Y*2!S=6)J96-T('1O('1H92!D96-I<VEOY
M;B!O;B!T:&4@9FER<W0@8VAO:6-E+@H@("`@($%N9"!S;R!F;W)T:"X*"B`@1
M("`@1F]R(&5X86UP;&4L(&`H86)\82EB*F,G(&-O=6QD(&UA=&-H(&!A8F,GW
M(&EN(&]N92!O9B!T=V\@=V%Y<RX*("`@("!4:&4@9FER<W0@8VAO:6-E(&EST
M(&)E='=E96X@8&%B)R!A;F0@8&$G.R!S:6YC92!@86(G(&ES(&5A<FQI97(L2
M(&%N9"!D;V5S"B`@("`@;&5A9"!T;R!A('-U8V-E<W-F=6P@;W9E<F%L;"!MD
M871C:"P@:70@:7,@8VAO<V5N+@H@("`@(%-I;F-E('1H92!@8B<@:7,@86QRT
M96%D>2!S<&]K96X@9F]R+`H@("`@('1H92!@8BHG(&UU<W0@;6%T8V@@:71S*
M(&QA<W0@<&]S<VEB:6QI='DM+71H92!E;7!T>2!S=')I;F<M+7-I;F-E"B`@&
M("`@:70@;75S="!R97-P96-T('1H92!E87)L:65R(&-H;VEC92X*"B`@("`@.
M26X@=&AE('!A<G1I8W5L87(@8V%S92!W:&5R92!N;R!@?"=S(&%R92!P<F5SK
M96YT(&%N9"!T:&5R92!I<R!O;FQY(&]N90H@("`@(&`J)RP@8"LG+"!O<B!@8
M/R<L('1H92!N970@969F96-T(&ES('1H870@=&AE(&QO;F=E<W0@<&]S<VEBA
M;&4*("`@("!M871C:"!W:6QL(&)E(&-H;W-E;BX*("`@("!3;R!@86(J)RP@A
M<')E<V5N=&5D('=I=&@@8'AA8F)B8GDG+"!W:6QL(&UA=&-H(&!A8F)B8B<N6
M"B`@("`@3F]T92!T:&%T(&EF(&!A8BHG(&ES('1R:65D(&%G86EN<W0@8'AAH
M8GEA8F)B>B<L(&ET"B`@("`@=VEL;"!M871C:"!@86(G(&IU<W0@869T97(@=
M8'@G+"!D=64@=&\@=&AE(&)E9VEN<RUE87)L:65S="!R=6QE+@H@("`@("A)L
M;B!E9F9E8W0L('1H92!D96-I<VEO;B!O;B!W:&5R92!T;R!S=&%R="!T:&4@`
M;6%T8V@@:7,@=&AE(&9I<G-T(&-H;VEC90H@("`@('1O(&)E(&UA9&4L(&AE!
M;F-E('-U8G-E<75E;G0@8VAO:6-E<R!M=7-T(')E<W!E8W0@:70@979E;B!IV
M9B!T:&ES(&QE861S('1H96T*("`@("!T;R!L97-S+7!R969E<G)E9"!A;'1E+
M<FYA=&EV97,N*0H*4PA310A%10A%($$(04P(3%,(4T\(3PH@("`@(&5G<F5P$
M*#$I+"!E>'!R*#$I"@H*"@H*1F]R;6%T=&5D(#@X+S$R+S,P("`@("`@("`@%
M("`@;&]C86P@("`@("`@("`@("`@("`@("`@("`@("`@("`@(#,*#`H*"@I2.
M14=%6%`H,RD@("`@("`@("`@("`@("`@3&EB<F%R>2!&=6YC=&EO;G,@("`@K
M("`@("`@("`@("!214=%6%`H,RD*"@H*1`A$20A)00A!1PA'3@A.3PA/4PA39
M5`A420A)0PA#4PA3"B`@("`@7PA27PAE7PAG7PAC7PAO7PAM7PAP(')E='5R@
M;G,@3E5,3"!F;W(@82!F86EL=7)E"B`@("`@*%\(<E\(95\(9U\(95\(<E\(]
M<E\(;U\(<B!P97)M:71T:6YG*2P*("`@("!W:&5R92!F86EL=7)E<R!A<F4@1
M<WEN=&%X(&5R<F]R<RP@97AC965D:6YG(&EM<&QE;65N=&%T:6]N(&QI;6ETA
M<RP*("`@("!O<B!A<'!L>6EN9R!@*R<@;W(@8"HG('1O(&$@<&]S<VEB;'DM8
M;G5L;"!O<&5R86YD+@H*2`A(20A)4PA35`A43PA/4@A260A9"B`@("`@0F]TQ
M:"!C;V1E(&%N9"!M86YU86P@<&%G92!W97)E"B`@("`@=W)I='1E;B!A="!5%
M(&]F(%0N"B`@("`@5&AE>2!A<F4@:6YT96YD960@=&\@8F4@8V]M<&%T:6)LC
M92!W:71H('1H92!"96QL(%8X(%\(<E\(95\(9U\(95\(>%\(<"@S*2P*("`@>
M("!B=70@87)E(&YO="!D97)I=F5D(&9R;VT@0F5L;"!C;V1E+@H*0@A"50A5%
M1PA'4PA3"B`@("`@16UP='D@8G)A;F-H97,@86YD(&5M<'1Y(')E9W5L87(@W
M97AP<F5S<VEO;G,@87)E(&YO="!P;W)T86)L92!T;R!6."X*"B`@("`@5&AEY
M(')E<W1R:6-T:6]N(&%G86EN<W0*("`@("!A<'!L>6EN9R!@*B<@;W(@8"LG/
M('1O(&$@<&]S<VEB;'DM;G5L;"!O<&5R86YD(&ES(&%N(&%R=&EF86-T(&]F8
M('1H90H@("`@('-I;7!L:7-T:6,@:6UP;&5M96YT871I;VXN"@H@("`@($1OG
M97,@;F]T('-U<'!O<G0@7PAE7PAG7PAR7PAE7PAP)W,@;F5W;&EN92US97!A^
M<F%T960@8G)A;F-H97,["B`@("`@;F5I=&AE<B!D;V5S('1H92!6."!?"')?\
M"&5?"&=?"&5?"'A?"'`H,RDL('1H;W5G:"X*"B`@("`@1'5E('1O(&5M<&AA*
M<VES(&]N"B`@("`@8V]M<&%C=&YE<W,@86YD('-I;7!L:6-I='DL"B`@("`@F
M:70G<R!N;W0@<W1R:6MI;F=L>2!F87-T+@H@("`@($ET(&1O97,@9VEV92!SD
M<&5C:6%L(&%T=&5N=&EO;B!T;R!H86YD;&EN9R!S:6UP;&4@8V%S97,@<75I4
M8VML>2X*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@I&;W)M871T960@3
M.#@O,3(O,S`@("`@("`@("`@("!L;V-A;"`@("`@("`@("`@("`@("`@("`@?
+("`@("`@("`@-`H@^
``
end
size 8651
SHAR_EOF
cat << \SHAR_EOF > stevie.doc

	    STEVIE - Simply Try this Editor for VI Enthusiasts

			 Quick Reference Card

				  by

	          Tony Andrews And G. R. (Fred) Walter

STEVIE may be freely distributed. The source isn't copyrighted or
restricted in any way. If you pass the program along, please include all
the documentation and, if practical, the source as well.

STEVIE used to stand for 'ST Editor for VI Enthusiasts', however since this
editor is used on more machines than just ST's the acronym was changed.

Starting the Editor
-------------------

The following command line forms are supported:

	vi [file ...]		Edit the specified file(s)

	vi -t tag		Start at location of the given tag

	vi + file		Edit file starting at end

	vi +n file		Edit file starting a line number 'n'

	vi +/pat file		Edit file starting at pattern 'pat'

If multiple files are given on the command line (using the first form),
the ":n" command goes to the next file, ":p" goes backward in the list,
and ":rew" can be used to rewind back to the start of the file list.

Set Command Options
-------------------

The ":set" command works as usual to set parameters. Each parameter has
a long and an abbreviated name, either of which may be used. Boolean
parameters are set as in:

	set showmatch

or cleared by:

	set noshowmatch

Numeric parameters are set as in:

	set scroll=5

Several parameters may be set with a single command:

	set novb sm report=1

To see the status of all parameters use ":set all". Typing ":set" with
no arguments will show only those parameters that have been changed.
The supported parameters, their names, defaults, and descriptions are
shown below:

Full Name	Short	Default		Description
------------------------------------------------------------------------------
vbell		vb	vb		Use visual bell (novb for audible bell)
showmatch	sm	nosm		Showmatch mode
wrapscan	ws	ws		Wrapscan (searches cross file start/end)
errorbells	eb	noeb		Ring bell when error messages are shown
showmode	mo	nomo		Show on status line when in insert mode
backup		bk	nobk		Leave backup in *.bak on file writes
return		cr	cr		End lines with cr-lf when writing
list		list	nolist		Show tabs and newlines graphically
autoindent      ai      noai            Start new line at same col as prior line
ignorecase      ic      noic            Ignore case in search strings
number          nu      nonu            Display lines with their line numbers

scroll		scroll	12		Number of lines to scroll for ^D and ^U
tabstop		ts	8		Number of spaces in a tab
report		report	5		Min # of lines to report operations on
lines		lines	25		Number of lines on the screen

The EXINIT environment variable can be used to modify the default values
on startup as in:

		setenv EXINIT="set sm ts=4"

The 'backup' parameter, if set, causes the editor to retain a backup of any
files that are written. During file writes, a backup is always kept for
safety until the write is completed. At that point, the 'backup' parameter
determines whether the backup file is deleted.

In environments (e.g. OS/2 or TOS) where lines are normally terminated by
CR-LF, the 'return' parameter allows files to be written with only a LF
terminator (if the parameter is cleared).

The 'lines' parameter tells the editor how many lines there are on the screen.
This is useful on systems like the ST where various screen resolutions may be
used. By using the 'lines' parameter, different screen sizes can be easily
handled. On the Amiga system window resizes are atomatically detected and
acted upon. It is suggested that one's window be larger than 2 rows and 5
columns.

Colon Commands
--------------

Several of the normal 'vi' colon commands are supported by STEVIE. Some commands
may be preceded by a line range specification. For commands that accept a range
of lines, the following address forms are supported:

addr
addr + number
addr - number

where 'addr' may be one of the following:
    a line number
    a mark (as in 'a or 'b)
    % (entire file)
    . (the current line)
    $ (the last line)

The Global Command
------------------

A limited form of the global command is supported, accepting the following
command form:

g/pattern/X

where X may be either 'd' or 'p' to delete or print lines that match the given
pattern. If a line range is given, only those lines are checked for a match
with the pattern. If no range is given, all lines are checked.

If the trailing command character is omitted, 'p' is assumed. In this case, the
trailing slash is also optional. The current version of the editor does not
support the undo operation following the deletion of lines with the global
command.

The Substitute Command
----------------------

The substitute command provides a powerful mechanism for making more complex
substitutions than can be done directly from visual mode. The general form of
the command is:

s/pattern/replacement/g

Each line in the given range (or the current line, if no range was given) is
scanned for the given regular expression. When found, the string that matched
the pattern is replaced with the given replacement string. If the replacement
string is null, each matching pattern string is deleted.

The trailing 'g' is optional and, if present, indicates that multiple
occurrences of 'pattern' on a line should all be replaced.

Some special sequences are recognized in the replacement string. The
ampersand character is replaced by the entire pattern that was matched.
For example, the following command could be used to put all occurrences
of 'foo' or 'bar' within double quotes:

1,$s/foo|bar/&/g

The special sequence "\n" where 'n' is a digit from 1 to 9, is replaced
by the string the matched the corresponding parenthesized expression in
the pattern. The following command could be used to swap the first two
parameters in calls to the C function "foo":

1,$s/foo\\(([^,]*),([^,]*),/foo(\\2,\\1,/g

Like the global command, substitutions can't be undone with this version of
the editor.

The Delete Command
------------------

:[range]d will delete the range of lines.

File Manipulation Commands
--------------------------

:w		write the current file
:wq		write and quit
:x		write (if necessary) and quit
ZZ		same as ":x"

:e file		edit the named file
:e!		re-edit the current file, discarding any changes
:e #		edit the alternate file

:w file		write the buffer to the named file
:x,y w file	write lines x through y to the named file
:r file		read the named file into the buffer

:n		edit the next file
:p		edit the previous file
:rew		rewind the file list

:f		show the current file name
:f name		change the current file name

:ta tag		go to the named tag
^]		like ":ta" using the current word as the tag

:help		display a command summary

The ":help" command can also be invoke with the <HELP> key on the Atari ST
or the Amiga. This actually displays a pretty complete summary of the real vi
with unsupported features indicated appropriately.

The commands above work pretty much like they do in 'vi'. Most of the
commands support a '!' suffix (if appropriate) to discard any pending
changes.

String Searches
---------------

String searches are supported, as in vi, accepting the usual regular
expression syntax. This was done using Henry Spencer's regular expression
library without modification. Tony Andrews added code outside the library to
support the '\<' and '\>' extensions and code inside the library to support
the ignorecase option.

Operators
---------

The vi operators (d, c, y, <, and >) work as true operators.

Tags
----

Tags are implemented.

System-Specific Comments
------------------------

The following sections provide additional relevant information for the
systems to which STEVIE has been ported.

Atari ST
--------

The editor has been tested in all three resolutions, although low and
high res. are less tested than medium. The 50-line high res. mode can
be used by setting the 'lines' parameter to 50. Alternatively, the
environment variable 'LINES' can be set. The editor doesn't actively
set the number of lines on the screen. It just operates using the number
of lines it was told.

The arrow keys, as well as the <INSERT>, <HELP>, and <UNDO> keys are
all mapped appropriately.

UNIX
----

The editor has been ported to UNIX System V release 3. This was done
mainly to get some profiling data so I haven't put much effort into
doing the UNIX version right. It's hard-coded for ansi-style escape
sequences and doesn't use the termcap/terminfo routines at all.

OS/2
----

This port was done because the editor that comes with the OS/2 developer's
kit really sucks. Make sure 'ansi' mode is on (using the 'ansi' command).
The OS/2 console driver doesn't support insert/delete line, so STEVIE
bypasses the driver and makes the appropriate system calls directly.
This is all done in the system-specific part of the editor so the kludge
is at least localized.

The arrow keys, page up/down and home/end all do what you'd expect. The function
keys are hard-coded to some useful macros until I can get true support for
macros into the editor. The current mappings are:

F1	:p <RETURN>
F2	:n <RETURN>
F3	:e # <RETURN>
F4	:rew <RETURN>
F5	[[
F6	]]
F7	<<
F8	>>
F9	:x <RETURN>
F10	:help <RETURN>

S-F1	:p! <RETURN>
S-F2	:n! <RETURN>

MSDOS
-----

STEVIE has been ported to MSDOS 3.3 on an AT using the Microsoft C compiler,
version 5.10.  The keyboard mappings are the same as for OS/2.
The only problem with the PC version is that the inefficiency of
the screen update code becomes painfully apparent on slower machines.

BSD 4.3
-------

This port was done so it could be worked on in a main-frame enviroment.

Amiga
-----

The arrow keys and the help key are supported, as is window re-sizing.
It is strongly suggested that you not try to type in console commands
(alt-esc in some keymaps, plus the appropriate other keys) since STEVIE
captures all console input. If you do type alt-esc then typing '|' will
return you to STEVIE.

Missing Features
----------------

1. Macros with support for function keys.

2. More "set" options.

3. Many others...

Known Bugs and Problems
-----------------------

1. The yank buffer uses statically allocated memory, so yanks of more than
   5K of text will fail. If a delete spans more than 5K, the program asks
   for confirmation before proceeding. That way, if you were moving text,
   you don't get screwed by the limited yank buffer. You just have to move
   smaller chunks at a time. All the internal buffers (yank, redo, etc.)
   need to be reworked to allocate memory dynamically.

2. If you stay in insert mode for a long time (around 5K's worth of
   characters, including newlines) the insert buffer can overflow.
   When this happens you lose your ability to automatically undo the text just
   inserted and the redo/undo/(undo of undo) buffers are reset to the
   current position.

3. Several other less bothersome glitches...

Character Function Summary
--------------------------

The following list describes the meaning of each character that's used
by the editor. In some cases characters have meaning in both command and
insert mode; these are all described.

^@	The null character. Not used in any mode. This character may not
	be present in the file, as is the case with vi.

^B	Backward one screen.

^D	Scroll the window down one half screen.

^E	Scroll the screen up one line.

^F	Forward one screen.

^G	Same as ":f" command. Displays file information.

^H (BS)	Moves cursor left one space in command mode. In insert mode, erases
	the last character typed.

^J	Move the cursor down one line.

^L	Clear and redraw the screen.

^M (CR)	Move to the first non-white character in the next line. In insert
	mode, a carriage return opens a new line for input.

^N	Move the cursor down a line.

^P	Move the cursor up a line.

^U	Scroll the window up one half screen.

^V	Indicates that the next character is should be treated as entered
	and not modified (used to enter control characters, etc.).

^Y	Scroll the screen down one line.

^[	Escape cancels a pending command in command mode, and is used to
	terminate insert mode.

^]	Moves to the tag whose name is given by the word in which the cursor
	resides.

^`	Same as ":e #" if supported (system-dependent).

SPACE	Move the cursor right on column.

$	Move to the end of the current line.

%	If the cursor rests on a paren '()', brace '{}', or bracket '[]',
	move to the matching one.

'	Used to move the cursor to a previously marked position, as in
	'a or 'b. The cursor moves to the start of the marked line. The
	special mark '' refers to the "previous context".

+	Same as carriage return, in command mode.

,	Reverse of the last t, T, f, or F command.

-	Move to the first non-white character in the previous line.

.	Repeat the last edit command.

/	Start of a forward string search command. String searches may be
	optionally terminated with a closing slash. To search for a slash
	use '\/' in the search string.

0	Move to the start of the current line. Also used within counts.

1-9	Used to add 'count' prefixes to commands.

:	Prefix character for "ex" commands.

;	Repeat last t, T, f, or F command.

<	The 'left shift' operator.

>	The 'right shift' operator.

?	Same as '/', but search backward.

A	Append at the end of the current line.

B	Backward one blank-delimited word.

C	Change the rest of the current line.

D	Delete the rest of the current line.

E	End of the end of a blank-delimited word.

F	Find a character backward on the current line.

G	Go to the given line number (end of file, by default).

H	Move to the first non-white char. on the top screen line.

I	Insert before the first non-white char. on the current line.

J	Join two lines.

L	Move to the first non-white char. on the bottom screen line.

M	Move to the first non-white char. on the middle screen line.

N	Reverse the last string search.

O	Open a new line above the current line, and start inserting.

P	Put the yank/delete buffer before the current cursor position.

T	Reverse search 'upto' the given character.

W	Move forward one blank-delimited word.

X	Delete one character before the cursor.

Y	Yank the current line. Same as 'yy'.

ZZ	Exit from the editor, saving changes if necessary.

[[	Move backward one C function.

]]	Move forward one C function.

^	Move to the first non-white on the current line.

`	Move to the given mark, as with '. The distinction between the two
	commands is important when used with operators. I support the
	difference correctly. If you don't know what I'm talking about,
	don't worry, it won't matter to you.

~       Switch case of character under cursor.

a	Append text after the cursor.

b	Back one word.

c	The change operator.

d	The delete operator.

e	Move to the end of a word.

f	Find a character on the current line.

h	Move left one column.

i	Insert text before the cursor.

j	Move down one line.

k	Move up one line.

l	Move right one column.

m	Set a mark at the current position (e.g. ma or mb).

n	Repeat the last string search.

o	Open a new line and start inserting text.

p	Put the yank/delete buffer after the cursor.

r	Replace a character.

s	Replace characters.

t	Move forward 'upto' the given character on the current line.

u	Undo the last edit.

w	Move forward one word.

x	Delete the character under the cursor.

y	The yank operator.

z	Redraw the screen with the current line at the top (zRETURN),
	the middle (z.), or the bottom (z-).

|	Move to the column given by the preceding count.
SHAR_EOF
#	End of shell archive
exit 0
-- 
Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
Have five nice days.