Vile 01/17 - vi feel-alike (multi-window)

Paul Fox pgf at cayman.COM
Sat Jun 8 08:09:05 AEST 1991


#!/bin/sh
# This is Vile, a shell archive (shar 3.47)
# made 06/07/1991 22:01 UTC by pgf at cayman.com
# Source directory /tmp_mnt/home/carl/pgf/vile
#
# existing files WILL be overwritten
#
# This is part 1 of a multipart archive                                    
# do not concatenate these parts, unpack them in order with /bin/sh        
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   3835 -r--r--r-- README
#   6488 -r--r--r-- ansi.c
#   4175 -r--r--r-- at386.c
#  20335 -r--r--r-- basic.c
#  21479 -r--r--r-- bind.c
#  20200 -r--r--r-- buffer.c
#   6009 -r--r--r-- buglist
#  17753 -r--r--r-- cmdtbl
#   6989 -r--r--r-- crypt.c
#   2171 -r--r--r-- csrch.c
#   3333 -r--r--r-- dg10.c
#  40087 -r--r--r-- display.c
#   4340 -r--r--r-- dolock.c
#  14722 -r--r--r-- ebind.h
#   9852 -r--r--r-- edef.h
#  27465 -r--r--r-- efunc.h
#    956 -r--r--r-- epath.h
#  30449 -r--r--r-- estruct.h
#  18430 -r--r--r-- eval.c
#   5247 -r--r--r-- evar.h
#  32572 -r--r--r-- exec.c
#  28527 -r--r--r-- file.c
#   7384 -r--r--r-- fileio.c
#   3373 -r--r--r-- finderr.c
#   2834 -r--r--r-- globals.c
#   3750 -r--r--r-- hp110.c
#   9245 -r--r--r-- hp150.c
#  10074 -r--r--r-- ibmpc.c
#  10225 -r--r--r-- input.c
#  18075 -r--r--r-- isearch.c
#  20714 -r--r--r-- line.c
#   3557 -r--r--r-- lock.c
#  23507 -r--r--r-- main.c
#   1438 -r--r--r-- make.ini
#   9302 -r--r--r-- makefile
#   7809 -r--r--r-- mktbls.c
#   5332 -rw-rw-r-- nebind.h
#  19211 -rw-rw-r-- nefunc.h
#  17247 -rw-rw-r-- nename.h
#   5376 -r--r--r-- news.c
#  19928 -r--r--r-- news.cps
#   2848 -r--r--r-- npopen.c
#   4253 -r--r--r-- oneliner.c
#   4699 -r--r--r-- opers.c
#  34147 -r--r--r-- random.c
#   7014 -r--r--r-- readme.news
#   9127 -r--r--r-- region.c
#  35047 -r--r--r-- search.c
#   7910 -r--r--r-- shorten/COPYING
#    178 -r--r--r-- shorten/defines.c
#    857 -r--r--r-- shorten/dups.c
#    674 -r--r--r-- shorten/header.h
#   1637 -r--r--r-- shorten/names.c
#    220 -r--r--r-- shorten/reserved
#      0 -r--r--r-- shorten/special
#  20300 -r--r--r-- spawn.c
#  19931 -r--r--r-- st520.c
#  57909 -r--r--r-- tags
#   7806 -r--r--r-- tags.c
#   6065 -r--r--r-- tcap.c
#  16097 -r--r--r-- termio.c
#   5308 -r--r--r-- tipc.c
#  11158 -r--r--r-- undo.c
#  24385 -r--r--r-- vile.hlp
#   6798 -r--r--r-- vmalloc.c
#   9271 -r--r--r-- vmsvt.c
#   3386 -r--r--r-- vt52.c
#  20419 -r--r--r-- window.c
#  10449 -r--r--r-- word.c
#   6094 -r--r--r-- wordmov.c
#    652 -r--r--r-- z100bios.asm
#   7806 -r--r--r-- z309.c
#
if test -r _shar_seq_.tmp; then
	echo 'Must unpack archives in sequence!'
	echo Please unpack part `cat _shar_seq_.tmp` next
	exit 1
fi
# ============= README ==============
echo 'x - extracting README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'README' &&
X
X
X
VILE -- VI Like Emacs: a vi workalike put together from Micro-Emacs by Paul Fox
-------------------------------------------------------------------------------
X
X	This editor grew out of a frustration that although lots of
X	eager programmers have tackled rewrites of Emacs, with new and
X	better features (not to mention free source), I've not seen
X	anything similar done with the Second True Editor.  (The
X	First, of course, being /bin/ed)
X
X	So I took a copy of MicroEmacs 3.9 (which I've since
X	discovered was out of date, unfortunately) and bashed and
X	badgered it into a vi "feel-alike".  It retains the multiple
X	buffer/multiple window features of uemacs, but the
X	"finger-feel", if you will, is very much that of vi.  It is
X	definitely not a clone, in that some substantial stuff is
X	missing, and the screen doesn't look quite the same.  But what
X	matters most is that one's "muscle memory" does the right thing
X	to the text in front of you, and that is what vile tries to do
X	for vi users.   THIS IS NOT A "CLONE"!
X
X	This is the first really public version of vile.  It is
X	version three.  Users of previous versions will hopefully find
X	the additions of ":" command line ranges and the ! filter
X	operator helpful. 
X
X	The collective developers of Micro-Emacs should be
X	complimented that the changes were as easy as they were.  The
X	code was pretty clean and well designed before I started on
X	it.  I'm not sure that the same can be said anymore... 
X
X	The benefits over standard vi include:
X		- multiple files open at once
X		- multiple windows on the screen
X		- a larger set of operator commands
X		- the possibility of porting to your favorite micro.
X			(mind you, I haven't even tried this on a small
X				UNIX machine, let alone DOS etc...)
X		- more uniform undo/yank register treatment
X		- using tags doesn't lose your last search pattern
X		- "next error" cursor positioning after compilation
X	Of course, it _may_ lack some of vi's reliability. :-)
X
X	( Although I can't imagine the emacs folks wanting to buy much
X	of this stuff back (insert mode, anyone? :-), they might
X	want to look at:
X		- full global undo
X		- tags support
X		- better (maybe?) UNIX terminal handling
X		- better UNIX shell escapes
X		- terminal scroll support
X		- multiple yank registers (formerly called kill buffers)
X		- multiple marks  (actually kind of messy)
X		- improved aesthetics of window splitting and deleting
X		- "next error" cursor positioning
X		- list mode )
X
X	Take a look at vile.hlp for more information about features
X	and differences. 
X
X	In general, I suspect that the quality of the code is roughly
X	on a par with MicroEmacs.  I've been using vile regularly under
X	both SunOS and 386 UNIX for about a year, with no major problems
X	(that havn't been fixed).  Another dedicated user has been
X	running it on various flavors of 386 UNIX (Bell, Open DeskTop,
X	Xenix) and Ultrix, also with no problems.
X
X	I have not tried this on a small system, or even _any_
X	non-UNIX system.  I'm sure work will be required to make
X	it work on DOS again, for instance -- especially for spawning
X	sub-shells, etc. 
X
X	I ifdef'ed out the language features (user-defined procs,
X	etc.) a long time ago -- I don't know if they still work,
X	though I didn't actively try to break them. 
X
X	If anyone is interested in doing major work on this thing, let me
X	know -- I have some ideas on how to make a full ex mode work, for 
X	instance, and on how to add the ":map" command.  Also, take a look 
X	at the buglist...
X
X	Hope you enjoy -- 
X
X	Paul G. Fox	June 3, 1991
X	pgf at cayman.com
X
p.s.  The code distributed with vile in the "shortnames" subdirectory
X	is covered by GNU Public License.  The vile code itself in the
X	upper level directory is _not_ covered by the GNU public license. 
X
p.p.s By the way, I'm _not_ the same Paul Fox who wrote Crisp, the Brief
X	work-alike.
SHAR_EOF
chmod 0444 README ||
echo 'restore of README failed'
Wc_c="`wc -c < 'README'`"
test 3835 -eq "$Wc_c" ||
	echo 'README: original size 3835, current size' "$Wc_c"
