Merge commit 'crater/master'
[dragonfly.git] / contrib / tcsh-6 / ed.inputl.c
blob248130a1fec147bc1cb55109a29126aa4479513f
1 /* $Header: /p/tcsh/cvsroot/tcsh/ed.inputl.c,v 3.70 2009/06/25 21:15:37 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.
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.
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.
33 #include "sh.h"
35 RCSID("$tcsh: ed.inputl.c,v 3.70 2009/06/25 21:15:37 christos Exp $")
37 #include "ed.h"
38 #include "ed.defns.h" /* for the function names */
39 #include "tw.h" /* for twenex stuff */
41 #define OKCMD INT_MAX
43 /* ed.inputl -- routines to get a single line from the input. */
45 extern int MapsAreInited;
47 /* mismatched first character */
48 static Char mismatch[] = { '\\', '-', '%', '\0' };
49 /* don't Strchr() for '\0', obey current history character settings */
50 #define MISMATCH(c) ((c) == '\0' || (c) == HIST || (c) == HISTSUB || \
51 Strchr(mismatch, (c)))
53 static int Repair (void);
54 static int GetNextCommand (KEYCMD *, Char *);
55 static int SpellLine (int);
56 static int CompleteLine (void);
57 static void RunCommand (Char *);
58 static void doeval1 (Char **);
60 static int rotate = 0;
63 static int
64 Repair(void)
66 if (NeedsRedraw) {
67 ClearLines();
68 ClearDisp();
69 NeedsRedraw = 0;
71 Refresh();
72 Argument = 1;
73 DoingArg = 0;
74 curchoice = -1;
75 return (int) (LastChar - InputBuf);
78 /* CCRETVAL */
79 int
80 Inputl(void)
82 CCRETVAL retval;
83 KEYCMD cmdnum = 0;
84 unsigned char tch; /* the place where read() goes */
85 Char ch;
86 int num; /* how many chars we have read at NL */
87 int expnum;
88 struct varent *crct = inheredoc ? NULL : adrof(STRcorrect);
89 struct varent *autol = adrof(STRautolist);
90 struct varent *matchbeep = adrof(STRmatchbeep);
91 struct varent *imode = adrof(STRinputmode);
92 Char *SaveChar, *CorrChar;
93 int matchval; /* from tenematch() */
94 int nr_history_exp; /* number of (attempted) history expansions */
95 COMMAND fn;
96 int curlen = 0;
97 int newlen;
98 int idx;
99 Char *autoexpand;
101 if (!MapsAreInited) /* double extra just in case */
102 ed_InitMaps();
104 ClearDisp(); /* reset the display stuff */
105 ResetInLine(0); /* reset the input pointers */
106 if (GettingInput)
107 MacroLvl = -1; /* editor was interrupted during input */
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;
116 #if defined(FIONREAD) && !defined(OREO)
117 if (!Tty_raw_mode && MacroLvl < 0) {
118 # ifdef SUNOS4
119 long chrs = 0;
120 # else /* !SUNOS4 */
122 * *Everyone* else has an int, but SunOS wants long!
123 * This breaks where int != long (alpha)
125 int chrs = 0;
126 # endif /* SUNOS4 */
128 (void) ioctl(SHIN, FIONREAD, (ioctl_t) & chrs);
129 if (chrs == 0) {
130 if (Rawmode() < 0)
131 return 0;
134 #endif /* FIONREAD && !OREO */
136 GettingInput = 1;
137 NeedsRedraw = 0;
138 tellwhat = 0;
140 if (RestoreSaved) {
141 copyn(InputBuf, SavedBuf.s, INBUFSIZE);/*FIXBUF*/
142 LastChar = InputBuf + LastSaved;
143 Cursor = InputBuf + CursSaved;
144 Hist_num = HistSaved;
145 HistSaved = 0;
146 RestoreSaved = 0;
148 if (HistSaved) {
149 Hist_num = HistSaved;
150 GetHistLine();
151 HistSaved = 0;
153 if (Expand) {
154 (void) e_up_hist(0);
155 Expand = 0;
157 Refresh(); /* print the prompt */
159 for (num = OKCMD; num == OKCMD;) { /* while still editing this line */
160 #ifdef DEBUG_EDIT
161 if (Cursor > LastChar)
162 xprintf("Cursor > LastChar\r\n");
163 if (Cursor < InputBuf)
164 xprintf("Cursor < InputBuf\r\n");
165 if (Cursor > InputLim)
166 xprintf("Cursor > InputLim\r\n");
167 if (LastChar > InputLim)
168 xprintf("LastChar > InputLim\r\n");
169 if (InputLim != &InputBuf[INBUFSIZE - 2])/*FIXBUF*/
170 xprintf("InputLim != &InputBuf[INBUFSIZE-2]\r\n");
171 if ((!DoingArg) && (Argument != 1))
172 xprintf("(!DoingArg) && (Argument != 1)\r\n");
173 if (CcKeyMap[0] == 0)
174 xprintf("CcKeyMap[0] == 0 (maybe not inited)\r\n");
175 #endif
177 /* if EOF or error */
178 if ((num = GetNextCommand(&cmdnum, &ch)) != OKCMD) {
179 break;
182 if (cmdnum >= NumFuns) {/* BUG CHECK command */
183 #ifdef DEBUG_EDIT
184 xprintf(CGETS(6, 1, "ERROR: illegal command from key 0%o\r\n"), ch);
185 #endif
186 continue; /* try again */
189 /* now do the real command */
190 retval = (*CcFuncTbl[cmdnum]) (ch);
192 /* save the last command here */
193 LastCmd = cmdnum;
195 /* make sure fn is initialized */
196 fn = (retval == CC_COMPLETE_ALL) ? LIST_ALL : LIST;
198 /* use any return value */
199 switch (retval) {
201 case CC_REFRESH:
202 Refresh();
203 /*FALLTHROUGH*/
204 case CC_NORM: /* normal char */
205 Argument = 1;
206 DoingArg = 0;
207 /*FALLTHROUGH*/
208 case CC_ARGHACK: /* Suggested by Rich Salz */
209 /* <rsalz@pineapple.bbn.com> */
210 curchoice = -1;
211 curlen = (int) (LastChar - InputBuf);
212 break; /* keep going... */
214 case CC_EOF: /* end of file typed */
215 curchoice = -1;
216 curlen = (int) (LastChar - InputBuf);
217 num = 0;
218 break;
220 case CC_WHICH: /* tell what this command does */
221 tellwhat = 1;
222 *LastChar++ = '\n'; /* for the benifit of CSH */
223 num = (int) (LastChar - InputBuf); /* number characters read */
224 break;
226 case CC_NEWLINE: /* normal end of line */
227 curlen = 0;
228 curchoice = -1;
229 matchval = 1;
230 if (crct && crct->vec != NULL && (!Strcmp(*(crct->vec), STRcmd) ||
231 !Strcmp(*(crct->vec), STRall))) {
232 Char *Origin;
234 PastBottom();
235 Origin = Strsave(InputBuf);
236 cleanup_push(Origin, xfree);
237 SaveChar = LastChar;
238 if (SpellLine(!Strcmp(*(crct->vec), STRcmd)) == 1) {
239 Char *Change;
241 PastBottom();
242 Change = Strsave(InputBuf);
243 cleanup_push(Change, xfree);
244 *Strchr(Change, '\n') = '\0';
245 CorrChar = LastChar; /* Save the corrected end */
246 LastChar = InputBuf; /* Null the current line */
247 SoundBeep();
248 printprompt(2, short2str(Change));
249 cleanup_until(Change);
250 Refresh();
251 if (xread(SHIN, &tch, 1) < 0) {
252 #ifdef convex
254 * need to print error message in case file
255 * is migrated
257 if (errno)
258 stderror(ERR_SYSTEM, progname, strerror(errno));
259 #else
260 cleanup_until(Origin);
261 break;
262 #endif
264 ch = tch;
265 if (ch == 'y' || ch == ' ') {
266 LastChar = CorrChar; /* Restore the corrected end */
267 xprintf("%s", CGETS(6, 2, "yes\n"));
269 else {
270 Strcpy(InputBuf, Origin);
271 LastChar = SaveChar;
272 if (ch == 'e') {
273 xprintf("%s", CGETS(6, 3, "edit\n"));
274 *LastChar-- = '\0';
275 Cursor = LastChar;
276 printprompt(3, NULL);
277 ClearLines();
278 ClearDisp();
279 Refresh();
280 cleanup_until(Origin);
281 break;
283 else if (ch == 'a') {
284 xprintf("%s", CGETS(6, 4, "abort\n"));
285 LastChar = InputBuf; /* Null the current line */
286 Cursor = LastChar;
287 printprompt(0, NULL);
288 Refresh();
289 cleanup_until(Origin);
290 break;
292 xprintf("%s", CGETS(6, 5, "no\n"));
294 flush();
296 cleanup_until(Origin);
297 } else if (crct && crct->vec != NULL &&
298 !Strcmp(*(crct->vec), STRcomplete)) {
299 if (LastChar > InputBuf && LastChar[-1] == '\n') {
300 LastChar[-1] = '\0';
301 LastChar--;
302 Cursor = LastChar;
304 match_unique_match = 1; /* match unique matches */
305 matchval = CompleteLine();
306 match_unique_match = 0;
307 curlen = (int) (LastChar - InputBuf);
308 if (matchval != 1) {
309 PastBottom();
311 if (matchval == 0) {
312 xprintf("%s", CGETS(6, 6, "No matching command\n"));
313 } else if (matchval == 2) {
314 xprintf("%s", CGETS(6, 7, "Ambiguous command\n"));
316 if (NeedsRedraw) {
317 ClearLines();
318 ClearDisp();
319 NeedsRedraw = 0;
321 Refresh();
322 Argument = 1;
323 DoingArg = 0;
324 if (matchval == 1) {
325 PastBottom();
326 *LastChar++ = '\n';
327 *LastChar = '\0';
329 curlen = (int) (LastChar - InputBuf);
331 else
332 PastBottom();
334 if (matchval == 1) {
335 tellwhat = 0; /* just in case */
336 Hist_num = 0; /* for the history commands */
337 /* return the number of chars read */
338 num = (int) (LastChar - InputBuf);
340 * For continuation lines, we set the prompt to prompt 2
342 printprompt(1, NULL);
344 break;
346 case CC_CORRECT:
347 if (tenematch(InputBuf, Cursor - InputBuf, SPELL) < 0)
348 SoundBeep(); /* Beep = No match/ambiguous */
349 curlen = Repair();
350 break;
352 case CC_CORRECT_L:
353 if (SpellLine(FALSE) < 0)
354 SoundBeep(); /* Beep = No match/ambiguous */
355 curlen = Repair();
356 break;
359 case CC_COMPLETE:
360 case CC_COMPLETE_ALL:
361 case CC_COMPLETE_FWD:
362 case CC_COMPLETE_BACK:
363 switch (retval) {
364 case CC_COMPLETE:
365 fn = RECOGNIZE;
366 curlen = (int) (LastChar - InputBuf);
367 curchoice = -1;
368 rotate = 0;
369 break;
370 case CC_COMPLETE_ALL:
371 fn = RECOGNIZE_ALL;
372 curlen = (int) (LastChar - InputBuf);
373 curchoice = -1;
374 rotate = 0;
375 break;
376 case CC_COMPLETE_FWD:
377 fn = RECOGNIZE_SCROLL;
378 curchoice++;
379 rotate = 1;
380 break;
381 case CC_COMPLETE_BACK:
382 fn = RECOGNIZE_SCROLL;
383 curchoice--;
384 rotate = 1;
385 break;
386 default:
387 abort();
389 if (InputBuf[curlen] && rotate) {
390 newlen = (int) (LastChar - InputBuf);
391 for (idx = (int) (Cursor - InputBuf);
392 idx <= newlen; idx++)
393 InputBuf[idx - newlen + curlen] =
394 InputBuf[idx];
395 LastChar = InputBuf + curlen;
396 Cursor = Cursor - newlen + curlen;
398 curlen = (int) (LastChar - InputBuf);
401 nr_history_exp = 0;
402 autoexpand = varval(STRautoexpand);
403 if (autoexpand != STRNULL)
404 nr_history_exp += ExpandHistory();
406 /* try normal expansion only if no history references were found */
407 if (nr_history_exp == 0 ||
408 Strcmp(autoexpand, STRonlyhistory) != 0) {
410 * Modified by Martin Boyer (gamin@ireq-robot.hydro.qc.ca):
411 * A separate variable now controls beeping after
412 * completion, independently of autolisting.
414 expnum = (int) (Cursor - InputBuf);
415 switch (matchval = tenematch(InputBuf, Cursor-InputBuf, fn)){
416 case 1:
417 if (non_unique_match && matchbeep &&
418 matchbeep->vec != NULL &&
419 (Strcmp(*(matchbeep->vec), STRnotunique) == 0))
420 SoundBeep();
421 break;
422 case 0:
423 if (matchbeep && matchbeep->vec != NULL) {
424 if (Strcmp(*(matchbeep->vec), STRnomatch) == 0 ||
425 Strcmp(*(matchbeep->vec), STRambiguous) == 0 ||
426 Strcmp(*(matchbeep->vec), STRnotunique) == 0)
427 SoundBeep();
429 else
430 SoundBeep();
431 break;
432 default:
433 if (matchval < 0) { /* Error from tenematch */
434 curchoice = -1;
435 SoundBeep();
436 break;
438 if (matchbeep && matchbeep->vec != NULL) {
439 if ((Strcmp(*(matchbeep->vec), STRambiguous) == 0 ||
440 Strcmp(*(matchbeep->vec), STRnotunique) == 0))
441 SoundBeep();
443 else
444 SoundBeep();
446 * Addition by David C Lawrence <tale@pawl.rpi.edu>: If an
447 * attempted completion is ambiguous, list the choices.
448 * (PWP: this is the best feature addition to tcsh I have
449 * seen in many months.)
451 if (autol && autol->vec != NULL &&
452 (Strcmp(*(autol->vec), STRambiguous) != 0 ||
453 expnum == Cursor - InputBuf)) {
454 if (adrof(STRhighlight) && MarkIsSet) {
455 /* clear highlighting before showing completions */
456 MarkIsSet = 0;
457 ClearLines();
458 ClearDisp();
459 Refresh();
460 MarkIsSet = 1;
462 PastBottom();
463 fn = (retval == CC_COMPLETE_ALL) ? LIST_ALL : LIST;
464 (void) tenematch(InputBuf, Cursor-InputBuf, fn);
466 break;
469 if (NeedsRedraw) {
470 PastBottom();
471 ClearLines();
472 ClearDisp();
473 NeedsRedraw = 0;
475 Refresh();
476 Argument = 1;
477 DoingArg = 0;
478 break;
480 case CC_LIST_CHOICES:
481 case CC_LIST_ALL:
482 if (InputBuf[curlen] && rotate) {
483 newlen = (int) (LastChar - InputBuf);
484 for (idx = (int) (Cursor - InputBuf);
485 idx <= newlen; idx++)
486 InputBuf[idx - newlen + curlen] =
487 InputBuf[idx];
488 LastChar = InputBuf + curlen;
489 Cursor = Cursor - newlen + curlen;
491 curlen = (int) (LastChar - InputBuf);
492 if (curchoice >= 0)
493 curchoice--;
495 fn = (retval == CC_LIST_ALL) ? LIST_ALL : LIST;
496 /* should catch ^C here... */
497 if (tenematch(InputBuf, Cursor - InputBuf, fn) < 0)
498 SoundBeep();
499 Refresh();
500 Argument = 1;
501 DoingArg = 0;
502 break;
505 case CC_LIST_GLOB:
506 if (tenematch(InputBuf, Cursor - InputBuf, GLOB) < 0)
507 SoundBeep();
508 curlen = Repair();
509 break;
511 case CC_EXPAND_GLOB:
512 if (tenematch(InputBuf, Cursor - InputBuf, GLOB_EXPAND) <= 0)
513 SoundBeep(); /* Beep = No match */
514 curlen = Repair();
515 break;
517 case CC_NORMALIZE_PATH:
518 if (tenematch(InputBuf, Cursor - InputBuf, PATH_NORMALIZE) <= 0)
519 SoundBeep(); /* Beep = No match */
520 curlen = Repair();
521 break;
523 case CC_EXPAND_VARS:
524 if (tenematch(InputBuf, Cursor - InputBuf, VARS_EXPAND) <= 0)
525 SoundBeep(); /* Beep = No match */
526 curlen = Repair();
527 break;
529 case CC_NORMALIZE_COMMAND:
530 if (tenematch(InputBuf, Cursor - InputBuf, COMMAND_NORMALIZE) <= 0)
531 SoundBeep(); /* Beep = No match */
532 curlen = Repair();
533 break;
535 case CC_HELPME:
536 xputchar('\n');
537 /* should catch ^C here... */
538 (void) tenematch(InputBuf, LastChar - InputBuf, PRINT_HELP);
539 Refresh();
540 Argument = 1;
541 DoingArg = 0;
542 curchoice = -1;
543 curlen = (int) (LastChar - InputBuf);
544 break;
546 case CC_FATAL: /* fatal error, reset to known state */
547 #ifdef DEBUG_EDIT
548 xprintf(CGETS(7, 8, "*** editor fatal ERROR ***\r\n\n"));
549 #endif /* DEBUG_EDIT */
550 /* put (real) cursor in a known place */
551 ClearDisp(); /* reset the display stuff */
552 ResetInLine(1); /* reset the input pointers */
553 Refresh(); /* print the prompt again */
554 Argument = 1;
555 DoingArg = 0;
556 curchoice = -1;
557 curlen = (int) (LastChar - InputBuf);
558 break;
560 case CC_ERROR:
561 default: /* functions we don't know about */
562 if (adrof(STRhighlight)) {
563 ClearLines();
564 ClearDisp();
565 Refresh();
567 DoingArg = 0;
568 Argument = 1;
569 SoundBeep();
570 flush();
571 curchoice = -1;
572 curlen = (int) (LastChar - InputBuf);
573 break;
576 (void) Cookedmode(); /* make sure the tty is set up correctly */
577 GettingInput = 0;
578 flush(); /* flush any buffered output */
579 return num;
582 void
583 PushMacro(Char *str)
585 if (str != NULL && MacroLvl + 1 < MAXMACROLEVELS) {
586 MacroLvl++;
587 KeyMacro[MacroLvl] = str;
589 else {
590 SoundBeep();
591 flush();
595 struct eval1_state
597 Char **evalvec, *evalp;
600 static void
601 eval1_cleanup(void *xstate)
603 struct eval1_state *state;
605 state = xstate;
606 evalvec = state->evalvec;
607 evalp = state->evalp;
608 doneinp = 0;
612 * Like eval, only using the current file descriptors
614 static void
615 doeval1(Char **v)
617 struct eval1_state state;
618 Char **gv;
619 int gflag;
621 gflag = tglob(v);
622 if (gflag) {
623 gv = v = globall(v, gflag);
624 if (v == 0)
625 stderror(ERR_NOMATCH);
626 v = copyblk(v);
628 else {
629 gv = NULL;
630 v = copyblk(v);
631 trim(v);
633 if (gv)
634 cleanup_push(gv, blk_cleanup);
636 state.evalvec = evalvec;
637 state.evalp = evalp;
638 evalvec = v;
639 evalp = 0;
640 cleanup_push(&state, eval1_cleanup);
641 process(0);
642 cleanup_until(&state);
643 if (gv)
644 cleanup_until(gv);
647 static void
648 RunCommand(Char *str)
650 Char *cmd[2];
652 xputchar('\n'); /* Start on a clean line */
654 cmd[0] = str;
655 cmd[1] = NULL;
657 (void) Cookedmode();
658 GettingInput = 0;
660 doeval1(cmd);
662 (void) Rawmode();
663 GettingInput = 1;
665 ClearLines();
666 ClearDisp();
667 NeedsRedraw = 0;
668 Refresh();
671 static int
672 GetNextCommand(KEYCMD *cmdnum, Char *ch)
674 KEYCMD cmd = 0;
675 int num;
677 while (cmd == 0 || cmd == F_XKEY) {
678 if ((num = GetNextChar(ch)) != 1) { /* if EOF or error */
679 return num;
681 #ifdef KANJI
682 if (
683 #ifdef DSPMBYTE
684 _enable_mbdisp &&
685 #else
686 MB_LEN_MAX == 1 &&
687 #endif
688 !adrof(STRnokanji) && (*ch & META)) {
689 MetaNext = 0;
690 cmd = F_INSERT;
691 break;
693 else
694 #endif /* KANJI */
695 if (MetaNext) {
696 MetaNext = 0;
697 *ch |= META;
699 /* XXX: This needs to be fixed so that we don't just truncate
700 * the character, we unquote it.
702 if (*ch < NT_NUM_KEYS)
703 cmd = CurrentKeyMap[*ch];
704 else
705 #ifdef WINNT_NATIVE
706 cmd = CurrentKeyMap[(unsigned char) *ch];
707 #else
708 cmd = F_INSERT;
709 #endif
710 if (cmd == F_XKEY) {
711 XmapVal val;
712 CStr cstr;
713 cstr.buf = ch;
714 cstr.len = 1;
715 switch (GetXkey(&cstr, &val)) {
716 case XK_CMD:
717 cmd = val.cmd;
718 break;
719 case XK_STR:
720 PushMacro(val.str.buf);
721 break;
722 case XK_EXE:
723 RunCommand(val.str.buf);
724 break;
725 default:
726 abort();
727 break;
730 if (!AltKeyMap)
731 CurrentKeyMap = CcKeyMap;
733 *cmdnum = cmd;
734 return OKCMD;
737 static Char ungetchar;
738 static int haveungetchar;
740 void
741 UngetNextChar(Char cp)
743 ungetchar = cp;
744 haveungetchar = 1;
748 GetNextChar(Char *cp)
750 int num_read;
751 int tried = 0;
752 char cbuf[MB_LEN_MAX];
753 size_t cbp;
755 if (haveungetchar) {
756 haveungetchar = 0;
757 *cp = ungetchar;
758 return 1;
760 for (;;) {
761 if (MacroLvl < 0) {
762 if (!Load_input_line())
763 break;
765 if (*KeyMacro[MacroLvl] == 0) {
766 MacroLvl--;
767 continue;
769 *cp = *KeyMacro[MacroLvl]++ & CHAR;
770 if (*KeyMacro[MacroLvl] == 0) { /* Needed for QuoteMode On */
771 MacroLvl--;
773 return (1);
776 if (Rawmode() < 0) /* make sure the tty is set up correctly */
777 return 0; /* oops: SHIN was closed */
779 #ifdef WINNT_NATIVE
780 __nt_want_vcode = 1;
781 #endif /* WINNT_NATIVE */
782 #ifdef SIG_WINDOW
783 if (windowchg)
784 (void) check_window_size(0); /* for window systems */
785 #endif /* SIG_WINDOW */
786 cbp = 0;
787 for (;;) {
788 while ((num_read = xread(SHIN, cbuf + cbp, 1)) == -1) {
789 if (!tried && fixio(SHIN, errno) != -1)
790 tried = 1;
791 else {
792 # ifdef convex
793 /* need to print error message in case the file is migrated */
794 stderror(ERR_SYSTEM, progname, strerror(errno));
795 # endif /* convex */
796 # ifdef WINNT_NATIVE
797 __nt_want_vcode = 0;
798 # endif /* WINNT_NATIVE */
799 *cp = '\0'; /* Loses possible partial character */
800 return -1;
803 if (AsciiOnly) {
804 *cp = (unsigned char)*cbuf;
805 } else {
806 cbp++;
807 if (normal_mbtowc(cp, cbuf, cbp) == -1) {
808 reset_mbtowc();
809 if (cbp < MB_CUR_MAX)
810 continue; /* Maybe a partial character */
811 /* And drop the following bytes, if any */
812 *cp = (unsigned char)*cbuf | INVALID_BYTE;
815 break;
817 #ifdef WINNT_NATIVE
818 /* This is the part that doesn't work with WIDE_STRINGS */
819 if (__nt_want_vcode == 2)
820 *cp = __nt_vcode;
821 __nt_want_vcode = 0;
822 #endif /* WINNT_NATIVE */
823 return num_read;
827 * SpellLine - do spelling correction on the entire command line
828 * (which may have trailing newline).
829 * If cmdonly is set, only check spelling of command words.
830 * Return value:
831 * -1: Something was incorrectible, and nothing was corrected
832 * 0: Everything was correct
833 * 1: Something was corrected
835 static int
836 SpellLine(int cmdonly)
838 int endflag, matchval;
839 Char *argptr, *OldCursor, *OldLastChar;
841 OldLastChar = LastChar;
842 OldCursor = Cursor;
843 argptr = InputBuf;
844 endflag = 1;
845 matchval = 0;
846 do {
847 while (ismetahash(*argptr) || iscmdmeta(*argptr))
848 argptr++;
849 for (Cursor = argptr;
850 *Cursor != '\0' && ((Cursor != argptr && Cursor[-1] == '\\') ||
851 (!ismetahash(*Cursor) && !iscmdmeta(*Cursor)));
852 Cursor++)
853 continue;
854 if (*Cursor == '\0') {
855 Cursor = LastChar;
856 if (LastChar[-1] == '\n')
857 Cursor--;
858 endflag = 0;
860 if (!MISMATCH(*argptr) &&
861 (!cmdonly || starting_a_command(argptr, InputBuf))) {
862 #ifdef WINNT_NATIVE
864 * This hack avoids correcting drive letter changes
866 if((Cursor - InputBuf) != 2 || (char)InputBuf[1] != ':')
867 #endif /* WINNT_NATIVE */
869 #ifdef HASH_SPELL_CHECK
870 Char save;
871 size_t len = Cursor - InputBuf;
873 save = InputBuf[len];
874 InputBuf[len] = '\0';
875 if (find_cmd(InputBuf, 0) != 0) {
876 InputBuf[len] = save;
877 argptr = Cursor;
878 continue;
880 InputBuf[len] = save;
881 #endif /* HASH_SPELL_CHECK */
882 switch (tenematch(InputBuf, Cursor - InputBuf, SPELL)) {
883 case 1: /* corrected */
884 matchval = 1;
885 break;
886 case -1: /* couldn't be corrected */
887 if (!matchval)
888 matchval = -1;
889 break;
890 default: /* was correct */
891 break;
894 if (LastChar != OldLastChar) {
895 if (argptr < OldCursor)
896 OldCursor += (LastChar - OldLastChar);
897 OldLastChar = LastChar;
900 argptr = Cursor;
901 } while (endflag);
902 Cursor = OldCursor;
903 return matchval;
907 * CompleteLine - do command completion on the entire command line
908 * (which may have trailing newline).
909 * Return value:
910 * 0: No command matched or failure
911 * 1: One command matched
912 * 2: Several commands matched
914 static int
915 CompleteLine(void)
917 int endflag, tmatch;
918 Char *argptr, *OldCursor, *OldLastChar;
920 OldLastChar = LastChar;
921 OldCursor = Cursor;
922 argptr = InputBuf;
923 endflag = 1;
924 do {
925 while (ismetahash(*argptr) || iscmdmeta(*argptr))
926 argptr++;
927 for (Cursor = argptr;
928 *Cursor != '\0' && ((Cursor != argptr && Cursor[-1] == '\\') ||
929 (!ismetahash(*Cursor) && !iscmdmeta(*Cursor)));
930 Cursor++)
931 continue;
932 if (*Cursor == '\0') {
933 Cursor = LastChar;
934 if (LastChar[-1] == '\n')
935 Cursor--;
936 endflag = 0;
938 if (!MISMATCH(*argptr) && starting_a_command(argptr, InputBuf)) {
939 tmatch = tenematch(InputBuf, Cursor - InputBuf, RECOGNIZE);
940 if (tmatch <= 0) {
941 return 0;
942 } else if (tmatch > 1) {
943 return 2;
945 if (LastChar != OldLastChar) {
946 if (argptr < OldCursor)
947 OldCursor += (LastChar - OldLastChar);
948 OldLastChar = LastChar;
951 argptr = Cursor;
952 } while (endflag);
953 Cursor = OldCursor;
954 return 1;