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

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

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

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	MAKE_TAGS
#	Makefile
#	README
#	TODO
#	amiga.h
#	ascii.h
#	bsd.c
#	bsd.h
#	dec.c
#	dos.c
#	dos.h
#	env.h
#	inc.c
#	keymap.h
#	linefunc.c
#	macros.h
#	makefile.amiga.lattice
#	makefile.bsd
#	makefile.dos
#	makefile.mwc
#	makefile.os2
#	makefile.tos
#	makefile.usg
#	mark.c
#	mk.c
#	os2.h
#	param.c
#	param.h
#	porting.doc
#	raw.c
#	regexp.h
#	regmagic.h
#	regsub.c
#	sendpacket.c
#	source.doc
#	tos.h
#	unix.c
#	unix.h
#	updateNs.c
#	updateRs.c
# This archive created: Tue Mar 14 14:40:09 1989
cat << \SHAR_EOF > MAKE_TAGS
/ctags/ctags -t    alloc.c charset.c cmdline.c dec.c edit.c
/ctags/ctags -t -a fileio.c help.c inc.c linefunc.c main.c mark.c
/ctags/ctags -t -a misccmds.c normal.c param.c raw.c screen.c
/ctags/ctags -t -a search.c sendpacket.c updateNs.c
/ctags/ctags -t -a updateRs.c ascii.h keymap.h
/ctags/ctags -t -a macros.h param.h stevie.h term.h mk.c

/ctags/ctags -t -a amiga.h amiga.c
SHAR_EOF
cat << \SHAR_EOF > Makefile
#
# Makefile for Lattice C 5.0 on Amiga
#

.c.o:
	lc $(CFLAGS) $<

CFLAGS = -cu -ma -O
LINKFLAGS = NODEBUG
LIBS = lib:lc.lib

MACH=	amiga.o raw.o sendpacket.o

OBJ1=	main.o edit.o linefunc.o normal.o cmdline.o charset.o
OBJ2=	updateRs.o misccmds.o help.o dec.o inc.o search.o alloc.o
OBJ3=	mk.o regexp.o regsub.o version.o
OBJ4=	updateNs.o mark.o screen.o fileio.o param.o

OBJ= $(OBJ1) $(OBJ2) $(OBJ3) $(OBJ4) $(MACH)

all: stevie
	say "done all"

stevie: $(OBJ)
	BLINK TO stevie FROM lib:cres.o $(OBJ) LIBRARY $(LIBS) $(LINKFLAGS)

clean:
	delete $(OBJ1)
	delete $(OBJ2)
	delete $(OBJ3)
	delete $(OBJ4)
	delete $(MACH)
	delete stevie
SHAR_EOF
cat << \SHAR_EOF > README
STEVIE Source Release

This is a source release of the STEVIE editor, a public domain clone
of the UNIX editor 'vi'. The program was originally developed for the
Atari ST, but has been ported to UNIX, OS/2, BSD 4.3 and the Amiga as well.

There are currently two divergent versions of STEVIE. This version is the one
that was ported to the Amiga and then worked on by me (G. R. Walter). The other
one Tony Andrews continued to work on. My version is faster in some respects
then his version, and his version does a couple of things mine doesn't. 

The files included in this release are:

README
	This file.

stevie.doc
	Reference manual for STEVIE. Assumes familiarity with vi.

source.doc
	Quick overview of the major data structures used.

porting.doc
	Tips for porting STEVIE to other systems.

makefile.dos
makefile.os2
makefile.usg
makefile.tos
makefile.bsd
makefile.amiga.lattice
	Makefiles for MS DOS, OS/2, UNIX System V, Atari ST, BSD 4.3 UNIX and
the Amiga respectively.

raw.c
sendpacket.c
amiga.c
amiga.h
bsd.c
bsd.h
dos.c
dos.h
os2.c
os2.h
unix.c
unix.h
tos.c
tos.h
	System-dependent routines for the same.

alloc.c ascii.h cmdline.c edit.c fileio.c help.c charset.c
keymap.h linefunc.c main.c mark.c misccmds.c normal.c param.c
regexp.c regsub.c version.c regexp.h regmagic.h
param.h ptrfunc.c screen.c search.c stevie.h term.h macros.h

	C source and header files for STEVIE.

To compile STEVIE for one of the provided systems:

	1. Compile the regular expression library and install as
	   appropriate for your system.

	2. Edit the file 'env.h' to set the system defines as needed.

	3. Check the makefile for your system, and modify as needed.

	4. Compile.

NOTE: implicit in the design is the assumption that char's are unsigned. Thus
      if your compiler assumes different by default, change the default or
      you may have to change the source.

Good Luck...

Tony Andrews            March  12, 1988
G. R. (Fred) Walter     August 14, 1988
SHAR_EOF
cat << \SHAR_EOF > TODO
To Do
-----

- Change the static buffers for insert/undo/redo/undoundo/etc to dynamic
  buffers.

- Add #'d and named buffers.

- Add 'R' and 'U'.

- Add 'set sw' option.

- In cmdline.c make get_range() give the appropriate error messages when it
  gets a bad line range.

- Add & (do last search and replace on current line) and :[range]&
  (do last search and replace on the range of lines).

- change the screen code so that number of columns is always a multiple
  of four. Then add assembler routines for copying (to be used in
  updateNextscreen()) that copy longs (4 bytes at a time). This will 
  speed up things even more.
SHAR_EOF
cat << \SHAR_EOF > amiga.h
/*
 * Amiga Machine-dependent routines. 
 */

extern FILE *raw_io;
extern int   new_window;

int  inchar();
void flushbuf();
void outchar();
void outstr();
void beep();
void windinit(), windexit(), windgoto();
void delay();
void sleep();
SHAR_EOF
cat << \SHAR_EOF > ascii.h
/*
 * STEVIE - Simply Try this Editor for VI Enthusiasts
 *
 * Code Contributions By : Tim Thompson           twitch!tjt
 *                         Tony Andrews           onecom!wldrdg!tony 
 *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
 */

/*
 * Definitions of various common control characters 
 */

#define	NUL			'\000'
#define	BS			'\010'
#define	BS_STR			"\010"
#define	TAB			'\011'
#define	NL			'\012'
#define	NL_STR			"\012"
#define	CR			'\015'
#define	ESC			'\033'
#define	ESC_STR			"\033"

#define	UNDO_SHIFTJ		'\333'
#define	UNDO_SHIFTJ_STR		"\333"

#define	ENABLE_REDRAWING	'\334'
#define	ENABLE_REDRAWING_STR	"\334"

#define	CTRL(x)	((x) & 0x1f)
SHAR_EOF
cat << \SHAR_EOF > bsd.c
/*
 * System-dependent routines for BSD 4.3 UNIX 
 */

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

/*
 * inchar() - get a character from the keyboard 
 */
int
inchar()
{
    int             c;

    fflush(stdout);		/* flush any pending output */

    c = getchar();

    return c;
}

void
outstr(s)
    char           *s;
{
    while (*s)
	outchar(*s++);
}

void
beep()
{
    if (RedrawingDisabled)
	return;

    outchar('\007');
}

void
delay()
{
    sleep(1);
}

static struct sgttyb ostate;

void
windinit()
{
    char           *getenv();
    char           *term;
    struct sgttyb   nstate;

    term = getenv("TERM");
    if (!term) {
	fprintf(stderr, "Invalid terminal type '%s'\n", term);
	exit(1);
    }
    if ((strncmp(term, "vt", 2) != 0) && (strncmp(term, "kd", 2) != 0)) {
	fprintf(stderr, "Invalid terminal type '%s'\n", term);
	exit(1);
    }
    Columns = 80;
    P(P_LI) = Rows = 24;

    /*
     * Go into cbreak mode 
     */
    ioctl(1, (long) TIOCGETP, (char *) &ostate);
    nstate = ostate;
    nstate.sg_flags = nstate.sg_flags & ~(ECHO | CRMOD) | CBREAK;
    ioctl(1, (long) TIOCSETP, (char *) &nstate);
}

void
windexit(r)
    int             r;
{
    fflush(stdout);

    ioctl(0, (long) TIOCSETP, (char *) &ostate);

    exit(r);
}

void
windgoto(r, c)
    int             c;
    int             r;
{
    r++;
    c++;

    outstr("\033[");
    if (r >= 10)
	outchar((char) (r / 10 + '0'));
    outchar((char) (r % 10 + '0'));
    outchar(';');
    if (c >= 10)
	outchar((char) (c / 10 + '0'));
    outchar((char) (c % 10 + '0'));
    outchar('H');
}

FILE           *
fopenb(fname, mode)
    char           *fname;
    char           *mode;
{
    return fopen(fname, mode);
}
SHAR_EOF
cat << \SHAR_EOF > bsd.h
/*
 * BSD 4.3 Machine-dependent routines. 
 */

int inchar();
#define outchar(c) putchar(c)
void outstr(), beep();
#define remove(path) unlink(path)
int rename();
void windinit(), windexit(), windgoto();
void delay();
SHAR_EOF
cat << \SHAR_EOF > dec.c
/*
 * STEVIE - Simply Try this Editor for VI Enthusiasts
 *
 * Code Contributions By : Tim Thompson           twitch!tjt
 *                         Tony Andrews           onecom!wldrdg!tony 
 *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
 */

