v15i038: Stevie, an "aspiring" VI clone for Unix, OS/2, Amiga, Part02/04

Rich Salz rsalz at uunet.uu.net
Tue Jun 7 00:48:56 AEST 1988


Submitted-by: onecom!wldrdg!tony (Tony Andrews)
Posting-number: Volume 15, Issue 38
Archive-name: stevie/part02

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 4)."
# Contents:  cmdline.c edit.c help.c main.c misccmds.c
# Wrapped by rsalz at fig.bbn.com on Sun Jun  5 11:45:43 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'cmdline.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cmdline.c'\"
else
echo shar: Extracting \"'cmdline.c'\" \(11004 characters\)
sed "s/^X//" >'cmdline.c' <<'END_OF_FILE'
X/*
X * STevie - ST editor for VI enthusiasts.   ...Tim Thompson...twitch!tjt...
X *
X * Extensive modifications by:  Tony Andrews       onecom!wldrdg!tony
X *
X */
X
X#include "stevie.h"
X
static	char	*altfile = NULL;	/* alternate file */
static	int	altline;		/* line # in alternate file */
X
static	char	*nowrtmsg = "No write since last change (use ! to override)";
X
extern	char	**files;		/* used for "n" and "rew" */
extern	int	numfiles, curfile;
X
X/*
X * The next two variables contain the bounds of any range given in a
X * command. If no range was given, both contain null line pointers.
X * If only a single line was given, u_pos will contain a null line
X * pointer.
X */
static	LPTR	l_pos, u_pos;
X
static	bool_t	interactive;	/* TRUE if we're reading a real command line */
X
X#define	CMDSZ	100		/* size of the command buffer */
X
static	bool_t	doecmd();
static	void	badcmd(), doshell(), get_range();
static	LPTR	*get_line();
X
X#ifdef	MEGAMAX
overlay "cmdline"
X#endif
X
X/*
X * readcmdline() - accept a command line starting with ':', '/', or '?'
X *
X * readcmdline() accepts and processes colon commands and searches. If
X * 'cmdline' is null, the command line is read here. Otherwise, cmdline
X * points to a complete command line that should be used. This is used
X * in main() to handle initialization commands in the environment variable
X * "EXINIT".
X */
void
readcmdline(firstc, cmdline)
int	firstc;		/* either ':', '/', or '?' */
char	*cmdline;	/* optional command string */
X{
X	int c;
X	char buff[CMDSZ];
X	char *p, *q, *cmd, *arg;
X
X	/*
X	 * Clear the range variables.
X	 */
X	l_pos.linep = (struct line *) NULL;
X	u_pos.linep = (struct line *) NULL;
X
X	interactive = (cmdline == NULL);
X
X	if (interactive)
X		gotocmd(1,1,firstc);
X	p = buff;
X	if ( firstc != ':' )
X		*p++ = firstc;
X
X	if (interactive) {
X		/* collect the command string, handling '\b' and @ */
X		for ( ; ; ) {
X			c = vgetc();
X			if ( c=='\n'||c=='\r'||c==EOF )
X				break;
X			if ( c=='\b' ) {
X				if ( p > buff ) {
X					p--;
X					/* this is gross, but it relies
X					 * only on 'gotocmd'
X					 */
X					gotocmd(1,0,firstc==':'?':':0);
X					for ( q=buff; q<p; q++ )
X						outchar(*q);
X				} else {
X					msg("");
X					return;		/* back to cmd mode */
X				}
X				continue;
X			}
X			if ( c=='@' ) {
X				p = buff;
X				gotocmd(1,1,firstc);
X				continue;
X			}
X			outchar(c);
X			*p++ = c;
X		}
X		*p = '\0';
X	} else {
X		if (strlen(cmdline) > CMDSZ-2)	/* should really do something */
X			return;			/* better here... */
X		strcpy(p, cmdline);
X	}
X
X	/* skip any initial white space */
X	for ( cmd = buff; *cmd != NUL && isspace(*cmd); cmd++ )
X		;
X
X	/* search commands */
X	c = *cmd;
X	if ( c == '/' || c == '?' ) {
X		cmd++;
X		if ( *cmd == c ) {
X			/* the command was '//' or '??' */
X			repsearch();
X			return;
X		}
X		/* If there is a matching '/' or '?' at the end, toss it */
X		p = strchr(cmd, NUL);
X		if ( *(p-1) == c && *(p-2) != '\\' )
X			*(p-1) = NUL;
X		dosearch((c == '/') ? FORWARD : BACKWARD, cmd);
X		return;
X	}
X
X	/*
X	 * Parse a range, if present (and update the cmd pointer).
X	 */
X	get_range(&cmd);
X
X	/* isolate the command and find any argument */
X	for ( p=cmd; *p != NUL && ! isspace(*p); p++ )
X		;
X	if ( *p == NUL )
X		arg = NULL;
X	else {
X		*p = NUL;
X		for (p++; *p != NUL && isspace(*p) ;p++)
X			;
X		arg = p;
X		if ( *arg == '\0' )
X			arg = NULL;
X	}
X	if ( strcmp(cmd,"q!")==0 )
X		getout();
X	if ( strcmp(cmd,"q")==0 ) {
X		if ( Changed )
X			emsg(nowrtmsg);
X		else
X			getout();
X		return;
X	}
X	if ( strcmp(cmd,"w")==0 ) {
X		if ( arg == NULL ) {
X			if (Filename != NULL) {
X				writeit(Filename, &l_pos, &u_pos);
X				UNCHANGED;
X			} else
X				emsg("No output file");
X		}
X		else
X			writeit(arg, &l_pos, &u_pos);
X		return;
X	}
X	if ( strcmp(cmd,"wq")==0 ) {
X		if (Filename != NULL) {
X			if ( writeit(Filename, NULL, NULL) )
X				getout();
X		} else
X			emsg("No output file");
X		return;
X	}
X	if ( strcmp(cmd, "x") == 0 ) {
X		if (Changed) {
X			if (Filename != NULL) {
X				if (!writeit(Filename, NULL, NULL))
X					return;
X			} else {
X				emsg("No output file");
X				return;
X			}
X		}
X		getout();
X	}
X	if ( strcmp(cmd,"f")==0 && arg==NULL ) {
X		fileinfo();
X		return;
X	}
X	if ( *cmd == 'n' ) {
X		if ( (curfile + 1) < numfiles ) {
X			/*
X			 * stuff ":e[!] FILE\n"
X			 */
X			stuffin(":e");
X			if (cmd[1] == '!')
X				stuffin("!");
X			stuffin(" ");
X			stuffin(files[++curfile]);
X			stuffin("\n");
X		} else
X			emsg("No more files!");
X		return;
X	}
X	if ( *cmd == 'p' ) {
X		if ( curfile > 0 ) {
X			/*
X			 * stuff ":e[!] FILE\n"
X			 */
X			stuffin(":e");
X			if (cmd[1] == '!')
X				stuffin("!");
X			stuffin(" ");
X			stuffin(files[--curfile]);
X			stuffin("\n");
X		} else
X			emsg("No more files!");
X		return;
X	}
X	if ( strncmp(cmd, "rew", 3) == 0) {
X		if (numfiles <= 1)		/* nothing to rewind */
X			return;
X		curfile = 0;
X		/*
X		 * stuff ":e[!] FILE\n"
X		 */
X		stuffin(":e");
X		if (cmd[3] == '!')
X			stuffin("!");
X		stuffin(" ");
X		stuffin(files[0]);
X		stuffin("\n");
X		return;
X	}
X	if ( strcmp(cmd,"e") == 0 || strcmp(cmd,"e!") == 0 ) {
X		doecmd(arg, cmd[1] == '!');
X		return;
X	}
X	if ( strcmp(cmd,"f") == 0 ) {
X		Filename = strsave(arg);
X		filemess("");
X		return;
X	}
X	if ( strcmp(cmd,"r") == 0 || strcmp(cmd,".r") == 0 ) {
X		if ( arg == NULL ) {
X			badcmd();
X			return;
X		}
X		if (readfile(arg, Curschar, 1)) {
X			emsg("Can't open file");
X			return;
X		}
X		updatescreen();
X		CHANGED;
X		return;
X	}
X	if ( strcmp(cmd,".=")==0 ) {
X		char messbuff[80];
X		sprintf(messbuff,"line %d", cntllines(Filemem,Curschar));
X		msg(messbuff);
X		return;
X	}
X	if ( strcmp(cmd,"$=")==0 ) {
X		char messbuff[8];
X		sprintf(messbuff, "%d", cntllines(Filemem, Fileend)-1);
X		msg(messbuff);
X		return;
X	}
X	if ( strncmp(cmd,"ta", 2) == 0 ) {
X		dotag(arg, cmd[2] == '!');
X		return;
X	}
X	if ( strcmp(cmd,"set")==0 ) {
X		doset(arg, interactive);
X		return;
X	}
X	if ( strcmp(cmd,"help")==0 ) {
X		if (help()) {
X			screenclear();
X			updatescreen();
X		}
X		return;
X	}
X	if ( strcmp(cmd, "version") == 0) {
X		extern	char	*Version;
X
X		msg(Version);
X		return;
X	}
X	if ( strcmp(cmd, "sh") == 0) {
X		doshell();
X		return;
X	}
X	/*
X	 * If we got a line, but no command, then go to the line.
X	 */
X	if (*cmd == NUL && l_pos.linep != NULL) {
X		*Curschar = l_pos;
X		cursupdate();
X		return;
X	}
X
X	badcmd();
X}
X
X/*
X * get_range - parse a range specifier
X *
X * Ranges are of the form:
X *
X * addr[,addr]
X *
X * where 'addr' is:
X *
X * $  [+- NUM]
X * 'x [+- NUM]	(where x denotes a currently defined mark)
X * .  [+- NUM]
X * NUM
X *
X * The pointer *cp is updated to point to the first character following
X * the range spec. If an initial address is found, but no second, the
X * upper bound is equal to the lower.
X */
static void
get_range(cp)
char	**cp;
X{
X	LPTR	*l;
X	char	*p;
X
X	if ((l = get_line(cp)) == NULL)
X		return;
X
X	l_pos = *l;
X
X	for (p = *cp; *p != NUL && isspace(*p) ;p++)
X		;
X
X	*cp = p;
X
X	if (*p != ',') {		/* is there another line spec ? */
X		u_pos = l_pos;
X		return;
X	}
X
X	*cp = ++p;
X
X	if ((l = get_line(cp)) == NULL) {
X		u_pos = l_pos;
X		return;
X	}
X
X	u_pos = *l;
X}
X
static LPTR *
get_line(cp)
char	**cp;
X{
X	static	LPTR	pos;
X	LPTR	*lp;
X	char	*p, c;
X	int	lnum;
X
X	pos.index = 0;		/* shouldn't matter... check back later */
X
X	p = *cp;
X	/*
X	 * Determine the basic form, if present.
X	 */
X	switch (c = *p++) {
X
X	case '$':
X		pos.linep = Fileend->linep->prev;
X		break;
X
X	case '.':
X		pos.linep = Curschar->linep;
X		break;
X
X	case '\'':
X		if ((lp = getmark(*p++)) == NULL) {
X			emsg("Unknown mark");
X			return (LPTR *) NULL;
X		}
X		pos = *lp;
X		break;
X
X	case '0': case '1': case '2': case '3': case '4':
X	case '5': case '6': case '7': case '8': case '9':
X		for (lnum = c - '0'; isdigit(*p) ;p++)
X			lnum = (lnum * 10) + (*p - '0');
X
X		pos = *gotoline(lnum);
X		break;
X
X	default:
X		return (LPTR *) NULL;
X	}
X
X	while (*p != NUL && isspace(*p))
X		p++;
X
X	if (*p == '-' || *p == '+') {
X		bool_t	neg = (*p++ == '-');
X
X		for (lnum = 0; isdigit(*p) ;p++)
X			lnum = (lnum * 10) + (*p - '0');
X
X		if (neg)
X			lnum = -lnum;
X
X		pos = *gotoline( cntllines(Filemem, &pos) + lnum );
X	}
X
X	*cp = p;
X	return &pos;
X}
X
static void
badcmd()
X{
X	if (interactive)
X		emsg("Unrecognized command");
X}
X
X#define	LSIZE	512	/* max. size of a line in the tags file */
X
X/*
X * dotag(tag, force) - goto tag
X */
void
dotag(tag, force)
char	*tag;
bool_t	force;
X{
X	FILE	*tp, *fopen();
X	char	lbuf[LSIZE];
X	char	*fname, *str;
X
X	if ((tp = fopen("tags", "r")) == NULL) {
X		emsg("Can't open tags file");
X		return;
X	}
X
X	while (fgets(lbuf, LSIZE, tp) != NULL) {
X	
X		if ((fname = strchr(lbuf, TAB)) == NULL) {
X			emsg("Format error in tags file");
X			return;
X		}
X		*fname++ = '\0';
X		if ((str = strchr(fname, TAB)) == NULL) {
X			emsg("Format error in tags file");
X			return;
X		}
X		*str++ = '\0';
X
X		if (strcmp(lbuf, tag) == 0) {
X			if (doecmd(fname, force)) {
X				stuffin(str);		/* str has \n at end */
X				stuffin("\007");	/* CTRL('G') */
X				fclose(tp);
X				return;
X			}
X		}
X	}
X	emsg("tag not found");
X	fclose(tp);
X}
X
static	bool_t
doecmd(arg, force)
char	*arg;
bool_t	force;
X{
X	int	line = 1;		/* line # to go to in new file */
X
X	if (!force && Changed) {
X		emsg(nowrtmsg);
X		return FALSE;
X	}
X	if ( arg != NULL ) {
X		/*
X		 * First detect a ":e" on the current file. This is mainly
X		 * for ":ta" commands where the destination is within the
X		 * current file.
X		 */
X		if (Filename != NULL && strcmp(arg, Filename) == 0) {
X			if (!Changed || (Changed && !force))
X				return TRUE;
X		}
X		if (strcmp(arg, "#") == 0) {	/* alternate */
X			char	*s = Filename;
X
X			if (altfile == NULL) {
X				emsg("No alternate file");
X				return FALSE;
X			}
X			Filename = altfile;
X			altfile  = s;
X			line = altline;
X			altline = cntllines(Filemem, Curschar);
X		} else {
X			altfile = Filename;
X			altline = cntllines(Filemem, Curschar);
X			Filename = strsave(arg);
X		}
X	}
X	if (Filename == NULL) {
X		emsg("No filename");
X		return FALSE;
X	}
X
X	/* clear mem and read file */
X	freeall();
X	filealloc();
X	UNCHANGED;
X
X	readfile(Filename, Filemem, 0);
X	*Topchar = *Curschar;
X	if (line != 1) {
X		stuffnum(line);
X		stuffin("G");
X	}
X	setpcmark();
X	updatescreen();
X	return TRUE;
X}
X
static void
doshell()
X{
X	char	*sh, *getenv();
X
X	if ((sh = getenv("SHELL")) == NULL) {
X		emsg("Shell variable not set");
X		return;
X	}
X	gotocmd(TRUE, FALSE, 0);
X
X	if (system(sh) < 0) {
X		emsg("Exec failed");
X		return;
X	}
X
X	wait_return();
X}
X
void
gotocmd(clr, fresh, firstc)
bool_t  clr, fresh;
char	firstc;
X{
X	int n;
X
X	windgoto(Rows-1,0);
X	if ( clr )
X		outstr(T_EL);		/* clear the bottom line */
X	if ( firstc )
X		outchar(firstc);
X}
X
X/*
X * msg(s) - displays the string 's' on the status line
X */
void
msg(s)
char *s;
X{
X	gotocmd(TRUE, TRUE, 0);
X	outstr(s);
X}
X
void
smsg(s, a1, a2, a3, a4, a5, a6, a7, a8, a9)
char	*s;
int	a1, a2, a3, a4, a5, a6, a7, a8, a9;
X{
X	char	sbuf[80];
X
X	sprintf(sbuf, s, a1, a2, a3, a4, a5, a6, a7, a8, a9);
X	msg(sbuf);
X}
X
X/*
X * emsg() - display an error message
X *
X * Rings the bell, if appropriate, and calls message() to do the real work
X */
void
emsg(s)
char	*s;
X{
X	if (P(P_EB))
X		beep();
X	msg(s);
X}
X
void
wait_return()
X{
X	char	c;
X
X	outstr("Press RETURN to continue");
X	do {
X		c = vgetc();
X	} while (c != '\r' && c != '\n');
X
X	screenclear();
X	updatescreen();
X}
END_OF_FILE
if test 11004 -ne `wc -c <'cmdline.c'`; then
    echo shar: \"'cmdline.c'\" unpacked with wrong size!
