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