1 /* $Header: /src/pub/tcsh/ed.inputl.c,v 3.51 2002/06/25 19:02:11 christos Exp $ */ 2 /* 3 * ed.inputl.c: Input line handling. 4 */ 5 /*- 6 * Copyright (c) 1980, 1991 The Regents of the University of California. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 #include "sh.h" 34 35 RCSID("$Id: ed.inputl.c,v 3.51 2002/06/25 19:02:11 christos Exp $") 36 37 #include "ed.h" 38 #include "ed.defns.h" /* for the function names */ 39 #include "tw.h" /* for twenex stuff */ 40 41 #define OKCMD (INBUFSIZE+INBUFSIZE) 42 43 /* ed.inputl -- routines to get a single line from the input. */ 44 45 extern bool tellwhat; 46 extern bool MapsAreInited; 47 extern bool Tty_raw_mode; 48 49 /* mismatched first character */ 50 static Char mismatch[] = 51 {'!', '^' , '\\', '-', '%', '\0', '"', '\'', '`', '\0' }; 52 53 static int Repair __P((void)); 54 static int GetNextCommand __P((KEYCMD *, Char *)); 55 static int SpellLine __P((int)); 56 static int CompleteLine __P((void)); 57 static void RunCommand __P((Char *)); 58 static void doeval1 __P((Char **)); 59 60 static bool rotate = 0; 61 62 63 static int 64 Repair() 65 { 66 if (NeedsRedraw) { 67 ClearLines(); 68 ClearDisp(); 69 NeedsRedraw = 0; 70 } 71 Refresh(); 72 Argument = 1; 73 DoingArg = 0; 74 curchoice = -1; 75 return (int) (LastChar - InputBuf); 76 } 77 78 /* CCRETVAL */ 79 int 80 Inputl() 81 { 82 CCRETVAL retval; 83 KEYCMD cmdnum = 0; 84 extern KEYCMD NumFuns; 85 unsigned char tch; /* the place where read() goes */ 86 Char ch; 87 int num; /* how many chars we have read at NL */ 88 int expnum; 89 struct varent *crct = inheredoc ? NULL : adrof(STRcorrect); 90 struct varent *autol = adrof(STRautolist); 91 struct varent *matchbeep = adrof(STRmatchbeep); 92 struct varent *imode = adrof(STRinputmode); 93 Char *SaveChar, *CorrChar; 94 Char Origin[INBUFSIZE], Change[INBUFSIZE]; 95 int matchval; /* from tenematch() */ 96 COMMAND fn; 97 int curlen = 0; 98 int newlen; 99 int idx; 100 101 if (!MapsAreInited) /* double extra just in case */ 102 ed_InitMaps(); 103 104 ClearDisp(); /* reset the display stuff */ 105 ResetInLine(0); /* reset the input pointers */ 106 if (GettingInput) 107 MacroLvl = -1; /* editor was interrupted during input */ 108 109 if (imode && imode->vec != NULL) { 110 if (!Strcmp(*(imode->vec), STRinsert)) 111 inputmode = MODE_INSERT; 112 else if (!Strcmp(*(imode->vec), STRoverwrite)) 113 inputmode = MODE_REPLACE; 114 } 115 116 #if defined(FIONREAD) && !defined(OREO) 117 if (!Tty_raw_mode && MacroLvl < 0) { 118 # ifdef SUNOS4 119 long chrs = 0; 120 # else /* !SUNOS4 */ 121 /* 122 * *Everyone* else has an int, but SunOS wants long! 123 * This breaks where int != long (alpha) 124 */ 125 int chrs = 0; 126 # endif /* SUNOS4 */ 127 128 (void) ioctl(SHIN, FIONREAD, (ioctl_t) & chrs); 129 if (chrs == 0) { 130 if (Rawmode() < 0) 131 return 0; 132 } 133 } 134 #endif /* FIONREAD && !OREO */ 135 136 GettingInput = 1; 137 NeedsRedraw = 0; 138 139 if (tellwhat) { 140 copyn(InputBuf, WhichBuf, INBUFSIZE); 141 LastChar = InputBuf + (LastWhich - WhichBuf); 142 Cursor = InputBuf + (CursWhich - WhichBuf); 143 tellwhat = 0; 144 Hist_num = HistWhich; 145 } 146 if (Expand) { 147 (void) e_up_hist(0); 148 Expand = 0; 149 } 150 Refresh(); /* print the prompt */ 151 152 for (num = OKCMD; num == OKCMD;) { /* while still editing this line */ 153 #ifdef DEBUG_EDIT 154 if (Cursor > LastChar) 155 xprintf("Cursor > LastChar\r\n"); 156 if (Cursor < InputBuf) 157 xprintf("Cursor < InputBuf\r\n"); 158 if (Cursor > InputLim) 159 xprintf("Cursor > InputLim\r\n"); 160 if (LastChar > InputLim) 161 xprintf("LastChar > InputLim\r\n"); 162 if (InputLim != &InputBuf[INBUFSIZE - 2]) 163 xprintf("InputLim != &InputBuf[INBUFSIZE-2]\r\n"); 164 if ((!DoingArg) && (Argument != 1)) 165 xprintf("(!DoingArg) && (Argument != 1)\r\n"); 166 if (CcKeyMap[0] == 0) 167 xprintf("CcKeyMap[0] == 0 (maybe not inited)\r\n"); 168 #endif 169 170 /* if EOF or error */ 171 if ((num = GetNextCommand(&cmdnum, &ch)) != OKCMD) { 172 break; 173 } 174 175 if (cmdnum >= NumFuns) {/* BUG CHECK command */ 176 #ifdef DEBUG_EDIT 177 xprintf(CGETS(6, 1, "ERROR: illegal command from key 0%o\r\n"), ch); 178 #endif 179 continue; /* try again */ 180 } 181 182 /* now do the real command */ 183 retval = (*CcFuncTbl[cmdnum]) (ch); 184 185 /* save the last command here */ 186 LastCmd = cmdnum; 187 188 /* make sure fn is initialized */ 189 fn = (retval == CC_COMPLETE_ALL) ? LIST_ALL : LIST; 190 191 /* use any return value */ 192 switch (retval) { 193 194 case CC_REFRESH: 195 Refresh(); 196 /*FALLTHROUGH*/ 197 case CC_NORM: /* normal char */ 198 Argument = 1; 199 DoingArg = 0; 200 /*FALLTHROUGH*/ 201 case CC_ARGHACK: /* Suggested by Rich Salz */ 202 /* <rsalz@pineapple.bbn.com> */ 203 curchoice = -1; 204 curlen = (int) (LastChar - InputBuf); 205 break; /* keep going... */ 206 207 case CC_EOF: /* end of file typed */ 208 curchoice = -1; 209 curlen = (int) (LastChar - InputBuf); 210 num = 0; 211 break; 212 213 case CC_WHICH: /* tell what this command does */ 214 tellwhat = 1; 215 copyn(WhichBuf, InputBuf, INBUFSIZE); 216 LastWhich = WhichBuf + (LastChar - InputBuf); 217 CursWhich = WhichBuf + (Cursor - InputBuf); 218 *LastChar++ = '\n'; /* for the benifit of CSH */ 219 HistWhich = Hist_num; 220 Hist_num = 0; /* for the history commands */ 221 num = (int) (LastChar - InputBuf); /* number characters read */ 222 break; 223 224 case CC_NEWLINE: /* normal end of line */ 225 curlen = 0; 226 curchoice = -1; 227 matchval = 1; 228 if (crct && crct->vec != NULL && (!Strcmp(*(crct->vec), STRcmd) || 229 !Strcmp(*(crct->vec), STRall))) { 230 PastBottom(); 231 copyn(Origin, InputBuf, INBUFSIZE); 232 SaveChar = LastChar; 233 if (SpellLine(!Strcmp(*(crct->vec), STRcmd)) == 1) { 234 PastBottom(); 235 copyn(Change, InputBuf, INBUFSIZE); 236 *Strchr(Change, '\n') = '\0'; 237 CorrChar = LastChar; /* Save the corrected end */ 238 LastChar = InputBuf; /* Null the current line */ 239 SoundBeep(); 240 printprompt(2, short2str(Change)); 241 Refresh(); 242 if (read(SHIN, (char *) &tch, 1) < 0) 243 #ifdef convex 244 /* 245 * need to print error message in case file 246 * is migrated 247 */ 248 if (errno && errno != EINTR) 249 stderror(ERR_SYSTEM, progname, strerror(errno)); 250 #else 251 break; 252 #endif 253 ch = tch; 254 if (ch == 'y' || ch == ' ') { 255 LastChar = CorrChar; /* Restore the corrected end */ 256 xprintf(CGETS(6, 2, "yes\n")); 257 } 258 else { 259 copyn(InputBuf, Origin, INBUFSIZE); 260 LastChar = SaveChar; 261 if (ch == 'e') { 262 xprintf(CGETS(6, 3, "edit\n")); 263 *LastChar-- = '\0'; 264 Cursor = LastChar; 265 printprompt(3, NULL); 266 ClearLines(); 267 ClearDisp(); 268 Refresh(); 269 break; 270 } 271 else if (ch == 'a') { 272 xprintf(CGETS(6, 4, "abort\n")); 273 LastChar = InputBuf; /* Null the current line */ 274 Cursor = LastChar; 275 printprompt(0, NULL); 276 Refresh(); 277 break; 278 } 279 xprintf(CGETS(6, 5, "no\n")); 280 } 281 flush(); 282 } 283 } else if (crct && crct->vec != NULL && 284 !Strcmp(*(crct->vec), STRcomplete)) { 285 if (LastChar > InputBuf && LastChar[-1] == '\n') { 286 LastChar[-1] = '\0'; 287 LastChar--; 288 Cursor = LastChar; 289 } 290 match_unique_match = 1; /* match unique matches */ 291 matchval = CompleteLine(); 292 match_unique_match = 0; 293 curlen = (int) (LastChar - InputBuf); 294 if (matchval != 1) { 295 PastBottom(); 296 } 297 if (matchval == 0) { 298 xprintf(CGETS(6, 6, "No matching command\n")); 299 } else if (matchval == 2) { 300 xprintf(CGETS(6, 7, "Ambiguous command\n")); 301 } 302 if (NeedsRedraw) { 303 ClearLines(); 304 ClearDisp(); 305 NeedsRedraw = 0; 306 } 307 Refresh(); 308 Argument = 1; 309 DoingArg = 0; 310 if (matchval == 1) { 311 PastBottom(); 312 *LastChar++ = '\n'; 313 *LastChar = '\0'; 314 } 315 curlen = (int) (LastChar - InputBuf); 316 } 317 else 318 PastBottom(); 319 320 if (matchval == 1) { 321 tellwhat = 0; /* just in case */ 322 Hist_num = 0; /* for the history commands */ 323 /* return the number of chars read */ 324 num = (int) (LastChar - InputBuf); 325 /* 326 * For continuation lines, we set the prompt to prompt 2 327 */ 328 printprompt(1, NULL); 329 } 330 break; 331 332 case CC_CORRECT: 333 if (tenematch(InputBuf, Cursor - InputBuf, SPELL) < 0) 334 SoundBeep(); /* Beep = No match/ambiguous */ 335 curlen = Repair(); 336 break; 337 338 case CC_CORRECT_L: 339 if (SpellLine(FALSE) < 0) 340 SoundBeep(); /* Beep = No match/ambiguous */ 341 curlen = Repair(); 342 break; 343 344 345 case CC_COMPLETE: 346 case CC_COMPLETE_ALL: 347 case CC_COMPLETE_FWD: 348 case CC_COMPLETE_BACK: 349 switch (retval) { 350 case CC_COMPLETE: 351 fn = RECOGNIZE; 352 curlen = (int) (LastChar - InputBuf); 353 curchoice = -1; 354 rotate = 0; 355 break; 356 case CC_COMPLETE_ALL: 357 fn = RECOGNIZE_ALL; 358 curlen = (int) (LastChar - InputBuf); 359 curchoice = -1; 360 rotate = 0; 361 break; 362 case CC_COMPLETE_FWD: 363 fn = RECOGNIZE_SCROLL; 364 curchoice++; 365 rotate = 1; 366 break; 367 case CC_COMPLETE_BACK: 368 fn = RECOGNIZE_SCROLL; 369 curchoice--; 370 rotate = 1; 371 break; 372 default: 373 abort(); 374 } 375 if (InputBuf[curlen] && rotate) { 376 newlen = (int) (LastChar - InputBuf); 377 for (idx = (int) (Cursor - InputBuf); 378 idx <= newlen; idx++) 379 InputBuf[idx - newlen + curlen] = 380 InputBuf[idx]; 381 LastChar = InputBuf + curlen; 382 Cursor = Cursor - newlen + curlen; 383 } 384 curlen = (int) (LastChar - InputBuf); 385 386 387 if (adrof(STRautoexpand)) 388 (void) e_expand_history(0); 389 /* 390 * Modified by Martin Boyer (gamin@ireq-robot.hydro.qc.ca): 391 * A separate variable now controls beeping after 392 * completion, independently of autolisting. 393 */ 394 expnum = (int) (Cursor - InputBuf); 395 switch (matchval = tenematch(InputBuf, Cursor-InputBuf, fn)){ 396 case 1: 397 if (non_unique_match && matchbeep && matchbeep->vec != NULL && 398 (Strcmp(*(matchbeep->vec), STRnotunique) == 0)) 399 SoundBeep(); 400 break; 401 case 0: 402 if (matchbeep && matchbeep->vec != NULL) { 403 if (Strcmp(*(matchbeep->vec), STRnomatch) == 0 || 404 Strcmp(*(matchbeep->vec), STRambiguous) == 0 || 405 Strcmp(*(matchbeep->vec), STRnotunique) == 0) 406 SoundBeep(); 407 } 408 else 409 SoundBeep(); 410 break; 411 default: 412 if (matchval < 0) { /* Error from tenematch */ 413 curchoice = -1; 414 SoundBeep(); 415 break; 416 } 417 if (matchbeep && matchbeep->vec != NULL) { 418 if ((Strcmp(*(matchbeep->vec), STRambiguous) == 0 || 419 Strcmp(*(matchbeep->vec), STRnotunique) == 0)) 420 SoundBeep(); 421 } 422 else 423 SoundBeep(); 424 /* 425 * Addition by David C Lawrence <tale@pawl.rpi.edu>: If an 426 * attempted completion is ambiguous, list the choices. 427 * (PWP: this is the best feature addition to tcsh I have 428 * seen in many months.) 429 */ 430 if (autol && autol->vec != NULL && 431 (Strcmp(*(autol->vec), STRambiguous) != 0 || 432 expnum == Cursor - InputBuf)) { 433 PastBottom(); 434 fn = (retval == CC_COMPLETE_ALL) ? LIST_ALL : LIST; 435 (void) tenematch(InputBuf, Cursor-InputBuf, fn); 436 } 437 break; 438 } 439 if (NeedsRedraw) { 440 PastBottom(); 441 ClearLines(); 442 ClearDisp(); 443 NeedsRedraw = 0; 444 } 445 Refresh(); 446 Argument = 1; 447 DoingArg = 0; 448 break; 449 450 case CC_LIST_CHOICES: 451 case CC_LIST_ALL: 452 if (InputBuf[curlen] && rotate) { 453 newlen = (int) (LastChar - InputBuf); 454 for (idx = (int) (Cursor - InputBuf); 455 idx <= newlen; idx++) 456 InputBuf[idx - newlen + curlen] = 457 InputBuf[idx]; 458 LastChar = InputBuf + curlen; 459 Cursor = Cursor - newlen + curlen; 460 } 461 curlen = (int) (LastChar - InputBuf); 462 if (curchoice >= 0) 463 curchoice--; 464 465 fn = (retval == CC_LIST_ALL) ? LIST_ALL : LIST; 466 /* should catch ^C here... */ 467 if (tenematch(InputBuf, Cursor - InputBuf, fn) < 0) 468 SoundBeep(); 469 Refresh(); 470 Argument = 1; 471 DoingArg = 0; 472 break; 473 474 475 case CC_LIST_GLOB: 476 if (tenematch(InputBuf, Cursor - InputBuf, GLOB) < 0) 477 SoundBeep(); 478 curlen = Repair(); 479 break; 480 481 case CC_EXPAND_GLOB: 482 if (tenematch(InputBuf, Cursor - InputBuf, GLOB_EXPAND) <= 0) 483 SoundBeep(); /* Beep = No match */ 484 curlen = Repair(); 485 break; 486 487 case CC_NORMALIZE_PATH: 488 if (tenematch(InputBuf, Cursor - InputBuf, PATH_NORMALIZE) <= 0) 489 SoundBeep(); /* Beep = No match */ 490 curlen = Repair(); 491 break; 492 493 case CC_EXPAND_VARS: 494 if (tenematch(InputBuf, Cursor - InputBuf, VARS_EXPAND) <= 0) 495 SoundBeep(); /* Beep = No match */ 496 curlen = Repair(); 497 break; 498 499 case CC_NORMALIZE_COMMAND: 500 if (tenematch(InputBuf, Cursor - InputBuf, COMMAND_NORMALIZE) <= 0) 501 SoundBeep(); /* Beep = No match */ 502 curlen = Repair(); 503 break; 504 505 case CC_HELPME: 506 xputchar('\n'); 507 /* should catch ^C here... */ 508 (void) tenematch(InputBuf, LastChar - InputBuf, PRINT_HELP); 509 Refresh(); 510 Argument = 1; 511 DoingArg = 0; 512 curchoice = -1; 513 curlen = (int) (LastChar - InputBuf); 514 break; 515 516 case CC_FATAL: /* fatal error, reset to known state */ 517 #ifdef DEBUG_EDIT 518 xprintf(CGETS(7, 8, "*** editor fatal ERROR ***\r\n\n")); 519 #endif /* DEBUG_EDIT */ 520 /* put (real) cursor in a known place */ 521 ClearDisp(); /* reset the display stuff */ 522 ResetInLine(1); /* reset the input pointers */ 523 Refresh(); /* print the prompt again */ 524 Argument = 1; 525 DoingArg = 0; 526 curchoice = -1; 527 curlen = (int) (LastChar - InputBuf); 528 break; 529 530 case CC_ERROR: 531 default: /* functions we don't know about */ 532 DoingArg = 0; 533 Argument = 1; 534 SoundBeep(); 535 flush(); 536 curchoice = -1; 537 curlen = (int) (LastChar - InputBuf); 538 break; 539 } 540 } 541 (void) Cookedmode(); /* make sure the tty is set up correctly */ 542 GettingInput = 0; 543 flush(); /* flush any buffered output */ 544 return num; 545 } 546 547 void 548 PushMacro(str) 549 Char *str; 550 { 551 if (str != NULL && MacroLvl + 1 < MAXMACROLEVELS) { 552 MacroLvl++; 553 KeyMacro[MacroLvl] = str; 554 } 555 else { 556 SoundBeep(); 557 flush(); 558 } 559 } 560 561 /* 562 * Like eval, only using the current file descriptors 563 */ 564 static Char **gv = NULL, **gav = NULL; 565 566 static void 567 doeval1(v) 568 Char **v; 569 { 570 Char **oevalvec; 571 Char *oevalp; 572 int my_reenter; 573 Char **savegv; 574 jmp_buf_t osetexit; 575 576 oevalvec = evalvec; 577 oevalp = evalp; 578 savegv = gv; 579 gav = v; 580 581 582 gflag = 0, tglob(gav); 583 if (gflag) { 584 gv = gav = globall(gav); 585 gargv = 0; 586 if (gav == 0) 587 stderror(ERR_NOMATCH); 588 gav = copyblk(gav); 589 } 590 else { 591 gv = NULL; 592 gav = copyblk(gav); 593 trim(gav); 594 } 595 596 getexit(osetexit); 597 598 /* PWP: setjmp/longjmp bugfix for optimizing compilers */ 599 #ifdef cray 600 my_reenter = 1; /* assume non-zero return val */ 601 if (setexit() == 0) { 602 my_reenter = 0; /* Oh well, we were wrong */ 603 #else /* !cray */ 604 if ((my_reenter = setexit()) == 0) { 605 #endif /* cray */ 606 evalvec = gav; 607 evalp = 0; 608 process(0); 609 } 610 611 evalvec = oevalvec; 612 evalp = oevalp; 613 doneinp = 0; 614 615 if (gv) 616 blkfree(gv); 617 618 gv = savegv; 619 resexit(osetexit); 620 if (my_reenter) 621 stderror(ERR_SILENT); 622 } 623 624 static void 625 RunCommand(str) 626 Char *str; 627 { 628 Char *cmd[2]; 629 630 xputchar('\n'); /* Start on a clean line */ 631 632 cmd[0] = str; 633 cmd[1] = NULL; 634 635 (void) Cookedmode(); 636 GettingInput = 0; 637 638 doeval1(cmd); 639 640 (void) Rawmode(); 641 GettingInput = 1; 642 643 ClearLines(); 644 ClearDisp(); 645 NeedsRedraw = 0; 646 Refresh(); 647 } 648 649 static int 650 GetNextCommand(cmdnum, ch) 651 KEYCMD *cmdnum; 652 register Char *ch; 653 { 654 KEYCMD cmd = 0; 655 int num; 656 657 while (cmd == 0 || cmd == F_XKEY) { 658 if ((num = GetNextChar(ch)) != 1) { /* if EOF or error */ 659 return num; 660 } 661 #ifdef KANJI 662 if ( 663 #ifdef DSPMBYTE 664 _enable_mbdisp && 665 #endif 666 !adrof(STRnokanji) && (*ch & META)) { 667 MetaNext = 0; 668 cmd = F_INSERT; 669 break; 670 } 671 else 672 #endif /* KANJI */ 673 if (MetaNext) { 674 MetaNext = 0; 675 *ch |= META; 676 } 677 /* XXX: This needs to be fixed so that we don't just truncate 678 * the character, we unquote it. 679 */ 680 if (*ch < NT_NUM_KEYS) 681 cmd = CurrentKeyMap[*ch]; 682 else 683 cmd = CurrentKeyMap[(unsigned char) *ch]; 684 if (cmd == F_XKEY) { 685 XmapVal val; 686 CStr cstr; 687 cstr.buf = ch; 688 cstr.len = Strlen(ch); 689 switch (GetXkey(&cstr, &val)) { 690 case XK_CMD: 691 cmd = val.cmd; 692 break; 693 case XK_STR: 694 PushMacro(val.str.buf); 695 break; 696 case XK_EXE: 697 RunCommand(val.str.buf); 698 break; 699 default: 700 abort(); 701 break; 702 } 703 } 704 if (!AltKeyMap) 705 CurrentKeyMap = CcKeyMap; 706 } 707 *cmdnum = cmd; 708 return OKCMD; 709 } 710 711 int 712 GetNextChar(cp) 713 register Char *cp; 714 { 715 register int num_read; 716 int tried = 0; 717 unsigned char tcp; 718 719 for (;;) { 720 if (MacroLvl < 0) { 721 if (!Load_input_line()) 722 break; 723 } 724 if (*KeyMacro[MacroLvl] == 0) { 725 MacroLvl--; 726 continue; 727 } 728 *cp = *KeyMacro[MacroLvl]++ & CHAR; 729 if (*KeyMacro[MacroLvl] == 0) { /* Needed for QuoteMode On */ 730 MacroLvl--; 731 } 732 return (1); 733 } 734 735 if (Rawmode() < 0) /* make sure the tty is set up correctly */ 736 return 0; /* oops: SHIN was closed */ 737 738 #ifdef WINNT_NATIVE 739 __nt_want_vcode = 1; 740 #endif /* WINNT_NATIVE */ 741 while ((num_read = read(SHIN, (char *) &tcp, 1)) == -1) { 742 if (errno == EINTR) 743 continue; 744 if (!tried && fixio(SHIN, errno) != -1) 745 tried = 1; 746 else { 747 #ifdef convex 748 /* need to print error message in case the file is migrated */ 749 if (errno != EINTR) 750 stderror(ERR_SYSTEM, progname, strerror(errno)); 751 #endif /* convex */ 752 #ifdef WINNT_NATIVE 753 __nt_want_vcode = 0; 754 #endif /* WINNT_NATIVE */ 755 *cp = '\0'; 756 return -1; 757 } 758 } 759 #ifdef WINNT_NATIVE 760 if (__nt_want_vcode == 2) 761 *cp = __nt_vcode; 762 else 763 *cp = tcp; 764 __nt_want_vcode = 0; 765 #else 766 *cp = tcp; 767 #endif /* WINNT_NATIVE */ 768 return num_read; 769 } 770 771 /* 772 * SpellLine - do spelling correction on the entire command line 773 * (which may have trailing newline). 774 * If cmdonly is set, only check spelling of command words. 775 * Return value: 776 * -1: Something was incorrectible, and nothing was corrected 777 * 0: Everything was correct 778 * 1: Something was corrected 779 */ 780 static int 781 SpellLine(cmdonly) 782 int cmdonly; 783 { 784 int endflag, matchval; 785 Char *argptr, *OldCursor, *OldLastChar; 786 787 OldLastChar = LastChar; 788 OldCursor = Cursor; 789 argptr = InputBuf; 790 endflag = 1; 791 matchval = 0; 792 do { 793 while (ismetahash(*argptr) || iscmdmeta(*argptr)) 794 argptr++; 795 for (Cursor = argptr; 796 *Cursor != '\0' && ((Cursor != argptr && Cursor[-1] == '\\') || 797 (!ismetahash(*Cursor) && !iscmdmeta(*Cursor))); 798 Cursor++) 799 continue; 800 if (*Cursor == '\0') { 801 Cursor = LastChar; 802 if (LastChar[-1] == '\n') 803 Cursor--; 804 endflag = 0; 805 } 806 /* Obey current history character settings */ 807 mismatch[0] = HIST; 808 mismatch[1] = HISTSUB; 809 if (!Strchr(mismatch, *argptr) && 810 (!cmdonly || starting_a_command(argptr, InputBuf))) { 811 #ifdef WINNT_NATIVE 812 /* 813 * This hack avoids correcting drive letter changes 814 */ 815 if((Cursor - InputBuf) != 2 || (char)InputBuf[1] != ':') 816 #endif /* WINNT_NATIVE */ 817 { 818 #ifdef HASH_SPELL_CHECK 819 Char save; 820 size_t len = Cursor - InputBuf; 821 822 save = InputBuf[len]; 823 InputBuf[len] = '\0'; 824 if (find_cmd(InputBuf, 0) != 0) { 825 InputBuf[len] = save; 826 argptr = Cursor; 827 continue; 828 } 829 InputBuf[len] = save; 830 #endif /* HASH_SPELL_CHECK */ 831 switch (tenematch(InputBuf, Cursor - InputBuf, SPELL)) { 832 case 1: /* corrected */ 833 matchval = 1; 834 break; 835 case -1: /* couldn't be corrected */ 836 if (!matchval) 837 matchval = -1; 838 break; 839 default: /* was correct */ 840 break; 841 } 842 } 843 if (LastChar != OldLastChar) { 844 if (argptr < OldCursor) 845 OldCursor += (LastChar - OldLastChar); 846 OldLastChar = LastChar; 847 } 848 } 849 argptr = Cursor; 850 } while (endflag); 851 Cursor = OldCursor; 852 return matchval; 853 } 854 855 /* 856 * CompleteLine - do command completion on the entire command line 857 * (which may have trailing newline). 858 * Return value: 859 * 0: No command matched or failure 860 * 1: One command matched 861 * 2: Several commands matched 862 */ 863 static int 864 CompleteLine() 865 { 866 int endflag, tmatch; 867 Char *argptr, *OldCursor, *OldLastChar; 868 869 OldLastChar = LastChar; 870 OldCursor = Cursor; 871 argptr = InputBuf; 872 endflag = 1; 873 do { 874 while (ismetahash(*argptr) || iscmdmeta(*argptr)) 875 argptr++; 876 for (Cursor = argptr; 877 *Cursor != '\0' && ((Cursor != argptr && Cursor[-1] == '\\') || 878 (!ismetahash(*Cursor) && !iscmdmeta(*Cursor))); 879 Cursor++) 880 continue; 881 if (*Cursor == '\0') { 882 Cursor = LastChar; 883 if (LastChar[-1] == '\n') 884 Cursor--; 885 endflag = 0; 886 } 887 if (!Strchr(mismatch, *argptr) && starting_a_command(argptr, InputBuf)) { 888 tmatch = tenematch(InputBuf, Cursor - InputBuf, RECOGNIZE); 889 if (tmatch <= 0) { 890 return 0; 891 } else if (tmatch > 1) { 892 return 2; 893 } 894 if (LastChar != OldLastChar) { 895 if (argptr < OldCursor) 896 OldCursor += (LastChar - OldLastChar); 897 OldLastChar = LastChar; 898 } 899 } 900 argptr = Cursor; 901 } while (endflag); 902 Cursor = OldCursor; 903 return 1; 904 } 905 906