Category : OS/2 Files
Archive   : KSH48.ZIP
Filename : VI.C

 
Output of file : VI.C contained in archive : KSH48.ZIP

/*
* vi command editing
* written by John Rochester (initially for nsh)
* bludgeoned to fit PD ksh by Larry Bouzane and Eric Gisin
* Further hacked (bugfixes and tweaks) by Mike Jetzer
*/

#include "config.h"
#ifdef VI

#ifndef lint
static char *RCSid = "$Id: vi.c,v 1.3 1992/08/10 12:03:31 sjg Exp $";
#endif

#include "stdh.h"
#include
#include
#include
#include
#include
#include
#include "sh.h"
#include "expand.h"
#include "edit.h"

#define CMDLEN 256
#define Ctrl(c) (c&0x1f)
extern int histN();

static int nextstate ARGS((int ch));
static int vi_insert ARGS((int ch));
static int vi_cmd ARGS((int argcnt, char *cmd));
static int domove ARGS((int argcnt, char *cmd, int sub));
static int redo_insert ARGS((int count));
static yank_range ARGS((int a, int b));
static int bracktype ARGS((int ch));
static edit_reset ARGS((char *buf, int len));
static int putbuf ARGS((char *buf, int len, int repl));
static stripblanks ARGS((void));
static del_range ARGS((int a, int b));
static int findch ARGS((int ch, int cnt, int forw, int incl));
static int forwword ARGS((int argcnt));
static int backword ARGS((int argcnt));
static int endword ARGS((int argcnt));
static int Forwword ARGS((int argcnt));
static int Backword ARGS((int argcnt));
static int Endword ARGS((int argcnt));
static int grabhist ARGS((int save, int n));
static int grabsearch ARGS((int save, int start, int fwd, char *pat));
static redraw_line ARGS((void));
static refresh ARGS((int leftside));
static int outofwin ARGS((void));
static rewindow ARGS((void));
static int newcol ARGS((int ch, int col));
static display ARGS((char *wb1, char *wb2, int leftside));
static ed_mov_opt ARGS((int col, char *wb));

#define C_ 0x1
#define M_ 0x2
#define E_ 0x4
#define X_ 0x8
#define U_ 0x10
#define B_ 0x20
#define O_ 0x40
#define S_ 0x80

#define isbad(c) (classify[c]&B_)
#define iscmd(c) (classify[c]&(M_|E_|C_|U_))
#define ismove(c) (classify[c]&M_)
#define isextend(c) (classify[c]&E_)
#define islong(c) (classify[c]&X_)
#define ismeta(c) (classify[c]&O_)
#define isundoable(c) (!(classify[c]&U_))
#define issrch(c) (classify[c]&S_)

char classify[256] = {
B_, 0, 0, 0, 0, 0, O_, 0,
#if 1 /* Mike B. changes */
C_|M_, 0, O_, 0, O_, O_, O_, 0,
#else
C_, 0, O_, 0, O_, O_, O_, 0,
#endif
O_, 0, C_|U_, 0, 0, 0, 0, 0,
0, 0, O_, 0, 0, 0, 0, 0,
#if 1 /* Mike B. changes */
C_|M_, 0, 0, C_, M_, C_, 0, 0,
#else
C_, 0, 0, C_, M_, C_, 0, 0,
#endif
0, 0, C_, C_, M_, C_, 0, C_|S_,
M_, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, M_, 0, C_, 0, C_|S_,
0, C_, M_, C_, C_, M_, M_|X_, C_,
0, C_, 0, 0, 0, 0, C_, 0,
C_, 0, C_, C_, M_|X_, 0, 0, M_,
C_, C_, 0, 0, 0, 0, M_, C_,
0, C_, M_, E_, E_, M_, M_|X_, 0,
M_, C_, C_, C_, M_, 0, C_, 0,
C_, 0, C_, C_, M_|X_, C_|U_, 0, M_,
C_, E_, 0, 0, 0, 0, C_, 0
};

#define MAXVICMD 3
#define SRCHLEN 40

#define INSERT 1
#define REPLACE 2

#define VNORMAL 0
#define VARG1 1
#define VEXTCMD 2
#define VARG2 3
#define VXCH 4
#define VFAIL 5
#define VCMD 6
#define VREDO 7
#define VLIT 8
#define VSEARCH 9
#define VREPLACE1CHAR 10

struct edstate {
int winleft;
char *cbuf;
int cbufsize;
int linelen;
int cursor;
};

static char undocbuf[CMDLEN];

static struct edstate ebuf;
static struct edstate undobuf = { 0, undocbuf, CMDLEN, 0, 0 };

static struct edstate *es; /* current editor state */
static struct edstate *undo;

