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