# ============= ansi.c ==============
echo 'x - extracting ansi.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'ansi.c' &&
/*
X * The routines in this file provide support for ANSI style terminals
X * over a serial line. The serial I/O services are provided by routines in
X * "termio.c". It compiles into nothing if not an ANSI device.
X */
X
#define	termdef	1			/* don't define "term" external */
X
#include        <stdio.h>
#include	"estruct.h"
#include        "edef.h"
X
#if     ANSI
X
#if	AMIGA
#define NROW    23                      /* Screen size.                 */
#define NCOL    77                      /* Edit if you want to.         */
#else
#define NROW    24                      /* Screen size.                 */
#define NCOL    80                      /* Edit if you want to.         */
#endif
#define	NPAUSE	100			/* # times thru update to pause */
#define	MARGIN	8			/* size of minimim margin and	*/
#define	SCRSIZ	64			/* scroll size for extended lines */
#define BEL     0x07                    /* BEL character.               */
#define ESC     0x1B                    /* ESC character.               */
X
extern  int     ttopen();               /* Forward references.          */
extern  int     ttgetc();
extern  int     ttputc();
extern  int     ttflush();
extern  int     ttclose();
extern  int     ansimove();
extern  int     ansieeol();
extern  int     ansieeop();
extern  int     ansibeep();
extern  int     ansiopen();
extern	int	ansirev();
extern	int	ansiclose();
extern	int	ansikopen();
extern	int	ansikclose();
extern	int	ansicres();
#if SCROLLCODE
extern	int	ansiscroll();
#endif
X
#if	COLOR
extern	int	ansifcol();
extern	int	ansibcol();
X
int	cfcolor = -1;		/* current forground color */
int	cbcolor = -1;		/* current background color */
X
#if	AMIGA
/* apperently the AMIGA does not follow the ANSI standards as
X   regards to colors....maybe because of the default pallette
X   settings?
*/
X
int coltran[8] = {2, 3, 5, 7, 0, 4, 6, 1};	/* color translation table */
#endif
#endif
X
/*
X * Standard terminal interface dispatch table. Most of the fields point into
X * "termio" code.
X */
TERM    term    = {
X	NROW-1,
X        NROW-1,
X        NCOL,
X        NCOL,
X	MARGIN,
X	SCRSIZ,
X	NPAUSE,
X        ansiopen,
X        ansiclose,
X	ansikopen,
X	ansikclose,
X        ttgetc,
X        ttputc,
X        ttflush,
X        ansimove,
X        ansieeol,
X        ansieeop,
X        ansibeep,
X	ansirev,
X	ansicres
#if	COLOR
X	, ansifcol,
X	ansibcol
#endif
#if SCROLLCODE
X	, ansiscroll
#endif
};
X
csi()
{
X	ttputc(ESC);
X	ttputc('[');
}
X
#if	COLOR
ansifcol(color)		/* set the current output color */
X
int color;	/* color to set */
X
{
X	if (color == cfcolor)
X		return;
X	csi();
#if	AMIGA
X	ansiparm(coltran[color]+30);
#else
X	ansiparm(color+30);
#endif
X	ttputc('m');
X	cfcolor = color;
}
X
ansibcol(color)		/* set the current background color */
X
int color;	/* color to set */
X
{
X	if (color == cbcolor)
X		return;
X	csi();
#if	AMIGA
X	ansiparm(coltran[color]+40);
#else
X	ansiparm(color+40);
#endif
X	ttputc('m');
X        cbcolor = color;
}
#endif
X
ansimove(row, col)
{
X	csi();
X        if (row) ansiparm(row+1);
X        ttputc(';');
X        if (col) ansiparm(col+1);
X        ttputc('H');
}
X
ansieeol()
{
X	csi();
X        ttputc('K');
}
X
ansieeop()
{
#if	COLOR
X	ansifcol(gfcolor);
X	ansibcol(gbcolor);
#endif
X	csi();
X        ttputc('J');
}
X
X
ansirev(state)		/* change reverse video state */
X
int state;	/* TRUE = reverse, FALSE = normal */
X
{
#if	COLOR
X	int ftmp, btmp;		/* temporaries for colors */
#else
X	static int revstate = -1;
X	if (state == revstate)
X		return;
X	revstate = state;
#endif
X
X	csi();
X	if (state) ttputc('7');
X	ttputc('m');
#if	COLOR
X	if (state == FALSE) {
X		ftmp = cfcolor;
X		btmp = cbcolor;
X		cfcolor = -1;
X		cbcolor = -1;
X		ansifcol(ftmp);
X		ansibcol(btmp);
X	}
#endif
}
X
ansicres()	/* change screen resolution */
{
X	return(TRUE);
}
X
spal(dummy)		/* change pallette settings */
{
X	/* none for now */
}
X
ansibeep()
{
X        ttputc(BEL);
X        ttflush();
}
X
#if SCROLLCODE
X
/* if your ansi terminal can scroll regions, like the vt100, then define
X	SCROLL_REG.  If not, you can use delete/insert line code, which
X	is prettier but slower if you do it a line at a time instead of
X	all at once.
*/
X
#define SCROLL_REG 1
X
/* move howmany lines starting at from to to */
ansiscroll(from,to,howmany)
{
X	int i;
X	if (to == from) return;
#if SCROLL_REG
X	if (to < from) {
X		ansiscrollregion(to, from + howmany - 1);
X		ansimove(from + howmany - 1,0);
X		for (i = from - to; i > 0; i--)
X			ttputc('\n');
X	} else { /* from < to */
X		ansiscrollregion(from, to + howmany - 1);
X		ansimove(from);
X		for (i = to - from; i > 0; i--) {
X			ttputc(ESC);
X			ttputc('M');
X		}
X	}
X	ansiscrollregion(0, term.t_mrow);
X		
#else /* use insert and delete line */
#if PRETTIER_SCROLL
X	if (abs(from-to) > 1) {
X		ansiscroll(from, (from<to) ? to-1:to+1, howmany);
X		if (from < to)
X			from = to-1;
X		else
X			from = to+1;	
X	}
#endif
X	if (to < from) {
X		ansimove(to,0);
X		csi();
X		if (from - to > 1) ansiparm(from - to);
X		ttputc('M'); /* delete */
X		ansimove(to+howmany,0);
X		csi();
X		if (from - to > 1) ansiparm(from - to);
X		ttputc('L'); /* insert */
X	} else {
X		ansimove(from+howmany,0);
X		csi();
X		if (to - from > 1) ansiparm(to - from);
X		ttputc('M'); /* delete */
X		ansimove(from,0);
X		csi();
X		if (to - from > 1) ansiparm(to - from);
X		ttputc('L'); /* insert */
X	}
#endif
}
X
#if SCROLL_REG
ansiscrollregion(top,bot)
{
X	csi();
X	if (top) ansiparm(top + 1);
X	ttputc(';');
X	if (bot != term.t_nrow) ansiparm(bot + 1);
X	ttputc('r');
}
#endif
X
#endif
X
ansiparm(n)
register int    n;
{
X        register int q,r;
X
X        q = n/10;
X        if (q != 0) {
X		r = q/10;
X		if (r != 0) {
X			ttputc((r%10)+'0');
X		}
X		ttputc((q%10) + '0');
X        }
X        ttputc((n%10) + '0');
}
X
ansiopen()
{
#if     V7 | USG | BSD
#if 0
X        register char *cp;
X        char *getenv();
X
X        if ((cp = getenv("TERM")) == NULL) {
X                puts("Shell variable TERM not defined!");
X                exit(1);
X        }
X        if (strcmp(cp, "vt100") != 0 && strcmp(cp, "ansi") != 0) {
X                puts("Terminal type not 'vt100' or 'ansi'!");
X                exit(1);
X        }
#endif
#endif
X	strcpy(sres, "NORMAL");
X	revexist = TRUE;
X        ttopen();
}
X
ansiclose()
{
#if	COLOR
X	ansifcol(7);
X	ansibcol(0);
#endif
X	ttclose();
}
X
ansikopen()	/* open the keyboard (a noop here) */
{
}
X
ansikclose()	/* close the keyboard (a noop here) */
{
}
X
#if	FLABEL
fnclabel(f, n)		/* label a function key */
int f,n;	/* default flag, numeric argument [unused] */
{
X	/* on machines with no function keys...don't bother */
X	return(TRUE);
}
#endif
#else
ansihello()
{
}
#endif
SHAR_EOF
chmod 0444 ansi.c ||
echo 'restore of ansi.c failed'
Wc_c="`wc -c < 'ansi.c'`"
test 6488 -eq "$Wc_c" ||
	echo 'ansi.c: original size 6488, current size' "$Wc_c"