static char ibuf[CMDLEN]; /* input buffer */
static int inslen; /* length of input buffer */
static int srchlen; /* length of current search pattern */
static char ybuf[CMDLEN]; /* yank buffer */
static int yanklen; /* length of yank buffer */
static int fsavecmd = ' '; /* last find command */
static int fsavech; /* character to find */
static char lastcmd[MAXVICMD]; /* last non-move command */
static int lastac; /* argcnt for lastcmd */
static int lastsearch = ' '; /* last search command */
static char srchpat[SRCHLEN]; /* last search pattern */
static int insert; /* non-zero in insert mode */
static int hnum; /* position in history */
static int hlast; /* 1 past last position in history */
static int modified; /* buffer has been "modified" */
static int state;

#if 0
vi_init()
{
es = (struct edstate *) malloc((unsigned) sizeof(struct edstate));
fsavecmd = ' ';
lastsearch = ' ';
}

edit_init()
{
wbuf[0] = malloc((unsigned) (x_cols - 3));
wbuf[1] = malloc((unsigned) (x_cols - 3));
}
#endif

void
vi_reset(buf, len)
char *buf;
int len;
{
state = VNORMAL;
hnum = hlast = histnum(-1) + 1;
insert = INSERT;
yanklen = 0;
inslen = 0;
lastcmd[0] = 'a';
lastac = 1;
modified = 1;
edit_reset(buf, len);
}

int
vi_hook(ch)
int ch;
{
static char curcmd[MAXVICMD];
static char locpat[SRCHLEN];
static int cmdlen;
static int argc1, argc2;

if (state != VSEARCH && (ch == '\r' || ch == '\n')) {
x_putc('\r');
x_putc('\n');
x_flush();
return 1;
}

switch (state) {

case VREPLACE1CHAR:
curcmd[cmdlen++] = ch;
state = VCMD;
break;

case VNORMAL:
if (insert != 0) {
if (ch == Ctrl('v')) {
state = VLIT;
ch = '^';
}
if (vi_insert(ch) != 0) {
x_putc(Ctrl('g'));
state = VNORMAL;
} else {
if (state == VLIT) {
es->cursor--;
refresh(0);
} else
refresh(insert != 0);
}
} else {
cmdlen = 0;
argc1 = 0;
if (ch >= '1' && ch <= '9') {
argc1 = ch - '0';
state = VARG1;
} else {
curcmd[cmdlen++] = ch;
state = nextstate(ch);
if (state == VSEARCH) {
save_cbuf();
es->cursor = 0;
es->linelen = 0;
if (ch == '/') {
if (putbuf("/", 1, 0) != 0) {
return -1;
}
} else if (putbuf("?", 1, 0) != 0)
return -1;
refresh(0);
}
}
}
break;

case VLIT:
if (isbad(ch)) {
del_range(es->cursor, es->cursor + 1);
x_putc(Ctrl('g'));
} else
es->cbuf[es->cursor++] = ch;
refresh(1);
state = VNORMAL;
break;

case VARG1:
if (isdigit(ch))
argc1 = argc1 * 10 + ch - '0';
else {
curcmd[cmdlen++] = ch;
state = nextstate(ch);
}
break;

case VEXTCMD:
argc2 = 0;
if (ch >= '1' && ch <= '9') {
argc2 = ch - '0';
state = VARG2;
return 0;
} else {
curcmd[cmdlen++] = ch;
if (ch == curcmd[0])
state = VCMD;
else if (ismove(ch))
state = nextstate(ch);
else
state = VFAIL;
}
break;

case VARG2:
if (isdigit(ch))
argc2 = argc2 * 10 + ch - '0';
else {
if (argc1 == 0)
argc1 = argc2;
else
argc1 *= argc2;
curcmd[cmdlen++] = ch;
if (ch == curcmd[0])
state = VCMD;
else if (ismove(ch))
state = nextstate(ch);
else
state = VFAIL;

}
break;

case VXCH:
if (ch == Ctrl('['))
state = VNORMAL;
else {
curcmd[cmdlen++] = ch;
state = VCMD;
}
break;

case VSEARCH:
switch (ch) {

/* case Ctrl('['): */
case '\r':
case '\n':
locpat[srchlen] = '\0';
(void) strcpy(srchpat, locpat);
/* redraw_line(); */
state = VCMD;
break;

case 0x7f:
if (srchlen == 0) {
restore_cbuf();
state = VNORMAL;
} else {
srchlen--;
if (locpat[srchlen] < ' ' ||
locpat[srchlen] == 0x7f) {
es->linelen--;
}
es->linelen--;
es->cursor = es->linelen;
refresh(0);
return 0;
}
refresh(0);
break;

case Ctrl('u'):
srchlen = 0;
es->linelen = 1;
es->cursor = 1;
refresh(0);
return 0;

default:
if (srchlen == SRCHLEN - 1)
x_putc(Ctrl('g'));
else {
locpat[srchlen++] = ch;
if (ch < ' ' || ch == 0x7f) {
es->cbuf[es->linelen++] = '^';
es->cbuf[es->linelen++] = ch ^ '@';
} else
es->cbuf[es->linelen++] = ch;
es->cursor = es->linelen;
refresh(0);
}
return 0;
break;
}
break;
}
switch (state) {

case VCMD:
state = VNORMAL;
switch (vi_cmd(argc1, curcmd)) {
case -1:
x_putc(Ctrl('g'));
break;
case 0:
if (insert != 0)
inslen = 0;
refresh(insert != 0);
break;
case 1:
refresh(0);
x_putc('\r');
x_putc('\n');
x_flush();
return 1;
}
break;

case VREDO:
state = VNORMAL;
if (argc1 != 0)
lastac = argc1;
switch (vi_cmd(lastac, lastcmd) != 0) {
case -1:
x_putc(Ctrl('g'));
refresh(0);
break;
case 0:
if (insert != 0) {
if (lastcmd[0] == 's' || lastcmd[0] == 'c' ||
lastcmd[0] == 'C') {
if (redo_insert(1) != 0)
x_putc(Ctrl('g'));
} else {
if (redo_insert(lastac) != 0)
x_putc(Ctrl('g'));
}
}
refresh(0);
break;
case 1:
refresh(0);
x_putc('\r');
x_putc('\n');
x_flush();
return 1;
}

break;

case VFAIL:
state = VNORMAL;
x_putc(Ctrl('g'));
break;
}
return 0;
}

