Import tcsh-6.17.00
[dragonfly.git] / contrib / tcsh-6 / ed.inputl.c
CommitLineData
57e3f2b5 1/* $Header: /p/tcsh/cvsroot/tcsh/ed.inputl.c,v 3.70 2009/06/25 21:15:37 christos Exp $ */
7d8fb588
MS
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
57e3f2b5 35RCSID("$tcsh: ed.inputl.c,v 3.70 2009/06/25 21:15:37 christos Exp $")
7d8fb588
MS
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 INT_MAX
42
43/* ed.inputl -- routines to get a single line from the input. */
44
45extern int MapsAreInited;
46
47/* mismatched first character */
57e3f2b5
SS
48static 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)))
7d8fb588
MS
52
53static int Repair (void);
54static int GetNextCommand (KEYCMD *, Char *);
55static int SpellLine (int);
56static int CompleteLine (void);
57static void RunCommand (Char *);
58static void doeval1 (Char **);
59
60static int rotate = 0;
61
62
63static int
64Repair(void)
65{
66 if (NeedsRedraw) {
67 ClearLines();
68 ClearDisp();
69 NeedsRedraw = 0;
70 }
71 Refresh();
72 Argument = 1;
73 DoingArg = 0;
74 curchoice = -1;
75 return (int) (LastChar - InputBuf);
76}
77
78/* CCRETVAL */
79int
80Inputl(void)
81{
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() */
57e3f2b5 94 int nr_history_exp; /* number of (attempted) history expansions */
7d8fb588
MS
95 COMMAND fn;
96 int curlen = 0;
97 int newlen;
98 int idx;
57e3f2b5 99 Char *autoexpand;
7d8fb588
MS
100
101 if (!MapsAreInited) /* double extra just in case */
102 ed_InitMaps();
103
104 ClearDisp(); /* reset the display stuff */
105 ResetInLine(0); /* reset the input pointers */
106 if (GettingInput)
107 MacroLvl = -1; /* editor was interrupted during input */
108
109 if (imode && imode->vec != NULL) {
110 if (!Strcmp(*(imode->vec), STRinsert))
111 inputmode = MODE_INSERT;
112 else if (!Strcmp(*(imode->vec), STRoverwrite))
113 inputmode = MODE_REPLACE;
114 }
115
116#if defined(FIONREAD) && !defined(OREO)
117 if (!Tty_raw_mode && MacroLvl < 0) {
118# ifdef SUNOS4
119 long chrs = 0;
120# else /* !SUNOS4 */
121 /*
122 * *Everyone* else has an int, but SunOS wants long!
123 * This breaks where int != long (alpha)
124 */
125 int chrs = 0;
126# endif /* SUNOS4 */
127
128 (void) ioctl(SHIN, FIONREAD, (ioctl_t) & chrs);
129 if (chrs == 0) {
130 if (Rawmode() < 0)
131 return 0;
132 }
133 }
134#endif /* FIONREAD && !OREO */
135
136 GettingInput = 1;
137 NeedsRedraw = 0;
138 tellwhat = 0;
139
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;
147 }
148 if (HistSaved) {
149 Hist_num = HistSaved;
150 GetHistLine();
151 HistSaved = 0;
152 }
153 if (Expand) {
154 (void) e_up_hist(0);
155 Expand = 0;
156 }
157 Refresh(); /* print the prompt */
158
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
176
177 /* if EOF or error */
178 if ((num = GetNextCommand(&cmdnum, &ch)) != OKCMD) {
179 break;
180 }
181
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 */
187 }
188
189 /* now do the real command */
190 retval = (*CcFuncTbl[cmdnum]) (ch);
191
192 /* save the last command here */
193 LastCmd = cmdnum;
194
195 /* make sure fn is initialized */
196 fn = (retval == CC_COMPLETE_ALL) ? LIST_ALL : LIST;
197
198 /* use any return value */
199 switch (retval) {
200
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... */
213
214 case CC_EOF: /* end of file typed */
215 curchoice = -1;
216 curlen = (int) (LastChar - InputBuf);
217 num = 0;
218 break;
219
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;
225
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;
233
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;
240
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
253 /*
254 * need to print error message in case file
255 * is migrated
256 */
257 if (errno)
258 stderror(ERR_SYSTEM, progname, strerror(errno));
259#else
260 cleanup_until(Origin);
261 break;
262#endif
263 }
264 ch = tch;
265 if (ch == 'y' || ch == ' ') {
266 LastChar = CorrChar; /* Restore the corrected end */
57e3f2b5 267 xprintf("%s", CGETS(6, 2, "yes\n"));
7d8fb588
MS
268 }
269 else {
270 Strcpy(InputBuf, Origin);
271 LastChar = SaveChar;
272 if (ch == 'e') {
57e3f2b5 273 xprintf("%s", CGETS(6, 3, "edit\n"));
7d8fb588
MS
274 *LastChar-- = '\0';
275 Cursor = LastChar;
276 printprompt(3, NULL);
277 ClearLines();
278 ClearDisp();
279 Refresh();
280 cleanup_until(Origin);
281 break;
282 }
283 else if (ch == 'a') {
57e3f2b5 284 xprintf("%s", CGETS(6, 4, "abort\n"));
7d8fb588
MS
285 LastChar = InputBuf; /* Null the current line */
286 Cursor = LastChar;
287 printprompt(0, NULL);
288 Refresh();
289 cleanup_until(Origin);
290 break;
291 }
57e3f2b5 292 xprintf("%s", CGETS(6, 5, "no\n"));
7d8fb588
MS
293 }
294 flush();
295 }
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;
303 }
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();
310 }
311 if (matchval == 0) {
57e3f2b5 312 xprintf("%s", CGETS(6, 6, "No matching command\n"));
7d8fb588 313 } else if (matchval == 2) {
57e3f2b5 314 xprintf("%s", CGETS(6, 7, "Ambiguous command\n"));
7d8fb588
MS
315 }
316 if (NeedsRedraw) {
317 ClearLines();
318 ClearDisp();
319 NeedsRedraw = 0;
320 }
321 Refresh();
322 Argument = 1;
323 DoingArg = 0;
324 if (matchval == 1) {
325 PastBottom();
326 *LastChar++ = '\n';
327 *LastChar = '\0';
328 }
329 curlen = (int) (LastChar - InputBuf);
330 }
331 else
332 PastBottom();
333
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);
339 /*
340 * For continuation lines, we set the prompt to prompt 2
341 */
342 printprompt(1, NULL);
343 }
344 break;
345
346 case CC_CORRECT:
347 if (tenematch(InputBuf, Cursor - InputBuf, SPELL) < 0)
348 SoundBeep(); /* Beep = No match/ambiguous */
349 curlen = Repair();
350 break;
351
352 case CC_CORRECT_L:
353 if (SpellLine(FALSE) < 0)
354 SoundBeep(); /* Beep = No match/ambiguous */
355 curlen = Repair();
356 break;
357
358
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();
388 }
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;
397 }
398 curlen = (int) (LastChar - InputBuf);
399
400
57e3f2b5
SS
401 nr_history_exp = 0;
402 autoexpand = varval(STRautoexpand);
403 if (autoexpand != STRNULL)
404 nr_history_exp += ExpandHistory();
405
406 /* try normal expansion only if no history references were found */
407 if (nr_history_exp == 0 ||
408 Strcmp(autoexpand, STRonlyhistory) != 0) {
409 /*
410 * Modified by Martin Boyer (gamin@ireq-robot.hydro.qc.ca):
411 * A separate variable now controls beeping after
412 * completion, independently of autolisting.
413 */
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))
7d8fb588 420 SoundBeep();
7d8fb588 421 break;
57e3f2b5
SS
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();
428 }
429 else
7d8fb588 430 SoundBeep();
57e3f2b5
SS
431 break;
432 default:
433 if (matchval < 0) { /* Error from tenematch */
434 curchoice = -1;
435 SoundBeep();
436 break;
7d8fb588 437 }
57e3f2b5
SS
438 if (matchbeep && matchbeep->vec != NULL) {
439 if ((Strcmp(*(matchbeep->vec), STRambiguous) == 0 ||
440 Strcmp(*(matchbeep->vec), STRnotunique) == 0))
441 SoundBeep();
442 }
443 else
444 SoundBeep();
445 /*
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.)
450 */
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;
461 }
462 PastBottom();
463 fn = (retval == CC_COMPLETE_ALL) ? LIST_ALL : LIST;
464 (void) tenematch(InputBuf, Cursor-InputBuf, fn);
465 }
466 break;
7d8fb588 467 }
7d8fb588
MS
468 }
469 if (NeedsRedraw) {
470 PastBottom();
471 ClearLines();
472 ClearDisp();
473 NeedsRedraw = 0;
474 }
475 Refresh();
476 Argument = 1;
477 DoingArg = 0;
478 break;
479
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;
490 }
491 curlen = (int) (LastChar - InputBuf);
492 if (curchoice >= 0)
493 curchoice--;
494
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;
503
504
505 case CC_LIST_GLOB:
506 if (tenematch(InputBuf, Cursor - InputBuf, GLOB) < 0)
507 SoundBeep();
508 curlen = Repair();
509 break;
510
511 case CC_EXPAND_GLOB:
512 if (tenematch(InputBuf, Cursor - InputBuf, GLOB_EXPAND) <= 0)
513 SoundBeep(); /* Beep = No match */
514 curlen = Repair();
515 break;
516
517 case CC_NORMALIZE_PATH:
518 if (tenematch(InputBuf, Cursor - InputBuf, PATH_NORMALIZE) <= 0)
519 SoundBeep(); /* Beep = No match */
520 curlen = Repair();
521 break;
522
523 case CC_EXPAND_VARS:
524 if (tenematch(InputBuf, Cursor - InputBuf, VARS_EXPAND) <= 0)
525 SoundBeep(); /* Beep = No match */
526 curlen = Repair();
527 break;
528
529 case CC_NORMALIZE_COMMAND:
530 if (tenematch(InputBuf, Cursor - InputBuf, COMMAND_NORMALIZE) <= 0)
531 SoundBeep(); /* Beep = No match */
532 curlen = Repair();
533 break;
534
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;
545
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;
559
560 case CC_ERROR:
561 default: /* functions we don't know about */
562 if (adrof(STRhighlight)) {
563 ClearLines();
564 ClearDisp();
565 Refresh();
566 }
567 DoingArg = 0;
568 Argument = 1;
569 SoundBeep();
570 flush();
571 curchoice = -1;
572 curlen = (int) (LastChar - InputBuf);
573 break;
574 }
575 }
576 (void) Cookedmode(); /* make sure the tty is set up correctly */
577 GettingInput = 0;
578 flush(); /* flush any buffered output */
579 return num;
580}
581
582void
583PushMacro(Char *str)
584{
585 if (str != NULL && MacroLvl + 1 < MAXMACROLEVELS) {
586 MacroLvl++;
587 KeyMacro[MacroLvl] = str;
588 }
589 else {
590 SoundBeep();
591 flush();
592 }
593}
594
595struct eval1_state
596{
597 Char **evalvec, *evalp;
598};
599
600static void
601eval1_cleanup(void *xstate)
602{
603 struct eval1_state *state;
604
605 state = xstate;
606 evalvec = state->evalvec;
607 evalp = state->evalp;
608 doneinp = 0;
609}
610
611/*
612 * Like eval, only using the current file descriptors
613 */
614static void
615doeval1(Char **v)
616{
617 struct eval1_state state;
618 Char **gv;
619 int gflag;
620
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);
627 }
628 else {
629 gv = NULL;
630 v = copyblk(v);
631 trim(v);
632 }
633 if (gv)
634 cleanup_push(gv, blk_cleanup);
635
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);
645}
646
647static void
648RunCommand(Char *str)
649{
650 Char *cmd[2];
651
652 xputchar('\n'); /* Start on a clean line */
653
654 cmd[0] = str;
655 cmd[1] = NULL;
656
657 (void) Cookedmode();
658 GettingInput = 0;
659
660 doeval1(cmd);
661
662 (void) Rawmode();
663 GettingInput = 1;
664
665 ClearLines();
666 ClearDisp();
667 NeedsRedraw = 0;
668 Refresh();
669}
670
671static int
672GetNextCommand(KEYCMD *cmdnum, Char *ch)
673{
674 KEYCMD cmd = 0;
675 int num;
676
677 while (cmd == 0 || cmd == F_XKEY) {
678 if ((num = GetNextChar(ch)) != 1) { /* if EOF or error */
679 return num;
680 }
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;
692 }
693 else
694#endif /* KANJI */
695 if (MetaNext) {
696 MetaNext = 0;
697 *ch |= META;
698 }
699 /* XXX: This needs to be fixed so that we don't just truncate
700 * the character, we unquote it.
701 */
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;
728 }
729 }
730 if (!AltKeyMap)
731 CurrentKeyMap = CcKeyMap;
732 }
733 *cmdnum = cmd;
734 return OKCMD;
735}
736
737static Char ungetchar;
738static int haveungetchar;
739
740void
741UngetNextChar(Char cp)
742{
743 ungetchar = cp;
744 haveungetchar = 1;
745}
746
747int
748GetNextChar(Char *cp)
749{
750 int num_read;
751 int tried = 0;
752 char cbuf[MB_LEN_MAX];
753 size_t cbp;
754
755 if (haveungetchar) {
756 haveungetchar = 0;
757 *cp = ungetchar;
758 return 1;
759 }
760 for (;;) {
761 if (MacroLvl < 0) {
762 if (!Load_input_line())
763 break;
764 }
765 if (*KeyMacro[MacroLvl] == 0) {
766 MacroLvl--;
767 continue;
768 }
769 *cp = *KeyMacro[MacroLvl]++ & CHAR;
770 if (*KeyMacro[MacroLvl] == 0) { /* Needed for QuoteMode On */
771 MacroLvl--;
772 }
773 return (1);
774 }
775
776 if (Rawmode() < 0) /* make sure the tty is set up correctly */
777 return 0; /* oops: SHIN was closed */
778
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;
801 }
802 }
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;
813 }
814 }
815 break;
816 }
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;
824}
825
826/*
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
834 */
835static int
836SpellLine(int cmdonly)
837{
838 int endflag, matchval;
839 Char *argptr, *OldCursor, *OldLastChar;
840
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;
859 }
57e3f2b5 860 if (!MISMATCH(*argptr) &&
7d8fb588
MS
861 (!cmdonly || starting_a_command(argptr, InputBuf))) {
862#ifdef WINNT_NATIVE
863 /*
864 * This hack avoids correcting drive letter changes
865 */
866 if((Cursor - InputBuf) != 2 || (char)InputBuf[1] != ':')
867#endif /* WINNT_NATIVE */
868 {
869#ifdef HASH_SPELL_CHECK
870 Char save;
871 size_t len = Cursor - InputBuf;
872
873 save = InputBuf[len];
874 InputBuf[len] = '\0';
875 if (find_cmd(InputBuf, 0) != 0) {
876 InputBuf[len] = save;
877 argptr = Cursor;
878 continue;
879 }
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;
892 }
893 }
894 if (LastChar != OldLastChar) {
895 if (argptr < OldCursor)
896 OldCursor += (LastChar - OldLastChar);
897 OldLastChar = LastChar;
898 }
899 }
900 argptr = Cursor;
901 } while (endflag);
902 Cursor = OldCursor;
903 return matchval;
904}
905
906/*
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
913 */
914static int
915CompleteLine(void)
916{
917 int endflag, tmatch;
918 Char *argptr, *OldCursor, *OldLastChar;
919
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;
937 }
57e3f2b5 938 if (!MISMATCH(*argptr) && starting_a_command(argptr, InputBuf)) {
7d8fb588
MS
939 tmatch = tenematch(InputBuf, Cursor - InputBuf, RECOGNIZE);
940 if (tmatch <= 0) {
941 return 0;
942 } else if (tmatch > 1) {
943 return 2;
944 }
945 if (LastChar != OldLastChar) {
946 if (argptr < OldCursor)
947 OldCursor += (LastChar - OldLastChar);
948 OldLastChar = LastChar;
949 }
950 }
951 argptr = Cursor;
952 } while (endflag);
953 Cursor = OldCursor;
954 return 1;
955}
956