ed.inputl.c revision 100616
1100616Smp/* $Header: /src/pub/tcsh/ed.inputl.c,v 3.51 2002/06/25 19:02:11 christos Exp $ */
259243Sobrien/*
359243Sobrien * ed.inputl.c: Input line handling.
459243Sobrien */
559243Sobrien/*-
659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California.
759243Sobrien * All rights reserved.
859243Sobrien *
959243Sobrien * Redistribution and use in source and binary forms, with or without
1059243Sobrien * modification, are permitted provided that the following conditions
1159243Sobrien * are met:
1259243Sobrien * 1. Redistributions of source code must retain the above copyright
1359243Sobrien *    notice, this list of conditions and the following disclaimer.
1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1559243Sobrien *    notice, this list of conditions and the following disclaimer in the
1659243Sobrien *    documentation and/or other materials provided with the distribution.
17100616Smp * 3. Neither the name of the University nor the names of its contributors
1859243Sobrien *    may be used to endorse or promote products derived from this software
1959243Sobrien *    without specific prior written permission.
2059243Sobrien *
2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2459243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3159243Sobrien * SUCH DAMAGE.
3259243Sobrien */
3359243Sobrien#include "sh.h"
3459243Sobrien
35100616SmpRCSID("$Id: ed.inputl.c,v 3.51 2002/06/25 19:02:11 christos Exp $")
3659243Sobrien
3759243Sobrien#include "ed.h"
3859243Sobrien#include "ed.defns.h"		/* for the function names */
3959243Sobrien#include "tw.h"			/* for twenex stuff */
4059243Sobrien
4159243Sobrien#define OKCMD (INBUFSIZE+INBUFSIZE)
4259243Sobrien
4359243Sobrien/* ed.inputl -- routines to get a single line from the input. */
4459243Sobrien
4559243Sobrienextern bool tellwhat;
4659243Sobrienextern bool MapsAreInited;
4759243Sobrienextern bool Tty_raw_mode;
4859243Sobrien
4959243Sobrien/* mismatched first character */
5059243Sobrienstatic Char mismatch[] =
5159243Sobrien    {'!', '^' , '\\', '-', '%', '\0', '"', '\'', '`', '\0' };
5259243Sobrien
5359243Sobrienstatic	int	Repair		__P((void));
5459243Sobrienstatic	int	GetNextCommand	__P((KEYCMD *, Char *));
5559243Sobrienstatic	int	SpellLine	__P((int));
5659243Sobrienstatic	int	CompleteLine	__P((void));
5759243Sobrienstatic	void	RunCommand	__P((Char *));
5859243Sobrienstatic  void 	doeval1		__P((Char **));
5959243Sobrien
6059243Sobrienstatic bool rotate = 0;
6159243Sobrien
6259243Sobrien
6359243Sobrienstatic int
6459243SobrienRepair()
6559243Sobrien{
6659243Sobrien    if (NeedsRedraw) {
6759243Sobrien	ClearLines();
6859243Sobrien	ClearDisp();
6959243Sobrien	NeedsRedraw = 0;
7059243Sobrien    }
7159243Sobrien    Refresh();
7259243Sobrien    Argument = 1;
7359243Sobrien    DoingArg = 0;
7459243Sobrien    curchoice = -1;
7559243Sobrien    return (int) (LastChar - InputBuf);
7659243Sobrien}
7759243Sobrien
7859243Sobrien/* CCRETVAL */
7959243Sobrienint
8059243SobrienInputl()
8159243Sobrien{
8259243Sobrien    CCRETVAL retval;
8359243Sobrien    KEYCMD  cmdnum = 0;
8459243Sobrien    extern KEYCMD NumFuns;
8559243Sobrien    unsigned char tch;		/* the place where read() goes */
8659243Sobrien    Char    ch;
8759243Sobrien    int     num;		/* how many chars we have read at NL */
8859243Sobrien    int	    expnum;
8959243Sobrien    struct varent *crct = inheredoc ? NULL : adrof(STRcorrect);
9059243Sobrien    struct varent *autol = adrof(STRautolist);
9159243Sobrien    struct varent *matchbeep = adrof(STRmatchbeep);
9259243Sobrien    struct varent *imode = adrof(STRinputmode);
9359243Sobrien    Char   *SaveChar, *CorrChar;
9459243Sobrien    Char    Origin[INBUFSIZE], Change[INBUFSIZE];
9559243Sobrien    int     matchval;		/* from tenematch() */
9659243Sobrien    COMMAND fn;
9759243Sobrien    int curlen = 0;
9859243Sobrien    int newlen;
9959243Sobrien    int idx;
10059243Sobrien
10159243Sobrien    if (!MapsAreInited)		/* double extra just in case */
10259243Sobrien	ed_InitMaps();
10359243Sobrien
10459243Sobrien    ClearDisp();		/* reset the display stuff */
10559243Sobrien    ResetInLine(0);		/* reset the input pointers */
10659243Sobrien    if (GettingInput)
10759243Sobrien	MacroLvl = -1;		/* editor was interrupted during input */
10859243Sobrien
109100616Smp    if (imode && imode->vec != NULL) {
11059243Sobrien	if (!Strcmp(*(imode->vec), STRinsert))
11159243Sobrien	    inputmode = MODE_INSERT;
11259243Sobrien	else if (!Strcmp(*(imode->vec), STRoverwrite))
11359243Sobrien	    inputmode = MODE_REPLACE;
11459243Sobrien    }
11559243Sobrien
11659243Sobrien#if defined(FIONREAD) && !defined(OREO)
11759243Sobrien    if (!Tty_raw_mode && MacroLvl < 0) {
11859243Sobrien# ifdef SUNOS4
11959243Sobrien	long chrs = 0;
12059243Sobrien# else /* !SUNOS4 */
12159243Sobrien	/*
12259243Sobrien	 * *Everyone* else has an int, but SunOS wants long!
12359243Sobrien	 * This breaks where int != long (alpha)
12459243Sobrien	 */
12559243Sobrien	int chrs = 0;
12659243Sobrien# endif /* SUNOS4 */
12759243Sobrien
12859243Sobrien	(void) ioctl(SHIN, FIONREAD, (ioctl_t) & chrs);
12959243Sobrien	if (chrs == 0) {
13059243Sobrien	    if (Rawmode() < 0)
13159243Sobrien		return 0;
13259243Sobrien	}
13359243Sobrien    }
13459243Sobrien#endif /* FIONREAD && !OREO */
13559243Sobrien
13659243Sobrien    GettingInput = 1;
13759243Sobrien    NeedsRedraw = 0;
13859243Sobrien
13959243Sobrien    if (tellwhat) {
14059243Sobrien	copyn(InputBuf, WhichBuf, INBUFSIZE);
14159243Sobrien	LastChar = InputBuf + (LastWhich - WhichBuf);
14259243Sobrien	Cursor = InputBuf + (CursWhich - WhichBuf);
14359243Sobrien	tellwhat = 0;
14459243Sobrien	Hist_num = HistWhich;
14559243Sobrien    }
14659243Sobrien    if (Expand) {
14759243Sobrien	(void) e_up_hist(0);
14859243Sobrien	Expand = 0;
14959243Sobrien    }
15059243Sobrien    Refresh();			/* print the prompt */
15159243Sobrien
15259243Sobrien    for (num = OKCMD; num == OKCMD;) {	/* while still editing this line */
15359243Sobrien#ifdef DEBUG_EDIT
15459243Sobrien	if (Cursor > LastChar)
15559243Sobrien	    xprintf("Cursor > LastChar\r\n");
15659243Sobrien	if (Cursor < InputBuf)
15759243Sobrien	    xprintf("Cursor < InputBuf\r\n");
15859243Sobrien	if (Cursor > InputLim)
15959243Sobrien	    xprintf("Cursor > InputLim\r\n");
16059243Sobrien	if (LastChar > InputLim)
16159243Sobrien	    xprintf("LastChar > InputLim\r\n");
16259243Sobrien	if (InputLim != &InputBuf[INBUFSIZE - 2])
16359243Sobrien	    xprintf("InputLim != &InputBuf[INBUFSIZE-2]\r\n");
16459243Sobrien	if ((!DoingArg) && (Argument != 1))
16559243Sobrien	    xprintf("(!DoingArg) && (Argument != 1)\r\n");
16659243Sobrien	if (CcKeyMap[0] == 0)
16759243Sobrien	    xprintf("CcKeyMap[0] == 0 (maybe not inited)\r\n");
16859243Sobrien#endif
16959243Sobrien
17059243Sobrien	/* if EOF or error */
17159243Sobrien	if ((num = GetNextCommand(&cmdnum, &ch)) != OKCMD) {
17259243Sobrien	    break;
17359243Sobrien	}
17459243Sobrien
17559243Sobrien	if (cmdnum >= NumFuns) {/* BUG CHECK command */
17659243Sobrien#ifdef DEBUG_EDIT
17759243Sobrien	    xprintf(CGETS(6, 1, "ERROR: illegal command from key 0%o\r\n"), ch);
17859243Sobrien#endif
17959243Sobrien	    continue;		/* try again */
18059243Sobrien	}
18159243Sobrien
18259243Sobrien	/* now do the real command */
18359243Sobrien	retval = (*CcFuncTbl[cmdnum]) (ch);
18459243Sobrien
18559243Sobrien	/* save the last command here */
18659243Sobrien	LastCmd = cmdnum;
18759243Sobrien
18859243Sobrien	/* make sure fn is initialized */
18959243Sobrien	fn = (retval == CC_COMPLETE_ALL) ? LIST_ALL : LIST;
19059243Sobrien
19159243Sobrien	/* use any return value */
19259243Sobrien	switch (retval) {
19359243Sobrien
19459243Sobrien	case CC_REFRESH:
19559243Sobrien	    Refresh();
19659243Sobrien	    /*FALLTHROUGH*/
19759243Sobrien	case CC_NORM:		/* normal char */
19859243Sobrien	    Argument = 1;
19959243Sobrien	    DoingArg = 0;
20059243Sobrien	    /*FALLTHROUGH*/
20159243Sobrien	case CC_ARGHACK:	/* Suggested by Rich Salz */
20259243Sobrien	    /* <rsalz@pineapple.bbn.com> */
20359243Sobrien	    curchoice = -1;
20459243Sobrien	    curlen = (int) (LastChar - InputBuf);
20559243Sobrien	    break;		/* keep going... */
20659243Sobrien
20759243Sobrien	case CC_EOF:		/* end of file typed */
20859243Sobrien	    curchoice = -1;
20959243Sobrien	    curlen = (int) (LastChar - InputBuf);
21059243Sobrien	    num = 0;
21159243Sobrien	    break;
21259243Sobrien
21359243Sobrien	case CC_WHICH:		/* tell what this command does */
21459243Sobrien	    tellwhat = 1;
21559243Sobrien	    copyn(WhichBuf, InputBuf, INBUFSIZE);
21659243Sobrien	    LastWhich = WhichBuf + (LastChar - InputBuf);
21759243Sobrien	    CursWhich = WhichBuf + (Cursor - InputBuf);
21859243Sobrien	    *LastChar++ = '\n';	/* for the benifit of CSH */
21959243Sobrien	    HistWhich = Hist_num;
22059243Sobrien	    Hist_num = 0;	/* for the history commands */
22159243Sobrien	    num = (int) (LastChar - InputBuf);	/* number characters read */
22259243Sobrien	    break;
22359243Sobrien
22459243Sobrien	case CC_NEWLINE:	/* normal end of line */
22559243Sobrien	    curlen = 0;
22659243Sobrien	    curchoice = -1;
22759243Sobrien	    matchval = 1;
228100616Smp	    if (crct && crct->vec != NULL && (!Strcmp(*(crct->vec), STRcmd) ||
22959243Sobrien			 !Strcmp(*(crct->vec), STRall))) {
23059243Sobrien                PastBottom();
23159243Sobrien		copyn(Origin, InputBuf, INBUFSIZE);
23259243Sobrien		SaveChar = LastChar;
23359243Sobrien		if (SpellLine(!Strcmp(*(crct->vec), STRcmd)) == 1) {
23459243Sobrien                    PastBottom();
23559243Sobrien		    copyn(Change, InputBuf, INBUFSIZE);
23659243Sobrien		    *Strchr(Change, '\n') = '\0';
23759243Sobrien		    CorrChar = LastChar;	/* Save the corrected end */
23859243Sobrien		    LastChar = InputBuf;	/* Null the current line */
23959243Sobrien		    SoundBeep();
24059243Sobrien		    printprompt(2, short2str(Change));
24159243Sobrien		    Refresh();
24259243Sobrien		    if (read(SHIN, (char *) &tch, 1) < 0)
24359243Sobrien#ifdef convex
24459243Sobrien		        /*
24559243Sobrien			 * need to print error message in case file
24659243Sobrien			 * is migrated
24759243Sobrien			 */
24859243Sobrien                        if (errno && errno != EINTR)
24959243Sobrien                            stderror(ERR_SYSTEM, progname, strerror(errno));
25059243Sobrien#else
25159243Sobrien			break;
25259243Sobrien#endif
25359243Sobrien		    ch = tch;
25459243Sobrien		    if (ch == 'y' || ch == ' ') {
25559243Sobrien			LastChar = CorrChar;	/* Restore the corrected end */
25659243Sobrien			xprintf(CGETS(6, 2, "yes\n"));
25759243Sobrien		    }
25859243Sobrien		    else {
25959243Sobrien			copyn(InputBuf, Origin, INBUFSIZE);
26059243Sobrien			LastChar = SaveChar;
26159243Sobrien			if (ch == 'e') {
26259243Sobrien			    xprintf(CGETS(6, 3, "edit\n"));
26359243Sobrien			    *LastChar-- = '\0';
26459243Sobrien			    Cursor = LastChar;
26559243Sobrien			    printprompt(3, NULL);
26659243Sobrien			    ClearLines();
26759243Sobrien			    ClearDisp();
26859243Sobrien			    Refresh();
26959243Sobrien			    break;
27059243Sobrien			}
27159243Sobrien			else if (ch == 'a') {
27259243Sobrien			    xprintf(CGETS(6, 4, "abort\n"));
27359243Sobrien		            LastChar = InputBuf;   /* Null the current line */
27459243Sobrien			    Cursor = LastChar;
27559243Sobrien			    printprompt(0, NULL);
27659243Sobrien			    Refresh();
27759243Sobrien			    break;
27859243Sobrien			}
27959243Sobrien			xprintf(CGETS(6, 5, "no\n"));
28059243Sobrien		    }
28159243Sobrien		    flush();
28259243Sobrien		}
283100616Smp	    } else if (crct && crct->vec != NULL &&
284100616Smp		!Strcmp(*(crct->vec), STRcomplete)) {
28559243Sobrien                if (LastChar > InputBuf && LastChar[-1] == '\n') {
28659243Sobrien                    LastChar[-1] = '\0';
28759243Sobrien                    LastChar--;
28859243Sobrien                    Cursor = LastChar;
28959243Sobrien                }
29059243Sobrien                match_unique_match = 1;  /* match unique matches */
29159243Sobrien		matchval = CompleteLine();
29259243Sobrien                match_unique_match = 0;
29359243Sobrien        	curlen = (int) (LastChar - InputBuf);
29459243Sobrien		if (matchval != 1) {
29559243Sobrien                    PastBottom();
29659243Sobrien		}
29759243Sobrien		if (matchval == 0) {
29859243Sobrien		    xprintf(CGETS(6, 6, "No matching command\n"));
29959243Sobrien		} else if (matchval == 2) {
30059243Sobrien		    xprintf(CGETS(6, 7, "Ambiguous command\n"));
30159243Sobrien		}
30259243Sobrien	        if (NeedsRedraw) {
30359243Sobrien		    ClearLines();
30459243Sobrien		    ClearDisp();
30559243Sobrien		    NeedsRedraw = 0;
30659243Sobrien	        }
30759243Sobrien	        Refresh();
30859243Sobrien	        Argument = 1;
30959243Sobrien	        DoingArg = 0;
31059243Sobrien		if (matchval == 1) {
31159243Sobrien                    PastBottom();
31259243Sobrien                    *LastChar++ = '\n';
31359243Sobrien                    *LastChar = '\0';
31459243Sobrien		}
31559243Sobrien        	curlen = (int) (LastChar - InputBuf);
31659243Sobrien            }
31759243Sobrien	    else
31859243Sobrien		PastBottom();
31959243Sobrien
32059243Sobrien	    if (matchval == 1) {
32159243Sobrien	        tellwhat = 0;	/* just in case */
32259243Sobrien	        Hist_num = 0;	/* for the history commands */
32359243Sobrien		/* return the number of chars read */
32459243Sobrien	        num = (int) (LastChar - InputBuf);
32559243Sobrien	        /*
32659243Sobrien	         * For continuation lines, we set the prompt to prompt 2
32759243Sobrien	         */
32859243Sobrien	        printprompt(1, NULL);
32959243Sobrien	    }
33059243Sobrien	    break;
33159243Sobrien
33259243Sobrien	case CC_CORRECT:
33359243Sobrien	    if (tenematch(InputBuf, Cursor - InputBuf, SPELL) < 0)
33459243Sobrien		SoundBeep();		/* Beep = No match/ambiguous */
33559243Sobrien	    curlen = Repair();
33659243Sobrien	    break;
33759243Sobrien
33859243Sobrien	case CC_CORRECT_L:
33959243Sobrien	    if (SpellLine(FALSE) < 0)
34059243Sobrien		SoundBeep();		/* Beep = No match/ambiguous */
34159243Sobrien	    curlen = Repair();
34259243Sobrien	    break;
34359243Sobrien
34459243Sobrien
34559243Sobrien	case CC_COMPLETE:
34659243Sobrien	case CC_COMPLETE_ALL:
34759243Sobrien	case CC_COMPLETE_FWD:
34859243Sobrien	case CC_COMPLETE_BACK:
34959243Sobrien	    switch (retval) {
35059243Sobrien	    case CC_COMPLETE:
35159243Sobrien		fn = RECOGNIZE;
35259243Sobrien		curlen = (int) (LastChar - InputBuf);
35359243Sobrien		curchoice = -1;
35459243Sobrien		rotate = 0;
35559243Sobrien		break;
35659243Sobrien	    case CC_COMPLETE_ALL:
35759243Sobrien		fn = RECOGNIZE_ALL;
35859243Sobrien		curlen = (int) (LastChar - InputBuf);
35959243Sobrien		curchoice = -1;
36059243Sobrien		rotate = 0;
36159243Sobrien		break;
36259243Sobrien	    case CC_COMPLETE_FWD:
36359243Sobrien		fn = RECOGNIZE_SCROLL;
36459243Sobrien		curchoice++;
36559243Sobrien		rotate = 1;
36659243Sobrien		break;
36759243Sobrien	    case CC_COMPLETE_BACK:
36859243Sobrien		fn = RECOGNIZE_SCROLL;
36959243Sobrien		curchoice--;
37059243Sobrien		rotate = 1;
37159243Sobrien		break;
37259243Sobrien	    default:
37359243Sobrien		abort();
37459243Sobrien	    }
37559243Sobrien	    if (InputBuf[curlen] && rotate) {
37659243Sobrien		newlen = (int) (LastChar - InputBuf);
37759243Sobrien		for (idx = (int) (Cursor - InputBuf);
37859243Sobrien		     idx <= newlen; idx++)
37959243Sobrien			InputBuf[idx - newlen + curlen] =
38059243Sobrien			InputBuf[idx];
38159243Sobrien		LastChar = InputBuf + curlen;
38259243Sobrien		Cursor = Cursor - newlen + curlen;
38359243Sobrien	    }
38459243Sobrien	    curlen = (int) (LastChar - InputBuf);
38559243Sobrien
38659243Sobrien
38759243Sobrien	    if (adrof(STRautoexpand))
38859243Sobrien		(void) e_expand_history(0);
38959243Sobrien	    /*
39059243Sobrien	     * Modified by Martin Boyer (gamin@ireq-robot.hydro.qc.ca):
39159243Sobrien	     * A separate variable now controls beeping after
39259243Sobrien	     * completion, independently of autolisting.
39359243Sobrien	     */
39459243Sobrien	    expnum = (int) (Cursor - InputBuf);
39559243Sobrien	    switch (matchval = tenematch(InputBuf, Cursor-InputBuf, fn)){
39659243Sobrien	    case 1:
397100616Smp		if (non_unique_match && matchbeep && matchbeep->vec != NULL &&
39859243Sobrien		    (Strcmp(*(matchbeep->vec), STRnotunique) == 0))
39959243Sobrien		    SoundBeep();
40059243Sobrien		break;
40159243Sobrien	    case 0:
402100616Smp		if (matchbeep && matchbeep->vec != NULL) {
40359243Sobrien		    if (Strcmp(*(matchbeep->vec), STRnomatch) == 0 ||
40459243Sobrien			Strcmp(*(matchbeep->vec), STRambiguous) == 0 ||
40559243Sobrien			Strcmp(*(matchbeep->vec), STRnotunique) == 0)
40659243Sobrien			SoundBeep();
40759243Sobrien		}
40859243Sobrien		else
40959243Sobrien		    SoundBeep();
41059243Sobrien		break;
41159243Sobrien	    default:
41259243Sobrien		if (matchval < 0) {	/* Error from tenematch */
41359243Sobrien		    curchoice = -1;
41459243Sobrien		    SoundBeep();
41559243Sobrien		    break;
41659243Sobrien		}
417100616Smp		if (matchbeep && matchbeep->vec != NULL) {
41859243Sobrien		    if ((Strcmp(*(matchbeep->vec), STRambiguous) == 0 ||
41959243Sobrien			 Strcmp(*(matchbeep->vec), STRnotunique) == 0))
42059243Sobrien			SoundBeep();
42159243Sobrien		}
42259243Sobrien		else
42359243Sobrien		    SoundBeep();
42459243Sobrien		/*
42559243Sobrien		 * Addition by David C Lawrence <tale@pawl.rpi.edu>: If an
42659243Sobrien		 * attempted completion is ambiguous, list the choices.
42759243Sobrien		 * (PWP: this is the best feature addition to tcsh I have
42859243Sobrien		 * seen in many months.)
42959243Sobrien		 */
430100616Smp		if (autol && autol->vec != NULL &&
431100616Smp		    (Strcmp(*(autol->vec), STRambiguous) != 0 ||
43259243Sobrien				     expnum == Cursor - InputBuf)) {
43359243Sobrien		    PastBottom();
43459243Sobrien		    fn = (retval == CC_COMPLETE_ALL) ? LIST_ALL : LIST;
43559243Sobrien		    (void) tenematch(InputBuf, Cursor-InputBuf, fn);
43659243Sobrien		}
43759243Sobrien		break;
43859243Sobrien	    }
43959243Sobrien	    if (NeedsRedraw) {
44059243Sobrien		PastBottom();
44159243Sobrien		ClearLines();
44259243Sobrien		ClearDisp();
44359243Sobrien		NeedsRedraw = 0;
44459243Sobrien	    }
44559243Sobrien	    Refresh();
44659243Sobrien	    Argument = 1;
44759243Sobrien	    DoingArg = 0;
44859243Sobrien	    break;
44959243Sobrien
45059243Sobrien	case CC_LIST_CHOICES:
45159243Sobrien	case CC_LIST_ALL:
45259243Sobrien	    if (InputBuf[curlen] && rotate) {
45359243Sobrien		newlen = (int) (LastChar - InputBuf);
45459243Sobrien		for (idx = (int) (Cursor - InputBuf);
45559243Sobrien		     idx <= newlen; idx++)
45659243Sobrien			InputBuf[idx - newlen + curlen] =
45759243Sobrien			InputBuf[idx];
45859243Sobrien		LastChar = InputBuf + curlen;
45959243Sobrien		Cursor = Cursor - newlen + curlen;
46059243Sobrien	    }
46159243Sobrien	    curlen = (int) (LastChar - InputBuf);
46259243Sobrien	    if (curchoice >= 0)
46359243Sobrien		curchoice--;
46459243Sobrien
46559243Sobrien	    fn = (retval == CC_LIST_ALL) ? LIST_ALL : LIST;
46659243Sobrien	    /* should catch ^C here... */
46759243Sobrien	    if (tenematch(InputBuf, Cursor - InputBuf, fn) < 0)
46859243Sobrien		SoundBeep();
46959243Sobrien	    Refresh();
47059243Sobrien	    Argument = 1;
47159243Sobrien	    DoingArg = 0;
47259243Sobrien	    break;
47359243Sobrien
47459243Sobrien
47559243Sobrien	case CC_LIST_GLOB:
47659243Sobrien	    if (tenematch(InputBuf, Cursor - InputBuf, GLOB) < 0)
47759243Sobrien		SoundBeep();
47859243Sobrien	    curlen = Repair();
47959243Sobrien	    break;
48059243Sobrien
48159243Sobrien	case CC_EXPAND_GLOB:
48259243Sobrien	    if (tenematch(InputBuf, Cursor - InputBuf, GLOB_EXPAND) <= 0)
48359243Sobrien		SoundBeep();		/* Beep = No match */
48459243Sobrien	    curlen = Repair();
48559243Sobrien	    break;
48659243Sobrien
48759243Sobrien	case CC_NORMALIZE_PATH:
48859243Sobrien	    if (tenematch(InputBuf, Cursor - InputBuf, PATH_NORMALIZE) <= 0)
48959243Sobrien		SoundBeep();		/* Beep = No match */
49059243Sobrien	    curlen = Repair();
49159243Sobrien	    break;
49259243Sobrien
49359243Sobrien	case CC_EXPAND_VARS:
49459243Sobrien	    if (tenematch(InputBuf, Cursor - InputBuf, VARS_EXPAND) <= 0)
49559243Sobrien		SoundBeep();		/* Beep = No match */
49659243Sobrien	    curlen = Repair();
49759243Sobrien	    break;
49859243Sobrien
49959243Sobrien	case CC_NORMALIZE_COMMAND:
50059243Sobrien	    if (tenematch(InputBuf, Cursor - InputBuf, COMMAND_NORMALIZE) <= 0)
50159243Sobrien		SoundBeep();		/* Beep = No match */
50259243Sobrien	    curlen = Repair();
50359243Sobrien	    break;
50459243Sobrien
50559243Sobrien	case CC_HELPME:
50659243Sobrien	    xputchar('\n');
50759243Sobrien	    /* should catch ^C here... */
50859243Sobrien	    (void) tenematch(InputBuf, LastChar - InputBuf, PRINT_HELP);
50959243Sobrien	    Refresh();
51059243Sobrien	    Argument = 1;
51159243Sobrien	    DoingArg = 0;
51259243Sobrien	    curchoice = -1;
51359243Sobrien	    curlen = (int) (LastChar - InputBuf);
51459243Sobrien	    break;
51559243Sobrien
51659243Sobrien	case CC_FATAL:		/* fatal error, reset to known state */
51759243Sobrien#ifdef DEBUG_EDIT
51859243Sobrien	    xprintf(CGETS(7, 8, "*** editor fatal ERROR ***\r\n\n"));
51959243Sobrien#endif				/* DEBUG_EDIT */
52059243Sobrien	    /* put (real) cursor in a known place */
52159243Sobrien	    ClearDisp();	/* reset the display stuff */
52259243Sobrien	    ResetInLine(1);	/* reset the input pointers */
52359243Sobrien	    Refresh();		/* print the prompt again */
52459243Sobrien	    Argument = 1;
52559243Sobrien	    DoingArg = 0;
52659243Sobrien	    curchoice = -1;
52759243Sobrien	    curlen = (int) (LastChar - InputBuf);
52859243Sobrien	    break;
52959243Sobrien
53059243Sobrien	case CC_ERROR:
53159243Sobrien	default:		/* functions we don't know about */
53259243Sobrien	    DoingArg = 0;
53359243Sobrien	    Argument = 1;
53459243Sobrien	    SoundBeep();
53559243Sobrien	    flush();
53659243Sobrien	    curchoice = -1;
53759243Sobrien	    curlen = (int) (LastChar - InputBuf);
53859243Sobrien	    break;
53959243Sobrien	}
54059243Sobrien    }
54159243Sobrien    (void) Cookedmode();	/* make sure the tty is set up correctly */
54259243Sobrien    GettingInput = 0;
54359243Sobrien    flush();			/* flush any buffered output */
54459243Sobrien    return num;
54559243Sobrien}
54659243Sobrien
54759243Sobrienvoid
54859243SobrienPushMacro(str)
54959243Sobrien    Char   *str;
55059243Sobrien{
55159243Sobrien    if (str != NULL && MacroLvl + 1 < MAXMACROLEVELS) {
55259243Sobrien	MacroLvl++;
55359243Sobrien	KeyMacro[MacroLvl] = str;
55459243Sobrien    }
55559243Sobrien    else {
55659243Sobrien	SoundBeep();
55759243Sobrien	flush();
55859243Sobrien    }
55959243Sobrien}
56059243Sobrien
56159243Sobrien/*
56259243Sobrien * Like eval, only using the current file descriptors
56359243Sobrien */
56459243Sobrienstatic Char **gv = NULL, **gav = NULL;
56559243Sobrien
56659243Sobrienstatic void
56759243Sobriendoeval1(v)
56859243Sobrien    Char **v;
56959243Sobrien{
57059243Sobrien    Char  **oevalvec;
57159243Sobrien    Char   *oevalp;
57259243Sobrien    int     my_reenter;
57359243Sobrien    Char  **savegv;
57459243Sobrien    jmp_buf_t osetexit;
57559243Sobrien
57659243Sobrien    oevalvec = evalvec;
57759243Sobrien    oevalp = evalp;
57859243Sobrien    savegv = gv;
57959243Sobrien    gav = v;
58059243Sobrien
58159243Sobrien
58259243Sobrien    gflag = 0, tglob(gav);
58359243Sobrien    if (gflag) {
58459243Sobrien	gv = gav = globall(gav);
58559243Sobrien	gargv = 0;
58659243Sobrien	if (gav == 0)
58759243Sobrien	    stderror(ERR_NOMATCH);
58859243Sobrien	gav = copyblk(gav);
58959243Sobrien    }
59059243Sobrien    else {
59159243Sobrien	gv = NULL;
59259243Sobrien	gav = copyblk(gav);
59359243Sobrien	trim(gav);
59459243Sobrien    }
59559243Sobrien
59659243Sobrien    getexit(osetexit);
59759243Sobrien
59859243Sobrien    /* PWP: setjmp/longjmp bugfix for optimizing compilers */
59959243Sobrien#ifdef cray
60059243Sobrien    my_reenter = 1;             /* assume non-zero return val */
60159243Sobrien    if (setexit() == 0) {
60259243Sobrien        my_reenter = 0;         /* Oh well, we were wrong */
60359243Sobrien#else /* !cray */
60459243Sobrien    if ((my_reenter = setexit()) == 0) {
60559243Sobrien#endif /* cray */
60659243Sobrien	evalvec = gav;
60759243Sobrien	evalp = 0;
60859243Sobrien	process(0);
60959243Sobrien    }
61059243Sobrien
61159243Sobrien    evalvec = oevalvec;
61259243Sobrien    evalp = oevalp;
61359243Sobrien    doneinp = 0;
61459243Sobrien
61559243Sobrien    if (gv)
61659243Sobrien	blkfree(gv);
61759243Sobrien
61859243Sobrien    gv = savegv;
61959243Sobrien    resexit(osetexit);
62059243Sobrien    if (my_reenter)
62159243Sobrien	stderror(ERR_SILENT);
62259243Sobrien}
62359243Sobrien
62459243Sobrienstatic void
62559243SobrienRunCommand(str)
62659243Sobrien    Char *str;
62759243Sobrien{
62859243Sobrien    Char *cmd[2];
62959243Sobrien
63059243Sobrien    xputchar('\n');	/* Start on a clean line */
63159243Sobrien
63259243Sobrien    cmd[0] = str;
63359243Sobrien    cmd[1] = NULL;
63459243Sobrien
63559243Sobrien    (void) Cookedmode();
63659243Sobrien    GettingInput = 0;
63759243Sobrien
63859243Sobrien    doeval1(cmd);
63959243Sobrien
64059243Sobrien    (void) Rawmode();
64159243Sobrien    GettingInput = 1;
64259243Sobrien
64359243Sobrien    ClearLines();
64459243Sobrien    ClearDisp();
64559243Sobrien    NeedsRedraw = 0;
64659243Sobrien    Refresh();
64759243Sobrien}
64859243Sobrien
64959243Sobrienstatic int
65059243SobrienGetNextCommand(cmdnum, ch)
65159243Sobrien    KEYCMD *cmdnum;
65259243Sobrien    register Char *ch;
65359243Sobrien{
65459243Sobrien    KEYCMD  cmd = 0;
65559243Sobrien    int     num;
65659243Sobrien
65759243Sobrien    while (cmd == 0 || cmd == F_XKEY) {
65859243Sobrien	if ((num = GetNextChar(ch)) != 1) {	/* if EOF or error */
65959243Sobrien	    return num;
66059243Sobrien	}
66159243Sobrien#ifdef	KANJI
66261519Sobrien	if (
66361519Sobrien#ifdef DSPMBYTE
66461519Sobrien	     _enable_mbdisp &&
66561519Sobrien#endif
66661519Sobrien	     !adrof(STRnokanji) && (*ch & META)) {
66759243Sobrien	    MetaNext = 0;
66859243Sobrien	    cmd = F_INSERT;
66959243Sobrien	    break;
67059243Sobrien	}
67159243Sobrien	else
67259243Sobrien#endif /* KANJI */
67359243Sobrien	if (MetaNext) {
67459243Sobrien	    MetaNext = 0;
67559243Sobrien	    *ch |= META;
67659243Sobrien	}
67759243Sobrien	/* XXX: This needs to be fixed so that we don't just truncate
67859243Sobrien	 * the character, we unquote it.
67959243Sobrien	 */
68059243Sobrien	if (*ch < NT_NUM_KEYS)
68159243Sobrien	    cmd = CurrentKeyMap[*ch];
68259243Sobrien	else
68359243Sobrien	    cmd = CurrentKeyMap[(unsigned char) *ch];
68459243Sobrien	if (cmd == F_XKEY) {
68559243Sobrien	    XmapVal val;
68659243Sobrien	    CStr cstr;
68759243Sobrien	    cstr.buf = ch;
68859243Sobrien	    cstr.len = Strlen(ch);
68959243Sobrien	    switch (GetXkey(&cstr, &val)) {
69059243Sobrien	    case XK_CMD:
69159243Sobrien		cmd = val.cmd;
69259243Sobrien		break;
69359243Sobrien	    case XK_STR:
69459243Sobrien		PushMacro(val.str.buf);
69559243Sobrien		break;
69659243Sobrien	    case XK_EXE:
69759243Sobrien		RunCommand(val.str.buf);
69859243Sobrien		break;
69959243Sobrien	    default:
70059243Sobrien		abort();
70159243Sobrien		break;
70259243Sobrien	    }
70359243Sobrien	}
70459243Sobrien	if (!AltKeyMap)
70559243Sobrien	    CurrentKeyMap = CcKeyMap;
70659243Sobrien    }
70759243Sobrien    *cmdnum = cmd;
70859243Sobrien    return OKCMD;
70959243Sobrien}
71059243Sobrien
71159243Sobrienint
71259243SobrienGetNextChar(cp)
71359243Sobrien    register Char *cp;
71459243Sobrien{
71559243Sobrien    register int num_read;
71659243Sobrien    int     tried = 0;
71759243Sobrien    unsigned char tcp;
71859243Sobrien
71959243Sobrien    for (;;) {
72059243Sobrien	if (MacroLvl < 0) {
72159243Sobrien	    if (!Load_input_line())
72259243Sobrien		break;
72359243Sobrien	}
72459243Sobrien	if (*KeyMacro[MacroLvl] == 0) {
72559243Sobrien	    MacroLvl--;
72659243Sobrien	    continue;
72759243Sobrien	}
72859243Sobrien	*cp = *KeyMacro[MacroLvl]++ & CHAR;
72959243Sobrien	if (*KeyMacro[MacroLvl] == 0) {	/* Needed for QuoteMode On */
73059243Sobrien	    MacroLvl--;
73159243Sobrien	}
73259243Sobrien	return (1);
73359243Sobrien    }
73459243Sobrien
73559243Sobrien    if (Rawmode() < 0)		/* make sure the tty is set up correctly */
73659243Sobrien	return 0;		/* oops: SHIN was closed */
73759243Sobrien
73869408Sache#ifdef WINNT_NATIVE
73959243Sobrien    __nt_want_vcode = 1;
74069408Sache#endif /* WINNT_NATIVE */
74159243Sobrien    while ((num_read = read(SHIN, (char *) &tcp, 1)) == -1) {
74259243Sobrien	if (errno == EINTR)
74359243Sobrien	    continue;
74459243Sobrien	if (!tried && fixio(SHIN, errno) != -1)
74559243Sobrien	    tried = 1;
74659243Sobrien	else {
74759243Sobrien#ifdef convex
74859243Sobrien            /* need to print error message in case the file is migrated */
74959243Sobrien            if (errno != EINTR)
75059243Sobrien                stderror(ERR_SYSTEM, progname, strerror(errno));
75159243Sobrien#endif  /* convex */
75269408Sache#ifdef WINNT_NATIVE
75359243Sobrien	    __nt_want_vcode = 0;
75469408Sache#endif /* WINNT_NATIVE */
75559243Sobrien	    *cp = '\0';
75659243Sobrien	    return -1;
75759243Sobrien	}
75859243Sobrien    }
75969408Sache#ifdef WINNT_NATIVE
76059243Sobrien    if (__nt_want_vcode == 2)
76159243Sobrien	*cp = __nt_vcode;
76259243Sobrien    else
76359243Sobrien	*cp = tcp;
76459243Sobrien    __nt_want_vcode = 0;
76559243Sobrien#else
76659243Sobrien    *cp = tcp;
76769408Sache#endif /* WINNT_NATIVE */
76859243Sobrien    return num_read;
76959243Sobrien}
77059243Sobrien
77159243Sobrien/*
77259243Sobrien * SpellLine - do spelling correction on the entire command line
77359243Sobrien * (which may have trailing newline).
77459243Sobrien * If cmdonly is set, only check spelling of command words.
77559243Sobrien * Return value:
77659243Sobrien * -1: Something was incorrectible, and nothing was corrected
77759243Sobrien *  0: Everything was correct
77859243Sobrien *  1: Something was corrected
77959243Sobrien */
78059243Sobrienstatic int
78159243SobrienSpellLine(cmdonly)
78259243Sobrien    int     cmdonly;
78359243Sobrien{
78459243Sobrien    int     endflag, matchval;
78559243Sobrien    Char   *argptr, *OldCursor, *OldLastChar;
78659243Sobrien
78759243Sobrien    OldLastChar = LastChar;
78859243Sobrien    OldCursor = Cursor;
78959243Sobrien    argptr = InputBuf;
79059243Sobrien    endflag = 1;
79159243Sobrien    matchval = 0;
79259243Sobrien    do {
79359243Sobrien	while (ismetahash(*argptr) || iscmdmeta(*argptr))
79459243Sobrien	    argptr++;
79559243Sobrien	for (Cursor = argptr;
79659243Sobrien	     *Cursor != '\0' && ((Cursor != argptr && Cursor[-1] == '\\') ||
79759243Sobrien				 (!ismetahash(*Cursor) && !iscmdmeta(*Cursor)));
79859243Sobrien	     Cursor++)
79959243Sobrien	     continue;
80059243Sobrien	if (*Cursor == '\0') {
80159243Sobrien	    Cursor = LastChar;
80259243Sobrien	    if (LastChar[-1] == '\n')
80359243Sobrien		Cursor--;
80459243Sobrien	    endflag = 0;
80559243Sobrien	}
80659243Sobrien	/* Obey current history character settings */
80759243Sobrien	mismatch[0] = HIST;
80859243Sobrien	mismatch[1] = HISTSUB;
80959243Sobrien	if (!Strchr(mismatch, *argptr) &&
81059243Sobrien	    (!cmdonly || starting_a_command(argptr, InputBuf))) {
81169408Sache#ifdef WINNT_NATIVE
81259243Sobrien	    /*
81359243Sobrien	     * This hack avoids correcting drive letter changes
81459243Sobrien	     */
81559243Sobrien	    if((Cursor - InputBuf) != 2 || (char)InputBuf[1] != ':')
81669408Sache#endif /* WINNT_NATIVE */
81759243Sobrien	    {
81859243Sobrien#ifdef HASH_SPELL_CHECK
81959243Sobrien		Char save;
82059243Sobrien		size_t len = Cursor - InputBuf;
82159243Sobrien
82259243Sobrien		save = InputBuf[len];
82359243Sobrien		InputBuf[len] = '\0';
82459243Sobrien		if (find_cmd(InputBuf, 0) != 0) {
82559243Sobrien		    InputBuf[len] = save;
82659243Sobrien		    argptr = Cursor;
82759243Sobrien		    continue;
82859243Sobrien		}
82959243Sobrien		InputBuf[len] = save;
83059243Sobrien#endif /* HASH_SPELL_CHECK */
83159243Sobrien		switch (tenematch(InputBuf, Cursor - InputBuf, SPELL)) {
83259243Sobrien		case 1:		/* corrected */
83359243Sobrien		    matchval = 1;
83459243Sobrien		    break;
83559243Sobrien		case -1:		/* couldn't be corrected */
83659243Sobrien		    if (!matchval)
83759243Sobrien			matchval = -1;
83859243Sobrien		    break;
83959243Sobrien		default:		/* was correct */
84059243Sobrien		    break;
84159243Sobrien		}
84259243Sobrien	    }
84359243Sobrien	    if (LastChar != OldLastChar) {
84459243Sobrien		if (argptr < OldCursor)
84559243Sobrien		    OldCursor += (LastChar - OldLastChar);
84659243Sobrien		OldLastChar = LastChar;
84759243Sobrien	    }
84859243Sobrien	}
84959243Sobrien	argptr = Cursor;
85059243Sobrien    } while (endflag);
85159243Sobrien    Cursor = OldCursor;
85259243Sobrien    return matchval;
85359243Sobrien}
85459243Sobrien
85559243Sobrien/*
85659243Sobrien * CompleteLine - do command completion on the entire command line
85759243Sobrien * (which may have trailing newline).
85859243Sobrien * Return value:
85959243Sobrien *  0: No command matched or failure
86059243Sobrien *  1: One command matched
86159243Sobrien *  2: Several commands matched
86259243Sobrien */
86359243Sobrienstatic int
86459243SobrienCompleteLine()
86559243Sobrien{
86659243Sobrien    int     endflag, tmatch;
86759243Sobrien    Char   *argptr, *OldCursor, *OldLastChar;
86859243Sobrien
86959243Sobrien    OldLastChar = LastChar;
87059243Sobrien    OldCursor = Cursor;
87159243Sobrien    argptr = InputBuf;
87259243Sobrien    endflag = 1;
87359243Sobrien    do {
87459243Sobrien	while (ismetahash(*argptr) || iscmdmeta(*argptr))
87559243Sobrien	    argptr++;
87659243Sobrien	for (Cursor = argptr;
87759243Sobrien	     *Cursor != '\0' && ((Cursor != argptr && Cursor[-1] == '\\') ||
87859243Sobrien				 (!ismetahash(*Cursor) && !iscmdmeta(*Cursor)));
87959243Sobrien	     Cursor++)
88059243Sobrien	     continue;
88159243Sobrien	if (*Cursor == '\0') {
88259243Sobrien	    Cursor = LastChar;
88359243Sobrien	    if (LastChar[-1] == '\n')
88459243Sobrien		Cursor--;
88559243Sobrien	    endflag = 0;
88659243Sobrien	}
88759243Sobrien	if (!Strchr(mismatch, *argptr) && starting_a_command(argptr, InputBuf)) {
88859243Sobrien	    tmatch = tenematch(InputBuf, Cursor - InputBuf, RECOGNIZE);
88959243Sobrien	    if (tmatch <= 0) {
89059243Sobrien                return 0;
89159243Sobrien            } else if (tmatch > 1) {
89259243Sobrien                return 2;
89359243Sobrien	    }
89459243Sobrien	    if (LastChar != OldLastChar) {
89559243Sobrien		if (argptr < OldCursor)
89659243Sobrien		    OldCursor += (LastChar - OldLastChar);
89759243Sobrien		OldLastChar = LastChar;
89859243Sobrien	    }
89959243Sobrien	}
90059243Sobrien	argptr = Cursor;
90159243Sobrien    } while (endflag);
90259243Sobrien    Cursor = OldCursor;
90359243Sobrien    return 1;
90459243Sobrien}
90559243Sobrien
906