#include "stevie.h"

/*
 * dec(p) 
 *
 * Decrement the line pointer 'p' crossing line boundaries as necessary. Return
 * 1 when crossing a line, -1 when at start of file, 0 otherwise. 
 */
int
dec(lp)
    register LPtr  *lp;
{
    if (lp->index > 0) {	/* still within line */
	lp->index--;
	return 0;
    }
    if (lp->linep->prev != Filetop->linep) {	/* there is a prior line */
	lp->linep = lp->linep->prev;
	lp->index = strlen(lp->linep->s);
	return 1;
    }
    lp->index = 0;		/* stick at first char */
    return -1;			/* at start of file */
}
SHAR_EOF
cat << \SHAR_EOF > dos.c
static char     RCSid[] =
"$Header: dos.c,v 1.1 88/05/03 14:22:16 tony Exp $";

/*
 * DOS System-dependent routines.
 *
 * System-specific code for MS-DOS. This has been tested with
 * MSDOS 3.3 on an AT. Also, the console driver "nansi.sys" is
 * required.
 *
 * $Log:	dos.c,v $
 * Revision 1.1  88/05/03  14:22:16  tony
 * Initial revision
 * 
 *
 */

#include "stevie.h"

/*
 * inchar() - get a character from the keyboard
 */
int
inchar()
{
    int             c;

    for (;; beep()) {		/* loop until we get a valid character */

	flushbuf();		/* flush any pending output */

	switch (c = getch()) {
	  case 0x1e:
	    return K_CGRAVE;
	  case 0:		/* special key */
	    if (State != NORMAL) {
		c = getch();	/* throw away next char */
		continue;	/* and loop for another char */
	    }
	    switch (c = getch()) {
	      case 0x50:
		return K_DARROW;
	      case 0x48:
		return K_UARROW;
	      case 0x4b:
		return K_LARROW;
	      case 0x4d:
		return K_RARROW;
	      case 0x52:
		return K_INSERT;
	      case 0x47:
		stuffReadbuff("1G");
		return -1;
	      case 0x4f:
		stuffReadbuff("G");
		return -1;
	      case 0x51:
		stuffReadbuff(mkstr(CTRL('F')));
		return -1;
	      case 0x49:
		stuffReadbuff(mkstr(CTRL('B')));
		return -1;
		/*
		 * Hard-code some useful function key macros. 
		 */
	      case 0x3b:	/* F1 */
		stuffReadbuff(":p\n");
		return -1;
	      case 0x54:	/* SF1 */
		stuffReadbuff(":p!\n");
		return -1;
	      case 0x3c:	/* F2 */
		stuffReadbuff(":n\n");
		return -1;
	      case 0x55:	/* SF2 */
		stuffReadbuff(":n!\n");
		return -1;
	      case 0x3d:	/* F3 */
		stuffReadbuff(":e #\n");
		return -1;
	      case 0x3e:	/* F4 */
		stuffReadbuff(":rew\n");
		return -1;
	      case 0x57:	/* SF4 */
		stuffReadbuff(":rew!\n");
		return -1;
	      case 0x3f:	/* F5 */
		stuffReadbuff("[[");
		return -1;
	      case 0x40:	/* F6 */
		stuffReadbuff("]]");
		return -1;
	      case 0x41:	/* F7 */
		stuffReadbuff("<<");
		return -1;
	      case 0x42:	/* F8 */
		stuffReadbuff(">>");
		return -1;
	      case 0x43:	/* F9 */
		stuffReadbuff(":x\n");
		return -1;
	      case 0x44:	/* F10 */
		stuffReadbuff(":help\n");
		return -1;
	      default:
		break;
	    }
	    break;

	  default:
	    return c;
	}
    }
}

#define	BSIZE	2048
static char     outbuf[BSIZE];
static int      bpos = 0;

flushbuf()
{
    if (bpos != 0)
	write(1, outbuf, bpos);
    bpos = 0;
}

/*
 * Macro to output a character. Used within this file for speed.
 */
#define	outone(c)	outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf()

/*
 * Function version for use outside this file.
 */
void
outchar(c)
    register char   c;
{
    outbuf[bpos++] = c;
    if (bpos >= BSIZE)
	flushbuf();
}

static char     cell[2] = {0, 7};

/*
 * outstr(s) - write a string to the console
 */
void
outstr(s)
    register char  *s;
{
    while (*s) {
	outone(*s++);
    }
}

void
beep()
{
    if (RedrawingDisabled)
	return;

    outone('\007');
}

void
sleep(n)
    int             n;
{
    /*
     * Should do something reasonable here. 
     */
}

void
delay()
{
    long            l;

    flushbuf();
    /*
     * Should do something better here... 
     */
    for (l = 0; l < 5000; l++);
}

void
windinit()
{
    Columns = 80;
    P(P_LI) = Rows = 25;
}

void
windexit(r)
    int             r;
{
    flushbuf();
    exit(r);
}

void
windgoto(r, c)
    register int    r, c;
{
    r += 1;
    c += 1;

    /*
     * Check for overflow once, to save time. 
     */
    if (bpos + 8 >= BSIZE)
	flushbuf();

    outbuf[bpos++] = '\033';
    outbuf[bpos++] = '[';
    if (r >= 10)
	outbuf[bpos++] = r / 10 + '0';
    outbuf[bpos++] = r % 10 + '0';
    outbuf[bpos++] = ';';
    if (c >= 10)
	outbuf[bpos++] = c / 10 + '0';
    outbuf[bpos++] = c % 10 + '0';
    outbuf[bpos++] = 'H';
}

FILE           *
fopenb(fname, mode)
    char           *fname;
    char           *mode;
{
    FILE           *fopen();
    char            modestr[16];

    sprintf(modestr, "%sb", mode);
    return fopen(fname, modestr);
}
SHAR_EOF
cat << \SHAR_EOF > dos.h
/*
 * MS DOS Machine-dependent routines. 
 */

int  inchar();
void outchar();
void outstr();
void beep();
void windinit();
void windexit();
void windgoto();
void delay();
void sleep();
SHAR_EOF
cat << \SHAR_EOF > env.h
/*
 * STEVIE - Simply Try this Editor for VI Enthusiasts
 *
 * Code Contributions By : Tim Thompson           twitch!tjt
 *                         Tony Andrews           onecom!wldrdg!tony 
 *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
 */

/*
 * The defines in this file establish the environment we're compiling
 * in. Set these appropriately before compiling the editor.
 */

/*
 * One (and only 1) of the following defines should be uncommented. Most of
 * the code is pretty machine-independent. Machine dependent code goes in a
 * file like tos.c or unix.c. The only other place where machine dependent
 * code goes is term.h for escape sequences. 
 */

#ifndef AMIGA
#define	ATARI			Atari ST */
/* #define	UNIX		System V */
/* #define	BSD		BSD 4.3 */
/* #define	OS2		Microsoft OS/2 */
/* #define	DOS		MS DOS 3.3 */
/* #define	AMIGA		Amiga */
#endif

/*
 * If ATARI is defined, one of the following compilers must be selected. 
 */
#ifdef	ATARI
#define MWC			Mark William's C 3.0.9 */
/* #define	MEGAMAX		Megamax Compiler */
/* #define	ALCYON		Alcyon C compiler */

# ifdef MWC
#  define AppendNumberToUndoUndobuff 	XX1
#  define AppendPositionToUndoUndobuff	XX2
#  define FOPENB
# endif

# ifdef MEGAMAX
#  define FOPENB
# endif
#endif

/*
 * If HELP is defined, the :help command shows a vi command summary. 
 */
#define	HELP			/* enable help command */

/*
 * STRCSPN should be defined if the target system doesn't have the
 * routine strcspn() available. See regexp.c for details.
 */

#ifdef	ATARI
#define	STRCSPN
#endif
SHAR_EOF
cat << \SHAR_EOF > inc.c
/*
 * STEVIE - Simply Try this Editor for VI Enthusiasts
 *
 * Code Contributions By : Tim Thompson           twitch!tjt
 *                         Tony Andrews           onecom!wldrdg!tony 
 *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
 */

#include "stevie.h"

/*
 * inc(p) 
 *
 * Increment the line pointer 'p' crossing line boundaries as necessary. Return
 * 1 when crossing a line, -1 when at end of file, 0 otherwise. 
 */
int
inc(lp)
    register LPtr  *lp;
{
    register char  *p = &(lp->linep->s[lp->index]);

    if (*p != NUL) {		/* still within line */
	lp->index++;
	return ((p[1] != NUL) ? 0 : 1);
    }
    if (lp->linep->next != Fileend->linep) {	/* there is a next line */
	lp->index = 0;
	lp->linep = lp->linep->next;
	return 1;
    }
    return -1;
}
SHAR_EOF
cat << \SHAR_EOF > keymap.h
/*
 * STEVIE - Simply Try this Editor for VI Enthusiasts
 *
 * Code Contributions By : Tim Thompson           twitch!tjt
 *                         Tony Andrews           onecom!wldrdg!tony 
 *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
 */

/*
 * Keycode definitions for special keys 
 *
 * On systems that have any of these keys, the routine 'inchar' in the
 * machine-dependent code should return one of the codes here. 
 */

#define	K_CGRAVE	0x1e	/* control grave accent */

