[comp.sys.atari.st] A mini-vi for the ST

tjt@glimmer.UUCP (Tim Thompson) (06/28/87)

# Enclosed is (part 1 of) the source for a mini-VI which I wrote when I
# first got the ST, to make things easier for my own development.  Although
# it is somewhat minimal in capabilities, it does have a fairly good
# implementation of the 'u' (undo) and '.' (repeat) commands.  I have
# much more interesting things to work on these days, so I am unlikely
# to provide any support (hence my posting of the source).  It has worked
# well for 6 months, and since no alternatives have appeared on the net
# (other than VIX, which is too different for me), I figure it might be
# useful.  See the README below for more info.
#    ...Tim Thompson...ihnp4!twitch!tjt...
#
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	Makefile
#	cmdline.c
#	edit.c
#	help.c
#	hexchars.c
#	linefunc.c
# This archive created: Sun Jun 28 13:18:36 1987
export PATH; PATH=/bin:$PATH
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
STEVIE - ST Editor for VI Enthusiasts   ...Tim Thompson...twitch!tjt...
=====================================

The STEVIE editor is a fairly accurate (in the small subset of commands
it chooses to implement) version of the VI editor.  It was written
at a time when alternatives (ie. VIX) were not available.  To VI users,
STEVIE should provide a much more familiar environment than VIX, but has
nowhere near the capabilities (or speed), in general.

Features/Limitations
====================

- The "." (repeat last operation) and "u" (undo last insertion or
  deletion) commands are available, and will repeat/undo almost
  anything.

- The commands implemented in STEVIE happen to be the subset of
  VI commands used by its author (suprise!).  A fair number of
  additional (positioning and substitution) commands should be
  easy to add.  Regular expressions and global substitutions
  are not implemented.

- STEVIE is limited to editing files < 64K.  The source code has no
  built-in limitations, but the file is kept in memory as a single
  contiguous stream of bytes.  This implies various limitations,
  among them the fact that operations such as insert and delete will
  slow down (by a LOT, in the current implementation) as the file
  being edited grows larger.  The slowness could be eliminated by
  some reworking, which I'm unmotiviated to do, since I rarely edit
  files larger than 16K.  Scrolling in general is also unnecessarily
  slow.  Reading/writing files is also slow.

- Known glitches/annoyances: <control-d> scrolling works strangely.
  Long (>80 chars) lines are usually handled okay, but strange
  (positional) things sometime happen at the bottom of the screen.
  Backspacing at the beginning of a line, in insert mode, isn't handled
  correctly.  Undoing insertions at the end of a line are sometimes
  off by a character.  The :r command does not work very well.
  A final line that does not end in '\n' is troublesome.

- There is some support in the editor for displaying and editing binary
  files.  Giving a '-b' option tells the editor that you are intentionally
  editing a binary file.  Unprintable characters are displayed in a
  [xxx] format, where xxx is either octal or hex (if you use the -x
  option).  The binary editing support is mostly an untested hack
  (although it was one of the original goals of the editor, so the
  support for it was not unplanned).  If it works, fine; I'm not
  claiming that it does.

- Although STEVIE has been used with no problems for several months,
  it no doubt contains bugs that will surface when used by others.
  Cautious initial use is recommended.

