#! /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 6 (of 13)."
# Contents:  stevie/cmdline.c stevie/misccmds.c stevie/unix.c
# Wrapped by thor@surt on Fri Oct 16 09:43:46 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'stevie/cmdline.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'stevie/cmdline.c'\"
else
echo shar: Extracting \"'stevie/cmdline.c'\" \(11790 characters\)
sed "s/^X//" >'stevie/cmdline.c' <<'END_OF_FILE'
X/* $Header: /nw/tony/src/stevie/src/RCS/cmdline.c,v 1.20 89/08/13 11:41:23 tony Exp $
X *
X * Routines to parse and execute "command line" commands, such as searches
X * or colon commands.
X */
X
X#include "stevie.h"
X
Xstatic	char	*altfile = NULL;	/* alternate file */
Xstatic	int	altline;		/* line # in alternate file */
X
Xstatic	char	*nowrtmsg = "No write since last change (use ! to override)";
Xstatic	char	*nooutfile = "No output file";
Xstatic	char	*morefiles = "more files to edit";
X
Xextern	char	**files;		/* used for "n" and "rew" */
Xextern	int	numfiles, curfile;
X
X#define	CMDSZ	100		/* size of the command buffer */
X
Xstatic	void	get_range();
Xstatic	LPTR	*get_line();
X
X/*
X * getcmdln() - read a command line from the terminal
X *
X * Reads a command line started by typing '/', '?', '!', or ':'. Returns a
X * pointer to the string that was read. For searches, an optional trailing
X * '/' or '?' is removed.
X */
Xchar *
Xgetcmdln(firstc)
Xchar	firstc;
X{
X	static	char	buff[CMDSZ];
X	register char	*p = buff;
X	register int	c;
X	register char	*q;
X
X	gotocmd(TRUE, firstc);
X
X	/* collect the command string, handling '\b' and @ */
X	do {
X		switch (c = vgetc()) {
X
X		default:		/* a normal character */
X			outchar(c);
X			*p++ = c;
X			break;
X
X		case BS:
X			if (p > buff) {
X				/*
X				 * this is gross, but it relies
X				 * only on 'gotocmd'
X				 */
X				p--;
X				gotocmd(TRUE, firstc);
X				for (q = buff; q < p ;q++)
X					outchar(*q);
X			} else {
X				msg("");
X				return NULL;		/* back to cmd mode */
X			}
X			break;
X
X		case '@':			/* line kill */
X			p = buff;
X			gotocmd(TRUE, firstc);
X			break;
X
X		case ESC:			/* abandon command */
X			msg("");
X			return  NULL;
X			break;
X
X		case NL:			/* done reading the line */
X		case CR:
X			break;
X		}
X	} while (c != NL && c != CR);
X
X	*p = '\0';
X
X	if (firstc == '/' || firstc == '?') {	/* did we do a search? */
X		/*
X		 * Look for a terminating '/' or '?'. This will be the first
X		 * one that isn't quoted. Truncate the search string there.
X		 */
X		for (p = buff; *p ;) {
X			if (*p == firstc) {	/* we're done */
X				*p = '\0';
X				break;
X			} else if (*p == '\\')	/* next char quoted */
X				p += 2;
X			else
X				p++;		/* normal char */
X		}
X	}
X	return buff;
X}
X
X/*
X * docmdln() - handle a colon command
X *
X * Handles a colon command received interactively by getcmdln() or from
X * the environment variable "EXINIT" (or eventually .virc).
X */
Xvoid
Xdocmdln(cmdline)
Xchar	*cmdline;
X{
X	char	buff[CMDSZ];
X	char	cmdbuf[CMDSZ];
X	char	argbuf[CMDSZ];
X	char	*cmd, *arg;
X	register char	*p;
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	 */
X	LPTR	l_pos, u_pos;
X
X
X	/*
X	 * Clear the range variables.
X	 */
X	l_pos.linep = (struct line *) NULL;
X	u_pos.linep = (struct line *) NULL;
X
X	if (cmdline == NULL)
X		return;
X
X	if (strlen(cmdline) > CMDSZ-2) {
X		msg("Error: command line too long");
X		return;
X	}
X	strcpy(buff, cmdline);
X
X	/* skip any initial white space */
X	for (cmd = buff; *cmd != NUL && isspace(*cmd) ;cmd++)
X		;
X
X	if (*cmd == '%') {		/* change '%' to "1,$" */
X		strcpy(cmdbuf, "1,$");	/* kind of gross... */
X		strcat(cmdbuf, cmd+1);
X		strcpy(cmd, cmdbuf);
X	}
X
X	while ((p=strchr(cmd, '%')) != NULL && *(p-1) != '\\') {
X					/* change '%' to Filename */
X		if (Filename == NULL) {
X			emsg("No filename");
X			return;
X		}
X		*p= NUL;
X		strcpy (cmdbuf, cmd);
X		strcat (cmdbuf, Filename);
X		strcat (cmdbuf, p+1);
X		strcpy(cmd, cmdbuf);
X		msg(cmd);			/*repeat */
X	}
X
X	while ((p=strchr(cmd, '#')) != NULL && *(p-1) != '\\') {
X					/* change '#' to Altname */
X		if (altfile == NULL) {
X			emsg("No alternate file");
X			return;
X		}
X		*p= NUL;
X		strcpy (cmdbuf, cmd);
X		strcat (cmdbuf, altfile);
X		strcat (cmdbuf, p+1);
X		strcpy(cmd, cmdbuf);
X		msg(cmd);			/*repeat */
X	}
X
X	/*
X	 * Parse a range, if present (and update the cmd pointer).
X	 */
X	get_range(&cmd, &l_pos, &u_pos);
X
X	if (l_pos.linep != NULL) {
X		if (LINEOF(&l_pos) > LINEOF(&u_pos)) {
X			emsg("Invalid range");
X			return;
X		}
X	}
X
X	strcpy(cmdbuf, cmd);	/* save the unmodified command */
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		if (*p == NUL)
X			arg = NULL;
X		else {
X			strcpy(argbuf, p);
X			arg = argbuf;
X		}
X	}
X	if (strcmp(cmd,"q!") == 0)
X		getout();
X	if (strcmp(cmd,"q") == 0) {
X		if (Changed)
X			emsg(nowrtmsg);
X		else {
X			if ((curfile + 1) < numfiles)
X				emsg(morefiles);
X			else
X				getout();
X		}
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			} else
X				emsg(nooutfile);
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, (LPTR *)NULL, (LPTR *)NULL))
X				getout();
X		} else
X			emsg(nooutfile);
X		return;
X	}
X	if (strcmp(cmd, "x") == 0) {
X		doxit();
X		return;
X	}
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 == 'N') {
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		(void) doecmd(arg, cmd[1] == '!');
X		return;
X	}
X	/*
X	 * The command ":e#" gets expanded to something like ":efile", so
X	 * detect that case here.
X	 */
X	if (*cmd == 'e' && arg == NULL) {
X		if (cmd[1] == '!')
X			(void) doecmd(&cmd[2], TRUE);
X		else
X			(void) doecmd(&cmd[1], FALSE);
X		return;
X	}
X	if (strcmp(cmd,"f") == 0) {
X		EnvEval (arg, CMDSZ);	/* expand environment vars */
X		Filename = strsave(arg);
X		filemess("");
X		return;
X	}
X	if (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		smsg("%d", cntllines(Filemem, &l_pos));
X		return;
X	}
X	if (strncmp(cmd,"ta", 2) == 0) {
X		dotag(arg, cmd[2] == '!');
X		return;
X	}
X	if (strncmp(cmd,"untag", 5) == 0) {
X		if (P(P_TG))
X			dountag(cmd[5]);
X		else
X			emsg("Tag stacking not enabled");
X		return;
X	}
X	if (strncmp(cmd,"set", 2) == 0) {
X		doset(arg);
X		return;
X	}
X	if (strcmp(cmd,"help") == 0) {
X		if (vi_help()) {
X			screenclear();
X			updatescreen();
X		}
X		return;
X	}
X	if (strncmp(cmd, "ve", 2) == 0) {
X		extern	char	*Version;
X
X		msg(Version);
X		return;
X	}
X	if (strcmp(cmd, "sh") == 0) {
X		doshell(NULL);
X		return;
X	}
X	if (*cmd == '!') {
X		doshell(cmdbuf+1);
X		return;
X	}
X	if (strncmp(cmd, "s/", 2) == 0) {
X		dosub(&l_pos, &u_pos, cmdbuf+1);
X		return;
X	}
X	if (strncmp(cmd, "g/", 2) == 0) {
X		doglob(&l_pos, &u_pos, cmdbuf+1);
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		return;
X	}
X
X	badcmd();
X}
X
X
Xdoxit()
X{
X	if (Changed) {
X		if (Filename != NULL) {
X			if (!writeit(Filename, (LPTR *)NULL, (LPTR *)NULL))
X				return;
X		} else {
X			emsg(nooutfile);
X			return;
X		}
X	}
X	if ((curfile + 1) < numfiles)
X		emsg(morefiles);
X	else
X		getout();
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 */
Xstatic void
Xget_range(cp, lower, upper)
Xregister char	**cp;
XLPTR	*lower, *upper;
X{
X	register LPTR	*l;
X	register char	*p;
X
X	if ((l = get_line(cp)) == NULL)
X		return;
X
X	*lower = *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		*upper = *lower;
X		return;
X	}
X
X	*cp = ++p;
X
X	if ((l = get_line(cp)) == NULL) {
X		*upper = *lower;
X		return;
X	}
X
X	*upper = *l;
X}
X
Xstatic LPTR *
Xget_line(cp)
Xchar	**cp;
X{
X	static	LPTR	pos;
X	LPTR	*lp;
X	register char	*p, c;
X	register 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
Xvoid
Xbadcmd()
X{
X	emsg("Unrecognized command");
X}
X
Xbool_t
Xdoecmd(arg, force)
Xchar	*arg;
Xbool_t	force;
X{
X	int	line = 1;		/* line # to go to in new file */
X
X	if (!force && Changed) {
X		emsg(nowrtmsg);
X		if (altfile)
X			free(altfile);
X		altfile = strsave(arg);
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 (altfile) {
X			if (strcmp (arg, altfile) == 0)
X				line = altline;
X			free(altfile);
X		}
X		altfile = Filename;
X		altline = cntllines(Filemem, Curschar);
X		Filename = strsave(arg);
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	if (readfile(Filename, Filemem, 0))
X		filemess("[New File]");
X
X	*Topchar = *Curschar;
X	if (line != 1) {
X		stuffnum(line);
X		stuffin("G");
X	}
X	do_mlines();
X	setpcmark();
X	updatescreen();
X	return TRUE;
X}
X
Xvoid
Xgotocmd(clr, firstc)
Xbool_t  clr;
Xchar	firstc;
X{
X	windgoto(Rows-1,0);
X	if (clr)
X		CLEOL;		/* 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 */
Xvoid
Xmsg(s)
Xchar	*s;
X{
X	gotocmd(TRUE, 0);
X	outstr(s);
X	flushbuf();
X}
X
X/*VARARGS1*/
Xvoid
Xsmsg(s, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)
Xchar	*s;
Xint	a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16;
X{
X	char	sbuf[80];
X
X	sprintf(sbuf, s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16);
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 */
Xvoid
Xemsg(s)
Xchar	*s;
X{
X	if (P(P_EB))
X		beep();
X	msg(s);
X}
X
Xvoid
Xwait_return()
X{
X	register char	c;
X
X	if (got_int)
X		outstr("Interrupt: ");
X
X	outstr("Press RETURN to continue");
X	do {
X		c = vgetc();
X	} while (c != CR && c != NL && c != ' ' && c != ':');
X
X	if (c == ':') {
X		outchar(NL);
X		docmdln(getcmdln(c));
X	} else
X		screenclear();
X
X	updatescreen();
X}
END_OF_FILE
if test 11790 -ne `wc -c <'stevie/cmdline.c'`; then
    echo shar: \"'stevie/cmdline.c'\" unpacked with wrong size!
fi
# end of 'stevie/cmdline.c'
fi
if test -f 'stevie/misccmds.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'stevie/misccmds.c'\"
else
echo shar: Extracting \"'stevie/misccmds.c'\" \(9492 characters\)
sed "s/^X//" >'stevie/misccmds.c' <<'END_OF_FILE'
X/* $Header: /nw/tony/src/stevie/src/RCS/misccmds.c,v 1.14 89/08/06 09:50:17 tony Exp $
X *
X * Various routines to perform specific editing operations or return
X * useful information about the file.
X */
X
X#include "stevie.h"
X
Xstatic	void	openfwd(), openbwd();
X
Xextern	bool_t	did_ai;
X
X/*
X * opencmd
X *
X * Add a blank line above or below the current line.
X */
X
Xvoid
Xopencmd(dir, can_ai)
Xint	dir;
Xint	can_ai;			/* if true, consider auto-indent */
X{
X	if (dir == FORWARD)
X		openfwd(can_ai);
X	else
X		openbwd(can_ai);
X}
X
Xstatic void
Xopenfwd(can_ai)
Xint	can_ai;
X{
X	register LINE	*l;
X	LPTR	*next;
X	register char	*s;	/* string to be moved to new line, if any */
X	int	newindex = 0;	/* index of the cursor on the new line */
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 || State == REPLACE)
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
X	else if (can_ai && P(P_AI) && !anyinput()) {
X		char	*p;
X
X		/*
X		 * Copy prior line, and truncate after white space
X		 */
X		strcpy(l->s, Curschar->linep->s);
X
X		for (p = l->s; *p == ' ' || *p == TAB ;p++)
X			;
X		*p = NUL;
X		newindex = p - l->s;
X
X		/*
X		 * If we just did an auto-indent, then we didn't type
X		 * anything on the prior line, and it should be truncated.
X		 */
X		if (did_ai)
X			Curschar->linep->s[0] = NUL;
X
X		did_ai = TRUE;
X	}
X
X	/* truncate current line at cursor */
X	if (State == INSERT || State == REPLACE)
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	/*
X	 * Get the cursor to the start of the line, so that 'Cursrow'
X	 * gets set to the right physical line number for the stuff
X	 * that follows...
X	 */
X	Curschar->index = 0;
X	cursupdate();
X
X	/*
X	 * If we're doing an open on the last logical line, then
X	 * go ahead and scroll the screen up. Otherwise, just insert
X	 * a blank line at the right place. We use calls to plines()
X	 * in case the cursor is resting on a long line.
X	 */
X	if (Cursrow + plines(Curschar) == (Rows - 1))
X		scrollup(1);
X	else
X		s_ins(Cursrow+plines(Curschar), 1);
X
X	*Curschar = *nextline(Curschar);	/* cursor moves down */
X	Curschar->index = newindex;
X
X	updatescreen();		/* because Botchar is now invalid... */
X
X	cursupdate();		/* update Cursrow before insert */
X}
X
Xstatic void
Xopenbwd(can_ai)
Xint	can_ai;
X{
X	register LINE	*l;
X	LINE	*prev;
X	int	newindex = 0;
X
X	prev = Curschar->linep->prev;
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	prev->next = l;
X
X	l->next = Curschar->linep;	/* link new line to neighbors */
X	l->prev = prev;
X
X	if (can_ai && P(P_AI) && !anyinput()) {
X		char	*p;
X
X		/*
X		 * Copy current line, and truncate after white space
X		 */
X		strcpy(l->s, Curschar->linep->s);
X
X		for (p = l->s; *p == ' ' || *p == TAB ;p++)
X			;
X		*p = NUL;
X		newindex = p - l->s;
X
X		did_ai = TRUE;
X	}
X
X	Curschar->linep = Curschar->linep->prev;
X	Curschar->index = newindex;
X
X	if (prev == Filetop->linep)		/* 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
Xint
Xcntllines(pbegin,pend)
Xregister LPTR	*pbegin, *pend;
X{
X	register 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 */
Xint
Xplines(p)
XLPTR	*p;
X{
X	register int	col = 0;
X	register char	*s;
X
X	s = p->linep->s;
X
X	if (*s == NUL)		/* empty line */
X		return 1;
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
X	/*
X	 * If list mode is on, then the '$' at the end of
X	 * the line takes up one extra column.
X	 */
X	if (P(P_LS))
X		col += 1;
X	/*
X	 * If 'number' mode is on, add another 8.
X	 */
X	if (P(P_NU))
X		col += 8;
X
X	return ((col + (Columns-1)) / Columns);
X}
X
Xvoid
Xfileinfo()
X{
X	extern	int	numfiles, curfile;
X	register long	l1, l2;
X
X	if (bufempty()) {
X 		l1 = 0;
X 		l2 = 1;			/* don't div by zero */
X 	} else {
X 		l1 = cntllines(Filemem, Curschar);
X 		l2 = cntllines(Filemem, Fileend) - 1;
X	}
X
X	if (numfiles > 1)
X		smsg("\"%s\"%s line %ld of %ld -- %ld %% -- (file %d of %d)",
X			(Filename != NULL) ? Filename : "No File",
X			Changed ? " [Modified]" : "",
X			l1, l2, (l1 * 100)/l2,
X			curfile+1, numfiles);
X	else
X		smsg("\"%s\"%s line %ld of %ld -- %ld %% --",
X			(Filename != NULL) ? Filename : "No File",
X			Changed ? " [Modified]" : "",
X			l1, l2, (l1 * 100)/l2);
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 */
XLPTR *
Xgotoline(n)
Xregister 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
Xvoid
Xinschar(c)
Xint	c;
X{
X	register char	*p, *pend;
X
X	/* make room for the new char. */
X	if ( ! canincrease(1) )
X		return;
X
X	if (State != REPLACE) {
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	} else {	/* replace mode */
X		/*
X		 * Once we reach the end of the line, we are effectively
X		 * inserting new text, so make sure the string terminator
X		 * stays out there.
X		 */
X		if (gchar(Curschar) == NUL)
X			Curschar->linep->s[Curschar->index+1] = NUL;
X		pchar(Curschar, c);
X	}
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			pause();		/* brief pause */
X			*Curschar = csave;	/* restore cursor position */
X			cursupdate();
X		}
X	}
X
X	inc(Curschar);
X	CHANGED;
X}
X
Xbool_t
Xdelchar(fixpos)
Xbool_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
Xvoid
Xdelline(nlines, can_update)
Xint	nlines;
Xbool_t	can_update;
X{
X	register LINE	*p, *q;
X	int	doscreen;		/* if true, update the screen */
X
X	doscreen = can_update;
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) && can_update) {
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 == Filetop->linep) {	/* first line of file so... */
X			Filemem->linep = q;	/* adjust start of file */
X			Topchar->linep = q;	/* and screen */
X		}
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((char *) 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 9492 -ne `wc -c <'stevie/misccmds.c'`; then
    echo shar: \"'stevie/misccmds.c'\" unpacked with wrong size!
fi
# end of 'stevie/misccmds.c'
fi
if test -f 'stevie/unix.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'stevie/unix.c'\"
else
echo shar: Extracting \"'stevie/unix.c'\" \(12229 characters\)
sed "s/^X//" >'stevie/unix.c' <<'END_OF_FILE'
X/* $Header: /nw/tony/src/stevie/src/RCS/unix.c,v 1.8 89/08/06 09:51:13 tony Exp $
X *
X * System-dependent routines for UNIX System V or Berkeley (BSD).
X * Also VxWorks 4.0.2 real-time system.
X */
X
X#include "stevie.h"
X#include "term.h"
X
X#ifdef VxWorks
X# include <ioLib.h>
X# include <sigLib.h>
X#else
X# ifdef BSD
X#  include <sgtty.h>
X# else
X#  include <termio.h>
X# endif
X# include <signal.h>
X#endif
X
X#include <assert.h>
X
X#ifdef TERMCAP
Xshort ospeed = 9600;          /* baud rate for tputs (termlib) */
Xchar PC = NULL;               /* padding character for tputs */
X#endif
X
X/*
X * inchar() - get a character from the keyboard
X */
Xint
Xinchar()
X{
X#ifdef VxWorks
X# define TIMEOUT      30    /* number of 1/60ths of a second to wait for cursor
X                                 code completion */
X#else
X# define TIMEOUT       5    /* number of 1/10ths of a second to wait for cursor
X                                 code completion */
X#endif
X
X        int j;              /* loop index */
X	char c;             /* input character */
X        char keystr[9];     /* escape sequences/key names */
X        int kl;             /* escape sequence length */
X        int esc_code;       /* decoded escape sequence code */
X        bool_t part_escape; /* flag: partial escape sequences match */
X        char* kn;           /* pointer to T_Kx */
X        int timeout;        /* timeout for waiting for cursor code completion */
X      
X
X	got_int = FALSE;
X
X	flushbuf();		/* flush any pending output */
X#ifdef TERMCAP
X        fflush(stdout);         /* tputs uses stdout, so make sure flushed */
X#endif
X
X	do {
X		while (read(0, &c, 1) != 1)
X			;
X	} while (c == NUL);
X
X        if (c==DEL)  {
X           c=BS;                /* always map DEL to backspace */
X        }
X        else if (c=='' && State==NORMAL)  {
X           /* this is control-^ or control-6 on some terminals. It is the same
X                as :e # */
X           stuffin(":e #\n");
X           return -1;
X        }
X        else if (c==T_KU[0])  {
X           /* Decode cursor keys T_KU, T_KD, T_KR, T_KL. Assumes they all
X                start with the same code, typically escape. */
X
X           keystr[0]=c;
X           keystr[1]=NULL;
X
X           kl=1;
X           esc_code=-1;
X           while (esc_code==-1 && kl<8)  {
X
X              timeout=0;
X              do {
X#ifdef VxWorks
X                 while (!kbhit())  {
X                    usleep(16667);          /* wait for 1/60th of a second */
X#endif
X                    if (++timeout>TIMEOUT)  {
X                       stuffin(keystr);
X                       return -1;
X                    }
X#ifdef VxWorks
X                 }
X#endif
X                 if (read(0, &c, 1) != 1)
X                    c=NUL;
X              } while (c == NUL);
X
X              keystr[kl++]=c;
X              keystr[kl]=NULL;
X
X              part_escape=FALSE;
X
X              for (j=0; j<4; j++)  {    /* enumerate cursor keys */
X
X                 switch (j)  {
X                    case 0: kn=T_KU; break;
X                    case 1: kn=T_KD; break;
X                    case 2: kn=T_KR; break;
X                    case 3: kn=T_KL; break;
X                    default: assert(FALSE);
X                 }
X
X                 /* check for match/partial match */
X                 if (kn[0]!=NULL && strncmp(keystr,kn,kl)==0)  {
X                    part_escape=TRUE;
X                    if (strlen(kn)==kl)  {
X                       /* complete match */
X                       esc_code=j;
X                       break;
X                    }
X                 }
X              }
X
X              if (!part_escape)  {
X                 /* no more possibilities for match, so quit */
X                 break;
X              }
X           }
X
X           if (esc_code!=-1)  {
X              /* got valid special key */
X              if (State != NORMAL)  {
X                 c=ESC;                /* not in command mode, so enter it */
X              }
X              else  {
X                 switch (esc_code)  {
X                    case 0: c=K_UARROW; break;
X                    case 1: c=K_DARROW; break;
X                    case 2: c=K_RARROW; break;
X                    case 3: c=K_LARROW; break;
X                    default: assert(FALSE);
X                 }
X              }
X           }
X           else {
X              stuffin(keystr);
X              return -1;
X           }
X        }
X
X	return c & 0xff;       /* mask because returning an int! */
X}
X
X#define	BSIZE	2048
Xstatic	char	outbuf[BSIZE];
Xstatic	int	bpos = 0;
X
X#ifdef TERMCAP
X/*
X * Function to output a character, to be passed to termlib routine tputs().
X */
Xstatic int
X_putchar(c)
Xchar c;
X{
X      return (putchar(c));
X}
X
Xvoid
Xflushbuf_pad()
X/*
X * Uses tputs so that padding specs in termcap get expanded.
X * This should be used to output control string sequences extracted from
X * termcap, such as cursor motion.
X * Important: The padding spec is expanded only if at the beginning of outbuf,
X * therefore calling routine must call flushbuf() immediately _before_
X * outputting the termcap control string and flushbuf_pad() immediately after.
X * Note that _putchar() uses stdio-buffered I/O, so flushbuf() must as well.
X */
X{
X        if (bpos > 0)  {
X                outbuf[bpos]=NULL;           /* null-terminate */
X                tputs(outbuf, 0, _putchar);
X        }
X        bpos = 0;
X}
X#endif
X
Xvoid
Xflushbuf()
X{
X        if (bpos > 0)  {
X#ifdef TERMCAP
X                /* use stdio-buffered I/O because flushbuf_pad() does */
X                fwrite(outbuf, 1, bpos, stdout);
X#else
X		write(1, outbuf, bpos);
X#endif
X        }
X	bpos = 0;
X}
X
X/*
X * Macro to output a character. Used within this file for speed.
X */
X#define	outone(c) outbuf[bpos++] = (c) & 0xff; if (bpos >= BSIZE) flushbuf()
X
X/*
X * Function version for use outside this file.
X */
Xvoid
Xoutchar(c)
Xchar	c;
X{
X	outone(c);
X}
X
Xvoid
Xoutstr(s)
Xregister char	*s;
X{
X	while (*s) {
X		outone(*s++);
X	}
X}
X
Xvoid
Xbeep()
X{
X	if ( P(P_VB) )
X		vbeep ();
X	else
X		outone('\007');
X}
X
X/*
X * remove(file) - remove a file
X */
Xvoid
Xremove(file)
Xchar *file;
X{
X 	if (file==NULL || file[0]==NULL)
X		return;
X#ifdef VxWorks
X	delete(file);
X#else
X	unlink(file);
X#endif
X}
X
X/*
X * rename(of, nf) - rename existing file 'of' to 'nf'
X * This doesn't really care if it succeeds(!)
X */
X#ifdef VxWorks
Xvoid
X_rename(of, nf)
Xchar	*of, *nf;
X{
X   STATUS st;
X   int fd;
X
X   if (of == NULL || of[0]==NULL || nf == NULL || nf[0]==NULL)
X       return;
X
X   /* try to open 'of' */
X   if ((fd = open (of, READ, 0)) < OK) {
X       /* printf ("can't open: %s\n", of); */
X       return;
X   }
X
X   /* delete any file with same name as 'nf' */
X   st=delete(nf);
X
X   /* rename it */
X   if (ioctl (fd, FIORENAME, nf) != OK) {
X       /* printf ("unable to rename file %s to %s\n", of,nf); */
X       st = ERROR;
X   }
X   else {
X       st = OK;
X   }
X
X   close (fd);
X   return /*(st)*/;
X}
X   
X#else   /* not VxWorks */
X
Xvoid
Xrename(of, nf)
Xchar	*of, *nf;
X{
X	unlink(nf);
X	link(of, nf);
X	unlink(of);
X}
X
X#endif /* VxWorks */
X
Xvoid
Xpause()
X{
X	sleep (1);
X}
X
X#ifdef VxWorks
Xstatic int ostate = 0;
X#else
X# ifdef BSD
Xstatic	struct	sgttyb	ostate;
X# else
Xstatic	struct	termio	ostate;
X# endif
X#endif
X
X/*
X * Go into cbreak mode
X */
Xvoid
Xset_tty()
X{
X#ifdef VxWorks
X        ostate=ioctl(0,FIOGETOPTIONS,0);
X        ioctl(0,FIOSETOPTIONS,OPT_CRMOD | OPT_TANDEM | OPT_7_BIT); /* set raw */
X        ospeed=13;         /* this is the termio/gtty code for 9600 baud,
X                                used by tputs() in the termlib library */
X#else
X# ifdef BSD
X	struct	sgttyb	nstate;
X
X	ioctl(0, TIOCGETP, &ostate);
X        ospeed=ostate.ospeed;            /* determine baud rate */
X	nstate = ostate;
X	nstate.sg_flags &= ~(XTABS|CRMOD|ECHO);
X	nstate.sg_flags |= CBREAK;
X	ioctl(0, TIOCSETN, &nstate);
X# else
X	struct	termio	nstate;
X
X	ioctl(0, TCGETA, &ostate);
X        ospeed=ostate.c_cflag & CBAUD;   /* determine baud rate */
X	nstate = ostate;
X	nstate.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
X	nstate.c_cc[VMIN] = 0;
X	nstate.c_cc[VTIME] = 1;       /* reads time out after 100 ms */
X	ioctl(0, TCSETAW, &nstate);
X# endif /* BSD */
X#endif  /* VxWorks */
X}
X
X/*
X * Restore original terminal modes
X */
Xvoid
Xreset_tty()
X{
X#ifdef VxWorks
X        ioctl(0,FIOSETOPTIONS,ostate);            /* restore */
X#else
X# ifdef BSD
X	ioctl(0, TIOCSETP, &ostate);
X# else
X	ioctl(0, TCSETAW, &ostate);
X# endif /* BSD */
X#endif  /* VxWorks */
X}
X
X#ifdef VxWorks
XFUNCPTR
Xsignal(type, func)
Xint type;
XFUNCPTR func;
X{
X   STATUS st;
X   SIGVEC sv;
X   SIGVEC svold;
X
X   sv.sv_handler=func;
X   sv.sv_mask=0;
X   sv.sv_flags=0;
X
X   st=sigvec(type, &sv, &svold);
X   if (st==VX_ERROR)
X      return((FUNCPTR)-1);
X   
X   return(svold.sv_handler);
X}
X#endif
X
X
Xvoid
Xsig()
X{
X	signal(SIGINT, sig);
X	signal(SIGQUIT, sig);
X
X	got_int = TRUE;
X}
X
Xvoid
Xwindinit()
X{
X#ifdef	TERMCAP
X	if (t_init() != 1) {
X		exit(1);
X	}
X#else
X	Columns = 80;
X	P(P_LI) = Rows = 24;
X#endif
X
X	/*
X	 * The code here makes sure that there isn't a window during which
X	 * we could get interrupted and exit with the tty in a weird state.
X	 */
X	signal(SIGINT, sig);
X	signal(SIGQUIT, sig);
X
X	set_tty();
X
X	if (got_int)
X		windexit(0);
X}
X
Xvoid
Xwindexit(r)
Xint r;
X{
X	reset_tty();
X	exit(r);
X}
X
Xvoid
Xwindgoto(r, c)
Xregister int	r, c;
X{
X#ifdef	TERMCAP
X	char	*tgoto();
X#else
X	r += 1;
X	c += 1;
X#endif
X
X	/*
X	 * Check for overflow once, to save time.
X	 */
X	if (bpos + 8 >= BSIZE)
X		flushbuf();
X
X#ifdef	TERMCAP
X        flushbuf();
X	outstr(tgoto(T_CM, c, r));
X        flushbuf_pad();
X#else
X	outbuf[bpos++] = '\033';
X	outbuf[bpos++] = '[';
X	if (r >= 10)
X		outbuf[bpos++] = r/10 + '0';
X	outbuf[bpos++] = r%10 + '0';
X	outbuf[bpos++] = ';';
X	if (c >= 10)
X		outbuf[bpos++] = c/10 + '0';
X	outbuf[bpos++] = c%10 + '0';
X	outbuf[bpos++] = 'H';
X#endif
X}
X
XFILE *
Xfopenb(fname, mode)
Xchar	*fname;
Xchar	*mode;
X{
X	return fopen(fname, mode);
X}
X
Xchar *
Xfixname(s)
Xchar	*s;
X{
X	return s;
X}
X
X/*
X * doshell() - run a command or an interactive shell
X */
Xvoid
Xdoshell(cmd)
Xchar	*cmd;
X{
X	char	*getenv();
X	char	cline[128];
X
X#ifdef VxWorks
X        emsg("Shell access not supported under VxWorks");
X        return;
X#else
X	outstr("\r\n");
X	flushbuf();
X
X	if (cmd == NULL) {
X		if ((cmd = getenv("SHELL")) == NULL)
X			cmd = "/bin/sh";
X		sprintf(cline, "%s -i", cmd);
X		cmd = cline;
X	}
X
X	reset_tty();
X	system(cmd);
X	set_tty();
X
X	wait_return();
X#endif
X}
X
X#ifdef VxWorks
X/*
X * The strchr() function is identical to index() except it uses int instead
X * of char for 'c'. strchr() comes from system V.
X */
Xchar* strchr (s,c)
Xchar* s;
Xint c;
X{
X   char *index();
X
X   return index(s,(char)c);
X}
X#endif
X
X
X/*
X *	FILL IT IN, FOR YOUR SYSTEM, AND SHARE IT!
X *
X *	The next couple of functions do system-specific stuff.
X *	They currently do nothing; I'm not familiar enough with
X *	system-specific programming on this system.
X *	If you fill it in for your system, please post the results
X *	and share with the rest of us.
X */
X
X
Xsetcolor (c)
X/*
X * Set the color to c, using the local system convention for numbering
X * colors or video attributes.
X *
X * If you implement this, remember to note the original color in
X * windinit(), before you do any setcolor() commands, and
X * do a setcolor() back to the original as part of windexit().
X */
X  int c;
X{
X	/* Dummy routine, just return 0 */
X	return (0);
X}
X
X
Xsetrows (r)
X/*
X * Set the number of lines to r, if possible.  Otherwise
X * "do the right thing".  Return the number of lines actually set.
X *
X * If you implement this, remember to note the original number of rows
X * in windinit(), before you do any setrows() commands, and
X * do a setrows() back to the original as part of windexit().
X */
X  int r;
X{
X	/* Since we do nothing, just return the current number of lines */
X	return ( P(P_LI) );
X}
X
X
Xvbeep ()
X/*
X * Do a "visual bell".  This generally consists of flashing the screen
X * once in inverse video.
X */
X{
X	int	color, revco;
X
X	color = P( P_CO );		/* get current color */
X	revco = reverse_color (color);	/* system-specific */
X	setcolor (revco);
X	flushbuf ();
X	pause ();
X	setcolor (color);
X	windgoto (Cursrow, Curscol);
X	flushbuf ();
X}
X
Xreverse_color (co)
X/*
X * Returns the inverse video attribute or color of co.
X * The existing code below is VERY simple-minded.
X * Replace it with proper code for your system.
X */
X int co;
X{
X	if (co)		return (0);
X	else		return (1);
X}
X
X
X/********** End of do-it-yourself kit **********************/
END_OF_FILE
echo shar: 1 control character may be missing from \"'stevie/unix.c'\"
if test 12229 -ne `wc -c <'stevie/unix.c'`; then
    echo shar: \"'stevie/unix.c'\" unpacked with wrong size!
fi
# end of 'stevie/unix.c'
fi
echo shar: End of archive 6 \(of 13\).
cp /dev/null ark6isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 13 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
