MFC: An off-by-one malloc size was corrupting the installer's memory,
[dragonfly.git] / contrib / tcsh-6 / ed.inputl.c
bloba97058e1feee829e475eeb6f7f891d28ab6d85f4
1 /* $Header: /p/tcsh/cvsroot/tcsh/ed.inputl.c,v 3.66 2006/11/29 22:32:24 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.66 2006/11/29 22:32:24 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[] =
49 {'!', '^' , '\\', '-', '%', '\0', '"', '\'', '`', '\0' };
51 static int Repair (void);
52 static int GetNextCommand (KEYCMD *, Char *);
53 static int SpellLine (int);
54 static int CompleteLine (void);
55 static void RunCommand (Char *);
56 static void doeval1 (Char **);
58 static int rotate = 0;
61 static int
62 Repair(void)
64 if (NeedsRedraw) {
65 ClearLines();
66 ClearDisp();
67 NeedsRedraw = 0;
69 Refresh();
70 Argument = 1;
71 DoingArg = 0;
72 curchoice = -1;
73 return (int) (LastChar - InputBuf);
76 /* CCRETVAL */
77 int
78 Inputl(void)
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 int matchval; /* from tenematch() */
92 COMMAND fn;
93 int curlen = 0;
94 int newlen;
95 int idx;
97 if (!MapsAreInited) /* double extra just in case */
98 ed_InitMaps();
100 ClearDisp(); /* reset the display stuff */
101 ResetInLine(0); /* reset the input pointers */
102 if (GettingInput)
103 MacroLvl = -1; /* editor was interrupted during input */
105 if (imode && imode->vec != NULL) {
106 if (!Strcmp(*(imode->vec), STRinsert))
107 inputmode = MODE_INSERT;
108 else if (!Strcmp(*(imode->vec), STRoverwrite))
109 inputmode = MODE_REPLACE;
112 #if defined(FIONREAD) && !defined(OREO)
113 if (!Tty_raw_mode && MacroLvl < 0) {
114 # ifdef SUNOS4
115 long chrs = 0;
116 # else /* !SUNOS4 */
118 * *Everyone* else has an int, but SunOS wants long!
119 * This breaks where int != long (alpha)
121 int chrs = 0;
122 # endif /* SUNOS4 */
124 (void) ioctl(SHIN, FIONREAD, (ioctl_t) & chrs);
125 if (chrs == 0) {
126 if (Rawmode() < 0)
127 return 0;
130 #endif /* FIONREAD && !OREO */
132 GettingInput = 1;
133 NeedsRedraw = 0;
134 tellwhat = 0;
136 if (RestoreSaved) {
137 copyn(InputBuf, SavedBuf.s, INBUFSIZE);/*FIXBUF*/
138 LastChar = InputBuf + LastSaved;
139 Cursor = InputBuf + CursSaved;
140 Hist_num = HistSaved;
141 HistSaved = 0;
142 RestoreSaved = 0;
144 if (HistSaved) {
145 Hist_num = HistSaved;
146 GetHistLine();
147 HistSaved = 0;
149 if (Expand) {
150 (void) e_up_hist(0);
151 Expand = 0;
153 Refresh(); /* print the prompt */
155 for (num = OKCMD; num == OKCMD;) { /* while still editing this line */
156 #ifdef DEBUG_EDIT
157 if (Cursor > LastChar)
158 xprintf("Cursor > LastChar\r\n");
159 if (Cursor < InputBuf)
160 xprintf("Cursor < InputBuf\r\n");
161 if (Cursor > InputLim)
162 xprintf("Cursor > InputLim\r\n");
163 if (LastChar > InputLim)
164 xprintf("LastChar > InputLim\r\n");
165 if (InputLim != &InputBuf[INBUFSIZE - 2])/*FIXBUF*/
166 xprintf("InputLim != &InputBuf[INBUFSIZE-2]\r\n");
167 if ((!DoingArg) && (Argument != 1))
168 xprintf("(!DoingArg) && (Argument != 1)\r\n");
169 if (CcKeyMap[0] == 0)
170 xprintf("CcKeyMap[0] == 0 (maybe not inited)\r\n");
171 #endif
173 /* if EOF or error */
174 if ((num = GetNextCommand(&cmdnum, &ch)) != OKCMD) {
175 break;
178 if (cmdnum >= NumFuns) {/* BUG CHECK command */
179 #ifdef DEBUG_EDIT
180 xprintf(CGETS(6, 1, "ERROR: illegal command from key 0%o\r\n"), ch);
181 #endif
182 continue; /* try again */
185 /* now do the real command */
186 retval = (*CcFuncTbl[cmdnum]) (ch);
188 /* save the last command here */
189 LastCmd = cmdnum;
191 /* make sure fn is initialized */
192 fn = (retval == CC_COMPLETE_ALL) ? LIST_ALL : LIST;
194 /* use any return value */
195 switch (retval) {
197 case CC_REFRESH:
198 Refresh();
199 /*FALLTHROUGH*/
200 case CC_NORM: /* normal char */
201 Argument = 1;
202 DoingArg = 0;
203 /*FALLTHROUGH*/
204 case CC_ARGHACK: /* Suggested by Rich Salz */
205 /* <rsalz@pineapple.bbn.com> */
206 curchoice = -1;
207 curlen = (int) (LastChar - InputBuf);
208 break; /* keep going... */
210 case CC_EOF: /* end of file typed */
211 curchoice = -1;
212 curlen = (int) (LastChar - InputBuf);
213 num = 0;
214 break;
216 case CC_WHICH: /* tell what this command does */
217 tellwhat = 1;
218 *LastChar++ = '\n'; /* for the benifit of CSH */
219 num = (int) (LastChar - InputBuf); /* number characters read */
220 break;
222 case CC_NEWLINE: /* normal end of line */
223 curlen = 0;
224 curchoice = -1;
225 matchval = 1;
226 if (crct && crct->vec != NULL && (!Strcmp(*(crct->vec), STRcmd) ||
227 !Strcmp(*(crct->vec), STRall))) {
228 Char *Origin;
230 PastBottom();
231 Origin = Strsave(InputBuf);
232 cleanup_push(Origin, xfree);
233 SaveChar = LastChar;
234 if (SpellLine(!Strcmp(*(crct->vec), STRcmd)) == 1) {
235 Char *Change;
237 PastBottom();
238 Change = Strsave(InputBuf);
239 cleanup_push(Change, xfree);
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 cleanup_until(Change);
246 Refresh();
247 if (xread(SHIN, &tch, 1) < 0) {
248 #ifdef convex
250 * need to print error message in case file
251 * is migrated
253 if (errno)
254 stderror(ERR_SYSTEM, progname, strerror(errno));
255 #else
256 cleanup_until(Origin);
257 break;
258 #endif
260 ch = tch;
261 if (ch == 'y' || ch == ' ') {
262 LastChar = CorrChar; /* Restore the corrected end */
263 xprintf(CGETS(6, 2, "yes\n"));
265 else {
266 Strcpy(InputBuf, Origin);
267 LastChar = SaveChar;
268 if (ch == 'e') {
269 xprintf(CGETS(6, 3, "edit\n"));
270 *LastChar-- = '\0';
271 Cursor = LastChar;
272 printprompt(3, NULL);
273 ClearLines();
274 ClearDisp();
275 Refresh();
276 cleanup_until(Origin);
277 break;
279 else if (ch == 'a') {
280 xprintf(CGETS(6, 4, "abort\n"));
281 LastChar = InputBuf; /* Null the current line */
282 Cursor = LastChar;
283 printprompt(0, NULL);
284 Refresh();
285 cleanup_until(Origin);
286 break;
288 xprintf(CGETS(6, 5, "no\n"));
290 flush();
292 cleanup_until(Origin);
293 } else if (crct && crct->vec != NULL &&
294 !Strcmp(*(crct->vec), STRcomplete)) {
295 if (LastChar > InputBuf && LastChar[-1] == '\n') {
296 LastChar[-1] = '\0';
297 LastChar--;
298 Cursor = LastChar;
300 match_unique_match = 1; /* match unique matches */
301 matchval = CompleteLine();
302 match_unique_match = 0;
303 curlen = (int) (LastChar - InputBuf);
304 if (matchval != 1) {
305 PastBottom();
307 if (matchval == 0) {
308 xprintf(CGETS(6, 6, "No matching command\n"));
309 } else if (matchval == 2) {
310 xprintf(CGETS(6, 7, "Ambiguous command\n"));
312 if (NeedsRedraw) {
313 ClearLines();
314 ClearDisp();
315 NeedsRedraw = 0;
317 Refresh();
318 Argument = 1;
319 DoingArg = 0;
320 if (matchval == 1) {
321 PastBottom();
322 *LastChar++ = '\n';
323 *LastChar = '\0';
325 curlen = (int) (LastChar - InputBuf);
327 else
328 PastBottom();
330 if (matchval == 1) {
331 tellwhat = 0; /* just in case */
332 Hist_num = 0; /* for the history commands */
333 /* return the number of chars read */
334 num = (int) (LastChar - InputBuf);
336 * For continuation lines, we set the prompt to prompt 2
338 printprompt(1, NULL);
340 break;
342 case CC_CORRECT:
343 if (tenematch(InputBuf, Cursor - InputBuf, SPELL) < 0)
344 SoundBeep(); /* Beep = No match/ambiguous */
345 curlen = Repair();
346 break;
348 case CC_CORRECT_L:
349 if (SpellLine(FALSE) < 0)
350 SoundBeep(); /* Beep = No match/ambiguous */
351 curlen = Repair();
352 break;
355 case CC_COMPLETE:
356 case CC_COMPLETE_ALL:
357 case CC_COMPLETE_FWD:
358 case CC_COMPLETE_BACK:
359 switch (retval) {
360 case CC_COMPLETE:
361 fn = RECOGNIZE;
362 curlen = (int) (LastChar - InputBuf);
363 curchoice = -1;
364 rotate = 0;
365 break;
366 case CC_COMPLETE_ALL:
367 fn = RECOGNIZE_ALL;
368 curlen = (int) (LastChar - InputBuf);
369 curchoice = -1;
370 rotate = 0;
371 break;
372 case CC_COMPLETE_FWD:
373 fn = RECOGNIZE_SCROLL;
374 curchoice++;
375 rotate = 1;
376 break;
377 case CC_COMPLETE_BACK:
378 fn = RECOGNIZE_SCROLL;
379 curchoice--;
380 rotate = 1;
381 break;
382 default:
383 abort();
385 if (InputBuf[curlen] && rotate) {
386 newlen = (int) (LastChar - InputBuf);
387 for (idx = (int) (Cursor - InputBuf);
388 idx <= newlen; idx++)
389 InputBuf[idx - newlen + curlen] =
390 InputBuf[idx];
391 LastChar = InputBuf + curlen;
392 Cursor = Cursor - newlen + curlen;
394 curlen = (int) (LastChar - InputBuf);
397 if (adrof(STRautoexpand))
398 (void) e_expand_history(0);
400 * Modified by Martin Boyer (gamin@ireq-robot.hydro.qc.ca):
401 * A separate variable now controls beeping after
402 * completion, independently of autolisting.
404 expnum = (int) (Cursor - InputBuf);
405 switch (matchval = tenematch(InputBuf, Cursor-InputBuf, fn)){
406 case 1:
407 if (non_unique_match && matchbeep && matchbeep->vec != NULL &&
408 (Strcmp(*(matchbeep->vec), STRnotunique) == 0))
409 SoundBeep();
410 break;
411 case 0:
412 if (matchbeep && matchbeep->vec != NULL) {
413 if (Strcmp(*(matchbeep->vec), STRnomatch) == 0 ||
414 Strcmp(*(matchbeep->vec), STRambiguous) == 0 ||
415 Strcmp(*(matchbeep->vec), STRnotunique) == 0)
416 SoundBeep();
418 else
419 SoundBeep();
420 break;
421 default:
422 if (matchval < 0) { /* Error from tenematch */
423 curchoice = -1;
424 SoundBeep();
425 break;
427 if (matchbeep && matchbeep->vec != NULL) {
428 if ((Strcmp(*(matchbeep->vec), STRambiguous) == 0 ||
429 Strcmp(*(matchbeep->vec), STRnotunique) == 0))
430 SoundBeep();
432 else
433 SoundBeep();
435 * Addition by David C Lawrence <tale@pawl.rpi.edu>: If an
436 * attempted completion is ambiguous, list the choices.
437 * (PWP: this is the best feature addition to tcsh I have
438 * seen in many months.)
440 if (autol && autol->vec != NULL &&
441 (Strcmp(*(autol->vec), STRambiguous) != 0 ||
442 expnum == Cursor - InputBuf)) {
443 if (adrof(STRhighlight) && MarkIsSet) {
444 /* clear highlighting before showing completions */
445 MarkIsSet = 0;
446 ClearLines();
447 ClearDisp();
448 Refresh();
449 MarkIsSet = 1;
451 PastBottom();
452 fn = (retval == CC_COMPLETE_ALL) ? LIST_ALL : LIST;
453 (void) tenematch(InputBuf, Cursor-InputBuf, fn);
455 break;
457 if (NeedsRedraw) {
458 PastBottom();
459 ClearLines();
460 ClearDisp();
461 NeedsRedraw = 0;
463 Refresh();
464 Argument = 1;
465 DoingArg = 0;
466 break;
468 case CC_LIST_CHOICES:
469 case CC_LIST_ALL:
470 if (InputBuf[curlen] && rotate) {
471 newlen = (int) (LastChar - InputBuf);
472 for (idx = (int) (Cursor - InputBuf);
473 idx <= newlen; idx++)
474 InputBuf[idx - newlen + curlen] =
475 InputBuf[idx];
476 LastChar = InputBuf + curlen;
477 Cursor = Cursor - newlen + curlen;
479 curlen = (int) (LastChar - InputBuf);
480 if (curchoice >= 0)
481 curchoice--;
483 fn = (retval == CC_LIST_ALL) ? LIST_ALL : LIST;
484 /* should catch ^C here... */
485 if (tenematch(InputBuf, Cursor - InputBuf, fn) < 0)
486 SoundBeep();
487 Refresh();
488 Argument = 1;
489 DoingArg = 0;
490 break;
493 case CC_LIST_GLOB:
494 if (tenematch(InputBuf, Cursor - InputBuf, GLOB) < 0)
495 SoundBeep();
496 curlen = Repair();
497 break;
499 case CC_EXPAND_GLOB:
500 if (tenematch(InputBuf, Cursor - InputBuf, GLOB_EXPAND) <= 0)
501 SoundBeep(); /* Beep = No match */
502 curlen = Repair();
503 break;
505 case CC_NORMALIZE_PATH:
506 if (tenematch(InputBuf, Cursor - InputBuf, PATH_NORMALIZE) <= 0)
507 SoundBeep(); /* Beep = No match */
508 curlen = Repair();
509 break;
511 case CC_EXPAND_VARS:
512 if (tenematch(InputBuf, Cursor - InputBuf, VARS_EXPAND) <= 0)
513 SoundBeep(); /* Beep = No match */
514 curlen = Repair();
515 break;
517 case CC_NORMALIZE_COMMAND:
518 if (tenematch(InputBuf, Cursor - InputBuf, COMMAND_NORMALIZE) <= 0)
519 SoundBeep(); /* Beep = No match */
520 curlen = Repair();
521 break;
523 case CC_HELPME:
524 xputchar('\n');
525 /* should catch ^C here... */
526 (void) tenematch(InputBuf, LastChar - InputBuf, PRINT_HELP);
527 Refresh();
528 Argument = 1;
529 DoingArg = 0;
530 curchoice = -1;
531 curlen = (int) (LastChar - InputBuf);
532 break;
534 case CC_FATAL: /* fatal error, reset to known state */
535 #ifdef DEBUG_EDIT
536 xprintf(CGETS(7, 8, "*** editor fatal ERROR ***\r\n\n"));
537 #endif /* DEBUG_EDIT */
538 /* put (real) cursor in a known place */
539 ClearDisp(); /* reset the display stuff */
540 ResetInLine(1); /* reset the input pointers */
541 Refresh(); /* print the prompt again */
542 Argument = 1;
543 DoingArg = 0;
544 curchoice = -1;
545 curlen = (int) (LastChar - InputBuf);
546 break;
548 case CC_ERROR:
549 default: /* functions we don't know about */
550 if (adrof(STRhighlight)) {
551 ClearLines();
552 ClearDisp();
553 Refresh();
555 DoingArg = 0;
556 Argument = 1;
557 SoundBeep();
558 flush();
559 curchoice = -1;
560 curlen = (int) (LastChar - InputBuf);
561 break;
564 (void) Cookedmode(); /* make sure the tty is set up correctly */
565 GettingInput = 0;
566 flush(); /* flush any buffered output */
567 return num;
570 void
571 PushMacro(Char *str)
573 if (str != NULL && MacroLvl + 1 < MAXMACROLEVELS) {
574 MacroLvl++;
575 KeyMacro[MacroLvl] = str;
577 else {
578 SoundBeep();
579 flush();
583 struct eval1_state
585 Char **evalvec, *evalp;
588 static void
589 eval1_cleanup(void *xstate)
591 struct eval1_state *state;
593 state = xstate;
594 evalvec = state->evalvec;
595 evalp = state->evalp;
596 doneinp = 0;
600 * Like eval, only using the current file descriptors
602 static void
603 doeval1(Char **v)
605 struct eval1_state state;
606 Char **gv;
607 int gflag;
609 gflag = tglob(v);
610 if (gflag) {
611 gv = v = globall(v, gflag);
612 if (v == 0)
613 stderror(ERR_NOMATCH);
614 v = copyblk(v);
616 else {
617 gv = NULL;
618 v = copyblk(v);
619 trim(v);
621 if (gv)
622 cleanup_push(gv, blk_cleanup);
624 state.evalvec = evalvec;
625 state.evalp = evalp;
626 evalvec = v;
627 evalp = 0;
628 cleanup_push(&state, eval1_cleanup);
629 process(0);
630 cleanup_until(&state);
631 if (gv)
632 cleanup_until(gv);
635 static void
636 RunCommand(Char *str)
638 Char *cmd[2];
640 xputchar('\n'); /* Start on a clean line */
642 cmd[0] = str;
643 cmd[1] = NULL;
645 (void) Cookedmode();
646 GettingInput = 0;
648 doeval1(cmd);
650 (void) Rawmode();
651 GettingInput = 1;
653 ClearLines();
654 ClearDisp();
655 NeedsRedraw = 0;
656 Refresh();
659 static int
660 GetNextCommand(KEYCMD *cmdnum, Char *ch)
662 KEYCMD cmd = 0;
663 int num;
665 while (cmd == 0 || cmd == F_XKEY) {
666 if ((num = GetNextChar(ch)) != 1) { /* if EOF or error */
667 return num;
669 #ifdef KANJI
670 if (
671 #ifdef DSPMBYTE
672 _enable_mbdisp &&
673 #else
674 MB_LEN_MAX == 1 &&
675 #endif
676 !adrof(STRnokanji) && (*ch & META)) {
677 MetaNext = 0;
678 cmd = F_INSERT;
679 break;
681 else
682 #endif /* KANJI */
683 if (MetaNext) {
684 MetaNext = 0;
685 *ch |= META;
687 /* XXX: This needs to be fixed so that we don't just truncate
688 * the character, we unquote it.
690 if (*ch < NT_NUM_KEYS)
691 cmd = CurrentKeyMap[*ch];
692 else
693 #ifdef WINNT_NATIVE
694 cmd = CurrentKeyMap[(unsigned char) *ch];
695 #else
696 cmd = F_INSERT;
697 #endif
698 if (cmd == F_XKEY) {
699 XmapVal val;
700 CStr cstr;
701 cstr.buf = ch;
702 cstr.len = 1;
703 switch (GetXkey(&cstr, &val)) {
704 case XK_CMD:
705 cmd = val.cmd;
706 break;
707 case XK_STR:
708 PushMacro(val.str.buf);
709 break;
710 case XK_EXE:
711 RunCommand(val.str.buf);
712 break;
713 default:
714 abort();
715 break;
718 if (!AltKeyMap)
719 CurrentKeyMap = CcKeyMap;
721 *cmdnum = cmd;
722 return OKCMD;
725 static Char ungetchar;
726 static int haveungetchar;
728 void
729 UngetNextChar(Char cp)
731 ungetchar = cp;
732 haveungetchar = 1;
736 GetNextChar(Char *cp)
738 int num_read;
739 int tried = 0;
740 char cbuf[MB_LEN_MAX];
741 size_t cbp;
743 if (haveungetchar) {
744 haveungetchar = 0;
745 *cp = ungetchar;
746 return 1;
748 for (;;) {
749 if (MacroLvl < 0) {
750 if (!Load_input_line())
751 break;
753 if (*KeyMacro[MacroLvl] == 0) {
754 MacroLvl--;
755 continue;
757 *cp = *KeyMacro[MacroLvl]++ & CHAR;
758 if (*KeyMacro[MacroLvl] == 0) { /* Needed for QuoteMode On */
759 MacroLvl--;
761 return (1);
764 if (Rawmode() < 0) /* make sure the tty is set up correctly */
765 return 0; /* oops: SHIN was closed */
767 #ifdef WINNT_NATIVE
768 __nt_want_vcode = 1;
769 #endif /* WINNT_NATIVE */
770 #ifdef SIG_WINDOW
771 if (windowchg)
772 (void) check_window_size(0); /* for window systems */
773 #endif /* SIG_WINDOW */
774 cbp = 0;
775 for (;;) {
776 while ((num_read = xread(SHIN, cbuf + cbp, 1)) == -1) {
777 if (!tried && fixio(SHIN, errno) != -1)
778 tried = 1;
779 else {
780 # ifdef convex
781 /* need to print error message in case the file is migrated */
782 stderror(ERR_SYSTEM, progname, strerror(errno));
783 # endif /* convex */
784 # ifdef WINNT_NATIVE
785 __nt_want_vcode = 0;
786 # endif /* WINNT_NATIVE */
787 *cp = '\0'; /* Loses possible partial character */
788 return -1;
791 if (AsciiOnly) {
792 *cp = (unsigned char)*cbuf;
793 } else {
794 cbp++;
795 if (normal_mbtowc(cp, cbuf, cbp) == -1) {
796 reset_mbtowc();
797 if (cbp < MB_CUR_MAX)
798 continue; /* Maybe a partial character */
799 /* And drop the following bytes, if any */
800 *cp = (unsigned char)*cbuf | INVALID_BYTE;
803 break;
805 #ifdef WINNT_NATIVE
806 /* This is the part that doesn't work with WIDE_STRINGS */
807 if (__nt_want_vcode == 2)
808 *cp = __nt_vcode;
809 __nt_want_vcode = 0;
810 #endif /* WINNT_NATIVE */
811 return num_read;
815 * SpellLine - do spelling correction on the entire command line
816 * (which may have trailing newline).
817 * If cmdonly is set, only check spelling of command words.
818 * Return value:
819 * -1: Something was incorrectible, and nothing was corrected
820 * 0: Everything was correct
821 * 1: Something was corrected
823 static int
824 SpellLine(int cmdonly)
826 int endflag, matchval;
827 Char *argptr, *OldCursor, *OldLastChar;
829 OldLastChar = LastChar;
830 OldCursor = Cursor;
831 argptr = InputBuf;
832 endflag = 1;
833 matchval = 0;
834 do {
835 while (ismetahash(*argptr) || iscmdmeta(*argptr))
836 argptr++;
837 for (Cursor = argptr;
838 *Cursor != '\0' && ((Cursor != argptr && Cursor[-1] == '\\') ||
839 (!ismetahash(*Cursor) && !iscmdmeta(*Cursor)));
840 Cursor++)
841 continue;
842 if (*Cursor == '\0') {
843 Cursor = LastChar;
844 if (LastChar[-1] == '\n')
845 Cursor--;
846 endflag = 0;
848 /* Obey current history character settings */
849 mismatch[0] = HIST;
850 mismatch[1] = HISTSUB;
851 if (!Strchr(mismatch, *argptr) &&
852 (!cmdonly || starting_a_command(argptr, InputBuf))) {
853 #ifdef WINNT_NATIVE
855 * This hack avoids correcting drive letter changes
857 if((Cursor - InputBuf) != 2 || (char)InputBuf[1] != ':')
858 #endif /* WINNT_NATIVE */
860 #ifdef HASH_SPELL_CHECK
861 Char save;
862 size_t len = Cursor - InputBuf;
864 save = InputBuf[len];
865 InputBuf[len] = '\0';
866 if (find_cmd(InputBuf, 0) != 0) {
867 InputBuf[len] = save;
868 argptr = Cursor;
869 continue;
871 InputBuf[len] = save;
872 #endif /* HASH_SPELL_CHECK */
873 switch (tenematch(InputBuf, Cursor - InputBuf, SPELL)) {
874 case 1: /* corrected */
875 matchval = 1;
876 break;
877 case -1: /* couldn't be corrected */
878 if (!matchval)
879 matchval = -1;
880 break;
881 default: /* was correct */
882 break;
885 if (LastChar != OldLastChar) {
886 if (argptr < OldCursor)
887 OldCursor += (LastChar - OldLastChar);
888 OldLastChar = LastChar;
891 argptr = Cursor;
892 } while (endflag);
893 Cursor = OldCursor;
894 return matchval;
898 * CompleteLine - do command completion on the entire command line
899 * (which may have trailing newline).
900 * Return value:
901 * 0: No command matched or failure
902 * 1: One command matched
903 * 2: Several commands matched
905 static int
906 CompleteLine(void)
908 int endflag, tmatch;
909 Char *argptr, *OldCursor, *OldLastChar;
911 OldLastChar = LastChar;
912 OldCursor = Cursor;
913 argptr = InputBuf;
914 endflag = 1;
915 do {
916 while (ismetahash(*argptr) || iscmdmeta(*argptr))
917 argptr++;
918 for (Cursor = argptr;
919 *Cursor != '\0' && ((Cursor != argptr && Cursor[-1] == '\\') ||
920 (!ismetahash(*Cursor) && !iscmdmeta(*Cursor)));
921 Cursor++)
922 continue;
923 if (*Cursor == '\0') {
924 Cursor = LastChar;
925 if (LastChar[-1] == '\n')
926 Cursor--;
927 endflag = 0;
929 if (!Strchr(mismatch, *argptr) && starting_a_command(argptr, InputBuf)) {
930 tmatch = tenematch(InputBuf, Cursor - InputBuf, RECOGNIZE);
931 if (tmatch <= 0) {
932 return 0;
933 } else if (tmatch > 1) {
934 return 2;
936 if (LastChar != OldLastChar) {
937 if (argptr < OldCursor)
938 OldCursor += (LastChar - OldLastChar);
939 OldLastChar = LastChar;
942 argptr = Cursor;
943 } while (endflag);
944 Cursor = OldCursor;
945 return 1;