fi
# end of 'cmdline.c'
fi
if test -f 'edit.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'edit.c'\"
else
echo shar: Extracting \"'edit.c'\" \(6480 characters\)
sed "s/^X//" >'edit.c' <<'END_OF_FILE'
X/*
X * STevie - ST editor for VI enthusiasts.     ...Tim Thompson...twitch!tjt...
X *
X * Extensive modifications by:  Tony Andrews       onecom!wldrdg!tony
X *
X */
X
X#include "stevie.h"
X
X/*
X * This flag is used to make auto-indent work right on lines where only
X * a <RETURN> or <ESC> is typed. It is set when an auto-indent is done,
X * and reset when any other editting is done on the line. If an <ESC>
X * or <RETURN> is received, and did_ai is TRUE, the line is truncated.
X */
bool_t	did_ai = FALSE;
X
void
edit()
X{
X	int c;
X	char *p, *q;
X
X	Prenum = 0;
X
X	/* position the display and the cursor at the top of the file. */
X	*Topchar = *Filemem;
X	*Curschar = *Filemem;
X	Cursrow = Curscol = 0;
X
X	for ( ;; ) {
X
X	/* Figure out where the cursor is based on Curschar. */
X	cursupdate();
X
X	windgoto(Cursrow,Curscol);
X
X	c = vgetc();
X
X	if (State == NORMAL) {
X
X		/* We're in the normal (non-insert) mode. */
X
X		/* Pick up any leading digits and compute 'Prenum' */
X		if ( (Prenum>0 && isdigit(c)) || (isdigit(c) && c!='0') ){
X			Prenum = Prenum*10 + (c-'0');
X			continue;
X		}
X		/* execute the command */
X		normal(c);
X		Prenum = 0;
X
X	} else {
X
X		switch (c) {	/* We're in insert mode */
X
X		case ESC:	/* an escape ends input mode */
X
X			set_want_col = TRUE;
X
X			/* Don't end up on a '\n' if you can help it. */
X			if (gchar(Curschar) == NUL && Curschar->index != 0)
X				dec(Curschar);
X
X			/*
X			 * The cursor should end up on the last inserted
X			 * character. This is an attempt to match the real
X			 * 'vi', but it may not be quite right yet.
X			 */
X			if (Curschar->index != 0 && !endofline(Curschar))
X				dec(Curschar);
X
X			State = NORMAL;
X			msg("");
X			*Uncurschar = *Insstart;
X			Undelchars = Ninsert;
X			/* Undobuff[0] = '\0'; */
X			/* construct the Redo buffer */
X			p=Redobuff;
X			q=Insbuff;
X			while ( q < Insptr )
X				*p++ = *q++;
X			*p++ = ESC;
X			*p = NUL;
X			updatescreen();
X			break;
X
X		case CTRL('D'):
X			/*
X			 * Control-D is treated as a backspace in insert
X			 * mode to make auto-indent easier. This isn't
X			 * completely compatible with vi, but it's a lot
X			 * easier than doing it exactly right, and the
X			 * difference isn't very noticeable.
X			 */
X		case BS:
X			/* can't backup past starting point */
X			if (Curschar->linep == Insstart->linep &&
X			    Curschar->index <= Insstart->index) {
X				beep();
X				break;
X			}
X
X			/* can't backup to a previous line */
X			if (Curschar->linep != Insstart->linep &&
X			    Curschar->index <= 0) {
X				beep();
X				break;
X			}
X
X			did_ai = FALSE;
X			dec(Curschar);
X			delchar(TRUE);
X			Insptr--;
X			Ninsert--;
X			cursupdate();
X			updateline();
X			break;
X
X		case CR:
X		case NL:
X			*Insptr++ = NL;
X			Ninsert++;
X			opencmd(FORWARD, TRUE);		/* open a new line */
X			cursupdate();
X			updatescreen();
X			break;
X
X		default:
X			did_ai = FALSE;
X			insertchar(c);
X			break;
X		}
X	}
X	}
X}
X
X/*
X * Special characters in this context are those that need processing other
X * than the simple insertion that can be performed here. This includes ESC
X * which terminates the insert, and CR/NL which need special processing to
X * open up a new line. This routine tries to optimize insertions performed
X * by the "redo" command, so it needs to know when it should stop and defer
X * processing to the "normal" mechanism.
X */
X#define	ISSPECIAL(c)	((c) == NL || (c) == CR || (c) == ESC)
X
void
insertchar(c)
int c;
X{
X	char *p;
X
X	if ( ! anyinput() ) {
X		inschar(c);
X		*Insptr++ = c;
X		Ninsert++;
X		/*
X		 * The following kludge avoids overflowing the statically
X		 * allocated insert buffer. Just dump the user back into
X		 * command mode, and print a message.
X		 */
X		if (Insptr+10 >= &Insbuff[1024]) {
X			stuffin(mkstr(ESC));
X			emsg("No buffer space - returning to command mode");
X			sleep(2);
X		}
X	}
X	else {
X		/* If there's any pending input, grab it all at once. */
X		p = Insptr;
X		*Insptr++ = c;
X		Ninsert++;
X		for (c = vpeekc(); !ISSPECIAL(c) ;c = vpeekc()) {
X			c = vgetc();
X			*Insptr++ = c;
X			Ninsert++;
X		}
X		*Insptr = '\0';
X		insstr(p);
X	}
X	updateline();
X}
X
void
getout()
X{
X	windgoto(Rows-1,0);
X	putchar('\r');
X	putchar('\n');
X	windexit(0);
X}
X
void
scrolldown(nlines)
int nlines;
X{
X	register LPTR	*p;
X	register int	done = 0;	/* total # of physical lines done */
X
X	/* Scroll up 'nlines' lines. */
X	while (nlines--) {
X		if ((p = prevline(Topchar)) == NULL)
X			break;
X		done += plines(p);
X		*Topchar = *p;
X		if (Curschar->linep == Botchar->linep->prev)
X			*Curschar = *prevline(Curschar);
X	}
X	s_ins(0, done);
X}
X
void
scrollup(nlines)
int nlines;
X{
X	register LPTR	*p;
X	register int	done = 0;	/* total # of physical lines done */
X	register int	pl;		/* # of plines for the current line */
X
X	/* Scroll down 'nlines' lines. */
X	while (nlines--) {
X		pl = plines(Topchar);
X		if ((p = nextline(Topchar)) == NULL)
X			break;
X		done += pl;
X		if (Curschar->linep == Topchar->linep)
X			*Curschar = *p;
X		*Topchar = *p;
X
X	}
X	s_del(0, done);
X}
X
X/*
X * oneright
X * oneleft
X * onedown
X * oneup
X *
X * Move one char {right,left,down,up}.  Return TRUE when
X * sucessful, FALSE when we hit a boundary (of a line, or the file).
X */
X
bool_t
oneright()
X{
X	set_want_col = TRUE;
X
X	switch (inc(Curschar)) {
X
X	case 0:
X		return TRUE;
X
X	case 1:
X		dec(Curschar);		/* crossed a line, so back up */
X		/* fall through */
X	case -1:
X		return FALSE;
X	}
X}
X
bool_t
oneleft()
X{
X	set_want_col = TRUE;
X
X	switch (dec(Curschar)) {
X
X	case 0:
X		return TRUE;
X
X	case 1:
X		inc(Curschar);		/* crossed a line, so back up */
X		/* fall through */
X	case -1:
X		return FALSE;
X	}
X}
X
void
beginline(flag)
bool_t	flag;
X{
X	while ( oneleft() )
X		;
X	if (flag) {
X		while (isspace(gchar(Curschar)) && oneright())
X			;
X	}
X	set_want_col = TRUE;
X}
X
bool_t
oneup(n)
X{
X	LPTR p, *np;
X	int k;
X
X	p = *Curschar;
X	for ( k=0; k<n; k++ ) {
X		/* Look for the previous line */
X		if ( (np=prevline(&p)) == NULL ) {
X			/* If we've at least backed up a little .. */
X			if ( k > 0 )
X				break;	/* to update the cursor, etc. */
X			else
X				return FALSE;
X		}
X		p = *np;
X	}
X	*Curschar = p;
X	/* This makes sure Topchar gets updated so the complete line */
X	/* is one the screen. */
X	cursupdate();
X	/* try to advance to the column we want to be at */
X	*Curschar = *coladvance(&p, Curswant);
X	return TRUE;
X}
X
bool_t
onedown(n)
X{
X	LPTR p, *np;
X	int k;
X
X	p = *Curschar;
X	for ( k=0; k<n; k++ ) {
X		/* Look for the next line */
X		if ( (np=nextline(&p)) == NULL ) {
X			if ( k > 0 )
X				break;
X			else
X				return FALSE;
X		}
X		p = *np;
X	}
X	/* try to advance to the column we want to be at */
X	*Curschar = *coladvance(&p, Curswant);
X	return TRUE;
X}
END_OF_FILE
if test 6480 -ne `wc -c <'edit.c'`; then
    echo shar: \"'edit.c'\" unpacked with wrong size!