Commands
========

   Some commands can make use of a numeric prefix, indicated in
   the summary below as [#].

   Cursor movement commands
   ========================
   control-l         Redraw screen
   control-d         Cursor down 1/2 screen
   control-u         Cursor up 1/2 screen
   control-f         Cursor forward 1 screen
   control-b         Cursor back 1 screen
   control-g         Give info on file

      h              Cursor left 1 char
      j              Cursor down 1 char
      k              Cursor up 1 char
      l              Cursor right 1 char
      $              Cursor to end of line
      ^ -or- 0       Cursor to beginning of line
      b              Cursor back 1 word
      w              Cursor forward 1 word\n\
      [#]G           Goto line # (or last line if no #)

    Modification commands
    =====================
    x           Delete 1 char
    dw          Delete 1 word
    D           Delete rest of line
    [#]dd       Delete 1 (or #) lines
    C           Change rest of line
    cw          Change word
    cc          Change line
    r           Replace single character
    [#]yy       Yank 1 (or #) lines
    p           Insert last yanked or deleted line(s)
    P              below (p) or above (P) current line
    J           Join current and next line
    [#]<<       Shift line left 1 (or #) tabs
    [#]>>       Shift line right 1 (or #) tabs
    i           Enter Insert mode (<ESC> to exit)
    a           Append (<ESC> to exit) \n\
    o           Open line (<ESC> to exit)\n\

    Miscellaneous
    =============
    .           Repeat last operation.  The works for most (but not all)
		commands, including insertions.
    u           Undo last insert or delete.   This works for most
		operations, although there are undoubtedly some for
		which it will not.
    /str/       Search for 'str' (NO REGULAR EXPRESSIONS)
    ?str?       Search backward for 'str'
    n           Repeat previous search
    :.=         Print current line number
    :$=         Print number of lines in file
    H		Help - a quick summary of commands

    File manipulation
    =================
    :w          Write file
    :wq         Write and quit
    :e {file}   Edit a new file
    :e!         Re-read current file
    :f          Print file into (current line and total # of lines)
    :f {file}   Change current file name
    :q          Quit
    :q!         Quit (no save)


SHAR_EOF
fi # end of overwriting check
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
CFLAGS = -DTCAP		# or UNIXPC or ATARI

OBJ = main.o edit.o linefunc.o normal.o \
	cmdline.o hexchars.o misccmds.o help.o

default : stevie

stevie : $(OBJ) tcapwind.o
	cc $(OBJ) tcapwind.o -lcurses -ltermcap -o stevie

s4vi : $(OBJ) unixpcwind.o
	cc $(OBJ) unixpcwind.o -ltam -ltermcap -o s4vi

tcapwind.o : window.c
	cc -c $(CFLAGS) window.c
	mv window.o tcapwind.o

unixpcwind.o : window.c
	cc -c $(CFLAGS) window.c
	mv window.o unixpcwind.o

clean :
	rm -f *.o stevie s4vi
SHAR_EOF
fi # end of overwriting check
if test -f 'cmdline.c'
then
	echo shar: will not over-write existing file "'cmdline.c'"
else
cat << \SHAR_EOF > 'cmdline.c'
/*
 * STevie - ST editor for VI enthusiasts.   ...Tim Thompson...twitch!tjt...
 */

#include <stdio.h>
#include <ctype.h>
#include "stevie.h"

readcmdline(firstc)
int firstc;	/* either ':', '/', or '?' */
{
	int c;
	char buff[100];
	char *p, *q, *cmd, *arg;

	gotocmd(1,1,firstc);
	p = buff;
	if ( firstc != ':' )
		*p++ = firstc;
	/* collect the command string, handling '\b' and @ */
	for ( ; ; ) {
		c = vgetc();
		if ( c=='\n'||c=='\r'||c==EOF )
			break;
		if ( c=='\b' ) {
			if ( p > buff ) {
				p--;
				/* I know this is gross, but it has the */
				/* advantage of relying only on 'gotocmd' */
				gotocmd(1,0,firstc==':'?':':0);
				for ( q=buff; q<p; q++ )
					windputc(*q);
				windrefresh();
			}
			continue;
		}
		if ( c=='@' ) {
			p = buff;
			gotocmd(1,1,firstc);
			continue;
		}
		windputc(c);
		windrefresh();
		*p++ = c;
	}
	*p = '\0';

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

	/* search commands */
	c = *cmd;
	if ( c == '/' || c == '?' ) {
		cmd++;
		if ( *cmd == c ) {
			/* the command was '//' or '??' */
			repsearch();
			return;
		}
		/* If there is a matching '/' or '?' at the end, toss it */
		p = strchr(cmd,'\0');
		if ( *(--p) == c )
			*p = '\0';
		dosearch(c=='/'?FORWARD:BACKWARD,cmd);
		return;
	}

	/* isolate the command and find any argument */
	for ( p=cmd; *p!='\0' && ! isspace(*p); p++ )
		;
	if ( *p == '\0' )
		arg = NULL;
	else {
		*p = '\0';
		while ( *(++p) != '\0' && isspace(*p) )
			;
		arg = p;
		if ( *arg == '\0' )
			arg = NULL;
	}
	if ( strcmp(cmd,"q!")==0 )
		getout();
	if ( strcmp(cmd,"q")==0 ) {
		if ( Changed )
			message("File not written out.  Use 'q!' to override.");
		else
			getout();
		return;
	}
	if ( strcmp(cmd,"w")==0 ) {
		if ( arg == NULL ) {
			writeit(Filename);
			UNCHANGED;
		}
		else
			writeit(arg);
		return;
	}
	if ( strcmp(cmd,"wq")==0 ) {
		if ( writeit(Filename) )
			getout();
		return;
	}
	if ( strcmp(cmd,"f")==0 && arg==NULL ) {
		fileinfo();
		return;
	}
	if ( strcmp(cmd,"e") == 0 || strcmp(cmd,"e!") == 0 ) {
		if ( cmd[1]!='!' && Changed ) {
			message("File not written out.  Use 'e!' to override.");
		}
		else {
			if ( arg != NULL )
				Filename = strsave(arg);
			/* clear mem and read file */
			Fileend = Topchar = Curschar = Filemem;
			UNCHANGED;
			p = nextline(Curschar);
			readfile(Filename,Fileend,0);
			updatescreen();
		}
		return;
	}
	if ( strcmp(cmd,"f") == 0 ) {
		Filename = strsave(arg);
		filemess("");
		return;
	}
	if ( strcmp(cmd,"r") == 0 || strcmp(cmd,".r") == 0 ) {
		char *pp;
		if ( arg == NULL ) {
			badcmd();
			return;
		}
		/* find the beginning of the next line and */
		/* read file in there */
		pp = nextline(Curschar);
		readfile(arg,pp,1);
		updatescreen();
		CHANGED;
		return;
	}
	if ( strcmp(cmd,".=")==0 ) {
		char messbuff[80];
		sprintf(messbuff,"line %d   character %d",
			cntlines(Filemem,Curschar),
			1+(int)(Curschar-Filemem));
		message(messbuff);
		return;
	}
	if ( strcmp(cmd,"$=")==0 ) {
		char messbuff[8];
		sprintf(messbuff,"%d",
			cntlines(Filemem,Fileend)-1);
		message(messbuff);
		return;
	}
	if ( strcmp(cmd,"set")==0 ) {
		if ( arg == NULL )
			badcmd();
		else if ( strcmp(arg,"oct")==0 ) {
			octchars();
			updatescreen();
		}
		else if ( strcmp(arg,"hex")==0 ) {
			hexchars();
			updatescreen();
		}
		else if ( strcmp(arg,"dec")==0 ) {
			decchars();
			updatescreen();
		}
		else
			badcmd();
		return;
	}
	badcmd();
}

badcmd()
{
	message("Unrecognized command");
}

gotocmd(clr,fresh,firstc)
{
	int n;

	windgoto(Rows-1,0);
	if ( clr ) {
		/* clear the line */
		for ( n=0; n<(Columns-1); n++ )
			windputc(' ');
		windgoto(Rows-1,0);
	}
	if ( firstc )
		windputc(firstc);
	if ( fresh )
		windrefresh();
}

message(s)
char *s;
{
	static char *lastmess = NULL;
	char *p;

	if ( lastmess!=NULL ) {
		if ( strcmp(lastmess,s)==0 )
			return;
		free(lastmess);
	}
	gotocmd(1,1,0);
	/* take off any trailing newline */
	if ( (p=strchr(s,'\0'))!=NULL && *p=='\n' )
		*p = '\0';
	windstr(s);
	lastmess = strsave(s);
}

writeit(fname)
char *fname;
{
	FILE *f;
	char buff[128];
	char *p;
	int n;

#ifdef ATARI
	if ( (f=fopen(fname,Binary?"bw":"w")) == NULL ) {
#else
	if ( (f=fopen(fname,"w")) == NULL ) {
#endif
		message("Unable to open file!");
		return(0);
	}
	for ( n=0,p=Filemem; p<Fileend; p++,n++ )
		putc(*p,f);
	fclose(f);
	sprintf(buff,"\"%s\" %d characters",fname,n);
	message(buff);
	UNCHANGED;
	return(1);
}

filemess(s)
char *s;
{
	char buff[128];
	sprintf(buff,"\"%s\" %s",Filename,s);
	message(buff);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'edit.c'
then
	echo shar: will not over-write existing file "'edit.c'"
else
cat << \SHAR_EOF > 'edit.c'
/*
 * STevie - ST editor for VI enthusiasts.     ...Tim Thompson...twitch!tjt...
 */

#include <stdio.h>
#include <ctype.h>
#include "stevie.h"

edit()
{
	int c, c1, c2;
	char *p, *q;

	Prenum = 0;

	/* position the display and the cursor at the top of the file. */
	Topchar = Filemem;
	Curschar = Filemem;
	Cursrow = Curscol = 0;

	for ( ;; ) {
	/* Figure out where the cursor is based on Curschar. */
	cursupdate();
	if ( State == INSERT )
		message("Insert Mode");
	/* printf("Curschar=(%d,%d) row/col=(%d,%d)",
		Curschar,*Curschar,Cursrow,Curscol); */
	windgoto(Cursrow,Curscol);
	windrefresh();
	c = vgetc();
	if ( State != INSERT )
		message("");
	switch(State) {
	case NORMAL:
		/* We're in the normal (non-insert) mode. */

		/* Pick up any leading digits and compute 'Prenum' */
		if ( (Prenum>0 && isdigit(c)) || (isdigit(c) && c!='0') ){
			Prenum = Prenum*10 + (c-'0');
			break;
		}
		/* execute the command */
		normal(c);
		Prenum = 0;
		break;
	case INSERT:
		/* We're in insert mode. */
		switch(c){
		case '\033':	/* an ESCape ends input mode */

			/* If we're past the end of the file, (which should */
			/* only happen when we're editing a new file or a */
			/* file that doesn't have a newline at the end of */
			/* the line), add a newline automatically. */
			if ( Curschar >= Fileend ) {
				insertchar('\n');
				Curschar--;
			}

			/* Don't end up on a '\n' if you can help it. */
			if ( Curschar>Filemem && *Curschar=='\n'
				&& *(Curschar-1)!='\n' ) {
				Curschar--;
			}
			State = NORMAL;
			message("");
			Uncurschar = Insstart;
			Undelchars = Ninsert;
			/* Undobuff[0] = '\0'; */
			/* construct the Redo buffer */
			p=Redobuff;
			q=Insbuff;
			while ( q<Insptr )
				*p++ = *q++;
			*p++ = '\033';
			*p = '\0';
			updatescreen();
			break;
		case '\b':
			if ( Curschar <= Insstart )
				beep();
			else {
				int wasnewline = 0;
				if ( *Curschar == '\n' )
					wasnewline=1;
				Curschar--;
				delchar();
				Insptr--;
				Ninsert--;
				if ( wasnewline )
					Curschar++;
				cursupdate();
				updatescreen();
			}
			break;
		case '\030':	/* control-x */ 
			{ int wasnewline = 0; char *p1;
			p1 = Curschar;
			if ( *Curschar == '\n' )
				wasnewline = 1;
			inschar('[');
			inschar('x');
			cursupdate();
			updatescreen();
			c1 = gethexchar();
			inschar(c1);
			cursupdate();
			updatescreen();
			c2 = gethexchar();
			Curschar = p1;
			delchar();
			delchar();
			delchar();
			c = 16*hextoint(c1)+hextoint(c2);
			if(Debug)printf("(c=%d)",c);
			if ( wasnewline )
				Curschar++;
			inschar(c);
			Ninsert++;
			*Insptr++ = c;
			updatescreen();
			break;
			}
		case '\017':
			break;
		case '\r':
			c = '\n';
			/* This is SUPPOSED to fall down into 'default' */
		default:
			insertchar(c);
			break;
		}
		break;
	}
	}
}

insertchar(c)
int c;
{
	char *p;

	if ( ! anyinput() ) {
		inschar(c);
		*Insptr++ = c;
		Ninsert++;
	}
	else {
		/* If there's any pending input, grab */
		/* it all at once. */
		p = Insptr;
		*Insptr++ = c;
		Ninsert++;
		while ( (c=vpeekc()) != '\033' ) {
			c = vgetc();
			*Insptr++ = c;
			Ninsert++;
		}
		*Insptr = '\0';
		insstr(p);
	}
	updatescreen();
}

gethexchar()
{
	int c;

	for ( ;; ) {
		windgoto(Cursrow,Curscol);
		windrefresh();
		c = vgetc();
		if ( hextoint(c) >= 0 )
			break;
		message("Expecting a hexidecimal character (0-9 or a-f)");
		beep();
		sleep(1);
	}
	return(c);
}

getout()
{
	windgoto(Rows-1,0);
	windrefresh();
	putchar('\r');
	putchar('\n');
	windexit(0);
}

cursupdate()
{
	char *p;
	int inc, c, nlines;

	/* special case: file is completely empty */
	if ( Fileend == Filemem ) {
		Topchar = Curschar = Filemem;
	}
	else if ( Curschar < Topchar ) {
		nlines = cntlines(Curschar,Topchar);
		/* if the cursor is above the top of */
		/* the screen, put it at the top of the screen.. */
		Topchar = Curschar;
		/* ... and, if we weren't very close to begin with, */
		/* we scroll so that the line is close to the middle. */
		if ( nlines > Rows/3 )
			scrolldown(Rows/3);
		else {
			/* make sure we have the current line completely */
			/* on the screen, by setting Topchar to the */
			/* beginning of the current line (in a strange way). */
			if ( (p=prevline(Topchar))!=NULL &&
				(p=nextline(p))!=NULL ) {
				Topchar = p;
			}
		}
		updatescreen();
	}
	else if ( Curschar >= Botchar && Curschar < Fileend ) {
		nlines = cntlines(Botchar,Curschar);
		/* If the cursor is off the bottom of the screen, */
		/* put it at the top of the screen.. */
		Topchar = Curschar;
		/* ... and back up */
		if ( nlines > Rows/3 )
			scrolldown((2*Rows)/3);
		else
			scrolldown(Rows-2);
		updatescreen();
	}

	Cursrow = Curscol = Cursvcol = 0;
	for ( p=Topchar; p<Curschar; p++ ) {
		c = *p;
		if ( c == '\n' ) {
			Cursrow++;
			Curscol = Cursvcol = 0;
			continue;
		}
		/* A tab gets expanded, depending on the current column */
		if ( c == '\t' )
			inc = (8 - (Curscol)%8);
		else
			inc = chars[(unsigned)(c & 0xff)].ch_size;
		Curscol += inc;
		Cursvcol += inc;
		if ( Curscol >= Columns ) {
			Curscol -= Columns;
			Cursrow++;
		}
	}
}

scrolldown(nlines)
int nlines;
{
	int n;
	char *p;

	/* Scroll up 'nlines' lines. */
	for ( n=nlines; n>0; n-- ) {
		if ( (p=prevline(Topchar)) == NULL )
			break;
		Topchar = p;
	}
}

/*
 * oneright
 * oneleft
 * onedown
 * oneup
 *
 * Move one char {right,left,down,up}.  Return 1 when
 * sucessful, 0 when we hit a boundary (of a line, or the file).
 */

oneright()
{
	char *p;

	p = Curschar;
	if ( (*p++)=='\n' || p>=Fileend || *p == '\n' )
		return(0);
	Curschar++;
	return(1);
}

oneleft()
{
	char *p;

	p = Curschar;
	if ( *p=='\n' || p==Filemem || *(p-1) == '\n' )
		return(0);
	Curschar--;
	return(1);
}

beginline()
{
	while ( oneleft() )
		;
}

oneup(n)
{
	char *p, *np;
	int savevcol, k;

	savevcol = Cursvcol;
	p = Curschar;
	for ( k=0; k<n; k++ ) {
		/* Look for the previous line */
		if ( (np=prevline(p)) == NULL ) {
			/* If we've at least backed up a little .. */
			if ( k > 0 )
				break;	/* to update the cursor, etc. */
			else
				return(0);
		}
		p = np;
	}
	Curschar = p;
	/* This makes sure Topchar gets updated so the complete line */
	/* is one the screen. */
	cursupdate();
	/* try to advance to the same (virtual) column */
	/* that we were at before. */
	Curschar = coladvance(p,savevcol);
	return(1);
}

onedown(n)
{
	char *p, *np;
	int k;

	p = Curschar;
	for ( k=0; k<n; k++ ) {
		/* Look for the next line */
		if ( (np=nextline(p)) == NULL ) {
			if ( k > 0 )
				break;
			else
				return(0);
		}
		p = np;
	}
	/* try to advance to the same (virtual) column */
	/* that we were at before. */
	Curschar = coladvance(p,Cursvcol);
	return(1);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'help.c'
then
	echo shar: will not over-write existing file "'help.c'"
else
cat << \SHAR_EOF > 'help.c'
/*
 * STevie - ST editor for VI enthusiasts.    ...Tim Thompson...twitch!tjt...
 */

#include <ctype.h>
#include "stevie.h"

static int helprow;

help()
{
	windclear();
	windgoto(helprow=0,0);
longline("\
\n\
   Cursor movement commands\n\
   ========================\n\
   control-l         Redraw screen\n\
   control-d         Cursor down 1/2 screen\n\
   control-u         Cursor up 1/2 screen\n\
   control-f         Cursor forward 1 screen\n");
longline("\
   control-b         Cursor back 1 screen\n\
   control-g         Give info on file\n\
\n\
      h              Cursor left 1 char\n\
      j              Cursor down 1 char\n\
      k              Cursor up 1 char\n");
longline("\
      l              Cursor right 1 char\n\
      $              Cursor to end of line\n\
      ^ -or- 0       Cursor to beginning of line\n\
      b              Cursor back 1 word\n");
longline("\
      w              Cursor forward 1 word\n\
      [#]G           Goto line # (or last line if no #)\n\
\n\
                                               <Press space bar to continue>\n\
                                               <Any other key will quit>");
	windrefresh();
	if ( vgetc() != ' ' )
		return;
	windclear();
	windgoto(helprow=0,0);
longline("\
\n\
    Modification commands\n\
    =====================\n\
    x           Delete 1 char\n\
    dw          Delete 1 word\n\
    D           Delete rest of line\n\
    [#]dd       Delete 1 (or #) lines\n\
    C           Change rest of line\n");
longline("\
    cw          Change word\n\
    cc          Change line\n\
    r           Replace single character\n\
    [#]yy       Yank 1 (or #) lines\n\
    p           Insert last yanked or deleted line(s)\n");
longline("\
    P              below (p) or above (P) current line\n\
    J           Join current and next line\n\
    [#]<<          Shift line left 1 (or #) tabs\n\
    [#]>>          Shift line right 1 (or #) tabs\n\
    i           Enter Insert mode (<ESC> to exit)\n");
longline("\
    a           Append (<ESC> to exit) \n\
    o           Open line (<ESC> to exit)\n\
\n\
                                               <Press space bar to continue>\n\
                                               <Any other key will quit>");
	windrefresh();
	if ( vgetc() != ' ' )
		return;
	windclear();
	windgoto(helprow=0,0);
longline("\
\n\
    Miscellaneous\n\
    =============\n\
    .           Repeat last insert or delete\n\
    u           Undo last insert or delete\n\
    /str/       Search for 'str'\n\
    ?str?       Search backward for 'str'\n");
longline("    n           Repeat previous search\n\
    :.=         Print current line number\n\
    :$=         Print number of lines in file\n\
    H		Help\n\
\n\
    File manipulation\n\
    =================\n");
longline("\
    :w          Write file\n\
    :wq         Write and quit\n\
    :e {file}   Edit a new file\n\
    :e!         Re-read current file\n\
    :f          Print file into (current line and total # of lines)\n");
longline("\
    :f {file}   Change current file name\n\
    :q          Quit\n\
    :q!         Quit (no save)\n\
\n\
                                                     <Press any key>");
	windrefresh();
	vgetc();
}

longline(p)
char *p;
{
	char *s;

	for ( s=p; *s; s++ ) {
		if ( *s == '\n' )
			windgoto(++helprow,0);
		else
			windputc(*s);
	}
}
SHAR_EOF
fi # end of overwriting check
if test -f 'hexchars.c'
then
	echo shar: will not over-write existing file "'hexchars.c'"
else
cat << \SHAR_EOF > 'hexchars.c'
/*
 * STevie - ST editor for VI enthusiasts.    ...Tim Thompson...twitch!tjt...
 */

#include <stdio.h>
#include "stevie.h"

/*
 * This stuff is used to provide readable interpretations of unprintable
 * characters.  The 'xxx' in each is replaced with either hex, octal, or
 * decimal numbers, depending on what command-line argument is given.
 */

struct charinfo chars[] = {
	/* 000 */	5, "[xxx]",
	/* 001 */	5, "[xxx]",
	/* 002 */	5, "[xxx]",
	/* 003 */	5, "[xxx]",
	/* 004 */	5, "[xxx]",
	/* 005 */	5, "[xxx]",
	/* 006 */	5, "[xxx]",
	/* 007 */	5, "[xxx]",
	/* 010 */	5, "[xxx]",
	/* 011 */	5, "[xxx]",
	/* 012 */	1, NULL,
	/* 013 */	5, "[xxx]",
	/* 014 */	5, "[xxx]",
	/* 015 */	5, "[xxx]",
	/* 016 */	5, "[xxx]",
	/* 017 */	5, "[xxx]",
	/* 020 */	5, "[xxx]",
	/* 021 */	5, "[xxx]",
	/* 022 */	5, "[xxx]",
	/* 023 */	5, "[xxx]",
	/* 024 */	5, "[xxx]",
	/* 025 */	5, "[xxx]",
	/* 026 */	5, "[xxx]",
	/* 027 */	5, "[xxx]",
	/* 030 */	5, "[xxx]",
	/* 031 */	5, "[xxx]",
	/* 032 */	5, "[xxx]",
	/* 033 */	5, "[xxx]",
	/* 034 */	5, "[xxx]",
	/* 035 */	5, "[xxx]",
	/* 036 */	5, "[xxx]",
	/* 037 */	5, "[xxx]",
	/* 040 */	1, NULL,
	/* 041 */	1, NULL,
	/* 042 */	1, NULL,
	/* 043 */	1, NULL,
	/* 044 */	1, NULL,
	/* 045 */	1, NULL,
	/* 046 */	1, NULL,
	/* 047 */	1, NULL,
	/* 050 */	1, NULL,
	/* 051 */	1, NULL,
	/* 052 */	1, NULL,
	/* 053 */	1, NULL,
	/* 054 */	1, NULL,
	/* 055 */	1, NULL,
	/* 056 */	1, NULL,
	/* 057 */	1, NULL,
	/* 060 */	1, NULL,
	/* 061 */	1, NULL,
	/* 062 */	1, NULL,
	/* 063 */	1, NULL,
	/* 064 */	1, NULL,
	/* 065 */	1, NULL,
	/* 066 */	1, NULL,
	/* 067 */	1, NULL,
	/* 070 */	1, NULL,
	/* 071 */	1, NULL,
	/* 072 */	1, NULL,
	/* 073 */	1, NULL,
	/* 074 */	1, NULL,
	/* 075 */	1, NULL,
	/* 076 */	1, NULL,
	/* 077 */	1, NULL,
	/* 100 */	1, NULL,
	/* 101 */	1, NULL,
	/* 102 */	1, NULL,
	/* 103 */	1, NULL,
	/* 104 */	1, NULL,
	/* 105 */	1, NULL,
	/* 106 */	1, NULL,
	/* 107 */	1, NULL,
	/* 110 */	1, NULL,
	/* 111 */	1, NULL,
	/* 112 */	1, NULL,
	/* 113 */	1, NULL,
	/* 114 */	1, NULL,
	/* 115 */	1, NULL,
	/* 116 */	1, NULL,
	/* 117 */	1, NULL,
	/* 120 */	1, NULL,
	/* 121 */	1, NULL,
	/* 122 */	1, NULL,
	/* 123 */	1, NULL,
	/* 124 */	1, NULL,
	/* 125 */	1, NULL,
	/* 126 */	1, NULL,
	/* 127 */	1, NULL,
	/* 130 */	1, NULL,
	/* 131 */	1, NULL,
	/* 132 */	1, NULL,
	/* 133 */	1, NULL,
	/* 134 */	1, NULL,
	/* 135 */	1, NULL,
	/* 136 */	1, NULL,
	/* 137 */	1, NULL,
	/* 140 */	1, NULL,
	/* 141 */	1, NULL,
	/* 142 */	1, NULL,
	/* 143 */	1, NULL,
	/* 144 */	1, NULL,
	/* 145 */	1, NULL,
	/* 146 */	1, NULL,
	/* 147 */	1, NULL,
	/* 150 */	1, NULL,
	/* 151 */	1, NULL,
	/* 152 */	1, NULL,
	/* 153 */	1, NULL,
	/* 154 */	1, NULL,
	/* 155 */	1, NULL,
	/* 156 */	1, NULL,
	/* 157 */	1, NULL,
	/* 160 */	1, NULL,
	/* 161 */	1, NULL,
	/* 162 */	1, NULL,
	/* 163 */	1, NULL,
	/* 164 */	1, NULL,
	/* 165 */	1, NULL,
	/* 166 */	1, NULL,
	/* 167 */	1, NULL,
	/* 170 */	1, NULL,
	/* 171 */	1, NULL,
	/* 172 */	1, NULL,
	/* 173 */	1, NULL,
	/* 174 */	1, NULL,
	/* 175 */	1, NULL,
	/* 176 */	1, NULL,
	/* 177 */	5, "[xxx]",
	/* 200 */	5, "[xxx]",
	/* 201 */	5, "[xxx]",
	/* 202 */	5, "[xxx]",
	/* 203 */	5, "[xxx]",
	/* 204 */	5, "[xxx]",
	/* 205 */	5, "[xxx]",
	/* 206 */	5, "[xxx]",
	/* 207 */	5, "[xxx]",
	/* 210 */	5, "[xxx]",
	/* 211 */	5, "[xxx]",
	/* 212 */	5, "[xxx]",
	/* 213 */	5, "[xxx]",
	/* 214 */	5, "[xxx]",
	/* 215 */	5, "[xxx]",
	/* 216 */	5, "[xxx]",
	/* 217 */	5, "[xxx]",
	/* 220 */	5, "[xxx]",
	/* 221 */	5, "[xxx]",
	/* 222 */	5, "[xxx]",
	/* 223 */	5, "[xxx]",
	/* 224 */	5, "[xxx]",
	/* 225 */	5, "[xxx]",
	/* 226 */	5, "[xxx]",
	/* 227 */	5, "[xxx]",
	/* 230 */	5, "[xxx]",
	/* 231 */	5, "[xxx]",
	/* 232 */	5, "[xxx]",
	/* 233 */	5, "[xxx]",
	/* 234 */	5, "[xxx]",
	/* 235 */	5, "[xxx]",
	/* 236 */	5, "[xxx]",
	/* 237 */	5, "[xxx]",
	/* 240 */	5, "[xxx]",
	/* 241 */	5, "[xxx]",
	/* 242 */	5, "[xxx]",
	/* 243 */	5, "[xxx]",
	/* 244 */	5, "[xxx]",
	/* 245 */	5, "[xxx]",
	/* 246 */	5, "[xxx]",
	/* 247 */	5, "[xxx]",
	/* 250 */	5, "[xxx]",
	/* 251 */	5, "[xxx]",
	/* 252 */	5, "[xxx]",
	/* 253 */	5, "[xxx]",
	/* 254 */	5, "[xxx]",
	/* 255 */	5, "[xxx]",
	/* 256 */	5, "[xxx]",
	/* 257 */	5, "[xxx]",
	/* 260 */	5, "[xxx]",
	/* 261 */	5, "[xxx]",
	/* 262 */	5, "[xxx]",
	/* 263 */	5, "[xxx]",
	/* 264 */	5, "[xxx]",
	/* 265 */	5, "[xxx]",
	/* 266 */	5, "[xxx]",
	/* 267 */	5, "[xxx]",
	/* 270 */	5, "[xxx]",
	/* 271 */	5, "[xxx]",
	/* 272 */	5, "[xxx]",
	/* 273 */	5, "[xxx]",
	/* 274 */	5, "[xxx]",
	/* 275 */	5, "[xxx]",
	/* 276 */	5, "[xxx]",
	/* 277 */	5, "[xxx]",
	/* 300 */	5, "[xxx]",
	/* 301 */	5, "[xxx]",
	/* 302 */	5, "[xxx]",
	/* 303 */	5, "[xxx]",
	/* 304 */	5, "[xxx]",
	/* 305 */	5, "[xxx]",
	/* 306 */	5, "[xxx]",
	/* 307 */	5, "[xxx]",
	/* 310 */	5, "[xxx]",
	/* 311 */	5, "[xxx]",
	/* 312 */	5, "[xxx]",
	/* 313 */	5, "[xxx]",
	/* 314 */	5, "[xxx]",
	/* 315 */	5, "[xxx]",
	/* 316 */	5, "[xxx]",
	/* 317 */	5, "[xxx]",
	/* 320 */	5, "[xxx]",
	/* 321 */	5, "[xxx]",
	/* 322 */	5, "[xxx]",
	/* 323 */	5, "[xxx]",
	/* 324 */	5, "[xxx]",
	/* 325 */	5, "[xxx]",
	/* 326 */	5, "[xxx]",
	/* 327 */	5, "[xxx]",
	/* 330 */	5, "[xxx]",
	/* 331 */	5, "[xxx]",
	/* 332 */	5, "[xxx]",
	/* 333 */	5, "[xxx]",
	/* 334 */	5, "[xxx]",
	/* 335 */	5, "[xxx]",
	/* 336 */	5, "[xxx]",
	/* 337 */	5, "[xxx]",
	/* 340 */	5, "[xxx]",
	/* 341 */	5, "[xxx]",
	/* 342 */	5, "[xxx]",
	/* 343 */	5, "[xxx]",
	/* 344 */	5, "[xxx]",
	/* 345 */	5, "[xxx]",
	/* 346 */	5, "[xxx]",
	/* 347 */	5, "[xxx]",
	/* 350 */	5, "[xxx]",
	/* 351 */	5, "[xxx]",
	/* 352 */	5, "[xxx]",
	/* 353 */	5, "[xxx]",
	/* 354 */	5, "[xxx]",
	/* 355 */	5, "[xxx]",
	/* 356 */	5, "[xxx]",
	/* 357 */	5, "[xxx]",
	/* 360 */	5, "[xxx]",
	/* 361 */	5, "[xxx]",
	/* 362 */	5, "[xxx]",
	/* 363 */	5, "[xxx]",
	/* 364 */	5, "[xxx]",
	/* 365 */	5, "[xxx]",
	/* 366 */	5, "[xxx]",
	/* 367 */	5, "[xxx]",
	/* 370 */	5, "[xxx]",
	/* 371 */	5, "[xxx]",
	/* 372 */	5, "[xxx]",
	/* 373 */	5, "[xxx]",
	/* 374 */	5, "[xxx]",
	/* 375 */	5, "[xxx]",
	/* 376 */	5, "[xxx]",
	/* 377 */	5, "[xxx]",
};

/*
 * octchars()
 *
 * Convert the charinfo strings to octal.
 */
octchars()
{
	char *p;
	int n;

	for ( n=0; n<256; n++ ) {
		p = chars[n].ch_str;
		if ( p==NULL || *p != '[' )
			continue;
		sprintf(++p,"%03o]",n);
	}
}

/*
 * hexchars()
 *
 * Convert the charinfo strings to hex.
 */
hexchars()
{
	char *p;
	int n;

	for ( n=0; n<256; n++ ) {
		p = chars[n].ch_str;
		if ( p==NULL || *p != '[' )
			continue;
		sprintf(++p,"x%02X]",n);
	}
}

/*
 * decchars()
 *
 * Convert the charinfo strings to decimal.
 */
decchars()
{
	char *p;
	int n;

	for ( n=0; n<256; n++ ) {
		p = chars[n].ch_str;
		if ( p==NULL || *p != '[' )
			continue;
		sprintf(++p,"%3d]",n);
	}
}

hextoint(c)
int c;
{
	if ( c>='0' && c<='9' )
		return(c-'0');
	if ( c>='a' && c<='f' )
		return(10+c-'a');
	if ( c>='A' && c<='F' )
		return(10+c-'A');
	return(-1);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'linefunc.c'
then
	echo shar: will not over-write existing file "'linefunc.c'"
else
cat << \SHAR_EOF > 'linefunc.c'
/*
 * STevie - ST editor for VI enthusiasts.    ...Tim Thompson...twitch!tjt...
 */

#include <stdio.h>
#include "stevie.h"

/*
 * nextline(curr)
 *
 * Return a pointer to the beginning of the next line after the
 * 'curr' char.  Return NULL if there is no next line.
 */

char *
nextline(curr)
char *curr;
{
	while ( curr<Fileend ) {
		if ( *curr++ == '\n' )
			break;
	}
	if ( curr >= Fileend )
		return(NULL);
	return(curr);
}

/*
 * prevline(curr)
 *
 * Return a pointer to the beginning of the previous line before the
 * 'curr' char.  Return NULL if there is no previous line.
 */

char *
prevline(curr)
char *curr;
{
	int nnl = 0;

	/* If we are currently positioned on a '\n', */
	/* we are on a blank line.  Adjust accordingly. */
	if ( *curr == '\n' )
		nnl = -1;
	while ( curr>Filemem ) {
		/* look for the 2nd previous newline */
		if ( *curr == '\n' ) {
			nnl++;
			if ( nnl == 2)
				break;
		}
		curr--;
	}
	if ( curr <= Filemem ) {
		/* If we found 1 newline, we found the first line */
		if ( nnl == 1 )
			return(Filemem);
		else
			return(NULL);
	}
	/* return the first char of the previous line */
	return(++curr);
}

/*
 * coladvance(p,col)
 *
 * Try to advance to the specified column, starting at p.
 */

char *
coladvance(p,col)
char *p;
int col;
{
	int c, inc;

	/* If we're on a blank ('\n' only) line, we can't do anything */
	if ( *p == '\n' )
		return(p);
	/* try to advance to the specified column */
	for ( c=0; col-- > 0; c++ ) {
		/* Count a tab for what it's worth */
		if ( *p == '\t' ) {
			inc = (7 - c%8);
			col -= inc;
			c += inc;
		}
		p++;
		/* Don't go past the end of */
		/* the file or the line. */
		if ( p==Fileend || *p=='\n' ) {
			p--;
			break;
		}
	}
	return(p);
}
char *strcpy(), *malloc();

#define NULL 0
  
char *
alloc(size)
unsigned size;
{
	char *p;		/* pointer to new storage space */

	p = malloc(size);
	if ( p == (char *)NULL ) {	/* if there is no more room... */
		message("alloc() is unable to find memory!");
	}
	return(p);
}

char *
strsave(string)
char *string;
{
	return(strcpy(alloc((unsigned)(strlen(string)+1)),string));
}

#define NULL 0

static char *laststr = NULL;
static int lastdir;

char *
ssearch(dir,str)
int dir;	/* FORWARD or BACKWARD */
char *str;
{
	if ( laststr != NULL )
		free(laststr);
	laststr = strsave(str);
	lastdir = dir;
	if ( dir == BACKWARD )
		return(bcksearch(str));
	else
		return(fwdsearch(str));
}

dosearch(dir,str)
int dir;
char *str;
{
	char *p;

	if ( (p=ssearch(dir,str)) == NULL )
		message("Pattern not found");
	else {
		char *savep;

		cursupdate();
		/* if we're backing up, we make sure the line we're on */
		/* is on the screen. */
		Curschar = savep = p;
		/* get to the beginning of the line */
		beginline();
		if ( Curschar < Topchar )
			Topchar = Curschar;
		Curschar = savep;
		cursupdate();
		updatescreen();
	}
}


repsearch()
{
	if ( laststr == NULL )
		beep();
	else {
		dosearch(lastdir,laststr);
	}
}

char *
fwdsearch(str)
char *str;
{
	register char *sofar = str;
	register char *infile = Curschar+1;
	int leng = strlen(str);
	char *stopit;

	/* search forward to the end of the file */
	for ( ; infile < Fileend && *sofar != '\0' ; infile++ ) {
		if ( *infile == *sofar )
			sofar++;
		else
			sofar = str;
	}
	if ( *sofar == '\0' )
		return(infile-strlen(str));
	/* search from the beginning of the file to Curschar */
	infile = Filemem;
	sofar = str;
	stopit = Curschar + leng;
	for ( ; infile <= stopit && *sofar != '\0' ; infile++ ) {
		if ( *infile == *sofar )
			sofar++;
		else
			sofar = str;
	}
	if ( *sofar == '\0' )
		return(infile-leng);
	else
		return(NULL);
}

char *
bcksearch(str)
char *str;
{
	int leng = strlen(str);
	char *infile = Curschar+1;
	char *endofstr, *sofar, *stopit;

	/* make sure str isn't empty before getting pointer to */
	/* its last character. */
	if ( leng == 0 )
		return(NULL);
	endofstr = &str[leng-1];
	sofar = endofstr;
	/* search backward to the beginning of the file */
	for ( ; infile >= Filemem && sofar >= str ; infile-- ) {
		if ( *infile == *sofar )
			sofar--;
		else
			sofar = endofstr;
	}
	if ( sofar < str )
		return(++infile);

	/* search backward from the end of the file */
	sofar = endofstr;
	infile = Fileend-1;
	stopit = Curschar - leng;
	for ( ; infile >= stopit && sofar >= str ; infile-- ) {
		if ( *infile == *sofar )
			sofar--;
		else
			sofar = endofstr;
	}
	if ( sofar < str )
		return(++infile);
	else
		return(NULL);
}
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0

tjt@glimmer.UUCP (Tim Thompson) (06/28/87)

# Enclosed is (part 2 of) the source for a mini-VI which I wrote when I
# first got the ST, to make things easier for my own development.  Although
# it is somewhat minimal in capabilities, it does have a fairly good
# implementation of the 'u' (undo) and '.' (repeat) commands.  I have
# much more interesting things to work on these days, so I am unlikely
# to provide any support.  It has worked well for 6 months, and since
# no alternatives have appeared on the net (other than VIX, which is
# too different for me), I figure it might be useful.
#      ...Tim Thompson...ihnp4!twitch!tjt...

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	main.c
#	misccmds.c
#	normal.c
#	stevie.h
#	window.c
# This archive created: Sun Jun 28 13:18:51 1987
export PATH; PATH=/bin:$PATH
if test -f 'main.c'
then
	echo shar: will not over-write existing file "'main.c'"
else
cat << \SHAR_EOF > 'main.c'
/*
 * STEVIE - ST Editor for VI Enthusiasts   ...Tim Thompson...twitch!tjt...
 */

#include <stdio.h>
#include <ctype.h>
#include "stevie.h"

#ifdef ATARI
#include <osbind.h>
#endif

#define NULL 0

int Rows;		/* Number of Rows and Columns */
int Columns;		/* in the current window. */

char *Realscreen;	/* What's currently on the screen, a single */
			/* array of size Rows*Columns. */
char *Nextscreen;	/* What's to be put on the screen. */

char *Filename = NULL;	/* Current file name */

char *Filemem;		/* The contents of the file, as a single array. */

char *Filemax;		/* Pointer to the end of allocated space for */
			/* Filemem. (It points to the first byte AFTER */
			/* the allocated space.) */

char *Fileend;		/* Pointer to the end of the file in Filemem. */
			/* (It points to the byte AFTER the last byte.) */

char *Topchar;		/* Pointer to the byte in Filemem which is */
			/* in the upper left corner of the screen. */

char *Botchar;		/* Pointer to the byte in Filemem which is */
			/* just off the bottom of the screen. */

char *Curschar;		/* Pointer to byte in Filemem at which the */
			/* cursor is currently placed. */

int Cursrow, Curscol;	/* Current position of cursor */

int Cursvcol;		/* Current virtual column, the column number of */
			/* the file's actual line, as opposed to the */
			/* column number we're at on the screen.  This */
			/* makes a difference on lines that span more */
			/* than one screen line. */

int State = NORMAL;	/* This is the current state of the command */
			/* interpreter. */

int Prenum = 0;		/* The (optional) number before a command. */

char *Insstart;		/* This is where the latest insert/append */
			/* mode started. */

int Changed = 0;	/* Set to 1 if something in the file has been */
			/* changed and not written out. */

int Debug = 0;

int Binary = 0;		/* Set to 1 if the file should be read and written */
			/* in binary mode (no cr-lf translation). */

char Redobuff[1024];	/* Each command should stuff characters into this */
			/* buffer that will re-execute itself. */

char Undobuff[1024];	/* Each command should stuff characters into this */
			/* buffer that will undo its effects. */

char Insbuff[1024];	/* Each insertion gets stuffed into this buffer. */

char *Uncurschar = NULL;/* Curschar is restored to this before undoing. */

int Ninsert = 0;	/* Number of characters in the current insertion. */
int Undelchars = 0;	/* Number of characters to delete, when undoing. */
char *Insptr = NULL;

main(argc,argv)
int argc;
char **argv;
{
	int mode = 8;

	while ( argc>1 && argv[1][0] == '-' ) {
		switch (argv[1][1]) {
		case 'x':
			mode = 16;
			break;
		case 'o':
			mode = 8;
			break;
		case 'd':
			Debug = 1;
			break;
		case 'b':
			Binary = 1;
			break;
		}
		argc--;
		argv++;
	}

	if ( argc <= 1 ) {
		fprintf(stderr,"usage: stevie {file}\n");
		exit(1);
	}

	Filename = strsave(argv[1]);

	windinit();

	/* Make sure Rows/Columns are big enough */
	if ( Rows < 3 || Columns < 16 ) {
		fprintf(stderr,"Rows=%d Columns=%d not big enough!\n",
			Rows,Columns);
		windexit(0);
	}

	switch ( mode ) {
	case 8:
		octchars();
		break;
	case 16:
		hexchars();
		break;
	}

	screenalloc();
	filealloc();

	screenclear();

	Fileend = Filemem;
	if ( readfile(Filename,Fileend,0) )
		filemess("[New File]");
	Topchar = Curschar = Filemem;

	updatescreen();
	
	edit();

	windexit(0);
}

/*
 * filetonext()
 *
 * Based on the current value of Topchar, transfer a screenfull of
 * stuff from Filemem to Nextscreen, and update Botchar.
 */

filetonext()
{
	int row, col;
	char *screenp = Nextscreen;
	char *memp = Topchar;
	char *endscreen;
	char *nextrow;
	char extra[16];
	int nextra = 0;
	int c;
	int n;

	/* The number of rows shown is Rows-1. */
	/* The last line is the status/command line. */
	endscreen = &screenp[(Rows-1)*Columns];

	row = col = 0;
	while ( screenp < endscreen && memp < Fileend ) {

		/* Get the next character to put on the screen. */

		/* The 'extra' array contains the extra stuff that is */
		/* inserted to represent special characters (tabs, and */
		/* other non-printable stuff.  The order in the 'extra' */
		/* array is reversed. */

		if ( nextra > 0 )
			c = extra[--nextra];
		else {
			c = (unsigned)(0xff & (*memp++));
			/* when getting a character from the file, we */
			/* may have to turn it into something else on */
			/* the way to putting it into 'Nextscreen'. */
			if ( c == '\t' ) {
				strcpy(extra,"        ");
				/* tab amount depends on current column */
				nextra = (7 - col%8);
				c = ' ';
			}
			else if ( (n=chars[c].ch_size) > 1 ) {
				char *p;
				nextra = 0;
				p = chars[c].ch_str;
				/* copy 'ch-str'ing into 'extra' in reverse */
				while ( n > 1 )
					extra[nextra++] = p[--n];
				c = p[0];
			}
		}

		if ( c == '\n' ) {
			row++;
			/* get pointer to start of next row */
			nextrow = &Nextscreen[row*Columns];
			/* blank out the rest of this row */
			while ( screenp != nextrow )
				*screenp++ = ' ';
			col = 0;
			continue;
		}
		/* store the character in Nextscreen */
		if ( col >= Columns ) {
			row++;
			col = 0;
		}
		*screenp++ = c;
		col++;
	}
	/* make sure the rest of the screen is blank */
	while ( screenp < endscreen )
		*screenp++ = ' ';
	/* put '~'s on rows that aren't part of the file. */
	if ( col != 0 )
		row++;
	while ( row < Rows ) {
		Nextscreen[row*Columns] = '~';
		row++;
	}
	Botchar = memp;
}

/*
 * nexttoscreen
 *
 * Transfer the contents of Nextscreen to the screen, using Realscreen
 * to avoid unnecessary output.
 */

nexttoscreen()
{
	char *np = Nextscreen;
	char *rp = Realscreen;
	char *endscreen;
	char nc;
	int row = 0, col = 0;
	int gorow = -1, gocol = -1;

	endscreen = &np[(Rows-1)*Columns];

	for ( ; np < endscreen ; np++,rp++ ) {
		/* If desired screen (contents of Nextscreen) does not */
		/* match what's really there, put it there. */
		if ( (nc=(*np)) != (*rp) ) {
			*rp = nc;
			/* if we are positioned at the right place, */
			/* we don't have to use windgoto(). */
			if ( ! (gorow == row && gocol == col) )
				windgoto(gorow=row,gocol=col);
			windputc(nc);
			gocol++;
		}
		if ( ++col >= Columns ) {
			col = 0;
			row++;
		}
	}
	windrefresh();
}

updatescreen()
{
	filetonext();
	nexttoscreen();
}

screenclear()
{
	int n;

	windclear();
	/* blank out the stored screens */
	for ( n=Rows*Columns-1; n>=0; n-- ) {
		Realscreen[n] = ' ';
		Nextscreen[n] = ' ';
	}
}

filealloc()
{
	if ( (Filemem=malloc((unsigned)FILELENG)) == NULL ) {
		fprintf(stderr,"Unable to allocate %d bytes for file memory!\n",
			FILELENG);
		exit(1);
	}
	Filemax = Filemem + FILELENG;
}

screenalloc()
{
	Realscreen = malloc((unsigned)(Rows*Columns));
	Nextscreen = malloc((unsigned)(Rows*Columns));
}

readfile(fname,fromp,nochangename)
char *fname;
char *fromp;
int nochangename;	/* if 1, don't change the Filename */
{
#ifdef ATARI
	static char currdisk = 0;
	char fbuff[128];
	int c1, c2;
#endif
	FILE *f;
	char buff[128];
	char *p;
	int c, n;
	int unprint = 0;

#ifdef ATARI
	if ( currdisk == 0 )
		currdisk = 'a' + Dgetdrv();

	/* If a drive is specified, it is used from then */
	/* on as the default drive. */
	c1 = tolower(*fname);
	c2 = *(fname+1);
	if ( c2 == ':' && c1>='a' && c1<='z' )
		currdisk = c1;
	else {
		/* if no drive is specified, use the default one. */
		sprintf(fbuff,"%c:\\%s",toupper(currdisk),fname);
		fname = fbuff;
	}
#endif
	if ( ! nochangename )
		Filename = strsave(fname);

#ifdef ATARI
	if ( (f=fopen(fname,Binary?"br":"r")) == NULL ) {
#else
	if ( (f=fopen(fname,"r")) == NULL ) {
#endif
		Fileend = Filemem;
		return(1);
	}

	for ( n=0; (c=getc(f)) != EOF; n++ ) {
		if ( ! (isprint(c)||isspace(c)) )
			unprint++;
		if ( fromp >= Filemax ) {
			fprintf(stderr,"File too long (limit is %d)!\n",FILELENG);
			exit(1);
		}
		/* Insert the char at the current point by shifting
		/* everything down. */
		for ( p=Fileend; p>fromp; p-- )
			*p = *(p-1);
		*fromp++ = c;
		if ( Fileend < fromp )
			Fileend = fromp;
	}
	if ( ! Binary && unprint > 0 ) {
		sprintf(buff,"%d unprintable chars!  Perhaps binary mode (-b) should be used?",unprint);
		message(buff);
		sleep(2);
	}
	if ( unprint > 0 )
		p = "\"%s\" %d characters (%d un-printable)  (Press 'H' for help)";
	else
		p = "\"%s\" %d characters  (Press 'H' for help)";
	sprintf(buff,p,fname,n,unprint);
	message(buff);
	fclose(f);
	return(0);
}

static char getcbuff[1024];
static char *getcnext = NULL;

stuffin(s)
char *s;
{
	if ( getcnext == NULL ) {
		strcpy(getcbuff,s);
		getcnext = getcbuff;
	}
	else
		strcat(getcbuff,s);
}

addtobuff(s,c1,c2,c3,c4,c5,c6)
char *s;
char c1, c2, c3, c4, c5, c6;
{
	char *p = s;
	if ( (*p++ = c1) == '\0' )
		return;
	if ( (*p++ = c2) == '\0' )
		return;
	if ( (*p++ = c3) == '\0' )
		return;
	if ( (*p++ = c4) == '\0' )
		return;
	if ( (*p++ = c5) == '\0' )
		return;
	if ( (*p++ = c6) == '\0' )
		return;
}

vgetc()
{
	if ( getcnext != NULL ) {
		int nextc = *getcnext++;
		if ( *getcnext == '\0' ) {
			*getcbuff = '\0';
			getcnext = NULL;
		}
		return(nextc);
	}
	return(windgetc());
}

vpeekc()
{
	if ( getcnext != NULL )
		return(*getcnext);
	return(-1);
}

/*
 * anyinput
 *
 * Return non-zero if input is pending.
 */

anyinput()
{
	if ( getcnext != NULL )
		return(1);
	return(0);
}

#ifdef ATARI
sleep(n)
int n;
{
	int k;

	k = Tgettime();
	while ( Tgettime() <= k+n )
		;
}
#endif
SHAR_EOF
fi # end of overwriting check
if test -f 'misccmds.c'
then
	echo shar: will not over-write existing file "'misccmds.c'"
else
cat << \SHAR_EOF > 'misccmds.c'
/*
 * STevie - ST editor for VI enthusiasts.    ...Tim Thompson...twitch!tjt...
 */

#include <stdio.h>
#include <ctype.h>
#include "stevie.h"

/*
 * opencmd
 *
 * Add a blank line below the current line.
 */

opencmd()
{
	/* get to the end of the current line */ 
	while ( Curschar<Fileend && (*Curschar) != '\n' )
		Curschar++;
	/* Try to handle a file that doesn't end with a newline */
	if ( Curschar >= Fileend )
		Curschar = Fileend-1;
	/* Add the blank line */
	appchar('\n');
}

issepchar(c)
char c;
{
	if ( strchr(WORDSEP,c) != NULL )
		return(1);
	return(0);
}

cntlines(pbegin,pend)
char *pbegin, *pend;
{
	int lnum = 1;
	char *p;

	for ( p=pbegin; p<pend; ) {
		if ( *p++ == '\n' )
			lnum++;
	}
	return(lnum);
}

fileinfo()
{
	char buff[128];

	sprintf(buff,"\"%s\"%s line %d of %d",
		Filename,
		Changed?" [Modified]":"",
		cntlines(Filemem,Curschar),
		cntlines(Filemem,Fileend)-1);
	message(buff);
}

gotoline(n)
int n;
{
	char *p;

	if ( n == 0 ) {
		if ( (p=prevline(Fileend)) != NULL )
			Curschar = p;
	}
	else {
		/* Start at the top of the file and go down 'n'-1 lines */
		Curschar = Filemem;
		while ( --n > 0 ) {
			if ( (p=nextline(Curschar)) == NULL )
				break;
			Curschar = p;
		}
	}
	Topchar = Curschar;
	for ( n=0; n<Rows/2; n++ ) {
		if ( (p=prevline(Topchar)) == NULL )
			break;
		Topchar = p;
	}
	updatescreen();
}

char *Savedline = NULL;
int Savednum = 0;

/*
 * yankline
 *
 * Save a copy of the current line(s) for later 'p'lacing.
 */

yankline(n)
{
	char *savep, *p, *q;
	int leng, k;

	if ( Savedline != NULL )
		free(Savedline);
	savep = Curschar;
	/* go to the beginning of the current line. */
	beginline();
	/* compute length of line */
	for ( p=Curschar,leng=0; ; p++ ) {
		if ( *p == '\n' ) {
			/* keep going until we've seen 'n' lines */
			if ( --n <= 0 )
				break;
		}
		leng++;
	}
	/* save a copy of it */
	Savedline = malloc((unsigned)(leng+2));
	for ( p=Curschar,q=Savedline,k=0; k<leng; k++ )
		*q++ = *p++;
	/* get the final newline */
	*q++ = *p;
	*q = '\0';
	Curschar = savep;
	Savednum = leng+1;
}

/*
 * putline
 *
 * If there is a currently saved line(s), 'p'ut it.
 * If k==1, 'P'ut the line (i.e. above instead of below.
 */

putline(k)
int k;
{
	char *p;
	int n;

	if ( Savedline == NULL )
		return;
	message("Inserting saved stuff...");
	if ( k == 0 ) {
		/* get to the end of the current line */
		while ( Curschar<Fileend && *Curschar != '\n' )
			Curschar++;
	}
	else
		beginline();
	/* append or insert the characters of the saved line */
	for ( p=Savedline,n=0; n<Savednum; p++,n++ ) {
		if ( k == 0 )
			appchar(*p);
		else
			inschar(*p);
	}
	/* We want to end up at the beginning of the line. */
	while ( n-->1 )
		Curschar--;
	if ( k == 1 )
		Curschar--;
	beginline();
	message("");
	updatescreen();
}

inschar(c)
int c;
{
	register char *p;

	/* Move everything in the file over to make */
	/* room for the new char. */
	if ( ! canincrease(1) )
		return;

	for ( p=Fileend; p>Curschar; p-- ) {
		*p = *(p-1);
	}
	*Curschar++ = c;
	Fileend++;
	CHANGED;
}

insstr(s)
char *s;
{
	register char *p;
	int k, n = strlen(s);

	/* Move everything in the file over to make */
	/* room for the new string. */
	if ( ! canincrease(n) )
		return;

	for ( p=Fileend-1+n; p>Curschar; p-- ) {
		*p = *(p-n);
	}
	for ( k=0; k<n; k++ )
		*Curschar++ = *s++;
	Fileend += n;
	CHANGED;
}

appchar(c)
int c;
{
	char *p, *endp;

	/* Move everything in the file over to make */
	/* room for the new char. */
	if ( ! canincrease(1) )
		return;

	endp = Curschar+1;
	for ( p=Fileend; p>endp; p-- ) {
		*p = *(p-1);
	}
	*(++Curschar) = c;
	Fileend++;
	CHANGED;
}

canincrease(n)
int n;
{
	if ( (Fileend+n) >= Filemax ) {
		message("Can't add anything, file is too big!");
		State = NORMAL;
		return(0);
	}
	return(1);
}

#define NULL 0

delchar()
{
	char *p;

	/* Check for degenerate case; there's nothing in the file. */
	if ( Filemem == Fileend )
		return;
	/* Delete the character at Curschar by shifting everything */
	/* in the file down. */
	for ( p=Curschar+1; p<Fileend; p++ )
		*(p-1) = *p;
	/* If we just took off the last character of a non-blank line, */
	/* we don't want to end up positioned at the newline. */
	if ( *Curschar=='\n' && Curschar>Filemem && *(Curschar-1)!='\n' )
		Curschar--;
	Fileend--;
	CHANGED;
}

delword(deltrailing)
int deltrailing;	/* 1 if trailing white space should be removed. */
{
	int c = *Curschar;
	char *p = Undobuff;

	/* The Undo string is an 'i'nsert of the word we're deleting. */
	*p++ = 'i';
	/* If we're positioned on a word separator... */
	if ( issepchar(c) && ! isspace(c) ) {
		/* If we're on a non-space separator, remove */
		/* the separators and any following space. */
		while ( issepchar(c) && ! isspace(c) ) {
			/* Add the deleted character to the Undobuff */
			*p++ = *Curschar;
			delchar();
			c = *Curschar;
		}
	}
	else {	/* we're positioned in the middle of a word */
		int endofline = 0;
		while ( ! issepchar(*Curschar) && *Curschar != '\n' ) {
			/* If the next char is a newline, we note */
			/* that fact here, because delchar() won't */
			/* position us there afterword. */
			if ( *(Curschar+1) == '\n' )
				endofline = 1;
			/* Add the deleted character to the Undobuff */
			*p++ = *Curschar;
			delchar();
			if ( endofline )
				break;
		}
	}
	if ( deltrailing ) {
		/* remove any trailing white space */
		while ( isspace(*Curschar) && *Curschar != '\n' ) {
			/* Add the deleted character to the Undobuff */
			*p++ = *Curschar;
			delchar();
		}
	}
	*p++ = '\033';
	*p = '\0';
}

delline(nlines)
{
	int nchars;
	char *p, *q;

	/* If we're not at the beginning of the line, get there. */
	if ( *Curschar != '\n' ) {
		/* back up to the previous newline (or the beginning */
		/* of the file. */
		while ( Curschar > Filemem ) {
			if ( *Curschar == '\n' ) {
				Curschar++;
				break;
			}
			Curschar--;
		}
	}
	message("Deleting...");
	while ( nlines-- > 0 ) {
		/* Count the characters in the line */
		for ( nchars=1,p=Curschar; p<Fileend&&*p!='\n'; p++,nchars++ )
			;
		/* Delete the characters of the line */
		/* by moving everything else in the file down. */
		q = Curschar;
		p = Curschar+nchars;
		while ( p<Fileend )
			*q++ = *p++;
		Fileend -= nchars;
		CHANGED;

		/* If we delete the last line in the file, back up */
		if ( Curschar >= Fileend ) {
			if ( (Curschar=prevline(Curschar)) == NULL )
				Curschar = Filemem;
			/* and don't try to delete any more lines */
			break;
		}
	}
	message("");
}

char *strchr(s,c)
char *s;
int c;
{
	do {
		if ( *s == c )
			return(s);
	} while (*s++);
	return(NULL);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'normal.c'
then
	echo shar: will not over-write existing file "'normal.c'"
else
cat << \SHAR_EOF > 'normal.c'
/*
 * STevie - ST editor for VI enthusiasts.    ...Tim Thompson...twitch!tjt...
 */

#include <ctype.h>
#include "stevie.h"

/*
 * normal
 *
 * Execute a command in normal mode.
 */

normal(c)
int c;
{
	char *p, *q;
	int nchar, n;

	switch(c){
	case 'H':
		help();
		/* fall through purposely */
	case '\014':
		screenclear();
		updatescreen();
		break;
	case 04:
		/* control-d */
		if ( ! onedown(10) )
			beep();
		break;
	case  025:
		/* control-u */
		if ( ! oneup(10) )
			beep();
		break;
	case 06:
		/* control-f */
		if ( ! onedown(Rows) )
			beep();
		break;
	case 02:
		/* control-b */
		if ( ! oneup(Rows) )
			beep();
		break;
	case '\007':
		fileinfo();
		break;
	case 'G':
		gotoline(Prenum);
		break;
	case 'l':
		if ( ! oneright() )
			beep();
		break;
	case 'h':
		if ( ! oneleft() )
			beep();
		break;
	case 'k':
		if ( ! oneup(1) )
			beep();
		break;
	case 'j':
		if ( ! onedown(1) )
			beep();
		break;
	case 'b':
		/* If we're on the first character of a word, force */
		/* an initial backup. */
		if ( ! issepchar(*Curschar) && Curschar>Filemem
			&& issepchar(*(Curschar-1)) )
			Curschar--;

		if ( ! issepchar(*Curschar) ) {
			/* If we start in the middle of a word, back */
			/* up until we hit a separator. */
			while ( Curschar>Filemem && !issepchar(*Curschar))
				Curschar--;
			if ( issepchar(*Curschar) )
				Curschar++;
		}
		else {
			/* back up past all separators. */
			while ( Curschar>Filemem && issepchar(*Curschar))
				Curschar--;
			/* back up past all non-separators. */
			while (Curschar>Filemem && !issepchar(*Curschar)){
				Curschar--;
			}
			if ( issepchar(*Curschar) )
				Curschar++;
		}
		break;
	case 'w':
		if ( issepchar(*Curschar) ) {
			/* If we're on a separator, we advance to */
			/* the next non-separator char. */
			while ( (p=Curschar+1) < Fileend ) {
				Curschar = p;
				if ( ! issepchar(*Curschar) )
					break;
			}
		}
		else {
			/* If we're in the middle of a word, we */
			/* advance to the next word-separator. */
			while ( (p=Curschar+1) < Fileend ) {
				Curschar = p;
				if ( issepchar(*Curschar) )
					break;
			}
			/* Now go past any trailing white space */
			while (isspace(*Curschar) && (Curschar+1)<Fileend)
				Curschar++;
		}
		break;
	case '$':
		while ( oneright() )
			;
		break;
	case '0':
	case '^':
		beginline();
		break;
	case 'x':
		/* Can't do it if we're on a blank line.  (Actually it */
		/* does work, but we want to match the real 'vi'...) */
		if ( *Curschar == '\n' )
			beep();
		else {
			addtobuff(Redobuff,'x',NULL);
			/* To undo it, we insert the same character back. */
			resetundo();
			addtobuff(Undobuff,'i',*Curschar,'\033',NULL);
			Uncurschar = Curschar;
			delchar();
			updatescreen();
		}
		break;
	case 'a':
		/* Works just like an 'i'nsert on the next character. */
		if ( Curschar < (Fileend-1) )
			Curschar++;
		resetundo();
		startinsert("a");
		break;
	case 'i':
		resetundo();
		startinsert("i");
		break;
	case 'o':
		opencmd();
		updatescreen();
		resetundo();
		startinsert("o");
		break;
	case 'd':
		nchar = vgetc();
		n = (Prenum==0?1:Prenum);
		switch(nchar){
		case 'd':
			sprintf(Redobuff,"%ddd",n);
			/* addtobuff(Redobuff,'d','d',NULL); */
			beginline();
			resetundo();
			Uncurschar = Curschar;
			yankline(n);
			delline(n);
			beginline();
			updatescreen();
			/* If we have backed xyzzy, then we deleted the */
			/* last line(s) in the file. */
			if ( Curschar < Uncurschar ) {
				Uncurschar = Curschar;
				nchar = 'p';
			}
			else
				nchar = 'P';
			addtobuff(Undobuff,nchar,NULL);
			break;
		case 'w':
			addtobuff(Redobuff,'d','w',NULL);
			resetundo();
			delword(1);
			Uncurschar = Curschar;
			updatescreen();
			break;
		}
		break;
	case 'c':
		nchar = vgetc();
		switch(nchar){
		case 'c':
			resetundo();
			/* Go to the beginning of the line */
			beginline();
			yankline(1);
			/* delete everything but the newline */
			while ( *Curschar != '\n' )
				delchar();
			startinsert("cc");
			updatescreen();
			break;
		case 'w':
			resetundo();
			delword(0);
			startinsert("cw");
			updatescreen();
			break;
		}
		break;
	case 'y':
		nchar = vgetc();
		switch(nchar){
		case 'y':
			yankline(Prenum==0?1:Prenum);
			break;
		default:
			beep();
		}
		break;
	case '>':
		nchar = vgetc();
		n = (Prenum==0?1:Prenum);
		switch(nchar){
		case '>':
			tabinout(0,n);
			updatescreen();
			break;
		default:
			beep();
		}
		break;
	case '<':
		nchar = vgetc();
		n = (Prenum==0?1:Prenum);
		switch(nchar){
		case '<':
			tabinout(1,n);
			updatescreen();
			break;
		default:
			beep();
		}
		break;
	case '?':
	case '/':
	case ':':
		readcmdline(c);
		break;
	case 'n':
		repsearch();
		break;
	case 'C':
	case 'D':
		p = Curschar;
		while ( Curschar >= p )
			delchar();
		updatescreen();
		resetundo();	/* This should really go above the */
				/* delchars above, and the undobuff should */
				/* be constructed by them. */
		if ( c == 'C' ) {
			Curschar++;
			startinsert("C");
		}
		break;
	case 'r':
		nchar = vgetc();
		resetundo();
		if ( nchar=='\n' || (!Binary && nchar=='\r') ) {
			/* Replacing a char with a newline breaks the */
			/* line in two, and is special. */
			nchar = '\n';	/* convert \r to \n */
			/* Save stuff necessary to undo it, by joining */
			Uncurschar = Curschar-1;
			addtobuff(Undobuff,'J','i',*Curschar,'\033',NULL);
			/* Change current character. */
			*Curschar = nchar;
			/* We don't want to end up on the '\n' */
			if ( Curschar > Filemem )
				Curschar--;
			else if (Curschar < Fileend )
				Curschar++;
		}
		else {
			/* Replacing with a normal character */
			addtobuff(Undobuff,'r',*Curschar,NULL);
			Uncurschar = Curschar;
			/* Change current character. */
			*Curschar = nchar;
		}
		/* Save stuff necessary to redo it */
		addtobuff(Redobuff,'r',nchar,NULL);
		updatescreen();
		break;
	case 'p':
		putline(0);
		break;
	case 'P':
		putline(1);
		break;
	case 'J':
		for ( p=Curschar; *p!= '\n' && p<(Fileend-1) ; p++ )
			;
		if ( p >= (Fileend-1) ) {
			beep();
			break;
		}
		Curschar = p;
		delchar();
		resetundo();
		Uncurschar = Curschar;
		addtobuff(Undobuff,'i','\n','\033',NULL);
		addtobuff(Redobuff,'J',NULL);
		updatescreen();
		break;
	case '.':
		stuffin(Redobuff);
		break;
	case 'u':
		if ( Uncurschar != NULL && *Undobuff != '\0' ) {
			Curschar = Uncurschar;
			stuffin(Undobuff);
			*Undobuff = '\0';
		}
		if ( Undelchars > 0 ) {
			Curschar = Uncurschar;
			/* construct the next Undobuff and Redobuff, which */
			/* will re-insert the characters we're deleting. */
			p = Undobuff;
			q = Redobuff;
			*p++ = *q++ = 'i';
			while ( Undelchars-- > 0 ) {
				*p++ = *q++ = *Curschar;
				delchar();
			}
			/* Finish constructing Uncursbuff, and Uncurschar */
			/* is left unchanged. */
			*p++ = *q++ = '\033';
			*p = *q = '\0';
			/* Undelchars has been reset to 0 */
			updatescreen();
		}
		break;
	default:
		beep();
		break;
	}
}

/*
 * tabinout(inout,num)
 *
 * If inout==0, add a tab to the begining of the next num lines.
 * If inout==1, delete a tab from the begining of the next num lines.
 */

tabinout(inout,num)
{
	int ntodo = num;
	char *savecurs, *p;

	beginline();
	savecurs = Curschar;
	while ( ntodo-- > 0 ) {
		beginline();
		if ( inout == 0 )
			inschar('\t');
		else {
			if ( *Curschar == '\t' )
				delchar();
		}
		if ( ntodo > 0 ) {
			if ( (p=nextline(Curschar)) != NULL )
				Curschar = p;
			else
				break;
		}
	}
	/* We want to end up where we started */
	Curschar = savecurs;
	updatescreen();
	/* Construct re-do and un-do stuff */
	sprintf(Redobuff,"%d%s",num,inout==0?">>":"<<");
	resetundo();
	Uncurschar = savecurs;
	sprintf(Undobuff,"%d%s",num,inout==0?"<<":">>");
}

startinsert(initstr)
char *initstr;
{
	char *p, c;

	Insstart = Curschar;
	Ninsert = 0;
	Insptr = Insbuff;
	for (p=initstr; (c=(*p++))!='\0'; )
		*Insptr++ = c;
	State = INSERT;
	windrefresh();
}

resetundo()
{
	Undelchars = 0;
	*Undobuff = '\0';
	Uncurschar = NULL;
}
SHAR_EOF
fi # end of overwriting check
if test -f 'stevie.h'
then
	echo shar: will not over-write existing file "'stevie.h'"
else
cat << \SHAR_EOF > 'stevie.h'
/*
 * STevie - ST editor for VI enthusiasts.    ...Tim Thompson...twitch!tjt...
 */

/* One (and only 1) of the following 3 defines should be uncommented. */
/* Most of the code is machine-independent.  Most of the machine- */
/* dependent stuff is in window.c */

#define ATARI		1	/* For the Atari 520 ST */
/*#define UNIXPC	1	/* The AT&T UNIX PC (console) */
/*#define TCAP		1	/* For termcap-based terminals */

#define FILELENG 64000
#define NORMAL 0
#define CMDLINE 1
#define INSERT 2
#define APPEND 3
#define FORWARD 4
#define BACKWARD 5
#define WORDSEP " \t\n()[]{},;:'\"-="

#define CHANGED Changed=1
#define UNCHANGED Changed=0

#ifndef NULL
#define NULL 0
#endif

struct charinfo {
	char ch_size;
	char *ch_str;
};

extern struct charinfo chars[];

extern int State;
extern int Rows;
extern int Columns;
extern char *Realscreen;
extern char *Nextscreen;
extern char *Filename;
extern char *Filemem;
extern char *Filemax;
extern char *Fileend;
extern char *Topchar;
extern char *Botchar;
extern char *Curschar;
extern char *Insstart;
extern int Cursrow, Curscol, Cursvcol;
extern int Prenum;
extern int Debug;
extern int Changed;
extern int Binary;
extern char Redobuff[], Undobuff[], Insbuff[];
extern char *Uncurschar, *Insptr;
extern int Ninsert, Undelchars;

char *malloc(), *strchr(), *strsave(), *alloc(), *strcpy();

char *nextline(), *prevline(), *coladvance(), *ssearch();
char *fwdsearch(), *bcksearch();
SHAR_EOF
fi # end of overwriting check
if test -f 'window.c'
then
	echo shar: will not over-write existing file "'window.c'"
else
cat << \SHAR_EOF > 'window.c'
/*
 * STevie - ST editor for VI enthusiasts.    ...Tim Thompson...twitch!tjt...
 */

#include "stevie.h"
#include <stdio.h>

#ifdef ATARI
#include <osbind.h>
#define EscSeq(x) Cconout('\033');Cconout(x);
#endif
#ifdef UNIXPC
#include <sys/window.h>
#endif
#ifdef TCAP
#include <curses.h>
#endif

windinit()
{
#ifdef ATARI
	Columns=80;
	Rows=25;
	Cursconf(1,NULL);
#endif
#ifdef UNIXPC
        struct uwdata uw;
        
	winit();
	if ( ioctl(0,WIOCGETD,&uw) == -1
	  && ioctl(1,WIOCGETD,&uw) == -1
	  && ioctl(2,WIOCGETD,&uw) == -1 ) {
		fprintf(stderr,"*** ERROR *** Not a window!\n");
		windexit(1);
	}
	Columns = uw.uw_width / uw.uw_hs;
	Rows = uw.uw_height / uw.uw_vs;
	cbreak();
	nonl();
	noecho();
#endif
#ifdef TCAP
	char *getenv();
	char *p = getenv("TERM");

	initscr();
	Columns = 80;
	if ( strncmp(p,"vt52",4)==0 )
		Rows = 25;
	else
		Rows = 24;
	cbreak();
	nonl();
	noecho();
#endif
}

windgoto(r,c)
int r,c;
{
#ifdef UNIXPC
	printf("\033[%d;%dH",r+1,c+1);
#endif
#ifdef ATARI
	EscSeq('Y');
	Cconout(r+040);
	Cconout(c+040);
#endif
#ifdef TCAP
	move(r,c);
#endif
}

windexit(r)
int r;
{
#ifdef UNIXPC
	nocbreak();
	nl();
	echo();
	wexit();
#endif
#ifdef TCAP
	nocbreak();
	nl();
	echo();
	endwin();
#endif
	exit(r);
}

windclear()
{
#ifdef UNIXPC
	printf("\033[H\033[J");
#endif
#ifdef ATARI
	Cconws("\033H\033J");
#endif
#ifdef TCAP
	clear();
	refresh();
#endif
}

windgetc()
{
#ifdef ATARI
	return(Cnecin());
#else
	return(getchar());
#endif
}

windstr(s)
char *s;
{
#ifdef ATARI
	Cconws(s);
#endif
#ifdef UNIXPC
	printf("%s",s);
#endif
#ifdef TCAP
	addstr(s);
	refresh();
#endif
}

windputc(c)
int c;
{
#ifdef ATARI
	Cconout(c);
#endif
#ifdef UNIXPC
	putchar(c);
#endif
#ifdef TCAP
	addch(c);
#endif
}

windrefresh()
{
#ifdef TCAP
	refresh();
#endif
}

beep()
{
#ifdef ATARI
	Cconout('\007');
#else
	putchar('\007');
#endif
}
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0