#define	K_HELP		0x80
#define	K_UNDO		0x81
#define	K_INSERT	0x82
#define	K_HOME		0x83
#define	K_UARROW	0x84
#define	K_DARROW	0x85
#define	K_LARROW	0x86
#define	K_RARROW	0x87
#define	K_SUARROW	0x88
#define	K_SDARROW	0x89
#define	K_SLARROW	0x8a
#define	K_SRARROW	0x8b

#define	K_F1		0x8c	/* function keys */
#define	K_F2		0x8d
#define	K_F3		0x8e
#define	K_F4		0x8f
#define	K_F5		0x90
#define	K_F6		0x91
#define	K_F7		0x92
#define	K_F8		0x93
#define	K_F9		0x94
#define	K_F10		0x95

#define	K_SF1		0x96	/* shifted function keys */
#define	K_SF2		0x97
#define	K_SF3		0x98
#define	K_SF4		0x99
#define	K_SF5		0x9a
#define	K_SF6		0x9b
#define	K_SF7		0x9c
#define	K_SF8		0x9d
#define	K_SF9		0x9e
#define	K_SF10		0x9f
SHAR_EOF
cat << \SHAR_EOF > linefunc.c
/*
 * STEVIE - Simply Try this Editor for VI Enthusiasts
 *
 * Code Contributions By : Tim Thompson           twitch!tjt
 *                         Tony Andrews           onecom!wldrdg!tony 
 *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
 */

#include "stevie.h"

/*
 * nextline(curr) 
 *
 * Return a pointer to the beginning of the next line after the one referenced
 * by 'curr'. Return NULL if there is no next line (at EOF). 
 */

LPtr           *
nextline(curr)
    LPtr           *curr;
{
    static LPtr     next;

    if (curr != NULL) {
	if (curr->linep->next != Fileend->linep) {
	    next.index = 0;
	    next.linep = curr->linep->next;
	    return &next;
	}
    }
    return (LPtr *) NULL;
}

/*
 * prevline(curr) 
 *
 * Return a pointer to the beginning of the line before the one referenced by
 * 'curr'. Return NULL if there is no prior line. 
 */

LPtr           *
prevline(curr)
    LPtr           *curr;
{
    static LPtr     prev;

    if (curr != NULL) {
	if (curr->linep->prev != Filetop->linep) {
	    prev.index = 0;
	    prev.linep = curr->linep->prev;
	    return &prev;
	}
    }
    return (LPtr *) NULL;
}

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

LPtr           *
coladvance(p, col)
    LPtr           *p;
    int             col;
{
    static LPtr     lp;
    int             c, in;

    lp.linep = p->linep;
    lp.index = p->index;

    /* If we're on a blank ('\n' only) line, we can't do anything */
    if (lp.linep->s[lp.index] == '\0')
	return &lp;
    /* try to advance to the specified column */
    for (c = 0; col-- > 0; c++) {
	/* Count a tab for what it's worth (if list mode not on) */
	if (gchar(&lp) == TAB && !P(P_LS)) {
	    in = ((P(P_TS) - 1) - c % P(P_TS));
	    col -= in;
	    c += in;
	}
	/* Don't go past the end of */
	/* the file or the line. */
	if (inc(&lp)) {
	    dec(&lp);
	    break;
	}
    }
    return &lp;
}
SHAR_EOF
cat << \SHAR_EOF > macros.h
/*
 * STEVIE - Simply Try this Editor for VI Enthusiasts
 *
 * Code Contributions By : Tim Thompson           twitch!tjt
 *                         Tony Andrews           onecom!wldrdg!tony 
 *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
 */

/*
 * gchar(lp) - get the character at position "lp" 
 */
#define gchar(lp) ((lp)->linep->s[(lp)->index])

/*
 * pchar(lp, c) - put character 'c' at position 'lp' 
 */
#define pchar(lp, c) ((lp)->linep->s[(lp)->index] = (c))

/*
 * pswap(a, b) - swap two position pointers 
 */
#define pswap(a, b) { LPtr pswaptmp; pswaptmp = a; a = b; b = pswaptmp; }

/*
 * Position comparisons 
 */
#define lt(a, b) ((LINEOF(a) != LINEOF(b)) \
                   ? (LINEOF(a) < LINEOF(b)) : ((a)->index < (b)->index))

#define ltoreq(a, b) ((LINEOF(a) != LINEOF(b)) \
                   ? (LINEOF(a) < LINEOF(b)) : ((a)->index <= (b)->index))

#define gt(a, b) ((LINEOF(a) != LINEOF(b)) \
                   ? (LINEOF(a) > LINEOF(b)) : ((a)->index > (b)->index))

#define gtoreq(a, b) ((LINEOF(a) != LINEOF(b)) \
                   ? (LINEOF(a) > LINEOF(b)) : ((a)->index >= (b)->index))

#define equal(a, b) (((a)->linep == (b)->linep) && ((a)->index == (b)->index))

/*
 * anyinput
 *
 * Return non-zero if input is pending.
 */
#define anyinput() (Readbuffptr != NULL)

/*
 * buf1line() - return TRUE if there is only one line in file buffer
 */
#define buf1line() (Filemem->linep->next == Fileend->linep)

/*
 * bufempty() - return TRUE if the file buffer is empty 
 */
#define bufempty() (buf1line() && Filemem->linep->s[0] == NUL)

/*
 * lineempty() - return TRUE if the line is empty 
 */
#define lineempty(p) ((p)->linep->s[0] == NUL)

/*
 * startofline() - return TRUE if the given position is at start of line 
 */
#define startofline(p) ((p)->index == 0)

/*
 * endofline() - return TRUE if the given position is at end of line 
 *
 * This routine will probably never be called with a position resting on the NUL
 * byte, but handle it correctly in case it happens. 
 */
#define endofline(p) \
     ((p)->linep->s[(p)->index] == NUL || (p)->linep->s[(p)->index + 1] == NUL)

/*
 * RowNumber() - return the row number (if no UndoInProgress)
 */
#define RowNumber(p) (UndoInProgress ? 0 : cntllines(Filemem, (p)))
SHAR_EOF
cat << \SHAR_EOF > makefile.amiga.lattice
#
# Makefile for Lattice C 5.0 on Amiga
#

.c.o:
	lc $(CFLAGS) $<

CFLAGS = -cu -ma -O
LINKFLAGS = NODEBUG
LIBS = lib:lc.lib

MACH=	amiga.o raw.o sendpacket.o

OBJ1=	main.o edit.o linefunc.o normal.o cmdline.o charset.o
OBJ2=	updateRs.o misccmds.o help.o dec.o inc.o search.o alloc.o
OBJ3=	mk.o regexp.o regsub.o version.o
OBJ4=	updateNs.o mark.o screen.o fileio.o param.o

OBJ= $(OBJ1) $(OBJ2) $(OBJ3) $(OBJ4) $(MACH)

all: stevie
	say "done all"

stevie: $(OBJ)
	BLINK TO stevie FROM lib:cres.o $(OBJ) LIBRARY $(LIBS) $(LINKFLAGS)

clean:
	delete $(OBJ1)
	delete $(OBJ2)
	delete $(OBJ3)
	delete $(OBJ4)
	delete $(MACH)
	delete stevie
SHAR_EOF
cat << \SHAR_EOF > makefile.bsd
#
# Makefile for BSD 4.3 UNIX
#

CFLAGS = -pg -g
LINTFLAGS = 

MACHOBJ=	bsd.o
MACHSRC=	bsd.c

SRC=	main.c edit.c linefunc.c normal.c cmdline.c charset.c \
	updateRs.c misccmds.c help.c dec.c inc.c search.c alloc.c \
	mk.c regexp.c regsub.c version.c \
	updateNs.c mark.c screen.c fileio.c param.c $(MACHSRC)

OBJ=	main.o edit.o linefunc.o normal.o cmdline.o charset.o \
	updateRs.o misccmds.o help.o dec.o inc.o search.o alloc.o \
	mk.o regexp.o regsub.o version.o \
	updateNs.o mark.o screen.o fileio.o param.o $(MACHOBJ)

all : stevie

stevie : $(OBJ)
	$(CC) $(OBJ) $(CFLAGS) -o stevie

lint:
	lint $(LINTFLAGS) $(SRC)

clean :
	rm -f *.out *.o core stevie *.BAK
SHAR_EOF
cat << \SHAR_EOF > makefile.dos
#
# Makefile for DOS
#
# This makefile is set up for Microsoft C 5.1
#

#
# Compact model lets us edit large files, but keep small model code
#
MODEL= /AC
CFLAGS = $(MODEL)

MACH=	dos.obj

OBJ=	main.obj edit.obj linefunc.obj normal.obj cmdline.obj charset.obj \
	mk.obj updateRs.obj regexp.obj regsub.obj version.obj \
	misccmds.obj help.obj dec.obj inc.obj search.obj alloc.obj \
	updateNs.obj mark.obj screen.obj fileio.obj param.obj $(MACH)

all:	stevie.exe

main.obj:	main.c
	cl -c $(CFLAGS) main.c

updateRs.obj:	updateRs.c
	cl -c $(CFLAGS) updateRs.c

mk.obj:	mk.c
	cl -c $(CFLAGS) mk.c

regexp.obj:	regexp.c
	cl -c $(CFLAGS) regexp.c

regsub.obj:	regsub.c
	cl -c $(CFLAGS) regsub.c