fi
# end of 'edit.c'
fi
if test -f 'help.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'help.c'\"
else
echo shar: Extracting \"'help.c'\" \(8348 characters\)
sed "s/^X//" >'help.c' <<'END_OF_FILE'
X/*
X * STevie - ST editor for VI enthusiasts.    ...Tim Thompson...twitch!tjt...
X *
X * Extensive modifications by:  Tony Andrews       onecom!wldrdg!tony
X *
X */
X
X#include "stevie.h"
X
char	*Version = "STEVIE - Version 3.10";
X
static	int	helprow;
X
X#ifdef	HELP
X
X#ifdef	MEGAMAX
overlay "help"
X#endif
X
static	void	longline();
X
bool_t
help()
X{
X
X/***********************************************************************
X * First Screen:   Positioning within file, Adjusting the Screen
X ***********************************************************************/
X
X	outstr(T_ED);
X	windgoto(helprow = 0, 0);
X
longline("\
X   Positioning within file\n\
X   =======================\n\
X      ^F             Forward screenfull             Original version by:\n\
X      ^B             Backward screenfull                Tim Thompson\n");
longline("\
X      ^D             scroll down half screen\n\
X      ^U             scroll up half screen          Extensive hacks by:\n");
longline("\
X      G              Goto line (end default)            Tony Andrews\n\
X      ]]             next function\n\
X      [[             previous function\n\
X      /re            next occurence of regular expression 're'\n");
longline("\
X      ?re            prior occurence of regular expression 're'\n\
X      n              repeat last / or ?\n\
X      N              reverse last / or ?\n\
X      %              find matching (, ), {, }, [, or ]\n");
longline("\
X\n\
X   Adjusting the screen\n\
X   ====================\n\
X      ^L             Redraw the screen\n\
X      ^E             scroll window down 1 line\n\
X      ^Y             scroll window up 1 line\n");
longline("\
X      z<RETURN>      redraw, current line at top\n\
X      z-             ... at bottom\n\
X      z.             ... at center\n");
X
X	windgoto(0, 52);
X	longline(Version);
X
X	windgoto(helprow = Rows-2, 47);
X	longline("<Press space bar to continue>\n");
X	windgoto(helprow = Rows-1, 47);
X	longline("<Any other key will quit>");
X
X	if ( vgetc() != ' ' )
X		return TRUE;
X
X/***********************************************************************
X * Second Screen:   Character positioning
X ***********************************************************************/
X
X	outstr(T_ED);
X	windgoto(helprow = 0, 0);
X
longline("\
X   Character Positioning\n\
X   =====================\n\
X      ^              first non-white\n\
X      0              beginning of line\n\
X      $              end of line\n\
X      h              backward\n");
longline("\
X      l              forward\n\
X      ^H             same as h\n\
X      space          same as l\n\
X      fx             find 'x' forward\n");
longline("\
X      Fx             find 'x' backward\n\
X      tx             upto 'x' forward\n\
X      Tx             upto 'x' backward\n\
X      ;              Repeat last f, F, t, or T\n");
longline("\
X      ,              inverse of ;\n\
X      |              to specified column\n\
X      %              find matching (, ), {, }, [, or ]\n");
X
X	windgoto(helprow = Rows-2, 47);
X	longline("<Press space bar to continue>\n");
X	windgoto(helprow = Rows-1, 47);
X	longline("<Any other key will quit>");
X
X	if ( vgetc() != ' ' )
X		return TRUE;
X
X/***********************************************************************
X * Third Screen:   Line Positioning, Marking and Returning
X ***********************************************************************/
X
X	outstr(T_ED);
X	windgoto(helprow = 0, 0);
X
longline("\
X    Line Positioning\n\
X    =====================\n\
X    H           home window line\n\
X    L           last window line\n\
X    M           middle window line\n");
longline("\
X    +           next line, at first non-white\n\
X    -           previous line, at first non-white\n\
X    CR          return, same as +\n\
X    j           next line, same column\n\
X    k           previous line, same column\n");
X
longline("\
X\n\
X    Marking and Returning\n\
X    =====================\n\
X    ``          previous context\n\
X    ''          ... at first non-white in line\n");
longline("\
X    mx          mark position with letter 'x'\n\
X    `x          to mark 'x'\n\
X    'x          ... at first non-white in line\n");
X
X	windgoto(helprow = Rows-2, 47);
X	longline("<Press space bar to continue>\n");
X	windgoto(helprow = Rows-1, 47);
X	longline("<Any other key will quit>");
X
X	if ( vgetc() != ' ' )
X		return TRUE;
X/***********************************************************************
X * Fourth Screen:   Insert & Replace, 
X ***********************************************************************/
X
X	outstr(T_ED);
X	windgoto(helprow = 0, 0);
X
longline("\
X    Insert and Replace\n\
X    ==================\n\
X    a           append after cursor\n\
X    i           insert before cursor\n\
X    A           append at end of line\n\
X    I           insert before first non-blank\n");
longline("\
X    o           open line below\n\
X    O           open line above\n\
X    rx          replace single char with 'x'\n\
X    R           replace characters (not yet)\n");
X
longline("\
X\n\
X    Words, sentences, paragraphs\n\
X    ============================\n\
X    w           word forward\n\
X    b           back word\n\
X    e           end of word\n\
X    )           to next sentence (not yet)\n\
X    }           to next paragraph (not yet)\n");
longline("\
X    (           back sentence (not yet)\n\
X    {           back paragraph (not yet)\n\
X    W           blank delimited word\n\
X    B           back W\n\
X    E           to end of W\n");
X
X	windgoto(helprow = Rows-2, 47);
X	longline("<Press space bar to continue>\n");
X	windgoto(helprow = Rows-1, 47);
X	longline("<Any other key will quit>");
X
X	if ( vgetc() != ' ' )
X		return TRUE;
X
X/***********************************************************************
X * Fifth Screen:   Misc. operations, 
X ***********************************************************************/
X
X	outstr(T_ED);
X	windgoto(helprow = 0, 0);
X
longline("\
X    Undo  &  Redo\n\
X    =============\n\
X    u           undo last change (partially done)\n\
X    U           restore current line (not yet)\n\
X    .           repeat last change\n");
X
longline("\
X\n\
X    File manipulation\n\
X    =================\n");
longline("\
X    :w          write back changes\n\
X    :wq         write and quit\n\
X    :x          write if modified, and quit\n\
X    :q          quit\n\
X    :q!         quit, discard changes\n\
X    :e name     edit file 'name'\n");
longline("\
X    :e!         reedit, discard changes\n\
X    :e #        edit alternate file\n\
X    :w name     write file 'name'\n");
longline("\
X    :n          edit next file in arglist\n\
X    :n args     specify new arglist (not yet)\n\
X    :rew        rewind arglist\n\
X    :f          show current file and lines\n");
longline("\
X    :f file     change current file name\n\
X    :ta tag     to tag file entry 'tag'\n\
X    ^]          :ta, current word is tag\n");
X
X	windgoto(helprow = Rows-2, 47);
X	longline("<Press space bar to continue>\n");
X	windgoto(helprow = Rows-1, 47);
X	longline("<Any other key will quit>");
X
X	if ( vgetc() != ' ' )
X		return TRUE;
X
X/***********************************************************************
X * Sixth Screen:   Operators, Misc. operations, Yank & Put
X ***********************************************************************/
X
X	outstr(T_ED);
X	windgoto(helprow = 0, 0);
X
longline("\
X    Operators (double to affect lines)\n\
X    ==================================\n\
X    d           delete\n\
X    c           change\n");
longline("\
X    <           left shift\n\
X    >           right shift\n\
X    y           yank to buffer\n");
X
longline("\n\
X    Miscellaneous operations\n\
X    ========================\n\
X    C           change rest of line\n\
X    D           delete rest of line\n\
X    s           substitute chars\n");
longline("\
X    S           substitute lines (not yet)\n\
X    J           join lines\n\
X    x           delete characters\n\
X    X           ... before cursor\n");
X
longline("\n\
X    Yank and Put\n\
X    ============\n\
X    p           put back text\n\
X    P           put before\n\
X    Y           yank lines");
X
X	windgoto(helprow = Rows-1, 47);
X	longline("<Press any key>");
X
X	vgetc();
X
X	return TRUE;
X}
X
static void
longline(p)
char *p;
X{
X	char *s;
X
X	for ( s = p; *s ;s++ ) {
X		if ( *s == '\n' )
X			windgoto(++helprow, 0);
X		else
X			outchar(*s);
X	}
X}
X#else
X
bool_t
help()
X{
X	msg("Sorry, help not configured");
X	return FALSE;
X}
X#endif
END_OF_FILE
if test 8348 -ne `wc -c <'help.c'`; then
    echo shar: \"'help.c'\" unpacked with wrong size!