static int
nextstate(ch)
int ch;
{
/*
* probably could have been done more elegantly than
* by creating a new state, but it works
*/
if (ch == 'r')
return VREPLACE1CHAR;
else if (isextend(ch))
return VEXTCMD;
else if (issrch(ch))
return VSEARCH;
else if (islong(ch))
return VXCH;
else if (ch == '.')
return VREDO;
else if (iscmd(ch))
return VCMD;
else
return VFAIL;
}

static int
vi_insert(ch)
int ch;
{
int tcursor;

switch (ch) {

case '\0':
return -1;

case Ctrl('['):
if (lastcmd[0] == 's' || lastcmd[0] == 'c' ||
lastcmd[0] == 'C')
return redo_insert(0);
else
return redo_insert(lastac - 1);

case 0x7f: /* delete */
/* tmp fix */
/* general fix is to get stty erase char and use that
*/
case Ctrl('H'): /* delete */
if (es->cursor != 0) {
if (inslen > 0)
inslen--;
es->cursor--;
if (insert != REPLACE) {
memmove(&es->cbuf[es->cursor],
&es->cbuf[es->cursor+1],
es->linelen - es->cursor);
es->linelen--;
}
}
break;

case Ctrl('U'):
if (es->cursor != 0) {
inslen = 0;
memmove(es->cbuf, &es->cbuf[es->cursor],
es->linelen - es->cursor);
es->linelen -= es->cursor;
es->cursor = 0;
}
break;

case Ctrl('W'):
if (es->cursor != 0) {
tcursor = backword(1);
memmove(&es->cbuf[tcursor], &es->cbuf[es->cursor],
es->linelen - es->cursor);
es->linelen -= es->cursor - tcursor;
if (inslen < es->cursor - tcursor)
inslen = 0;
else
inslen -= es->cursor - tcursor;
es->cursor = tcursor;
}
break;

default:
if (es->linelen == es->cbufsize - 1)
return -1;
ibuf[inslen++] = ch;
if (insert == INSERT) {
memmove(&es->cbuf[es->cursor+1], &es->cbuf[es->cursor],
es->linelen - es->cursor);
es->linelen++;
}
es->cbuf[es->cursor++] = ch;
if (insert == REPLACE && es->cursor > es->linelen)
es->linelen++;
}
return 0;
}

