elvis 1.3 - a clone of vi/ex, part 3 of 6
Steve Kirkendall
kirkenda at eecs.cs.pdx.edu
Sat Aug 25 03:54:42 AEST 1990
Archive-name: elvis1.3/part3
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
# atari.c
# curses.c
# curses.h
# cut.c
# elvis.ndx
# ex.c
# input.c
# main.c
# misc.c
# This archive created: Fri Aug 24 10:29:55 1990
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'atari.c'
then
echo shar: "will not over-write existing file 'atari.c'"
else
cat << \SHAR_EOF > 'atari.c'
/* atari.c */
/* Author:
* Guntram Blohm
* Buchenstrasse 19
* 7904 Erbach, West Germany
* Tel. ++49-7305-6997
* sorry - no regular network connection
*/
/*
* This file contains the 'standard' functions which are not supported
* by Atari/Mark Williams, and some other TOS-only requirements.
*/
#include "config.h"
#include "vi.h"
#if TOS
#include <osbind.h>
/* vi uses mode==0 only ... */
int access(file, mode)
char *file;
{
int fd=Fopen(file, 0);
if (fd<0)
return -1;
Fclose(fd);
return 0;
}
char *mktemp(template)
char *template;
{
return template;
}
/* read -- text mode, compress \r\n to \n
* warning: might fail when maxlen==1 and at eol
*/
int tread(fd, buf, maxlen)
int fd;
char *buf;
int maxlen;
{
int i, j, nread=read(fd, buf, maxlen);
if (nread && buf[nread-1]=='\r')
{ nread--;
lseek(fd, -1l, 1);
}
for (i=j=0; j<nread; i++,j++)
{ if (buf[j]=='\r' && buf[j+1]=='\n')
j++;
buf[i]=buf[j];
}
return i;
}
int twrite(fd, buf, maxlen)
int fd;
char *buf;
int maxlen;
{
int i, j, nwritten=0, hadnl=0;
char writbuf[BLKSIZE];
for (i=j=0; j<maxlen; )
{
if ((writbuf[i++]=buf[j++])=='\n')
{ writbuf[i-1]='\r';
if (i<BLKSIZE)
writbuf[i++]='\n';
else
hadnl=1;
}
if (i==BLKSIZE)
{
write(fd, writbuf, i);
i=0;
}
if (hadnl)
{
writbuf[i++]='\n';
hadnl=0;
}
}
if (i)
write(fd, writbuf, i);
return j;
}
#endif
SHAR_EOF
fi
if test -f 'curses.c'
then
echo shar: "will not over-write existing file 'curses.c'"
else
cat << \SHAR_EOF > 'curses.c'
/* curses.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This file contains the functions & variables needed for a tiny subset of
* curses. The principle advantage of this version of curses is its
* extreme speed. Disadvantages are potentially larger code, few supported
* functions, limited compatibility with full curses, and only stdscr.
*/
#include "config.h"
#include "vi.h"
#if UNIXV
# include <termio.h>
#endif
#if BSD || UNIX7 || MINIX
# include <sgtty.h>
#endif
#if TOS
# include <osbind.h>
#endif
#include <signal.h>
extern char *getenv();
/* variables, publicly available & used in the macros */
short ospeed; /* speed of the tty, eg B2400 */
char PC; /* Pad char */
WINDOW *stdscr; /* pointer into kbuf[] */
WINDOW kbuf[KBSIZ]; /* a very large output buffer */
int LINES; /* :li#: number of rows */
int COLS; /* :co#: number of columns */
int AM; /* :am: boolean: auto margins? */
int PT; /* :pt: boolean: physical tabs? */
char *VB; /* :vb=: visible bell */
char *UP; /* :up=: move cursor up */
char *SO; /* :so=: standout start */
char *SE; /* :se=: standout end */
char *US = ""; /* :us=: underline start */
char *UE = ""; /* :ue=: underline end */
char *VB_s = ""; /* :VB=: bold start */
char *VB_e = ""; /* :Vb=: bold end */
char *AS; /* :as=: alternate (italic) start */
char *AE; /* :ae=: alternate (italic) end */
char *CM; /* :cm=: cursor movement */
char *CE; /* :ce=: clear to end of line */
char *CD; /* :cd=: clear to end of screen */
char *AL; /* :al=: add a line */
char *DL; /* :dl=: delete a line */
char *SR; /* :sr=: scroll reverse */
char *KU; /* :ku=: key sequence sent by up arrow */
char *KD; /* :kd=: key sequence sent by down arrow */
char *KL; /* :kl=: key sequence sent by left arrow */
char *KR; /* :kr=: key sequence sent by right arrow */
char *HM; /* :HM=: key sequence sent by the <Home> key */
char *EN; /* :EN=: key sequence sent by the <End> key */
char *PU; /* :PU=: key sequence sent by the <PgUp> key */
char *PD; /* :PD=: key sequence sent by the <PgDn> key */
char *IM; /* :im=: insert mode start */
char *IC = ""; /* :ic=: insert the following character */
char *EI; /* :ei=: insert mode end */
char *DC; /* :dc=: delete a character */
char *TI; /* :ti=: terminal init */ /* GB */
char *TE; /* :te=: terminal exit */ /* GB */
#ifndef NO_CURSORSHAPE
char *CQ = (char *)0;/* :cQ=: normal cursor */
char *CX = (char *)1;/* :cX=: cursor used for EX command/entry */
char *CV = (char *)2;/* :cV=: cursor used for VI command mode */
char *CI = (char *)3;/* :cI=: cursor used for VI input mode */
char *CR = (char *)4;/* :cR=: cursor used for VI replace mode */
#endif
char *aend = ""; /* end an attribute -- either UE or VB_e */
char ERASEKEY; /* backspace key taken from ioctl structure */
#if UNIXV
static struct termio oldtermio; /* original tty mode */
static struct termio newtermio; /* raw/noecho tty mode */
#endif
#if BSD || UNIX7 || MINIX
static struct sgttyb oldsgttyb; /* original tty mode */
static struct sgttyb newsgttyb; /* raw/nl/noecho tty mode */
static int oldint;
#endif
static char *capbuf; /* capability string buffer */
initscr()
{
/* make sure TERM variable is set */
#if MSDOS
char *val;
if (! (val = getenv("TERM"))
|| !strcmp(val, "pcbios"))
#else
if (!getenv("TERM"))
#endif
{
#if ANY_UNIX || TOS
write(2, "Environment variable TERM must be set\n", 38);
exit(1);
#endif
#if MSDOS
getsize(0);
#endif
}
else
{
#if MSDOS
*o_pcbios=0;
#endif
/* start termcap stuff */
starttcap();
}
/* create stdscr and curscr */
stdscr = kbuf;
/* change the terminal mode to raw/noecho */
#if UNIXV
ioctl(2, TCGETA, &oldtermio);
#endif
#if BSD || UNIX7 || MINIX
ioctl(2, TIOCGETP, &oldsgttyb);
#endif
resume_curses(TRUE);
}
endwin()
{
/* change the terminal mode back the way it was */
suspend_curses();
}
suspend_curses()
{
#if BSD || UNIX7 || MINIX
struct tchars tbuf;
#endif
#ifndef NO_CURSORSHAPE
if (has_CQ)
{
do_CQ();
}
#endif
if (has_TE) /* GB */
{
do_TE();
}
/* change the terminal mode back the way it was */
#if UNIXV
ioctl(2, TCSETAW, &oldtermio);
#endif
#if BSD || UNIX7 || MINIX
ioctl(2, TIOCSETP, &oldsgttyb);
ioctl(2, TIOCGETC, &tbuf);
tbuf.t_intrc = oldint;
ioctl(2, TIOCSETC, &tbuf);
#endif
}
resume_curses(quietly)
int quietly;
{
/* change the terminal mode to raw/noecho */
#if UNIXV
ospeed = (oldtermio.c_cflag & CBAUD);
ERASEKEY = oldtermio.c_cc[VERASE];
newtermio = oldtermio;
newtermio.c_iflag &= (IXON|IXOFF|IXANY|ISTRIP|IGNBRK);
newtermio.c_oflag &= ~OPOST;
newtermio.c_lflag &= ISIG;
newtermio.c_cc[VINTR] = ctrl('C'); /* always use ^C for interrupts */
newtermio.c_cc[VEOF] = 1; /* minimum # characters to read */
newtermio.c_cc[VEOL] = 2; /* allow at least 0.2 seconds */
ioctl(2, TCSETAW, &newtermio);
#endif
#if BSD || UNIX7 || MINIX
struct tchars tbuf;
ospeed = oldsgttyb.sg_ospeed;
ERASEKEY = oldsgttyb.sg_erase;
newsgttyb = oldsgttyb;
newsgttyb.sg_flags |= CBREAK;
newsgttyb.sg_flags &= ~(CRMOD|ECHO|XTABS);
ioctl(2, TIOCSETP, &newsgttyb);
ioctl(2, TIOCGETC, &tbuf);
oldint = tbuf.t_intrc;
tbuf.t_intrc = ctrl('C'); /* always use ^C for interrupts */
ioctl(2, TIOCSETC, &tbuf);
#endif
if (has_TI) /* GB */
{
do_TI();
}
/* If we're supposed to quit quietly, then we're done */
if (quietly)
{
return;
}
signal(SIGINT, SIG_IGN);
move(LINES - 1, 0);
do_SO();
qaddstr("[Press <RETURN> to continue]");
do_SE();
refresh();
ttyread(kbuf, 20); /* in RAW mode, so <20 is very likely */
if (kbuf[0] == ':')
{
mode = MODE_COLON;
addch('\n');
refresh();
}
else
{
mode = MODE_VI;
redraw(MARK_UNSET, FALSE);
}
exwrote = FALSE;
#if TURBOC
signal(SIGINT, (void(*)()) trapint);
#else
signal(SIGINT, trapint);
#endif
}
static lacking(s)
char *s;
{
write(2, "This termcap entry lacks the :", 30);
write(2, s, 2);
write(2, "=: capability\n", 14);
exit(1);
}
starttcap()
{
char *str;
static char cbmem[800];
#define MUSTHAVE(T,s) if (!(T = tgetstr(s, &capbuf))) lacking(s)
#define MAYHAVE(T,s) if (str = tgetstr(s, &capbuf)) T = str
#define PAIR(T,U,sT,sU) T=tgetstr(sT,&capbuf);U=tgetstr(sU,&capbuf);if (!T||!U)T=U=""
/* allocate memory for capbuf */
capbuf = cbmem;
/* get the termcap entry */
switch (tgetent(kbuf, getenv("TERM")))
{
case -1:
write(2, "Can't read /etc/termcap\n", 24);
exit(2);
case 0:
write(2, "Unrecognized TERM type\n", 23);
exit(3);
}
/* get strings */
MUSTHAVE(UP, "up");
MAYHAVE(VB, "vb");
MUSTHAVE(CM, "cm");
PAIR(SO, SE, "so", "se");
PAIR(TI, TE, "ti", "te");
if (tgetnum("ug") <= 0)
{
PAIR(US, UE, "us", "ue");
PAIR(VB_s, VB_e, "VB", "Vb");
/* get italics, or have it default to underline */
PAIR(AS, AE, "as", "ae");
if (!*AS)
{
AS = US;
AE = UE;
}
}
MAYHAVE(AL, "al");
MAYHAVE(DL, "dl");
MUSTHAVE(CE, "ce");
MAYHAVE(CD, "cd");
MAYHAVE(SR, "sr");
PAIR(IM, EI, "im", "ei");
MAYHAVE(IC, "ic");
MAYHAVE(DC, "dc");
/* other termcap stuff */
AM = tgetflag("am");
PT = tgetflag("pt");
getsize(0);
/* Key sequences */
MAYHAVE(KU, "ku");
MAYHAVE(KD, "kd");
MAYHAVE(KL, "kl");
MAYHAVE(KR, "kr");
MAYHAVE(PU, "PU");
MAYHAVE(PD, "PD");
MAYHAVE(HM, "HM");
MAYHAVE(EN, "EN");
#ifndef NO_CURSORSHAPE
/* cursor shapes */
CQ = tgetstr("cQ", &capbuf);
if (has_CQ)
{
CX = tgetstr("cX", &capbuf);
if (!CX) CX = CQ;
CV = tgetstr("cV", &capbuf);
if (!CV) CV = CQ;
CI = tgetstr("cI", &capbuf);
if (!CI) CI = CQ;
CR = tgetstr("cR", &capbuf);
if (!CR) CR = CQ;
}
#endif
#undef MUSTHAVE
#undef MAYHAVE
#undef PAIR
}
/* This function gets the window size. It uses the TIOCGWINSZ ioctl call if
* your system has it, or tgetnum("li") and tgetnum("co") if it doesn't.
* This function is called once during initialization, and thereafter it is
* called whenever the SIGWINCH signal is sent to this process.
*/
getsize(signo)
int signo;
{
int lines;
int cols;
#ifdef TIOCGWINSZ
struct winsize size;
#endif
#ifdef SIGWINCH
/* reset the signal vector */
signal(SIGWINCH, getsize);
#endif
/* get the window size, one way or another. */
lines = cols = 0;
#ifdef TIOCGWINSZ
if (ioctl(2, TIOCGWINSZ, &size) >= 0)
{
lines = size.ws_row;
cols = size.ws_col;
}
#endif
if ((lines == 0 || cols == 0) && signo == 0)
{
LINES = CHECKBIOS(v_rows(), tgetnum("li"));
COLS = CHECKBIOS(v_cols(), tgetnum("co"));
}
if (lines >= 2 && cols >= 30)
{
LINES = lines;
COLS = cols;
}
/* Make sure we got values that we can live with */
if (LINES < 2 || COLS < 30)
{
write(2, "Screen too small\n", 17);
endwin();
exit(2);
}
/* !!! copy the new values into Elvis' options */
{
extern char o_columns[], o_lines[];
*o_columns = COLS;
*o_lines = LINES;
}
}
/* This is a function version of addch() -- it is used by tputs() */
int faddch(ch)
int ch;
{
addch(ch);
}
/* These functions are equivelent to the macros of the same names... */
void qaddstr(str)
char *str;
{
register char *s_, *d_;
#if MSDOS
if (o_pcbios[0])
{
while (*str)
qaddch(*str++);
return;
}
#endif
for (s_=(str), d_=stdscr; *d_++ = *s_++; )
{
}
stdscr = d_ - 1;
}
void attrset(a)
int a;
{
do_aend();
if (a == A_BOLD)
{
do_VB_s();
aend = VB_e;
}
else if (a == A_UNDERLINE)
{
do_US();
aend = UE;
}
else if (a == A_ALTCHARSET)
{
do_AS();
aend = AE;
}
else
{
aend = "";
}
}
void insch(ch)
int ch;
{
if (has_IM)
do_IM();
do_IC();
qaddch(ch);
if (has_EI)
do_EI();
}
#if MSDOS
static int alarmtime;
/* raw read - #defined to read (0, ...) on non-MSDOS.
* With MSDOS, am maximum of 1 byte is read.
* If more bytes should be read, just change the loop.
* The following code uses the IBM-PC-System-Timer, so probably wont't work
* on non-compatibles.
*/
/*ARGSUSED*/
ttyread(buf, len)
char *buf;
int len;
{
volatile char far *biostimer;
char oldtime;
int nticks = 0;
int pos = 0;
biostimer = (char far *)0x0040006cl;
oldtime = *biostimer;
while (!pos && (!alarmtime || nticks<alarmtime))
{ if (kbhit())
if ((buf[pos++] = getch()) == 0) /* function key */
buf[pos-1] = '#';
if (oldtime != *biostimer)
{ nticks++;
oldtime = *biostimer;
}
}
return pos;
}
alarm(time)
int time;
{
alarmtime = 2 * time; /* ticks are 1/18 sec. */
}
#endif
#if TOS
static int alarmtime;
static long timer;
static gettime()
{
timer = *(long *)(0x4ba);
}
/*ARGSUSED*/
ttyread(buf, len)
char *buf;
int len;
{
int pos=0;
long l;
long endtime;
Supexec(gettime);
endtime = timer+alarmtime;
while (!pos && (!alarmtime || timer<endtime))
{
if (Bconstat(2))
{
l = Bconin(2);
if ((buf[pos++]=l) == '\0')
{
buf[pos-1]='#';
buf[pos++]=l>>16;
}
}
Supexec(gettime);
}
return pos;
}
alarm(time)
int time;
{
alarmtime = 50 * time; /* ticks are 1/200 sec. */
}
ttywrite(buf, len)
char *buf;
int len;
{
while (len--)
Bconout(2, *buf++);
}
#endif
SHAR_EOF
fi
if test -f 'curses.h'
then
echo shar: "will not over-write existing file 'curses.h'"
else
cat << \SHAR_EOF > 'curses.h'
/* curses.h */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This is the header file for a small, fast, fake curses package */
/* termcap stuff */
extern char *tgoto();
extern char *tgetstr();
extern void tputs();
#if MSDOS
/* BIOS interface used instead of termcap for MS-DOS */
extern int vmode;
extern void v_up();
extern void v_cb();
extern void v_cs();
extern void v_ce();
extern void v_cl();
extern void v_cd();
extern void v_al();
extern void v_dl();
extern void v_sr();
extern void v_move();
#endif
/* faddch() is a function. a pointer to it is passed to tputs() */
extern int faddch();
/* data types */
#define WINDOW char
/* CONSTANTS & SYMBOLS */
#define TRUE 1
#define FALSE 0
#define A_NORMAL 0
#define A_STANDOUT 1
#define A_BOLD 2
#define A_UNDERLINE 3
#define A_ALTCHARSET 4
#if MSDOS
#define KBSIZ (10*1024)
#else
#define KBSIZ (6*1024)
#endif
/* extern variables, defined in curses.c */
extern short ospeed; /* tty speed, eg B2400 */
extern char PC; /* Pad char */
extern WINDOW *stdscr; /* pointer into kbuf[] */
extern WINDOW kbuf[KBSIZ]; /* a very large output buffer */
extern int LINES; /* :li#: number of rows */
extern int COLS; /* :co#: number of columns */
extern int AM; /* :am: boolean: auto margins? */
extern int PT; /* :pt: boolean: physical tabs? */
extern char *VB; /* :vb=: visible bell */
extern char *UP; /* :up=: move cursor up */
extern char *SO; /* :so=: standout start */
extern char *SE; /* :se=: standout end */
extern char *US; /* :us=: underline start */
extern char *UE; /* :ue=: underline end */
extern char *VB_s; /* :VB=: bold start */
extern char *VB_e; /* :Vb=: bold end */
extern char *AS; /* :as=: alternate (italic) start */
extern char *AE; /* :ae=: alternate (italic) end */
extern char *CM; /* :cm=: cursor movement */
extern char *CE; /* :ce=: clear to end of line */
extern char *CD; /* :cd=: clear to end of screen */
extern char *AL; /* :al=: add a line */
extern char *DL; /* :dl=: delete a line */
extern char *SR; /* :sr=: scroll reverse */
extern char *KU; /* :ku=: sequence sent by up key */
extern char *KD; /* :kd=: sequence sent by down key */
extern char *KL; /* :kl=: sequence sent by left key */
extern char *KR; /* :kr=: sequence sent by right key */
extern char *PU; /* :PU=: key sequence sent by PgUp key */
extern char *PD; /* :PD=: key sequence sent by PgDn key */
extern char *HM; /* :HM=: key sequence sent by Home key */
extern char *EN; /* :EN=: key sequence sent by End key */
extern char *IM; /* :im=: insert mode start */
extern char *IC; /* :ic=: insert following char */
extern char *EI; /* :ei=: insert mode end */
extern char *DC; /* :dc=: delete a character */
extern char *TI; /* :ti=: terminal init */ /* GB */
extern char *TE; /* :te=: terminal exit */ /* GB */
#ifndef NO_CURSORSHAPE
extern char *CQ; /* :cQ=: normal cursor */
extern char *CX; /* :cX=: cursor used for EX command/entry */
extern char *CV; /* :cV=: cursor used for VI command mode */
extern char *CI; /* :cI=: cursor used for VI input mode */
extern char *CR; /* :cR=: cursor used for VI replace mode */
#endif
extern char *aend; /* end an attribute -- either UE or VB_e */
extern char ERASEKEY; /* taken from the ioctl structure */
/* Msdos-versions may use bios; others always termcap.
* Will emit some 'code has no effect' warnings in unix.
*/
#if MSDOS
extern char o_pcbios[1]; /* BAH! */
#define CHECKBIOS(x,y) (*o_pcbios ? (x) : (y))
#define VOIDBIOS(x,y) {if (*o_pcbios) {x;} else {y;}}
#else
#define CHECKBIOS(x,y) (y)
#define VOIDBIOS(x,y) {y;}
#endif
#define do_VB() VOIDBIOS(0, tputs(VB, 1, faddch))
#define do_UP() VOIDBIOS(v_up(), tputs(UP, 1, faddch))
#define do_SO() VOIDBIOS((vmode=A_STANDOUT), tputs(SO, 1, faddch))
#define do_SE() VOIDBIOS((vmode=A_NORMAL), tputs(SE, 1, faddch))
#define do_US() VOIDBIOS((vmode=A_UNDERLINE), tputs(US, 1, faddch))
#define do_UE() VOIDBIOS((vmode=A_NORMAL), tputs(UE, 1, faddch))
#define do_VB_s() VOIDBIOS((vmode=A_BOLD), tputs(VB_s, 1, faddch))
#define do_VB_e() VOIDBIOS((vmode=A_NORMAL), tputs(VB_e, 1, faddch))
#define do_AS() VOIDBIOS((vmode=A_ALTCHARSET), tputs(AS, 1, faddch))
#define do_AE() VOIDBIOS((vmode=A_NORMAL), tputs(AE, 1, faddch))
#undef do_CM /* move */
#define do_CE() VOIDBIOS(v_ce(), tputs(CE, 1, faddch))
#define do_CD() VOIDBIOS(v_cd(), tputs(CD, 1, faddch))
#define do_AL() VOIDBIOS(v_al(), tputs(AL, LINES, faddch))
#define do_DL() VOIDBIOS(v_dl(), tputs(DL, LINES, faddch))
#define do_SR() VOIDBIOS(v_sr(), tputs(SR, 1, faddch))
#define do_IM() VOIDBIOS(0, tputs(IM, 1, faddch))
#define do_IC() VOIDBIOS(0, tputs(IC, 1, faddch))
#define do_EI() VOIDBIOS(0, tputs(EI, 1, faddch))
#define do_DC() VOIDBIOS(0, tputs(DC, COLS, faddch))
#define do_TI() VOIDBIOS(0, (void)ttywrite(TI, strlen(TI)))
#define do_TE() VOIDBIOS(0, (void)ttywrite(TE, strlen(TE)))
#ifndef NO_CURSORSHAPE
# define do_CQ() VOIDBIOS(v_cs(), tputs(CQ, 1, faddch))
# define do_CX() VOIDBIOS(v_cs(), tputs(CX, 1, faddch))
# define do_CV() VOIDBIOS(v_cs(), tputs(CV, 1, faddch))
# define do_CI() VOIDBIOS(v_cb(), tputs(CI, 1, faddch))
# define do_CR() VOIDBIOS(v_cb(), tputs(CR, 1, faddch))
#endif
#define do_aend() VOIDBIOS((vmode=A_NORMAL), tputs(aend, 1, faddch))
#define has_AM CHECKBIOS(1, AM)
#define has_PT CHECKBIOS(0, PT)
#define has_VB CHECKBIOS((char *)0, VB)
#define has_UP CHECKBIOS((char *)1, UP)
#define has_SO CHECKBIOS((char)1, (*SO))
#define has_SE CHECKBIOS((char)1, (*SE))
#define has_US CHECKBIOS((char)1, (*US))
#define has_UE CHECKBIOS((char)1, (*UE))
#define has_VB_s CHECKBIOS((char)1, (*VB_s))
#define has_VB_e CHECKBIOS((char)1, (*VB_e))
#define has_AS CHECKBIOS((char)1, (*AS))
#define has_AE CHECKBIOS((char)1, (*AE))
#undef has_CM /* cursor move: don't need */
#define has_CB CHECKBIOS(1, 0)
#define has_CS CHECKBIOS(1, 0)
#define has_CE CHECKBIOS((char *)1, CE)
#define has_CD CHECKBIOS((char *)1, CD)
#define has_AL CHECKBIOS((char *)1, AL)
#define has_DL CHECKBIOS((char *)1, DL)
#define has_SR CHECKBIOS((char *)1, SR)
#define has_KU CHECKBIOS("#H", KU)
#define has_KD CHECKBIOS("#P", KD)
#define has_KL CHECKBIOS("#K", KL)
#define has_KR CHECKBIOS("#M", KR)
#define has_HM CHECKBIOS("#G", HM)
#define has_EN CHECKBIOS("#O", EN)
#define has_PU CHECKBIOS("#I", PU)
#define has_PD CHECKBIOS("#Q", PD)
#define has_IM CHECKBIOS((char)0, (*IM))
#define has_IC CHECKBIOS((char)0, (*IC))
#define has_EI CHECKBIOS((char)0, (*EI))
#define has_DC CHECKBIOS((char *)0, DC)
#define has_TI CHECKBIOS((char)0, (*TI))
#define has_TE CHECKBIOS((char)0, (*TE))
#ifndef NO_CURSORSHAPE
#define has_CQ CHECKBIOS((char *)1, CQ)
#endif
/* (pseudo)-Curses-functions */
#define _addCR (void)CHECKBIOS(0, (stdscr[-1] == '\n' ? qaddch('\r') : 0))
#define qaddch(ch) CHECKBIOS(v_put(ch), (*stdscr++ = (ch)))
#define addch(ch) if (qaddch(ch) == '\n') qaddch('\r'); else
extern void attrset();
extern void insch();
extern void qaddstr();
#define addstr(str) {qaddstr(str); _addCR;}
#define move(y,x) VOIDBIOS(v_move(x,y), \
tputs(tgoto(CM, x, y), 1, faddch))
#define mvaddch(y,x,ch) {move(y,x); addch(ch);}
#define refresh() VOIDBIOS(0, wrefresh(stdscr))
#define wrefresh(w) if ((w) != kbuf) VOIDBIOS((w) = kbuf, {ttywrite(kbuf, (int)((w) - kbuf)); (w) = kbuf;}) else
#define wqrefresh(w) if ((w) - kbuf > 2000) VOIDBIOS((w) = kbuf, {ttywrite(kbuf, (int)((w) - kbuf)); (w) = kbuf;}) else
#define standout() do_SO()
#define standend() do_SE()
#define clrtoeol() do_CE()
#define clrtobot() do_CD()
#define insertln() do_AL()
#define deleteln() do_DL()
#define delch() do_DC()
#define scrollok(w,b)
#define raw()
#define echo()
#define cbreak()
#define noraw()
#define noecho()
#define nocbreak()
SHAR_EOF
fi
if test -f 'cut.c'
then
echo shar: "will not over-write existing file 'cut.c'"
else
cat << \SHAR_EOF > 'cut.c'
/* cut.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This file contains function which manipulate the cut buffers. */
#include "config.h"
#include "vi.h"
#if TURBOC
#include <process.h> /* needed for getpid */
#endif
#if TOS
#include <osbind.h>
#define rename(a,b) Frename(0,a,b)
#endif
# define NANNONS 9 /* number of annonymous buffers */
static struct cutbuf
{
short *phys; /* pointer to an array of #s of BLKs containing text */
int nblks; /* number of blocks in phys[] array */
int start; /* offset into first block of start of cut */
int end; /* offset into last block of end of cut */
int fd; /* fd of tmp file, or -1 to use tmpfd */
char lnmode; /* boolean: line-mode cut? (as opposed to char-mode) */
}
named[27], /* cut buffers "a through "z and ". */
annon[NANNONS]; /* annonymous cut buffers */
static char cbname; /* name chosen for next cut/paste operation */
#ifndef NO_RECYCLE
/* This function builds a list of all blocks needed in the current tmp file
* for the contents of cut buffers.
* !!! WARNING: if you have more than ~450000 bytes of text in all of the
* cut buffers, then this will fail disastrously, because buffer overflow
* is *not* allowed for.
*/
int cutneeds(need)
BLK *need; /* this is where we deposit the list */
{
struct cutbuf *cb; /* used to count through cut buffers */
int i; /* used to count through blocks of a cut buffer */
int n; /* total number of blocks in list */
n = 0;
/* first the named buffers... */
for (cb = named; cb < &named[27]; cb++)
{
if (cb->fd > 0)
continue;
for (i = cb->nblks; i-- > 0; )
{
need->n[n++] = cb->phys[i];
}
}
/* then the anonymous buffers */
for (cb = annon; cb < &annon[NANNONS]; cb++)
{
if (cb->fd > 0)
continue;
for (i = cb->nblks; i-- > 0; )
{
need->n[n++] = cb->phys[i];
}
}
return n;
}
#endif
/* This function is called when we are about to abort a tmp file. If any
* cut buffers still need the file, then a copy of the file should be
* created for use by the cut buffers.
*
* To minimize the number of extra files lying around, only named cut buffers
* are preserved in a file switch; the annonymous buffers just go away.
*/
cutswitch(tmpname)
char *tmpname; /* name of the tmp file */
{
char cutname[50]; /* used to build a new name for the tmp file */
int fd; /* a new fd for the current tmp file */
int i, j;
/* discard all annonymous cut buffers */
for (i = 0; i < NANNONS; i++)
{
cutfree(&annon[i]);
}
/* find the first named buffer that uses this tmp file */
for (i = 0; i < 27; i++)
{
if (named[i].nblks > 0 && named[i].fd < 0)
{
break;
}
}
/* if none of them use this tmp file, then we're done */
if (i == 27)
{
return;
}
/* else we'll need this file and an fd a little longer */
/* !!! we could use some error checking here */
#if TOS
/* Hack! Tos allows dup for standard handles only. */
fd = tmpfd;
tmpfd = -1;
#else
fd = dup(tmpfd);
#endif
#if MSDOS || TOS
strcpy(cutname, o_directory);
if ((j = strlen(cutname)) && !strchr(":/\\", cutname[j-1]))
cutname[j++]=SLASH;
sprintf(cutname+j, CUTNAME+3, getpid(), fd);
rename(tmpname, cutname);
#else
sprintf(cutname, CUTNAME, o_directory, getpid(), fd);
link(tmpname, cutname) || unlink(tmpname);
#endif
/* have all cut buffers use the new fd instead */
for (; i < 27; i++)
{
if (named[i].nblks > 0 && named[i].fd < 0)
{
named[i].fd = fd;
}
}
}
/* This function frees a cut buffer */
static cutfree(buf)
struct cutbuf *buf;
{
char cutname[50];
int i;
/* return immediately if the buffer is already empty */
if (buf->nblks <= 0)
{
return;
}
/* else free up stuff */
buf->nblks = 0;
free(buf->phys);
/* see if anybody else needs this tmp file */
if (buf->fd >= 0)
{
for (i = 0; i < 27; i++)
{
#if 0
if (named[i].nblks > 0 && named[i].fd >= 0)
#else
if (named[i].nblks > 0 && named[i].fd == buf->fd)
#endif
{
break;
}
}
}
/* if nobody else needs it, then discard the tmp file */
if (buf->fd >= 0 && i == 27)
{
close(buf->fd);
#if MSDOS || TOS
strcpy(cutname, o_directory);
if ((i = strlen(cutname)) && !strchr(":/\\", cutname[i-1]))
cutname[i++]=SLASH;
sprintf(cutname+i, CUTNAME+3, getpid(), buf->fd);
#else
sprintf(cutname, CUTNAME, o_directory, getpid(), buf->fd);
#endif
unlink(cutname);
}
}
/* This function should be called just before termination of vi */
cutend()
{
int i;
/* free all named cut buffers, since they might be forcing an older
* tmp file to be retained.
*/
for (i = 0; i < 27; i++)
{
cutfree(&named[i]);
}
}
/* This function is used to select the cut buffer to be used next */
cutname(name)
int name; /* a single character */
{
cbname = name;
}
/* This function copies a selected segment of text to a cut buffer */
cut(from, to)
MARK from; /* start of text to cut */
MARK to; /* end of text to cut */
{
int first; /* logical number of first block in cut */
int last; /* logical number of last block used in cut */
long line; /* a line number */
register struct cutbuf *cb;
register long l;
register int i;
register char *scan;
char *blkc;
/* decide which cut buffer to use */
if (!cbname)
{
/* free up the last annonymous cut buffer */
cutfree(&annon[NANNONS - 1]);
/* shift the annonymous cut buffers */
for (i = NANNONS - 1; i > 0; i--)
{
annon[i] = annon[i - 1];
}
/* use the first annonymous cut buffer */
cb = annon;
cb->nblks = 0;
}
else if (cbname >= 'a' && cbname <= 'z')
{
cb = &named[cbname - 'a'];
cutfree(cb);
}
else if (cbname == '.')
{
cb = &named[26];
cutfree(cb);
}
else
{
msg("Invalid cut buffer name: \"%c", cbname);
cbname = '\0';
return;
}
cbname = '\0';
cb->fd = -1;
/* detect whether we're doing a line mode cut */
cb->lnmode = (markidx(from) == 0 && markidx(to) == 0);
/* ---------- */
/* Reporting... */
if (markidx(from) == 0 && markidx(to) == 0)
{
rptlines = markline(to) - markline(from);
rptlabel = "yanked";
}
/* ---------- */
blksync();
/* find the first block in the cut */
line = markline(from);
for (first = 1; line > lnum[first]; first++)
{
}
/* fetch text of the block containing that line */
blkc = scan = blkget(first)->c;
/* find the mark in the block */
for (l = lnum[first - 1]; ++l < line; )
{
while (*scan++ != '\n')
{
}
}
scan += markidx(from);
/* remember the offset of the start */
cb->start = scan - blkc;
/* ---------- */
/* find the last block in the cut */
line = markline(to);
for (last = first; line > lnum[last]; last++)
{
}
/* fetch text of the block containing that line */
if (last != first)
{
blkc = scan = blkget(last)->c;
}
else
{
scan = blkc;
}
/* find the mark in the block */
for (l = lnum[last - 1]; ++l < line; )
{
while (*scan++ != '\n')
{
}
}
if (markline(to) <= nlines)
{
scan += markidx(to);
}
/* remember the offset of the end */
cb->end = scan - blkc;
/* ------- */
/* remember the physical block numbers of all included blocks */
cb->nblks = last - first;
if (cb->end > 0)
{
cb->nblks++;
}
cb->phys = (short *)malloc((unsigned)(cb->nblks * sizeof(short)));
for (i = 0; i < cb->nblks; i++)
{
cb->phys[i] = hdr.n[first++];
}
}
static readcutblk(cb, blkno)
struct cutbuf *cb;
int blkno;
{
int fd; /* either tmpfd or cb->fd */
/* decide which fd to use */
if (cb->fd >= 0)
{
fd = cb->fd;
}
else
{
fd = tmpfd;
}
/* get the block */
lseek(fd, (long)cb->phys[blkno] * (long)BLKSIZE, 0);
if (read(fd, tmpblk.c, BLKSIZE) != BLKSIZE)
{
msg("Error reading back from tmp file for pasting!");
}
}
/* This function inserts text from a cut buffer, and returns the MARK where
* insertion ended. Return MARK_UNSET on errors.
*/
MARK paste(at, after, retend)
MARK at; /* where to insert the text */
int after; /* boolean: insert after mark? (rather than before) */
int retend; /* boolean: return end marker (rather than start) */
{
register struct cutbuf *cb;
register int i;
/* decide which cut buffer to use */
if (cbname >= 'a' && cbname <= 'z')
{
cb = &named[cbname - 'a'];
}
else if (cbname >= '1' && cbname <= '9')
{
cb = &annon[cbname - '1'];
}
else if (cbname == '.')
{
cb = &named[26];
}
else if (!cbname)
{
cb = annon;
}
else
{
msg("Invalid cut buffer name: \"%c", cbname);
return MARK_UNSET;
}
/* make sure it isn't empty */
if (cb->nblks == 0)
{
if (cbname)
msg("Cut buffer \"%c is empty", cbname);
else
msg("Cut buffer is empty");
cbname = '\0';
return MARK_UNSET;
}
cbname = '\0';
/* adjust the insertion MARK for "after" and line-mode cuts */
if (cb->lnmode)
{
at &= ~(BLKSIZE - 1);
if (after)
{
at += BLKSIZE;
}
}
else if (after)
{
/* careful! if markidx(at) == 0 we might be pasting into an
* empty line -- so we can't blindly increment "at".
*/
if (markidx(at) == 0)
{
pfetch(markline(at));
if (plen != 0)
{
at++;
}
}
else
{
at++;
}
}
/* put a copy of the "at" mark in the mark[] array, so it stays in
* sync with changes made via add().
*/
mark[27] = at;
/* simple one-block paste? */
if (cb->nblks == 1)
{
/* get the block */
readcutblk(cb, 0);
/* isolate the text we need within it */
if (cb->end)
{
tmpblk.c[cb->end] = '\0';
}
/* insert it */
ChangeText
{
add(at, &tmpblk.c[cb->start]);
}
}
else
{
/* multi-block paste */
ChangeText
{
i = cb->nblks - 1;
/* add text from the last block first */
if (cb->end > 0)
{
readcutblk(cb, i);
tmpblk.c[cb->end] = '\0';
add(at, tmpblk.c);
i--;
}
/* add intervening blocks */
while (i > 0)
{
readcutblk(cb, i);
add(at, tmpblk.c);
i--;
}
/* add text from the first cut block */
readcutblk(cb, 0);
add(at, &tmpblk.c[cb->start]);
}
}
/* Reporting... */
rptlines = markline(mark[27]) - markline(at);
rptlabel = "pasted";
/* correct the redraw range */
redrawafter = preredraw = markline(at);
postredraw = markline(mark[27]);
/* return the mark at the beginning of inserted text */
if (retend)
{
return mark[27] - 1L;
}
return at;
}
SHAR_EOF
fi
if test -f 'elvis.ndx'
then
echo shar: "will not over-write existing file 'elvis.ndx'"
else
cat << \SHAR_EOF > 'elvis.ndx'
@@@@@@@ @ @ @ @@@ @@@@@
@ @ @ @ @ @ @
@ @ @ @ @ @
@@@@@ @ @ @ @ @@@@@
@ @ @ @ @ @
@ @ @ @ @ @ @
@@@@@@@ @@@@@@@ @ @@@ @@@@@
- a clone of vi/ex -
version 1.3
Author: Steve Kirkendall
9665 SW Serena Way
Beaverton, OR 97007
E-Mail: kirkenda at cs.pdx.edu
or ...uunet!tektronix!psueea!eecs!kirkenda
Phone: (503) 642-9905
Introduction .................................................. 1
Overview of Elvis ........................................... 1
Visual Mode Commands .......................................... 2
Input Mode .................................................. 5
Arrow keys in Input Mode .................................... 5
Digraphs .................................................... 6
Colon Mode Commands ........................................... 7
Line Specifiers ............................................. 8
Text Entry Commands ......................................... 9
Cut & Paste Commands ........................................ 9
Display Text Commands ....................................... 9
Global Operations Commands .................................. 10
Line Editing Commands ....................................... 10
Undo Command ................................................ 10
Configuration & Status Commands ............................. 10
Multiple File Commands ...................................... 12
Switching Files Commands .................................... 12
Exit Commands ............................................... 12
File I/O Commands ........................................... 13
Directory Commands .......................................... 13
Debugging Commands .......................................... 13
Regular Expressions ........................................... 14
Syntax ...................................................... 14
Options ..................................................... 14
Substitutions ............................................... 15
Options ....................................................... 16
autoindent .................................................. 17
autowrite ................................................... 17
charattr .................................................... 17
columns ..................................................... 17
directory ................................................... 17
errorbells .................................................. 18
exrefresh ................................................... 18
hideformat .................................................. 18
ignorecase .................................................. 18
inputmode ................................................... 18
keytime ..................................................... 18
keywordprg .................................................. 19
lines ....................................................... 19
list ........................................................ 19
magic ....................................................... 20
paragraphs .................................................. 20
readonly .................................................... 20
report ...................................................... 20
scroll ...................................................... 21
sections .................................................... 21
shell ....................................................... 21
shiftwidth .................................................. 21
showmode .................................................... 21
sidescroll .................................................. 21
sync ........................................................ 22
tabstop ..................................................... 22
term ........................................................ 22
vbell ....................................................... 22
warn ........................................................ 22
wrapmargin .................................................. 23
wrapscan .................................................... 23
Programs ...................................................... 24
elvis, ex, vi, view, input - The editor ..................... 24
ctags - Generates "tags" and (optionally) "refs" files ...... 24
ref - Display a C function header ........................... 25
virec - Recover the modified version after a crash .......... 25
Differences between elvis and the real vi/ex .................. 26
Extensions .................................................. 26
Omissions ................................................... 28
Internal ...................................................... 29
The temporary file .......................................... 29
Implementation of Editing ................................... 29
Marks and the Cursor ........................................ 30
Colon Command Interpretation ................................ 30
Screen Control .............................................. 31
Portability ................................................. 31
CFLAGS ........................................................ 32
-DM_SYSV, -DTOS, -DOS9 ...................................... 32
-DDATE ...................................................... 32
-DNBUFS ..................................................... 32
-DBLKSIZE ................................................... 32
-DTMPDIR .................................................... 33
-DEXRC -DHMEXRC -DSYSEXRC ................................... 33
-DKEYWORDPRG ................................................ 33
-DDEBUG ..................................................... 33
-DNO_CHARATTR ............................................... 33
-DNO_RECYCLE ................................................ 33
-DNO_SENTENCE ............................................... 34
-DNO_CHARSEARCH ............................................. 34
-DNO_EXTENSIONS ............................................. 34
-DNO_MAGIC .................................................. 34
-DNO_SHOWMODE ............................................... 34
-DNO_CURSORSHAPE ............................................ 34
-DNO_DIGRAPH ................................................ 35
Termcap ....................................................... 36
Required numeric capabilities ............................... 36
Required string capabilities ................................ 36
Boolean capabilities ........................................ 36
Optional string capabilities ................................ 36
Optional strings received from the keyboard ................. 36
Optional capabilities that describe character attributes .... 37
Optional capabilities that affect the shape of the cursor ... 37
An example .................................................. 37
Environment Variables ......................................... 38
TERM, TERMCAP ............................................... 38
TMP, TEMP ................................................... 38
EXINIT ...................................................... 38
SHELL, COMSPEC .............................................. 38
HOME ........................................................ 38
Versions ...................................................... 39
BSD UNIX .................................................... 39
System-V UNIX ............................................... 39
SCO Xenix ................................................... 39
Minix ....................................................... 40
MS-DOS ...................................................... 40
Atari TOS ................................................... 41
SHAR_EOF
fi
if test -f 'ex.c'
then
echo shar: "will not over-write existing file 'ex.c'"
else
cat << \SHAR_EOF > 'ex.c'
/* ex.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This file contains the code for reading ex commands. */
#include "config.h"
#include <ctype.h>
#include "vi.h"
#ifndef isascii
# define isascii(c) !((c)&~0x7f)
#endif
/* This data type is used to describe the possible argument combinations */
typedef short ARGT;
#define FROM 1 /* allow a linespec */
#define TO 2 /* allow a second linespec */
#define BANG 4 /* allow a ! after the command name */
#define EXTRA 8 /* allow extra args after command name */
#define XFILE 16 /* expand wildcards in extra part */
#define NOSPC 32 /* no spaces allowed in the extra part */
#define DFLALL 64 /* default file range is 1,$ */
#define DFLNONE 128 /* no default file range */
#define NODFL 256 /* do not default to the current file name */
#define EXRCOK 512 /* can be in a .exrc file */
#define FILES (XFILE + EXTRA) /* multiple extra files allowed */
#define WORD1 (EXTRA + NOSPC) /* one extra word allowed */
#define FILE1 (FILES + NOSPC) /* 1 file allowed, defaults to current file */
#define NAMEDF (FILE1 + NODFL) /* 1 file allowed, defaults to "" */
#define NAMEDFS (FILES + NODFL) /* multiple files allowed, default is "" */
#define RANGE (FROM + TO) /* range of linespecs allowed */
#define NONE 0 /* no args allowed at all */
/* This array maps ex command names to command codes. The order in which
* command names are listed below is significant -- ambiguous abbreviations
* are always resolved to be the first possible match. (e.g. "r" is taken
* to mean "read", not "rewind", because "read" comes before "rewind")
*/
static struct
{
char *name; /* name of the command */
CMD code; /* enum code of the command */
void (*fn)();/* function which executes the command */
ARGT argt; /* command line arguments permitted/needed/used */
}
cmdnames[] =
{ /* cmd name cmd code function arguments */
{"append", CMD_APPEND, cmd_append, FROM },
#ifdef DEBUG
{"bug", CMD_DEBUG, cmd_debug, RANGE+BANG+EXTRA},
#endif
{"change", CMD_CHANGE, cmd_append, RANGE },
{"delete", CMD_DELETE, cmd_delete, RANGE+WORD1 },
{"edit", CMD_EDIT, cmd_edit, BANG+FILE1 },
{"file", CMD_FILE, cmd_file, NONE },
{"global", CMD_GLOBAL, cmd_global, RANGE+BANG+EXTRA+DFLALL},
{"insert", CMD_INSERT, cmd_append, FROM },
{"join", CMD_INSERT, cmd_join, RANGE },
{"k", CMD_MARK, cmd_mark, FROM+WORD1 },
{"list", CMD_LIST, cmd_list, RANGE },
{"move", CMD_MOVE, cmd_move, RANGE+EXTRA },
{"next", CMD_NEXT, cmd_next, BANG+NAMEDFS },
{"Next", CMD_PREVIOUS, cmd_next, BANG },
{"print", CMD_PRINT, cmd_print, RANGE },
{"quit", CMD_QUIT, cmd_quit, BANG },
{"read", CMD_READ, cmd_read, FROM+BANG+NAMEDF},
{"substitute", CMD_SUBSTITUTE, cmd_substitute, RANGE+EXTRA },
{"to", CMD_COPY, cmd_move, RANGE+EXTRA },
{"undo", CMD_UNDO, cmd_undo, NONE },
{"vglobal", CMD_VGLOBAL, cmd_global, RANGE+EXTRA+DFLALL},
{"write", CMD_WRITE, cmd_write, RANGE+BANG+FILE1+DFLALL},
{"xit", CMD_XIT, cmd_xit, BANG },
{"yank", CMD_YANK, cmd_delete, RANGE+WORD1 },
{"!", CMD_BANG, cmd_shell, EXRCOK+RANGE+NAMEDFS+DFLNONE},
{"<", CMD_SHIFTL, cmd_shift, RANGE },
{">", CMD_SHIFTR, cmd_shift, RANGE },
{"=", CMD_FILE, cmd_file, RANGE },
{"args", CMD_ARGS, cmd_args, EXRCOK+NAMEDFS },
{"cd", CMD_CD, cmd_cd, EXRCOK+NAMEDF },
{"copy", CMD_COPY, cmd_move, RANGE+EXTRA },
#ifndef NO_DIGRAPH
{"digraph", CMD_DIGRAPH, cmd_digraph, EXRCOK+BANG+EXTRA},
#endif
{"ex", CMD_EDIT, cmd_edit, BANG+FILE1 },
{"map", CMD_MAP, cmd_map, EXRCOK+BANG+EXTRA},
#ifndef NO_EXTENSIONS
{"mkexrc", CMD_MKEXRC, cmd_mkexrc, NONE },
#endif
{"put", CMD_PUT, cmd_put, FROM+WORD1 },
{"set", CMD_SET, cmd_set, EXRCOK+EXTRA },
{"shell", CMD_SHELL, cmd_shell, NONE },
{"source", CMD_SOURCE, cmd_source, EXRCOK+NAMEDF },
{"tag", CMD_TAG, cmd_tag, BANG+WORD1 },
{"version", CMD_VERSION, cmd_version, EXRCOK+NONE },
{"visual", CMD_VISUAL, cmd_visual, NONE },
{"wq", CMD_WQUIT, cmd_xit, NONE },
#ifdef DEBUG
{"debug", CMD_DEBUG, cmd_debug, RANGE+BANG+EXTRA},
{"validate", CMD_VALIDATE, cmd_validate, BANG },
#endif
{"chdir", CMD_CD, cmd_cd, EXRCOK+NAMEDF },
{"mark", CMD_MARK, cmd_mark, FROM+WORD1 },
{"previous", CMD_PREVIOUS, cmd_next, BANG },
{"rewind", CMD_REWIND, cmd_next, BANG },
{"unmap", CMD_UNMAP, cmd_map, EXRCOK+BANG+EXTRA},
{(char *)0}
};
/* This function parses a search pattern - given a pointer to a / or ?,
* it replaces the ending / or ? with a \0, and returns a pointer to the
* stuff that came after the pattern.
*/
char *parseptrn(ptrn)
register char *ptrn;
{
register char *scan;
for (scan = ptrn + 1;
*scan && *scan != *ptrn;
scan++)
{
/* allow backslashed versions of / and ? in the pattern */
if (*scan == '\\' && scan[1] != '\0')
{
scan++;
}
}
if (*scan)
{
*scan++ = '\0';
}
return scan;
}
/* This function parses a line specifier for ex commands */
char *linespec(s, markptr)
register char *s; /* start of the line specifier */
MARK *markptr; /* where to store the mark's value */
{
long num;
register char *t;
/* parse each ;-delimited clause of this linespec */
do
{
/* skip an initial ';', if any */
if (*s == ';')
{
s++;
}
/* skip leading spaces */
while (isascii(*s) && isspace(*s))
{
s++;
}
/* dot means current position */
if (*s == '.')
{
s++;
*markptr = cursor;
}
/* '$' means the last line */
else if (*s == '$')
{
s++;
*markptr = m_toline(cursor, nlines);
}
/* digit means an absolute line number */
else if (isascii(*s) && isdigit(*s))
{
for (num = 0; isascii(*s) && isdigit(*s); s++)
{
num = num * 10 + *s - '0';
}
*markptr = m_toline(cursor, num);
}
/* appostrophe means go to a set mark */
else if (*s == '\'')
{
s++;
*markptr = m_tomark(cursor, 1L, (int)*s);
s++;
}
/* slash means do a search */
else if (*s == '/' || *s == '?')
{
/* put a '\0' at the end of the search pattern */
t = parseptrn(s);
/* search for the pattern */
if (*s == '/')
{
pfetch(markline(*markptr));
*markptr = (*markptr & ~(BLKSIZE - 1)) + plen - 1;
*markptr = m_fsrch(*markptr, s + 1);
}
else
{
*markptr &= ~(BLKSIZE - 1);
*markptr = m_bsrch(*markptr, s + 1);
}
/* adjust command string pointer */
s = t;
}
/* if linespec was faulty, quit now */
if (!*markptr)
{
return s;
}
/* maybe add an offset */
if (*s == '-')
{
s++;
for (num = 0; *s >= '0' && *s <= '9'; s++)
{
num = num * 10 + *s - '0';
}
if (num == 0)
{
num = 1;
}
*markptr = m_up(*markptr, num);
}
else if (*s == '+')
{
s++;
for (num = 0; *s >= '0' && *s <= '9'; s++)
{
num = num * 10 + *s - '0';
}
if (num == 0)
{
num = 1;
}
*markptr = m_down(*markptr, num);
}
} while (*s == ';' || *s == '+' || *s == '-');
return s;
}
/* This function reads an ex command and executes it. */
ex()
{
char cmdbuf[80];
register int cmdlen;
/* read a line */
cmdlen = vgets(':', cmdbuf, sizeof cmdbuf);
if (cmdlen < 0)
{
return;
}
addch('\n');
refresh();
/* if empty line, assume ".+1" */
if (cmdlen == 0)
{
strcpy(cmdbuf, ".+1");
}
/* parse & execute the command */
doexcmd(cmdbuf);
}
doexcmd(cmdbuf)
char *cmdbuf; /* string containing an ex command */
{
register char *scan; /* used to scan thru cmdbuf */
MARK frommark; /* first linespec */
MARK tomark; /* second linespec */
register int cmdlen; /* length of the command name given */
CMD cmd; /* what command is this? */
ARGT argt; /* argument types for this command */
short forceit; /* bang version of a command? */
register int cmdidx; /* index of command */
register char *build; /* used while copying filenames */
int iswild; /* boolean: filenames use wildcards? */
int isdfl; /* using default line ranges? */
int didsub; /* did we substitute file names for % or # */
/* ex commands can't be undone via the shift-U command */
U_line = 0L;
/* ignore command lines that start with "#" */
if (*cmdbuf == '#' || *cmdbuf == '"')
{
return;
}
/* permit extra colons at the start of the line */
while (*cmdbuf == ':')
{
cmdbuf++;
}
/* parse the line specifier */
scan = cmdbuf;
if (nlines < 1)
{
/* no file, so don't allow addresses */
}
else if (*scan == '%')
{
/* '%' means all lines */
frommark = m_toline(cursor, 1L);
tomark = m_toline(cursor, nlines);
scan++;
}
else
{
frommark = cursor;
scan = linespec(scan, &frommark);
tomark = frommark;
if (frommark && *scan == ',')
{
scan++;
scan = linespec(scan, &tomark);
}
if (!tomark)
{
/* faulty line spec -- fault already described */
return;
}
if (frommark > tomark)
{
msg("first address exceeds the second");
return;
}
}
isdfl = (scan == cmdbuf);
/* skip whitespace */
while (isascii(*scan) && isspace(*scan))
{
scan++;
}
/* if no command, then just move the cursor to the mark & print */
if (!*scan)
{
cursor = tomark;
if (mode != MODE_EX)
{
return;
}
scan = "p";
}
/* figure out how long the command name is */
if (isascii(*scan) && !isalpha(*scan))
{
cmdlen = 1;
}
else
{
for (cmdlen = 1;
!isascii(scan[cmdlen]) || isalpha(scan[cmdlen]);
cmdlen++)
{
}
}
/* lookup the command code */
for (cmdidx = 0;
cmdnames[cmdidx].name && strncmp(scan, cmdnames[cmdidx].name, cmdlen);
cmdidx++)
{
}
argt = cmdnames[cmdidx].argt;
cmd = cmdnames[cmdidx].code;
if (cmd == CMD_NULL)
{
msg("Unknown command \"%.*s\"", cmdlen, scan);
return;
}
/* if the command ended with a bang, set the forceit flag */
scan += cmdlen;
if ((argt & BANG) && *scan == '!')
{
scan++;
forceit = 1;
}
else
{
forceit = 0;
}
/* skip any more whitespace, to leave scan pointing to arguments */
while (isascii(*scan) && isspace(*scan))
{
scan++;
}
/* a couple of special cases for filenames */
if (argt & XFILE)
{
/* if names were given, process them */
if (*scan)
{
for (build = tmpblk.c, iswild = didsub = FALSE; *scan; scan++)
{
switch (*scan)
{
case '%':
if (!*origname)
{
msg("No filename to substitute for %");
return;
}
strcpy(build, origname);
while (*build)
{
build++;
}
didsub = TRUE;
break;
case '#':
if (!*prevorig)
{
msg("No filename to substitute for #");
return;
}
strcpy(build, prevorig);
while (*build)
{
build++;
}
didsub = TRUE;
break;
case '*':
case '?':
#if ! (MSDOS || TOS)
case '[':
case '`':
case '{': /* } */
case '$':
case '~':
#endif
*build++ = *scan;
iswild = TRUE;
break;
default:
*build++ = *scan;
}
}
*build = '\0';
if (cmd == CMD_BANG
|| cmd == CMD_READ && (forceit || tmpblk.c[0] != '!'))
{
if (didsub)
{
addch('\n');
addstr(tmpblk.c);
addch('\n');
exrefresh();
}
}
else
{
if (iswild && tmpblk.c[0] != '>')
{
scan = wildcard(tmpblk.c);
}
}
}
else /* no names given, maybe assume origname */
{
if (!(argt & NODFL))
{
strcpy(tmpblk.c, origname);
}
else
{
*tmpblk.c = '\0';
}
}
scan = tmpblk.c;
}
/* bad arguments? */
if (!(argt & EXRCOK) && nlines < 1L)
{
msg("Can't use the \"%s\" command in a %s file", cmdnames[cmdidx].name, EXRC);
return;
}
if (!(argt & FROM) && frommark != cursor && nlines >= 1L)
{
msg("Can't use address with \"%s\" command.", cmdnames[cmdidx].name);
return;
}
if (!(argt & TO) && tomark != frommark && nlines >= 1L)
{
msg("Can't use a range with \"%s\" command.", cmdnames[cmdidx].name);
return;
}
if (!(argt & EXTRA) && *scan)
{
msg("Extra characters after \"%s\" command.", cmdnames[cmdidx].name);
return;
}
if ((argt & NOSPC) && !(cmd == CMD_READ && (forceit || *scan == '!')))
{
for (build = scan; *build; build++)
{
if (isspace(*build))
{
msg("Too many %s to \"%s\" command.",
(argt & XFILE) ? "filenames" : "arguments",
cmdnames[cmdidx].name);
return;
}
}
}
/* some commands have special default ranges */
if (isdfl && (argt & DFLALL))
{
frommark = MARK_FIRST;
tomark = MARK_LAST;
}
else if (isdfl && (argt & DFLNONE))
{
frommark = tomark = 0L;
}
/* act on the command */
(*cmdnames[cmdidx].fn)(frommark, tomark, cmd, forceit, scan);
}
/* This function executes EX commands from a file. It returns 1 normally, or
* 0 if the file could not be opened for reading.
*/
int doexrc(filename)
char *filename; /* name of a ".exrc" file */
{
int fd; /* file descriptor */
int len; /* length of the ".exrc" file */
char *cmd; /* start of a command */
char *end; /* used to search for the end of cmd */
char buf[MAXRCLEN]; /* buffer, holds the entire .exrc file */
/* open the file, read it, and close */
fd = open(filename, O_RDONLY);
if (fd < 0)
{
return 0;
}
len = tread(fd, buf, MAXRCLEN);
close(fd);
/* find & do each command */
for (cmd = buf; cmd < &buf[len]; cmd = end + 1)
{
/* find the end of the command */
for (end = cmd; *end != '\n'; end++)
{
}
*end = '\0';
/* do it */
doexcmd(cmd);
}
return 1;
}
SHAR_EOF
fi
if test -f 'input.c'
then
echo shar: "will not over-write existing file 'input.c'"
else
cat << \SHAR_EOF > 'input.c'
/* input.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This file contains the input() function, which implements vi's INPUT mode.
* It also contains the code that supports digraphs.
*/
#include <ctype.h>
#include "config.h"
#include "vi.h"
#ifndef NO_DIGRAPH
static struct
{
char key1;
char key2;
char dig;
} digs[MAXDIGS];
static char digraph(key1, key2)
char key1; /* the first character (punctuation) */
char key2; /* the overtyped character (probably a letter) */
{
int i;
/* can only be a digraph if key1 is punctuation */
if (!isascii(key1) || !ispunct(key1))
{
return key2;
}
/* scan through the digraph chart */
for (i = 0;
i < MAXDIGS && (!digs[i].dig || digs[i].key1 != key1 || digs[i].key2 != key2);
i++)
{
}
/* if this combination isn't in there, just use the new key */
if (i >= MAXDIGS)
{
return key2;
}
/* else use the digraph key */
return digs[i].dig;
}
do_digraph(bang, args)
int bang;
char args[];
{
int i;
int dig;
/* if no args, then display the existing digraphs */
if (*args < ' ')
{
for (i = 0; i < MAXDIGS; i++)
{
if (digs[i].dig)
{
msg("digraph %c%c %c", digs[i].key1, digs[i].key2, digs[i].dig);
}
}
return;
}
/* first character of a digraph must be punctuation */
if (!isascii(args[0]) || !ispunct(args[0]))
{
msg("The first character of a digraph must be punctuation");
return;
}
if (!args[1])
{
msg("Digraphs must be composed of two characters");
return;
}
/* locate the new digraph character */
for (i = 2; args[i] == ' ' || args[i] == '\t'; i++)
{
}
dig = args[i];
if (!bang && dig)
{
dig |= 0x80;
}
/* search for the digraph */
for (i = 0; i < MAXDIGS && (digs[i].key1 != args[0] || digs[i].key2 != args[1]); i++)
{
}
if (i >= MAXDIGS)
{
for (i = 0; i < MAXDIGS && digs[i].dig; i++)
{
}
if (i >= MAXDIGS)
{
msg("Out of space in the digraph table");
return;
}
}
/* assign it the new digraph value */
digs[i].key1 = args[0];
digs[i].key2 = args[1];
digs[i].dig = dig;
}
savedigs(fd)
int fd;
{
int i;
static char buf[] = "digraph! XX Y\n";
for (i = 0; i < MAXDIGS; i++)
{
if (digs[i].dig)
{
buf[9] = digs[i].key1;
buf[10] = digs[i].key2;
buf[12] = digs[i].dig;
write(fd, buf, 14);
}
}
}
#endif
/* This function allows the user to replace an existing (possibly zero-length)
* chunk of text with typed-in text. It returns the MARK of the last character
* that the user typed in.
*/
MARK input(from, to, when)
MARK from; /* where to start inserting text */
MARK to; /* extent of text to delete */
int when; /* either WHEN_VIINP or WHEN_VIREP */
{
char key[2]; /* key char followed by '\0' char */
char *build; /* used in building a newline+indent string */
char *scan; /* used while looking at the indent chars of a line */
MARK m; /* some place in the text */
#ifndef NO_EXTENSIONS
int quit = FALSE; /* boolean: are we exiting after this? */
#endif
#ifdef DEBUG
/* if "from" and "to" are reversed, complain */
if (from > to)
{
msg("ERROR: input(%ld:%d, %ld:%d)",
markline(from), markidx(from),
markline(to), markidx(to));
return MARK_UNSET;
}
#endif
key[1] = 0;
/* if we're replacing text with new text, save the old stuff */
/* (Alas, there is no easy way to save text for replace mode) */
if (from != to)
{
cut(from, to);
}
ChangeText
{
/* if doing a dot command, then reuse the previous text */
if (doingdot)
{
/* delete the text that's there now */
if (from != to)
{
delete(from, to);
}
/* insert the previous text */
cutname('.');
cursor = paste(from, FALSE, TRUE) + 1L;
/* explicitly set preredraw and postredraw */
redrawafter = markline(from);
preredraw = markline(to);
postredraw = markline(cursor);
}
else /* interactive version */
{
/* if doing a change within the line... */
if (from != to && markline(from) == markline(to))
{
/* mark the end of the text with a "$" */
change(to - 1, to, "$");
}
else
{
/* delete the old text right off */
if (from != to)
{
delete(from, to);
}
to = from;
}
/* handle autoindent of the first line, maybe */
cursor = from;
if (*o_autoindent && markline(cursor) > 1L && markidx(cursor) == 0)
{
/* Only autoindent blank lines. */
pfetch(markline(cursor));
if (plen == 0)
{
/* Okay, we really want to autoindent */
pfetch(markline(cursor) - 1L);
for (scan = ptext, build = tmpblk.c;
*scan == ' ' || *scan == '\t';
)
{
*build++ = *scan++;
}
if (build > tmpblk.c)
{
*build = '\0';
add(cursor, tmpblk.c);
cursor += (build - tmpblk.c);
}
}
}
/* repeatedly add characters from the user */
for (;;)
{
/* Get a character */
redraw(cursor, TRUE);
key[0] = getkey(when);
/* if whitespace & wrapmargin is set & we're
/* past the warpmargin, then change the
/* whitespace character into a newline
*/
if ((*key == ' ' || *key == '\t')
&& *o_wrapmargin != 0)
{
pfetch(markline(cursor));
if (idx2col(cursor, ptext, TRUE) > COLS - (*o_wrapmargin & 0xff))
{
*key = '\n';
}
}
/* process it */
switch (*key)
{
#ifndef NO_EXTENSIONS
case 0: /* special movement mapped keys */
*key = getkey(0);
switch (*key)
{
case 'h': m = m_left(cursor, 0L); break;
case 'j': m = m_down(cursor, 0L); break;
case 'k': m = m_up(cursor, 0L); break;
case 'l': m = cursor + 1; break;
case 'b': m = m_bword(cursor, 0L); break;
case 'w': m = m_fword(cursor, 0L); break;
case '^': m = m_front(cursor, 0L); break;
case '$': m = m_rear(cursor, 0L); break;
case ctrl('B'):
case ctrl('F'):
m = m_scroll(cursor, 0L, *key); break;
case 'x': m = v_xchar(cursor, 0L); break;
case 'i': m = to = from = cursor; break;
default: m = MARK_UNSET; break;
}
/* adjust the moved cursor */
m = adjmove(cursor, m, (*key == 'j' || *key == 'k' ? 0x20 : 0));
if (*key == '$' || (*key == 'l' && m <= cursor))
{
m++;
}
/* if the cursor is reasonable, use it */
if (m == MARK_UNSET)
{
beep();
}
else
{
if (to > cursor)
{
delete(cursor, to);
redraw(cursor, TRUE);
}
from = to = cursor = m;
}
break;
case ctrl('Z'):
if (getkey(0) == ctrl('Z'))
{
quit = TRUE;
goto BreakBreak;
}
break;
#endif
case ctrl('['):
goto BreakBreak;
case ctrl('U'):
if (markline(cursor) == markline(from))
{
cursor = from;
}
else
{
cursor &= ~(BLKSIZE - 1);
}
break;
case ctrl('D'):
case ctrl('T'):
mark[27] = cursor;
cmd_shift(cursor, cursor, *key == ctrl('D') ? CMD_SHIFTL : CMD_SHIFTR, TRUE, "");
if (mark[27])
{
cursor = mark[27];
}
else
{
cursor = m_front(cursor, 0L);
}
break;
case '\b':
if (cursor <= from)
{
beep();
}
else if (markidx(cursor) == 0)
{
cursor -= BLKSIZE;
pfetch(markline(cursor));
cursor += plen;
}
else
{
cursor--;
}
break;
case ctrl('W'):
m = m_bword(cursor, 1L);
if (markline(m) == markline(cursor) && m >= from)
{
cursor = m;
if (from > cursor)
{
from = cursor;
}
}
else
{
beep();
}
break;
case '\n':
case '\r':
build = tmpblk.c;
*build++ = '\n';
if (*o_autoindent)
{
pfetch(markline(cursor));
for (scan = ptext; *scan == ' ' || *scan == '\t'; )
{
*build++ = *scan++;
}
}
*build = 0;
if (cursor >= to && when != WHEN_VIREP)
{
add(cursor, tmpblk.c);
}
else
{
change(cursor, to, tmpblk.c);
}
redraw(cursor, TRUE);
to = cursor = (cursor & ~(BLKSIZE - 1))
+ BLKSIZE
+ (int)(build - tmpblk.c) - 1;
break;
case ctrl('A'):
case ctrl('P'):
if (cursor < to)
{
delete(cursor, to);
}
if (*key == ctrl('A'))
{
cutname('.');
}
to = cursor = paste(cursor, FALSE, TRUE) + 1L;
break;
case ctrl('V'):
if (cursor >= to && when != WHEN_VIREP)
{
add(cursor, "^");
}
else
{
change(cursor, to, "^");
}
redraw(cursor, TRUE);
*key = getkey(0);
if (*key == '\n')
{
/* '\n' too hard to handle */
*key = '\r';
}
change(cursor, cursor + 1, key);
cursor++;
if (cursor > to)
{
to = cursor;
}
break;
case ctrl('L'):
case ctrl('R'):
redraw(MARK_UNSET, FALSE);
break;
default:
if (cursor >= to && when != WHEN_VIREP)
{
add(cursor, key);
cursor++;
to = cursor;
}
else
{
pfetch(markline(cursor));
if (markidx(cursor) == plen)
{
add(cursor, key);
}
else
{
#ifndef NO_DIGRAPH
*key = digraph(ptext[markidx(cursor)], *key);
#endif
change(cursor, cursor + 1, key);
}
cursor++;
}
} /* end switch(*key) */
} /* end for(;;) */
BreakBreak:;
/* delete any excess characters */
if (cursor < to)
{
delete(cursor, to);
}
} /* end if doingdot else */
} /* end ChangeText */
/* put the new text into a cut buffer for possible reuse */
if (!doingdot)
{
blksync();
cutname('.');
cut(from, cursor);
}
/* move to last char that we inputted, unless it was newline */
if (markidx(cursor) != 0)
{
cursor--;
}
redraw(cursor, FALSE);
#ifndef NO_EXTENSIONS
if (quit)
{
refresh();
cursor = v_xit(cursor, 0L, 'Z');
}
#endif
rptlines = 0L;
return cursor;
}
SHAR_EOF
fi
if test -f 'main.c'
then
echo shar: "will not over-write existing file 'main.c'"
else
cat << \SHAR_EOF > 'main.c'
/* main.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This file contains the main() function of vi */
#include "config.h"
#include <signal.h>
#include <setjmp.h>
#include "vi.h"
extern trapint(); /* defined below */
extern char *getenv();
jmp_buf jmpenv;
/*---------------------------------------------------------------------*/
void main(argc, argv)
int argc;
char *argv[];
{
int i;
char *cmd = (char *)0;
char *tag = (char *)0;
char *str;
#if MSDOS || TOS
char firstarg[256];
#else
char *firstarg;
#endif
#ifndef NO_ARGV0
/* set mode to MODE_VI or MODE_EX depending on program name */
switch (argv[0][strlen(argv[0]) - 1])
{
case 'x': /* "ex" */
mode = MODE_EX;
break;
case 'w': /* "view" */
mode = MODE_VI;
*o_readonly = TRUE;
break;
#ifndef NO_EXTENSIONS
case 't': /* "edit" or "input" */
mode = MODE_VI;
*o_inputmode = TRUE;
break;
#endif
default: /* "vi" or "elvis" */
mode = MODE_VI;
}
#endif
/* start curses */
initscr();
cbreak();
noecho();
scrollok(stdscr, TRUE);
#ifndef DEBUG
#ifdef SIGQUIT
/* normally, we ignore SIGQUIT. SIGINT is trapped later */
signal(SIGQUIT, SIG_IGN);
#endif
#endif
/* initialize the options */
initopts();
/* map the arrow keys. The KU,KD,KL,and KR variables correspond to
* the :ku=: (etc.) termcap capabilities. The variables are defined
* as part of the curses package.
*/
if (has_KU) mapkey(has_KU, "k", WHEN_VICMD|WHEN_INMV, "<Up>");
if (has_KD) mapkey(has_KD, "j", WHEN_VICMD|WHEN_INMV, "<Down>");
if (has_KL) mapkey(has_KL, "h", WHEN_VICMD|WHEN_INMV, "<Left>");
if (has_KR) mapkey(has_KR, "l", WHEN_VICMD|WHEN_INMV, "<Right>");
if (has_HM) mapkey(has_HM, "^", WHEN_VICMD|WHEN_INMV, "<Home>");
if (has_EN) mapkey(has_EN, "$", WHEN_VICMD|WHEN_INMV, "<End>");
if (has_PU) mapkey(has_PU, "\002", WHEN_VICMD|WHEN_INMV, "<PgUp>");
if (has_PD) mapkey(has_PD, "\006", WHEN_VICMD|WHEN_INMV, "<PgDn>");
#if MSDOS
if (*o_pcbios)
{
mapkey("#R", "i", WHEN_VICMD|WHEN_INMV, "<Insrt>");
mapkey("#S", "x", WHEN_VICMD|WHEN_INMV, "<Del>");
mapkey("#s", "B", WHEN_VICMD|WHEN_INMV, "^<left>");
mapkey("#t", "W", WHEN_VICMD|WHEN_INMV, "^<right>");
}
#else
if (ERASEKEY != '\177')
{
mapkey("\177", "x", WHEN_VICMD|WHEN_INMV, "<Del>");
}
#endif
/* process any flags */
for (i = 1; i < argc && *argv[i] == '-'; i++)
{
switch (argv[i][1])
{
case 'R': /* readonly */
*o_readonly = TRUE;
break;
case 'r': /* recover */
msg("Use the `virec` command to recover lost files\n");
refresh();
endwin();
exit(0);
break;
case 't': /* tag */
if (argv[i][2])
{
tag = argv[i] + 2;
}
else
{
i++;
tag = argv[i];
}
break;
case 'v': /* vi mode */
mode = MODE_VI;
break;
case 'e': /* ex mode */
mode = MODE_EX;
break;
#ifndef NO_EXTENSIONS
case 'i': /* input mode */
*o_inputmode = TRUE;
break;
#endif
default:
msg("Ignoring unknown flag \"%s\"", argv[i]);
}
}
/* if we were given an initial ex command, save it... */
if (i < argc && *argv[i] == '+')
{
if (argv[i][1])
{
cmd = argv[i++] + 1;
}
else
{
cmd = "$"; /* "vi + file" means start at EOF */
i++;
}
}
/* the remaining args are file names. */
nargs = argc - i;
if (nargs > 0)
{
#if ! ( MSDOS || TOS )
firstarg = argv[i];
#endif
strcpy(args, argv[i]);
while (++i < argc && strlen(args) + 1 + strlen(argv[i]) < sizeof args)
{
strcat(args, " ");
strcat(args, argv[i]);
}
}
#if ! ( MSDOS || TOS )
else
{
firstarg = "";
}
#endif
argno = 0;
#if MSDOS || TOS
if (nargs > 0)
{
strcpy(args, wildcard(args));
nargs = 1;
for (i = 0; args[i]; i++)
{
if (args[i] == ' ')
{
nargs++;
}
}
for (i = 0; args[i] && args[i] != ' '; i++)
{
firstarg[i] = args[i];
}
firstarg[i] = '\0';
}
else
{
firstarg[0] = '\0';
}
#endif
/* perform the .exrc files and EXINIT environment variable */
#ifdef SYSEXRC
doexrc(SYSEXRC);
#endif
#ifdef HMEXRC
str = getenv("HOME");
if (str)
{
sprintf(tmpblk.c, "%s%c%s", str, SLASH, HMEXRC);
doexrc(tmpblk.c);
}
#endif
doexrc(EXRC);
#ifdef EXINIT
str = getenv(EXINIT);
if (str)
{
doexcmd(str);
}
#endif
/* search for a tag now, if desired */
blkinit();
if (tag)
{
cmd_tag(MARK_FIRST, MARK_FIRST, CMD_TAG, 0, tag);
}
/* if no tag, or tag failed, then start with first arg */
if (tmpfd < 0 && tmpstart(firstarg) == 0 && *origname)
{
ChangeText
{
}
clrflag(file, MODIFIED);
}
/* now we do the immediate ex command that we noticed before */
if (cmd)
{
doexcmd(cmd);
}
/* repeatedly call ex() or vi() (depending on the mode) until the
* mode is set to MODE_QUIT
*/
while (mode != MODE_QUIT)
{
if (setjmp(jmpenv))
{
/* Maybe we just aborted a change? */
abortdo();
}
#if TURBOC
signal(SIGINT, (void(*)()) trapint);
#else
signal(SIGINT, trapint);
#endif
switch (mode)
{
case MODE_VI:
vi();
break;
case MODE_EX:
ex();
break;
#ifdef DEBUG
default:
msg("mode = %d?", mode);
mode = MODE_QUIT;
#endif
}
}
/* free up the cut buffers */
cutend();
/* end curses */
#ifndef NO_CURSORSHAPE
if (has_CQ)
do_CQ();
#endif
refresh();
endwin();
exit(0);
/*NOTREACHED*/
}
/*ARGSUSED*/
trapint(signo)
int signo;
{
resume_curses(FALSE);
longjmp(jmpenv, 1);
}
SHAR_EOF
fi
if test -f 'misc.c'
then
echo shar: "will not over-write existing file 'misc.c'"
else
cat << \SHAR_EOF > 'misc.c'
/* misc.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This file contains functions which didn't seem happy anywhere else */
#include "config.h"
#include "vi.h"
/* find a particular line & return a pointer to a copy of its text */
char *fetchline(line)
long line; /* line number of the line to fetch */
{
int i;
register char *scan; /* used to search for the line in a BLK */
long l; /* line number counter */
static BLK buf; /* holds ONLY the selected line (as string) */
register char *cpy; /* used while copying the line */
static long nextline; /* } These four variables are used */
static long chglevel; /* } to implement a shortcut when */
static char *nextscan; /* } consecutive lines are fetched */
static long nextlnum; /* } */
/* can we do a shortcut? */
if (changes == chglevel && line == nextline)
{
scan = nextscan;
}
else
{
/* scan lnum[] to determine which block its in */
for (i = 1; line > lnum[i]; i++)
{
}
nextlnum = lnum[i];
/* fetch text of the block containing that line */
scan = blkget(i)->c;
/* find the line in the block */
for (l = lnum[i - 1]; ++l < line; )
{
while (*scan++ != '\n')
{
}
}
}
/* copy it into a block by itself, with no newline */
for (cpy = buf.c; *scan != '\n'; )
{
*cpy++ = *scan++;
}
*cpy = '\0';
/* maybe speed up the next call to fetchline() ? */
if (line < nextlnum)
{
nextline = line + 1;
chglevel = changes;
nextscan = scan + 1;
}
else
{
nextline = 0;
}
/* Calls to fetchline() interfere with calls to pfetch(). Make sure
* that pfetch() resets itself on its next invocation.
*/
pchgs = 0L;
/* Return a pointer to the line's text */
return buf.c;
}
/* find a particular line & delete it */
deleteline(line)
long line; /* line number of the line to fetch */
{
MARK frommark, tomark;
frommark = MARK_AT_LINE(line);
tomark = frommark + BLKSIZE;
delete(frommark, tomark);
}
/* insert a given line at a particular line number */
addline(l, txt)
long l; /* line number where the new line should go */
char *txt; /* text of line, terminated with '\0' (not '\n') */
{
MARK atmark;
BLK newtext;
strcpy(newtext.c, txt);
strcat(newtext.c, "\n");
atmark = MARK_AT_LINE(l);
add(atmark, newtext.c);
}
/* replace one version of a line with another */
changeline(l, txt)
long l; /* line# of line to change */
char *txt; /* new version of line, terminated with '\0' */
{
deleteline(l);
addline(l, txt);
}
/* error message from the regexp code */
void regerror(txt)
char *txt; /* an error message */
{
msg("RE error: %s", txt);
}
/* This function is equivelent to the pfetch() macro */
void pfetch(l)
long l; /* line number of line to fetch */
{
if(l != pline || changes != pchgs)
{
pline = (l);
ptext = fetchline(pline);
plen = strlen(ptext);
pchgs = changes;
}
}
SHAR_EOF
fi
exit 0
# End of shell archive
-------------------------------------------------------------------------------
Steve Kirkendall kirkenda at cs.pdx.edu uunet!tektronix!psueea!eecs!kirkenda
More information about the Alt.sources
mailing list