# ============= at386.c ==============
echo 'x - extracting at386.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'at386.c' &&
/*	AT386:   hacked tcap.c for the 386 console, when you don't
X		have libtermcap.   grrr.
*/
X
#define	termdef	1			/* don't define "term" external */
X
#include <stdio.h>
#include	"estruct.h"
#include        "edef.h"
X
#if AT386
X
#define NROW    25                      /* Screen size.                 */
#define NCOL    80                      /* Edit if you want to.         */
#define	MARGIN	8
#define	SCRSIZ	64
#define	NPAUSE	10			/* # times thru update to pause */
#define BEL     0x07
#define ESC     0x1B
X
extern int      ttopen();
extern int      ttgetc();
extern int      ttputc();
extern int	tgetnum();
extern int      ttflush();
extern int      ttclose();
extern int	at386kopen();
extern int	at386kclose();
extern int      at386move();
extern int      at386eeol();
extern int      at386eeop();
extern int      at386beep();
extern int	at386rev();
extern int	at386cres();
extern int      at386open();
extern int      tput();
extern char     *tgoto();
#if	COLOR
extern	int	at386fcol();
extern	int	at386bcol();
#endif
#if	SCROLLCODE
extern	int	at386scroll_delins();
#endif
X
#define TCAPSLEN 315
char at386buf[TCAPSLEN];
char *UP, PC, *CM, *CE, *CL, *SO, *SE;
X
#if	SCROLLCODE
char *DL, *AL, *SF, *SR;
#endif
X
TERM term = {
X	NROW-1,
X	NROW-1,
X	NCOL,
X	NCOL,
X	MARGIN,
X	SCRSIZ,
X	NPAUSE,
X        at386open,
X        ttclose,
X        at386kopen,
X        at386kclose,
X        ttgetc,
X        ttputc,
X        ttflush,
X        at386move,
X        at386eeol,
X        at386eeop,
X        at386beep,
X        at386rev,
X        at386cres
#if	COLOR
X	, at386fcol,
X	at386bcol
#endif
#if	SCROLLCODE
X	, NULL		/* set dynamically at open time */
#endif
};
X
at386open()
{
X        char *getenv();
X        char *t, *p, *tgetstr();
X        char tcbuf[1024];
X        char *tv_stype;
X        char err_str[72];
X
X        CL = "\033[2J\033[H";
X        CE = "\033[K";
X        UP = "\033[A";
X	SE = "\033[m";
X	SO = "\033[7m";
X	revexist = TRUE;
X
X
#if SCROLLCODE
X	DL = "\033[1M";
X	AL = "\033[1L";
X	term.t_scroll = at386scroll_delins;
#endif
X        ttopen();
}
X
at386kopen()
{
X	strcpy(sres, "NORMAL");
}
X
at386kclose()
{
}
X
csi()
{
X	ttputc(ESC);
X	ttputc('[');
}
X
ansiparm(n)
register int    n;
{
X        register int q,r;
X
X        q = n/10;
X        if (q != 0) {
X		r = q/10;
X		if (r != 0) {
X			ttputc((r%10)+'0');
X		}
X		ttputc((q%10) + '0');
X        }
X        ttputc((n%10) + '0');
}
X
at386move(row, col)
register int row, col;
{
X	csi();
X        if (row) ansiparm(row+1);
X        ttputc(';');
X        if (col) ansiparm(col+1);
X        ttputc('H');
}
X
at386eeol()
{
X        fputs(CE,stdout);
}
X
at386eeop()
{
X        fputs(CL,stdout);
}
X
at386rev(state)		/* change reverse video status */
int state;		/* FALSE = normal video, TRUE = reverse video */
{
X	static int revstate = -1;
X	if (state == revstate)
X		return;
X	revstate = state;
X	if (state) {
X		if (SO != NULL)
X			fputs(SO,stdout);
X	} else {
X		if (SE != NULL)
X			fputs(SE,stdout);
X	}
}
X
at386cres()	/* change screen resolution */
{
X	return(TRUE);
}
X
#if SCROLLCODE
X
/* 
PRETTIER_SCROLL is prettier but slower -- it scrolls 
X		a line at a time instead of all at once.
*/
X
/* move howmany lines starting at from to to */
at386scroll_delins(from,to,howmany)
{
X	int i;
X	if (to == from) return;
#if PRETTIER_SCROLL
X	if (abs(from-to) > 1) {
X		at386scroll_delins(from, (from<to) ? to-1:to+1, howmany);
X		if (from < to)
X			from = to-1;
X		else
X			from = to+1;	
X	}
#endif
X	if (to < from) {
X		at386move(to,0);
X		for (i = from - to; i > 0; i--)
X			fputs(DL,stdout);
X		at386move(to+howmany,0);
X		for (i = from - to; i > 0; i--)
X			fputs(AL,stdout);
X	} else {
X		at386move(from+howmany,0);
X		for (i = to - from; i > 0; i--)
X			fputs(DL,stdout);
X		at386move(from,0);
X		for (i = to - from; i > 0; i--)
X			fputs(AL,stdout);
X	}
}
X
#endif
X
spal(dummy)	/* change palette string */
{
X	/*	Does nothing here	*/
}
X
X
#if	COLOR
at386fcol()	/* no colors here, ignore this */
{
}
X
at386bcol()	/* no colors here, ignore this */
{
}
#endif
X
at386beep()
{
X	ttputc(BEL);
}
X
X
#if	FLABEL
fnclabel(f, n)		/* label a function key */
int f,n;	/* default flag, numeric argument [unused] */
{
X	/* on machines with no function keys...don't bother */
X	return(TRUE);
}
#endif
#else
X
hello()
{
}
X
#endif
SHAR_EOF
chmod 0444 at386.c ||
echo 'restore of at386.c failed'
Wc_c="`wc -c < 'at386.c'`"
test 4175 -eq "$Wc_c" ||
	echo 'at386.c: original size 4175, current size' "$Wc_c"
