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