version.obj:	version.c
	cl -c $(CFLAGS) version.c

alloc.obj : alloc.c
	cl -c $(CFLAGS) alloc.c

edit.obj : edit.c
	cl -c $(CFLAGS) edit.c

updateNs.obj : updateNs.c
	cl -c $(CFLAGS) updateNs.c

linefunc.obj : linefunc.c
	cl -c $(CFLAGS) linefunc.c

normal.obj : normal.c
	cl -c $(CFLAGS) normal.c

cmdline.obj : cmdline.c
	cl -c $(CFLAGS) cmdline.c

charset.obj : charset.c
	cl -c $(CFLAGS) charset.c

misccmds.obj : misccmds.c
	cl -c $(CFLAGS) misccmds.c

help.obj : help.c
	cl -c $(CFLAGS) help.c

dec.obj : dec.c
	cl -c $(CFLAGS) dec.c

inc.obj : inc.c
	cl -c $(CFLAGS) inc.c

search.obj : search.c
	cl -c $(CFLAGS) search.c

mark.obj : mark.c
	cl -c $(CFLAGS) mark.c

screen.obj : screen.c
	cl -c $(CFLAGS) screen.c

fileio.obj : fileio.c
	cl -c $(CFLAGS) fileio.c

param.obj : param.c
	cl -c $(CFLAGS) param.c

os2.obj : os2.c
	cl -c $(CFLAGS) os2.c

stevie.exe : $(OBJ)
	cl $(MODEL) *.obj c:\lib\setargv.obj -o stevie.exe /F 6000 -link /NOE
SHAR_EOF
cat << \SHAR_EOF > makefile.mwc
#
#
#
# Makefile for Mark Williams C
#
CFLAGS = -O -VPEEP 
LDFLAGS = -s -x -v
LINKER=ld

OBJ1=	main.o edit.o linefunc.o normal.o cmdline.o charset.o \
	updatere.o misccmds.o help.o dec.o inc.o 
OBJ2=	alloc.o search.o mk.o regexp.o regsub.o version.o updatene.o \
	mark.o screen.o fileio.o param.o tos.o

SRC=	main.c edit.c linefunc.c normal.c cmdline.c charset.c \
	updatere.c misccmds.c help.c dec.c inc.c search.c alloc.c \
	mk.c regexp.c regsub.c version.c \
	updatene.c mark.c screen.c fileio.c param.c \
	tos.c


all : stevie.ttp

stevie.a: $(OBJ1) $(OBJ2)
	ar rv stevie.a $(OBJ1)
	ar rv stevie.a $(OBJ2)

stevie.ttp:	stevie.a
	cc stevie.a $(LIBS) -o stevie.ttp
SHAR_EOF
cat << \SHAR_EOF > makefile.os2
#
# Makefile for OS/2
#
# The make command with OS/2 is really stupid.
#

#
# Compact model lets us edit large files, but keep small model code
#
MODEL= -AC
CFLAGS = $(MODEL) -I..\regexp -J

MACH=	os2.obj

OBJ=	main.obj edit.obj linefunc.obj normal.obj cmdline.obj charset.obj \
	mk.obj updateRs.obj regexp.obj regsub.obj version.obj \
	misccmds.obj help.obj dec.obj inc.obj search.obj alloc.obj \
	updateNs.obj mark.obj screen.obj fileio.obj param.obj $(MACH)

all:	stevie.exe

main.obj:	main.c
	cl -c $(CFLAGS) main.c

updateRs.obj:	updateRs.c
	cl -c $(CFLAGS) updateRs.c

mk.obj:	mk.c
	cl -c $(CFLAGS) mk.c

regexp.obj:	regexp.c
	cl -c $(CFLAGS) regexp.c

regsub.obj:	regsub.c
	cl -c $(CFLAGS) regsub.c

version.obj:	version.c
	cl -c $(CFLAGS) version.c

alloc.obj : alloc.c
	cl -c $(CFLAGS) alloc.c

edit.obj : edit.c
	cl -c $(CFLAGS) edit.c

updateNs.obj : updateNs.c
	cl -c $(CFLAGS) updateNs.c

linefunc.obj : linefunc.c
	cl -c $(CFLAGS) linefunc.c

normal.obj : normal.c
	cl -c $(CFLAGS) normal.c

cmdline.obj : cmdline.c
	cl -c $(CFLAGS) cmdline.c

charset.obj : charset.c
	cl -c $(CFLAGS) charset.c

misccmds.obj : misccmds.c
	cl -c $(CFLAGS) misccmds.c

help.obj : help.c
	cl -c $(CFLAGS) help.c

dec.obj : dec.c
	cl -c $(CFLAGS) dec.c

inc.obj : inc.c
	cl -c $(CFLAGS) inc.c

search.obj : search.c
	cl -c $(CFLAGS) search.c

mark.obj : mark.c
	cl -c $(CFLAGS) mark.c

screen.obj : screen.c
	cl -c $(CFLAGS) screen.c

fileio.obj : fileio.c
	cl -c $(CFLAGS) fileio.c

param.obj : param.c
	cl -c $(CFLAGS) param.c

os2.obj : os2.c
	cl -c $(CFLAGS) os2.c

stevie.exe : $(OBJ)
	cl $(MODEL) *.obj $(LIBS) -o stevie.exe
	copy stevie.exe rstevie.exe
	bind rstevie.exe \lib\api.lib \lib\doscalls.lib
SHAR_EOF
cat << \SHAR_EOF > makefile.tos
#
# Makefile for the Atari ST - Megamax C compiler
#

CFLAGS = -DMEGAMAX

#	Megamax rule
.c.o:
	mmcc $(CFLAGS) $<
	mmimp $*.o
	mmlib rv vi.lib $*.o

MACH=	tos.o

OBJ=	main.o edit.o linefunc.o normal.o cmdline.o charset.o \
	updateRs.o misccmds.o help.o dec.o inc.o search.o alloc.o \
	mk.o regexp.o regsub.o version.o \
	updateNs.o mark.o screen.o fileio.o param.o $(MACH)

all : stevie.ttp

stevie.ttp : $(OBJ)
	$(LINKER) vi.lib $(LIBS) -o stevie.ttp

clean :
	$(RM) $(OBJ) vi.lib
SHAR_EOF
cat << \SHAR_EOF > makefile.usg
#
# Makefile for UNIX (System V)
#

CFLAGS = -O

MACH=	unix.o

OBJ=	main.o edit.o linefunc.o normal.o cmdline.o charset.o \
	updateRs.o misccmds.o help.o dec.o inc.o search.o alloc.o \
	mk.o regexp.o regsub.o version.o \
	updateNs.o mark.o screen.o fileio.o param.o $(MACH)

all : stevie

stevie : $(OBJ)
	$(CC) $(OBJ) $(LIBS) -o stevie

clean :
	rm $(OBJ)
SHAR_EOF
cat << \SHAR_EOF > mark.c
/*
 * STEVIE - Simply Try this Editor for VI Enthusiasts
 *
 * Code Contributions By : Tim Thompson           twitch!tjt
 *                         Tony Andrews           onecom!wldrdg!tony 
 *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
 */

#include "stevie.h"

#ifdef	MEGAMAX
overlay "mark"
#endif

/*
 * This file contains routines to maintain and manipulate marks. 
 */

#define	NMARKS	10		/* max. # of marks that can be saved */

struct mark {
    char            name;
    LPtr            pos;
};

static struct mark mlist[NMARKS];
static struct mark pcmark;	/* previous context mark */
static bool_t   pcvalid = FALSE;/* true if pcmark is valid */

/*
 * setmark(c) - set mark 'c' at current cursor position 
 *
 * Returns TRUE on success, FALSE if no room for mark or bad name given. 
 */
bool_t
setmark(c)
    char            c;
{
    int             i;

    if (!isalpha(c))
	return FALSE;

    /*
     * If there is already a mark of this name, then just use the existing
     * mark entry. 
     */
    for (i = 0; i < NMARKS; i++) {
	if (mlist[i].name == c) {
	    mlist[i].pos = *Curschar;
	    return TRUE;
	}
    }

    /*
     * There wasn't a mark of the given name, so find a free slot 
     */
    for (i = 0; i < NMARKS; i++) {
	if (mlist[i].name == NUL) {	/* got a free one */
	    mlist[i].name = c;
	    mlist[i].pos = *Curschar;
	    return TRUE;
	}
    }
    return FALSE;
}

/*
 * setpcmark() - set the previous context mark to the current position 
 */
void
setpcmark()
{
    pcmark.pos = *Curschar;
    pcvalid = TRUE;
}

/*
 * getmark(c) - find mark for char 'c' 
 *
 * Return pointer to LPtr or NULL if no such mark. 
 */
LPtr           *
getmark(c)
    char            c;
{
    int             i;

    if (c == '\'' || c == '`')	/* previous context mark */
	return pcvalid ? &(pcmark.pos) : (LPtr *) NULL;

    for (i = 0; i < NMARKS; i++) {
	if (mlist[i].name == c)
	    return &(mlist[i].pos);
    }
    return (LPtr *) NULL;
}

/*
 * clrall() - clear all marks 
 *
 * Used mainly when trashing the entire buffer during ":e" type commands 
 */