# ============= basic.c ==============
echo 'x - extracting basic.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'basic.c' &&
/*
X * The routines in this file move the cursor around on the screen. They
X * compute a new value for the cursor, then adjust ".". The display code
X * always updates the cursor location, so only moves between lines, or
X * functions that adjust the top line in the window and invalidate the
X * framing, are hard.
X */
#include        <stdio.h>
#include	"estruct.h"
#include        "edef.h"
X
/*
X * Move the cursor to the
X * beginning of the current line.
X * Trivial.
X */
gotobol(f, n)
{
X        curwp->w_doto  = 0;
X        return (TRUE);
}
X
/*
X * Move the cursor backwards by "n" characters. If "n" is less than zero call
X * "forwchar" to actually do the move. Otherwise compute the new cursor
X * location. Error if you try and move out of the buffer. Set the flag if the
X * line pointer for dot changes.
X */
backchar(f, n)
register int    n;
{
X        register LINE   *lp;
X
X	if (f == FALSE) n = 1;
X        if (n < 0)
X                return (forwchar(f, -n));
X        while (n--) {
X                if (curwp->w_doto == 0) {
X                        if ((lp=lback(curwp->w_dotp)) == curbp->b_linep)
X                                return (FALSE);
X                        curwp->w_dotp  = lp;
X                        curwp->w_doto  = llength(lp);
X                        curwp->w_flag |= WFMOVE;
X                } else
X                        curwp->w_doto--;
X        }
X        return (TRUE);
}
X
/*
X * Move the cursor to the end of the current line. Trivial. No errors.
X */
gotoeol(f, n)
{
X	if (f == TRUE) {
X		if (n > 0)
X			 --n;
X		else if (n < 0)
X			 ++n;
X		forwline(f,n);
X	}
X        curwp->w_doto  = llength(curwp->w_dotp);
X	curgoal = HUGE;
X        return (TRUE);
}
X
/*
X * Move the cursor forwards by "n" characters. If "n" is less than zero call
X * "backchar" to actually do the move. Otherwise compute the new cursor
X * location, and move ".". Error if you try and move off the end of the
X * buffer. Set the flag if the line pointer for dot changes.
X */
forwchar(f, n)
register int    n;
{
X	if (f == FALSE) n = 1;
X        if (n < 0)
X                return (backchar(f, -n));
X        while (n--) {
X                if (curwp->w_doto == llength(curwp->w_dotp)) {
X                        if (curwp->w_dotp == curbp->b_linep ||
X					lforw(curwp->w_dotp) == curbp->b_linep)
X                                return (FALSE);
X                        curwp->w_dotp  = lforw(curwp->w_dotp);
X                        curwp->w_doto  = 0;
X                        curwp->w_flag |= WFMOVE;
X                } else
X                        curwp->w_doto++;
X        }
X        return (TRUE);
}
X
gotoline(f, n)		/* move to a particular line.
X			   argument (n) must be a positive integer for
X			   this to actually do anything		*/
{
X	register int status;	/* status return */
X
X	/* get an argument if one doesnt exist */
X	if (f == FALSE) {
X		return(gotoeob(f,n));
X	}
X
X	if (n < 1)		/* if a bogus argument...then leave */
X		return(FALSE);
X
X	/* first, we go to the start of the buffer */
X        curwp->w_dotp  = lforw(curbp->b_linep);
X        curwp->w_doto  = 0;
X	status = forwline(f, n-1);
X	if (status == TRUE)
X		firstnonwhite(f,n);
X	return(status);
}
X
/*
X * Goto the beginning of the buffer. Massive adjustment of dot. This is
X * considered to be hard motion; it really isn't if the original value of dot
X * is the same as the new value of dot.
X */
gotobob(f, n)
{
X        curwp->w_dotp  = lforw(curbp->b_linep);
X        curwp->w_doto  = 0;
X        curwp->w_flag |= WFMOVE;
X        return (TRUE);
}
X
/*
X * Move to the end of the buffer. Dot is always put at the end of the file
X * (ZJ). The standard screen code does most of the hard parts of update.
X */
gotoeob(f, n)
{
X        curwp->w_dotp  = lback(curbp->b_linep);
X	firstnonwhite(FALSE,1);
X        curwp->w_flag |= WFMOVE;
X        return (TRUE);
}
X
gotobos(f,n)
{
X	int s = TRUE;
X	if (f == FALSE || n <= 0) n = 1;
X	curwp->w_dotp = curwp->w_linep;
X	while (--n) {
X		if ((s = forwline(FALSE,1)) != TRUE)
X			break;
X	}
X	firstnonwhite(f,n);
X	return (s);
}
X
gotomos(f,n)
{
X	return gotobos(TRUE,curwp->w_ntrows/2);
}
X
gotoeos(f,n)
{
X	return gotobos(TRUE,curwp->w_ntrows-(f==TRUE? n-1:0));
}
X
/*
X * Move forward by full lines. If the number of lines to move is less than
X * zero, call the backward line function to actually do it. The last command
X * controls how the goal column is set. No errors are
X * possible.
X */
forwline(f, n)
{
X        register LINE   *dlp;
X
X	if (f == FALSE) n = 1;
X        if (n < 0)
X                return (backline(f, -n));
X
X	/* if we are on the last line as we start....fail the command */
X	if (curwp->w_dotp == curbp->b_linep)
X		return(FALSE);
X
X	/* if the last command was not a line move,
X	   reset the goal column */
X        if (curgoal < 0)
X                curgoal = getccol(FALSE);
X
X	/* and move the point down */
X        dlp = curwp->w_dotp;
X        while (n-- && dlp!=curbp->b_linep)
X                dlp = lforw(dlp);
X
X	/* resetting the current position */
X        curwp->w_dotp  = (dlp == curbp->b_linep) ? lback(dlp) : dlp;
X        curwp->w_doto  = getgoal(dlp);
X        curwp->w_flag |= WFMOVE;
X        return (TRUE);
}
X
firstnonwhite(f,n)
{
X	int c;
X        curwp->w_doto  = 0;
X	while ( curwp->w_doto != llength(curwp->w_dotp) && 
X			isspace(lgetc(curwp->w_dotp, curwp->w_doto)) )
X		curwp->w_doto++;
X	return (TRUE);
}
X
lastnonwhite(f,n)
{
X	int c;
X        curwp->w_doto  = llength(curwp->w_dotp)-1;
X	while ( curwp->w_doto != 0 && 
X	    ((c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' || c == '\t'))
X		curwp->w_doto--;
X	return (TRUE);
X
}
X
/* like forwline, but got to first non-white char position */
forwbline(f,n)
{
X	int s;
X
X	if (f == FALSE) n = 1;
X	if ((s = forwline(f,n)) != TRUE)
X		return (s);
X	firstnonwhite(f,n);
X	return(TRUE);
}
X
/* like backline, but got to first non-white char position */
backbline(f,n)
{
X	int s;
X
X	if (f == FALSE) n = 1;
X	if ((s = backline(f,n)) != TRUE)
X		return (s);
X	firstnonwhite(f,n);
X	return(TRUE);
}
X
/*
X * This function is like "forwline", but goes backwards. The scheme is exactly
X * the same. Check for arguments that are less than zero and call your
X * alternate. Figure out the new line and call "movedot" to perform the
X * motion. No errors are possible.
X */
backline(f, n)
{
X        register LINE   *dlp;
X
X	if (f == FALSE) n = 1;
X        if (n < 0)
X                return (forwline(f, -n));
X
X
X	/* if we are on the last line as we start....fail the command */
X	if (lback(curwp->w_dotp) == curbp->b_linep)
X		return(FALSE);
X
X	/* if the last command was not note a line move,
X	   reset the goal column */
X        if (curgoal < 0)
X                curgoal = getccol(FALSE);
X
X	/* and move the point up */
X        dlp = curwp->w_dotp;
X        while (n-- && lback(dlp)!=curbp->b_linep)
X                dlp = lback(dlp);
X
X	/* reseting the current position */
X        curwp->w_dotp  = dlp;
X        curwp->w_doto  = getgoal(dlp);
X        curwp->w_flag |= WFMOVE;
X        return (TRUE);
}
X
#if	WORDPRO
X
gotobop(f,n)
{
X	return(backlinebeg(f,n,"\n.","ILPQb"));
}
gotoeop(f,n)
{
X	return(forwlinebeg(f,n,"\n.","ILPQb"));
}
gotobosec(f,n)
{
#if STUTTER_SEC_CMD
X	int this1key;
X	if (!clexec) {
X		this1key = last1key;
X		kbd_seq();
X		if (this1key != last1key) {
X			TTbeep();
X			return(FALSE);
X		}
X	}
#endif
X	return(backlinebeg(f,n,"{\f.","SHN"));
}
gotoeosec(f,n)
{
#if STUTTER_SEC_CMD
X	int this1key;
X	if (!clexec) {
X		this1key = last1key;
X		kbd_seq();
X		if (this1key != last1key) {
X			TTbeep();
X			return(FALSE);
X		}
X	}
#endif
X	return(forwlinebeg(f,n,"{\f.","SHN"));
}
X
backlinebeg(f, n, s1, s2)
char *s1, *s2;
{
X	register int suc;	/* success of last backchar */
X	LINE *odotp;
X
X	if (f == FALSE) n = 1;
X	if (n < 0)	/* the other way...*/
X		return(gotoeop(f, -n));
X
X	odotp = curwp->w_dotp;
X	while (n-- > 0) {	/* for each one asked for */
X
X		/* first scan back until we are in a word */
X		suc = backchar(FALSE, 1);
X		while (!inword() && suc)
X			suc = backchar(FALSE, 1);
X
X		while (lback(curwp->w_dotp) != curbp->b_linep) {
X			if (issecbeg(s1,s2) == TRUE)
X				break;
X			curwp->w_dotp = lback(curwp->w_dotp);
X		}
X	}
X	/* if doing an operation and we moved */
X	if (doingopcmd && odotp != curwp->w_dotp) {
X		curwp->w_dotp = lforw(curwp->w_dotp);
X		curwp->w_doto = 0;
X	} else {
X		firstnonwhite(f,n);
X	}
X	curwp->w_flag |= WFMOVE;	/* force screen update */
X	return(TRUE);
}
X
forwlinebeg(f, n, s1, s2)
char *s1, *s2;
{
X	register int suc;	/* success of last backchar */
X	LINE *odotp;
X
X	if (f == FALSE) n = 1;
X	if (n < 0)	/* the other way...*/
X		return(gotobop(f, -n));
X
X	odotp = curwp->w_dotp;
X	while (n-- > 0) {	/* for each one asked for */
X
X		/* first scan forward until we are in a word */
X		suc = forwchar(FALSE, 1);
X		while (!inword() && suc)
X			suc = forwchar(FALSE, 1);
X		curwp->w_doto = 0;	/* and go to the B-O-Line */
X		if (suc)	/* of next line if not at EOF */
X			curwp->w_dotp = lforw(curwp->w_dotp);
X
X		while (curwp->w_dotp != curbp->b_linep) {
X			if (issecbeg(s1,s2) == TRUE)
X				break;
X			curwp->w_dotp = lforw(curwp->w_dotp);
X		}
X	}
X	/* if doing an operation and we moved */
X	if (doingopcmd && odotp != curwp->w_dotp) {
X		curwp->w_dotp = lback(curwp->w_dotp);
X		curwp->w_doto = llength(curwp->w_dotp)-1;
X	} else {
X		firstnonwhite(f,n);
X	}
X	curwp->w_flag |= WFMOVE;	/* force screen update */
X	return(TRUE);
}
X
/* a new "section" of some sort starts at the beginning of the line,
X	with either a character from s1 or a "." followed by a character
X	from s2 */
issecbeg(s1,s2)
char *s1,*s2;
{
X	register char *cp1, *cp2;
X	register int l, c1, c2;
X
X	l = llength(curwp->w_dotp);
X	for(cp1 = s1; *cp1 != 0; cp1++) {
X		if ( l == 0) {
X			if (*cp1 == '\n')
X				return TRUE;
X			else
X				continue;
X		}
X		c1 = lgetc(curwp->w_dotp, 0);
X		if (c1 == '.' && *cp1 == '.' && s2) {
X			for(cp2 = s2; *cp2 != 0; cp2++) {
X				if ( l <= 1) {
X					if (*cp2 == '\n')
X						return TRUE;
X					else
X						continue;
X				} 
X				c2 = lgetc(curwp->w_dotp, 1);
X				if ( *cp2 == c2 )
X					return TRUE;
X			}
X			
X		} else if ( *cp1 == c1 ) {
X			return TRUE;
X		}
X	}
X	return FALSE;
}
#endif
X
/*
X * This routine, given a pointer to a LINE, and the current cursor goal
X * column, return the best choice for the offset. The offset is returned.
X * Used by "C-N" and "C-P".
X */
getgoal(dlp)
register LINE   *dlp;
{
X        register int    c;
X        register int    col;
X        register int    newcol;
X        register int    dbo;
X
X        col = 0;
X        dbo = 0;
X        while (dbo != llength(dlp)) {
X                c = lgetc(dlp, dbo);
X                newcol = col;
X		if (((curwp->w_bufp->b_mode&MDLIST) == 0) && c == '\t')
X                        newcol |= TABMASK;
X                else if (!isprint(c))
X                        ++newcol;
X                ++newcol;
X                if (newcol > curgoal)
X                        break;
X                col = newcol;
X                ++dbo;
X        }
X        return (dbo);
}
X
/*
X * Scroll forward by a specified number of lines, or by a full page if no
X * argument.  The "2" in the arithmetic on the window size is
X * the overlap; this value is the default overlap value in ITS EMACS. Because
X * this zaps the top line in the display window, we have to do a hard update.
X */
forwpage(f, n)
register int    n;
{
X        register LINE   *lp;
X
X        if (f == FALSE) {
X                n = curwp->w_ntrows - 2;        /* Default scroll.      */
X                if (n <= 0)                     /* Forget the overlap   */
X                        n = 1;                  /* if tiny window.      */
X        } else if (n < 0)
X                return (backpage(f, -n));
#if     CVMVAS
X        else                                    /* Convert from pages   */
X                n *= curwp->w_ntrows;           /* to lines.            */
#endif
X        lp = curwp->w_linep;
X        while (n-- && lp!=curbp->b_linep)
X                lp = lforw(lp);
X        curwp->w_linep = lp;
X        curwp->w_dotp  = lp;
X        curwp->w_doto  = 0;
X        curwp->w_flag |= WFHARD;
X        return (TRUE);
}
X
/*
X * This command is like "forwpage", but it goes backwards. The "2", like
X * above, is the overlap between the two windows. The value is from the ITS
X * EMACS manual. We do a hard update for exactly the same
X * reason.
X */
backpage(f, n)
register int    n;
{
X        register LINE   *lp;
X
X        if (f == FALSE) {
X                n = curwp->w_ntrows - 2;        /* Default scroll.      */
X                if (n <= 0)                     /* Don't blow up if the */
X                        n = 1;                  /* window is tiny.      */
X        } else if (n < 0)
X                return (forwpage(f, -n));
#if     CVMVAS
X        else                                    /* Convert from pages   */
X                n *= curwp->w_ntrows;           /* to lines.            */
#endif
X        lp = curwp->w_linep;
X        while (n-- && lback(lp)!=curbp->b_linep)
X                lp = lback(lp);
X        curwp->w_linep = lp;
X        curwp->w_dotp  = lp;
X        curwp->w_doto  = 0;
X        curwp->w_flag |= WFHARD;
X        return (TRUE);
}
X
/*
X * Scroll forward by a specified number of lines, or by a full page if no
X * argument. The "2" in the arithmetic on the window size is
X * the overlap; this value is the default overlap value in ITS EMACS. Because
X * this zaps the top line in the display window, we have to do a hard update.
X */
forwhpage(f, n)
register int    n;
{
X        register LINE   *llp, *dlp;
X
X        if (f == FALSE) {
X                n = curwp->w_ntrows / 2;        /* Default scroll.      */
X                if (n <= 0)                     /* Forget the overlap   */
X                        n = 1;                  /* if tiny window.      */
X        } else if (n < 0)
X                return (backhpage(f, -n));
#if     CVMVAS
X        else                                    /* Convert from pages   */
X                n *= curwp->w_ntrows/2;           /* to lines.            */
#endif
X        llp = curwp->w_linep;
X        dlp = curwp->w_dotp;
X        while (n-- && lforw(dlp) != curbp->b_linep) {
X                llp = lforw(llp);
X                dlp = lforw(dlp);
X	}
X        curwp->w_linep = llp;
X        curwp->w_dotp  = dlp;
X	firstnonwhite(f,n);
X        curwp->w_flag |= WFHARD|WFKILLS;
X        return (TRUE);
}
X
/*
X * This command is like "forwpage", but it goes backwards. The "2", like
X * above, is the overlap between the two windows. The value is from the ITS
X * EMACS manual. We do a hard update for exactly the same
X * reason.
X */
backhpage(f, n)
register int    n;
{
X        register LINE   *llp, *dlp;
X
X        if (f == FALSE) {
X                n = curwp->w_ntrows / 2;        /* Default scroll.      */
X                if (n <= 0)                     /* Don't blow up if the */
X                        n = 1;                  /* window is tiny.      */
X        } else if (n < 0)
X                return (forwhpage(f, -n));
#if     CVMVAS
X        else                                    /* Convert from pages   */
X                n *= curwp->w_ntrows/2;           /* to lines.            */
#endif
X        llp = curwp->w_linep;
X        dlp = curwp->w_dotp;
X        while (n-- && lback(dlp)!=curbp->b_linep) {
X                llp = lback(llp);
X                dlp = lback(dlp);
X	}
X        curwp->w_linep = llp;
X        curwp->w_dotp  = dlp;
X	firstnonwhite(f,n);
X        curwp->w_flag |= WFHARD|WFINS;
X        return (TRUE);
}
X
X
X
/*
X * Set the named mark in the current window to the value of "." in the window.
X * No errors are possible.
X */
setnmmark(f,n)
{
X	char *s;
X	int c,i;
X
X	if (clexec || isnamedcmd) {
X		int stat;
X		static char cbuf[2];
X	        if ((stat=mlreply("Set mark: ", cbuf, 2)) != TRUE)
X	                return stat;
X		c = cbuf[0];
X        } else {
X		c = kbd_key();
X        }
X	if (c < 'a' || c > 'z') {
X		TTbeep();
X		mlwrite("[Invalid mark name]");
X		return FALSE;
X	}
X		
X	if (curbp->b_nmmarks == NULL) {
X		curbp->b_nmmarks = 
X			(struct MARK *)malloc(26*sizeof(struct MARK));
X		if (curbp->b_nmmarks == NULL) {
X			mlwrite("[OUT OF MEMORY]");
X			return FALSE;
X		}
X		for (i = 0; i < 26; i++) {
X			curbp->b_nmmarks[i].markp = NULL;
X			curbp->b_nmmarks[i].marko = 0;
X		}
X	}
X		
X        curbp->b_nmmarks[c-'a'].markp = curwp->w_dotp;
X        curbp->b_nmmarks[c-'a'].marko = curwp->w_doto;
X        s = "[Mark X set]";
X	s[6] = c;
X        mlwrite(s);
X        return TRUE;
}
X
golinenmmark(f,n)
{
X	int status;
X	status = goexactnmmark(f,n);
X	if (status != TRUE)
X		return(status);
X	firstnonwhite(f,n);
X	return(TRUE);
}
X
goexactnmmark(f,n)
{
X	int c;
X	int this1key;
X	int useldmark;
X
X	this1key = last1key;
X	c = kbd_seq();
X	useldmark = (last1key == this1key);  /* '' or `` */
X	c = kcod2key(c);
X
X	if (useldmark)
X		c = '\'';
X
X	return gonmmark(c);
}
X
gonmmark(c)
{
X	register LINE **markpp;
X	register int *markop;
X	LINE *tmarkp;
X	int tmarko;
X	int found;
X
X	if (!islower(c) && c != '\'') {
X		TTbeep();
X		mlwrite("[Invalid mark name]");
X		return FALSE;
X	}
X
X	markpp = NULL;
X
X	if (c == '\'') { /* use the 'last dot' mark */
X		markpp = &(curwp->w_ldmkp);
X		markop = &(curwp->w_ldmko);
X	} else if (curbp->b_nmmarks != NULL) {
X		markpp = &(curbp->b_nmmarks[c-'a'].markp);
X 		markop = &(curbp->b_nmmarks[c-'a'].marko);
X	}
X		
X	found = FALSE;
X	if (markpp != NULL && *markpp != NULL) {
X		register LINE *lp;
X		for (lp = lforw(curbp->b_linep);
X				lp != curbp->b_linep; lp = lforw(lp)) {
X			if (*markpp == lp) {
X				found = TRUE;
X				break;
X			}
X		}
X	}
X	if (!found) {
X		TTbeep();
X		mlwrite("[Mark not set]");
X		return (FALSE);
X	}
X	
X	/* save current dot */
X	tmarkp = curwp->w_dotp;
X	tmarko = curwp->w_doto;
X
X	/* move to the selected mark */
X	curwp->w_dotp = *markpp;
X	curwp->w_doto = *markop;
X
X	/* reset last-dot-mark to old dot */
X	curwp->w_ldmkp = tmarkp;
X	curwp->w_ldmko = tmarko;
X
X        curwp->w_flag |= WFMOVE;
X        return (TRUE);
}
X
/*
X * Set the mark in the current window to the value of "." in the window. No
X * errors are possible.
X */
setmark()
{
X        curwp->w_mkp = curwp->w_dotp;
X        curwp->w_mko = curwp->w_doto;
X        return (TRUE);
}
X
gomark(f,n)
{
X        curwp->w_dotp = curwp->w_mkp;
X        curwp->w_doto = curwp->w_mko;
X        curwp->w_flag |= WFMOVE;
X        return (TRUE);
}
X
/* this odd routine puts us at the internal mark, plus an offset of lines */
/*  n == 1 leaves us at mark, n == 2 one line down, etc. */
/*  this is for the use of stuttered commands, and line oriented regions */
godotplus(f,n)
{
X	int s;
X	if (!f || n == 1)
X	        return (TRUE);
X	if (n < 1)
X	        return (FALSE);
X	s = forwline(TRUE,n-1);
X	if (s && curwp->w_dotp == curbp->b_linep)
X		s = backline(FALSE,1);
X	return s;
}
X
atmark()
{
X        return ((curwp->w_dotp == curwp->w_mkp) && 
X		(curwp->w_doto == curwp->w_mko));
}
X
/*
X * Swap the values of "." and "mark" in the current window. This is pretty
X * easy, bacause all of the hard work gets done by the standard routine
X * that moves the mark about. The only possible error is "no mark".
X */
swapmark()
{
X        register LINE   *odotp;
X        register int    odoto;
X
X        if (curwp->w_mkp == NULL) {
X                mlwrite("No mark in this window");
X                return (FALSE);
X        }
X        odotp = curwp->w_dotp;
X        odoto = curwp->w_doto;
X        curwp->w_dotp  = curwp->w_mkp;
X        curwp->w_doto  = curwp->w_mko;
X        curwp->w_mkp = odotp;
X        curwp->w_mko = odoto;
X        curwp->w_flag |= WFMOVE;
X        return (TRUE);
}
X
X
X
#if	NeWS
/* SETCURSOR
X *
X * Mouse support function.  Put the cursor to the requested location.
X * The cursor will be put just after the last character of the line if 
X * requested past the line.  The coordinates are expected in the command
X * stream.
X *   In the case of multiple windows, the window indicated by the mouse
X * is located and made the current window.
X */
setcursor()
{
int	row, col, pasteol ;
register LINE	*dlp;
WINDOW *wp0 ;		/* current window on entry */
X
X	row = tgetc() ;
X	col = tgetc() ;
X
/* find the window we are pointing to */
X	wp0 = curwp ;
X	while ( row < curwp->w_toprow ||
X		row > curwp->w_ntrows + curwp->w_toprow ) {
X		nextwind(FALSE,0) ;
X		if ( curwp == wp0 ) break ;	/* full circle */
X	}
X
/* move to the right row */
X	row -= curwp->w_toprow ;
X	dlp = curwp->w_linep ;			/* get pointer to 1st line */
X	while ( row-- && (dlp != curbp->b_linep) ) dlp = lforw(dlp) ;
X	curwp->w_dotp = dlp ;			/* set dot line pointer */
X
X	/* now move the dot over until near the requested column */
X	curgoal = col ;		/* a global for this ?? */
X	curwp->w_doto = getgoal(dlp) ;
X	curwp->w_flag |= WFMOVE;
X	return (TRUE);
}
#endif
SHAR_EOF
chmod 0444 basic.c ||
echo 'restore of basic.c failed'
Wc_c="`wc -c < 'basic.c'`"
test 20335 -eq "$Wc_c" ||
	echo 'basic.c: original size 20335, current size' "$Wc_c"
# ============= bind.c ==============
echo 'x - extracting bind.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'bind.c' &&
/*	This file is for functions having to do with key bindings,
X	descriptions, help commands and startup file.
X
X	written 11-feb-86 by Daniel Lawrence
X								*/
X
#include	<stdio.h>
#include	"estruct.h"
#include	"edef.h"
#include	"epath.h"
X
/* dummy prefix binding functions */
extern CMDFUNC f_cntl_af, f_cntl_xf, f_unarg, f_esc;
X
/* give me some help!!!! bring up a buffer and read the help file into it */
help(f, n)
{
X	register WINDOW *wp;	/* scaning pointer to windows */
X	register BUFFER *bp;	/* buffer pointer to help */
X	char *fname;		/* ptr to file returned by flook() */
X
X	/* first check if we are already here */
X	bp = bfind("[Help]", OK_CREAT, BFSCRTCH);
X	if (bp == NULL)
X		return FALSE;
X
X	if (bp->b_active == FALSE) { /* never been used */
X		fname = flook(pathname[1], FL_ANYWHERE);
X		if (fname == NULL) {
X			mlwrite("[Sorry, can't find the help information]");
X			zotbuf(bp);
X			return(FALSE);
X		}
X		/* and read the stuff in */
X		if (readin(fname, 0, bp, TRUE) == FALSE ||
X				popupbuff(bp) == FALSE) {
X			zotbuf(bp);
X			return(FALSE);
X		}
X		strcpy(bp->b_bname,"[Help]");
X	        sprintf(bp->b_fname, "       %s   %s",prognam,version);
X		bp->b_mode |= MDVIEW;
X		bp->b_mode &= ~MDEXACT;
X		bp->b_flag |= BFSCRTCH;
X	}
X	return swbuffer(bp);
}
X
#if REBIND
X
deskey(f, n)	/* describe the command for a certain key */
{
X	register int c;		/* key to describe */
X	register char *ptr;	/* string pointer to scan output strings */
X	char outseq[NSTRING];	/* output buffer for command sequence */
X	char *kcod2prc();
X
X	/* prompt the user to type us a key to describe */
X	mlwrite(": describe-key ");
X
X	/* get the command sequence to describe
X	   change it to something we can print as well */
X
X	/* check to see if we are executing a command line */
X	if (clexec) {
X		char tok[NSTRING];
X		macarg(tok);	/* get the next token */
X		c = prc2kcod(tok);
X	} else {
X		c = kbd_seq();
X	}
X	kcod2prc(c, &outseq[0]);
X
X	/* and dump it out */
X	ostring(outseq);
X	ostring(" ");
X
X	/* find the right ->function */
X	if ((ptr = fnc2engl(kcod2fnc(c))) == NULL)
X		ptr = "Not Bound";
X
X	/* output the command sequence */
X	ostring(ptr);
}
X
/* bindkey:	add a new key to the key binding table		*/
X
bindkey(f, n)
int f, n;	/* command arguments [IGNORED] */
{
X	register int c;		/* command key to bind */
X	register CMDFUNC *kcmd;	/* ptr to the requested function to bind to */
X	register KBIND *kbp;	/* pointer into a binding table */
X	register int found;	/* matched command flag */
X	char outseq[80];	/* output buffer for keystroke sequence */
X	char *fnp;
X	char *kbd_engl();
X	char *kcod2prc();
X
X	/* prompt the user to type in a key to bind */
X	mlwrite(": bind-to-key ");
X
X	/* get the function name to bind it to */
#if	NeWS
X	newsimmediateon() ;
#endif
X	fnp = kbd_engl();
#if	NeWS
X	newsimmediateoff() ;
#endif
X
X	if (fnp == NULL || (kcmd = engl2fnc(fnp)) == NULL) {
X		mlwrite("[No such function]");
X		return(FALSE);
X	}
X	ostring(" ");
X	TTflush();
X
X	/* get the command sequence to bind */
X	if (clexec) {
X		char tok[NSTRING];
X		macarg(tok);	/* get the next token */
X		c = prc2kcod(tok);
X	} else {
X		/* perhaps we only want a single key, not a sequence */
X		/* 	(see more comments below) */
X		if ((kcmd == &f_cntl_af) || (kcmd == &f_cntl_xf) ||
X	            (kcmd == &f_unarg) || (kcmd == &f_esc))
X			c = kbd_key();
X		else
X			c = kbd_seq();
X	}
X
X	/* change it to something we can print as well */
X	kcod2prc(c, &outseq[0]);
X
X	/* and dump it out */
X	ostring(outseq);
X
X	/* if the function is a prefix key, i.e. we're changing the definition
X		of a prefix key, then they typed a dummy function name, which
X		has been translated into a dummy function pointer */
X	if (kcmd == &f_cntl_af || kcmd == &f_cntl_xf ||
X	    kcmd == &f_unarg || kcmd == &f_esc) {
X	    	register CMDFUNC **cfp;
X		/* search for an existing binding for the prefix key */
X		cfp = asciitbl;
X		found = FALSE;
X		for (cfp = asciitbl; cfp < &asciitbl[128]; cfp++) {
X			if (*cfp == kcmd) {
X				unbindchar(cfp - asciitbl);
X				break;
X			}
X		}
X
X		/* reset the appropriate global prefix variable */
X		if (kcmd == &f_cntl_af)
X			cntl_a = c;
X		if (kcmd == &f_cntl_xf)
X			cntl_x = c;
X		if (kcmd == &f_unarg)
X			reptc = c;
X		if (kcmd == &f_esc)
X			abortc = c;
X	}
X	
X	if ((c & (CTLA|SPEC|CTLX)) == 0) {
X		asciitbl[c] = kcmd;
X	} else {
X		for(kbp = kbindtbl; kbp->k_cmd && kbp->k_code != c; kbp++)
X			;
X		if (kbp->k_cmd) { /* found it, change it in place */
X			kbp->k_cmd = kcmd;
X		} else {
X			if (kbp >= &kbindtbl[NBINDS-1]) {
X				mlwrite("Prefixed binding table full");
X				return(FALSE);
X			}
X			kbp->k_code = c;	/* add keycode */
X			kbp->k_cmd = kcmd; /* and func pointer */
X			++kbp;		/* and make sure the next is null */
X			kbp->k_code = 0;
X			kbp->k_cmd = NULL;
X		}
X	}
X
X	return TRUE;
}
X
/* unbindkey:	delete a key from the key binding table	*/
X
unbindkey(f, n)
int f, n;	/* command arguments [IGNORED] */
{
X	register int c;		/* command key to unbind */
X	char outseq[80];	/* output buffer for keystroke sequence */
X	char *kcod2prc();
X
X	/* prompt the user to type in a key to unbind */
X	mlwrite(": unbind-key ");
X
X	/* get the command sequence to unbind */
X	if (clexec) {
X		char tok[NSTRING];
X		macarg(tok);	/* get the next token */
X		c = prc2kcod(tok);
X	} else {
X		c = kbd_seq();
X	}
X
X	/* change it to something we can print as well */
X	kcod2prc(c, &outseq[0]);
X
X	/* and dump it out */
X	ostring(outseq);
X
X	/* if it isn't bound, bitch */
X	if (unbindchar(c) == FALSE) {
X		mlwrite("[Key not bound]");
X		return(FALSE);
X	}
X	return(TRUE);
}
X
unbindchar(c)
int c;		/* command key to unbind */
{
X	register KBIND *kbp;	/* pointer into the command table */
X	register KBIND *skbp;	/* saved pointer into the command table */
X	register int found;	/* matched command flag */
X
X	if ((c & (CTLA|SPEC|CTLX)) == 0) {
X		asciitbl[c] = NULL;
X	} else {
X		/* search the table to see if the key exists */
X		for (kbp = kbindtbl; kbp->k_cmd && kbp->k_code != c; kbp++)
X			;
X
X		/* if it isn't bound, bitch */
X		if (kbp->k_cmd == NULL)
X			return(FALSE);
X
X		/* save the pointer and scan to the end of the table */
X		skbp = kbp;
X		while (kbp->k_cmd != NULL)
X			++kbp;
X		--kbp;		/* backup to the last legit entry */
X
X		/* copy the last entry to the current one */
X		skbp->k_code = kbp->k_code;
X		skbp->k_cmd  = kbp->k_cmd;
X
X		/* null out the last one */
X		kbp->k_code = 0;
X		kbp->k_cmd = NULL;
X	}
X	return TRUE;
}
X
/* describe bindings bring up a fake buffer and list the key bindings
X		   into it with view mode			*/
desbind(f, n)
{
X	return mkblist(NULL);
}
X
#if	APROP
apro(f, n)	/* Apropos (List functions that match a substring) */
{
X	static char mstring[NSTRING] = 0;	/* string to match cmd names to */
X        register int    s;
X
X
X	s = mlreply("Apropos string: ", mstring, NSTRING - 1);
X	if (s != TRUE)
X		return(s);
X
X	return mkblist(mstring);
}
#endif
X
mkblist(mstring)
char *mstring;
{
X        register BUFFER *bp;
X        register int    s;
X
X	/* create the buffer list buffer   */
X	bp = bfind("[Binding List]", OK_CREAT, BFSCRTCH);
X	if (bp == NULL)
X		return FALSE;
X	
X        if ((s=bclear(bp)) != TRUE) /* clear old text (?) */
X                return (s);
X        s = buildlist(mstring,bp);
X	if (s != TRUE || popupbuff(bp) == FALSE) {
X		mlwrite("[Sorry, can't list. ]");
X		zotbuf(bp);
X                return (s);
X        }
X        strcpy(bp->b_fname, "");
X	bp->b_mode |= MDVIEW;
X	bp->b_flag |= BFSCRTCH;
X        bp->b_flag &= ~BFCHG;        /* Don't complain!      */
X        bp->b_active = TRUE;
X
X        return TRUE;
}
X
X
/* build a binding list (limited or full) */
buildlist(mstring, bp)
char *mstring;		/* match string if partial list, NULL to list all */
register BUFFER *bp;	/* buffer to put binding list into */
{
#if	ST520 & LATTICE
#define	register		
#endif
X	register WINDOW *wp;	/* scanning pointer to windows */
X	register KBIND *kbp;	/* pointer into a key binding table */
X	register CMDFUNC **cfp;	/* pointer into the ascii table */
X	register NTAB *nptr,*nptr2;	/* pointer into the name table */
X	char *strp;		/* pointer int string to send */
X	int cpos;		/* current position to use in outseq */
X	char outseq[81];	/* output buffer for keystroke sequence */
X	int i,pass;
X	char *kcod2prc();
X
X
X	/* let us know this is in progress */
X	mlwrite("[Building binding list]");
X
X	/* build the contents of this window, inserting it line by line */
X	for (pass = 0; pass < 2; pass++) {
X	    for (nptr = nametbl; nptr->n_name != NULL; ++nptr) {
X
X		/* if we've already described this one, move on */
X		if (nptr->n_cmd->c_flags & LISTED)
X			continue;
X
X		/* try to avoid alphabetizing by the real short names */
X		if (pass == 0 && strlen(nptr->n_name) <= 2)
X			continue;
X
X		/* add in the command name */
X		strcpy(outseq,"\"");
X		strcat(outseq, nptr->n_name);
X		strcat(outseq,"\"");
X		cpos = strlen(outseq);
X		while (cpos < 32)
X			outseq[cpos++] = ' ';
X		outseq[cpos] = 0;
X		
#if	APROP
X		/* if we are executing an apropos command
X		   and current string doesn't include the search string */
X		if (mstring && (strinc(outseq, mstring) == FALSE))
X		    	continue;
#endif
X		/* look in the simple ascii binding table first */
X		for(cfp = asciitbl, i = 0; cfp < &asciitbl[128]; cfp++, i++) {
X			if (*cfp == nptr->n_cmd) {
X				cpos = kcod2prc(i, &outseq[strlen(outseq)]) -
X					outseq;
X				while(cpos & 7)
X					outseq[cpos++] = ' ';
X				outseq[cpos] = '\0';
X			}
X		}
X		/* then look in the multi-key table */
X		for(kbp = kbindtbl; kbp->k_cmd; kbp++) {
X			if (kbp->k_cmd == nptr->n_cmd) {
X				cpos = 
X				kcod2prc(kbp->k_code, &outseq[strlen(outseq)]) -
X					outseq;
X				while(cpos & 7)
X					outseq[cpos++] = ' ';
X				outseq[cpos] = '\0';
X			}
X		}
X		/* dump the line */
X		addline(bp,outseq,-1);
X
X		cpos = 0;
X
X		/* then look for synonyms */
X		for (nptr2 = nametbl; nptr2->n_name != NULL; ++nptr2) {
X			/* if it's the one we're on, skip */
X			if (nptr2 == nptr)
X				continue;
X			/* if it's already been listed, skip */
X			if (nptr2->n_cmd->c_flags & LISTED)
X				continue;
X			/* if it's not a synonym, skip */
X			if (nptr2->n_cmd != nptr->n_cmd)
X				continue;
X			while (cpos < 8)
X				outseq[cpos++] = ' ';
X			outseq[cpos] = '\0';
X			strcat(outseq,"\"");
X			strcat(outseq,nptr2->n_name);
X			strcat(outseq,"\"");
X			addline(bp,outseq,-1);
X			cpos = 0;	/* and clear the line */
X
X		}
X
X		nptr->n_cmd->c_flags |= LISTED; /* mark it as already listed */
X	    }
X	}
X
X	for (nptr = nametbl; nptr->n_name != NULL; ++nptr)
X		nptr->n_cmd->c_flags &= ~LISTED; /* mark it as unlisted */
X
X	mlwrite("");	/* clear the mode line */
X	return(TRUE);
}
X
#if	APROP
strinc(source, sub)	/* does source include sub? */
char *source;	/* string to search in */
char *sub;	/* substring to look for */
{
X	char *sp;	/* ptr into source */
X	char *nxtsp;	/* next ptr into source */
X	char *tp;	/* ptr into substring */
X
X	/* for each character in the source string */
X	sp = source;
X	while (*sp) {
X		tp = sub;
X		nxtsp = sp;
X
X		/* is the substring here? */
X		while (*tp) {
X			if (*nxtsp++ != *tp)
X				break;
X			else
X				tp++;
X		}
X
X		/* yes, return a success */
X		if (*tp == 0)
X			return(TRUE);
X
X		/* no, onward */
X		sp++;
X	}
X	return(FALSE);
}
#endif
X
#endif /* REBIND */
X
X
/* execute the startup file */
X
startup(sfname)
char *sfname;	/* name of startup file  */
{
X	char *fname;	/* resulting file name to execute */
X
X	/* look up the startup file */
X	fname = flook(sfname, FL_HERE_HOME);
X
X	/* if it isn't around, don't sweat it */
X	if (fname == NULL) {
X		mlwrite("[Can't find startup file %s]",sfname);
X		return(TRUE);
X	}
X
X	/* otherwise, execute the sucker */
X	return(dofile(fname));
}
X
/*	Look up the existence of a file along the normal or PATH
X	environment variable. Look first in the HOME directory if
X	asked and possible
*/
X
char *
flook(fname, hflag)
char *fname;	/* base file name to search for */
int hflag;	/* Look in the HOME environment variable first? */
{
X	register char *home;	/* path to home directory */
X	register char *path;	/* environmental PATH variable */
X	register char *sp;	/* pointer into path spec */
X	register int i;		/* index */
X	static char fspec[NSTRING];	/* full path spec to search */
X	char *getenv();
X
X	/* tak care of special cases */
X	if (!fname || !fname[0] || isspace(fname[0]))
X		return NULL;
X	else if (fname[0] == '!')
X		return fname;
X		
X	/* always try the current directory first */
X	if (ffropen(fname) == FIOSUC) {
X		ffclose();
X		return(fname);
X	}
X
X	if (hflag == FL_HERE)
X		return NULL;
X
#if	ENVFUNC
X
X	if (hflag) {
X		home = getenv("HOME");
X		if (home != NULL) {
X			/* build home dir file spec */
X			strcpy(fspec, home);
X			strcat(fspec, "/");
X			strcat(fspec, fname);
X
X			/* and try it out */
X			if (ffropen(fspec) == FIOSUC) {
X				ffclose();
X				return(fspec);
X			}
X		}
X	}
X
X	if (hflag == FL_HERE_HOME)
X		return NULL;
X
#if PATHLOOK
X	/* get the PATH variable */
X	path = getenv("PATH");
X	if (path != NULL)
X		while (*path) {
X
X			/* build next possible file spec */
X			sp = fspec;
X			while (*path && (*path != PATHCHR))
X				*sp++ = *path++;
X			*sp++ = '/';
X			*sp = 0;
X			strcat(fspec, fname);
X
X			/* and try it out */
X			if (ffropen(fspec) == FIOSUC) {
X				ffclose();
X				return(fspec);
X			}
X
X			if (*path == PATHCHR)
X				++path;
X		}
#endif
#endif
X
X	/* look it up via the old table method */
X	for (i=2; i < NPNAMES; i++) {
X		strcpy(fspec, pathname[i]);
X		strcat(fspec, fname);
X
X		/* and try it out */
X		if (ffropen(fspec) == FIOSUC) {
X			ffclose();
X			return(fspec);
X		}
X	}
X
X
X	return NULL;	/* no such luck */
}
X
/* translate a 10-bit keycode to its printable name (like "M-j")  */
char *
kcod2prc(c, seq)
int c;		/* sequence to translate */
char *seq;	/* destination string for sequence */
{
X	char *ptr;	/* pointer into current position in sequence */
X
X	ptr = seq;
X
X	/* apply cntl_a sequence if needed */
X	if (c & CTLA) {
X		*ptr++ = '^';
X		*ptr++ = 'A';
X		*ptr++ = '-';
X	}
X
X	/* apply ^X sequence if needed */
X	if (c & CTLX) {
X		*ptr++ = '^';
X		*ptr++ = 'X';
X		*ptr++ = '-';
X	}
X
X	/* apply SPEC sequence if needed */
X	if (c & SPEC) {
X		*ptr++ = 'F';
X		*ptr++ = 'N';
X		*ptr++ = '-';
X	}
X	
X	c = kcod2key(c);
X
X	/* apply control sequence if needed */
X	if (iscntrl(c)) {
X		*ptr++ = '^';
X		c = toalpha(c);
X	}
X
X	/* and output the final sequence */
X
X	if (c == ' ') {
X		*ptr++ = '<';
X		*ptr++ = 's';
X		*ptr++ = 'p';
X		*ptr++ = '>';
X	} else if (c == '\t') {
X		*ptr++ = '<';
X		*ptr++ = 't';
X		*ptr++ = 'a';
X		*ptr++ = 'b';
X		*ptr++ = '>';
X	} else {
X		*ptr++ = c;
X	}
X	*ptr = 0;	/* terminate the string */
X	return ptr;
}
X
X
/* kcod2fnc:  translate a 10-bit keycode to a function pointer */
/*	(look a key binding up in the binding table)		*/
CMDFUNC *
kcod2fnc(c)
int c;	/* key to find what is bound to it */
{
X	register KBIND *kbp;
X
X	if ((c & (CTLA|SPEC|CTLX)) == 0) {
X		return asciitbl[c];
X	} else {
X		for (kbp = kbindtbl; kbp->k_cmd && kbp->k_code != c; kbp++)
X			;
X		return kbp->k_cmd;
X	}
}
X
X
/* fnc2engl: translate a function pointer to the english name for 
X		that function
*/
X
char *
fnc2engl(cfp)
CMDFUNC *cfp;	/* ptr to the requested function to bind to */
{
X	register NTAB *nptr;	/* pointer into the name table */
X
X	/* skim through the table, looking for a match */
X	for (nptr = nametbl; nptr->n_cmd; nptr++) {
SHAR_EOF
true || echo 'restore of bind.c failed'
echo 'End of Vile part 1'
echo 'File bind.c is continued in part 2'
echo 2 > _shar_seq_.tmp
exit 0
-- 
		paul fox, pgf at cayman.com, (617)494-1999
		Cayman Systems, 26 Landsdowne St., Cambridge, MA 02139



More information about the Alt.sources mailing list