/contrib/tcsh/ed.inputl.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 956 lines · 777 code · 78 blank · 101 comment · 231 complexity · 5898836516b8f782dfeaca51a08213ca MD5 · raw file

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