void
clrall()
{
    int             i;

    for (i = 0; i < NMARKS; i++)
	mlist[i].name = NUL;
    pcvalid = FALSE;
}

/*
 * clrmark(line) - clear any marks for 'line' 
 *
 * Used any time a line is deleted so we don't have marks pointing to
 * non-existent lines. 
 */
void
clrmark(line)
    LINE           *line;
{
    int             i;

    for (i = 0; i < NMARKS; i++) {
	if (mlist[i].pos.linep == line)
	    mlist[i].name = NUL;
    }
    if (pcvalid && (pcmark.pos.linep == line))
	pcvalid = FALSE;
}
SHAR_EOF
cat << \SHAR_EOF > mk.c
/*
 * STEVIE - Simply Try this Editor for VI Enthusiasts
 *
 * Code Contributions By : Tim Thompson           twitch!tjt
 *                         Tony Andrews           onecom!wldrdg!tony 
 *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
 */

#include "stevie.h"

char           *
mkline(n)
    int             n;
{
    static char     lbuf[9];
    int             i = 6;

    strcpy(lbuf, "        ");

    lbuf[i--] = (char) ((n % 10) + '0');
    n /= 10;
    if (n != 0) {
	lbuf[i--] = (char) ((n % 10) + '0');
	n /= 10;
    }
    if (n != 0) {
	lbuf[i--] = (char) ((n % 10) + '0');
	n /= 10;
    }
    if (n != 0) {
	lbuf[i--] = (char) ((n % 10) + '0');
	n /= 10;
    }
    if (n != 0) {
	lbuf[i--] = (char) ((n % 10) + '0');
	n /= 10;
    }
    return lbuf;
}

char           *
mkstr(c)
    char            c;
{
    static char     s[2];

    s[0] = c;
    s[1] = NUL;

    return s;
}
SHAR_EOF
cat << \SHAR_EOF > os2.h
/*
 * OS2 Machine-dependent routines. 
 */

int  inchar();
void outchar();
void outstr(), beep();
void windinit(), windexit(), windgoto();
void delay();
void sleep();
SHAR_EOF
cat << \SHAR_EOF > param.c
/*
 * STEVIE - Simply Try this Editor for VI Enthusiasts
 *
 * Code Contributions By : Tim Thompson           twitch!tjt
 *                         Tony Andrews           onecom!wldrdg!tony 
 *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
 */

/*
 * Code to handle user-settable parameters. This is all pretty much table-
 * driven. To add a new parameter, put it in the params array, and add a
 * macro for it in param.h. If it's a numeric parameter, add any necessary
 * bounds checks to doset(). String parameters aren't currently supported. 
 */

#include "stevie.h"

struct param    params[] = {

			    {"tabstop", "ts", 8, P_NUM},
			    {"scroll", "scroll", 12, P_NUM},
			    {"report", "report", 5, P_NUM},
			    {"lines", "lines", 25, P_NUM},

			    {"vbell", "vb", TRUE, P_BOOL},
			    {"showmatch", "sm", FALSE, P_BOOL},
			    {"wrapscan", "ws", TRUE, P_BOOL},
			    {"errorbells", "eb", FALSE, P_BOOL},
			    {"showmode", "mo", FALSE, P_BOOL},
			    {"backup", "bk", FALSE, P_BOOL},
			    {"return", "cr", TRUE, P_BOOL},
			    {"list", "list", FALSE, P_BOOL},
			    {"ignorecase", "ic", FALSE, P_BOOL},
			    {"autoindent", "ai", FALSE, P_BOOL},
			    {"number", "nu", FALSE, P_BOOL},
			    {"", "", 0, 0}	/* end marker */
};

static void     showparms();

void
doset(arg, inter)
    char           *arg;	/* parameter string */
    bool_t          inter;	/* TRUE if called interactively */
{
    int             i;
    char           *s;
    bool_t          did_lines = FALSE;

    bool_t          state = TRUE;	/* new state of boolean parms. */

    if (arg == NULL) {
	showparms(FALSE);
	return;
    }
    if (strncmp(arg, "all", 3) == 0) {
	showparms(TRUE);
	return;
    }
    if (strncmp(arg, "no", 2) == 0) {
	state = FALSE;
	arg += 2;
    }
    for (i = 0; params[i].fullname[0] != NUL; i++) {
	s = params[i].fullname;
	if (strncmp(arg, s, strlen(s)) == 0)	/* matched full name */
	    break;
	s = params[i].shortname;
	if (strncmp(arg, s, strlen(s)) == 0)	/* matched short name */
	    break;
    }

    if (params[i].fullname[0] != NUL) {	/* found a match */
	if (params[i].flags & P_NUM) {
	    did_lines = (i == P_LI);
	    if (inter && (arg[strlen(s)] != '=' || state == FALSE))
		emsg("Invalid set of numeric parameter");
	    else {
		params[i].value = atoi(arg + strlen(s) + 1);
		params[i].flags |= P_CHANGED;
	    }
	} else {		/* boolean */
	    if (inter && (arg[strlen(s)] == '='))
		emsg("Invalid set of boolean parameter");
	    else {
		params[i].value = state;
		params[i].flags |= P_CHANGED;
	    }
	}
    } else {
	if (inter)
	    emsg("Unrecognized 'set' option");
    }

    /*
     * Update the screen in case we changed something like "tabstop" or
     * "list" that will change its appearance. 
     */
    if (inter)
	updateNextscreen(NOT_VALID);

    if (did_lines) {
	Rows = P(P_LI);
	screenalloc();		/* allocate new screen buffers */
	screenclear();
	updateNextscreen(NOT_VALID);
    }
    /*
     * Check the bounds for numeric parameters here 
     */
    if (P(P_TS) <= 0 || P(P_TS) > 32) {
	if (inter)
	    emsg("Invalid tab size specified");
	P(P_TS) = 8;
	return;
    }
    if (P(P_SS) <= 0 || P(P_SS) > Rows) {
	if (inter)
	    emsg("Invalid scroll size specified");
	P(P_SS) = 12;
	return;
    }
    /*
     * Check for another argument, and call doset() recursively, if found. If
     * any argument results in an error, no further parameters are processed. 
     */
    while (*arg != ' ' && *arg != '\t') {	/* skip to next white space */
	if (*arg == NUL)
	    return;		/* end of parameter list */
	arg++;
    }
    while (*arg == ' ' || *arg == '\t')	/* skip to next non-white */
	arg++;

    if (*arg)
	doset(arg, TRUE);	/* recurse on next parameter, if present */
}

static void
showparms(all)
    bool_t          all;	/* show ALL parameters */
{
    struct param   *p;
    char            buf[64];

    gotocmdline(YES, NUL);
    outstr("Parameters:\r\n");

    for (p = &params[0]; p->fullname[0] != NUL; p++) {
	if (!all && ((p->flags & P_CHANGED) == 0))
	    continue;
	if (p->flags & P_BOOL)
	    sprintf(buf, "\t%s%s\r\n",
		    (p->value ? "" : "no"), p->fullname);
	else
	    sprintf(buf, "\t%s=%d\r\n", p->fullname, p->value);

	outstr(buf);
    }
    wait_return();
}
SHAR_EOF
cat << \SHAR_EOF > param.h
/*
 * STEVIE - Simply Try this Editor for VI Enthusiasts
 *
 * Code Contributions By : Tim Thompson           twitch!tjt
 *                         Tony Andrews           onecom!wldrdg!tony 
 *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
 */

/*
 * Settable parameters 
 */

struct param {
    char           *fullname;	/* full parameter name */
    char           *shortname;	/* permissible abbreviation */
    int             value;	/* parameter value */
    int             flags;
};

extern struct param params[];

/*
 * Flags 
 */
#define	P_BOOL		0x01	/* the parameter is boolean */
#define	P_NUM		0x02	/* the parameter is numeric */
#define	P_CHANGED	0x04	/* the parameter has been changed */

/*
 * The following are the indices in the params array for each parameter 
 */

/*
 * Numeric parameters 
 */
#define	P_TS		0	/* tab size */
#define	P_SS		1	/* scroll size */
#define	P_RP		2	/* report */
#define	P_LI		3	/* lines */

/*
 * Boolean parameters 
 */
#define	P_VB		4	/* visual bell */
#define	P_SM		5	/* showmatch */
#define	P_WS		6	/* wrap scan */
#define	P_EB		7	/* error bells */
#define	P_MO		8	/* show mode */
#define	P_BK		9	/* make backups when writing out files */
#define	P_CR		10	/* use cr-lf to terminate lines on writes */
#define	P_LS		11	/* show tabs and newlines graphically */
#define	P_IC		12	/* ignore case in searches */
#define	P_AI		13	/* auto-indent */
#define	P_NU		14	/* number lines on the screen */

/*
 * Macro to get the value of a parameter 
 */
#define	P(n)	(params[n].value)
SHAR_EOF
cat << \SHAR_EOF > porting.doc

		 Release Notes for STEVIE - Version 3.31B

			       Porting

		     Tony Andrews -  March 6, 1988
		    G. R. Walter -  January 6, 1988


	Porting the editor is a relatively simple task. Most of the
code is pretty machine-independent. For each environment, there is
a file of routines that perform various low-level operations that
tend to vary a lot from one machine to another. Another file contains
the escape sequences to be used for each machine.

	The machine-dependent files currently used are:

