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