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