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