static int
vi_cmd(argcnt, cmd)
int argcnt;
char *cmd;
{
int ncursor;
int cur, c1, c2, c3 = 0;
struct edstate *t;


if (argcnt == 0) {
if (*cmd == 'G')
argcnt = hlast + 1;
else if (*cmd != '_')
argcnt = 1;
}

if (ismove(*cmd)) {
if ((cur = domove(argcnt, cmd, 0)) >= 0) {
if (cur == es->linelen && cur != 0)
cur--;
es->cursor = cur;
} else
return -1;
} else {
if (isundoable(*cmd)) {
undo->winleft = es->winleft;
memmove(undo->cbuf, es->cbuf, es->linelen);
undo->linelen = es->linelen;
undo->cursor = es->cursor;
lastac = argcnt;
memmove(lastcmd, cmd, MAXVICMD);
}
switch (*cmd) {

case Ctrl('r'):
redraw_line();
break;

case 'a':
modified = 1;
if (es->linelen != 0)
es->cursor++;
insert = INSERT;
break;

case 'A':
modified = 1;
del_range(0, 0);
es->cursor = es->linelen;
insert = INSERT;
break;

case 'c':
case 'd':
case 'y':
if (*cmd == cmd[1]) {
c1 = 0;
c2 = es->linelen;
} else if (!ismove(cmd[1]))
return -1;
else {
if ((ncursor = domove(argcnt, &cmd[1], 1)) < 0)
return -1;
if (*cmd == 'c' &&
(cmd[1]=='w' || cmd[1]=='W') &&
!isspace(es->cbuf[es->cursor])) {
while (isspace(es->cbuf[--ncursor]))
;
ncursor++;
}
if (ncursor > es->cursor) {
c1 = es->cursor;
c2 = ncursor;
} else {
c1 = ncursor;
c2 = es->cursor;
}
}
if (*cmd != 'c' && c1 != c2)
yank_range(c1, c2);
if (*cmd != 'y') {
del_range(c1, c2);
es->cursor = c1;
}
if (*cmd == 'c') {
modified = 1;
insert = INSERT;
}
break;

case 'p':
modified = 1;
if (es->linelen != 0)
es->cursor++;
while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
;
if (es->cursor != 0)
es->cursor--;
if (argcnt != 0)
return -1;
break;

case 'P':
modified = 1;
while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
;
if (es->cursor != 0)
es->cursor--;
if (argcnt != 0)
return -1;
break;

case 'C':
modified = 1;
del_range(es->cursor, es->linelen);
insert = INSERT;
break;

case 'D':
yank_range(es->cursor, es->linelen);
del_range(es->cursor, es->linelen);
if (es->cursor != 0)
es->cursor--;
break;

case 'G':
if (grabhist(modified, argcnt - 1) < 0)
return -1;
else {
modified = 0;
hnum = argcnt - 1;
}
break;

case 'i':
modified = 1;
insert = INSERT;
break;

case 'I':
modified = 1;
es->cursor = 0;
insert = INSERT;
break;

case '+':
case 'j':
if (grabhist(modified, hnum + argcnt) < 0)
return -1;
else {
modified = 0;
hnum += argcnt;
}
break;

case '-':
case 'k':
if (grabhist(modified, hnum - argcnt) < 0)
return -1;
else {
modified = 0;
hnum -= argcnt;
}
break;

case 'r':
if (es->linelen == 0)
return -1;
modified = 1;
es->cbuf[es->cursor] = cmd[1];
break;

case 'R':
modified = 1;
insert = REPLACE;
break;

case 's':
if (es->linelen == 0)
return -1;
modified = 1;
if (es->cursor + argcnt > es->linelen)
argcnt = es->linelen - es->cursor;
del_range(es->cursor, es->cursor + argcnt);
insert = INSERT;
break;

case 'x':
if (es->linelen == 0)
return -1;
modified = 1;
if (es->cursor + argcnt > es->linelen)
argcnt = es->linelen - es->cursor;
yank_range(es->cursor, es->cursor + argcnt);
del_range(es->cursor, es->cursor + argcnt);
break;

case 'X':
if (es->cursor > 0) {
modified = 1;
if (es->cursor < argcnt)
argcnt = es->cursor;
yank_range(es->cursor - argcnt, es->cursor);
del_range(es->cursor - argcnt, es->cursor);
es->cursor -= argcnt;
} else
return -1;
break;

case 'u':
t = es;
es = undo;
undo = t;

break;

case '?':
hnum = -1;
/* ahhhhhh... */
case '/':
c3 = 1;
srchlen = 0;
lastsearch = *cmd;
/* fall through */
case 'n':
case 'N':
if (lastsearch == ' ')
return -1;
if (lastsearch == '?')
c1 = 1;
else
c1 = 0;
if (*cmd == 'N')
c1 = !c1;
if ((c2 = grabsearch(modified, hnum,
c1, srchpat)) < 0) {
if (c3) {
restore_cbuf();
refresh(0);
}
return -1;
} else {
modified = 0;
hnum = c2;
}
break;
case '_': {
int space;
char *p, *sp;

(void) histnum(-1);
p = *histpos();
#define issp(c) (isspace((c)) || (c) == '\n')
if (argcnt) {
while (*p && issp(*p))
p++;
while (*p && --argcnt) {
while (*p && !issp(*p))
p++;
while (*p && issp(*p))
p++;
}
if (!*p)
return -1;
sp = p;
} else {
sp = p;
space = 0;
while (*p) {
if (issp(*p))
space = 1;
else if (space) {
space = 0;
sp = p;
}
p++;
}
p = sp;
}
modified = 1;
if (es->linelen != 0)
es->cursor++;
while (*p && !issp(*p)) {
argcnt++;
p++;
}
if (putbuf(" ", 1, 0) != 0)
argcnt = -1;
else if (putbuf(sp, argcnt, 0) != 0)
argcnt = -1;
if (argcnt < 0) {
if (es->cursor != 0)
es->cursor--;
return -1;
}
insert = INSERT;
}
break;

case '~': {
char *p;

if (es->linelen == 0)
return -1;
p = &es->cbuf[es->cursor];
if (islower(*p)) {
modified = 1;
*p = toupper(*p);
} else if (isupper(*p)) {
modified = 1;
*p = tolower(*p);
}
if (es->cursor < es->linelen - 1)
es->cursor++;
}
break;

case '#':
es->cursor = 0;
if (putbuf("#", 1, 0) != 0)
return -1;
return 1;

case '*':
case '=': {
int rval = 0;
int start, end;
char *toglob = undo->cbuf;
char **ap;
char **ap2;
char **globstr();

if (isspace(es->cbuf[es->cursor]))
return -1;
start = es->cursor;
while (start > -1 && !isspace(es->cbuf[start]))
start--;
start++;
end = es->cursor;
while (end < es->linelen && !isspace(es->cbuf[end]))
end++;
/* use undo buffer to build word up in */
memmove(toglob, &es->cbuf[start], end-start);
if (toglob[end-start-1] != '*') {
toglob[end-start] = '*';
toglob[end-start+1] = '\0';
} else
toglob[end-start] = '\0';
ap = globstr(toglob);
ap2 = ap;
if (strcmp(ap[0], toglob) == 0 && ap[1] == (char *) 0)
rval = -1;
/* restore undo buffer that we used temporarily */
memmove(toglob, es->cbuf, es->linelen);
if (rval < 0)
return rval;
if (*cmd == '=') {
fputc('\n', shlout);
pr_menu(ap2, 0);
fflush(shlout);
if (es->linelen != 0)
es->cursor++;
redraw_line();
insert = INSERT;
state = VNORMAL;
return 0;
} else {
del_range(start, end);
es->cursor = start;
while (1) {
if (putbuf(*ap, strlen(*ap), 0) != 0) {
rval = -1;
break;
}
if (*++ap == (char *) 0)
break;
if (putbuf(" ", 1, 0) != 0) {
rval = -1;
break;
}

}
#if 0
/*
* this is definitely wrong
*/
for (ap = ap2; *ap; ap++)
free(*ap);

free(ap2);
#endif

modified = 1;
insert = INSERT;
refresh(0);
}
if (rval != 0)
return rval;
}
break;
}
if (insert == 0 && es->cursor != 0 && es->cursor >= es->linelen)
es->cursor--;
}
return 0;
}

