159243Sobrien/* 259243Sobrien * ed.inputl.c: Input line handling. 359243Sobrien */ 459243Sobrien/*- 559243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 659243Sobrien * All rights reserved. 759243Sobrien * 859243Sobrien * Redistribution and use in source and binary forms, with or without 959243Sobrien * modification, are permitted provided that the following conditions 1059243Sobrien * are met: 1159243Sobrien * 1. Redistributions of source code must retain the above copyright 1259243Sobrien * notice, this list of conditions and the following disclaimer. 1359243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1459243Sobrien * notice, this list of conditions and the following disclaimer in the 1559243Sobrien * documentation and/or other materials provided with the distribution. 16100616Smp * 3. Neither the name of the University nor the names of its contributors 1759243Sobrien * may be used to endorse or promote products derived from this software 1859243Sobrien * without specific prior written permission. 1959243Sobrien * 2059243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2159243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2259243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2359243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2459243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2559243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2659243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2759243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2859243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2959243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3059243Sobrien * SUCH DAMAGE. 3159243Sobrien */ 3259243Sobrien#include "sh.h" 3359243Sobrien#include "ed.h" 3459243Sobrien#include "ed.defns.h" /* for the function names */ 3559243Sobrien#include "tw.h" /* for twenex stuff */ 3659243Sobrien 37167465Smp#define OKCMD INT_MAX 3859243Sobrien 3959243Sobrien/* ed.inputl -- routines to get a single line from the input. */ 4059243Sobrien 41145479Smpextern int MapsAreInited; 4259243Sobrien 4359243Sobrien/* mismatched first character */ 44195609Smpstatic Char mismatch[] = { '\\', '-', '%', '\0' }; 45195609Smp/* don't Strchr() for '\0', obey current history character settings */ 46195609Smp#define MISMATCH(c) ((c) == '\0' || (c) == HIST || (c) == HISTSUB || \ 47195609Smp Strchr(mismatch, (c))) 4859243Sobrien 49167465Smpstatic int Repair (void); 50167465Smpstatic int GetNextCommand (KEYCMD *, Char *); 51167465Smpstatic int SpellLine (int); 52167465Smpstatic int CompleteLine (void); 53167465Smpstatic void RunCommand (Char *); 54167465Smpstatic void doeval1 (Char **); 5559243Sobrien 56145479Smpstatic int rotate = 0; 5759243Sobrien 5859243Sobrien 5959243Sobrienstatic int 60167465SmpRepair(void) 6159243Sobrien{ 6259243Sobrien if (NeedsRedraw) { 6359243Sobrien ClearLines(); 6459243Sobrien ClearDisp(); 6559243Sobrien NeedsRedraw = 0; 6659243Sobrien } 6759243Sobrien Refresh(); 6859243Sobrien Argument = 1; 6959243Sobrien DoingArg = 0; 7059243Sobrien curchoice = -1; 7159243Sobrien return (int) (LastChar - InputBuf); 7259243Sobrien} 7359243Sobrien 7459243Sobrien/* CCRETVAL */ 7559243Sobrienint 76167465SmpInputl(void) 7759243Sobrien{ 7859243Sobrien CCRETVAL retval; 7959243Sobrien KEYCMD cmdnum = 0; 8059243Sobrien unsigned char tch; /* the place where read() goes */ 8159243Sobrien Char ch; 8259243Sobrien int num; /* how many chars we have read at NL */ 8359243Sobrien int expnum; 8459243Sobrien struct varent *crct = inheredoc ? NULL : adrof(STRcorrect); 8559243Sobrien struct varent *autol = adrof(STRautolist); 8659243Sobrien struct varent *matchbeep = adrof(STRmatchbeep); 8759243Sobrien struct varent *imode = adrof(STRinputmode); 8859243Sobrien Char *SaveChar, *CorrChar; 8959243Sobrien int matchval; /* from tenematch() */ 90195609Smp int nr_history_exp; /* number of (attempted) history expansions */ 9159243Sobrien COMMAND fn; 9259243Sobrien int curlen = 0; 9359243Sobrien int newlen; 9459243Sobrien int idx; 95195609Smp Char *autoexpand; 9659243Sobrien 9759243Sobrien if (!MapsAreInited) /* double extra just in case */ 9859243Sobrien ed_InitMaps(); 9959243Sobrien 10059243Sobrien ClearDisp(); /* reset the display stuff */ 10159243Sobrien ResetInLine(0); /* reset the input pointers */ 10259243Sobrien if (GettingInput) 10359243Sobrien MacroLvl = -1; /* editor was interrupted during input */ 10459243Sobrien 105100616Smp if (imode && imode->vec != NULL) { 10659243Sobrien if (!Strcmp(*(imode->vec), STRinsert)) 10759243Sobrien inputmode = MODE_INSERT; 10859243Sobrien else if (!Strcmp(*(imode->vec), STRoverwrite)) 10959243Sobrien inputmode = MODE_REPLACE; 11059243Sobrien } 11159243Sobrien 11259243Sobrien#if defined(FIONREAD) && !defined(OREO) 11359243Sobrien if (!Tty_raw_mode && MacroLvl < 0) { 11459243Sobrien# ifdef SUNOS4 11559243Sobrien long chrs = 0; 11659243Sobrien# else /* !SUNOS4 */ 11759243Sobrien /* 11859243Sobrien * *Everyone* else has an int, but SunOS wants long! 11959243Sobrien * This breaks where int != long (alpha) 12059243Sobrien */ 12159243Sobrien int chrs = 0; 12259243Sobrien# endif /* SUNOS4 */ 12359243Sobrien 12459243Sobrien (void) ioctl(SHIN, FIONREAD, (ioctl_t) & chrs); 12559243Sobrien if (chrs == 0) { 12659243Sobrien if (Rawmode() < 0) 12759243Sobrien return 0; 12859243Sobrien } 12959243Sobrien } 13059243Sobrien#endif /* FIONREAD && !OREO */ 13159243Sobrien 13259243Sobrien GettingInput = 1; 13359243Sobrien NeedsRedraw = 0; 134167465Smp tellwhat = 0; 13559243Sobrien 136167465Smp if (RestoreSaved) { 137167465Smp copyn(InputBuf, SavedBuf.s, INBUFSIZE);/*FIXBUF*/ 138167465Smp LastChar = InputBuf + LastSaved; 139167465Smp Cursor = InputBuf + CursSaved; 140167465Smp Hist_num = HistSaved; 141167465Smp HistSaved = 0; 142167465Smp RestoreSaved = 0; 14359243Sobrien } 144167465Smp if (HistSaved) { 145167465Smp Hist_num = HistSaved; 146167465Smp GetHistLine(); 147167465Smp HistSaved = 0; 148167465Smp } 14959243Sobrien if (Expand) { 15059243Sobrien (void) e_up_hist(0); 15159243Sobrien Expand = 0; 15259243Sobrien } 15359243Sobrien Refresh(); /* print the prompt */ 15459243Sobrien 15559243Sobrien for (num = OKCMD; num == OKCMD;) { /* while still editing this line */ 15659243Sobrien#ifdef DEBUG_EDIT 15759243Sobrien if (Cursor > LastChar) 15859243Sobrien xprintf("Cursor > LastChar\r\n"); 15959243Sobrien if (Cursor < InputBuf) 16059243Sobrien xprintf("Cursor < InputBuf\r\n"); 16159243Sobrien if (Cursor > InputLim) 16259243Sobrien xprintf("Cursor > InputLim\r\n"); 16359243Sobrien if (LastChar > InputLim) 16459243Sobrien xprintf("LastChar > InputLim\r\n"); 165167465Smp if (InputLim != &InputBuf[INBUFSIZE - 2])/*FIXBUF*/ 16659243Sobrien xprintf("InputLim != &InputBuf[INBUFSIZE-2]\r\n"); 16759243Sobrien if ((!DoingArg) && (Argument != 1)) 16859243Sobrien xprintf("(!DoingArg) && (Argument != 1)\r\n"); 16959243Sobrien if (CcKeyMap[0] == 0) 17059243Sobrien xprintf("CcKeyMap[0] == 0 (maybe not inited)\r\n"); 17159243Sobrien#endif 17259243Sobrien 17359243Sobrien /* if EOF or error */ 17459243Sobrien if ((num = GetNextCommand(&cmdnum, &ch)) != OKCMD) { 17559243Sobrien break; 17659243Sobrien } 17759243Sobrien 17859243Sobrien if (cmdnum >= NumFuns) {/* BUG CHECK command */ 17959243Sobrien#ifdef DEBUG_EDIT 18059243Sobrien xprintf(CGETS(6, 1, "ERROR: illegal command from key 0%o\r\n"), ch); 18159243Sobrien#endif 18259243Sobrien continue; /* try again */ 18359243Sobrien } 18459243Sobrien 18559243Sobrien /* now do the real command */ 18659243Sobrien retval = (*CcFuncTbl[cmdnum]) (ch); 18759243Sobrien 18859243Sobrien /* save the last command here */ 18959243Sobrien LastCmd = cmdnum; 19059243Sobrien 19159243Sobrien /* make sure fn is initialized */ 19259243Sobrien fn = (retval == CC_COMPLETE_ALL) ? LIST_ALL : LIST; 19359243Sobrien 19459243Sobrien /* use any return value */ 19559243Sobrien switch (retval) { 19659243Sobrien 19759243Sobrien case CC_REFRESH: 19859243Sobrien Refresh(); 19959243Sobrien /*FALLTHROUGH*/ 20059243Sobrien case CC_NORM: /* normal char */ 20159243Sobrien Argument = 1; 20259243Sobrien DoingArg = 0; 20359243Sobrien /*FALLTHROUGH*/ 20459243Sobrien case CC_ARGHACK: /* Suggested by Rich Salz */ 20559243Sobrien /* <rsalz@pineapple.bbn.com> */ 20659243Sobrien curchoice = -1; 20759243Sobrien curlen = (int) (LastChar - InputBuf); 20859243Sobrien break; /* keep going... */ 20959243Sobrien 21059243Sobrien case CC_EOF: /* end of file typed */ 21159243Sobrien curchoice = -1; 21259243Sobrien curlen = (int) (LastChar - InputBuf); 21359243Sobrien num = 0; 21459243Sobrien break; 21559243Sobrien 21659243Sobrien case CC_WHICH: /* tell what this command does */ 21759243Sobrien tellwhat = 1; 21859243Sobrien *LastChar++ = '\n'; /* for the benifit of CSH */ 21959243Sobrien num = (int) (LastChar - InputBuf); /* number characters read */ 22059243Sobrien break; 22159243Sobrien 22259243Sobrien case CC_NEWLINE: /* normal end of line */ 22359243Sobrien curlen = 0; 22459243Sobrien curchoice = -1; 22559243Sobrien matchval = 1; 226100616Smp if (crct && crct->vec != NULL && (!Strcmp(*(crct->vec), STRcmd) || 22759243Sobrien !Strcmp(*(crct->vec), STRall))) { 228167465Smp Char *Origin; 229167465Smp 23059243Sobrien PastBottom(); 231167465Smp Origin = Strsave(InputBuf); 232167465Smp cleanup_push(Origin, xfree); 23359243Sobrien SaveChar = LastChar; 23459243Sobrien if (SpellLine(!Strcmp(*(crct->vec), STRcmd)) == 1) { 235167465Smp Char *Change; 236167465Smp 23759243Sobrien PastBottom(); 238167465Smp Change = Strsave(InputBuf); 239167465Smp cleanup_push(Change, xfree); 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)); 245167465Smp cleanup_until(Change); 24659243Sobrien Refresh(); 247167465Smp if (xread(SHIN, &tch, 1) < 0) { 24859243Sobrien#ifdef convex 24959243Sobrien /* 25059243Sobrien * need to print error message in case file 25159243Sobrien * is migrated 25259243Sobrien */ 253167465Smp if (errno) 25459243Sobrien stderror(ERR_SYSTEM, progname, strerror(errno)); 25559243Sobrien#else 256167465Smp cleanup_until(Origin); 25759243Sobrien break; 25859243Sobrien#endif 259167465Smp } 26059243Sobrien ch = tch; 26159243Sobrien if (ch == 'y' || ch == ' ') { 26259243Sobrien LastChar = CorrChar; /* Restore the corrected end */ 263195609Smp xprintf("%s", CGETS(6, 2, "yes\n")); 26459243Sobrien } 26559243Sobrien else { 266167465Smp Strcpy(InputBuf, Origin); 26759243Sobrien LastChar = SaveChar; 26859243Sobrien if (ch == 'e') { 269195609Smp xprintf("%s", CGETS(6, 3, "edit\n")); 27059243Sobrien *LastChar-- = '\0'; 27159243Sobrien Cursor = LastChar; 27259243Sobrien printprompt(3, NULL); 27359243Sobrien ClearLines(); 27459243Sobrien ClearDisp(); 27559243Sobrien Refresh(); 276167465Smp cleanup_until(Origin); 27759243Sobrien break; 27859243Sobrien } 27959243Sobrien else if (ch == 'a') { 280195609Smp xprintf("%s", CGETS(6, 4, "abort\n")); 28159243Sobrien LastChar = InputBuf; /* Null the current line */ 28259243Sobrien Cursor = LastChar; 28359243Sobrien printprompt(0, NULL); 28459243Sobrien Refresh(); 285167465Smp cleanup_until(Origin); 28659243Sobrien break; 28759243Sobrien } 288195609Smp xprintf("%s", CGETS(6, 5, "no\n")); 28959243Sobrien } 29059243Sobrien flush(); 29159243Sobrien } 292167465Smp cleanup_until(Origin); 293100616Smp } else if (crct && crct->vec != NULL && 294100616Smp !Strcmp(*(crct->vec), STRcomplete)) { 29559243Sobrien if (LastChar > InputBuf && LastChar[-1] == '\n') { 29659243Sobrien LastChar[-1] = '\0'; 29759243Sobrien LastChar--; 29859243Sobrien Cursor = LastChar; 29959243Sobrien } 30059243Sobrien match_unique_match = 1; /* match unique matches */ 30159243Sobrien matchval = CompleteLine(); 30259243Sobrien match_unique_match = 0; 30359243Sobrien curlen = (int) (LastChar - InputBuf); 30459243Sobrien if (matchval != 1) { 30559243Sobrien PastBottom(); 30659243Sobrien } 30759243Sobrien if (matchval == 0) { 308195609Smp xprintf("%s", CGETS(6, 6, "No matching command\n")); 30959243Sobrien } else if (matchval == 2) { 310195609Smp xprintf("%s", CGETS(6, 7, "Ambiguous command\n")); 31159243Sobrien } 31259243Sobrien if (NeedsRedraw) { 31359243Sobrien ClearLines(); 31459243Sobrien ClearDisp(); 31559243Sobrien NeedsRedraw = 0; 31659243Sobrien } 31759243Sobrien Refresh(); 31859243Sobrien Argument = 1; 31959243Sobrien DoingArg = 0; 32059243Sobrien if (matchval == 1) { 32159243Sobrien PastBottom(); 32259243Sobrien *LastChar++ = '\n'; 32359243Sobrien *LastChar = '\0'; 32459243Sobrien } 32559243Sobrien curlen = (int) (LastChar - InputBuf); 32659243Sobrien } 32759243Sobrien else 32859243Sobrien PastBottom(); 32959243Sobrien 33059243Sobrien if (matchval == 1) { 33159243Sobrien tellwhat = 0; /* just in case */ 33259243Sobrien Hist_num = 0; /* for the history commands */ 33359243Sobrien /* return the number of chars read */ 33459243Sobrien num = (int) (LastChar - InputBuf); 33559243Sobrien /* 33659243Sobrien * For continuation lines, we set the prompt to prompt 2 33759243Sobrien */ 33859243Sobrien printprompt(1, NULL); 33959243Sobrien } 34059243Sobrien break; 34159243Sobrien 34259243Sobrien case CC_CORRECT: 34359243Sobrien if (tenematch(InputBuf, Cursor - InputBuf, SPELL) < 0) 34459243Sobrien SoundBeep(); /* Beep = No match/ambiguous */ 34559243Sobrien curlen = Repair(); 34659243Sobrien break; 34759243Sobrien 34859243Sobrien case CC_CORRECT_L: 34959243Sobrien if (SpellLine(FALSE) < 0) 35059243Sobrien SoundBeep(); /* Beep = No match/ambiguous */ 35159243Sobrien curlen = Repair(); 35259243Sobrien break; 35359243Sobrien 35459243Sobrien 35559243Sobrien case CC_COMPLETE: 35659243Sobrien case CC_COMPLETE_ALL: 35759243Sobrien case CC_COMPLETE_FWD: 35859243Sobrien case CC_COMPLETE_BACK: 35959243Sobrien switch (retval) { 36059243Sobrien case CC_COMPLETE: 36159243Sobrien fn = RECOGNIZE; 36259243Sobrien curlen = (int) (LastChar - InputBuf); 36359243Sobrien curchoice = -1; 36459243Sobrien rotate = 0; 36559243Sobrien break; 36659243Sobrien case CC_COMPLETE_ALL: 36759243Sobrien fn = RECOGNIZE_ALL; 36859243Sobrien curlen = (int) (LastChar - InputBuf); 36959243Sobrien curchoice = -1; 37059243Sobrien rotate = 0; 37159243Sobrien break; 37259243Sobrien case CC_COMPLETE_FWD: 37359243Sobrien fn = RECOGNIZE_SCROLL; 37459243Sobrien curchoice++; 37559243Sobrien rotate = 1; 37659243Sobrien break; 37759243Sobrien case CC_COMPLETE_BACK: 37859243Sobrien fn = RECOGNIZE_SCROLL; 37959243Sobrien curchoice--; 38059243Sobrien rotate = 1; 38159243Sobrien break; 38259243Sobrien default: 38359243Sobrien abort(); 38459243Sobrien } 38559243Sobrien if (InputBuf[curlen] && rotate) { 38659243Sobrien newlen = (int) (LastChar - InputBuf); 38759243Sobrien for (idx = (int) (Cursor - InputBuf); 38859243Sobrien idx <= newlen; idx++) 38959243Sobrien InputBuf[idx - newlen + curlen] = 39059243Sobrien InputBuf[idx]; 39159243Sobrien LastChar = InputBuf + curlen; 39259243Sobrien Cursor = Cursor - newlen + curlen; 39359243Sobrien } 39459243Sobrien curlen = (int) (LastChar - InputBuf); 39559243Sobrien 39659243Sobrien 397195609Smp nr_history_exp = 0; 398195609Smp autoexpand = varval(STRautoexpand); 399195609Smp if (autoexpand != STRNULL) 400195609Smp nr_history_exp += ExpandHistory(); 401195609Smp 402195609Smp /* try normal expansion only if no history references were found */ 403195609Smp if (nr_history_exp == 0 || 404195609Smp Strcmp(autoexpand, STRonlyhistory) != 0) { 405195609Smp /* 406195609Smp * Modified by Martin Boyer (gamin@ireq-robot.hydro.qc.ca): 407195609Smp * A separate variable now controls beeping after 408195609Smp * completion, independently of autolisting. 409195609Smp */ 410195609Smp expnum = (int) (Cursor - InputBuf); 411195609Smp switch (matchval = tenematch(InputBuf, Cursor-InputBuf, fn)){ 412195609Smp case 1: 413195609Smp if (non_unique_match && matchbeep && 414195609Smp matchbeep->vec != NULL && 415195609Smp (Strcmp(*(matchbeep->vec), STRnotunique) == 0)) 41659243Sobrien SoundBeep(); 41759243Sobrien break; 418195609Smp case 0: 419195609Smp if (matchbeep && matchbeep->vec != NULL) { 420195609Smp if (Strcmp(*(matchbeep->vec), STRnomatch) == 0 || 421195609Smp Strcmp(*(matchbeep->vec), STRambiguous) == 0 || 422195609Smp Strcmp(*(matchbeep->vec), STRnotunique) == 0) 423195609Smp SoundBeep(); 424195609Smp } 425195609Smp else 42659243Sobrien SoundBeep(); 427195609Smp break; 428195609Smp default: 429195609Smp if (matchval < 0) { /* Error from tenematch */ 430195609Smp curchoice = -1; 431195609Smp SoundBeep(); 432195609Smp break; 433167465Smp } 434195609Smp if (matchbeep && matchbeep->vec != NULL) { 435195609Smp if ((Strcmp(*(matchbeep->vec), STRambiguous) == 0 || 436195609Smp Strcmp(*(matchbeep->vec), STRnotunique) == 0)) 437195609Smp SoundBeep(); 438195609Smp } 439195609Smp else 440195609Smp SoundBeep(); 441195609Smp /* 442195609Smp * Addition by David C Lawrence <tale@pawl.rpi.edu>: If an 443195609Smp * attempted completion is ambiguous, list the choices. 444195609Smp * (PWP: this is the best feature addition to tcsh I have 445195609Smp * seen in many months.) 446195609Smp */ 447195609Smp if (autol && autol->vec != NULL && 448195609Smp (Strcmp(*(autol->vec), STRambiguous) != 0 || 449195609Smp expnum == Cursor - InputBuf)) { 450195609Smp if (adrof(STRhighlight) && MarkIsSet) { 451195609Smp /* clear highlighting before showing completions */ 452195609Smp MarkIsSet = 0; 453195609Smp ClearLines(); 454195609Smp ClearDisp(); 455195609Smp Refresh(); 456195609Smp MarkIsSet = 1; 457195609Smp } 458195609Smp PastBottom(); 459195609Smp fn = (retval == CC_COMPLETE_ALL) ? LIST_ALL : LIST; 460195609Smp (void) tenematch(InputBuf, Cursor-InputBuf, fn); 461195609Smp } 462195609Smp break; 46359243Sobrien } 46459243Sobrien } 46559243Sobrien if (NeedsRedraw) { 46659243Sobrien PastBottom(); 46759243Sobrien ClearLines(); 46859243Sobrien ClearDisp(); 46959243Sobrien NeedsRedraw = 0; 47059243Sobrien } 47159243Sobrien Refresh(); 47259243Sobrien Argument = 1; 47359243Sobrien DoingArg = 0; 47459243Sobrien break; 47559243Sobrien 47659243Sobrien case CC_LIST_CHOICES: 47759243Sobrien case CC_LIST_ALL: 47859243Sobrien if (InputBuf[curlen] && rotate) { 47959243Sobrien newlen = (int) (LastChar - InputBuf); 48059243Sobrien for (idx = (int) (Cursor - InputBuf); 48159243Sobrien idx <= newlen; idx++) 48259243Sobrien InputBuf[idx - newlen + curlen] = 48359243Sobrien InputBuf[idx]; 48459243Sobrien LastChar = InputBuf + curlen; 48559243Sobrien Cursor = Cursor - newlen + curlen; 48659243Sobrien } 48759243Sobrien curlen = (int) (LastChar - InputBuf); 48859243Sobrien if (curchoice >= 0) 48959243Sobrien curchoice--; 49059243Sobrien 49159243Sobrien fn = (retval == CC_LIST_ALL) ? LIST_ALL : LIST; 49259243Sobrien /* should catch ^C here... */ 49359243Sobrien if (tenematch(InputBuf, Cursor - InputBuf, fn) < 0) 49459243Sobrien SoundBeep(); 49559243Sobrien Refresh(); 49659243Sobrien Argument = 1; 49759243Sobrien DoingArg = 0; 49859243Sobrien break; 49959243Sobrien 50059243Sobrien 50159243Sobrien case CC_LIST_GLOB: 50259243Sobrien if (tenematch(InputBuf, Cursor - InputBuf, GLOB) < 0) 50359243Sobrien SoundBeep(); 50459243Sobrien curlen = Repair(); 50559243Sobrien break; 50659243Sobrien 50759243Sobrien case CC_EXPAND_GLOB: 50859243Sobrien if (tenematch(InputBuf, Cursor - InputBuf, GLOB_EXPAND) <= 0) 50959243Sobrien SoundBeep(); /* Beep = No match */ 51059243Sobrien curlen = Repair(); 51159243Sobrien break; 51259243Sobrien 51359243Sobrien case CC_NORMALIZE_PATH: 51459243Sobrien if (tenematch(InputBuf, Cursor - InputBuf, PATH_NORMALIZE) <= 0) 51559243Sobrien SoundBeep(); /* Beep = No match */ 51659243Sobrien curlen = Repair(); 51759243Sobrien break; 51859243Sobrien 51959243Sobrien case CC_EXPAND_VARS: 52059243Sobrien if (tenematch(InputBuf, Cursor - InputBuf, VARS_EXPAND) <= 0) 52159243Sobrien SoundBeep(); /* Beep = No match */ 52259243Sobrien curlen = Repair(); 52359243Sobrien break; 52459243Sobrien 52559243Sobrien case CC_NORMALIZE_COMMAND: 52659243Sobrien if (tenematch(InputBuf, Cursor - InputBuf, COMMAND_NORMALIZE) <= 0) 52759243Sobrien SoundBeep(); /* Beep = No match */ 52859243Sobrien curlen = Repair(); 52959243Sobrien break; 53059243Sobrien 53159243Sobrien case CC_HELPME: 53259243Sobrien xputchar('\n'); 53359243Sobrien /* should catch ^C here... */ 53459243Sobrien (void) tenematch(InputBuf, LastChar - InputBuf, PRINT_HELP); 53559243Sobrien Refresh(); 53659243Sobrien Argument = 1; 53759243Sobrien DoingArg = 0; 53859243Sobrien curchoice = -1; 53959243Sobrien curlen = (int) (LastChar - InputBuf); 54059243Sobrien break; 54159243Sobrien 54259243Sobrien case CC_FATAL: /* fatal error, reset to known state */ 54359243Sobrien#ifdef DEBUG_EDIT 54459243Sobrien xprintf(CGETS(7, 8, "*** editor fatal ERROR ***\r\n\n")); 54559243Sobrien#endif /* DEBUG_EDIT */ 54659243Sobrien /* put (real) cursor in a known place */ 54759243Sobrien ClearDisp(); /* reset the display stuff */ 54859243Sobrien ResetInLine(1); /* reset the input pointers */ 54959243Sobrien Refresh(); /* print the prompt again */ 55059243Sobrien Argument = 1; 55159243Sobrien DoingArg = 0; 55259243Sobrien curchoice = -1; 55359243Sobrien curlen = (int) (LastChar - InputBuf); 55459243Sobrien break; 55559243Sobrien 55659243Sobrien case CC_ERROR: 55759243Sobrien default: /* functions we don't know about */ 558167465Smp if (adrof(STRhighlight)) { 559167465Smp ClearLines(); 560167465Smp ClearDisp(); 561167465Smp Refresh(); 562167465Smp } 56359243Sobrien DoingArg = 0; 56459243Sobrien Argument = 1; 56559243Sobrien SoundBeep(); 56659243Sobrien flush(); 56759243Sobrien curchoice = -1; 56859243Sobrien curlen = (int) (LastChar - InputBuf); 56959243Sobrien break; 57059243Sobrien } 57159243Sobrien } 57259243Sobrien (void) Cookedmode(); /* make sure the tty is set up correctly */ 57359243Sobrien GettingInput = 0; 57459243Sobrien flush(); /* flush any buffered output */ 57559243Sobrien return num; 57659243Sobrien} 57759243Sobrien 57859243Sobrienvoid 579167465SmpPushMacro(Char *str) 58059243Sobrien{ 58159243Sobrien if (str != NULL && MacroLvl + 1 < MAXMACROLEVELS) { 58259243Sobrien MacroLvl++; 58359243Sobrien KeyMacro[MacroLvl] = str; 58459243Sobrien } 58559243Sobrien else { 58659243Sobrien SoundBeep(); 58759243Sobrien flush(); 58859243Sobrien } 58959243Sobrien} 59059243Sobrien 591167465Smpstruct eval1_state 592167465Smp{ 593167465Smp Char **evalvec, *evalp; 594167465Smp}; 595167465Smp 596167465Smpstatic void 597167465Smpeval1_cleanup(void *xstate) 598167465Smp{ 599167465Smp struct eval1_state *state; 600167465Smp 601167465Smp state = xstate; 602167465Smp evalvec = state->evalvec; 603167465Smp evalp = state->evalp; 604167465Smp doneinp = 0; 605167465Smp} 606167465Smp 60759243Sobrien/* 60859243Sobrien * Like eval, only using the current file descriptors 60959243Sobrien */ 61059243Sobrienstatic void 611167465Smpdoeval1(Char **v) 61259243Sobrien{ 613167465Smp struct eval1_state state; 614167465Smp Char **gv; 615167465Smp int gflag; 61659243Sobrien 617167465Smp gflag = tglob(v); 61859243Sobrien if (gflag) { 619167465Smp gv = v = globall(v, gflag); 620167465Smp if (v == 0) 62159243Sobrien stderror(ERR_NOMATCH); 622167465Smp v = copyblk(v); 62359243Sobrien } 62459243Sobrien else { 62559243Sobrien gv = NULL; 626167465Smp v = copyblk(v); 627167465Smp trim(v); 62859243Sobrien } 629167465Smp if (gv) 630167465Smp cleanup_push(gv, blk_cleanup); 63159243Sobrien 632167465Smp state.evalvec = evalvec; 633167465Smp state.evalp = evalp; 634167465Smp evalvec = v; 635167465Smp evalp = 0; 636167465Smp cleanup_push(&state, eval1_cleanup); 637167465Smp process(0); 638167465Smp cleanup_until(&state); 63959243Sobrien if (gv) 640167465Smp cleanup_until(gv); 64159243Sobrien} 64259243Sobrien 64359243Sobrienstatic void 644167465SmpRunCommand(Char *str) 64559243Sobrien{ 64659243Sobrien Char *cmd[2]; 64759243Sobrien 64859243Sobrien xputchar('\n'); /* Start on a clean line */ 64959243Sobrien 65059243Sobrien cmd[0] = str; 65159243Sobrien cmd[1] = NULL; 65259243Sobrien 65359243Sobrien (void) Cookedmode(); 65459243Sobrien GettingInput = 0; 65559243Sobrien 65659243Sobrien doeval1(cmd); 657167465Smp 65859243Sobrien (void) Rawmode(); 65959243Sobrien GettingInput = 1; 66059243Sobrien 66159243Sobrien ClearLines(); 66259243Sobrien ClearDisp(); 66359243Sobrien NeedsRedraw = 0; 66459243Sobrien Refresh(); 66559243Sobrien} 66659243Sobrien 667354195Sbrooksint 668354195SbrooksGetCmdChar(Char ch) 669354195Sbrooks{ 670354195Sbrooks#ifndef WINNT_NATIVE // We use more than 256 for various extended keys 671354195Sbrooks wint_t c = ch & CHAR; 672354195Sbrooks#else 673354195Sbrooks wint_t c = ch; 674354195Sbrooks#endif 675354195Sbrooks return c < NT_NUM_KEYS ? CurrentKeyMap[c] : F_INSERT; 676354195Sbrooks} 677354195Sbrooks 67859243Sobrienstatic int 679167465SmpGetNextCommand(KEYCMD *cmdnum, Char *ch) 68059243Sobrien{ 68159243Sobrien KEYCMD cmd = 0; 68259243Sobrien int num; 68359243Sobrien 68459243Sobrien while (cmd == 0 || cmd == F_XKEY) { 68559243Sobrien if ((num = GetNextChar(ch)) != 1) { /* if EOF or error */ 68659243Sobrien return num; 68759243Sobrien } 68859243Sobrien#ifdef KANJI 68961519Sobrien if ( 69061519Sobrien#ifdef DSPMBYTE 69161519Sobrien _enable_mbdisp && 692145479Smp#else 693316957Sdchagin MB_LEN_MAX == 1 && 69461519Sobrien#endif 69561519Sobrien !adrof(STRnokanji) && (*ch & META)) { 69659243Sobrien MetaNext = 0; 69759243Sobrien cmd = F_INSERT; 69859243Sobrien break; 69959243Sobrien } 70059243Sobrien else 70159243Sobrien#endif /* KANJI */ 70259243Sobrien if (MetaNext) { 70359243Sobrien MetaNext = 0; 70459243Sobrien *ch |= META; 70559243Sobrien } 706354195Sbrooks 707354195Sbrooks cmd = GetCmdChar(*ch); 70859243Sobrien if (cmd == F_XKEY) { 70959243Sobrien XmapVal val; 71059243Sobrien CStr cstr; 71159243Sobrien cstr.buf = ch; 712167465Smp cstr.len = 1; 71359243Sobrien switch (GetXkey(&cstr, &val)) { 71459243Sobrien case XK_CMD: 71559243Sobrien cmd = val.cmd; 71659243Sobrien break; 71759243Sobrien case XK_STR: 71859243Sobrien PushMacro(val.str.buf); 71959243Sobrien break; 72059243Sobrien case XK_EXE: 72159243Sobrien RunCommand(val.str.buf); 72259243Sobrien break; 72359243Sobrien default: 72459243Sobrien abort(); 72559243Sobrien break; 72659243Sobrien } 72759243Sobrien } 72859243Sobrien if (!AltKeyMap) 72959243Sobrien CurrentKeyMap = CcKeyMap; 73059243Sobrien } 73159243Sobrien *cmdnum = cmd; 73259243Sobrien return OKCMD; 73359243Sobrien} 73459243Sobrien 735145479Smpstatic Char ungetchar; 736145479Smpstatic int haveungetchar; 737145479Smp 738145479Smpvoid 739145479SmpUngetNextChar(Char cp) 740145479Smp{ 741145479Smp ungetchar = cp; 742145479Smp haveungetchar = 1; 743145479Smp} 744145479Smp 74559243Sobrienint 746167465SmpGetNextChar(Char *cp) 74759243Sobrien{ 748145479Smp int num_read; 74959243Sobrien int tried = 0; 750145479Smp char cbuf[MB_LEN_MAX]; 751145479Smp size_t cbp; 75259243Sobrien 753145479Smp if (haveungetchar) { 754145479Smp haveungetchar = 0; 755145479Smp *cp = ungetchar; 756145479Smp return 1; 757145479Smp } 75859243Sobrien for (;;) { 75959243Sobrien if (MacroLvl < 0) { 76059243Sobrien if (!Load_input_line()) 76159243Sobrien break; 76259243Sobrien } 76359243Sobrien if (*KeyMacro[MacroLvl] == 0) { 76459243Sobrien MacroLvl--; 76559243Sobrien continue; 76659243Sobrien } 76759243Sobrien *cp = *KeyMacro[MacroLvl]++ & CHAR; 76859243Sobrien if (*KeyMacro[MacroLvl] == 0) { /* Needed for QuoteMode On */ 76959243Sobrien MacroLvl--; 77059243Sobrien } 77159243Sobrien return (1); 77259243Sobrien } 77359243Sobrien 77459243Sobrien if (Rawmode() < 0) /* make sure the tty is set up correctly */ 77559243Sobrien return 0; /* oops: SHIN was closed */ 77659243Sobrien 77769408Sache#ifdef WINNT_NATIVE 77859243Sobrien __nt_want_vcode = 1; 77969408Sache#endif /* WINNT_NATIVE */ 780145479Smp#ifdef SIG_WINDOW 781145479Smp if (windowchg) 782145479Smp (void) check_window_size(0); /* for window systems */ 783145479Smp#endif /* SIG_WINDOW */ 784145479Smp cbp = 0; 785145479Smp for (;;) { 786167465Smp while ((num_read = xread(SHIN, cbuf + cbp, 1)) == -1) { 787145479Smp if (!tried && fixio(SHIN, errno) != -1) 788145479Smp tried = 1; 789145479Smp else { 790145479Smp# ifdef convex 791145479Smp /* need to print error message in case the file is migrated */ 792167465Smp stderror(ERR_SYSTEM, progname, strerror(errno)); 793145479Smp# endif /* convex */ 794145479Smp# ifdef WINNT_NATIVE 795145479Smp __nt_want_vcode = 0; 796145479Smp# endif /* WINNT_NATIVE */ 797145479Smp *cp = '\0'; /* Loses possible partial character */ 798145479Smp return -1; 799145479Smp } 80059243Sobrien } 801354195Sbrooks if (cbp == 0 /* && *cbuf < NT_NUM_KEYS */ 802354195Sbrooks && CurrentKeyMap[(unsigned char)*cbuf] == F_XKEY) { 803354195Sbrooks *cp = (unsigned char)*cbuf; 804354195Sbrooks } else { 805354195Sbrooks cbp++; 806354195Sbrooks if (normal_mbtowc(cp, cbuf, cbp) == -1) { 807354195Sbrooks reset_mbtowc(); 808354195Sbrooks if (cbp < MB_CUR_MAX) 809354195Sbrooks continue; /* Maybe a partial character */ 810354195Sbrooks /* And drop the following bytes, if any */ 811354195Sbrooks *cp = (unsigned char)*cbuf | INVALID_BYTE; 812354195Sbrooks } 813145479Smp } 814145479Smp break; 81559243Sobrien } 81669408Sache#ifdef WINNT_NATIVE 817145479Smp /* This is the part that doesn't work with WIDE_STRINGS */ 81859243Sobrien if (__nt_want_vcode == 2) 81959243Sobrien *cp = __nt_vcode; 82059243Sobrien __nt_want_vcode = 0; 82169408Sache#endif /* WINNT_NATIVE */ 82259243Sobrien return num_read; 82359243Sobrien} 82459243Sobrien 82559243Sobrien/* 82659243Sobrien * SpellLine - do spelling correction on the entire command line 82759243Sobrien * (which may have trailing newline). 82859243Sobrien * If cmdonly is set, only check spelling of command words. 82959243Sobrien * Return value: 83059243Sobrien * -1: Something was incorrectible, and nothing was corrected 83159243Sobrien * 0: Everything was correct 83259243Sobrien * 1: Something was corrected 83359243Sobrien */ 83459243Sobrienstatic int 835167465SmpSpellLine(int cmdonly) 83659243Sobrien{ 83759243Sobrien int endflag, matchval; 83859243Sobrien Char *argptr, *OldCursor, *OldLastChar; 83959243Sobrien 84059243Sobrien OldLastChar = LastChar; 84159243Sobrien OldCursor = Cursor; 84259243Sobrien argptr = InputBuf; 84359243Sobrien endflag = 1; 84459243Sobrien matchval = 0; 84559243Sobrien do { 84659243Sobrien while (ismetahash(*argptr) || iscmdmeta(*argptr)) 84759243Sobrien argptr++; 84859243Sobrien for (Cursor = argptr; 84959243Sobrien *Cursor != '\0' && ((Cursor != argptr && Cursor[-1] == '\\') || 85059243Sobrien (!ismetahash(*Cursor) && !iscmdmeta(*Cursor))); 85159243Sobrien Cursor++) 85259243Sobrien continue; 85359243Sobrien if (*Cursor == '\0') { 85459243Sobrien Cursor = LastChar; 85559243Sobrien if (LastChar[-1] == '\n') 85659243Sobrien Cursor--; 85759243Sobrien endflag = 0; 85859243Sobrien } 859195609Smp if (!MISMATCH(*argptr) && 86059243Sobrien (!cmdonly || starting_a_command(argptr, InputBuf))) { 86169408Sache#ifdef WINNT_NATIVE 86259243Sobrien /* 86359243Sobrien * This hack avoids correcting drive letter changes 86459243Sobrien */ 86559243Sobrien if((Cursor - InputBuf) != 2 || (char)InputBuf[1] != ':') 86669408Sache#endif /* WINNT_NATIVE */ 86759243Sobrien { 86859243Sobrien#ifdef HASH_SPELL_CHECK 86959243Sobrien Char save; 87059243Sobrien size_t len = Cursor - InputBuf; 87159243Sobrien 87259243Sobrien save = InputBuf[len]; 87359243Sobrien InputBuf[len] = '\0'; 87459243Sobrien if (find_cmd(InputBuf, 0) != 0) { 87559243Sobrien InputBuf[len] = save; 87659243Sobrien argptr = Cursor; 87759243Sobrien continue; 87859243Sobrien } 87959243Sobrien InputBuf[len] = save; 88059243Sobrien#endif /* HASH_SPELL_CHECK */ 88159243Sobrien switch (tenematch(InputBuf, Cursor - InputBuf, SPELL)) { 88259243Sobrien case 1: /* corrected */ 88359243Sobrien matchval = 1; 88459243Sobrien break; 88559243Sobrien case -1: /* couldn't be corrected */ 88659243Sobrien if (!matchval) 88759243Sobrien matchval = -1; 88859243Sobrien break; 88959243Sobrien default: /* was correct */ 89059243Sobrien break; 89159243Sobrien } 89259243Sobrien } 89359243Sobrien if (LastChar != OldLastChar) { 89459243Sobrien if (argptr < OldCursor) 89559243Sobrien OldCursor += (LastChar - OldLastChar); 89659243Sobrien OldLastChar = LastChar; 89759243Sobrien } 89859243Sobrien } 89959243Sobrien argptr = Cursor; 90059243Sobrien } while (endflag); 90159243Sobrien Cursor = OldCursor; 90259243Sobrien return matchval; 90359243Sobrien} 90459243Sobrien 90559243Sobrien/* 90659243Sobrien * CompleteLine - do command completion on the entire command line 90759243Sobrien * (which may have trailing newline). 90859243Sobrien * Return value: 90959243Sobrien * 0: No command matched or failure 91059243Sobrien * 1: One command matched 91159243Sobrien * 2: Several commands matched 91259243Sobrien */ 91359243Sobrienstatic int 914167465SmpCompleteLine(void) 91559243Sobrien{ 91659243Sobrien int endflag, tmatch; 91759243Sobrien Char *argptr, *OldCursor, *OldLastChar; 91859243Sobrien 91959243Sobrien OldLastChar = LastChar; 92059243Sobrien OldCursor = Cursor; 92159243Sobrien argptr = InputBuf; 92259243Sobrien endflag = 1; 92359243Sobrien do { 92459243Sobrien while (ismetahash(*argptr) || iscmdmeta(*argptr)) 92559243Sobrien argptr++; 92659243Sobrien for (Cursor = argptr; 92759243Sobrien *Cursor != '\0' && ((Cursor != argptr && Cursor[-1] == '\\') || 92859243Sobrien (!ismetahash(*Cursor) && !iscmdmeta(*Cursor))); 92959243Sobrien Cursor++) 93059243Sobrien continue; 93159243Sobrien if (*Cursor == '\0') { 93259243Sobrien Cursor = LastChar; 93359243Sobrien if (LastChar[-1] == '\n') 93459243Sobrien Cursor--; 93559243Sobrien endflag = 0; 93659243Sobrien } 937195609Smp if (!MISMATCH(*argptr) && starting_a_command(argptr, InputBuf)) { 93859243Sobrien tmatch = tenematch(InputBuf, Cursor - InputBuf, RECOGNIZE); 93959243Sobrien if (tmatch <= 0) { 94059243Sobrien return 0; 94159243Sobrien } else if (tmatch > 1) { 94259243Sobrien return 2; 94359243Sobrien } 94459243Sobrien if (LastChar != OldLastChar) { 94559243Sobrien if (argptr < OldCursor) 94659243Sobrien OldCursor += (LastChar - OldLastChar); 94759243Sobrien OldLastChar = LastChar; 94859243Sobrien } 94959243Sobrien } 95059243Sobrien argptr = Cursor; 95159243Sobrien } while (endflag); 95259243Sobrien Cursor = OldCursor; 95359243Sobrien return 1; 95459243Sobrien} 95559243Sobrien 956