tos.c:	 Atari ST - ifdef for either Megamax or Alcyon
tos.h

unix.c:	 UNIX System V
unix.h

os2.c:	 Microsoft OS/2
os2.h

dos.c:   MS DOS
dos.h

amiga.c: Amiga
amiga.h

bsd.c:   BSD 4.3 UNIX
bsd.h

	Each of these files are around 150 lines long and deal with
low-level issues like character I/O to the terminal, terminal
initialization, cursor addressing, and so on. There are different
tradeoffs to be made depending on the environment. For example, the
UNIX version buffers terminal output because of the relatively high
overhead of system calls. A quick look at the files will make it clear
what needs to be done in a new environment.

	Terminal escape sequences are in the file "term.h". These are
defined statically, for the time being. There is some discussion in
term.h regarding which sequences are optional and which are not. The
editor is somewhat flexible in dealing with a lack of terminal
capabilities.

	The character set is in the file "charset.c".

	Because not all C compilers support command line macro definitions,
the #define's for system-specific macros are placed in the file "env.h".
If you port to a new system, add another line there to define the macro you
choose for your port.

	The basic process for doing a new port is:

	1. Come up with a macro name to use when ifdef'ing your system-
	   specific changes. Add a line to 'env.h' to define
	   the macro name you've chosen.

	2. Look at amiga.c, bsd.c, unix.c, tos.c, dos.c and os2.c and copy the
	   one that comes closest to working on your system. Then modify your
	   new file as needed.

	3. Look at term.h and edit the file appropriately adding a new
	   set of escape sequence definitions for your system.

	4. Compiling and debug the editor.
SHAR_EOF
cat << \SHAR_EOF > raw.c
/*
 * raw.c 
 *
 * This is a routine for setting a given stream to raw or cooked mode on the
 * Amiga . This is useful when you are using Lattice C to produce programs
 * that want to read single characters with the "getch()" or "fgetc" call. 
 *
 * Written : 18-Jun-87 By Chuck McManis.
 */

#include <proto/exec.h>
#include <proto/dos.h>
#include <stdio.h>
#include <ios1.h>
#include <error.h>

extern int      errno;		/* The error variable */

/*
 * Function raw() - Convert the specified file pointer to 'raw' mode. This
 * only works on TTY's and essentially keeps DOS from translating keys for
 * you, also (BIG WIN) it means getch() will return immediately rather than
 * wait for a return. You lose editing features though. 
 */
long
raw(fp)
    FILE           *fp;

{
    struct MsgPort *mp;		/* The File Handle message port */
    struct FileHandle *afh;
    struct UFB     *ufb;
    long            Arg[1], res;

    ufb = (struct UFB *) chkufb(fileno(fp));	/* Step one, get the file
						 * handle */
    afh = (struct FileHandle *) (ufb->ufbfh);

    if (!IsInteractive(afh)) {	/* Step two, check to see if it's a console */
	errno = ENOTTY;
	return (-1);
    }
    /* Step three, get it's message port. */
    mp = ((struct FileHandle *) (BADDR(afh)))->fh_Type;
    Arg[0] = -1L;
    res = SendPacket(mp, ACTION_SCREEN_MODE, Arg, 1);	/* Put it in RAW: mode */
    if (res == 0) {
	errno = ENXIO;
	return (-1);
    }
    return (0);
}

/*
 * Function - cooked() this function returns the designate file pointer to
 * it's normal, wait for a <CR> mode. This is exactly like raw() except that
 * it sends a 0 to the console to make it back into a CON: from a RAW: 
 */

long
cooked(fp)
    FILE           *fp;

{
    struct MsgPort *mp;		/* The File Handle message port */
    struct FileHandle *afh;
    struct UFB     *ufb;
    long            Arg[1], res;

    ufb = (struct UFB *) chkufb(fileno(fp));
    afh = (struct FileHandle *) (ufb->ufbfh);
    if (!IsInteractive(afh)) {
	errno = ENOTTY;
	return (-1);
    }
    mp = ((struct FileHandle *) (BADDR(afh)))->fh_Type;
    Arg[0] = 0;
    res = SendPacket(mp, ACTION_SCREEN_MODE, Arg, 1);
    if (res == 0) {
	errno = ENXIO;
	return (-1);
    }
    return (0);
}
SHAR_EOF
cat << \SHAR_EOF > regexp.h
/*
 * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
 *
 * This is NOT the original regular expression code as written by
 * Henry Spencer. This code has been modified specifically for use
 * with the STEVIE editor, and should not be used apart from compiling
 * STEVIE. If you want a good regular expression library, get the
 * original code. The copyright notice that follows is from the
 * original.
 *
 * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
 *
 * Definitions etc. for regexp(3) routines.
 *
 * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof],
 * not the System V one.
 */
#define NSUBEXP  10
typedef struct regexp {
    char           *startp[NSUBEXP];
    char           *endp[NSUBEXP];
    char            regstart;	/* Internal use only. */
    char            reganch;	/* Internal use only. */
    char           *regmust;	/* Internal use only. */
    int             regmlen;	/* Internal use only. */
    char            program[1];	/* Unwarranted chumminess with compiler. */
}               regexp;

extern regexp  *regcomp();
extern int      regexec();
extern void     regsub();
extern void     regerror();

#ifndef	ORIGINAL
extern int      reg_ic;		/* set non-zero to ignore case in searches */
#endif
SHAR_EOF
cat << \SHAR_EOF > regmagic.h
/*
 * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
 *
 * This is NOT the original regular expression code as written by
 * Henry Spencer. This code has been modified specifically for use
 * with the STEVIE editor, and should not be used apart from compiling
 * STEVIE. If you want a good regular expression library, get the
 * original code. The copyright notice that follows is from the
 * original.
 *
 * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
 *
 * The first byte of the regexp internal "program" is actually this magic
 * number; the start node begins in the second byte.
 */
#define	MAGIC	0234
SHAR_EOF
cat << \SHAR_EOF > regsub.c
/*
 * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
 *
 * This is NOT the original regular expression code as written by
 * Henry Spencer. This code has been modified specifically for use
 * with the STEVIE editor, and should not be used apart from compiling
 * STEVIE. If you want a good regular expression library, get the
 * original code. The copyright notice that follows is from the
 * original.
 *
 * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
 *
 * regsub
 *
 *	Copyright (c) 1986 by University of Toronto.
 *	Written by Henry Spencer.  Not derived from licensed software.
 *
 *	Permission is granted to anyone to use this software for any
 *	purpose on any computer system, and to redistribute it freely,
 *	subject to the following restrictions:
 *
 *	1. The author is not responsible for the consequences of use of
 *		this software, no matter how awful, even if they arise
 *		from defects in it.
 *
 *	2. The origin of this software must not be misrepresented, either
 *		by explicit claim or by omission.
 *
 *	3. Altered versions must be plainly marked as such, and must not
 *		be misrepresented as being the original software.
 *
 * $Log:	regsub.c,v $
 * Revision 1.2  88/04/28  08:11:25  tony
 * First modification of the regexp library. Added an external variable
 * 'reg_ic' which can be set to indicate that case should be ignored.
 * Added a new parameter to regexec() to indicate that the given string
 * comes from the beginning of a line and is thus eligible to match
 * 'beginning-of-line'.
 * 
 */

#include "env.h"

#ifdef	MEGAMAX
overlay "regexp"
#endif

#include <stdio.h>
#include "regexp.h"
#include "regmagic.h"

#ifndef CHARBITS
#define	UCHARAT(p)	((int)*(unsigned char *)(p))
#else
#define	UCHARAT(p)	((int)*(p)&CHARBITS)
#endif

/*
 - regsub - perform substitutions after a regexp match
 */
void
regsub(prog, source, dest)
    regexp         *prog;
    char           *source;
    char           *dest;
{
    register char  *src;
    register char  *dst;
    register char   c;
    register int    no;
    register int    len;
    extern char    *strncpy();

    if (prog == NULL || source == NULL || dest == NULL) {
	regerror("NULL parm to regsub");
	return;
    }
    if (UCHARAT(prog->program) != MAGIC) {
	regerror("damaged regexp fed to regsub");
	return;
    }
    src = source;
    dst = dest;
    while ((c = *src++) != '\0') {
	if (c == '&')
	    no = 0;
	else if (c == '\\' && '0' <= *src && *src <= '9')
	    no = *src++ - '0';
	else
	    no = -1;
	if (no < 0) {		/* Ordinary character. */
	    if (c == '\\' && (*src == '\\' || *src == '&'))
		c = *src++;
	    *dst++ = c;
	} else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
	    len = prog->endp[no] - prog->startp[no];
	    (void) strncpy(dst, prog->startp[no], len);
	    dst += len;
	    if (len != 0 && *(dst - 1) == '\0') {	/* strncpy hit NUL. */
		regerror("damaged match string");
		return;
	    }
	}
    }
    *dst++ = '\0';
}
SHAR_EOF
cat << \SHAR_EOF > sendpacket.c
/*
 * Sendpacket.c 
 *
 * An invaluable addition to your Amiga.lib file. This code sends a packet the
 * given message port. This makes working around DOS lots easier. 
 *
 * Note, I didn't write this, those wonderful folks at CBM did. I do suggest
 * however that you may wish to add it to Amiga.Lib, to do so, compile it and
 * say 'oml lib:amiga.lib -r sendpacket.o' 
 */