static int
domove(argcnt, cmd, sub)
int argcnt;
char *cmd;
int sub;
{
int bcount, i = 0, t; /* = 0 kludge for gcc -W */
int ncursor = 0; /* = 0 kludge for gcc -W */

switch (*cmd) {

case 'b':
if (!sub && es->cursor == 0)
return -1;
ncursor = backword(argcnt);
break;

case 'B':
if (!sub && es->cursor == 0)
return -1;
ncursor = Backword(argcnt);
break;

case 'e':
if (!sub && es->cursor + 1 >= es->linelen)
return -1;
ncursor = endword(argcnt);
if (sub)
ncursor++;
break;

case 'E':
if (!sub && es->cursor + 1 >= es->linelen)
return -1;
ncursor = Endword(argcnt);
if (sub)
ncursor++;
break;

case 'f':
case 'F':
case 't':
case 'T':
fsavecmd = *cmd;
fsavech = cmd[1];
/* drop through */

case ',':
case ';':
if (fsavecmd == ' ')
return -1;
i = fsavecmd == 'f' || fsavecmd == 'F';
t = fsavecmd > 'a';
if (*cmd == ',')
t = !t;
if ((ncursor = findch(fsavech, argcnt, t, i)) < 0)
return -1;
if (sub && t)
ncursor++;
break;

case 'h':
/* tmp fix */
case Ctrl('H'):
if (!sub && es->cursor == 0)
return -1;
ncursor = es->cursor - argcnt;
if (ncursor < 0)
ncursor = 0;
break;

case ' ':
case 'l':
if (!sub && es->cursor + 1 >= es->linelen)
return -1;
if (es->linelen != 0) {
ncursor = es->cursor + argcnt;
if (ncursor >= es->linelen)
ncursor = es->linelen - 1;
}
break;

case 'w':
if (!sub && es->cursor + 1 >= es->linelen)
return -1;
ncursor = forwword(argcnt);
break;

case 'W':
if (!sub && es->cursor + 1 >= es->linelen)
return -1;
ncursor = Forwword(argcnt);
break;

case '0':
ncursor = 0;
break;

case '^':
ncursor = 0;
while (ncursor < es->linelen - 1 && isspace(es->cbuf[ncursor]))
ncursor++;
break;

case '$':
if (es->linelen != 0)
ncursor = es->linelen;
else
ncursor = 0;
break;

case '%':
ncursor = es->cursor;
while (ncursor < es->linelen &&
(i = bracktype(es->cbuf[ncursor])) == 0)
ncursor++;
if (ncursor == es->linelen)
return -1;
bcount = 1;
do {
if (i > 0) {
if (++ncursor >= es->linelen)
return -1;
} else {
if (--ncursor < 0)
return -1;
}
t = bracktype(es->cbuf[ncursor]);
if (t == i)
bcount++;
else if (t == -i)
bcount--;
} while (bcount != 0);
if (sub)
ncursor++;
break;

default:
return -1;
}
return ncursor;
}

