/*
* BASIC by Phil Cockcroft
*/
#include "bas.h"
#include <errno.h>
/*
* these variables should be set in the terminal configuration routines.
*/
#ifndef CTRL
#define CTRL(c) ((c) & 037)
#endif
int ch_erase = CTRL('h');
int ch_kill = CTRL('u');
int ch_eof = CTRL('d');
int ch_rprnt = CTRL('r');
int ch_werase = CTRL('w');
int ch_lnext = CTRL('v');
int ch_susp = CTRL('z');
int line_len = 80;
extern int ter_width;
/* read a single character */
int
readc()
{
char c='\r';
#ifdef SIG_JMP
if(!setjmp(ecall)){
ecalling = 1;
if(read(0,&c,1) <= 0){
ecalling = 0;
VOID quit();
}
ecalling = 0;
}
#else
switch(read(0,&c,1)){ /* reading from a pipe exit on eof */
case 1:
break;
case 0:
VOID quit();
break;
case -1:
if(errno != EINTR)
VOID quit();
break;
}
#endif
return( ((int)c) & 0177);
}
/* sets up the terminal structures so that the editor is in rare
* with no paging or line boundries and no echo
* Also sets up the user modes so that they are sensible when
* we exit. ( friendly ).
*/
void
setupmyterm()
{
/*
set_cap();
*/
setu_term();
if(ter_width > 10)
line_len = ter_width;
}
/* the actual editor pretty straight forward but.. */
#define NORMAL_CHAR(c) ((c) >= ' ' && (c) <= '~')
#define HIST_SIZ 500
#define NORMAL_EDIT 0
#define COMMAND_EDIT 1
#define INSERT_EDIT 2
#define TRAPPED_EDIT 3
static CHAR *xpbuf;
static int xpbuflen;
static CHAR *eline;
static int edit_mode;
static jmp_buf edit_chg;
static int cur_elnumb;
static int hist_numb;
static int cursr;
static int scstart;
static int scend;
static int scrlim;
static int line_end;
static int lastxm;
static int llim;
typedef struct {
CHAR *bufp;
int slen;
} savl_t;
int Hist_Siz = HIST_SIZ;
static savl_t *edit_history;
#define DATAVALID(buf) ((buf)->bufp != 0 && (buf)->slen > 0)
static savl_t ubuf;
static savl_t clbuf;
static int clcur;
static savl_t srbuf;
static savl_t Ubuf;
static struct undo {
savl_t dels;
savl_t ins;
int posn;
int ocur;
int ncur;
int ucmd;
int uop;
int orepcnt;
int uswaped;
} undo;
static int last_ftFT;
static int last_ftFTc;
static int curcmd;
static int lastsrch;
static CHAR lastgtcmd[4];
static CHAR *lastgtcmdp;
static void putchs(const CHAR *, int);
static void putch(int);
static void pflush(void);
static void mv_cursr(int);
static void sav_ubuf(savl_t *, int, CHAR *);
static void setundo(void);
static void insert_mode(int, int);
static void redraw_line(int);
static void mvto_lin(int);
static int dosrch(int);
static int substr(CHAR *, int, CHAR *, int, int);
static void kill_line(void);
static void yank_line(void);
static void chng_line(void);
static void recov_line(savl_t *);
static void free_ubuf(savl_t *);
static void setscend(void);
static int mtchbrkt(void);
static void del_c(int, int);
static int gtword(int, int, int);
static void sav_curline(void);
static void draw_from_cursr(int);
static int normal_edit(void);
static int command_mode(ival);
static int find_c(int, int, int, int);
static int rd_xcmd(int, int, void (*)(void), int);
static void beep(void);
static void set_sc(void);
static int putxch(int);
static int vsize(int);
static void addnchars(int, CHAR *, CHAR **, CHAR **);
static void savustr(CHAR *, int, int, int);
static void dodotcmd(int);
static void doundo(void);
static void dotilde(int);
static void dopcmd(int, int);
static CHAR *do_ctrl_d(CHAR *, CHAR *);
static const char *xemsgs[] = {
" ",
"> ",
"< ",
"* "
};
static const char delstr[] = "\b \b\b \b";
static const char crlf[] = "\r\n";
/*
erase = ^h; kill = ^u;
eof = ^d; eol = <undef>; eol2 = <undef>; swtch = <undef>;
start = ^q; stop = ^s; susp = ^z; dsusp = ^y;
rprnt = ^r; flush = ^o; werase = ^w; lnext = ^v;
*/
/*ARGSUSED*/
int
edit(fl,fi,fc)
ival fl, fi, fc;
{
register CHAR *q;
register CHAR *p;
int c = 0;
int special;
int llen;
savl_t *cur_line;
CHAR xeline[MAXLIN+1];
CHAR _xpbuf[MAXLIN+1];
xpbuf = _xpbuf;
xpbuflen = 0;
eline = xeline;
set_term();
if(!edit_history){
llen = sizeof(savl_t) * Hist_Siz;
edit_history = (savl_t *)mmalloc(llen);
clr_mem( (memp)edit_history, (ival)llen);
}
cur_elnumb = ++hist_numb;
cur_line = &edit_history[cur_elnumb % Hist_Siz];
free_ubuf(cur_line);
scrlim = line_len - 4;
llim = fl;
curcmd = 0;
setundo();
if(fi){
VOID strmov(eline, line, fi);
putchs(eline, fi);
}
eline[fi] = 0;
cursr=(int)fi;
line_end = fi;
lastxm = 0;
edit_mode = NORMAL_EDIT;
switch(setjmp(edit_chg)){
case 0: /* normal edit */
c = normal_edit();
if(c == ESCAPE && !noedit)
c = command_mode(fc);
break;
case INSERT_EDIT:
c = '\n';
break;
case TRAPPED_EDIT:
free_ubuf(&clbuf);
free_ubuf(&Ubuf);
setundo();
putchs(crlf, 2);
pflush();
hist_numb--;
cursor=0;
rset_term(0);
return(c);
}
if(!noedit)
putchs(crlf, 2);
pflush();
eline[line_end] = 0;
/* special characters are dealt with here- null is never returned */
for(p=eline,q=line,special=0;*p;p++){
if(special){
special=0;
if(*p >= CTRL('a') && *p < ' ')
*q++ = *p;
else {
*q++ = '\\';
*q++ = *p;
}
}
else if(*p=='\\')
special++;
else *q++ = *p;
}
*q=0;
llen = q - (line +llim);
if(llen > 0)
sav_ubuf(cur_line, llen, line + llim);
else
hist_numb--;
free_ubuf(&clbuf);
free_ubuf(&Ubuf);
setundo();
cursor=0;
rset_term(0);
return(c);
}
static int
normal_edit()
{
register CHAR *pcursr;
register int c;
register int i;
int lastescaped = 0;
int inword;
CHAR *plim;
CHAR *tmp;
pcursr = eline + cursr;
plim = eline + llim;
for(;;){
pflush();
c = readc();
if(trapped){
*pcursr = 0;
longjmp(edit_chg, TRAPPED_EDIT);
}
if(!c)
continue;
if(NORMAL_CHAR(c) || lastescaped){
lastescaped = 0;
if(pcursr >= eline + MAXLIN){
beep();
continue;
}
if(!noedit)
VOID putxch(c);
*pcursr++ = (CHAR)c;
continue;
}
if(c == ch_eof){
#ifdef MDUMP
mdump();
#endif
if( (tmp = do_ctrl_d(pcursr, plim)) != 0){
pcursr = tmp;
continue;
}
c = readc();
if(c != ch_eof){
beep();
continue;
}
putchs(crlf, 2);
pflush();
VOID quit();
break;
} else if(c == '\r' || c == '\n' || c == ESCAPE){
break;
} else if(c == '\t'){
i = pcursr - eline;
do {
if(i >= MAXLIN){
beep();
break;
}
*pcursr++ = (CHAR)' ';
if(!noedit)
putch(' ');
} while(++i & 7);
continue;
}
if(noedit){
if(pcursr < eline + MAXLIN)
*pcursr++ = (CHAR)c;
continue;
}
if(c == ch_kill){
i = pcursr - eline;
if(i > line_len)
i %= line_len;
else
i -= llim;
while(i-- > 0)
putchs(delstr, 3 * vsize(*--pcursr));
pcursr = plim;
continue;
} else if(c == ch_erase){
if(pcursr > plim)
putchs(delstr, 3 * vsize(*--pcursr));
else
beep();
continue;
} else if(c == ch_rprnt){
putchs("^R\r\n", 4);
for(i = pcursr - plim, pcursr = plim; i ; i--)
VOID putxch(*pcursr++);
continue;
} else if(c == ch_werase){
if(pcursr <= plim){
beep();
continue;
}
inword = 0;
while(pcursr > plim){
if(pcursr[-1] == ' '){
if(inword)
break;
}
else
inword = 1;
putchs(delstr, 3*vsize(*--pcursr));
}
continue;
} else if(c == ch_lnext){
lastescaped = 1;
putchs("^\b", 2);
continue;
#ifdef SIGTSTP
} else if(c == ch_susp){
putchs(crlf, 2);
pflush(); /* flush it out */
rset_term(0);
VOID kill(0, SIGTSTP);
set_term();
if(llim)
putchs(eline, llim);
for(i = pcursr - plim, pcursr = plim; i ; i--)
VOID putxch(*pcursr++);
continue;
#endif
}
if(pcursr >= eline + MAXLIN){
beep();
continue;
}
*pcursr++ = (CHAR)c;
VOID putxch(c);
}
*pcursr = 0;
line_end = cursr = pcursr - eline;
return(c);
}
static int
command_mode(fc)
ival fc;
{
register int mcursr;
register int c = 0;
int lnum;
int nchars;
register int repcnt = 1;
int repset;
edit_mode = COMMAND_EDIT;
redraw_line(1);
sav_ubuf(&Ubuf, line_end - llim, eline + llim);
while(!trapped){
pflush();
c = readc();
if(trapped)
break;
if(c >= '1' && c <= '9'){
repset = 1;
repcnt = c - '0';
for(;;){
c = readc();
if(trapped)
break;
if(c < '0' || c > '9'){
if(repcnt < 0 || repcnt > MAXLIN)
repcnt = MAXLIN;
break;
}
repcnt = repcnt * 10 + c - '0';
}
}
else {
repset = 0;
repcnt = 1;
}
if(c == '\r' || c == '\n' || trapped)
break;
lastgtcmdp = 0;
mcursr = cursr;
switch(curcmd = c){
case '\b':
case 'h':
if( (mcursr -= repcnt) >= llim)
mv_cursr(mcursr);
else
beep();
break;
case 'l':
case ' ':
if((mcursr += repcnt) < line_end)
mv_cursr(mcursr);
else
beep();
break;
case '$':
if(mcursr >= line_end || line_end <= llim)
beep();
else
mv_cursr(line_end);
break;
case 'j':
case '+':
setundo();
undo.posn = cur_elnumb;
undo.uop = 4;
mvto_lin(cur_elnumb + repcnt);
undo.ocur = cur_elnumb;
break;
case '-':
case 'k':
setundo();
undo.posn = cur_elnumb;
undo.uop = 4;
mvto_lin(cur_elnumb - repcnt);
undo.ocur = cur_elnumb;
break;
case 'G':
if(!repset){
repcnt = cur_elnumb - Hist_Siz - 1;
if(repcnt < 1)
repcnt = 1;
}
setundo();
undo.posn = cur_elnumb;
mvto_lin(repcnt);
undo.ocur = cur_elnumb;
if(cur_elnumb != undo.posn)
undo.uop = 4;
break;
case CTRL('L'):
putch('\n');
redraw_line(0);
break;
case 'w':
case 'e':
case 'b':
case 'W':
case 'E':
case 'B':
mcursr = gtword(c, repcnt, 0);
if(mcursr < 0 || (cursr >= line_end-1 &&
mcursr >= cursr))
beep();
else
mv_cursr(mcursr);
break;
case '0':
mv_cursr(llim);
break;
case '^':
for(mcursr = llim ; mcursr < line_end ; mcursr++)
if(eline[mcursr] != ' ')
break;
mv_cursr(mcursr);
break;
case '|':
mv_cursr(llim + repcnt - 1);
break;
case ';':
if(!last_ftFT){
beep();
break;
}
mcursr = find_c(last_ftFT, repcnt, last_ftFTc, 0);
if(mcursr >= 0)
mv_cursr(mcursr);
else
beep();
break;
case ',':
switch(last_ftFT){
case 't':
c = 'T';
break;
case 'f':
c = 'F';
break;
case 'F':
c = 'f';
break;
case 'T':
c = 't';
break;
default:
c = 0;
break;
}
if(!c){
beep();
break;
}
mcursr = find_c(c, repcnt, last_ftFTc, 0);
if(mcursr >= 0)
mv_cursr(mcursr);
else
beep();
break;
case 't':
case 'f':
case 'F':
case 'T':
mcursr = find_c(c, repcnt, 0, 0);
if(mcursr >= 0)
mv_cursr(mcursr);
else
beep();
break;
case '%':
mcursr = mtchbrkt();
if(mcursr >= 0)
mv_cursr(mcursr);
else
beep();
break;
case 'A':
case 'a':
case 'I':
case 'i':
case 'R':
case 'r':
case 'S':
setundo();
insert_mode(c, repcnt);
break;
case 's':
setundo();
if(mcursr + repcnt <= line_end)
insert_mode(c, repcnt);
else
beep();
break;
case 'd':
setundo();
mcursr = rd_xcmd(repcnt, c, kill_line, 0);
if(mcursr < 0)
break;
nchars = mcursr - cursr;
if(!nchars){
beep();
break;
}
if(nchars < 0){
mv_cursr(mcursr);
nchars = -nchars;
}
del_c(nchars, 0);
break;
case 'c':
setundo();
mcursr = rd_xcmd(repcnt, c, chng_line, 0);
if(mcursr < 0)
break;
nchars = mcursr - cursr;
if(!nchars){
beep();
break;
}
if(nchars < 0){
mv_cursr(mcursr);
nchars = -nchars;
}
insert_mode(c, nchars);
break;
case 'C':
nchars = line_end - mcursr;
if(!nchars){
beep();
break;
}
setundo();
insert_mode(c, nchars);
break;
case 'D':
nchars = line_end - mcursr;
if(!nchars)
beep();
else {
setundo();
del_c(nchars, 0);
}
break;
case 'x':
setundo();
del_c(repcnt, 0);
break;
case 'X':
setundo();
if(mcursr - repcnt < llim){
beep();
break;
}
mv_cursr(mcursr - repcnt);
del_c(repcnt, 0);
break;
case '.':
if(undo.ucmd == 0)
beep();
else
dodotcmd(undo.ucmd);
break;
case 'u':
if(undo.ucmd && undo.uop > 0)
doundo();
else
beep();
break;
case 'U':
setundo();
kill_line();
undo.uop = 3;
if(DATAVALID(&Ubuf))
addnchars(Ubuf.slen, Ubuf.bufp, (CHAR **)0,
(CHAR **)0);
savustr(Ubuf.bufp, Ubuf.slen, llim, 0);
mv_cursr(llim);
break;
/*
* search operations
*/
case '/':
case '?':
/*
* do a save cur line.
* go into insert mode with a special flag set.
* when returned from routine, text is in eline
* do a search for this line. If found, do a move
* to this line. If not found, do a move to current
* line and beep.
*/
lastsrch = c;
if(cur_elnumb == hist_numb)
sav_curline();
free_ubuf(&srbuf);
insert_mode(c, 1);
if(trapped)
break;
if(!DATAVALID(&srbuf) || *srbuf.bufp != c){
free_ubuf(&srbuf);
lnum = hist_numb;
beep();
}
else {
lnum = dosrch(c);
if(lnum < 0)
lnum = hist_numb;
}
cur_elnumb = -1; /* force movement */
mvto_lin(lnum);
break;
case 'n':
case 'N':
/* repeat search with known search string. */
if( (lastsrch != '/' && lastsrch != '?') ||
srbuf.slen <= 0){
beep();
break;
}
lnum = dosrch( (c == 'n') ? lastsrch :
((lastsrch == '/') ? '?' : '/'));
if(lnum < 0)
break;
mvto_lin(lnum);
break;
case 'y':
setundo();
mcursr = rd_xcmd(repcnt, c, yank_line, 0);
if(mcursr < 0)
break;
nchars = mcursr - cursr;
if(!nchars){
beep();
break;
}
if(nchars < 0)
nchars = -nchars;
else
mcursr = cursr;
sav_ubuf(&ubuf, nchars, eline + mcursr);
break;
case 'Y':
setundo();
yank_line();
break;
case 'p':
case 'P':
dopcmd(c, repcnt);
break;
case '~':
setundo();
dotilde(repcnt);
break;
case ESCAPE:
if(!fc){
beep();
break;
}
eline[line_end] = 0;
return(c);
default:
beep();
break;
}
}
if(trapped)
longjmp(edit_chg, TRAPPED_EDIT);
eline[line_end] = 0;
return(c);
}
static void
dodotcmd(c)
int c;
{
register int ndels = 0;
register int ndelp = 0;
register int doins = 0;
int mcursr = cursr;
struct undo xundo;
CHAR in_text[MAXLIN+1];
CHAR *itext = in_text;
/* copy undo buf */
xundo = undo;
if(undo.uswaped){
/* unswap undo buf */
xundo.dels = undo.ins;
xundo.ins = undo.dels;
}
undo.dels.bufp = 0;
undo.ins.bufp = 0;
setundo();
undo.ucmd = c;
edit_mode = INSERT_EDIT;
switch(c){
case 'A':
undo.uop = 1;
mv_cursr(line_end);
doins++;
break;
case 'a':
case 'p':
undo.uop = 1;
if(line_end != llim)
mv_cursr(cursr+1);
doins++;
break;
case 'i':
case 'P':
undo.uop = 1;
doins++;
break;
case 'I':
undo.uop = 1;
mv_cursr(llim);
doins++;
break;
case 'R':
case 'r':
case 'S':
case 's':
ndels = xundo.dels.slen;
undo.uop = 3;
ndelp = 2;
doins++;
break;
case 'c':
/*
* BUG here: what should we do if we get cc for a dotcmd?
* we do what ksh does which is to do what we have here.
* vi does something different - i.e. it effectively
* does nothing.
*/
mcursr = rd_xcmd(1, c, chng_line, 1);
if(mcursr < 0)
break;
ndels = mcursr - cursr;
if(!ndels)
beep();
else if(ndels < 0){
mv_cursr(mcursr);
ndels = -ndels;
}
ndelp = 2;
undo.uop = 3;
doins++;
break;
case 'C':
ndels = line_end - mcursr;
if(!ndels){
beep();
break;
}
undo.uop = 3;
ndelp = 2;
doins++;
break;
case 'd':
mcursr = rd_xcmd(1, c, kill_line, 1);
if(mcursr < 0){
break;
}
ndels = mcursr - cursr;
if(!ndels)
beep();
else if(ndels < 0){
mv_cursr(mcursr);
ndels = -ndels;
}
break;
case 'D':
ndels = line_end - mcursr;
if(!ndels)
beep();
break;
case 'x':
ndels = xundo.dels.slen;
if(ndels <= 0)
beep();
break;
case 'X':
ndels = xundo.dels.slen;
if(mcursr - ndels < llim){
beep();
ndels = 0;
}
else
mv_cursr(mcursr - ndels);
break;
case '~':
dotilde(xundo.orepcnt);
break;
default:
beep();
break;
}
if(ndels > 0)
del_c(ndels, ndelp);
if(doins){
mcursr = cursr;
if(DATAVALID(&xundo.ins))
addnchars(xundo.ins.slen, xundo.ins.bufp,
&itext, (CHAR **)0);
savustr(in_text, itext - in_text, mcursr, 0);
if(cursr > llim)
mv_cursr(cursr - 1);
}
free_ubuf(&xundo.dels);
free_ubuf(&xundo.ins);
edit_mode = COMMAND_EDIT;
mv_cursr(cursr);
}
static void
doundo()
{
if(undo.uop & 8){
mv_cursr(undo.ocur);
dotilde(undo.orepcnt);
if(undo.uswaped)
undo.uswaped = 0;
else {
undo.uswaped = 1;
mv_cursr(undo.ocur);
}
return;
}
if(undo.uop & 4){
if(undo.uswaped){
undo.uswaped = 0;
mvto_lin(undo.ocur);
}
else {
undo.uswaped = 1;
mvto_lin(undo.posn);
}
return;
}
edit_mode = INSERT_EDIT;
if(undo.uswaped){
undo.uswaped = 0;
mv_cursr(undo.posn);
if( (undo.uop & 2) && DATAVALID(&undo.dels))
del_c(undo.dels.slen, 1);
if( (undo.uop & 1) && DATAVALID(&undo.ins))
addnchars(undo.ins.slen, undo.ins.bufp,
(CHAR **)0, (CHAR **)0);
mv_cursr(undo.ncur);
}
else {
undo.ncur = cursr;
mv_cursr(undo.posn);
if( (undo.uop & 1) && DATAVALID(&undo.ins))
del_c(undo.ins.slen, 1);
if( (undo.uop & 2) && DATAVALID(&undo.dels))
addnchars(undo.dels.slen, undo.dels.bufp,
(CHAR **)0, (CHAR **)0);
mv_cursr(undo.ocur);
undo.uswaped = 1;
}
edit_mode = COMMAND_EDIT;
mv_cursr(cursr);
}
static void
dopcmd(c, repcnt)
int c, repcnt;
{
int mcursr;
CHAR in_text[MAXLIN+1];
CHAR *itext = in_text;
setundo();
if(!DATAVALID(&ubuf)){
beep();
return;
}
edit_mode = INSERT_EDIT;
if(c == 'p' && line_end != llim)
mv_cursr(cursr+1);
undo.uop = 1;
mcursr = cursr;
while(repcnt-- > 0)
addnchars(ubuf.slen, ubuf.bufp, &itext, (CHAR **)0);
savustr(in_text, itext - in_text, mcursr, 0);
if(cursr > llim)
mv_cursr(cursr - 1);
edit_mode = COMMAND_EDIT;
}
void
dotilde(repcnt)
register int repcnt;
{
register int c;
if(llim == line_end){
undo.orepcnt = 0;
beep();
return;
}
undo.orepcnt = repcnt;
if(cursr + repcnt >= line_end)
repcnt = line_end - cursr;
while(repcnt > 0){
repcnt--;
c = eline[cursr];
if(c >= 'A' && c <= 'Z')
c += 'a' - 'A';
else if(c >= 'a' && c <= 'z')
c += 'A' - 'a';
VOID putxch(c);
eline[cursr] = (CHAR)c;
mv_cursr(++cursr);
}
undo.uop = 8;
}
static void
insert_mode(c, repcnt)
register int c;
int repcnt;
{
register int mcursr;
int nchanged;
int iposn;
int inword;
int escaped;
CHAR in_text[MAXLIN+1];
CHAR *itext = in_text;
CHAR rep_text[MAXLIN+1];
CHAR *rtext = 0;
int srch = 0;
CHAR xc;
edit_mode = INSERT_EDIT;
iposn = cursr;
switch(c){
case '/':
case '?':
eline[llim] = (char)c;
*itext++ = (char)c;
line_end = llim + 1;
cursr = line_end;
eline[line_end] = 0;
iposn = cursr;
redraw_line(3);
srch = 1;
break;
/*
* c and S are a problem, since we also have to save what
* we changed it to. so that we can do a change back again.
* this is not nice.
*/
case 'C':
case 'c':
case 's':
if(repcnt)
del_c(repcnt, 2);
undo.uop = 3;
/* must copy ubuf here */
break;
case 'S':
nchanged = line_end - llim;
sav_ubuf(&ubuf, nchanged, eline + llim);
savustr(eline + llim, nchanged, llim, 1);
undo.uop = 3;
line_end = llim;
cursr = llim;
eline[line_end] = 0;
redraw_line(3);
/* must copy ubuf here */
break;
case 'I':
undo.uop = 1;
mv_cursr(llim);
break;
case 'R':
undo.uop = 3;
rtext = rep_text;
break;
case 'r':
undo.uop = 3;
do {
c = readc();
if(trapped)
longjmp(edit_chg, TRAPPED_EDIT);
} while(c == 0);
if(repcnt > MAXLIN)
repcnt = MAXLIN;
set_mem(itext, repcnt, c);
rtext = rep_text;
addnchars(repcnt, itext, &itext, &rtext);
savustr(in_text, itext - in_text, iposn, 0);
savustr(rep_text, rtext - rep_text, iposn, 1);
if(cursr > llim)
mv_cursr(cursr - 1);
edit_mode = COMMAND_EDIT;
return;
case 'A':
undo.uop = 1;
mv_cursr(line_end);
break;
case 'a':
undo.uop = 1;
if(line_end != llim)
mv_cursr(cursr+1);
break;
default:
undo.uop = 1;
break;
}
iposn = cursr;
escaped = 0;
for(;;){
pflush();
c = readc();
if(trapped)
longjmp(edit_chg, TRAPPED_EDIT);
if(c == 0)
continue;
if(escaped){
escaped = 0;
xc = (CHAR)c;
addnchars(1, &xc, &itext, &rtext);
continue;
}
if(c == ESCAPE)
break;
if(c == '\n' || c == '\r')
if(srch)
break;
else
longjmp(edit_chg, INSERT_EDIT);
if(c == ch_kill){
iposn = llim;
itext = in_text;
if(rtext)
rtext = rep_text;
if(!srch)
kill_line();
else {
line_end = llim;
cursr = llim;
eline[line_end] = 0;
redraw_line(3);
}
} else if(c == '\b' || c == ch_erase){
if(itext > in_text){
mv_cursr(cursr-1);
del_c(1, 1);
itext--;
if(rtext)
rtext--;
}
else
beep();
}
else if(c == CTRL('w')){
if(itext <= in_text){
beep();
continue;
}
inword = 0;
for(mcursr = cursr; mcursr > iposn ; mcursr--)
if(eline[mcursr-1] == ' '){
if(inword)
break;
}
else
inword = 1;
nchanged = cursr - mcursr;
itext -= nchanged;
if(rtext)
rtext -= nchanged;
mv_cursr(mcursr);
del_c(nchanged, 1);
}
else if(c == ch_eof){
beep();
}
else if(c == CTRL('v')){
escaped = 1;
}
else if(c == '\t'){
addnchars(8 - (cursr & 7), " ", &itext, &rtext);
}
else {
xc = (CHAR)c;
addnchars(1, &xc, &itext, &rtext);
}
}
if(srch){
sav_ubuf(&srbuf, itext - in_text, in_text);
edit_mode = COMMAND_EDIT;
return;
}
savustr(in_text, itext - in_text, iposn, 0);
if(rtext)
savustr(rep_text, rtext - rep_text, iposn, 1);
if(cursr > llim)
mv_cursr(cursr - 1);
edit_mode = COMMAND_EDIT;
}
static void
addnchars(nchars, buf, ibuf, rbuf)
int nchars;
CHAR *buf;
CHAR **ibuf, **rbuf;
{
register CHAR *p;
int nc, mcursr, nchanged;
if(!nchars)
return;
if(cursr >= MAXLIN -1){
beep();
return;
}
p = eline + cursr;
if(vsize(*p) > 1)
putch('\b');
if(rbuf && *rbuf){
if(cursr + nchars >= MAXLIN)
nchars = MAXLIN - cursr;
/* do an overwrite */
nc = nchars;
if(cursr + nc > line_end)
nc = line_end - cursr;
if(nc)
*rbuf = strmov(*rbuf, p, nc);
if(ibuf)
*ibuf = strmov(*ibuf, buf, nchars);
VOID strmov(p, buf, nchars);
mcursr = cursr + nchars;
if(mcursr > line_end)
line_end = mcursr;
}
else {
if(line_end + nchars >= MAXLIN)
nchars = MAXLIN - line_end;
/* not at end of line */
if(cursr < line_end){
register CHAR *sp, *q;
sp = eline + line_end;
q = sp + nchars;
while(sp >= p)
*q-- = *sp--;
}
if(ibuf)
*ibuf = strmov(*ibuf, buf, nchars);
VOID strmov(p, buf, nchars);
line_end += nchars;
mcursr = cursr + nchars;
}
eline[line_end] = 0;
setscend();
nchanged = line_end - cursr + 1;
if(nchanged < 1)
nchanged = 1;
if(cursr + nchanged >= scend){
cursr = mcursr;
redraw_line(0);
}
else {
draw_from_cursr(nchanged);
mv_cursr(mcursr);
}
}
static void
redraw_line(force)
int force;
{
register CHAR *p;
register int i;
register int scursr;
int savscr;
int xem = 0;
if(cursr >= line_end){
if(edit_mode == COMMAND_EDIT)
cursr = line_end - 1;
else if(cursr > line_end)
cursr = line_end;
}
if(cursr < llim)
cursr = llim;
if(cursr < scstart || cursr >= scend || force)
set_sc();
putch('\r');
putchs(eline, llim);
if(scstart > llim)
xem |= 2;
savscr = llim;
p = eline + scstart;
for(i = scstart, scursr = llim ; scursr < scrlim ; i++, p++){
if(i == cursr)
savscr = scursr;
if(i >= line_end){
if(!xem && !lastxm && !(force & 2))
break;
scursr += putxch(' ');
}
else
scursr += putxch(*p);
}
if(i < line_end)
xem |= 1;
if(xem || lastxm || (force & 2)){
putchs(xemsgs[xem], 2);
scursr += 2;
}
while(scursr > savscr){
putch('\b');
scursr--;
}
if(vsize(eline[cursr]) > 1)
putch('^');
lastxm = xem;
}
static void
draw_from_cursr(nchanged)
int nchanged;
{
register CHAR *p;
register int i;
int xem = 0;
int savscr;
int scursr;
int ocursr;
ocursr = cursr;
if(cursr >= line_end){
if(edit_mode == COMMAND_EDIT)
cursr = line_end - 1;
else if(cursr > line_end)
cursr = line_end;
}
if(cursr < llim)
cursr = llim;
if(scstart > llim)
xem |= 2;
scursr = llim;
p = eline + scstart;
for(i = scstart ; i < cursr ; i++, p++)
scursr += vsize(*p);
savscr = scursr;
if(cursr != ocursr)
for(; i < ocursr ; i++, p++)
scursr += vsize(*p);
for(; scursr < scrlim ; p++, i++, nchanged--){
if(i >= line_end){
if(!xem && !lastxm && !nchanged)
break;
scursr += putxch(' ');
}
else
scursr += putxch(*p);
}
if(i < line_end)
xem |= 1;
if(xem || lastxm || nchanged){
putchs(xemsgs[xem], 2);
scursr += 2;
}
while(scursr > savscr){
putch('\b');
scursr--;
}
if(vsize(eline[cursr]) > 1)
putch('^');
lastxm = xem;
}
static void
mv_cursr(ncursr)
int ncursr;
{
register CHAR *p;
register int i;
if(ncursr >= line_end){
if(edit_mode == COMMAND_EDIT)
ncursr = line_end - 1;
else if(ncursr > line_end)
ncursr = line_end;
}
if(ncursr < llim)
ncursr = llim;
if(ncursr < scstart || ncursr >= scend){
cursr = ncursr;
redraw_line(0);
return;
}
i = ncursr - cursr;
if(!i)
return;
p = eline + cursr;
cursr = ncursr;
if(vsize(*p) > 1)
putch('\b');
if(i < 0){
i = -i;
do {
putchs("\b\b", vsize(*--p));
}while(--i);
}
else {
do {
VOID putxch(*p++);
} while(--i);
}
if(vsize(*p) > 1)
putch('^');
}
static void
mvto_lin(lnum)
register int lnum;
{
register savl_t *savlp;
if(lnum == cur_elnumb){
redraw_line(3);
return;
}
if(lnum < 0 || lnum > hist_numb || lnum <= hist_numb - Hist_Siz){
beep();
redraw_line(3);
return;
}
if(lnum == hist_numb){ /* back to current line. */
recov_line(&clbuf);
cursr = clcur;
free_ubuf(&clbuf);
}
else { /* moveing off of current line. */
savlp = &edit_history[lnum % Hist_Siz];
if(!DATAVALID(savlp)){
beep();
redraw_line(3);
return;
}
cursr = llim;
if(cur_elnumb == hist_numb)
sav_curline();
recov_line(savlp);
}
cur_elnumb = lnum;
redraw_line(3);
}
static int
dosrch(cmdc)
int cmdc;
{
register int i, lnum;
int incr = (cmdc == '?') ? 1 : -1;
CHAR *mstr = srbuf.bufp + 1;
int nchrs = srbuf.slen - 1;
register savl_t *ptr;
int bol = 0;
if(*mstr == '^'){
mstr++;
nchrs--;
bol++;
}
lnum = cur_elnumb + incr + Hist_Siz;
for(i = 1 ; i < Hist_Siz ; i++, lnum += incr){
ptr = &edit_history[lnum % Hist_Siz];
if(!DATAVALID(ptr))
break;
if(ptr->slen < nchrs)
continue;
if(substr(mstr, nchrs, ptr->bufp, ptr->slen, bol)){
while(lnum < hist_numb - Hist_Siz)
lnum += Hist_Siz;
while(lnum > hist_numb)
lnum -= Hist_Siz;
return(lnum);
}
}
beep();
return(-1);
}
static int
substr(str, slen, ofstr, oflen, bol)
CHAR *str, *ofstr;
int slen, oflen, bol;
{
int retrys;
register CHAR *p, *q;
register int icnt;
retrys = oflen - slen;
do {
for(p = str, q = ofstr, icnt = slen ; icnt ; icnt--, p++, q++)
if(*p != *q)
break;
if(!icnt)
return(1);
ofstr++;
} while(--retrys >= 0 && !bol);
return(0);
}
static void
del_c(nchars, ubufupdate)
int nchars;
int ubufupdate;
{
register CHAR *p, *q;
register CHAR *eq;
int nchanged;
if(cursr >= line_end){
beep();
return;
}
nchanged = line_end - cursr;
if(nchars > nchanged)
nchars = nchanged;
if(line_end - nchars < llim){
beep();
return;
}
p = &eline[cursr];
q = p + nchars;
switch(ubufupdate){
case 0: /* normal case */
sav_ubuf(&ubuf, nchars, p);
savustr(p, nchars, cursr, 1);
undo.uop = 2;
break;
case 1: /* no update */
break;
case 2: /* a change update */
savustr(p, nchars, cursr, 1);
break;
}
eq = eline + line_end;
if(vsize(*p) > 1)
putch('\b');
while(q <= eq){
if(!NORMAL_CHAR(*p))
nchanged++;
*p++ = *q++;
}
line_end -= nchars;
eline[line_end] = 0;
setscend();
if(cursr < scstart || cursr + nchanged >= scend)
redraw_line(2);
else
draw_from_cursr(nchanged);
}
static void
yank_line()
{
sav_ubuf(&ubuf, line_end - llim, eline + llim);
}
static void
chng_line()
{
if(line_end == llim){
beep();
return;
}
mv_cursr(llim);
insert_mode('c', line_end - llim);
}
static void
sav_ubuf(savl, nchars, sbuf)
register savl_t *savl;
int nchars;
CHAR *sbuf;
{
if(savl->bufp)
mfree( (MEMP)savl->bufp);
savl->slen = nchars;
savl->bufp = (CHAR *)mmalloc( (ival)(nchars + 1));
if(nchars)
VOID strmov(savl->bufp, sbuf, nchars);
savl->bufp[nchars] = 0;
}
static void
free_ubuf(savl)
register savl_t *savl;
{
if(savl->bufp){
mfree( (MEMP)savl->bufp);
savl->bufp = 0;
}
savl->slen = 0;
}
static void
setundo()
{
free_ubuf(&undo.dels);
free_ubuf(&undo.ins);
undo.dels.slen = -1;
undo.ins.slen = -1;
undo.ocur = cursr;
undo.ncur = -1;
undo.ucmd = curcmd;
undo.uop = 0;
undo.uswaped = 0;
}
static void
savustr(buf, len, posn, isdel)
CHAR *buf;
int len, posn, isdel;
{
sav_ubuf(isdel ? &undo.dels : &undo.ins, len, buf);
if(posn >= 0)
undo.posn = posn;
}
static void
sav_curline()
{
sav_ubuf(&clbuf, line_end - llim, eline + llim);
clcur = cursr;
}
static void
recov_line(savl)
register savl_t *savl;
{
if(llim)
VOID strmov(eline, line, llim);
line_end = llim;
if(DATAVALID(savl)){
VOID strmov(eline + llim, savl->bufp, savl->slen);
line_end += savl->slen;
}
eline[line_end] = 0;
}
static void
set_sc()
{
register int i, sc;
register int ncur;
register CHAR *p;
ncur = cursr;
for(i = sc = llim, p = eline + i ; i < ncur ; i++, p++)
sc += vsize(*p);
if(sc >= scrlim){
/* cursor is beyond end of line. */
sc = (scrlim - llim) / 2;
while(sc > 0){
sc -= vsize(*p--);
i--;
}
scstart = i;
}
else
scstart = llim;
setscend();
}
static void
setscend()
{
register int i;
register int scrwidth = scrlim - llim;
register CHAR *p;
scend = scstart;
p = eline + scstart;
for(i = 0 ; i < scrwidth && scend < line_end; scend++, p++)
i += vsize(*p);
scend += (scrwidth - i); /* this assumes space = 1 char width */
}
static void
kill_line()
{ /* save the whole line */
register int nchars;
nchars = line_end - llim;
sav_ubuf(&ubuf, nchars, eline + llim);
savustr(eline + llim, nchars, llim, 1);
undo.uop = 2;
line_end = llim;
cursr = llim;
eline[line_end] = 0;
redraw_line(3);
}
static int
rd_xcmd(repcnt, cmdc, dfunc, dotcmd)
int repcnt, cmdc;
void (*dfunc)(void);
int dotcmd;
{
register int mcursr;
int c;
int xrepcnt;
lastgtcmdp = lastgtcmd;
if(!dotcmd){
c = readc();
if(trapped)
return(-1);
if(c >= '1' && c <= '9'){
xrepcnt = c - '0';
for(;;){
c = readc();
if(trapped)
return(-1);
if(c < '0' || c > '9'){
repcnt *= xrepcnt;
if(repcnt < 0 || repcnt > MAXLIN)
repcnt = MAXLIN;
break;
}
xrepcnt = xrepcnt * 10 + c - '0';
}
}
*lastgtcmdp++ = (CHAR)c;
undo.orepcnt = repcnt;
}
else {
c = *lastgtcmdp++;
repcnt = undo.orepcnt;
}
if(c == cmdc && dfunc){
/* 't'is a duplicate. do it to the whole line. */
/* and the only thing that you can do is a cc or a dd or a yy */
(*dfunc)();
return(-1);
}
switch(c){
case 'f':
case 'F':
case 't':
case 'T':
mcursr = find_c(c, repcnt, 0, dotcmd);
if(mcursr >= cursr)
mcursr++;
break;
case 'W':
case 'w':
if(cmdc == 'c'){
if(eline[cursr] == ' '){
if(--repcnt == 0){
mcursr = cursr + 1;
break;
}
}
c = ((c == 'w') ? 'e' : 'E');
}
mcursr = gtword(c, repcnt, 1);
break;
case 'e':
case 'b':
case 'E':
case 'B':
mcursr = gtword(c, repcnt, 1);
break;
case 'l':
mcursr = cursr + repcnt;
if(mcursr > line_end)
mcursr = -1;
break;
case 'h':
mcursr = cursr - repcnt;
if(mcursr <= llim)
mcursr = -1;
break;
case '0':
mcursr = llim;
break;
case '$':
mcursr = line_end;
break;
case '%':
mcursr = mtchbrkt();
if(mcursr > cursr)
mcursr++;
break;
default:
lastgtcmdp = lastgtcmd;
mcursr = -1;
break;
}
if(mcursr < 0)
beep();
if(!dotcmd)
*lastgtcmdp = 0;
return(mcursr);
}
static int
find_c(c, repcnt, last_c, dotcmd)
int c, repcnt;
int last_c, dotcmd;
{
register int mcursr = cursr;
register int xc;
register int found = 0;
if( (xc = last_c) <= 0){
if(!dotcmd || !lastgtcmdp){
xc = readc();
if(trapped)
return(-1);
last_ftFT = c;
last_ftFTc = xc;
if(lastgtcmdp)
*lastgtcmdp++ = (CHAR)xc;
}
else
xc = *lastgtcmdp++;
}
if(c == 'f' || c == 't'){
for(found = 0; mcursr < line_end && found < repcnt;)
if(eline[++mcursr] == xc)
found++;
if(c == 't'){
if(mcursr > llim)
mcursr--;
else
found = 0;
}
}
else {
for(; mcursr > llim && found < repcnt;)
if(eline[--mcursr] == xc)
found++;
if(c == 'T'){
if(mcursr < line_end - 1)
mcursr++;
else
found = 0;
}
}
if(found >= repcnt)
return(mcursr);
return(-1);
}
static int
is_inword(c, ascw)
int c, ascw;
{
if(c == ' ')
return(2);
if(!ascw)
return(1);
return((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9'));
}
static int
gtword(c, repcnt, cw)
int c, repcnt, cw;
{
register int mcursr = cursr;
register int wtype, rtype;
int ascword;
ascword = (c < 'A' || c > 'Z');
switch(c){
case 'W':
case 'w':
do {
if(mcursr >= line_end)
return(-1);
wtype = is_inword(eline[mcursr], ascword);
while(mcursr < line_end){
rtype = is_inword(eline[++mcursr], ascword);
if(rtype != wtype){
if(rtype != 2)
break;
wtype = rtype;
}
}
} while(--repcnt > 0);
break;
case 'E':
case 'e':
do {
wtype = is_inword(eline[mcursr+1], ascword);
for(;mcursr < line_end;mcursr++){
rtype = is_inword(eline[mcursr+1], ascword);
if(rtype != wtype){
if(wtype != 2)
break;
wtype = rtype;
}
}
}while(--repcnt > 0);
if(cw && mcursr < line_end)
mcursr++;
break;
case 'B':
case 'b':
do {
if(mcursr <= llim)
return(-1);
wtype = is_inword(eline[mcursr-1], ascword);
for(; mcursr > llim ; mcursr--){
rtype = is_inword(eline[mcursr-1], ascword);
if(rtype != wtype){
if(wtype != 2)
break;
wtype = rtype;
}
}
} while(--repcnt > 0);
break;
}
return(mcursr);
}
static int
mtchbrkt()
{
register int mcursr = cursr;
register int nc = 0, rbseen = 0;
/*
* search forward for matching '('
*/
while(mcursr < line_end){
if(eline[mcursr] == ')'){
if(--nc <= 0)
break;
}
else if(eline[mcursr] == '('){
rbseen++;
nc++;
}
mcursr++;
}
if(mcursr >= line_end)
return(-1);
if(nc < 0 && !rbseen){
/* must search back for previous bracket */
nc = 0;
while(mcursr > llim){
if(eline[mcursr] == ')')
nc++;
else if(eline[mcursr] == '('){
if(--nc <= 0)
return(mcursr);
}
mcursr--;
}
}
return( (nc <= 0) ? mcursr : -1);
}
static CHAR *
do_ctrl_d(pcursr, plim)
CHAR *pcursr, *plim;
{
CHAR *savc;
const struct tabl *l;
const CHAR *flist = 0;
int ndone = 0;
int i = 0;
int sslen;
int force = 0;
savc = pcursr - 1;
if(savc < plim || noedit)
return( (CHAR *)0);
if(*savc == '.' && savc > plim){
force = 1;
savc--;
}
if(is_inword( (int)*savc, 1) != 1)
return( (CHAR *)0);
while(savc >= plim && is_inword(*savc, 1) == 1){
savc--;
i++;
}
savc++;
for(l = table ; l->string ; l++){
if(*l->string != *savc)
continue;
sslen = slen( (char *)l->string);
if(sslen < i)
continue;
if(!substr(savc, i, (CHAR *)l->string, sslen, 1))
continue;
if(!force || flist == 0)
flist = l->string;
putchs(crlf, 2);
putchs(" ", 8);
putchs(l->string, sslen);
ndone++;
}
if(ndone){
putchs(crlf, 2);
if(ndone == 1 || force){
while(*flist && savc < eline + MAXLIN)
*savc++ = *flist++;
pcursr = savc;
}
for(i = pcursr - eline, pcursr = eline; i ; i--)
VOID putxch(*pcursr++);
}
else
beep();
return(pcursr);
}
/* put out a character uses buffere output of up to 256 characters
* It used to use a static buffer but this is a waste of space so
* it now uses gblock as this is never used during an edit.
* A value of zero for the parameter will flush the buffer.
*/
static void
putch(c)
int c;
{
#ifdef MSDOS
if(c &= MASK)
bdos(6, (char)c);
#else
if(xpbuflen >= MAXLIN)
pflush();
xpbuf[xpbuflen++] = (CHAR) c;
#endif
}
static void
pflush()
{
if(xpbuflen > 0)
VOID write(1, (char *)xpbuf, xpbuflen);
xpbuflen = 0;
}
static void
putchs(sp, len)
const char *sp;
register int len;
{
register CHAR *s = (CHAR *)sp;
if(len + xpbuflen < MAXLIN){
VOID strmov(xpbuf + xpbuflen, s, len);
xpbuflen += len;
}
else {
for(;*s && len > 0 ; s++, len--)
putch(*s);
}
}
static int
putxch(c)
int c;
{
if(NORMAL_CHAR(c)){
putch(c);
return(1);
}
putch('^');
if(c == '\177')
putch('?');
else
putch(c + 'A'-1);
return(2);
}
static int
vsize(c)
int c;
{
return(NORMAL_CHAR(c) ? 1 : (c ? 2 : 0));
}
static void
beep()
{
putch('\007');
}
syntax highlighted by Code2HTML, v. 0.9.1