#include <proto/exec.h>
/* #include <exec/ports.h> */
#include <exec/memory.h>
#include <proto/dos.h>

/*
 * Function - SendPacket written by Phil Lindsay, Carolyn Scheppner, and Andy
 * Finkel. This function will send a packet of the given type to the Message
 * Port supplied. 
 */

long
SendPacket(pid, action, args, nargs)
    struct MsgPort *pid;	/* process indentifier ... (handlers message
				 * port ) */
    long            action,	/* packet type ... (what you want handler to
				 * do )   */
                    args[],	/* a pointer to a argument list */
                    nargs;	/* number of arguments in list  */
{
    struct MsgPort *replyport;
    struct StandardPacket *packet;

    long            count, *pargs, res1;

    replyport = (struct MsgPort *) CreatePort(NULL, 0);
    if (!replyport)
	return (0);

    /* Allocate space for a packet, make it public and clear it */
    packet = (struct StandardPacket *)
	AllocMem((long) sizeof(struct StandardPacket), MEMF_PUBLIC | MEMF_CLEAR);
    if (!packet) {
	DeletePort(replyport);
	return (0);
    }
    packet->sp_Msg.mn_Node.ln_Name = (char *) &(packet->sp_Pkt);
    packet->sp_Pkt.dp_Link = &(packet->sp_Msg);
    packet->sp_Pkt.dp_Port = replyport;
    packet->sp_Pkt.dp_Type = action;

    /* copy the args into the packet */
    pargs = &(packet->sp_Pkt.dp_Arg1);	/* address of first argument */
    for (count = 0; count < nargs; count++)
	pargs[count] = args[count];

    PutMsg(pid, packet);	/* send packet */

    WaitPort(replyport);
    GetMsg(replyport);

    res1 = packet->sp_Pkt.dp_Res1;

    FreeMem(packet, (long) sizeof(struct StandardPacket));
    DeletePort(replyport);

    return (res1);
}
SHAR_EOF
cat << \SHAR_EOF > source.doc

		 Release Notes for STEVIE - Version 3.10a

			      Source Notes

		      Tony Andrews - March 6, 1988

Overview
--------

	This file provides a brief description of the source code for
Stevie. The data structures are described later as well. For information
specific to porting the editor, see the file 'porting.doc'. This document
is more relevant to people who want to hack on the editor apart from doing
a simple port.

	Most of this document was written some time ago so a lot of the
discussion centers on problems related to the Atari ST environment and
compilers. Most of this can be ignored for other systems.

Things You Need - ATARI
-----------------------

	Stevie has been compiled with both the Alcyon (4.14A) and the
Megamax C compilers. For the posted binary, Megamax was used because
it's less buggy and provides a reasonable malloc(). Ports to other
compilers should be pretty simple. The current ifdef's for ALCYON and
MEGAMAX should point to the potential trouble areas. (See 'porting.doc'
for more information.)

	The search code depends on Henry Spencer's regular expression
code. I used a version I got from the net recently (as part of a 'grep'
posting) and had absolutely no trouble compiling it on the ST. Thanks,
Henry!

	The file 'getenv.c' contains a getenv routine that may or may
not be needed with your compiler. My version works with Alcyon and
Megamax, under either the Beckemeyer or Gulam shells.

	Lastly, you need a decent malloc. Lots of stuff in stevie is
allocated dynamically. The malloc with Alcyon is problematic because
it allocates from the heap between the end of data and the top of stack.
If you make the stack big enough to edit large files, you wind up
wasting space when working with small files. Mallocs that get their memory
from GEMDOS (in fairly large chunks) are much better.

Things You Need - AMIGA
-----------------------

	Lattice C version 5.0 or later.

Data Structures
---------------

	A brief discussion of the evolution of the data structures will
do much to clarify the code, and explain some of the strangeness you may
see.

	In the original version, the file was maintained in memory as a
simple contiguous buffer. References to positions in the file were simply
character pointers. Due to the obvious performance problems inherent in
this approach, the following changes were made.

	The file is now represented by a doubly linked list of 'line'
structures defined as follows:

struct	line {
	struct	line   *next;	/* next line */
	struct	line   *prev;	/* previous line */
	char	       *s;	/* text for this line */
	int	        size;	/* actual size of space at 's' */
	unsigned long   num;	/* line "number" */
};

The members of the line structure are described more completely here:

prev	- pointer to the structure for the prior line, or NULL for the
	  first line of the file

next	- like 'prev' but points to the next line

s	- points to the contents of the line (null terminated)

size	- contains the size of the chunk of space pointed to by s. This
	  is used so we know when we can add text to a line without getting
	  more space. When we DO need more space, we always get a little
	  extra so we don't make so many calls to malloc.

num	- This is a pseudo line number that makes it easy to compare
	  positions within the file. Otherwise, we'd have to traverse
	  all the links to tell which line came first.

	Since character pointers served to mark file positions in the
original, a similar data object was needed for the new data structures.
This purpose is served by the 'lptr' structure which is defined as:

struct	lptr {
	struct	line   *linep;	/* line we're referencing */
	int         	index;	/* position within that line */
};

The member 'linep' points to the 'line' structure for the line containing
the location of interest. The integer 'index' is the offset into the line
data (member 's') of the character to be referenced.

The following typedef's are more commonly used:

typedef	struct line	LINE;
typedef	struct lptr	LPtr;

Many operations that were trivial with character pointers had to be
implemented by functions or macros to manipulate LPtr's. Most of these are in
the files 'ptrfunc.c' and 'macros.h'. There you'll find functions to increment,
decrement, and compare LPtr's.
SHAR_EOF
cat << \SHAR_EOF > tos.h
/*
 * Atari Machine-dependent routines. 
 */

int  inchar();
void outchar();
void outstr(), beep();
void remove(), rename();
void windinit(), windexit(), windgoto();
void delay();
void sleep();
SHAR_EOF
cat << \SHAR_EOF > unix.c
/*
 * System-dependent routines for UNIX System V Release 3. 
 */

#include "stevie.h"
/* #include <termio.h> /* System V */
#include <curses.h>		/* BSD */

/*
 * inchar() - get a character from the keyboard 
 */
int
inchar()
{
    char            c;

    flushbuf();			/* flush any pending output */

    while (read(0, &c, 1) != 1);

    return (int) c;
}

#define	BSIZE	2048
static char     outbuf[BSIZE];
static int      bpos = 0;

flushbuf()
{
    if (bpos != 0)
	write(1, outbuf, bpos);
    bpos = 0;
}

/*
 * Macro to output a character. Used within this file for speed. 
 */
#define	outone(c)	outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf()

/*
 * Function version for use outside this file. 
 */
void
outchar(c)
    char            c;
{
    outbuf[bpos++] = c;
    if (bpos >= BSIZE)
	flushbuf();
}

void
outstr(s)
    char           *s;
{
    while (*s) {
	outone(*s++);
    }
}

void
beep()
{
    if (RedrawingDisabled)
	return;

    outone('\007');
}

/*
 * remove(file) - remove a file 
 */
void
remove(file)
    char           *file;
{
    unlink(file);
}

/*
 * rename(of, nf) - rename existing file 'of' to 'nf' 
 */
void
rename(of, nf)
    char           *of, *nf;
{
    unlink(nf);
    link(of, nf);
    unlink(of);
}

void
delay()
{
    /* not implemented */
}

static struct termio ostate;

void
windinit()
{
    char           *getenv();
    char           *term;
    struct termio   nstate;

    if ((term = getenv("TERM")) == NULL || strcmp(term, "vt100") != 0) {
	fprintf(stderr, "Invalid terminal type '%s'\n", term);
	exit(1);
    }
    Columns = 80;
    P(P_LI) = Rows = 24;

    /*
     * Go into cbreak mode 
     */
    ioctl(0, TCGETA, &ostate);
    nstate = ostate;
    nstate.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
    nstate.c_cc[VMIN] = 1;
    nstate.c_cc[VTIME] = 0;
    ioctl(0, TCSETAW, &nstate);
}

void
windexit(r)
    int             r;
{
    /*
     * Restore terminal modes 
     */
    ioctl(0, TCSETAW, &ostate);

    exit(r);
}

#define	outone(c)	outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf()

void
windgoto(r, c)
    int             r, c;
{
    r += 1;
    c += 1;

    /*
     * Check for overflow once, to save time. 
     */
    if (bpos + 8 >= BSIZE)
	flushbuf();

    outbuf[bpos++] = '\033';
    outbuf[bpos++] = '[';
    if (r >= 10)
	outbuf[bpos++] = r / 10 + '0';
    outbuf[bpos++] = r % 10 + '0';
    outbuf[bpos++] = ';';
    if (c >= 10)
	outbuf[bpos++] = c / 10 + '0';
    outbuf[bpos++] = c % 10 + '0';
    outbuf[bpos++] = 'H';
}

FILE           *
fopenb(fname, mode)
    char           *fname;
    char           *mode;
{
    return fopen(fname, mode);
}
SHAR_EOF
cat << \SHAR_EOF > unix.h
/*
 * Unix Machine-dependent routines. 
 */