static int
redo_insert(count)
int count;
{
while (count-- > 0)
if (putbuf(ibuf, inslen, insert==REPLACE) != 0)
return -1;
if (es->cursor > 0)
es->cursor--;
insert = 0;
return 0;
}

static
yank_range(a, b)
int a, b;
{
yanklen = b - a;
if (yanklen != 0)
memmove(ybuf, &es->cbuf[a], yanklen);
}

static int
bracktype(ch)
int ch;
{
switch (ch) {

case '(':
return 1;

case '[':
return 2;

case '{':
return 3;

case ')':
return -1;

case ']':
return -2;

case '}':
return -3;

default:
return 0;
}
}

/*
* Non user interface editor routines below here
*/

static int cur_col; /* current column on line */
static int pwidth; /* width of prompt */
static int winwidth; /* width of window */
/*static char *wbuf[2]; /* window buffers */
static char wbuf[2][128-3]; /* window buffers */ /* TODO */
static int win; /* window buffer in use */
static char morec; /* more character at right of window */
static int lastref; /* argument to last refresh() */
static char holdbuf[CMDLEN]; /* place to hold last edit buffer */
static int holdlen; /* length of holdbuf */

save_cbuf()
{
memmove(holdbuf, es->cbuf, es->linelen);
holdlen = es->linelen;
holdbuf[holdlen] = '\0';
}

restore_cbuf()
{
es->cursor = 0;
es->linelen = holdlen;
memmove(es->cbuf, holdbuf, holdlen);
}

static
edit_reset(buf, len)
char *buf;
int len;
{
es = &ebuf;
es->cbuf = buf;
es->cbufsize = len;
undo = &undobuf;
undo->cbufsize = len;

es->linelen = undo->linelen = 0;
es->cursor = undo->cursor = 0;
es->winleft = undo->winleft = 0;

cur_col = pwidth = promptlen(prompt);
winwidth = x_cols - pwidth - 3;
x_putc('\r');
x_flush();
pprompt(prompt);
/* docap(CLR_EOL, 0); */
win = 0;
morec = ' ';
lastref = 1;
}

static int
putbuf(buf, len, repl)
char *buf;
int len;
int repl;
{
if (len == 0)
return 0;
if (repl) {
if (es->cursor + len >= es->cbufsize - 1)
return -1;
if (es->cursor + len > es->linelen)
es->linelen = es->cursor + len;
} else {
if (es->linelen + len >= es->cbufsize - 1)
return -1;
memmove(&es->cbuf[es->cursor + len], &es->cbuf[es->cursor],
es->linelen - es->cursor);
es->linelen += len;
}
memmove(&es->cbuf[es->cursor], buf, len);
es->cursor += len;
return 0;
}

static
stripblanks()
{
int ncursor;

ncursor = 0;
while (ncursor < es->linelen && isspace(es->cbuf[ncursor]))
ncursor++;
del_range(0, ncursor);
}

static
del_range(a, b)
int a, b;
{
if (es->linelen != b)
memmove(&es->cbuf[a], &es->cbuf[b], es->linelen - b);
es->linelen -= b - a;
}

static int
findch(ch, cnt, forw, incl)
int ch;
int forw;
int incl;
{
int ncursor;

if (es->linelen == 0)
return -1;
ncursor = es->cursor;
while (cnt--) {
do {
if (forw) {
if (++ncursor == es->linelen)
return -1;
} else {
if (--ncursor < 0)
return -1;
}
} while (es->cbuf[ncursor] != ch);
}
if (!incl) {
if (forw)
ncursor--;
else
ncursor++;
}
return ncursor;
}

#define Isalnum(x) (isalnum(x) || (x == '_'))
static int
forwword(argcnt)
int argcnt;
{
int ncursor;

ncursor = es->cursor;
while (ncursor < es->linelen && argcnt--) {
if (Isalnum(es->cbuf[ncursor]))
while (Isalnum(es->cbuf[ncursor]) &&
++ncursor < es->linelen)
;
else if (!isspace(es->cbuf[ncursor]))
while (!Isalnum(es->cbuf[ncursor]) &&
!isspace(es->cbuf[ncursor]) &&
++ncursor < es->linelen)
;
while (isspace(es->cbuf[ncursor]) && ++ncursor < es->linelen)
;
}
return ncursor;
}

