1232633Smp/* $Header: /p/tcsh/cvsroot/tcsh/ed.inputl.c,v 3.71 2010/12/22 17:26:04 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
35232633SmpRCSID("$tcsh: ed.inputl.c,v 3.71 2010/12/22 17:26:04 christos Exp $")
3659243Sobrien
3759243Sobrien#include "ed.h"
3859243Sobrien#include "ed.defns.h"		/* for the function names */
3959243Sobrien#include "tw.h"			/* for twenex stuff */
4059243Sobrien
41167465Smp#define OKCMD INT_MAX
4259243Sobrien
4359243Sobrien/* ed.inputl -- routines to get a single line from the input. */
4459243Sobrien
45145479Smpextern int MapsAreInited;
4659243Sobrien
4759243Sobrien/* mismatched first character */
48195609Smpstatic Char mismatch[] = { '\\', '-', '%', '\0' };
49195609Smp/* don't Strchr() for '\0', obey current history character settings */
50195609Smp#define MISMATCH(c) ((c) == '\0' || (c) == HIST || (c) == HISTSUB || \
51195609Smp			Strchr(mismatch, (c)))
5259243Sobrien
53167465Smpstatic	int	Repair		(void);
54167465Smpstatic	int	GetNextCommand	(KEYCMD *, Char *);
55167465Smpstatic	int	SpellLine	(int);
56167465Smpstatic	int	CompleteLine	(void);
57167465Smpstatic	void	RunCommand	(Char *);
58167465Smpstatic  void 	doeval1		(Char **);
5959243Sobrien
60145479Smpstatic int rotate = 0;
6159243Sobrien
6259243Sobrien
6359243Sobrienstatic int
64167465SmpRepair(void)
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
80167465SmpInputl(void)
8159243Sobrien{
8259243Sobrien    CCRETVAL retval;
8359243Sobrien    KEYCMD  cmdnum = 0;
8459243Sobrien    unsigned char tch;		/* the place where read() goes */
8559243Sobrien    Char    ch;
8659243Sobrien    int     num;		/* how many chars we have read at NL */
8759243Sobrien    int	    expnum;
8859243Sobrien    struct varent *crct = inheredoc ? NULL : adrof(STRcorrect);
8959243Sobrien    struct varent *autol = adrof(STRautolist);
9059243Sobrien    struct varent *matchbeep = adrof(STRmatchbeep);
9159243Sobrien    struct varent *imode = adrof(STRinputmode);
9259243Sobrien    Char   *SaveChar, *CorrChar;
9359243Sobrien    int     matchval;		/* from tenematch() */
94195609Smp    int     nr_history_exp;     /* number of (attempted) history expansions */
9559243Sobrien    COMMAND fn;
9659243Sobrien    int curlen = 0;
9759243Sobrien    int newlen;
9859243Sobrien    int idx;
99195609Smp    Char *autoexpand;
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;
138167465Smp    tellwhat = 0;
13959243Sobrien
140167465Smp    if (RestoreSaved) {
141167465Smp	copyn(InputBuf, SavedBuf.s, INBUFSIZE);/*FIXBUF*/
142167465Smp	LastChar = InputBuf + LastSaved;
143167465Smp	Cursor = InputBuf + CursSaved;
144167465Smp	Hist_num = HistSaved;
145167465Smp	HistSaved = 0;
146167465Smp	RestoreSaved = 0;
14759243Sobrien    }
148167465Smp    if (HistSaved) {
149167465Smp	Hist_num = HistSaved;
150167465Smp	GetHistLine();
151167465Smp	HistSaved = 0;
152167465Smp    }
15359243Sobrien    if (Expand) {
15459243Sobrien	(void) e_up_hist(0);
15559243Sobrien	Expand = 0;
15659243Sobrien    }
15759243Sobrien    Refresh();			/* print the prompt */
15859243Sobrien
15959243Sobrien    for (num = OKCMD; num == OKCMD;) {	/* while still editing this line */
16059243Sobrien#ifdef DEBUG_EDIT
16159243Sobrien	if (Cursor > LastChar)
16259243Sobrien	    xprintf("Cursor > LastChar\r\n");
16359243Sobrien	if (Cursor < InputBuf)
16459243Sobrien	    xprintf("Cursor < InputBuf\r\n");
16559243Sobrien	if (Cursor > InputLim)
16659243Sobrien	    xprintf("Cursor > InputLim\r\n");
16759243Sobrien	if (LastChar > InputLim)
16859243Sobrien	    xprintf("LastChar > InputLim\r\n");
169167465Smp	if (InputLim != &InputBuf[INBUFSIZE - 2])/*FIXBUF*/
17059243Sobrien	    xprintf("InputLim != &InputBuf[INBUFSIZE-2]\r\n");
17159243Sobrien	if ((!DoingArg) && (Argument != 1))
17259243Sobrien	    xprintf("(!DoingArg) && (Argument != 1)\r\n");
17359243Sobrien	if (CcKeyMap[0] == 0)
17459243Sobrien	    xprintf("CcKeyMap[0] == 0 (maybe not inited)\r\n");
17559243Sobrien#endif
17659243Sobrien
17759243Sobrien	/* if EOF or error */
17859243Sobrien	if ((num = GetNextCommand(&cmdnum, &ch)) != OKCMD) {
17959243Sobrien	    break;
18059243Sobrien	}
18159243Sobrien
18259243Sobrien	if (cmdnum >= NumFuns) {/* BUG CHECK command */
18359243Sobrien#ifdef DEBUG_EDIT
18459243Sobrien	    xprintf(CGETS(6, 1, "ERROR: illegal command from key 0%o\r\n"), ch);
18559243Sobrien#endif
18659243Sobrien	    continue;		/* try again */
18759243Sobrien	}
18859243Sobrien
18959243Sobrien	/* now do the real command */
19059243Sobrien	retval = (*CcFuncTbl[cmdnum]) (ch);
19159243Sobrien
19259243Sobrien	/* save the last command here */
19359243Sobrien	LastCmd = cmdnum;
19459243Sobrien
19559243Sobrien	/* make sure fn is initialized */
19659243Sobrien	fn = (retval == CC_COMPLETE_ALL) ? LIST_ALL : LIST;
19759243Sobrien
19859243Sobrien	/* use any return value */
19959243Sobrien	switch (retval) {
20059243Sobrien
20159243Sobrien	case CC_REFRESH:
20259243Sobrien	    Refresh();
20359243Sobrien	    /*FALLTHROUGH*/
20459243Sobrien	case CC_NORM:		/* normal char */
20559243Sobrien	    Argument = 1;
20659243Sobrien	    DoingArg = 0;
20759243Sobrien	    /*FALLTHROUGH*/
20859243Sobrien	case CC_ARGHACK:	/* Suggested by Rich Salz */
20959243Sobrien	    /* <rsalz@pineapple.bbn.com> */
21059243Sobrien	    curchoice = -1;
21159243Sobrien	    curlen = (int) (LastChar - InputBuf);
21259243Sobrien	    break;		/* keep going... */
21359243Sobrien
21459243Sobrien	case CC_EOF:		/* end of file typed */
21559243Sobrien	    curchoice = -1;
21659243Sobrien	    curlen = (int) (LastChar - InputBuf);
21759243Sobrien	    num = 0;
21859243Sobrien	    break;
21959243Sobrien
22059243Sobrien	case CC_WHICH:		/* tell what this command does */
22159243Sobrien	    tellwhat = 1;
22259243Sobrien	    *LastChar++ = '\n';	/* for the benifit of CSH */
22359243Sobrien	    num = (int) (LastChar - InputBuf);	/* number characters read */
22459243Sobrien	    break;
22559243Sobrien
22659243Sobrien	case CC_NEWLINE:	/* normal end of line */
22759243Sobrien	    curlen = 0;
22859243Sobrien	    curchoice = -1;
22959243Sobrien	    matchval = 1;
230100616Smp	    if (crct && crct->vec != NULL && (!Strcmp(*(crct->vec), STRcmd) ||
23159243Sobrien			 !Strcmp(*(crct->vec), STRall))) {
232167465Smp		Char *Origin;
233167465Smp
23459243Sobrien                PastBottom();
235167465Smp		Origin = Strsave(InputBuf);
236167465Smp		cleanup_push(Origin, xfree);
23759243Sobrien		SaveChar = LastChar;
23859243Sobrien		if (SpellLine(!Strcmp(*(crct->vec), STRcmd)) == 1) {
239167465Smp		    Char *Change;
240167465Smp
24159243Sobrien                    PastBottom();
242167465Smp		    Change = Strsave(InputBuf);
243167465Smp		    cleanup_push(Change, xfree);
24459243Sobrien		    *Strchr(Change, '\n') = '\0';
24559243Sobrien		    CorrChar = LastChar;	/* Save the corrected end */
24659243Sobrien		    LastChar = InputBuf;	/* Null the current line */
24759243Sobrien		    SoundBeep();
24859243Sobrien		    printprompt(2, short2str(Change));
249167465Smp		    cleanup_until(Change);
25059243Sobrien		    Refresh();
251167465Smp		    if (xread(SHIN, &tch, 1) < 0) {
25259243Sobrien#ifdef convex
25359243Sobrien		        /*
25459243Sobrien			 * need to print error message in case file
25559243Sobrien			 * is migrated
25659243Sobrien			 */
257167465Smp                        if (errno)
25859243Sobrien                            stderror(ERR_SYSTEM, progname, strerror(errno));
25959243Sobrien#else
260167465Smp			cleanup_until(Origin);
26159243Sobrien			break;
26259243Sobrien#endif
263167465Smp		    }
26459243Sobrien		    ch = tch;
26559243Sobrien		    if (ch == 'y' || ch == ' ') {
26659243Sobrien			LastChar = CorrChar;	/* Restore the corrected end */
267195609Smp			xprintf("%s", CGETS(6, 2, "yes\n"));
26859243Sobrien		    }
26959243Sobrien		    else {
270167465Smp			Strcpy(InputBuf, Origin);
27159243Sobrien			LastChar = SaveChar;
27259243Sobrien			if (ch == 'e') {
273195609Smp			    xprintf("%s", CGETS(6, 3, "edit\n"));
27459243Sobrien			    *LastChar-- = '\0';
27559243Sobrien			    Cursor = LastChar;
27659243Sobrien			    printprompt(3, NULL);
27759243Sobrien			    ClearLines();
27859243Sobrien			    ClearDisp();
27959243Sobrien			    Refresh();
280167465Smp			    cleanup_until(Origin);
28159243Sobrien			    break;
28259243Sobrien			}
28359243Sobrien			else if (ch == 'a') {
284195609Smp			    xprintf("%s", CGETS(6, 4, "abort\n"));
28559243Sobrien		            LastChar = InputBuf;   /* Null the current line */
28659243Sobrien			    Cursor = LastChar;
28759243Sobrien			    printprompt(0, NULL);
28859243Sobrien			    Refresh();
289167465Smp			    cleanup_until(Origin);
29059243Sobrien			    break;
29159243Sobrien			}
292195609Smp			xprintf("%s", CGETS(6, 5, "no\n"));
29359243Sobrien		    }
29459243Sobrien		    flush();
29559243Sobrien		}
296167465Smp		cleanup_until(Origin);
297100616Smp	    } else if (crct && crct->vec != NULL &&
298100616Smp		!Strcmp(*(crct->vec), STRcomplete)) {
29959243Sobrien                if (LastChar > InputBuf && LastChar[-1] == '\n') {
30059243Sobrien                    LastChar[-1] = '\0';
30159243Sobrien                    LastChar--;
30259243Sobrien                    Cursor = LastChar;
30359243Sobrien                }
30459243Sobrien                match_unique_match = 1;  /* match unique matches */
30559243Sobrien		matchval = CompleteLine();
30659243Sobrien                match_unique_match = 0;
30759243Sobrien        	curlen = (int) (LastChar - InputBuf);
30859243Sobrien		if (matchval != 1) {
30959243Sobrien                    PastBottom();
31059243Sobrien		}
31159243Sobrien		if (matchval == 0) {
312195609Smp		    xprintf("%s", CGETS(6, 6, "No matching command\n"));
31359243Sobrien		} else if (matchval == 2) {
314195609Smp		    xprintf("%s", CGETS(6, 7, "Ambiguous command\n"));
31559243Sobrien		}
31659243Sobrien	        if (NeedsRedraw) {
31759243Sobrien		    ClearLines();
31859243Sobrien		    ClearDisp();
31959243Sobrien		    NeedsRedraw = 0;
32059243Sobrien	        }
32159243Sobrien	        Refresh();
32259243Sobrien	        Argument = 1;
32359243Sobrien	        DoingArg = 0;
32459243Sobrien		if (matchval == 1) {
32559243Sobrien                    PastBottom();
32659243Sobrien                    *LastChar++ = '\n';
32759243Sobrien                    *LastChar = '\0';
32859243Sobrien		}
32959243Sobrien        	curlen = (int) (LastChar - InputBuf);
33059243Sobrien            }
33159243Sobrien	    else
33259243Sobrien		PastBottom();
33359243Sobrien
33459243Sobrien	    if (matchval == 1) {
33559243Sobrien	        tellwhat = 0;	/* just in case */
33659243Sobrien	        Hist_num = 0;	/* for the history commands */
33759243Sobrien		/* return the number of chars read */
33859243Sobrien	        num = (int) (LastChar - InputBuf);
33959243Sobrien	        /*
34059243Sobrien	         * For continuation lines, we set the prompt to prompt 2
34159243Sobrien	         */
34259243Sobrien	        printprompt(1, NULL);
34359243Sobrien	    }
34459243Sobrien	    break;
34559243Sobrien
34659243Sobrien	case CC_CORRECT:
34759243Sobrien	    if (tenematch(InputBuf, Cursor - InputBuf, SPELL) < 0)
34859243Sobrien		SoundBeep();		/* Beep = No match/ambiguous */
34959243Sobrien	    curlen = Repair();
35059243Sobrien	    break;
35159243Sobrien
35259243Sobrien	case CC_CORRECT_L:
35359243Sobrien	    if (SpellLine(FALSE) < 0)
35459243Sobrien		SoundBeep();		/* Beep = No match/ambiguous */
35559243Sobrien	    curlen = Repair();
35659243Sobrien	    break;
35759243Sobrien
35859243Sobrien
35959243Sobrien	case CC_COMPLETE:
36059243Sobrien	case CC_COMPLETE_ALL:
36159243Sobrien	case CC_COMPLETE_FWD:
36259243Sobrien	case CC_COMPLETE_BACK:
36359243Sobrien	    switch (retval) {
36459243Sobrien	    case CC_COMPLETE:
36559243Sobrien		fn = RECOGNIZE;
36659243Sobrien		curlen = (int) (LastChar - InputBuf);
36759243Sobrien		curchoice = -1;
36859243Sobrien		rotate = 0;
36959243Sobrien		break;
37059243Sobrien	    case CC_COMPLETE_ALL:
37159243Sobrien		fn = RECOGNIZE_ALL;
37259243Sobrien		curlen = (int) (LastChar - InputBuf);
37359243Sobrien		curchoice = -1;
37459243Sobrien		rotate = 0;
37559243Sobrien		break;
37659243Sobrien	    case CC_COMPLETE_FWD:
37759243Sobrien		fn = RECOGNIZE_SCROLL;
37859243Sobrien		curchoice++;
37959243Sobrien		rotate = 1;
38059243Sobrien		break;
38159243Sobrien	    case CC_COMPLETE_BACK:
38259243Sobrien		fn = RECOGNIZE_SCROLL;
38359243Sobrien		curchoice--;
38459243Sobrien		rotate = 1;
38559243Sobrien		break;
38659243Sobrien	    default:
38759243Sobrien		abort();
38859243Sobrien	    }
38959243Sobrien	    if (InputBuf[curlen] && rotate) {
39059243Sobrien		newlen = (int) (LastChar - InputBuf);
39159243Sobrien		for (idx = (int) (Cursor - InputBuf);
39259243Sobrien		     idx <= newlen; idx++)
39359243Sobrien			InputBuf[idx - newlen + curlen] =
39459243Sobrien			InputBuf[idx];
39559243Sobrien		LastChar = InputBuf + curlen;
39659243Sobrien		Cursor = Cursor - newlen + curlen;
39759243Sobrien	    }
39859243Sobrien	    curlen = (int) (LastChar - InputBuf);
39959243Sobrien
40059243Sobrien
401195609Smp	    nr_history_exp = 0;
402195609Smp	    autoexpand = varval(STRautoexpand);
403195609Smp	    if (autoexpand != STRNULL)
404195609Smp		nr_history_exp += ExpandHistory();
405195609Smp
406195609Smp	    /* try normal expansion only if no history references were found */
407195609Smp	    if (nr_history_exp == 0 ||
408195609Smp		Strcmp(autoexpand, STRonlyhistory) != 0) {
409195609Smp		/*
410195609Smp		 * Modified by Martin Boyer (gamin@ireq-robot.hydro.qc.ca):
411195609Smp		 * A separate variable now controls beeping after
412195609Smp		 * completion, independently of autolisting.
413195609Smp		 */
414195609Smp		expnum = (int) (Cursor - InputBuf);
415195609Smp		switch (matchval = tenematch(InputBuf, Cursor-InputBuf, fn)){
416195609Smp		case 1:
417195609Smp		    if (non_unique_match && matchbeep &&
418195609Smp			matchbeep->vec != NULL &&
419195609Smp			(Strcmp(*(matchbeep->vec), STRnotunique) == 0))
42059243Sobrien			SoundBeep();
42159243Sobrien		    break;
422195609Smp		case 0:
423195609Smp		    if (matchbeep && matchbeep->vec != NULL) {
424195609Smp			if (Strcmp(*(matchbeep->vec), STRnomatch) == 0 ||
425195609Smp			    Strcmp(*(matchbeep->vec), STRambiguous) == 0 ||
426195609Smp			    Strcmp(*(matchbeep->vec), STRnotunique) == 0)
427195609Smp			    SoundBeep();
428195609Smp		    }
429195609Smp		    else
43059243Sobrien			SoundBeep();
431195609Smp		    break;
432195609Smp		default:
433195609Smp		    if (matchval < 0) {	/* Error from tenematch */
434195609Smp			curchoice = -1;
435195609Smp			SoundBeep();
436195609Smp			break;
437167465Smp		    }
438195609Smp		    if (matchbeep && matchbeep->vec != NULL) {
439195609Smp			if ((Strcmp(*(matchbeep->vec), STRambiguous) == 0 ||
440195609Smp			     Strcmp(*(matchbeep->vec), STRnotunique) == 0))
441195609Smp			    SoundBeep();
442195609Smp		    }
443195609Smp		    else
444195609Smp			SoundBeep();
445195609Smp		    /*
446195609Smp		     * Addition by David C Lawrence <tale@pawl.rpi.edu>: If an
447195609Smp		     * attempted completion is ambiguous, list the choices.
448195609Smp		     * (PWP: this is the best feature addition to tcsh I have
449195609Smp		     * seen in many months.)
450195609Smp		     */
451195609Smp		    if (autol && autol->vec != NULL &&
452195609Smp			(Strcmp(*(autol->vec), STRambiguous) != 0 ||
453195609Smp					 expnum == Cursor - InputBuf)) {
454195609Smp			if (adrof(STRhighlight) && MarkIsSet) {
455195609Smp			    /* clear highlighting before showing completions */
456195609Smp			    MarkIsSet = 0;
457195609Smp			    ClearLines();
458195609Smp			    ClearDisp();
459195609Smp			    Refresh();
460195609Smp			    MarkIsSet = 1;
461195609Smp			}
462195609Smp			PastBottom();
463195609Smp			fn = (retval == CC_COMPLETE_ALL) ? LIST_ALL : LIST;
464195609Smp			(void) tenematch(InputBuf, Cursor-InputBuf, fn);
465195609Smp		    }
466195609Smp		    break;
46759243Sobrien		}
46859243Sobrien	    }
46959243Sobrien	    if (NeedsRedraw) {
47059243Sobrien		PastBottom();
47159243Sobrien		ClearLines();
47259243Sobrien		ClearDisp();
47359243Sobrien		NeedsRedraw = 0;
47459243Sobrien	    }
47559243Sobrien	    Refresh();
47659243Sobrien	    Argument = 1;
47759243Sobrien	    DoingArg = 0;
47859243Sobrien	    break;
47959243Sobrien
48059243Sobrien	case CC_LIST_CHOICES:
48159243Sobrien	case CC_LIST_ALL:
48259243Sobrien	    if (InputBuf[curlen] && rotate) {
48359243Sobrien		newlen = (int) (LastChar - InputBuf);
48459243Sobrien		for (idx = (int) (Cursor - InputBuf);
48559243Sobrien		     idx <= newlen; idx++)
48659243Sobrien			InputBuf[idx - newlen + curlen] =
48759243Sobrien			InputBuf[idx];
48859243Sobrien		LastChar = InputBuf + curlen;
48959243Sobrien		Cursor = Cursor - newlen + curlen;
49059243Sobrien	    }
49159243Sobrien	    curlen = (int) (LastChar - InputBuf);
49259243Sobrien	    if (curchoice >= 0)
49359243Sobrien		curchoice--;
49459243Sobrien
49559243Sobrien	    fn = (retval == CC_LIST_ALL) ? LIST_ALL : LIST;
49659243Sobrien	    /* should catch ^C here... */
49759243Sobrien	    if (tenematch(InputBuf, Cursor - InputBuf, fn) < 0)
49859243Sobrien		SoundBeep();
49959243Sobrien	    Refresh();
50059243Sobrien	    Argument = 1;
50159243Sobrien	    DoingArg = 0;
50259243Sobrien	    break;
50359243Sobrien
50459243Sobrien
50559243Sobrien	case CC_LIST_GLOB:
50659243Sobrien	    if (tenematch(InputBuf, Cursor - InputBuf, GLOB) < 0)
50759243Sobrien		SoundBeep();
50859243Sobrien	    curlen = Repair();
50959243Sobrien	    break;
51059243Sobrien
51159243Sobrien	case CC_EXPAND_GLOB:
51259243Sobrien	    if (tenematch(InputBuf, Cursor - InputBuf, GLOB_EXPAND) <= 0)
51359243Sobrien		SoundBeep();		/* Beep = No match */
51459243Sobrien	    curlen = Repair();
51559243Sobrien	    break;
51659243Sobrien
51759243Sobrien	case CC_NORMALIZE_PATH:
51859243Sobrien	    if (tenematch(InputBuf, Cursor - InputBuf, PATH_NORMALIZE) <= 0)
51959243Sobrien		SoundBeep();		/* Beep = No match */
52059243Sobrien	    curlen = Repair();
52159243Sobrien	    break;
52259243Sobrien
52359243Sobrien	case CC_EXPAND_VARS:
52459243Sobrien	    if (tenematch(InputBuf, Cursor - InputBuf, VARS_EXPAND) <= 0)
52559243Sobrien		SoundBeep();		/* Beep = No match */
52659243Sobrien	    curlen = Repair();
52759243Sobrien	    break;
52859243Sobrien
52959243Sobrien	case CC_NORMALIZE_COMMAND:
53059243Sobrien	    if (tenematch(InputBuf, Cursor - InputBuf, COMMAND_NORMALIZE) <= 0)
53159243Sobrien		SoundBeep();		/* Beep = No match */
53259243Sobrien	    curlen = Repair();
53359243Sobrien	    break;
53459243Sobrien
53559243Sobrien	case CC_HELPME:
53659243Sobrien	    xputchar('\n');
53759243Sobrien	    /* should catch ^C here... */
53859243Sobrien	    (void) tenematch(InputBuf, LastChar - InputBuf, PRINT_HELP);
53959243Sobrien	    Refresh();
54059243Sobrien	    Argument = 1;
54159243Sobrien	    DoingArg = 0;
54259243Sobrien	    curchoice = -1;
54359243Sobrien	    curlen = (int) (LastChar - InputBuf);
54459243Sobrien	    break;
54559243Sobrien
54659243Sobrien	case CC_FATAL:		/* fatal error, reset to known state */
54759243Sobrien#ifdef DEBUG_EDIT
54859243Sobrien	    xprintf(CGETS(7, 8, "*** editor fatal ERROR ***\r\n\n"));
54959243Sobrien#endif				/* DEBUG_EDIT */
55059243Sobrien	    /* put (real) cursor in a known place */
55159243Sobrien	    ClearDisp();	/* reset the display stuff */
55259243Sobrien	    ResetInLine(1);	/* reset the input pointers */
55359243Sobrien	    Refresh();		/* print the prompt again */
55459243Sobrien	    Argument = 1;
55559243Sobrien	    DoingArg = 0;
55659243Sobrien	    curchoice = -1;
55759243Sobrien	    curlen = (int) (LastChar - InputBuf);
55859243Sobrien	    break;
55959243Sobrien
56059243Sobrien	case CC_ERROR:
56159243Sobrien	default:		/* functions we don't know about */
562167465Smp	    if (adrof(STRhighlight)) {
563167465Smp		ClearLines();
564167465Smp		ClearDisp();
565167465Smp		Refresh();
566167465Smp	    }
56759243Sobrien	    DoingArg = 0;
56859243Sobrien	    Argument = 1;
56959243Sobrien	    SoundBeep();
57059243Sobrien	    flush();
57159243Sobrien	    curchoice = -1;
57259243Sobrien	    curlen = (int) (LastChar - InputBuf);
57359243Sobrien	    break;
57459243Sobrien	}
57559243Sobrien    }
57659243Sobrien    (void) Cookedmode();	/* make sure the tty is set up correctly */
57759243Sobrien    GettingInput = 0;
57859243Sobrien    flush();			/* flush any buffered output */
57959243Sobrien    return num;
58059243Sobrien}
58159243Sobrien
58259243Sobrienvoid
583167465SmpPushMacro(Char *str)
58459243Sobrien{
58559243Sobrien    if (str != NULL && MacroLvl + 1 < MAXMACROLEVELS) {
58659243Sobrien	MacroLvl++;
58759243Sobrien	KeyMacro[MacroLvl] = str;
58859243Sobrien    }
58959243Sobrien    else {
59059243Sobrien	SoundBeep();
59159243Sobrien	flush();
59259243Sobrien    }
59359243Sobrien}
59459243Sobrien
595167465Smpstruct eval1_state
596167465Smp{
597167465Smp    Char **evalvec, *evalp;
598167465Smp};
599167465Smp
600167465Smpstatic void
601167465Smpeval1_cleanup(void *xstate)
602167465Smp{
603167465Smp    struct eval1_state *state;
604167465Smp
605167465Smp    state = xstate;
606167465Smp    evalvec = state->evalvec;
607167465Smp    evalp = state->evalp;
608167465Smp    doneinp = 0;
609167465Smp}
610167465Smp
61159243Sobrien/*
61259243Sobrien * Like eval, only using the current file descriptors
61359243Sobrien */
61459243Sobrienstatic void
615167465Smpdoeval1(Char **v)
61659243Sobrien{
617167465Smp    struct eval1_state state;
618167465Smp    Char  **gv;
619167465Smp    int gflag;
62059243Sobrien
621167465Smp    gflag = tglob(v);
62259243Sobrien    if (gflag) {
623167465Smp	gv = v = globall(v, gflag);
624167465Smp	if (v == 0)
62559243Sobrien	    stderror(ERR_NOMATCH);
626167465Smp	v = copyblk(v);
62759243Sobrien    }
62859243Sobrien    else {
62959243Sobrien	gv = NULL;
630167465Smp	v = copyblk(v);
631167465Smp	trim(v);
63259243Sobrien    }
633167465Smp    if (gv)
634167465Smp	cleanup_push(gv, blk_cleanup);
63559243Sobrien
636167465Smp    state.evalvec = evalvec;
637167465Smp    state.evalp = evalp;
638167465Smp    evalvec = v;
639167465Smp    evalp = 0;
640167465Smp    cleanup_push(&state, eval1_cleanup);
641167465Smp    process(0);
642167465Smp    cleanup_until(&state);
64359243Sobrien    if (gv)
644167465Smp	cleanup_until(gv);
64559243Sobrien}
64659243Sobrien
64759243Sobrienstatic void
648167465SmpRunCommand(Char *str)
64959243Sobrien{
65059243Sobrien    Char *cmd[2];
65159243Sobrien
65259243Sobrien    xputchar('\n');	/* Start on a clean line */
65359243Sobrien
65459243Sobrien    cmd[0] = str;
65559243Sobrien    cmd[1] = NULL;
65659243Sobrien
65759243Sobrien    (void) Cookedmode();
65859243Sobrien    GettingInput = 0;
65959243Sobrien
66059243Sobrien    doeval1(cmd);
661167465Smp
66259243Sobrien    (void) Rawmode();
66359243Sobrien    GettingInput = 1;
66459243Sobrien
66559243Sobrien    ClearLines();
66659243Sobrien    ClearDisp();
66759243Sobrien    NeedsRedraw = 0;
66859243Sobrien    Refresh();
66959243Sobrien}
67059243Sobrien
67159243Sobrienstatic int
672167465SmpGetNextCommand(KEYCMD *cmdnum, Char *ch)
67359243Sobrien{
67459243Sobrien    KEYCMD  cmd = 0;
67559243Sobrien    int     num;
67659243Sobrien
67759243Sobrien    while (cmd == 0 || cmd == F_XKEY) {
67859243Sobrien	if ((num = GetNextChar(ch)) != 1) {	/* if EOF or error */
67959243Sobrien	    return num;
68059243Sobrien	}
68159243Sobrien#ifdef	KANJI
68261519Sobrien	if (
68361519Sobrien#ifdef DSPMBYTE
68461519Sobrien	     _enable_mbdisp &&
685145479Smp#else
686232633Smp	     MB_CUR_MAX == 1 &&
68761519Sobrien#endif
68861519Sobrien	     !adrof(STRnokanji) && (*ch & META)) {
68959243Sobrien	    MetaNext = 0;
69059243Sobrien	    cmd = F_INSERT;
69159243Sobrien	    break;
69259243Sobrien	}
69359243Sobrien	else
69459243Sobrien#endif /* KANJI */
69559243Sobrien	if (MetaNext) {
69659243Sobrien	    MetaNext = 0;
69759243Sobrien	    *ch |= META;
69859243Sobrien	}
69959243Sobrien	/* XXX: This needs to be fixed so that we don't just truncate
70059243Sobrien	 * the character, we unquote it.
70159243Sobrien	 */
70259243Sobrien	if (*ch < NT_NUM_KEYS)
70359243Sobrien	    cmd = CurrentKeyMap[*ch];
70459243Sobrien	else
705145479Smp#ifdef WINNT_NATIVE
70659243Sobrien	    cmd = CurrentKeyMap[(unsigned char) *ch];
707145479Smp#else
708145479Smp	    cmd = F_INSERT;
709145479Smp#endif
71059243Sobrien	if (cmd == F_XKEY) {
71159243Sobrien	    XmapVal val;
71259243Sobrien	    CStr cstr;
71359243Sobrien	    cstr.buf = ch;
714167465Smp	    cstr.len = 1;
71559243Sobrien	    switch (GetXkey(&cstr, &val)) {
71659243Sobrien	    case XK_CMD:
71759243Sobrien		cmd = val.cmd;
71859243Sobrien		break;
71959243Sobrien	    case XK_STR:
72059243Sobrien		PushMacro(val.str.buf);
72159243Sobrien		break;
72259243Sobrien	    case XK_EXE:
72359243Sobrien		RunCommand(val.str.buf);
72459243Sobrien		break;
72559243Sobrien	    default:
72659243Sobrien		abort();
72759243Sobrien		break;
72859243Sobrien	    }
72959243Sobrien	}
73059243Sobrien	if (!AltKeyMap)
73159243Sobrien	    CurrentKeyMap = CcKeyMap;
73259243Sobrien    }
73359243Sobrien    *cmdnum = cmd;
73459243Sobrien    return OKCMD;
73559243Sobrien}
73659243Sobrien
737145479Smpstatic Char ungetchar;
738145479Smpstatic int haveungetchar;
739145479Smp
740145479Smpvoid
741145479SmpUngetNextChar(Char cp)
742145479Smp{
743145479Smp    ungetchar = cp;
744145479Smp    haveungetchar = 1;
745145479Smp}
746145479Smp
74759243Sobrienint
748167465SmpGetNextChar(Char *cp)
74959243Sobrien{
750145479Smp    int num_read;
75159243Sobrien    int     tried = 0;
752145479Smp    char cbuf[MB_LEN_MAX];
753145479Smp    size_t cbp;
75459243Sobrien
755145479Smp    if (haveungetchar) {
756145479Smp	haveungetchar = 0;
757145479Smp	*cp = ungetchar;
758145479Smp	return 1;
759145479Smp    }
76059243Sobrien    for (;;) {
76159243Sobrien	if (MacroLvl < 0) {
76259243Sobrien	    if (!Load_input_line())
76359243Sobrien		break;
76459243Sobrien	}
76559243Sobrien	if (*KeyMacro[MacroLvl] == 0) {
76659243Sobrien	    MacroLvl--;
76759243Sobrien	    continue;
76859243Sobrien	}
76959243Sobrien	*cp = *KeyMacro[MacroLvl]++ & CHAR;
77059243Sobrien	if (*KeyMacro[MacroLvl] == 0) {	/* Needed for QuoteMode On */
77159243Sobrien	    MacroLvl--;
77259243Sobrien	}
77359243Sobrien	return (1);
77459243Sobrien    }
77559243Sobrien
77659243Sobrien    if (Rawmode() < 0)		/* make sure the tty is set up correctly */
77759243Sobrien	return 0;		/* oops: SHIN was closed */
77859243Sobrien
77969408Sache#ifdef WINNT_NATIVE
78059243Sobrien    __nt_want_vcode = 1;
78169408Sache#endif /* WINNT_NATIVE */
782145479Smp#ifdef SIG_WINDOW
783145479Smp    if (windowchg)
784145479Smp	(void) check_window_size(0);	/* for window systems */
785145479Smp#endif /* SIG_WINDOW */
786145479Smp    cbp = 0;
787145479Smp    for (;;) {
788167465Smp	while ((num_read = xread(SHIN, cbuf + cbp, 1)) == -1) {
789145479Smp	    if (!tried && fixio(SHIN, errno) != -1)
790145479Smp		tried = 1;
791145479Smp	    else {
792145479Smp# ifdef convex
793145479Smp		/* need to print error message in case the file is migrated */
794167465Smp		stderror(ERR_SYSTEM, progname, strerror(errno));
795145479Smp# endif  /* convex */
796145479Smp# ifdef WINNT_NATIVE
797145479Smp		__nt_want_vcode = 0;
798145479Smp# endif /* WINNT_NATIVE */
799145479Smp		*cp = '\0'; /* Loses possible partial character */
800145479Smp		return -1;
801145479Smp	    }
80259243Sobrien	}
803167465Smp	if (AsciiOnly) {
804167465Smp	    *cp = (unsigned char)*cbuf;
805167465Smp	} else {
806167465Smp	    cbp++;
807167465Smp	    if (normal_mbtowc(cp, cbuf, cbp) == -1) {
808167465Smp		reset_mbtowc();
809167465Smp		if (cbp < MB_CUR_MAX)
810167465Smp		    continue; /* Maybe a partial character */
811167465Smp		/* And drop the following bytes, if any */
812167465Smp		*cp = (unsigned char)*cbuf | INVALID_BYTE;
813167465Smp	    }
814145479Smp	}
815145479Smp	break;
81659243Sobrien    }
81769408Sache#ifdef WINNT_NATIVE
818145479Smp    /* This is the part that doesn't work with WIDE_STRINGS */
81959243Sobrien    if (__nt_want_vcode == 2)
82059243Sobrien	*cp = __nt_vcode;
82159243Sobrien    __nt_want_vcode = 0;
82269408Sache#endif /* WINNT_NATIVE */
82359243Sobrien    return num_read;
82459243Sobrien}
82559243Sobrien
82659243Sobrien/*
82759243Sobrien * SpellLine - do spelling correction on the entire command line
82859243Sobrien * (which may have trailing newline).
82959243Sobrien * If cmdonly is set, only check spelling of command words.
83059243Sobrien * Return value:
83159243Sobrien * -1: Something was incorrectible, and nothing was corrected
83259243Sobrien *  0: Everything was correct
83359243Sobrien *  1: Something was corrected
83459243Sobrien */
83559243Sobrienstatic int
836167465SmpSpellLine(int cmdonly)
83759243Sobrien{
83859243Sobrien    int     endflag, matchval;
83959243Sobrien    Char   *argptr, *OldCursor, *OldLastChar;
84059243Sobrien
84159243Sobrien    OldLastChar = LastChar;
84259243Sobrien    OldCursor = Cursor;
84359243Sobrien    argptr = InputBuf;
84459243Sobrien    endflag = 1;
84559243Sobrien    matchval = 0;
84659243Sobrien    do {
84759243Sobrien	while (ismetahash(*argptr) || iscmdmeta(*argptr))
84859243Sobrien	    argptr++;
84959243Sobrien	for (Cursor = argptr;
85059243Sobrien	     *Cursor != '\0' && ((Cursor != argptr && Cursor[-1] == '\\') ||
85159243Sobrien				 (!ismetahash(*Cursor) && !iscmdmeta(*Cursor)));
85259243Sobrien	     Cursor++)
85359243Sobrien	     continue;
85459243Sobrien	if (*Cursor == '\0') {
85559243Sobrien	    Cursor = LastChar;
85659243Sobrien	    if (LastChar[-1] == '\n')
85759243Sobrien		Cursor--;
85859243Sobrien	    endflag = 0;
85959243Sobrien	}
860195609Smp	if (!MISMATCH(*argptr) &&
86159243Sobrien	    (!cmdonly || starting_a_command(argptr, InputBuf))) {
86269408Sache#ifdef WINNT_NATIVE
86359243Sobrien	    /*
86459243Sobrien	     * This hack avoids correcting drive letter changes
86559243Sobrien	     */
86659243Sobrien	    if((Cursor - InputBuf) != 2 || (char)InputBuf[1] != ':')
86769408Sache#endif /* WINNT_NATIVE */
86859243Sobrien	    {
86959243Sobrien#ifdef HASH_SPELL_CHECK
87059243Sobrien		Char save;
87159243Sobrien		size_t len = Cursor - InputBuf;
87259243Sobrien
87359243Sobrien		save = InputBuf[len];
87459243Sobrien		InputBuf[len] = '\0';
87559243Sobrien		if (find_cmd(InputBuf, 0) != 0) {
87659243Sobrien		    InputBuf[len] = save;
87759243Sobrien		    argptr = Cursor;
87859243Sobrien		    continue;
87959243Sobrien		}
88059243Sobrien		InputBuf[len] = save;
88159243Sobrien#endif /* HASH_SPELL_CHECK */
88259243Sobrien		switch (tenematch(InputBuf, Cursor - InputBuf, SPELL)) {
88359243Sobrien		case 1:		/* corrected */
88459243Sobrien		    matchval = 1;
88559243Sobrien		    break;
88659243Sobrien		case -1:		/* couldn't be corrected */
88759243Sobrien		    if (!matchval)
88859243Sobrien			matchval = -1;
88959243Sobrien		    break;
89059243Sobrien		default:		/* was correct */
89159243Sobrien		    break;
89259243Sobrien		}
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 matchval;
90459243Sobrien}
90559243Sobrien
90659243Sobrien/*
90759243Sobrien * CompleteLine - do command completion on the entire command line
90859243Sobrien * (which may have trailing newline).
90959243Sobrien * Return value:
91059243Sobrien *  0: No command matched or failure
91159243Sobrien *  1: One command matched
91259243Sobrien *  2: Several commands matched
91359243Sobrien */
91459243Sobrienstatic int
915167465SmpCompleteLine(void)
91659243Sobrien{
91759243Sobrien    int     endflag, tmatch;
91859243Sobrien    Char   *argptr, *OldCursor, *OldLastChar;
91959243Sobrien
92059243Sobrien    OldLastChar = LastChar;
92159243Sobrien    OldCursor = Cursor;
92259243Sobrien    argptr = InputBuf;
92359243Sobrien    endflag = 1;
92459243Sobrien    do {
92559243Sobrien	while (ismetahash(*argptr) || iscmdmeta(*argptr))
92659243Sobrien	    argptr++;
92759243Sobrien	for (Cursor = argptr;
92859243Sobrien	     *Cursor != '\0' && ((Cursor != argptr && Cursor[-1] == '\\') ||
92959243Sobrien				 (!ismetahash(*Cursor) && !iscmdmeta(*Cursor)));
93059243Sobrien	     Cursor++)
93159243Sobrien	     continue;
93259243Sobrien	if (*Cursor == '\0') {
93359243Sobrien	    Cursor = LastChar;
93459243Sobrien	    if (LastChar[-1] == '\n')
93559243Sobrien		Cursor--;
93659243Sobrien	    endflag = 0;
93759243Sobrien	}
938195609Smp	if (!MISMATCH(*argptr) && starting_a_command(argptr, InputBuf)) {
93959243Sobrien	    tmatch = tenematch(InputBuf, Cursor - InputBuf, RECOGNIZE);
94059243Sobrien	    if (tmatch <= 0) {
94159243Sobrien                return 0;
94259243Sobrien            } else if (tmatch > 1) {
94359243Sobrien                return 2;
94459243Sobrien	    }
94559243Sobrien	    if (LastChar != OldLastChar) {
94659243Sobrien		if (argptr < OldCursor)
94759243Sobrien		    OldCursor += (LastChar - OldLastChar);
94859243Sobrien		OldLastChar = LastChar;
94959243Sobrien	    }
95059243Sobrien	}
95159243Sobrien	argptr = Cursor;
95259243Sobrien    } while (endflag);
95359243Sobrien    Cursor = OldCursor;
95459243Sobrien    return 1;
95559243Sobrien}
95659243Sobrien
957