#include "sh.h"
RCSID("$Id: ed.inputl.c,v 1.1.1.2 2001/06/28 23:10:47 bbraun Exp $")
#include "ed.h"
#include "ed.defns.h"
#include "tw.h"
#define OKCMD (INBUFSIZE+INBUFSIZE)
extern bool tellwhat;
extern bool MapsAreInited;
extern bool Tty_raw_mode;
static Char mismatch[] =
{'!', '^' , '\\', '-', '%', '\0', '"', '\'', '`', '\0' };
static int Repair __P((void));
static int GetNextCommand __P((KEYCMD *, Char *));
static int SpellLine __P((int));
static int CompleteLine __P((void));
static void RunCommand __P((Char *));
static void doeval1 __P((Char **));
static bool rotate = 0;
static int
Repair()
{
if (NeedsRedraw) {
ClearLines();
ClearDisp();
NeedsRedraw = 0;
}
Refresh();
Argument = 1;
DoingArg = 0;
curchoice = -1;
return (int) (LastChar - InputBuf);
}
int
Inputl()
{
CCRETVAL retval;
KEYCMD cmdnum = 0;
extern KEYCMD NumFuns;
unsigned char tch;
Char ch;
int num;
int expnum;
struct varent *crct = inheredoc ? NULL : adrof(STRcorrect);
struct varent *autol = adrof(STRautolist);
struct varent *matchbeep = adrof(STRmatchbeep);
struct varent *imode = adrof(STRinputmode);
Char *SaveChar, *CorrChar;
Char Origin[INBUFSIZE], Change[INBUFSIZE];
int matchval;
COMMAND fn;
int curlen = 0;
int newlen;
int idx;
if (!MapsAreInited)
ed_InitMaps();
ClearDisp();
ResetInLine(0);
if (GettingInput)
MacroLvl = -1;
if (imode) {
if (!Strcmp(*(imode->vec), STRinsert))
inputmode = MODE_INSERT;
else if (!Strcmp(*(imode->vec), STRoverwrite))
inputmode = MODE_REPLACE;
}
#if defined(FIONREAD) && !defined(OREO)
if (!Tty_raw_mode && MacroLvl < 0) {
# ifdef SUNOS4
long chrs = 0;
# else
int chrs = 0;
# endif
(void) ioctl(SHIN, FIONREAD, (ioctl_t) & chrs);
if (chrs == 0) {
if (Rawmode() < 0)
return 0;
}
}
#endif
GettingInput = 1;
NeedsRedraw = 0;
if (tellwhat) {
copyn(InputBuf, WhichBuf, INBUFSIZE);
LastChar = InputBuf + (LastWhich - WhichBuf);
Cursor = InputBuf + (CursWhich - WhichBuf);
tellwhat = 0;
Hist_num = HistWhich;
}
if (Expand) {
(void) e_up_hist(0);
Expand = 0;
}
Refresh();
for (num = OKCMD; num == OKCMD;) {
#ifdef DEBUG_EDIT
if (Cursor > LastChar)
xprintf("Cursor > LastChar\r\n");
if (Cursor < InputBuf)
xprintf("Cursor < InputBuf\r\n");
if (Cursor > InputLim)
xprintf("Cursor > InputLim\r\n");
if (LastChar > InputLim)
xprintf("LastChar > InputLim\r\n");
if (InputLim != &InputBuf[INBUFSIZE - 2])
xprintf("InputLim != &InputBuf[INBUFSIZE-2]\r\n");
if ((!DoingArg) && (Argument != 1))
xprintf("(!DoingArg) && (Argument != 1)\r\n");
if (CcKeyMap[0] == 0)
xprintf("CcKeyMap[0] == 0 (maybe not inited)\r\n");
#endif
if ((num = GetNextCommand(&cmdnum, &ch)) != OKCMD) {
break;
}
if (cmdnum >= NumFuns) {
#ifdef DEBUG_EDIT
xprintf(CGETS(6, 1, "ERROR: illegal command from key 0%o\r\n"), ch);
#endif
continue;
}
retval = (*CcFuncTbl[cmdnum]) (ch);
LastCmd = cmdnum;
fn = (retval == CC_COMPLETE_ALL) ? LIST_ALL : LIST;
switch (retval) {
case CC_REFRESH:
Refresh();
case CC_NORM:
Argument = 1;
DoingArg = 0;
case CC_ARGHACK:
curchoice = -1;
curlen = (int) (LastChar - InputBuf);
break;
case CC_EOF:
curchoice = -1;
curlen = (int) (LastChar - InputBuf);
num = 0;
break;
case CC_WHICH:
tellwhat = 1;
copyn(WhichBuf, InputBuf, INBUFSIZE);
LastWhich = WhichBuf + (LastChar - InputBuf);
CursWhich = WhichBuf + (Cursor - InputBuf);
*LastChar++ = '\n';
HistWhich = Hist_num;
Hist_num = 0;
num = (int) (LastChar - InputBuf);
break;
case CC_NEWLINE:
curlen = 0;
curchoice = -1;
matchval = 1;
if (crct && (!Strcmp(*(crct->vec), STRcmd) ||
!Strcmp(*(crct->vec), STRall))) {
PastBottom();
copyn(Origin, InputBuf, INBUFSIZE);
SaveChar = LastChar;
if (SpellLine(!Strcmp(*(crct->vec), STRcmd)) == 1) {
PastBottom();
copyn(Change, InputBuf, INBUFSIZE);
*Strchr(Change, '\n') = '\0';
CorrChar = LastChar;
LastChar = InputBuf;
SoundBeep();
printprompt(2, short2str(Change));
Refresh();
if (read(SHIN, (char *) &tch, 1) < 0)
#ifdef convex
if (errno && errno != EINTR)
stderror(ERR_SYSTEM, progname, strerror(errno));
#else
break;
#endif
ch = tch;
if (ch == 'y' || ch == ' ') {
LastChar = CorrChar;
xprintf(CGETS(6, 2, "yes\n"));
}
else {
copyn(InputBuf, Origin, INBUFSIZE);
LastChar = SaveChar;
if (ch == 'e') {
xprintf(CGETS(6, 3, "edit\n"));
*LastChar-- = '\0';
Cursor = LastChar;
printprompt(3, NULL);
ClearLines();
ClearDisp();
Refresh();
break;
}
else if (ch == 'a') {
xprintf(CGETS(6, 4, "abort\n"));
LastChar = InputBuf;
Cursor = LastChar;
printprompt(0, NULL);
Refresh();
break;
}
xprintf(CGETS(6, 5, "no\n"));
}
flush();
}
} else if (crct && !Strcmp(*(crct->vec), STRcomplete)) {
if (LastChar > InputBuf && LastChar[-1] == '\n') {
LastChar[-1] = '\0';
LastChar--;
Cursor = LastChar;
}
match_unique_match = 1;
matchval = CompleteLine();
match_unique_match = 0;
curlen = (int) (LastChar - InputBuf);
if (matchval != 1) {
PastBottom();
}
if (matchval == 0) {
xprintf(CGETS(6, 6, "No matching command\n"));
} else if (matchval == 2) {
xprintf(CGETS(6, 7, "Ambiguous command\n"));
}
if (NeedsRedraw) {
ClearLines();
ClearDisp();
NeedsRedraw = 0;
}
Refresh();
Argument = 1;
DoingArg = 0;
if (matchval == 1) {
PastBottom();
*LastChar++ = '\n';
*LastChar = '\0';
}
curlen = (int) (LastChar - InputBuf);
}
else
PastBottom();
if (matchval == 1) {
tellwhat = 0;
Hist_num = 0;
num = (int) (LastChar - InputBuf);
printprompt(1, NULL);
}
break;
case CC_CORRECT:
if (tenematch(InputBuf, Cursor - InputBuf, SPELL) < 0)
SoundBeep();
curlen = Repair();
break;
case CC_CORRECT_L:
if (SpellLine(FALSE) < 0)
SoundBeep();
curlen = Repair();
break;
case CC_COMPLETE:
case CC_COMPLETE_ALL:
case CC_COMPLETE_FWD:
case CC_COMPLETE_BACK:
switch (retval) {
case CC_COMPLETE:
fn = RECOGNIZE;
curlen = (int) (LastChar - InputBuf);
curchoice = -1;
rotate = 0;
break;
case CC_COMPLETE_ALL:
fn = RECOGNIZE_ALL;
curlen = (int) (LastChar - InputBuf);
curchoice = -1;
rotate = 0;
break;
case CC_COMPLETE_FWD:
fn = RECOGNIZE_SCROLL;
curchoice++;
rotate = 1;
break;
case CC_COMPLETE_BACK:
fn = RECOGNIZE_SCROLL;
curchoice--;
rotate = 1;
break;
default:
abort();
}
if (InputBuf[curlen] && rotate) {
newlen = (int) (LastChar - InputBuf);
for (idx = (int) (Cursor - InputBuf);
idx <= newlen; idx++)
InputBuf[idx - newlen + curlen] =
InputBuf[idx];
LastChar = InputBuf + curlen;
Cursor = Cursor - newlen + curlen;
}
curlen = (int) (LastChar - InputBuf);
if (adrof(STRautoexpand))
(void) e_expand_history(0);
expnum = (int) (Cursor - InputBuf);
switch (matchval = tenematch(InputBuf, Cursor-InputBuf, fn)){
case 1:
if (non_unique_match && matchbeep &&
(Strcmp(*(matchbeep->vec), STRnotunique) == 0))
SoundBeep();
break;
case 0:
if (matchbeep) {
if (Strcmp(*(matchbeep->vec), STRnomatch) == 0 ||
Strcmp(*(matchbeep->vec), STRambiguous) == 0 ||
Strcmp(*(matchbeep->vec), STRnotunique) == 0)
SoundBeep();
}
else
SoundBeep();
break;
default:
if (matchval < 0) {
curchoice = -1;
SoundBeep();
break;
}
if (matchbeep) {
if ((Strcmp(*(matchbeep->vec), STRambiguous) == 0 ||
Strcmp(*(matchbeep->vec), STRnotunique) == 0))
SoundBeep();
}
else
SoundBeep();
if (autol && (Strcmp(*(autol->vec), STRambiguous) != 0 ||
expnum == Cursor - InputBuf)) {
PastBottom();
fn = (retval == CC_COMPLETE_ALL) ? LIST_ALL : LIST;
(void) tenematch(InputBuf, Cursor-InputBuf, fn);
}
break;
}
if (NeedsRedraw) {
PastBottom();
ClearLines();
ClearDisp();
NeedsRedraw = 0;
}
Refresh();
Argument = 1;
DoingArg = 0;
break;
case CC_LIST_CHOICES:
case CC_LIST_ALL:
if (InputBuf[curlen] && rotate) {
newlen = (int) (LastChar - InputBuf);
for (idx = (int) (Cursor - InputBuf);
idx <= newlen; idx++)
InputBuf[idx - newlen + curlen] =
InputBuf[idx];
LastChar = InputBuf + curlen;
Cursor = Cursor - newlen + curlen;
}
curlen = (int) (LastChar - InputBuf);
if (curchoice >= 0)
curchoice--;
fn = (retval == CC_LIST_ALL) ? LIST_ALL : LIST;
if (tenematch(InputBuf, Cursor - InputBuf, fn) < 0)
SoundBeep();
Refresh();
Argument = 1;
DoingArg = 0;
break;
case CC_LIST_GLOB:
if (tenematch(InputBuf, Cursor - InputBuf, GLOB) < 0)
SoundBeep();
curlen = Repair();
break;
case CC_EXPAND_GLOB:
if (tenematch(InputBuf, Cursor - InputBuf, GLOB_EXPAND) <= 0)
SoundBeep();
curlen = Repair();
break;
case CC_NORMALIZE_PATH:
if (tenematch(InputBuf, Cursor - InputBuf, PATH_NORMALIZE) <= 0)
SoundBeep();
curlen = Repair();
break;
case CC_EXPAND_VARS:
if (tenematch(InputBuf, Cursor - InputBuf, VARS_EXPAND) <= 0)
SoundBeep();
curlen = Repair();
break;
case CC_NORMALIZE_COMMAND:
if (tenematch(InputBuf, Cursor - InputBuf, COMMAND_NORMALIZE) <= 0)
SoundBeep();
curlen = Repair();
break;
case CC_HELPME:
xputchar('\n');
(void) tenematch(InputBuf, LastChar - InputBuf, PRINT_HELP);
Refresh();
Argument = 1;
DoingArg = 0;
curchoice = -1;
curlen = (int) (LastChar - InputBuf);
break;
case CC_FATAL:
#ifdef DEBUG_EDIT
xprintf(CGETS(7, 8, "*** editor fatal ERROR ***\r\n\n"));
#endif
ClearDisp();
ResetInLine(1);
Refresh();
Argument = 1;
DoingArg = 0;
curchoice = -1;
curlen = (int) (LastChar - InputBuf);
break;
case CC_ERROR:
default:
DoingArg = 0;
Argument = 1;
SoundBeep();
flush();
curchoice = -1;
curlen = (int) (LastChar - InputBuf);
break;
}
}
(void) Cookedmode();
GettingInput = 0;
flush();
return num;
}
void
PushMacro(str)
Char *str;
{
if (str != NULL && MacroLvl + 1 < MAXMACROLEVELS) {
MacroLvl++;
KeyMacro[MacroLvl] = str;
}
else {
SoundBeep();
flush();
}
}
static Char **gv = NULL, **gav = NULL;
static void
doeval1(v)
Char **v;
{
Char **oevalvec;
Char *oevalp;
int my_reenter;
Char **savegv;
jmp_buf_t osetexit;
oevalvec = evalvec;
oevalp = evalp;
savegv = gv;
gav = v;
gflag = 0, tglob(gav);
if (gflag) {
gv = gav = globall(gav);
gargv = 0;
if (gav == 0)
stderror(ERR_NOMATCH);
gav = copyblk(gav);
}
else {
gv = NULL;
gav = copyblk(gav);
trim(gav);
}
getexit(osetexit);
#ifdef cray
my_reenter = 1;
if (setexit() == 0) {
my_reenter = 0;
#else
if ((my_reenter = setexit()) == 0) {
#endif
evalvec = gav;
evalp = 0;
process(0);
}
evalvec = oevalvec;
evalp = oevalp;
doneinp = 0;
if (gv)
blkfree(gv);
gv = savegv;
resexit(osetexit);
if (my_reenter)
stderror(ERR_SILENT);
}
static void
RunCommand(str)
Char *str;
{
Char *cmd[2];
xputchar('\n');
cmd[0] = str;
cmd[1] = NULL;
(void) Cookedmode();
GettingInput = 0;
doeval1(cmd);
(void) Rawmode();
GettingInput = 1;
ClearLines();
ClearDisp();
NeedsRedraw = 0;
Refresh();
}
static int
GetNextCommand(cmdnum, ch)
KEYCMD *cmdnum;
register Char *ch;
{
KEYCMD cmd = 0;
int num;
while (cmd == 0 || cmd == F_XKEY) {
if ((num = GetNextChar(ch)) != 1) {
return num;
}
#ifdef KANJI
if (
#ifdef DSPMBYTE
_enable_mbdisp &&
#endif
!adrof(STRnokanji) && (*ch & META)) {
MetaNext = 0;
cmd = F_INSERT;
break;
}
else
#endif
if (MetaNext) {
MetaNext = 0;
*ch |= META;
}
if (*ch < NT_NUM_KEYS)
cmd = CurrentKeyMap[*ch];
else
cmd = CurrentKeyMap[(unsigned char) *ch];
if (cmd == F_XKEY) {
XmapVal val;
CStr cstr;
cstr.buf = ch;
cstr.len = Strlen(ch);
switch (GetXkey(&cstr, &val)) {
case XK_CMD:
cmd = val.cmd;
break;
case XK_STR:
PushMacro(val.str.buf);
break;
case XK_EXE:
RunCommand(val.str.buf);
break;
default:
abort();
break;
}
}
if (!AltKeyMap)
CurrentKeyMap = CcKeyMap;
}
*cmdnum = cmd;
return OKCMD;
}
int
GetNextChar(cp)
register Char *cp;
{
register int num_read;
int tried = 0;
unsigned char tcp;
for (;;) {
if (MacroLvl < 0) {
if (!Load_input_line())
break;
}
if (*KeyMacro[MacroLvl] == 0) {
MacroLvl--;
continue;
}
*cp = *KeyMacro[MacroLvl]++ & CHAR;
if (*KeyMacro[MacroLvl] == 0) {
MacroLvl--;
}
return (1);
}
if (Rawmode() < 0)
return 0;
#ifdef WINNT_NATIVE
__nt_want_vcode = 1;
#endif
while ((num_read = read(SHIN, (char *) &tcp, 1)) == -1) {
if (errno == EINTR)
continue;
if (!tried && fixio(SHIN, errno) != -1)
tried = 1;
else {
#ifdef convex
if (errno != EINTR)
stderror(ERR_SYSTEM, progname, strerror(errno));
#endif
#ifdef WINNT_NATIVE
__nt_want_vcode = 0;
#endif
*cp = '\0';
return -1;
}
}
#ifdef WINNT_NATIVE
if (__nt_want_vcode == 2)
*cp = __nt_vcode;
else
*cp = tcp;
__nt_want_vcode = 0;
#else
*cp = tcp;
#endif
return num_read;
}
static int
SpellLine(cmdonly)
int cmdonly;
{
int endflag, matchval;
Char *argptr, *OldCursor, *OldLastChar;
OldLastChar = LastChar;
OldCursor = Cursor;
argptr = InputBuf;
endflag = 1;
matchval = 0;
do {
while (ismetahash(*argptr) || iscmdmeta(*argptr))
argptr++;
for (Cursor = argptr;
*Cursor != '\0' && ((Cursor != argptr && Cursor[-1] == '\\') ||
(!ismetahash(*Cursor) && !iscmdmeta(*Cursor)));
Cursor++)
continue;
if (*Cursor == '\0') {
Cursor = LastChar;
if (LastChar[-1] == '\n')
Cursor--;
endflag = 0;
}
mismatch[0] = HIST;
mismatch[1] = HISTSUB;
if (!Strchr(mismatch, *argptr) &&
(!cmdonly || starting_a_command(argptr, InputBuf))) {
#ifdef WINNT_NATIVE
if((Cursor - InputBuf) != 2 || (char)InputBuf[1] != ':')
#endif
{
#ifdef HASH_SPELL_CHECK
Char save;
size_t len = Cursor - InputBuf;
save = InputBuf[len];
InputBuf[len] = '\0';
if (find_cmd(InputBuf, 0) != 0) {
InputBuf[len] = save;
argptr = Cursor;
continue;
}
InputBuf[len] = save;
#endif
switch (tenematch(InputBuf, Cursor - InputBuf, SPELL)) {
case 1:
matchval = 1;
break;
case -1:
if (!matchval)
matchval = -1;
break;
default:
break;
}
}
if (LastChar != OldLastChar) {
if (argptr < OldCursor)
OldCursor += (LastChar - OldLastChar);
OldLastChar = LastChar;
}
}
argptr = Cursor;
} while (endflag);
Cursor = OldCursor;
return matchval;
}
static int
CompleteLine()
{
int endflag, tmatch;
Char *argptr, *OldCursor, *OldLastChar;
OldLastChar = LastChar;
OldCursor = Cursor;
argptr = InputBuf;
endflag = 1;
do {
while (ismetahash(*argptr) || iscmdmeta(*argptr))
argptr++;
for (Cursor = argptr;
*Cursor != '\0' && ((Cursor != argptr && Cursor[-1] == '\\') ||
(!ismetahash(*Cursor) && !iscmdmeta(*Cursor)));
Cursor++)
continue;
if (*Cursor == '\0') {
Cursor = LastChar;
if (LastChar[-1] == '\n')
Cursor--;
endflag = 0;
}
if (!Strchr(mismatch, *argptr) && starting_a_command(argptr, InputBuf)) {
tmatch = tenematch(InputBuf, Cursor - InputBuf, RECOGNIZE);
if (tmatch <= 0) {
return 0;
} else if (tmatch > 1) {
return 2;
}
if (LastChar != OldLastChar) {
if (argptr < OldCursor)
OldCursor += (LastChar - OldLastChar);
OldLastChar = LastChar;
}
}
argptr = Cursor;
} while (endflag);
Cursor = OldCursor;
return 1;
}