int  inchar();
void outchar();
void outstr(), beep();
void remove(), rename();
void windinit(), windexit(), windgoto();
void delay();
SHAR_EOF
cat << \SHAR_EOF > updateNs.c
/*
 * STEVIE - Simply Try this Editor for VI Enthusiasts
 *
 * Code Contributions By : Tim Thompson           twitch!tjt
 *                         Tony Andrews           onecom!wldrdg!tony 
 *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
 */

#include "stevie.h"

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

void
updateNextscreen(type)
    int             type;
{
    register char  *ptr;
    register char   c;
    register int    row;
    register int    col;
    register char  *screenp;
    register char  *endscreen;
    register char  *nextrow;
    LPtr            start;
    LINE           *memp;
    LINE           *save;	/* save pos. in case line won't fit */
    char            extra[16];
    char           *p_extra;
    int             n_extra;
    bool_t          done;	/* if TRUE, we hit the end of the file */
    bool_t          didline;	/* if TRUE, we finished the last line */
    int             srow;	/* starting row of the current line */
    int             lno;	/* number of the line we're doing */
    int             coff;	/* column offset */
    int             idx;
    int             i;
    int             j;
    char            lines;

    if (NumLineSizes == 0)
	type = NOT_VALID;

    MustRedrawLine = FALSE;
    MustRedrawScreen = TRUE;

    idx = 0;
    row = 0;
    start.linep = Topchar->linep;
    screenp = Nextscreen;

    /* The number of rows shown is Rows-1. */
    /* The last line is the status/command line. */
    endscreen = Nextscreen + (Rows - 1) * Columns;

    if ((type == VALID) || (type == VALID_TO_CURSCHAR)) {
	j = -1;
	for (i = 0; i < NumLineSizes; i++) {
	    if (LinePointers[i] == Topchar->linep) {
		j = i;
		break;
	    }
	    row += LineSizes[i];
	}
	if (j == -1) {
	    /* Are we off the top of the screen by one line ? */
	    if (Topchar->linep->next == LinePointers[0]) {
		i = plines(Topchar);
		if (i < (Rows - 1)) {
		    screenp = endscreen - (i * Columns);
		
		    while (screenp > Nextscreen)
		        *(--endscreen) = *(--screenp);

		    endscreen = Nextscreen + (i * Columns);

		    for(idx = NumLineSizes;  idx > 0;  idx--) {
			LinePointers[idx] = LinePointers[idx - 1];
			LineSizes[idx] = LineSizes[idx - 1];
		    }
		    LineSizes[idx] = i;
		}
	    }
	    row = 0;
	} else if (j == 0 && type == VALID) {
	    return;
	} else {
	    nextrow = Nextscreen + row * Columns;
	    row = 0;
	    for (;;) {
		LineSizes[idx] = LineSizes[j];
		LinePointers[idx] = LinePointers[j];

		if (type == VALID_TO_CURSCHAR) {
		    if (LinePointers[idx]->next == Curschar->linep) {
			break;
		    }
		}
		j++;
		if (j >= NumLineSizes)
		    break;

		row += LineSizes[idx];
		idx++;
	    }
	    start.linep = LinePointers[idx];

	    endscreen = nextrow + row * Columns;
	    while (nextrow < endscreen)
		*screenp++ = *nextrow++;
    	    endscreen = Nextscreen + (Rows - 1) * Columns;
	}
    }

    srow = row;
    save = memp = start.linep;

    coff = P(P_NU) ? 8 : 0;

    if (P(P_NU))
	lno = cntllines(Filemem, &start);

    done = didline = FALSE;
    col = 0;
    lines = 1;

    LinePointers[idx] = memp;

    p_extra = NULL;
    n_extra = 0;
    if (P(P_NU)) {
	strcpy(extra, mkline(lno++));
	p_extra = extra;
	n_extra = 8;
    }
    ptr = memp->s;

    /*
     * We go one past the end of the screen so we can find out if the last
     * line fit on the screen or not. 
     */
    while (screenp <= endscreen) {

	/* 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. 
	 */

	if (n_extra > 0) {
	    c = *p_extra++;
	    n_extra--;
	} else {
	    c = *ptr++;
	    if (c < 32 || c > 127) {
	        if (c == NUL) {
		    srow = ++row;
		    /*
		     * Save this position in case the next line won't fit on the
		     * screen completely. 
		     */
		    save = memp;
		    if (memp->next != Fileend->linep) {
		        memp = memp->next;
		        ptr = memp->s;
		    } else {
		        done = TRUE;
		    }
		    if (P(P_LS)) {
		        *screenp++ = '$';
		        if (screenp > endscreen)
			    break;
		        col++;
		        if (col >= Columns) {
			    row++;
			    lines++;
		        }
		    }

		    LineSizes[idx++] = lines;
		    lines = 1;
		    LinePointers[idx] = memp;
		    if (P(P_NU)) {
		        strcpy(extra, mkline(lno++));
		        p_extra = extra;
		        n_extra = 8;
		    }
		    /* blank out the rest of this row */
		    nextrow = Nextscreen + (row * Columns);
		    while (screenp < nextrow)
		        *screenp++ = ' ';

		    if (done)
		        break;

		    if (screenp == endscreen) {
			didline = TRUE;
			break;
		    } else if (screenp > endscreen) {
			idx--;
			break;
		    }

		    col = 0;
		    continue;
	        } else if (c == TAB) {
	            if (!P(P_LS)) {
		        strcpy(extra, "               ");
		        p_extra = extra;
		        /* tab amount depends on current column */
		        n_extra = ((P(P_TS) - 1) - (col - coff) % P(P_TS));
		        c = ' ';
		    }
		} else if ((n_extra = chars[c].ch_size - 1) > 0) {
		    p_extra = chars[c].ch_str;
		    c = *p_extra++;
	        }
	    }
	}

	if (col >= Columns) {
	    lines++;
	    row++;
	    col = 0;
	}
	/* store the character in Nextscreen */
	*screenp++ = c;
	col++;
    }

    /* Do we have to do off the top of the screen processing ? */
    if (endscreen != (Nextscreen + (Rows - 1) * Columns)) {
        endscreen = Nextscreen + (Rows - 1) * Columns;

	row = 0;
	for(idx = 0; idx <= NumLineSizes && row < (Rows - 1);  idx++)
	    row += LineSizes[idx];

	if (row < (Rows - 1)) {
	    screenp = Nextscreen + (row * Columns);
	    done = TRUE;
	} else if (row > (Rows - 1)) {	/* Need to blank out the last line */
	    idx--;
	    save = LinePointers[idx];
	    srow = row - LineSizes[idx];
	    didline = FALSE;
	} else {
	    memp = LinePointers[idx];
	    screenp = Nextscreen + (row * Columns);
	    didline = TRUE;
	}
    }

    /*
     * If we didn't hit the end of the file, and we didn't finish the last
     * line we were working on, then the line didn't fit. 
     */
    if (!done && !didline) {
	/*
	 * Clear the rest of the screen and mark the unused lines. 
	 */
	screenp = Nextscreen + (srow * Columns);
	while (screenp < endscreen)
	    *screenp++ = ' ';

	for (; srow < (Rows - 1); srow++)
	    Nextscreen[srow * Columns] = '@';

	Botchar->linep = save;
    } else {
	/* 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++;
	}

	if (done)		/* we hit the end of the file */
	    *Botchar = *Fileend;
	else
	    Botchar->linep = memp;	/* FIX - prev? */
    }

    NumLineSizes = idx;
}
SHAR_EOF
cat << \SHAR_EOF > updateRs.c
/*
 * STEVIE - Simply Try this Editor for VI Enthusiasts
 *
 * Code Contributions By : Tim Thompson           twitch!tjt
 *                         Tony Andrews           onecom!wldrdg!tony 
 *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
 */

#include "stevie.h"

/*
 * updateRealscreen 
 *
 * Transfer the contents of Nextscreen to the screen, using Realscreen to avoid
 * unnecessary output. 
 */
void
updateRealscreen()
{
    register char  *np = Nextscreen;
    register char  *rp = Realscreen;
    register char  *endscreen;
    register int    row = 0, col = 0;
    int             gorow = -1, gocol = -1;

    if (RedrawingDisabled)
	return;

    if (!MustRedrawScreen && !MustRedrawLine)
	return;

    if (MustRedrawLine) {
	msg("internal error: updateRealscreen called when MustRedrawLine set");
	sleep(5);
    }
    endscreen = &np[(Rows - 1) * Columns];

    outstr(T_CI);		/* disable cursor */

    for (; np < endscreen; np++, rp++) {
	/* If desired screen (contents of Nextscreen) does not */
	/* match what's really there, put it there. */
	if (*np != *rp) {
	    /* if we are positioned at the right place, */
	    /* we don't have to use windgoto(). */
	    if (gocol != col || gorow != row) {
		/*
		 * If we're just off by one, don't send an entire esc. seq.
		 * (this happens a lot!) 
		 */
		if (gorow == row && gocol + 1 == col) {
		    outchar(*(np - 1));
		    gocol++;
		} else
		    windgoto(gorow = row, gocol = col);
	    }
	    outchar(*rp = *np);
	    gocol++;
	}
	if (++col >= Columns) {
	    col = 0;
	    row++;
	}
    }

    outstr(T_CV);		/* enable cursor again */

    MustRedrawLine = FALSE;
    MustRedrawScreen = FALSE;
}
SHAR_EOF
#	End of shell archive
exit 0
-- 
Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
Have five nice days.