fi
# end of 'help.c'
fi
if test -f 'main.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'main.c'\"
else
echo shar: Extracting \"'main.c'\" \(6750 characters\)
sed "s/^X//" >'main.c' <<'END_OF_FILE'
X/*
X * STEVIE - ST Editor for VI Enthusiasts   ...Tim Thompson...twitch!tjt...
X *
X * Extensive modifications by:  Tony Andrews       onecom!wldrdg!tony
X *
X */
X
X#include "stevie.h"
X
int Rows;		/* Number of Rows and Columns */
int Columns;		/* in the current window. */
X
char *Realscreen = NULL;	/* What's currently on the screen, a single */
X				/* array of size Rows*Columns. */
char *Nextscreen = NULL;	/* What's to be put on the screen. */
X
char *Filename = NULL;	/* Current file name */
X
LPTR *Filemem;		/* The contents of the file, as a single array. */
X
LPTR *Fileend;		/* Pointer to the end of the file in Filemem. */
X			/* (It points to the byte AFTER the last byte.) */
X
LPTR *Topchar;		/* Pointer to the byte in Filemem which is */
X			/* in the upper left corner of the screen. */
X
LPTR *Botchar;		/* Pointer to the byte in Filemem which is */
X			/* just off the bottom of the screen. */
X
LPTR *Curschar;		/* Pointer to byte in Filemem at which the */
X			/* cursor is currently placed. */
X
int Cursrow, Curscol;	/* Current position of cursor */
X
int Cursvcol;		/* Current virtual column, the column number of */
X			/* the file's actual line, as opposed to the */
X			/* column number we're at on the screen.  This */
X			/* makes a difference on lines that span more */
X			/* than one screen line. */
X
int Curswant = 0;	/* The column we'd like to be at. This is used */
X			/* try to stay in the same column through up/down */
X			/* cursor motions. */
X
bool_t set_want_col;	/* If set, then update Curswant the next time */
X			/* through cursupdate() to the current virtual */
X			/* column. */
X
int State = NORMAL;	/* This is the current state of the command */
X			/* interpreter. */
X
int Prenum = 0;		/* The (optional) number before a command. */
X
LPTR *Insstart;		/* This is where the latest insert/append */
X			/* mode started. */
X
bool_t Changed = 0;	/* Set to 1 if something in the file has been */
X			/* changed and not written out. */
X
bool_t Debug = 0;
X
char Redobuff[1024];	/* Each command should stuff characters into this */
X			/* buffer that will re-execute itself. */
X
char Undobuff[1024];	/* Each command should stuff characters into this */
X			/* buffer that will undo its effects. */
X
char Insbuff[1024];	/* Each insertion gets stuffed into this buffer. */
X
LPTR *Uncurschar;	/* Curschar is restored to this before undoing. */
X
int Ninsert = 0;	/* Number of characters in the current insertion. */
int Undelchars = 0;	/* Number of characters to delete, when undoing. */
char *Insptr = NULL;
X
char **files;		/* list of input files */
int  numfiles;		/* number of input files */
int  curfile;		/* number of the current file */
X
static void
usage()
X{
X	fprintf(stderr, "usage: stevie [file ...]\n");
X	fprintf(stderr, "       stevie -t tag\n");
X	fprintf(stderr, "       stevie +[num] file\n");
X	fprintf(stderr, "       stevie +/pat  file\n");
X	exit(1);
X}
X
main(argc,argv)
int	argc;
char	*argv[];
X{
X	char	*initstr, *getenv();	/* init string from the environment */
X	char	*tag = NULL;		/* tag from command line */
X	char	*pat = NULL;		/* pattern from command line */
X	int	line = -1;		/* line number from command line */
X
X	/*
X	 * Process the command line arguments.
X	 */
X	if (argc > 1) {
X		switch (argv[1][0]) {
X		
X		case '-':			/* -t tag */
X			if (argv[1][1] != 't')
X				usage();
X
X			if (argv[2] == NULL)
X				usage();
X
X			Filename = NULL;
X			tag = argv[2];
X			numfiles = 1;
X			break;
X
X		case '+':			/* +n or +/pat */
X			if (argv[1][1] == '/') {
X				if (argv[2] == NULL)
X					usage();
X				Filename = strsave(argv[2]);
X				pat = &(argv[1][1]);
X				numfiles = 1;
X
X			} else if (isdigit(argv[1][1]) || argv[1][1] == NUL) {
X				if (argv[2] == NULL)
X					usage();
X				Filename = strsave(argv[2]);
X				numfiles = 1;
X
X				line = (isdigit(argv[1][1])) ?
X					atoi(&(argv[1][1])) : 0;
X			} else
X				usage();
X
X			break;
X
X		default:			/* must be a file name */
X			Filename = strsave(argv[1]);
X			files = &(argv[1]);
X			numfiles = argc - 1;
X			break;
X		}
X	} else {
X		Filename = NULL;
X		numfiles = 1;
X	}
X	curfile = 0;
X
X	windinit();
X
X	/*
X	 * Allocate LPTR structures for all the various position pointers
X	 */
X	if ((Filemem = (LPTR *) malloc(sizeof(LPTR))) == NULL) {
X		fprintf(stderr, "Can't allocate data structures\n");
X		windexit(0);
X	}
X	if ((Fileend = (LPTR *) malloc(sizeof(LPTR))) == NULL) {
X		fprintf(stderr, "Can't allocate data structures\n");
X		windexit(0);
X	}
X	if ((Topchar = (LPTR *) malloc(sizeof(LPTR))) == NULL) {
X		fprintf(stderr, "Can't allocate data structures\n");
X		windexit(0);
X	}
X	if ((Botchar = (LPTR *) malloc(sizeof(LPTR))) == NULL) {
X		fprintf(stderr, "Can't allocate data structures\n");
X		windexit(0);
X	}
X	if ((Curschar = (LPTR *) malloc(sizeof(LPTR))) == NULL) {
X		fprintf(stderr, "Can't allocate data structures\n");
X		windexit(0);
X	}
X	if ((Insstart = (LPTR *) malloc(sizeof(LPTR))) == NULL) {
X		fprintf(stderr, "Can't allocate data structures\n");
X		windexit(0);
X	}
X	if ((Uncurschar = (LPTR *) malloc(sizeof(LPTR))) == NULL) {
X		fprintf(stderr, "Can't allocate data structures\n");
X		windexit(0);
X	}
X
X	screenalloc();
X	filealloc();		/* Initialize Filemem & Fileend */
X
X	screenclear();
X
X	if ((initstr = getenv("EXINIT")) != NULL) {
X		char *lp, buf[128];
X
X		if ((lp = getenv("LINES")) != NULL) {
X			sprintf(buf, "%s lines=%s", initstr, lp);
X			readcmdline(':', buf);
X		} else
X			readcmdline(':', initstr);
X	}
X
X	if (Filename != NULL) {
X		if (readfile(Filename, Filemem, FALSE))
X			filemess("[New File]");
X	} else
X		msg("Empty Buffer");
X
X	setpcmark();
X
X	updatescreen();
X	
X	if (tag) {
X		stuffin(":ta ");
X		stuffin(tag);
X		stuffin("\n");
X
X	} else if (pat) {
X		stuffin(pat);
X		stuffin("\n");
X
X	} else if (line >= 0) {
X		if (line > 0)
X			stuffnum(line);
X		stuffin("G");
X	}
X
X	edit();
X
X	windexit(0);
X}
X
X#define	RBSIZE	1280		/* should be a little bigger than YBSIZE */
static char getcbuff[RBSIZE];
static char *getcnext = NULL;
X
void
stuffin(s)
char *s;
X{
X	if ( getcnext == NULL ) {
X		strcpy(getcbuff,s);
X		getcnext = getcbuff;
X	} else
X		strcat(getcbuff,s);
X}
X
void
stuffnum(n)
int	n;
X{
X	char	buf[32];
X
X	sprintf(buf, "%d", n);
X	stuffin(buf);
X}
X
void
addtobuff(s,c1,c2,c3,c4,c5,c6)
char *s;
char c1, c2, c3, c4, c5, c6;
X{
X	char *p = s;
X	if ( (*p++ = c1) == NUL )
X		return;
X	if ( (*p++ = c2) == NUL )
X		return;
X	if ( (*p++ = c3) == NUL )
X		return;
X	if ( (*p++ = c4) == NUL )
X		return;
X	if ( (*p++ = c5) == NUL )
X		return;
X	if ( (*p++ = c6) == NUL )
X		return;
X}
X
int
vgetc()
X{
X	if ( getcnext != NULL ) {
X		int nextc = *getcnext++;
X		if ( *getcnext == NUL ) {
X			*getcbuff = NUL;
X			getcnext = NULL;
X		}
X		return(nextc);
X	}
X	return(inchar());
X}
X
int
vpeekc()
X{
X	if ( getcnext != NULL )
X		return(*getcnext);
X	return(-1);
X}
X
X/*
X * anyinput
X *
X * Return non-zero if input is pending.
X */
X
bool_t
anyinput()
X{
X	return (getcnext != NULL);
X}
END_OF_FILE
if test 6750 -ne `wc -c <'main.c'`; then
    echo shar: \"'main.c'\" unpacked with wrong size!