static int
backword(argcnt)
int argcnt;
{
int ncursor;

ncursor = es->cursor;
while (ncursor > 0 && argcnt--) {
while (--ncursor > 0 && isspace(es->cbuf[ncursor]))
;
if (ncursor > 0) {
if (Isalnum(es->cbuf[ncursor]))
while (--ncursor >= 0 &&
Isalnum(es->cbuf[ncursor]))
;
else
while (--ncursor >= 0 &&
!Isalnum(es->cbuf[ncursor]) &&
!isspace(es->cbuf[ncursor]))
;
ncursor++;
}
}
return ncursor;
}

static int
endword(argcnt)
int argcnt;
{
int ncursor;

ncursor = es->cursor;
while (ncursor < es->linelen && argcnt--) {
while (++ncursor < es->linelen - 1 &&
isspace(es->cbuf[ncursor]))
;
if (ncursor < es->linelen - 1) {
if (Isalnum(es->cbuf[ncursor]))
while (++ncursor < es->linelen &&
Isalnum(es->cbuf[ncursor]))
;
else
while (++ncursor < es->linelen &&
!Isalnum(es->cbuf[ncursor]) &&
!isspace(es->cbuf[ncursor]))
;
ncursor--;
}
}
return ncursor;
}

static int
Forwword(argcnt)
int argcnt;
{
int ncursor;

ncursor = es->cursor;
while (ncursor < es->linelen && argcnt--) {
while (!isspace(es->cbuf[ncursor]) && ++ncursor < es->linelen)
;
while (isspace(es->cbuf[ncursor]) && ++ncursor < es->linelen)
;
}
return ncursor;
}

static int
Backword(argcnt)
int argcnt;
{
int ncursor;

ncursor = es->cursor;
while (ncursor > 0 && argcnt--) {
while (--ncursor >= 0 && isspace(es->cbuf[ncursor]))
;
while (ncursor >= 0 && !isspace(es->cbuf[ncursor]))
ncursor--;
ncursor++;
}
return ncursor;
}

static int
Endword(argcnt)
int argcnt;
{
int ncursor;

ncursor = es->cursor;
while (ncursor < es->linelen - 1 && argcnt--) {
while (++ncursor < es->linelen - 1 &&
isspace(es->cbuf[ncursor]))
;
if (ncursor < es->linelen - 1) {
while (++ncursor < es->linelen &&
!isspace(es->cbuf[ncursor]))
;
ncursor--;
}
}
return ncursor;
}

static int
grabhist(save, n)
int save;
int n;
{
char *hptr;

if (n < 0 || n > hlast)
return -1;
if (n == hlast) {
restore_cbuf();
return 0;
}
(void) histnum(n);
if ((hptr = *histpos()) == NULL) {
shellf("grabhist: bad history array\n");
return -1;
}
if (save)
save_cbuf();
es->linelen = strlen(hptr);
memmove(es->cbuf, hptr, es->linelen);
es->cursor = 0;
return 0;
}

static int
grabsearch(save, start, fwd, pat)
int save, start, fwd;
char *pat;
{
char *hptr;

if ((start == 0 && fwd == 0) || (start >= hlast - 1 && fwd == 1))
return -1;
if ((hptr = findhist(start, fwd, pat)) == NULL) {
/* if (start != 0 && fwd && match(holdbuf, pat) >= 0) { */
if (start != 0 && fwd && strcmp(holdbuf, pat) >= 0) {
restore_cbuf();
return 0;
} else
return -1;
} else if (hptr == (char *)-1) {
return -1;
}
if (save)
save_cbuf();
es->linelen = strlen(hptr);
memmove(es->cbuf, hptr, es->linelen);
es->cursor = 0;
return histN();
}

static
redraw_line()
{
x_putc('\r');
x_putc('\n');
x_flush();
pprompt(prompt);
cur_col = pwidth;
morec = ' ';
}

static
refresh(leftside)
int leftside;
{
if (leftside < 0)
leftside = lastref;
else
lastref = leftside;
if (outofwin())
rewindow();
display(wbuf[1 - win], wbuf[win], leftside);
win = 1 - win;
}

static int
outofwin()
{
int cur, col;

if (es->cursor < es->winleft)
return 1;
col = 0;
cur = es->winleft;
while (cur < es->cursor)
col = newcol(es->cbuf[cur++], col);
if (col > winwidth)
return 1;
return 0;
}

static
rewindow()
{
register int tcur, tcol;
int holdcur1, holdcol1;
int holdcur2, holdcol2;

holdcur1 = holdcur2 = tcur = 0;
holdcol1 = holdcol2 = tcol = 0;
while (tcur < es->cursor) {
if (tcol - holdcol2 > winwidth / 2) {
holdcur1 = holdcur2;
holdcol1 = holdcol2;
holdcur2 = tcur;
holdcol2 = tcol;
}
tcol = newcol(es->cbuf[tcur++], tcol);
}
while (tcol - holdcol1 > winwidth / 2)
holdcol1 = newcol(es->cbuf[holdcur1++], holdcol1);
es->winleft = holdcur1;
}

