/contrib/tcsh/ed.chared.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 3889 lines · 3609 code · 88 blank · 192 comment · 253 complexity · a2c5a75c5215a6e8990bfe15e981ea72 MD5 · raw file

Large files are truncated click here to view the full file

  1. /* $Header: /p/tcsh/cvsroot/tcsh/ed.chared.c,v 3.98 2010/05/08 00:37:39 christos Exp $ */
  2. /*
  3. * ed.chared.c: Character editing functions.
  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. /*
  34. Bjorn Knutsson @ Thu Jun 24 19:02:17 1999
  35. e_dabbrev_expand() did not do proper completion if quoted spaces were present
  36. in the string being completed. Exemple:
  37. # echo hello\ world
  38. hello world
  39. # echo h<press key bound to dabbrev-expande>
  40. # echo hello\<cursor>
  41. Correct behavior is:
  42. # echo h<press key bound to dabbrev-expande>
  43. # echo hello\ world<cursor>
  44. The same problem occured if spaces were present in a string withing quotation
  45. marks. Example:
  46. # echo "hello world"
  47. hello world
  48. # echo "h<press key bound to dabbrev-expande>
  49. # echo "hello<cursor>
  50. The former problem could be solved with minor modifications of c_preword()
  51. and c_endword(). The latter, however, required a significant rewrite of
  52. c_preword(), since quoted strings must be parsed from start to end to
  53. determine if a given character is inside or outside the quotation marks.
  54. Compare the following two strings:
  55. # echo \"" 'foo \' bar\"
  56. " 'foo \' bar\
  57. # echo '\"" 'foo \' bar\"
  58. \"" foo ' bar"
  59. The only difference between the two echo lines is in the first character
  60. after the echo command. The result is either one or three arguments.
  61. */
  62. #include "sh.h"
  63. RCSID("$tcsh: ed.chared.c,v 3.98 2010/05/08 00:37:39 christos Exp $")
  64. #include "ed.h"
  65. #include "tw.h"
  66. #include "ed.defns.h"
  67. /* #define SDEBUG */
  68. #define TCSHOP_NOP 0x00
  69. #define TCSHOP_DELETE 0x01
  70. #define TCSHOP_INSERT 0x02
  71. #define TCSHOP_CHANGE 0x04
  72. #define CHAR_FWD 0
  73. #define CHAR_BACK 1
  74. /*
  75. * vi word treatment
  76. * from: Gert-Jan Vons <vons@cesar.crbca1.sinet.slb.com>
  77. */
  78. #define C_CLASS_WHITE 1
  79. #define C_CLASS_ALNUM 2
  80. #define C_CLASS_OTHER 3
  81. static Char *InsertPos = InputBuf; /* Where insertion starts */
  82. static Char *ActionPos = 0; /* Where action begins */
  83. static int ActionFlag = TCSHOP_NOP; /* What delayed action to take */
  84. /*
  85. * Word search state
  86. */
  87. static int searchdir = F_UP_SEARCH_HIST; /* Direction of last search */
  88. static struct Strbuf patbuf; /* = Strbuf_INIT; Search target */
  89. /*
  90. * Char search state
  91. */
  92. static int srch_dir = CHAR_FWD; /* Direction of last search */
  93. static Char srch_char = 0; /* Search target */
  94. /* all routines that start with c_ are private to this set of routines */
  95. static void c_alternativ_key_map (int);
  96. void c_insert (int);
  97. void c_delafter (int);
  98. void c_delbefore (int);
  99. static int c_to_class (Char);
  100. static Char *c_prev_word (Char *, Char *, int);
  101. static Char *c_next_word (Char *, Char *, int);
  102. static Char *c_number (Char *, int *, int);
  103. static Char *c_expand (Char *);
  104. static int c_excl (Char *);
  105. static int c_substitute (void);
  106. static void c_delfini (void);
  107. static int c_hmatch (Char *);
  108. static void c_hsetpat (void);
  109. #ifdef COMMENT
  110. static void c_get_word (Char **, Char **);
  111. #endif
  112. static Char *c_preword (Char *, Char *, int, Char *);
  113. static Char *c_nexword (Char *, Char *, int);
  114. static Char *c_endword (Char *, Char *, int, Char *);
  115. static Char *c_eword (Char *, Char *, int);
  116. static void c_push_kill (Char *, Char *);
  117. static void c_save_inputbuf (void);
  118. static CCRETVAL c_search_line (Char *, int);
  119. static CCRETVAL v_repeat_srch (int);
  120. static CCRETVAL e_inc_search (int);
  121. #ifdef notyet
  122. static CCRETVAL e_insert_str (Char *);
  123. #endif
  124. static CCRETVAL v_search (int);
  125. static CCRETVAL v_csearch_fwd (Char, int, int);
  126. static CCRETVAL v_action (int);
  127. static CCRETVAL v_csearch_back (Char, int, int);
  128. static void
  129. c_alternativ_key_map(int state)
  130. {
  131. switch (state) {
  132. case 0:
  133. CurrentKeyMap = CcKeyMap;
  134. break;
  135. case 1:
  136. CurrentKeyMap = CcAltMap;
  137. break;
  138. default:
  139. return;
  140. }
  141. AltKeyMap = (Char) state;
  142. }
  143. void
  144. c_insert(int num)
  145. {
  146. Char *cp;
  147. if (LastChar + num >= InputLim)
  148. return; /* can't go past end of buffer */
  149. if (Cursor < LastChar) { /* if I must move chars */
  150. for (cp = LastChar; cp >= Cursor; cp--)
  151. cp[num] = *cp;
  152. if (Mark && Mark > Cursor)
  153. Mark += num;
  154. }
  155. LastChar += num;
  156. }
  157. void
  158. c_delafter(int num)
  159. {
  160. Char *cp, *kp = NULL;
  161. if (num > LastChar - Cursor)
  162. num = (int) (LastChar - Cursor); /* bounds check */
  163. if (num > 0) { /* if I can delete anything */
  164. if (VImode) {
  165. kp = UndoBuf; /* Set Up for VI undo command */
  166. UndoAction = TCSHOP_INSERT;
  167. UndoSize = num;
  168. UndoPtr = Cursor;
  169. for (cp = Cursor; cp <= LastChar; cp++) {
  170. *kp++ = *cp; /* Save deleted chars into undobuf */
  171. *cp = cp[num];
  172. }
  173. }
  174. else
  175. for (cp = Cursor; cp + num <= LastChar; cp++)
  176. *cp = cp[num];
  177. LastChar -= num;
  178. /* Mark was within the range of the deleted word? */
  179. if (Mark && Mark > Cursor && Mark <= Cursor+num)
  180. Mark = Cursor;
  181. /* Mark after the deleted word? */
  182. else if (Mark && Mark > Cursor)
  183. Mark -= num;
  184. }
  185. #ifdef notdef
  186. else {
  187. /*
  188. * XXX: We don't want to do that. In emacs mode overwrite should be
  189. * sticky. I am not sure how that affects vi mode
  190. */
  191. inputmode = MODE_INSERT;
  192. }
  193. #endif /* notdef */
  194. }
  195. void
  196. c_delbefore(int num) /* delete before dot, with bounds checking */
  197. {
  198. Char *cp, *kp = NULL;
  199. if (num > Cursor - InputBuf)
  200. num = (int) (Cursor - InputBuf); /* bounds check */
  201. if (num > 0) { /* if I can delete anything */
  202. if (VImode) {
  203. kp = UndoBuf; /* Set Up for VI undo command */
  204. UndoAction = TCSHOP_INSERT;
  205. UndoSize = num;
  206. UndoPtr = Cursor - num;
  207. for (cp = Cursor - num; cp <= LastChar; cp++) {
  208. *kp++ = *cp;
  209. *cp = cp[num];
  210. }
  211. }
  212. else
  213. for (cp = Cursor - num; cp + num <= LastChar; cp++)
  214. *cp = cp[num];
  215. LastChar -= num;
  216. Cursor -= num;
  217. /* Mark was within the range of the deleted word? */
  218. if (Mark && Mark > Cursor && Mark <= Cursor+num)
  219. Mark = Cursor;
  220. /* Mark after the deleted word? */
  221. else if (Mark && Mark > Cursor)
  222. Mark -= num;
  223. }
  224. }
  225. static Char *
  226. c_preword(Char *p, Char *low, int n, Char *delim)
  227. {
  228. while (n--) {
  229. Char *prev = low;
  230. Char *new;
  231. while (prev < p) { /* Skip initial non-word chars */
  232. if (!Strchr(delim, *prev) || *(prev-1) == (Char)'\\')
  233. break;
  234. prev++;
  235. }
  236. new = prev;
  237. while (new < p) {
  238. prev = new;
  239. new = c_endword(prev-1, p, 1, delim); /* Skip to next non-word char */
  240. new++; /* Step away from end of word */
  241. while (new <= p) { /* Skip trailing non-word chars */
  242. if (!Strchr(delim, *new) || *(new-1) == (Char)'\\')
  243. break;
  244. new++;
  245. }
  246. }
  247. p = prev; /* Set to previous word start */
  248. }
  249. if (p < low)
  250. p = low;
  251. return (p);
  252. }
  253. /*
  254. * c_to_class() returns the class of the given character.
  255. *
  256. * This is used to make the c_prev_word() and c_next_word() functions
  257. * work like vi's, which classify characters. A word is a sequence of
  258. * characters belonging to the same class, classes being defined as
  259. * follows:
  260. *
  261. * 1/ whitespace
  262. * 2/ alphanumeric chars, + underscore
  263. * 3/ others
  264. */
  265. static int
  266. c_to_class(Char ch)
  267. {
  268. if (Isspace(ch))
  269. return C_CLASS_WHITE;
  270. if (Isdigit(ch) || Isalpha(ch) || ch == '_')
  271. return C_CLASS_ALNUM;
  272. return C_CLASS_OTHER;
  273. }
  274. static Char *
  275. c_prev_word(Char *p, Char *low, int n)
  276. {
  277. p--;
  278. if (!VImode) {
  279. while (n--) {
  280. while ((p >= low) && !isword(*p))
  281. p--;
  282. while ((p >= low) && isword(*p))
  283. p--;
  284. }
  285. /* cp now points to one character before the word */
  286. p++;
  287. if (p < low)
  288. p = low;
  289. /* cp now points where we want it */
  290. return(p);
  291. }
  292. while (n--) {
  293. int c_class;
  294. if (p < low)
  295. break;
  296. /* scan until beginning of current word (may be all whitespace!) */
  297. c_class = c_to_class(*p);
  298. while ((p >= low) && c_class == c_to_class(*p))
  299. p--;
  300. /* if this was a non_whitespace word, we're ready */
  301. if (c_class != C_CLASS_WHITE)
  302. continue;
  303. /* otherwise, move back to beginning of the word just found */
  304. c_class = c_to_class(*p);
  305. while ((p >= low) && c_class == c_to_class(*p))
  306. p--;
  307. }
  308. p++; /* correct overshoot */
  309. return (p);
  310. }
  311. static Char *
  312. c_next_word(Char *p, Char *high, int n)
  313. {
  314. if (!VImode) {
  315. while (n--) {
  316. while ((p < high) && !isword(*p))
  317. p++;
  318. while ((p < high) && isword(*p))
  319. p++;
  320. }
  321. if (p > high)
  322. p = high;
  323. /* p now points where we want it */
  324. return(p);
  325. }
  326. while (n--) {
  327. int c_class;
  328. if (p >= high)
  329. break;
  330. /* scan until end of current word (may be all whitespace!) */
  331. c_class = c_to_class(*p);
  332. while ((p < high) && c_class == c_to_class(*p))
  333. p++;
  334. /* if this was all whitespace, we're ready */
  335. if (c_class == C_CLASS_WHITE)
  336. continue;
  337. /* if we've found white-space at the end of the word, skip it */
  338. while ((p < high) && c_to_class(*p) == C_CLASS_WHITE)
  339. p++;
  340. }
  341. p--; /* correct overshoot */
  342. return (p);
  343. }
  344. static Char *
  345. c_nexword(Char *p, Char *high, int n)
  346. {
  347. while (n--) {
  348. while ((p < high) && !Isspace(*p))
  349. p++;
  350. while ((p < high) && Isspace(*p))
  351. p++;
  352. }
  353. if (p > high)
  354. p = high;
  355. /* p now points where we want it */
  356. return(p);
  357. }
  358. /*
  359. * Expand-History (originally "Magic-Space") code added by
  360. * Ray Moody <ray@gibbs.physics.purdue.edu>
  361. * this is a neat, but odd, addition.
  362. */
  363. /*
  364. * c_number: Ignore character p points to, return number appearing after that.
  365. * A '$' by itself means a big number; "$-" is for negative; '^' means 1.
  366. * Return p pointing to last char used.
  367. */
  368. /*
  369. * dval is the number to subtract from for things like $-3
  370. */
  371. static Char *
  372. c_number(Char *p, int *num, int dval)
  373. {
  374. int i;
  375. int sign = 1;
  376. if (*++p == '^') {
  377. *num = 1;
  378. return(p);
  379. }
  380. if (*p == '$') {
  381. if (*++p != '-') {
  382. *num = INT_MAX; /* Handle $ */
  383. return(--p);
  384. }
  385. sign = -1; /* Handle $- */
  386. ++p;
  387. }
  388. for (i = 0; *p >= '0' && *p <= '9'; i = 10 * i + *p++ - '0')
  389. continue;
  390. *num = (sign < 0 ? dval - i : i);
  391. return(--p);
  392. }
  393. /*
  394. * excl_expand: There is an excl to be expanded to p -- do the right thing
  395. * with it and return a version of p advanced over the expanded stuff. Also,
  396. * update tsh_cur and related things as appropriate...
  397. */
  398. static Char *
  399. c_expand(Char *p)
  400. {
  401. Char *q;
  402. struct Hist *h = Histlist.Hnext;
  403. struct wordent *l;
  404. int i, from, to, dval;
  405. int all_dig;
  406. int been_once = 0;
  407. Char *op = p;
  408. Char *buf;
  409. size_t buf_len;
  410. Char *modbuf;
  411. buf = NULL;
  412. if (!h)
  413. goto excl_err;
  414. excl_sw:
  415. switch (*(q = p + 1)) {
  416. case '^':
  417. buf = expand_lex(&h->Hlex, 1, 1);
  418. break;
  419. case '$':
  420. if ((l = (h->Hlex).prev) != 0)
  421. buf = expand_lex(l->prev->prev, 0, 0);
  422. break;
  423. case '*':
  424. buf = expand_lex(&h->Hlex, 1, INT_MAX);
  425. break;
  426. default:
  427. if (been_once) { /* unknown argument */
  428. /* assume it's a modifier, e.g. !foo:h, and get whole cmd */
  429. buf = expand_lex(&h->Hlex, 0, INT_MAX);
  430. q -= 2;
  431. break;
  432. }
  433. been_once = 1;
  434. if (*q == ':') /* short form: !:arg */
  435. --q;
  436. if (HIST != '\0' && *q != HIST) {
  437. /*
  438. * Search for a space, tab, or colon. See if we have a number (as
  439. * in !1234:xyz). Remember the number.
  440. */
  441. for (i = 0, all_dig = 1;
  442. *q != ' ' && *q != '\t' && *q != ':' && q < Cursor; q++) {
  443. /*
  444. * PWP: !-4 is a valid history argument too, therefore the test
  445. * is if not a digit, or not a - as the first character.
  446. */
  447. if ((*q < '0' || *q > '9') && (*q != '-' || q != p + 1))
  448. all_dig = 0;
  449. else if (*q == '-')
  450. all_dig = 2;/* we are sneeky about this */
  451. else
  452. i = 10 * i + *q - '0';
  453. }
  454. --q;
  455. /*
  456. * If we have a number, search for event i. Otherwise, search for
  457. * a named event (as in !foo). (In this case, I is the length of
  458. * the named event).
  459. */
  460. if (all_dig) {
  461. if (all_dig == 2)
  462. i = -i; /* make it negitive */
  463. if (i < 0) /* if !-4 (for example) */
  464. i = eventno + 1 + i; /* remember: i is < 0 */
  465. for (; h; h = h->Hnext) {
  466. if (h->Hnum == i)
  467. break;
  468. }
  469. }
  470. else {
  471. for (i = (int) (q - p); h; h = h->Hnext) {
  472. if ((l = &h->Hlex) != 0) {
  473. if (!Strncmp(p + 1, l->next->word, (size_t) i))
  474. break;
  475. }
  476. }
  477. }
  478. }
  479. if (!h)
  480. goto excl_err;
  481. if (q[1] == ':' || q[1] == '-' || q[1] == '*' ||
  482. q[1] == '$' || q[1] == '^') { /* get some args */
  483. p = q[1] == ':' ? ++q : q;
  484. /*
  485. * Go handle !foo:*
  486. */
  487. if ((q[1] < '0' || q[1] > '9') &&
  488. q[1] != '-' && q[1] != '$' && q[1] != '^')
  489. goto excl_sw;
  490. /*
  491. * Go handle !foo:$
  492. */
  493. if (q[1] == '$' && (q[2] != '-' || q[3] < '0' || q[3] > '9'))
  494. goto excl_sw;
  495. /*
  496. * Count up the number of words in this event. Store it in dval.
  497. * Dval will be fed to number.
  498. */
  499. dval = 0;
  500. if ((l = h->Hlex.prev) != 0) {
  501. for (l = l->prev; l != h->Hlex.next; l = l->prev, dval++)
  502. continue;
  503. }
  504. if (!dval)
  505. goto excl_err;
  506. if (q[1] == '-')
  507. from = 0;
  508. else
  509. q = c_number(q, &from, dval);
  510. if (q[1] == '-') {
  511. ++q;
  512. if ((q[1] < '0' || q[1] > '9') && q[1] != '$')
  513. to = dval - 1;
  514. else
  515. q = c_number(q, &to, dval);
  516. }
  517. else if (q[1] == '*') {
  518. ++q;
  519. to = INT_MAX;
  520. }
  521. else {
  522. to = from;
  523. }
  524. if (from < 0 || to < from)
  525. goto excl_err;
  526. buf = expand_lex(&h->Hlex, from, to);
  527. }
  528. else /* get whole cmd */
  529. buf = expand_lex(&h->Hlex, 0, INT_MAX);
  530. break;
  531. }
  532. if (buf == NULL)
  533. buf = SAVE("");
  534. /*
  535. * Apply modifiers, if any.
  536. */
  537. if (q[1] == ':') {
  538. modbuf = buf;
  539. while (q[1] == ':' && modbuf != NULL) {
  540. switch (q[2]) {
  541. case 'r':
  542. case 'e':
  543. case 'h':
  544. case 't':
  545. case 'q':
  546. case 'x':
  547. case 'u':
  548. case 'l':
  549. if ((modbuf = domod(buf, (int) q[2])) != NULL) {
  550. xfree(buf);
  551. buf = modbuf;
  552. }
  553. ++q;
  554. break;
  555. case 'a':
  556. case 'g':
  557. /* Not implemented; this needs to be done before expanding
  558. * lex. We don't have the words available to us anymore.
  559. */
  560. ++q;
  561. break;
  562. case 'p':
  563. /* Ok */
  564. ++q;
  565. break;
  566. case '\0':
  567. break;
  568. default:
  569. ++q;
  570. break;
  571. }
  572. if (q[1])
  573. ++q;
  574. }
  575. }
  576. buf_len = Strlen(buf);
  577. /*
  578. * Now replace the text from op to q inclusive with the text from buf.
  579. */
  580. q++;
  581. /*
  582. * Now replace text non-inclusively like a real CS major!
  583. */
  584. if (LastChar + buf_len - (q - op) >= InputLim)
  585. goto excl_err;
  586. (void) memmove(op + buf_len, q, (LastChar - q) * sizeof(Char));
  587. LastChar += buf_len - (q - op);
  588. Cursor += buf_len - (q - op);
  589. (void) memcpy(op, buf, buf_len * sizeof(Char));
  590. *LastChar = '\0';
  591. xfree(buf);
  592. return op + buf_len;
  593. excl_err:
  594. xfree(buf);
  595. SoundBeep();
  596. return(op + 1);
  597. }
  598. /*
  599. * c_excl: An excl has been found at point p -- back up and find some white
  600. * space (or the beginning of the buffer) and properly expand all the excl's
  601. * from there up to the current cursor position. We also avoid (trying to)
  602. * expanding '>!'
  603. * Returns number of expansions attempted (doesn't matter whether they succeeded
  604. * or not).
  605. */
  606. static int
  607. c_excl(Char *p)
  608. {
  609. int i;
  610. Char *q;
  611. int nr_exp;
  612. /*
  613. * if />[SPC TAB]*![SPC TAB]/, back up p to just after the >. otherwise,
  614. * back p up to just before the current word.
  615. */
  616. if ((p[1] == ' ' || p[1] == '\t') &&
  617. (p[-1] == ' ' || p[-1] == '\t' || p[-1] == '>')) {
  618. for (q = p - 1; q > InputBuf && (*q == ' ' || *q == '\t'); --q)
  619. continue;
  620. if (*q == '>')
  621. ++p;
  622. }
  623. else {
  624. while (*p != ' ' && *p != '\t' && p > InputBuf)
  625. --p;
  626. }
  627. /*
  628. * Forever: Look for history char. (Stop looking when we find the cursor.)
  629. * Count backslashes. If odd, skip history char. Expand if even number of
  630. * backslashes.
  631. */
  632. nr_exp = 0;
  633. for (;;) {
  634. if (HIST != '\0')
  635. while (*p != HIST && p < Cursor)
  636. ++p;
  637. for (i = 1; (p - i) >= InputBuf && p[-i] == '\\'; i++)
  638. continue;
  639. if (i % 2 == 0)
  640. ++p;
  641. if (p >= Cursor) /* all done */
  642. return nr_exp;
  643. if (i % 2 == 1) {
  644. p = c_expand(p);
  645. ++nr_exp;
  646. }
  647. }
  648. }
  649. static int
  650. c_substitute(void)
  651. {
  652. Char *p;
  653. int nr_exp;
  654. /*
  655. * Start p out one character before the cursor. Move it backwards looking
  656. * for white space, the beginning of the line, or a history character.
  657. */
  658. for (p = Cursor - 1;
  659. p > InputBuf && *p != ' ' && *p != '\t' && *p && *p != HIST; --p)
  660. continue;
  661. /*
  662. * If we found a history character, go expand it.
  663. */
  664. if (HIST != '\0' && *p == HIST)
  665. nr_exp = c_excl(p);
  666. else
  667. nr_exp = 0;
  668. Refresh();
  669. return nr_exp;
  670. }
  671. static void
  672. c_delfini(void) /* Finish up delete action */
  673. {
  674. int Size;
  675. if (ActionFlag & TCSHOP_INSERT)
  676. c_alternativ_key_map(0);
  677. ActionFlag = TCSHOP_NOP;
  678. if (ActionPos == 0)
  679. return;
  680. UndoAction = TCSHOP_INSERT;
  681. if (Cursor > ActionPos) {
  682. Size = (int) (Cursor-ActionPos);
  683. c_delbefore(Size);
  684. RefCursor();
  685. }
  686. else if (Cursor < ActionPos) {
  687. Size = (int)(ActionPos-Cursor);
  688. c_delafter(Size);
  689. }
  690. else {
  691. Size = 1;
  692. c_delafter(Size);
  693. }
  694. UndoPtr = Cursor;
  695. UndoSize = Size;
  696. }
  697. static Char *
  698. c_endword(Char *p, Char *high, int n, Char *delim)
  699. {
  700. Char inquote = 0;
  701. p++;
  702. while (n--) {
  703. while (p < high) { /* Skip non-word chars */
  704. if (!Strchr(delim, *p) || *(p-1) == (Char)'\\')
  705. break;
  706. p++;
  707. }
  708. while (p < high) { /* Skip string */
  709. if ((*p == (Char)'\'' || *p == (Char)'"')) { /* Quotation marks? */
  710. if (inquote || *(p-1) != (Char)'\\') { /* Should it be honored? */
  711. if (inquote == 0) inquote = *p;
  712. else if (inquote == *p) inquote = 0;
  713. }
  714. }
  715. /* Break if unquoted non-word char */
  716. if (!inquote && Strchr(delim, *p) && *(p-1) != (Char)'\\')
  717. break;
  718. p++;
  719. }
  720. }
  721. p--;
  722. return(p);
  723. }
  724. static Char *
  725. c_eword(Char *p, Char *high, int n)
  726. {
  727. p++;
  728. while (n--) {
  729. while ((p < high) && Isspace(*p))
  730. p++;
  731. if (isword(*p))
  732. while ((p < high) && isword(*p))
  733. p++;
  734. else
  735. while ((p < high) && !(Isspace(*p) || isword(*p)))
  736. p++;
  737. }
  738. p--;
  739. return(p);
  740. }
  741. /* Set the max length of the kill ring */
  742. void
  743. SetKillRing(int max)
  744. {
  745. CStr *new;
  746. int count, i, j;
  747. if (max < 1)
  748. max = 1; /* no ring, but always one buffer */
  749. if (max == KillRingMax)
  750. return;
  751. new = xcalloc(max, sizeof(CStr));
  752. if (KillRing != NULL) {
  753. if (KillRingLen != 0) {
  754. if (max >= KillRingLen) {
  755. count = KillRingLen;
  756. j = KillPos;
  757. } else {
  758. count = max;
  759. j = (KillPos - count + KillRingLen) % KillRingLen;
  760. }
  761. for (i = 0; i < KillRingLen; i++) {
  762. if (i < count) /* copy latest */
  763. new[i] = KillRing[j];
  764. else /* free the others */
  765. xfree(KillRing[j].buf);
  766. j = (j + 1) % KillRingLen;
  767. }
  768. KillRingLen = count;
  769. KillPos = count % max;
  770. YankPos = count - 1;
  771. }
  772. xfree(KillRing);
  773. }
  774. KillRing = new;
  775. KillRingMax = max;
  776. }
  777. /* Push string from start upto (but not including) end onto kill ring */
  778. static void
  779. c_push_kill(Char *start, Char *end)
  780. {
  781. CStr save, *pos;
  782. Char *dp, *cp, *kp;
  783. int len = end - start, i, j, k;
  784. /* Check for duplicates? */
  785. if (KillRingLen > 0 && (dp = varval(STRkilldup)) != STRNULL) {
  786. YankPos = (KillPos - 1 + KillRingLen) % KillRingLen;
  787. if (eq(dp, STRerase)) { /* erase earlier one (actually move up) */
  788. j = YankPos;
  789. for (i = 0; i < KillRingLen; i++) {
  790. if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
  791. KillRing[j].buf[len] == '\0') {
  792. save = KillRing[j];
  793. for ( ; i > 0; i--) {
  794. k = j;
  795. j = (j + 1) % KillRingLen;
  796. KillRing[k] = KillRing[j];
  797. }
  798. KillRing[j] = save;
  799. return;
  800. }
  801. j = (j - 1 + KillRingLen) % KillRingLen;
  802. }
  803. } else if (eq(dp, STRall)) { /* skip if any earlier */
  804. for (i = 0; i < KillRingLen; i++)
  805. if (Strncmp(KillRing[i].buf, start, (size_t) len) == 0 &&
  806. KillRing[i].buf[len] == '\0')
  807. return;
  808. } else if (eq(dp, STRprev)) { /* skip if immediately previous */
  809. j = YankPos;
  810. if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
  811. KillRing[j].buf[len] == '\0')
  812. return;
  813. }
  814. }
  815. /* No duplicate, go ahead and push */
  816. len++; /* need space for '\0' */
  817. YankPos = KillPos;
  818. if (KillRingLen < KillRingMax)
  819. KillRingLen++;
  820. pos = &KillRing[KillPos];
  821. KillPos = (KillPos + 1) % KillRingMax;
  822. if (pos->len < len) {
  823. pos->buf = xrealloc(pos->buf, len * sizeof(Char));
  824. pos->len = len;
  825. }
  826. cp = start;
  827. kp = pos->buf;
  828. while (cp < end)
  829. *kp++ = *cp++;
  830. *kp = '\0';
  831. }
  832. /* Save InputBuf etc in SavedBuf etc for restore after cmd exec */
  833. static void
  834. c_save_inputbuf()
  835. {
  836. SavedBuf.len = 0;
  837. Strbuf_append(&SavedBuf, InputBuf);
  838. Strbuf_terminate(&SavedBuf);
  839. LastSaved = LastChar - InputBuf;
  840. CursSaved = Cursor - InputBuf;
  841. HistSaved = Hist_num;
  842. RestoreSaved = 1;
  843. }
  844. CCRETVAL
  845. GetHistLine()
  846. {
  847. struct Hist *hp;
  848. int h;
  849. if (Hist_num == 0) { /* if really the current line */
  850. if (HistBuf.s != NULL)
  851. copyn(InputBuf, HistBuf.s, INBUFSIZE);/*FIXBUF*/
  852. else
  853. *InputBuf = '\0';
  854. LastChar = InputBuf + HistBuf.len;
  855. #ifdef KSHVI
  856. if (VImode)
  857. Cursor = InputBuf;
  858. else
  859. #endif /* KSHVI */
  860. Cursor = LastChar;
  861. return(CC_REFRESH);
  862. }
  863. hp = Histlist.Hnext;
  864. if (hp == NULL)
  865. return(CC_ERROR);
  866. for (h = 1; h < Hist_num; h++) {
  867. if ((hp->Hnext) == NULL) {
  868. Hist_num = h;
  869. return(CC_ERROR);
  870. }
  871. hp = hp->Hnext;
  872. }
  873. if (HistLit && hp->histline) {
  874. copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
  875. CurrentHistLit = 1;
  876. }
  877. else {
  878. Char *p;
  879. p = sprlex(&hp->Hlex);
  880. copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
  881. xfree(p);
  882. CurrentHistLit = 0;
  883. }
  884. LastChar = Strend(InputBuf);
  885. if (LastChar > InputBuf) {
  886. if (LastChar[-1] == '\n')
  887. LastChar--;
  888. #if 0
  889. if (LastChar[-1] == ' ')
  890. LastChar--;
  891. #endif
  892. if (LastChar < InputBuf)
  893. LastChar = InputBuf;
  894. }
  895. #ifdef KSHVI
  896. if (VImode)
  897. Cursor = InputBuf;
  898. else
  899. #endif /* KSHVI */
  900. Cursor = LastChar;
  901. return(CC_REFRESH);
  902. }
  903. static CCRETVAL
  904. c_search_line(Char *pattern, int dir)
  905. {
  906. Char *cp;
  907. size_t len;
  908. len = Strlen(pattern);
  909. if (dir == F_UP_SEARCH_HIST) {
  910. for (cp = Cursor; cp >= InputBuf; cp--)
  911. if (Strncmp(cp, pattern, len) == 0 ||
  912. Gmatch(cp, pattern)) {
  913. Cursor = cp;
  914. return(CC_NORM);
  915. }
  916. return(CC_ERROR);
  917. } else {
  918. for (cp = Cursor; *cp != '\0' && cp < InputLim; cp++)
  919. if (Strncmp(cp, pattern, len) == 0 ||
  920. Gmatch(cp, pattern)) {
  921. Cursor = cp;
  922. return(CC_NORM);
  923. }
  924. return(CC_ERROR);
  925. }
  926. }
  927. static CCRETVAL
  928. e_inc_search(int dir)
  929. {
  930. static const Char STRfwd[] = { 'f', 'w', 'd', '\0' },
  931. STRbck[] = { 'b', 'c', 'k', '\0' };
  932. static Char pchar = ':'; /* ':' = normal, '?' = failed */
  933. static Char endcmd[2];
  934. const Char *cp;
  935. Char ch,
  936. *oldCursor = Cursor,
  937. oldpchar = pchar;
  938. CCRETVAL ret = CC_NORM;
  939. int oldHist_num = Hist_num,
  940. oldpatlen = patbuf.len,
  941. newdir = dir,
  942. done, redo;
  943. if (LastChar + sizeof(STRfwd)/sizeof(Char) + 2 + patbuf.len >= InputLim)
  944. return(CC_ERROR);
  945. for (;;) {
  946. if (patbuf.len == 0) { /* first round */
  947. pchar = ':';
  948. Strbuf_append1(&patbuf, '*');
  949. }
  950. done = redo = 0;
  951. *LastChar++ = '\n';
  952. for (cp = newdir == F_UP_SEARCH_HIST ? STRbck : STRfwd;
  953. *cp; *LastChar++ = *cp++)
  954. continue;
  955. *LastChar++ = pchar;
  956. for (cp = &patbuf.s[1]; cp < &patbuf.s[patbuf.len];
  957. *LastChar++ = *cp++)
  958. continue;
  959. *LastChar = '\0';
  960. if (adrof(STRhighlight) && pchar == ':') {
  961. /* if the no-glob-search patch is applied, remove the - 1 below */
  962. IncMatchLen = patbuf.len - 1;
  963. ClearLines();
  964. ClearDisp();
  965. }
  966. Refresh();
  967. if (GetNextChar(&ch) != 1)
  968. return(e_send_eof(0));
  969. switch (ch > NT_NUM_KEYS
  970. ? F_INSERT : CurrentKeyMap[(unsigned char) ch]) {
  971. case F_INSERT:
  972. case F_DIGIT:
  973. case F_MAGIC_SPACE:
  974. if (LastChar + 1 >= InputLim) /*FIXBUF*/
  975. SoundBeep();
  976. else {
  977. Strbuf_append1(&patbuf, ch);
  978. *LastChar++ = ch;
  979. *LastChar = '\0';
  980. Refresh();
  981. }
  982. break;
  983. case F_INC_FWD:
  984. newdir = F_DOWN_SEARCH_HIST;
  985. redo++;
  986. break;
  987. case F_INC_BACK:
  988. newdir = F_UP_SEARCH_HIST;
  989. redo++;
  990. break;
  991. case F_DELPREV:
  992. if (patbuf.len > 1)
  993. done++;
  994. else
  995. SoundBeep();
  996. break;
  997. default:
  998. switch (ASC(ch)) {
  999. case 0007: /* ^G: Abort */
  1000. ret = CC_ERROR;
  1001. done++;
  1002. break;
  1003. case 0027: /* ^W: Append word */
  1004. /* No can do if globbing characters in pattern */
  1005. for (cp = &patbuf.s[1]; ; cp++)
  1006. if (cp >= &patbuf.s[patbuf.len]) {
  1007. Cursor += patbuf.len - 1;
  1008. cp = c_next_word(Cursor, LastChar, 1);
  1009. while (Cursor < cp && *Cursor != '\n') {
  1010. if (LastChar + 1 >= InputLim) {/*FIXBUF*/
  1011. SoundBeep();
  1012. break;
  1013. }
  1014. Strbuf_append1(&patbuf, *Cursor);
  1015. *LastChar++ = *Cursor++;
  1016. }
  1017. Cursor = oldCursor;
  1018. *LastChar = '\0';
  1019. Refresh();
  1020. break;
  1021. } else if (isglob(*cp)) {
  1022. SoundBeep();
  1023. break;
  1024. }
  1025. break;
  1026. default: /* Terminate and execute cmd */
  1027. endcmd[0] = ch;
  1028. PushMacro(endcmd);
  1029. /*FALLTHROUGH*/
  1030. case 0033: /* ESC: Terminate */
  1031. ret = CC_REFRESH;
  1032. done++;
  1033. break;
  1034. }
  1035. break;
  1036. }
  1037. while (LastChar > InputBuf && *LastChar != '\n')
  1038. *LastChar-- = '\0';
  1039. *LastChar = '\0';
  1040. if (!done) {
  1041. /* Can't search if unmatched '[' */
  1042. for (cp = &patbuf.s[patbuf.len - 1], ch = ']'; cp > patbuf.s; cp--)
  1043. if (*cp == '[' || *cp == ']') {
  1044. ch = *cp;
  1045. break;
  1046. }
  1047. if (patbuf.len > 1 && ch != '[') {
  1048. if (redo && newdir == dir) {
  1049. if (pchar == '?') { /* wrap around */
  1050. Hist_num = newdir == F_UP_SEARCH_HIST ? 0 : INT_MAX;
  1051. if (GetHistLine() == CC_ERROR)
  1052. /* Hist_num was fixed by first call */
  1053. (void) GetHistLine();
  1054. Cursor = newdir == F_UP_SEARCH_HIST ?
  1055. LastChar : InputBuf;
  1056. } else
  1057. Cursor += newdir == F_UP_SEARCH_HIST ? -1 : 1;
  1058. }
  1059. Strbuf_append1(&patbuf, '*');
  1060. Strbuf_terminate(&patbuf);
  1061. if (Cursor < InputBuf || Cursor > LastChar ||
  1062. (ret = c_search_line(&patbuf.s[1], newdir)) == CC_ERROR) {
  1063. LastCmd = (KEYCMD) newdir; /* avoid c_hsetpat */
  1064. ret = newdir == F_UP_SEARCH_HIST ?
  1065. e_up_search_hist(0) : e_down_search_hist(0);
  1066. if (ret != CC_ERROR) {
  1067. Cursor = newdir == F_UP_SEARCH_HIST ?
  1068. LastChar : InputBuf;
  1069. (void) c_search_line(&patbuf.s[1], newdir);
  1070. }
  1071. }
  1072. patbuf.s[--patbuf.len] = '\0';
  1073. if (ret == CC_ERROR) {
  1074. SoundBeep();
  1075. if (Hist_num != oldHist_num) {
  1076. Hist_num = oldHist_num;
  1077. if (GetHistLine() == CC_ERROR)
  1078. return(CC_ERROR);
  1079. }
  1080. Cursor = oldCursor;
  1081. pchar = '?';
  1082. } else {
  1083. pchar = ':';
  1084. }
  1085. }
  1086. ret = e_inc_search(newdir);
  1087. if (ret == CC_ERROR && pchar == '?' && oldpchar == ':') {
  1088. /* break abort of failed search at last non-failed */
  1089. ret = CC_NORM;
  1090. }
  1091. }
  1092. if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
  1093. /* restore on normal return or error exit */
  1094. pchar = oldpchar;
  1095. patbuf.len = oldpatlen;
  1096. if (Hist_num != oldHist_num) {
  1097. Hist_num = oldHist_num;
  1098. if (GetHistLine() == CC_ERROR)
  1099. return(CC_ERROR);
  1100. }
  1101. Cursor = oldCursor;
  1102. if (ret == CC_ERROR)
  1103. Refresh();
  1104. }
  1105. if (done || ret != CC_NORM)
  1106. return(ret);
  1107. }
  1108. }
  1109. static CCRETVAL
  1110. v_search(int dir)
  1111. {
  1112. struct Strbuf tmpbuf = Strbuf_INIT;
  1113. Char ch;
  1114. Char *oldbuf;
  1115. Char *oldlc, *oldc;
  1116. cleanup_push(&tmpbuf, Strbuf_cleanup);
  1117. oldbuf = Strsave(InputBuf);
  1118. cleanup_push(oldbuf, xfree);
  1119. oldlc = LastChar;
  1120. oldc = Cursor;
  1121. Strbuf_append1(&tmpbuf, '*');
  1122. InputBuf[0] = '\0';
  1123. LastChar = InputBuf;
  1124. Cursor = InputBuf;
  1125. searchdir = dir;
  1126. c_insert(2); /* prompt + '\n' */
  1127. *Cursor++ = '\n';
  1128. *Cursor++ = dir == F_UP_SEARCH_HIST ? '?' : '/';
  1129. Refresh();
  1130. for (ch = 0;ch == 0;) {
  1131. if (GetNextChar(&ch) != 1) {
  1132. cleanup_until(&tmpbuf);
  1133. return(e_send_eof(0));
  1134. }
  1135. switch (ASC(ch)) {
  1136. case 0010: /* Delete and backspace */
  1137. case 0177:
  1138. if (tmpbuf.len > 1) {
  1139. *Cursor-- = '\0';
  1140. LastChar = Cursor;
  1141. tmpbuf.len--;
  1142. }
  1143. else {
  1144. copyn(InputBuf, oldbuf, INBUFSIZE);/*FIXBUF*/
  1145. LastChar = oldlc;
  1146. Cursor = oldc;
  1147. cleanup_until(&tmpbuf);
  1148. return(CC_REFRESH);
  1149. }
  1150. Refresh();
  1151. ch = 0;
  1152. break;
  1153. case 0033: /* ESC */
  1154. #ifdef IS_ASCII
  1155. case '\r': /* Newline */
  1156. case '\n':
  1157. #else
  1158. case '\012': /* ASCII Line feed */
  1159. case '\015': /* ASCII (or EBCDIC) Return */
  1160. #endif
  1161. break;
  1162. default:
  1163. Strbuf_append1(&tmpbuf, ch);
  1164. *Cursor++ = ch;
  1165. LastChar = Cursor;
  1166. Refresh();
  1167. ch = 0;
  1168. break;
  1169. }
  1170. }
  1171. cleanup_until(oldbuf);
  1172. if (tmpbuf.len == 1) {
  1173. /*
  1174. * Use the old pattern, but wild-card it.
  1175. */
  1176. if (patbuf.len == 0) {
  1177. InputBuf[0] = '\0';
  1178. LastChar = InputBuf;
  1179. Cursor = InputBuf;
  1180. Refresh();
  1181. cleanup_until(&tmpbuf);
  1182. return(CC_ERROR);
  1183. }
  1184. if (patbuf.s[0] != '*') {
  1185. oldbuf = Strsave(patbuf.s);
  1186. patbuf.len = 0;
  1187. Strbuf_append1(&patbuf, '*');
  1188. Strbuf_append(&patbuf, oldbuf);
  1189. xfree(oldbuf);
  1190. Strbuf_append1(&patbuf, '*');
  1191. Strbuf_terminate(&patbuf);
  1192. }
  1193. }
  1194. else {
  1195. Strbuf_append1(&tmpbuf, '*');
  1196. Strbuf_terminate(&tmpbuf);
  1197. patbuf.len = 0;
  1198. Strbuf_append(&patbuf, tmpbuf.s);
  1199. Strbuf_terminate(&patbuf);
  1200. }
  1201. cleanup_until(&tmpbuf);
  1202. LastCmd = (KEYCMD) dir; /* avoid c_hsetpat */
  1203. Cursor = LastChar = InputBuf;
  1204. if ((dir == F_UP_SEARCH_HIST ? e_up_search_hist(0) :
  1205. e_down_search_hist(0)) == CC_ERROR) {
  1206. Refresh();
  1207. return(CC_ERROR);
  1208. }
  1209. else {
  1210. if (ASC(ch) == 0033) {
  1211. Refresh();
  1212. *LastChar++ = '\n';
  1213. *LastChar = '\0';
  1214. PastBottom();
  1215. return(CC_NEWLINE);
  1216. }
  1217. else
  1218. return(CC_REFRESH);
  1219. }
  1220. }
  1221. /*
  1222. * semi-PUBLIC routines. Any routine that is of type CCRETVAL is an
  1223. * entry point, called from the CcKeyMap indirected into the
  1224. * CcFuncTbl array.
  1225. */
  1226. /*ARGSUSED*/
  1227. CCRETVAL
  1228. v_cmd_mode(Char c)
  1229. {
  1230. USE(c);
  1231. InsertPos = 0;
  1232. ActionFlag = TCSHOP_NOP; /* [Esc] cancels pending action */
  1233. ActionPos = 0;
  1234. DoingArg = 0;
  1235. if (UndoPtr > Cursor)
  1236. UndoSize = (int)(UndoPtr - Cursor);
  1237. else
  1238. UndoSize = (int)(Cursor - UndoPtr);
  1239. inputmode = MODE_INSERT;
  1240. c_alternativ_key_map(1);
  1241. #ifdef notdef
  1242. /*
  1243. * We don't want to move the cursor, because all the editing
  1244. * commands don't include the character under the cursor.
  1245. */
  1246. if (Cursor > InputBuf)
  1247. Cursor--;
  1248. #endif
  1249. RefCursor();
  1250. return(CC_NORM);
  1251. }
  1252. /*ARGSUSED*/
  1253. CCRETVAL
  1254. e_unassigned(Char c)
  1255. { /* bound to keys that arn't really assigned */
  1256. USE(c);
  1257. SoundBeep();
  1258. flush();
  1259. return(CC_NORM);
  1260. }
  1261. #ifdef notyet
  1262. static CCRETVAL
  1263. e_insert_str(Char *c)
  1264. {
  1265. int i, n;
  1266. n = Strlen(c);
  1267. if (LastChar + Argument * n >= InputLim)
  1268. return(CC_ERROR); /* end of buffer space */
  1269. if (inputmode != MODE_INSERT) {
  1270. c_delafter(Argument * Strlen(c));
  1271. }
  1272. c_insert(Argument * n);
  1273. while (Argument--) {
  1274. for (i = 0; i < n; i++)
  1275. *Cursor++ = c[i];
  1276. }
  1277. Refresh();
  1278. return(CC_NORM);
  1279. }
  1280. #endif
  1281. CCRETVAL
  1282. e_insert(Char c)
  1283. {
  1284. #ifndef SHORT_STRINGS
  1285. c &= ASCII; /* no meta chars ever */
  1286. #endif
  1287. if (!c)
  1288. return(CC_ERROR); /* no NULs in the input ever!! */
  1289. if (LastChar + Argument >= InputLim)
  1290. return(CC_ERROR); /* end of buffer space */
  1291. if (Argument == 1) { /* How was this optimized ???? */
  1292. if (inputmode != MODE_INSERT) {
  1293. UndoBuf[UndoSize++] = *Cursor;
  1294. UndoBuf[UndoSize] = '\0';
  1295. c_delafter(1); /* Do NOT use the saving ONE */
  1296. }
  1297. c_insert(1);
  1298. *Cursor++ = (Char) c;
  1299. DoingArg = 0; /* just in case */
  1300. RefPlusOne(1); /* fast refresh for one char. */
  1301. }
  1302. else {
  1303. if (inputmode != MODE_INSERT) {
  1304. int i;
  1305. for(i = 0; i < Argument; i++)
  1306. UndoBuf[UndoSize++] = *(Cursor + i);
  1307. UndoBuf[UndoSize] = '\0';
  1308. c_delafter(Argument); /* Do NOT use the saving ONE */
  1309. }
  1310. c_insert(Argument);
  1311. while (Argument--)
  1312. *Cursor++ = (Char) c;
  1313. Refresh();
  1314. }
  1315. if (inputmode == MODE_REPLACE_1)
  1316. (void) v_cmd_mode(0);
  1317. return(CC_NORM);
  1318. }
  1319. int
  1320. InsertStr(Char *s) /* insert ASCIZ s at cursor (for complete) */
  1321. {
  1322. int len;
  1323. if ((len = (int) Strlen(s)) <= 0)
  1324. return -1;
  1325. if (LastChar + len >= InputLim)
  1326. return -1; /* end of buffer space */
  1327. c_insert(len);
  1328. while (len--)
  1329. *Cursor++ = *s++;
  1330. return 0;
  1331. }
  1332. void
  1333. DeleteBack(int n) /* delete the n characters before . */
  1334. {
  1335. if (n <= 0)
  1336. return;
  1337. if (Cursor >= &InputBuf[n]) {
  1338. c_delbefore(n); /* delete before dot */
  1339. }
  1340. }
  1341. CCRETVAL
  1342. e_digit(Char c) /* gray magic here */
  1343. {
  1344. if (!Isdigit(c))
  1345. return(CC_ERROR); /* no NULs in the input ever!! */
  1346. if (DoingArg) { /* if doing an arg, add this in... */
  1347. if (LastCmd == F_ARGFOUR) /* if last command was ^U */
  1348. Argument = c - '0';
  1349. else {
  1350. if (Argument > 1000000)
  1351. return CC_ERROR;
  1352. Argument = (Argument * 10) + (c - '0');
  1353. }
  1354. return(CC_ARGHACK);
  1355. }
  1356. else {
  1357. if (LastChar + 1 >= InputLim)
  1358. return CC_ERROR; /* end of buffer space */
  1359. if (inputmode != MODE_INSERT) {
  1360. UndoBuf[UndoSize++] = *Cursor;
  1361. UndoBuf[UndoSize] = '\0';
  1362. c_delafter(1); /* Do NOT use the saving ONE */
  1363. }
  1364. c_insert(1);
  1365. *Cursor++ = (Char) c;
  1366. DoingArg = 0; /* just in case */
  1367. RefPlusOne(1); /* fast refresh for one char. */
  1368. }
  1369. return(CC_NORM);
  1370. }
  1371. CCRETVAL
  1372. e_argdigit(Char c) /* for ESC-n */
  1373. {
  1374. #ifdef IS_ASCII
  1375. c &= ASCII;
  1376. #else
  1377. c = CTL_ESC(ASC(c) & ASCII); /* stripping for EBCDIC done the ASCII way */
  1378. #endif
  1379. if (!Isdigit(c))
  1380. return(CC_ERROR); /* no NULs in the input ever!! */
  1381. if (DoingArg) { /* if doing an arg, add this in... */
  1382. if (Argument > 1000000)
  1383. return CC_ERROR;
  1384. Argument = (Argument * 10) + (c - '0');
  1385. }
  1386. else { /* else starting an argument */
  1387. Argument = c - '0';
  1388. DoingArg = 1;
  1389. }
  1390. return(CC_ARGHACK);
  1391. }
  1392. CCRETVAL
  1393. v_zero(Char c) /* command mode 0 for vi */
  1394. {
  1395. if (DoingArg) { /* if doing an arg, add this in... */
  1396. if (Argument > 1000000)
  1397. return CC_ERROR;
  1398. Argument = (Argument * 10) + (c - '0');
  1399. return(CC_ARGHACK);
  1400. }
  1401. else { /* else starting an argument */
  1402. Cursor = InputBuf;
  1403. if (ActionFlag & TCSHOP_DELETE) {
  1404. c_delfini();
  1405. return(CC_REFRESH);
  1406. }
  1407. RefCursor(); /* move the cursor */
  1408. return(CC_NORM);
  1409. }
  1410. }
  1411. /*ARGSUSED*/
  1412. CCRETVAL
  1413. e_newline(Char c)
  1414. { /* always ignore argument */
  1415. USE(c);
  1416. if (adrof(STRhighlight) && MarkIsSet) {
  1417. MarkIsSet = 0;
  1418. ClearLines();
  1419. ClearDisp();
  1420. Refresh();
  1421. }
  1422. MarkIsSet = 0;
  1423. /* PastBottom(); NOW done in ed.inputl.c */
  1424. *LastChar++ = '\n'; /* for the benefit of CSH */
  1425. *LastChar = '\0'; /* just in case */
  1426. if (VImode)
  1427. InsertPos = InputBuf; /* Reset editing position */
  1428. return(CC_NEWLINE);
  1429. }
  1430. /*ARGSUSED*/
  1431. CCRETVAL
  1432. e_newline_hold(Char c)
  1433. {
  1434. USE(c);
  1435. c_save_inputbuf();
  1436. HistSaved = 0;
  1437. *LastChar++ = '\n'; /* for the benefit of CSH */
  1438. *LastChar = '\0'; /* just in case */
  1439. return(CC_NEWLINE);
  1440. }
  1441. /*ARGSUSED*/
  1442. CCRETVAL
  1443. e_newline_down_hist(Char c)
  1444. {
  1445. USE(c);
  1446. if (Hist_num > 1) {
  1447. HistSaved = Hist_num;
  1448. }
  1449. *LastChar++ = '\n'; /* for the benefit of CSH */
  1450. *LastChar = '\0'; /* just in case */
  1451. return(CC_NEWLINE);
  1452. }
  1453. /*ARGSUSED*/
  1454. CCRETVAL
  1455. e_send_eof(Char c)
  1456. { /* for when ^D is ONLY send-eof */
  1457. USE(c);
  1458. PastBottom();
  1459. *LastChar = '\0'; /* just in case */
  1460. return(CC_EOF);
  1461. }
  1462. /*ARGSUSED*/
  1463. CCRETVAL
  1464. e_complete(Char c)
  1465. {
  1466. USE(c);
  1467. *LastChar = '\0'; /* just in case */
  1468. return(CC_COMPLETE);
  1469. }
  1470. /*ARGSUSED*/
  1471. CCRETVAL
  1472. e_complete_back(Char c)
  1473. {
  1474. USE(c);
  1475. *LastChar = '\0'; /* just in case */
  1476. return(CC_COMPLETE_BACK);
  1477. }
  1478. /*ARGSUSED*/
  1479. CCRETVAL
  1480. e_complete_fwd(Char c)
  1481. {
  1482. USE(c);
  1483. *LastChar = '\0'; /* just in case */
  1484. return(CC_COMPLETE_FWD);
  1485. }
  1486. /*ARGSUSED*/
  1487. CCRETVAL
  1488. e_complete_all(Char c)
  1489. {
  1490. USE(c);
  1491. *LastChar = '\0'; /* just in case */
  1492. return(CC_COMPLETE_ALL);
  1493. }
  1494. /*ARGSUSED*/
  1495. CCRETVAL
  1496. v_cm_complete(Char c)
  1497. {
  1498. USE(c);
  1499. if (Cursor < LastChar)
  1500. Cursor++;
  1501. *LastChar = '\0'; /* just in case */
  1502. return(CC_COMPLETE);
  1503. }
  1504. /*ARGSUSED*/
  1505. CCRETVAL
  1506. e_toggle_hist(Char c)
  1507. {
  1508. struct Hist *hp;
  1509. int h;
  1510. USE(c);
  1511. *LastChar = '\0'; /* just in case */
  1512. if (Hist_num <= 0) {
  1513. return CC_ERROR;
  1514. }
  1515. hp = Histlist.Hnext;
  1516. if (hp == NULL) { /* this is only if no history */
  1517. return(CC_ERROR);
  1518. }
  1519. for (h = 1; h < Hist_num; h++)
  1520. hp = hp->Hnext;
  1521. if (!CurrentHistLit) {
  1522. if (hp->histline) {
  1523. copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
  1524. CurrentHistLit = 1;
  1525. }
  1526. else {
  1527. return CC_ERROR;
  1528. }
  1529. }
  1530. else {
  1531. Char *p;
  1532. p = sprlex(&hp->Hlex);
  1533. copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
  1534. xfree(p);
  1535. CurrentHistLit = 0;
  1536. }
  1537. LastChar = Strend(InputBuf);
  1538. if (LastChar > InputBuf) {
  1539. if (LastChar[-1] == '\n')
  1540. LastChar--;
  1541. if (LastChar[-1] == ' ')
  1542. LastChar--;
  1543. if (LastChar < InputBuf)
  1544. LastChar = InputBuf;
  1545. }
  1546. #ifdef KSHVI
  1547. if (VImode)
  1548. Cursor = InputBuf;
  1549. else
  1550. #endif /* KSHVI */
  1551. Cursor = LastChar;
  1552. return(CC_REFRESH);
  1553. }
  1554. /*ARGSUSED*/
  1555. CCRETVAL
  1556. e_up_hist(Char c)
  1557. {
  1558. Char beep = 0;
  1559. USE(c);
  1560. UndoAction = TCSHOP_NOP;
  1561. *LastChar = '\0'; /* just in case */
  1562. if (Hist_num == 0) { /* save the current buffer away */
  1563. HistBuf.len = 0;
  1564. Strbuf_append(&HistBuf, InputBuf);
  1565. Strbuf_terminate(&HistBuf);
  1566. }
  1567. Hist_num += Argument;
  1568. if (GetHistLine() == CC_ERROR) {
  1569. beep = 1;
  1570. (void) GetHistLine(); /* Hist_num was fixed by first call */
  1571. }
  1572. Refresh();
  1573. if (beep)
  1574. return(CC_ERROR);
  1575. else
  1576. return(CC_NORM); /* was CC_UP_HIST */
  1577. }
  1578. /*ARGSUSED*/
  1579. CCRETVAL
  1580. e_down_hist(Char c)
  1581. {
  1582. USE(c);
  1583. UndoAction = TCSHOP_NOP;
  1584. *LastChar = '\0'; /* just in case */
  1585. Hist_num -= Argument;
  1586. if (Hist_num < 0) {
  1587. Hist_num = 0;
  1588. return(CC_ERROR); /* make it beep */
  1589. }
  1590. return(GetHistLine());
  1591. }
  1592. /*
  1593. * c_hmatch() return True if the pattern matches the prefix
  1594. */
  1595. static int
  1596. c_hmatch(Char *str)
  1597. {
  1598. if (Strncmp(patbuf.s, str, patbuf.len) == 0)
  1599. return 1;
  1600. return Gmatch(str, patbuf.s);
  1601. }
  1602. /*
  1603. * c_hsetpat(): Set the history seatch pattern
  1604. */
  1605. static void
  1606. c_hsetpat(void)
  1607. {
  1608. if (LastCmd != F_UP_SEARCH_HIST && LastCmd != F_DOWN_SEARCH_HIST) {
  1609. patbuf.len = 0;
  1610. Strbuf_appendn(&patbuf, InputBuf, Cursor - InputBuf);
  1611. Strbuf_terminate(&patbuf);
  1612. }
  1613. #ifdef SDEBUG
  1614. xprintf("\nHist_num = %d\n", Hist_num);
  1615. xprintf("patlen = %d\n", (int)patbuf.len);
  1616. xprintf("patbuf = \"%S\"\n", patbuf.s);
  1617. xprintf("Cursor %d LastChar %d\n", Cursor - InputBuf, LastChar - InputBuf);
  1618. #endif
  1619. }
  1620. /*ARGSUSED*/
  1621. CCRETVAL
  1622. e_up_search_hist(Char c)
  1623. {
  1624. struct Hist *hp;
  1625. int h;
  1626. int found = 0;
  1627. USE(c);
  1628. ActionFlag = TCSHOP_NOP;
  1629. UndoAction = TCSHOP_NOP;
  1630. *LastChar = '\0'; /* just in case */
  1631. if (Hist_num < 0) {
  1632. #ifdef DEBUG_EDIT
  1633. xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname);
  1634. #endif
  1635. Hist_num = 0;
  1636. return(CC_ERROR);
  1637. }
  1638. if (Hist_num == 0) {
  1639. HistBuf.len = 0;
  1640. Strbuf_append(&HistBuf, InputBuf);
  1641. Strbuf_terminate(&HistBuf);
  1642. }
  1643. hp = Histlist.Hnext;
  1644. if (hp == NULL)
  1645. return(CC_ERROR);
  1646. c_hsetpat(); /* Set search pattern !! */
  1647. for (h = 1; h <= Hist_num; h++)
  1648. hp = hp->Hnext;
  1649. while (hp != NULL) {
  1650. Char *hl;
  1651. int matched;
  1652. if (hp->histline == NULL)
  1653. hp->histline = sprlex(&hp->Hlex);
  1654. if (HistLit)
  1655. hl = hp->histline;
  1656. else {
  1657. hl = sprlex(&hp->Hlex);
  1658. cleanup_push(hl, xfree);
  1659. }
  1660. #ifdef SDEBUG
  1661. xprintf("Comparing with \"%S\"\n", hl);
  1662. #endif
  1663. matched = (Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
  1664. hl[LastChar-InputBuf]) && c_hmatch(hl);
  1665. if (!HistLit)
  1666. cleanup_until(hl);
  1667. if (matched) {
  1668. found++;
  1669. break;
  1670. }
  1671. h++;
  1672. hp = hp->Hnext;
  1673. }
  1674. if (!found) {
  1675. #ifdef SDEBUG
  1676. xprintf("not found\n");
  1677. #endif
  1678. return(CC_ERROR);
  1679. }
  1680. Hist_num = h;
  1681. return(GetHistLine());
  1682. }
  1683. /*ARGSUSED*/
  1684. CCRETVAL
  1685. e_down_search_hist(Char c)
  1686. {
  1687. struct Hist *hp;
  1688. int h;
  1689. int found = 0;
  1690. USE(c);
  1691. ActionFlag = TCSHOP_NOP;
  1692. UndoAction = TCSHOP_NOP;
  1693. *LastChar = '\0'; /* just in case */
  1694. if (Hist_num == 0)
  1695. return(CC_ERROR);
  1696. hp = Histlist.Hnext;
  1697. if (hp == 0)
  1698. return(CC_ERROR);
  1699. c_hsetpat(); /* Set search pattern !! */
  1700. for (h = 1; h < Hist_num && hp; h++) {
  1701. Char *hl;
  1702. if (hp->histline == NULL)
  1703. hp->histline = sprlex(&hp->Hlex);
  1704. if (HistLit)
  1705. hl = hp->histline;
  1706. else {
  1707. hl = sprlex(&hp->Hlex);
  1708. cleanup_push(hl, xfree);
  1709. }
  1710. #ifdef SDEBUG
  1711. xprintf("Comparing with \"%S\"\n", hl);
  1712. #endif
  1713. if ((Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
  1714. hl[LastChar-InputBuf]) && c_hmatch(hl))
  1715. found = h;
  1716. if (!HistLit)
  1717. cleanup_until(hl);
  1718. hp = hp->Hnext;
  1719. }
  1720. if (!found) { /* is it the current history number? */
  1721. if (!c_hmatch(HistBuf.s)) {
  1722. #ifdef SDEBUG
  1723. xprintf("not found\n");
  1724. #endif
  1725. return(CC_ERROR);
  1726. }
  1727. }
  1728. Hist_num = found;
  1729. return(GetHistLine());
  1730. }
  1731. /*ARGSUSED*/
  1732. CCRETVAL
  1733. e_helpme(Char c)
  1734. {
  1735. USE(c);
  1736. PastBottom();
  1737. *LastChar = '\0'; /* just in case */
  1738. return(CC_HELPME);
  1739. }
  1740. /*ARGSUSED*/
  1741. CCRETVAL
  1742. e_correct(Char c)
  1743. {
  1744. USE(c);
  1745. *LastChar = '\0'; /* just in case */
  1746. return(CC_CORRECT);
  1747. }
  1748. /*ARGSUSED*/
  1749. CCRETVAL
  1750. e_correctl(Char c)
  1751. {
  1752. USE(c);
  1753. *LastChar = '\0'; /* just in case */
  1754. return(CC_CORRECT_L);
  1755. }
  1756. /*ARGSUSED*/
  1757. CCRETVAL
  1758. e_run_fg_editor(Char c)
  1759. {
  1760. struct process *pp;
  1761. USE(c);
  1762. if ((pp = find_stop_ed()) != NULL) {
  1763. /* save our editor state so we can restore it */
  1764. c_save_inputbuf();
  1765. Hist_num = 0; /* for the history commands */
  1766. /* put the tty in a sane mode */
  1767. PastBottom();
  1768. (void) Cookedmode(); /* make sure the tty is set up correctly */
  1769. /* do it! */
  1770. fg_proc_entry(pp);
  1771. (void) Rawmode(); /* go on */
  1772. Refresh();
  1773. RestoreSaved = 0;
  1774. HistSaved = 0;
  1775. }
  1776. return(CC_NORM);
  1777. }
  1778. /*ARGSUSED*/
  1779. CCRETVAL
  1780. e_list_choices(Char c)
  1781. {
  1782. USE(c);
  1783. PastBottom();
  1784. *LastChar = '\0'; /* just in case */
  1785. return(CC_LIST_CHOICES);
  1786. }
  1787. /*ARGSUSED*/
  1788. CCRETVAL
  1789. e_list_all(Char c)
  1790. {
  1791. USE(c);
  1792. PastBottom();
  1793. *LastChar = '\0'; /* just in case */
  1794. return(CC_LIST_ALL);
  1795. }
  1796. /*ARGSUSED*/
  1797. CCRETVAL
  1798. e_list_glob(Char c)
  1799. {
  1800. USE(c);
  1801. PastBottom();
  1802. *LastChar = '\0'; /* just in case */
  1803. return(CC_LIST_GLOB);
  1804. }
  1805. /*ARGSUSED*/
  1806. CCRETVAL
  1807. e_expand_glob(Char c)
  1808. {
  1809. USE(c);
  1810. *LastChar = '\0'; /* just in case */
  1811. return(CC_EXPAND_GLOB);
  1812. }
  1813. /*ARGSUSED*/
  1814. CCRETVAL
  1815. e_normalize_path(Char c)
  1816. {
  1817. USE(c);
  1818. *LastChar = '\0'; /* just in case */
  1819. return(CC_NORMALIZE_PATH);
  1820. }
  1821. /*ARGSUSED*/
  1822. CCRETVAL
  1823. e_normalize_command(Char c)
  1824. {
  1825. USE(c);
  1826. *LastChar = '\0'; /* just in case */
  1827. return(CC_NORMALIZE_COMMAND);
  1828. }
  1829. /*ARGSUSED*/
  1830. CCRETVAL
  1831. e_expand_vars(Char c)
  1832. {
  1833. USE(c);
  1834. *LastChar = '\0'; /* just in case */
  1835. return(CC_EXPAND_VARS);
  1836. }
  1837. /*ARGSUSED*/
  1838. CCRETVAL
  1839. e_which(Char c)
  1840. { /* do a fast command line which(1) */
  1841. USE(c);
  1842. c_save_inputbuf();
  1843. Hist_num = 0; /* for the history commands */
  1844. PastBottom();
  1845. *LastChar = '\0'; /* just in case */
  1846. return(CC_WHICH);
  1847. }
  1848. /*ARGSUSED*/
  1849. CCRETVAL
  1850. e_last_item(Char c)
  1851. { /* insert the last element of the prev. cmd */
  1852. struct Hist *hp;
  1853. struct wordent *wp, *firstp;
  1854. int i;
  1855. Char *expanded;
  1856. USE(c);
  1857. if (Argument <= 0)
  1858. return(CC_ERROR);
  1859. hp = Histlist.Hnext;
  1860. if (hp == NULL) { /* this is only if no history */
  1861. return(CC_ERROR);
  1862. }
  1863. wp = (hp->Hlex).prev;
  1864. if (wp->prev == (struct wordent *) NULL)
  1865. return(CC_ERROR); /* an empty history entry */
  1866. firstp = (hp->Hlex).next;
  1867. /* back up arg words in lex */
  1868. for (i = 0; i < Argument && wp != firstp; i++) {
  1869. wp = wp->prev;
  1870. }
  1871. expanded = expand_lex(wp->prev, 0, i - 1);
  1872. if (InsertStr(expanded)) {
  1873. xfree(expanded);
  1874. return(CC_ERROR);
  1875. }
  1876. xfree(expanded);
  1877. return(CC_REFRESH);
  1878. }
  1879. /*ARGSUSED*/
  1880. CCRETVAL
  1881. e_dabbrev_expand(Char c)
  1882. { /* expand to preceding word matching prefix */
  1883. Char *cp, *ncp, *bp;
  1884. struct Hist *hp;
  1885. int arg = 0, i;
  1886. size_t len = 0;
  1887. int found = 0;
  1888. Char *hbuf;
  1889. static int oldevent, hist, word;
  1890. static Char *start, *oldcursor;
  1891. USE(c);
  1892. if (Argument <= 0)
  1893. return(CC_ERROR);
  1894. cp = c_preword(Cursor, InputBuf, 1, STRshwordsep);
  1895. if (cp == Cursor || Isspace(*cp))
  1896. return(CC_ERROR);
  1897. hbuf = NULL;
  1898. hp = Histlist.Hnext;
  1899. bp = InputBuf;
  1900. if (Argument == 1 && eventno == oldevent && cp == start &&
  1901. Cursor == oldcursor && patbuf.len > 0
  1902. && Strncmp(patbuf.s, cp, patbuf.len) == 0){
  1903. /* continue previous search - go to last match (hist/word) */
  1904. if (hist != 0) { /* need to move up history */
  1905. for (i = 1; i < hist && hp != NULL; i++)
  1906. hp = hp->Hnext;
  1907. if (hp == NULL) /* "can't happen" */
  1908. goto err_hbuf;
  1909. hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
  1910. cp = Strend(hbuf);
  1911. bp = hbuf;
  1912. hp = hp->Hnext;
  1913. }
  1914. cp = c_preword(cp, bp, word, STRshwordsep);
  1915. } else { /* starting new search */
  1916. oldevent = eventno;
  1917. start = cp;
  1918. patbuf.len = 0;
  1919. Strbuf_appendn(&patbuf, cp, Cursor - cp);
  1920. hist = 0;
  1921. word = 0;
  1922. }
  1923. while (!found) {
  1924. ncp = c_preword(cp, bp, 1, STRshwordsep);
  1925. if (ncp == cp || Isspace(*ncp)) { /* beginning of line */
  1926. hist++;
  1927. word = 0;
  1928. if (hp == NULL)
  1929. goto err_hbuf;
  1930. hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
  1931. cp = Strend(hbuf);
  1932. bp = hbuf;
  1933. hp = hp->Hnext;
  1934. continue;
  1935. } else {
  1936. word++;
  1937. len = c_endword(ncp-1, cp, 1, STRshwordsep) - ncp + 1;
  1938. cp = ncp;
  1939. }
  1940. if (len > patbuf.len && Strncmp(cp, patbuf.s, patbuf.len) == 0) {
  1941. /* We don't fully check distinct matches as Gnuemacs does: */
  1942. if (Argument > 1) { /* just count matches */
  1943. if (++arg >= Argument)
  1944. found++;
  1945. } else { /* match if distinct from previous */
  1946. if (len != (size_t)(Cursor - start)
  1947. || Strncmp(cp, start, len) != 0)
  1948. found++;
  1949. }
  1950. }
  1951. }
  1952. if (LastChar + len - (Cursor - start) >= InputLim)
  1953. goto err_hbuf; /* no room */
  1954. DeleteBack(Cursor - start);
  1955. c_insert(len);
  1956. while (len--)
  1957. *Cursor++ = *cp++;
  1958. oldcursor = Cursor;
  1959. xfree(hbuf);
  1960. return(CC_REFRESH);
  1961. err_hbuf:
  1962. xfree(hbuf);
  1963. return CC_ERROR;
  1964. }
  1965. /*ARGSUSED*/
  1966. CCRETVAL
  1967. e_yank_kill(Char c)
  1968. { /* almost like GnuEmacs */
  1969. int len;
  1970. Char *kp, *cp;
  1971. USE(c);
  1972. if (KillRingLen == 0) /* nothing killed */
  1973. return(CC_ERROR);
  1974. len = Strlen(KillRing[YankPos].buf);
  1975. if (LastChar + len >= InputLim)
  1976. return(CC_ERROR); /* end of buffer space */
  1977. /* else */
  1978. cp = Cursor; /* for speed */
  1979. c_insert(len); /* open the space, */
  1980. for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */
  1981. *cp++ = *kp;
  1982. if (Argument == 1) { /* if no arg */
  1983. Mark = Cursor; /* mark at beginning, cursor at end */
  1984. Cursor = cp;
  1985. } else {
  1986. Mark = cp; /* else cursor at beginning, mark at end */
  1987. }
  1988. if (adrof(STRhighlight) && MarkIsSet) {
  1989. ClearLines();
  1990. ClearDisp();
  1991. }
  1992. MarkIsSet = 0;
  1993. return(CC_REFRESH);
  1994. }
  1995. /*ARGSUSED*/
  1996. CCRETVAL
  1997. e_yank_pop(Char c)
  1998. { /* almost like GnuEmacs */
  1999. int m_bef_c, del_len, ins_len;
  2000. Char *kp, *cp;
  2001. USE(c);
  2002. #if 0
  2003. /* XXX This "should" be here, but doesn't work, since LastCmd
  2004. gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?).
  2005. (But what about F_ARGFOUR?) I.e. if you hit M-y twice the
  2006. second one will "succeed" even if the first one wasn't preceded
  2007. by a yank, and giving an argument is impossible. Now we "succeed"
  2008. regardless of previous command, which is wrong too of course. */
  2009. if (LastCmd != F_YANK_KILL && LastCmd != F_YANK_POP)
  2010. return(CC_ERROR);
  2011. #endif
  2012. if (KillRingLen == 0) /* nothing killed */
  2013. return(CC_ERROR);
  2014. YankPos -= Argument;
  2015. while (YankPos < 0)
  2016. YankPos += KillRingLen;
  2017. YankPos %= KillRingLen;
  2018. if (Cursor > Mark) {
  2019. del_len = Cursor - Mark;
  2020. m_bef_c = 1;
  2021. } else {
  2022. del_len = Mark - Cursor;
  2023. m_bef_c = 0;
  2024. }
  2025. ins_len = Strlen(KillRing[YankPos].buf);
  2026. if (LastChar + ins_len - del_len >= InputLim)
  2027. return(CC_ERROR); /* end of buffer space */
  2028. if (m_bef_c) {
  2029. c_delbefore(del_len);
  2030. } else {
  2031. c_delafter(del_len);
  2032. }
  2033. cp = Cursor; /* for speed */
  2034. c_insert