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