static int
newcol(ch, col)
int ch, col;
{
if (ch < ' ' || ch == 0x7f) {
if (ch == '\t')
return (col | 7) + 1;
else
return col + 2;
} else
return col + 1;
}

static
display(wb1, wb2, leftside)
char *wb1, *wb2;
int leftside;
{
char *twb1, *twb2, mc;
int cur, col, cnt;
int ncol = 0; /* set to 0 kludge for gcc -W */
int moreright;

col = 0;
cur = es->winleft;
moreright = 0;
twb1 = wb1;
while (col < winwidth && cur < es->linelen) {
if (cur == es->cursor && leftside)
ncol = col + pwidth;
if (es->cbuf[cur] < ' ' || es->cbuf[cur] == 0x7f) {
if (es->cbuf[cur] == '\t') {
do {
*twb1++ = ' ';
} while (++col < winwidth && (col & 7) != 0);
} else {
*twb1++ = '^';
if (++col < winwidth) {
*twb1++ = es->cbuf[cur] ^ '@';
col++;
}
}
} else {
*twb1++ = es->cbuf[cur];
col++;
}
if (cur == es->cursor && !leftside)
ncol = col + pwidth - 1;
cur++;
}
if (cur == es->cursor)
ncol = col + pwidth;
if (col < winwidth) {
while (col < winwidth) {
*twb1++ = ' ';
col++;
}
} else
moreright++;
*twb1 = ' ';

col = pwidth;
cnt = winwidth;
twb1 = wb1;
twb2 = wb2;
while (cnt--) {
if (*twb1 != *twb2) {
if (cur_col != col)
ed_mov_opt(col, wb1);
x_putc(*twb1);
cur_col++;
}
twb1++;
twb2++;
col++;
}
if (es->winleft > 0 && moreright)
mc = '+';
else if (es->winleft > 0)
mc = '<';
else if (moreright)
mc = '>';
else
mc = ' ';
if (mc != morec) {
ed_mov_opt(x_cols - 2, wb1);
x_putc(mc);
cur_col++;
morec = mc;
}
#if 0
/*
* Hack to fix the ^r redraw problem, but it redraws way too much.
* Probably unacceptable at low baudrates. Someone please fix this
*/
else
{
ed_mov_opt(x_cols - 2, wb1);
}
#endif
if (cur_col != ncol)
ed_mov_opt(ncol, wb1);
}

static
ed_mov_opt(col, wb)
int col;
char *wb;
{
if (col < cur_col) {
if (col + 1 < cur_col - col) {
x_putc('\r');
x_flush();
pprompt(prompt);
cur_col = pwidth;
while (cur_col++ < col)
x_putc(*wb++);
} else {
while (cur_col-- > col)
x_putc('\b');
}
} else {
wb = &wb[cur_col - pwidth];
while (cur_col++ < col)
x_putc(*wb++);
}
cur_col = col;
}

int
x_vi(buf, len)
char *buf;
size_t len;
{
int c;

vi_reset(buf, len > CMDLEN ? CMDLEN : len);
x_flush();
while ((c = getch()) != -1) {
if (vi_hook(c))
break;
x_flush();
}

if (c == -1)
return -1;

if (es->cbuf != buf) {
memmove(buf, es->cbuf, es->linelen);
buf[es->linelen] = '\n';
} else
es->cbuf[es->linelen] = '\n';

es->linelen++;
return es->linelen;
}

getch()
{
unsigned char buf;

#ifdef OS2
do
{
buf = _read_kbd(0, 1, 0);
if ( buf == 0 || buf == 0xE0 )
_read_kbd(0, 1, 0);
}
while ( buf == 0 || buf == 0xE0 );
if (buf == Ctrl('c')) {
#else
if (read(ttyfd, &buf, 1) != 1)
return -1;
if ((buf & 0x7f) == Ctrl('c')) {
#endif
/*
* If you hit ctrl-c, the buffer was left in a
* strange state; the next command typed was
* mucked up. Doing all of this is probably
* overkill, but it works most of the time.
*/
memset(es->cbuf, 0, CMDLEN);
es->winleft = 0;
es->cbufsize = 0;
es->linelen = 0;
es->cursor = 0;

memset(undo->cbuf, 0, CMDLEN);
undo->winleft = 0;
undo->cbufsize = 0;
undo->linelen = 0;
undo->cursor = 0;
x_mode(FALSE);
trapsig(SIGINT);
#ifdef OS2
} else if (buf == Ctrl('d'))
return -1;
return buf;
#else
} else if ((buf & 0x7f) == Ctrl('d'))
return -1;
return buf & 0x7f;
#endif
}


char **globstr(stuff)
char *stuff;
{
char *vecp[2];

vecp[0] = stuff;
vecp[1] = NULL;
return(eval(vecp, DOBLANK|DOGLOB|DOTILDE));
}
#endif /* VI */