fi
# end of 'main.c'
fi
if test -f 'misccmds.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'misccmds.c'\"
else
echo shar: Extracting \"'misccmds.c'\" \(8039 characters\)
sed "s/^X//" >'misccmds.c' <<'END_OF_FILE'
X/*
X * STevie - ST editor for VI enthusiasts.    ...Tim Thompson...twitch!tjt...
X *
X * Extensive modifications by:  Tony Andrews       onecom!wldrdg!tony
X *
X */
X
X#include "stevie.h"
X
static	void	openfwd(), openbwd();
X
extern	int	did_ai;
X
X/*
X * opencmd
X *
X * Add a blank line above or below the current line.
X */
X
void
opencmd(dir, can_ai)
int	dir;
int	can_ai;			/* if true, consider auto-indent */
X{
X	if (dir == FORWARD)
X		openfwd(can_ai);
X	else
X		openbwd(can_ai);
X}
X
static void
openfwd(can_ai)
int	can_ai;
X{
X	LINE	*l;
X	LPTR	*next;
X	char	*s;		/* string to be moved to new line, if any */
X
X	/*
X	 * If we're in insert mode, we need to move the remainder of the
X	 * current line onto the new line. Otherwise the new line is left
X	 * blank.
X	 */
X	if (State == INSERT)
X		s = &Curschar->linep->s[Curschar->index];
X	else
X		s = "";
X
X	if ((next = nextline(Curschar)) == NULL)	/* open on last line */
X		next = Fileend;
X
X	/*
X	 * By asking for as much space as the prior line had we make sure
X	 * that we'll have enough space for any auto-indenting.
X	 */
X	if ((l = newline(strlen(Curschar->linep->s) + SLOP)) == NULL)
X		return;
X
X	if (*s != NUL)
X		strcpy(l->s, s);		/* copy string to new line */
X#if 0
X	else if (can_ai && P(P_AI)) {
X		/*
X		 * Auto-indent removed due to buggy implementation...
X		 */
X		 did_ai = TRUE;
X	}
X#endif
X
X	if (State == INSERT)		/* truncate current line at cursor */
X		*s = NUL;
X			
X
X	Curschar->linep->next = l;	/* link neighbors to new line */
X	next->linep->prev = l;
X
X	l->prev = Curschar->linep;	/* link new line to neighbors */
X	l->next = next->linep;
X
X	if (next == Fileend)			/* new line at end */
X		l->num = Curschar->linep->num + LINEINC;
X
X	else if ((l->prev->num) + 1 == l->next->num)	/* no gap, renumber */
X		renum();
X
X	else {					/* stick it in the middle */
X		unsigned long	lnum;
X		lnum = ((long)l->prev->num + (long)l->next->num) / 2;
X		l->num = lnum;
X	}
X
X	*Curschar = *nextline(Curschar);	/* cursor moves down */
X	Curschar->index = 0;
X
X	s_ins(Cursrow+1, 1);	/* insert a physical line */
X
X	updatescreen();		/* because Botchar is now invalid... */
X
X	cursupdate();		/* update Cursrow before insert */
X}
X
static void
openbwd(can_ai)
int	can_ai;
X{
X	LINE	*l;
X	LPTR	*prev;
X
X	prev = prevline(Curschar);
X
X	if ((l = newline(strlen(Curschar->linep->s) + SLOP)) == NULL)
X		return;
X
X	Curschar->linep->prev = l;	/* link neighbors to new line */
X	if (prev != NULL)
X		prev->linep->next = l;
X
X	l->next = Curschar->linep;	/* link new line to neighbors */
X	if (prev != NULL)
X		l->prev = prev->linep;
X
X#if 0
X	if (can_ai && P(P_AI)) {
X		did_ai = TRUE;
X	}
X#endif
X
X	*Curschar = *prevline(Curschar);	/* cursor moves up */
X	Curschar->index = 0;
X
X	if (prev == NULL)			/* new start of file */
X		Filemem->linep = l;
X
X	renum();	/* keep it simple - we don't do this often */
X
X	cursupdate();			/* update Cursrow before insert */
X	if (Cursrow != 0)
X		s_ins(Cursrow, 1);		/* insert a physical line */
X
X	updatescreen();
X}
X
int
cntllines(pbegin,pend)
LPTR *pbegin, *pend;
X{
X	LINE *lp;
X	int lnum = 1;
X
X	for (lp = pbegin->linep; lp != pend->linep ;lp = lp->next)
X		lnum++;
X
X	return(lnum);
X}
X
X/*
X * plines(p) - return the number of physical screen lines taken by line 'p'
X */
int
plines(p)
LPTR	*p;
X{
X	register int	col;
X	register char	*s;
X
X	s = p->linep->s;
X
X	if (*s == NUL)		/* empty line */
X		return 1;
X
X	/*
X	 * If list mode is on, then the '$' at the end of
X	 * the line takes up one extra column.
X	 */
X	col = P(P_LS) ? 1 : 0;
X
X	for (; *s != NUL ;s++) {
X		if ( *s == TAB && !P(P_LS))
X			col += P(P_TS) - (col % P(P_TS));
X		else
X			col += chars[(unsigned)(*s & 0xff)].ch_size;
X	}
X	return ((col + (Columns-1)) / Columns);
X}
X
void
fileinfo()
X{
X	long	l1, l2;
X	char	buf[80];
X
X	if (bufempty()) {
X		msg("Buffer Empty");
X		return;
X	}
X
X	l1 = cntllines(Filemem, Curschar);
X	l2 = cntllines(Filemem, Fileend) - 1;
X	sprintf(buf, "\"%s\"%s line %ld of %ld -- %ld %% --",
X		(Filename != NULL) ? Filename : "No File",
X		Changed ? " [Modified]" : "",
X		l1, l2, (l1 * 100)/l2);
X	msg(buf);
X}
X
X/*
X * gotoline(n) - return a pointer to line 'n'
X *
X * Returns a pointer to the last line of the file if n is zero, or
X * beyond the end of the file.
X */
LPTR *
gotoline(n)
int n;
X{
X	static	LPTR	l;
X
X	l.index = 0;
X
X	if ( n == 0 )
X		l = *prevline(Fileend);
X	else {
X		LPTR	*p;
X
X		for (l = *Filemem; --n > 0 ;l = *p)
X			if ((p = nextline(&l)) == NULL)
X				break;
X	}
X	return &l;
X}
X
void
inschar(c)
int	c;
X{
X	register char	*p, *pend;
X
X	/* make room for the new char. */
X	if ( ! canincrease(1) )
X		return;
X
X	p = &Curschar->linep->s[strlen(Curschar->linep->s) + 1];
X	pend = &Curschar->linep->s[Curschar->index];
X
X	for (; p > pend ;p--)
X		*p = *(p-1);
X
X	*p = c;
X
X	/*
X	 * If we're in insert mode and showmatch mode is set, then
X	 * check for right parens and braces. If there isn't a match,
X	 * then beep. If there is a match AND it's on the screen, then
X	 * flash to it briefly. If it isn't on the screen, don't do anything.
X	 */
X	if (P(P_SM) && State == INSERT && (c == ')' || c == '}' || c == ']')) {
X		LPTR	*lpos, csave;
X
X		if ((lpos = showmatch()) == NULL)	/* no match, so beep */
X			beep();
X		else if (LINEOF(lpos) >= LINEOF(Topchar)) {
X			updatescreen();		/* show the new char first */
X			csave = *Curschar;
X			*Curschar = *lpos;	/* move to matching char */
X			cursupdate();
X			windgoto(Cursrow, Curscol);
X			delay();		/* brief pause */
X			*Curschar = csave;	/* restore cursor position */
X			cursupdate();
X		}
X	}
X
X	inc(Curschar);
X	CHANGED;
X}
X
void
insstr(s)
register char *s;
X{
X	register char *p, *endp;
X	register int k, n = strlen(s);
X
X	/* Move everything in the file over to make */
X	/* room for the new string. */
X	if (!canincrease(n))
X		return;
X
X	endp = &Curschar->linep->s[Curschar->index];
X	p = Curschar->linep->s + strlen(Curschar->linep->s) + 1 + n;
X
X	for (; p>endp ;p--)
X		*p = *(p-n);
X
X	p = &Curschar->linep->s[Curschar->index];
X	for ( k=0; k<n; k++ ) {
X		*p++ = *s++;
X		inc(Curschar);
X	}
X	CHANGED;
X}
X
bool_t
delchar(fixpos)
bool_t	fixpos;		/* if TRUE, fix the cursor position when done */
X{
X	register int i;
X
X	/* Check for degenerate case; there's nothing in the file. */
X	if (bufempty())
X		return FALSE;
X
X	if (lineempty())	/* can't do anything */
X		return FALSE;
X
X	/* Delete the char. at Curschar by shifting everything */
X	/* in the line down. */
X	for ( i=Curschar->index+1; i < Curschar->linep->size ;i++)
X		Curschar->linep->s[i-1] = Curschar->linep->s[i];
X
X	/* If we just took off the last character of a non-blank line, */
X	/* we don't want to end up positioned at the newline. */
X	if (fixpos) {
X		if (gchar(Curschar)==NUL && Curschar->index>0 && State!=INSERT)
X			Curschar->index--;
X	}
X	CHANGED;
X
X	return TRUE;
X}
X
X
void
delline(nlines)
X{
X	register LINE *p, *q;
X	int	doscreen = TRUE;	/* if true, update the screen */
X
X	/*
X	 * There's no point in keeping the screen updated if we're
X	 * deleting more than a screen's worth of lines.
X	 */
X	if (nlines > (Rows - 1)) {
X		doscreen = FALSE;
X		s_del(Cursrow, Rows-1);	/* flaky way to clear rest of screen */
X	}
X
X	while ( nlines-- > 0 ) {
X
X		if (bufempty())			/* nothing to delete */
X			break;
X
X		if (buf1line()) {		/* just clear the line */
X			Curschar->linep->s[0] = NUL;
X			Curschar->index = 0;
X			break;
X		}
X
X		p = Curschar->linep->prev;
X		q = Curschar->linep->next;
X
X		if (p == NULL) {		/* first line of file so... */
X			Filemem->linep = q;	/* adjust start of file */
X			Topchar->linep = q;	/* and screen */
X		} else
X			p->next = q;
X		q->prev = p;
X
X		clrmark(Curschar->linep);	/* clear marks for the line */
X
X		/*
X		 * Delete the correct number of physical lines on the screen
X		 */
X		if (doscreen)
X			s_del(Cursrow, plines(Curschar));
X
X		/*
X		 * If deleting the top line on the screen, adjust Topchar
X		 */
X		if (Topchar->linep == Curschar->linep)
X			Topchar->linep = q;
X
X		free(Curschar->linep->s);
X		free(Curschar->linep);
X
X		Curschar->linep = q;
X		Curschar->index = 0;		/* is this right? */
X		CHANGED;
X
X		/* If we delete the last line in the file, back up */
X		if ( Curschar->linep == Fileend->linep) {
X			Curschar->linep = Curschar->linep->prev;
X			/* and don't try to delete any more lines */
X			break;
X		}
X	}
X}
END_OF_FILE
if test 8039 -ne `wc -c <'misccmds.c'`; then
    echo shar: \"'misccmds.c'\" unpacked with wrong size!
fi
# end of 'misccmds.c'
fi
echo shar: End of archive 2 \(of 4\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 4 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.



More information about the Comp.sources.unix mailing list