PageRenderTime 70ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/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
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, LGPL-2.0, LGPL-2.1, BSD-2-Clause, 0BSD, JSON, AGPL-1.0, GPL-2.0
  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(ins_len); /* open the space, */
  2035. for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */
  2036. *cp++ = *kp;
  2037. if (m_bef_c) {
  2038. Mark = Cursor; /* mark at beginning, cursor at end */
  2039. Cursor = cp;
  2040. } else {
  2041. Mark = cp; /* else cursor at beginning, mark at end */
  2042. }
  2043. if (adrof(STRhighlight) && MarkIsSet) {
  2044. ClearLines();
  2045. ClearDisp();
  2046. }
  2047. MarkIsSet = 0;
  2048. return(CC_REFRESH);
  2049. }
  2050. /*ARGSUSED*/
  2051. CCRETVAL
  2052. v_delprev(Char c) /* Backspace key in insert mode */
  2053. {
  2054. int rc;
  2055. USE(c);
  2056. rc = CC_ERROR;
  2057. if (InsertPos != 0) {
  2058. if (Argument <= Cursor - InsertPos) {
  2059. c_delbefore(Argument); /* delete before */
  2060. rc = CC_REFRESH;
  2061. }
  2062. }
  2063. return(rc);
  2064. } /* v_delprev */
  2065. /*ARGSUSED*/
  2066. CCRETVAL
  2067. e_delprev(Char c)
  2068. {
  2069. USE(c);
  2070. if (Cursor > InputBuf) {
  2071. c_delbefore(Argument); /* delete before dot */
  2072. return(CC_REFRESH);
  2073. }
  2074. else {
  2075. return(CC_ERROR);
  2076. }
  2077. }
  2078. /*ARGSUSED*/
  2079. CCRETVAL
  2080. e_delwordprev(Char c)
  2081. {
  2082. Char *cp;
  2083. USE(c);
  2084. if (Cursor == InputBuf)
  2085. return(CC_ERROR);
  2086. /* else */
  2087. cp = c_prev_word(Cursor, InputBuf, Argument);
  2088. c_push_kill(cp, Cursor); /* save the text */
  2089. c_delbefore((int)(Cursor - cp)); /* delete before dot */
  2090. return(CC_REFRESH);
  2091. }
  2092. /* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93
  2093. *
  2094. * Changed the names of some of the ^D family of editor functions to
  2095. * correspond to what they actually do and created new e_delnext_list
  2096. * for completeness.
  2097. *
  2098. * Old names: New names:
  2099. *
  2100. * delete-char delete-char-or-eof
  2101. * F_DELNEXT F_DELNEXT_EOF
  2102. * e_delnext e_delnext_eof
  2103. * edelnxt edelnxteof
  2104. * delete-char-or-eof delete-char
  2105. * F_DELNEXT_EOF F_DELNEXT
  2106. * e_delnext_eof e_delnext
  2107. * edelnxteof edelnxt
  2108. * delete-char-or-list delete-char-or-list-or-eof
  2109. * F_LIST_DELNEXT F_DELNEXT_LIST_EOF
  2110. * e_list_delnext e_delnext_list_eof
  2111. * edellsteof
  2112. * (no old equivalent) delete-char-or-list
  2113. * F_DELNEXT_LIST
  2114. * e_delnext_list
  2115. * e_delnxtlst
  2116. */
  2117. /* added by mtk@ari.ncl.omron.co.jp (920818) */
  2118. /* rename e_delnext() -> e_delnext_eof() */
  2119. /*ARGSUSED*/
  2120. CCRETVAL
  2121. e_delnext(Char c)
  2122. {
  2123. USE(c);
  2124. if (Cursor == LastChar) {/* if I'm at the end */
  2125. if (!VImode) {
  2126. return(CC_ERROR);
  2127. }
  2128. else {
  2129. if (Cursor != InputBuf)
  2130. Cursor--;
  2131. else
  2132. return(CC_ERROR);
  2133. }
  2134. }
  2135. c_delafter(Argument); /* delete after dot */
  2136. if (Cursor > LastChar)
  2137. Cursor = LastChar; /* bounds check */
  2138. return(CC_REFRESH);
  2139. }
  2140. /*ARGSUSED*/
  2141. CCRETVAL
  2142. e_delnext_eof(Char c)
  2143. {
  2144. USE(c);
  2145. if (Cursor == LastChar) {/* if I'm at the end */
  2146. if (!VImode) {
  2147. if (Cursor == InputBuf) {
  2148. /* if I'm also at the beginning */
  2149. so_write(STReof, 4);/* then do a EOF */
  2150. flush();
  2151. return(CC_EOF);
  2152. }
  2153. else
  2154. return(CC_ERROR);
  2155. }
  2156. else {
  2157. if (Cursor != InputBuf)
  2158. Cursor--;
  2159. else
  2160. return(CC_ERROR);
  2161. }
  2162. }
  2163. c_delafter(Argument); /* delete after dot */
  2164. if (Cursor > LastChar)
  2165. Cursor = LastChar; /* bounds check */
  2166. return(CC_REFRESH);
  2167. }
  2168. /*ARGSUSED*/
  2169. CCRETVAL
  2170. e_delnext_list(Char c)
  2171. {
  2172. USE(c);
  2173. if (Cursor == LastChar) { /* if I'm at the end */
  2174. PastBottom();
  2175. *LastChar = '\0'; /* just in case */
  2176. return(CC_LIST_CHOICES);
  2177. }
  2178. else {
  2179. c_delafter(Argument); /* delete after dot */
  2180. if (Cursor > LastChar)
  2181. Cursor = LastChar; /* bounds check */
  2182. return(CC_REFRESH);
  2183. }
  2184. }
  2185. /*ARGSUSED*/
  2186. CCRETVAL
  2187. e_delnext_list_eof(Char c)
  2188. {
  2189. USE(c);
  2190. if (Cursor == LastChar) { /* if I'm at the end */
  2191. if (Cursor == InputBuf) { /* if I'm also at the beginning */
  2192. so_write(STReof, 4);/* then do a EOF */
  2193. flush();
  2194. return(CC_EOF);
  2195. }
  2196. else {
  2197. PastBottom();
  2198. *LastChar = '\0'; /* just in case */
  2199. return(CC_LIST_CHOICES);
  2200. }
  2201. }
  2202. else {
  2203. c_delafter(Argument); /* delete after dot */
  2204. if (Cursor > LastChar)
  2205. Cursor = LastChar; /* bounds check */
  2206. return(CC_REFRESH);
  2207. }
  2208. }
  2209. /*ARGSUSED*/
  2210. CCRETVAL
  2211. e_list_eof(Char c)
  2212. {
  2213. CCRETVAL rv;
  2214. USE(c);
  2215. if (Cursor == LastChar && Cursor == InputBuf) {
  2216. so_write(STReof, 4); /* then do a EOF */
  2217. flush();
  2218. rv = CC_EOF;
  2219. }
  2220. else {
  2221. PastBottom();
  2222. *LastChar = '\0'; /* just in case */
  2223. rv = CC_LIST_CHOICES;
  2224. }
  2225. return rv;
  2226. }
  2227. /*ARGSUSED*/
  2228. CCRETVAL
  2229. e_delwordnext(Char c)
  2230. {
  2231. Char *cp;
  2232. USE(c);
  2233. if (Cursor == LastChar)
  2234. return(CC_ERROR);
  2235. /* else */
  2236. cp = c_next_word(Cursor, LastChar, Argument);
  2237. c_push_kill(Cursor, cp); /* save the text */
  2238. c_delafter((int)(cp - Cursor)); /* delete after dot */
  2239. if (Cursor > LastChar)
  2240. Cursor = LastChar; /* bounds check */
  2241. return(CC_REFRESH);
  2242. }
  2243. /*ARGSUSED*/
  2244. CCRETVAL
  2245. e_toend(Char c)
  2246. {
  2247. USE(c);
  2248. Cursor = LastChar;
  2249. if (VImode)
  2250. if (ActionFlag & TCSHOP_DELETE) {
  2251. c_delfini();
  2252. return(CC_REFRESH);
  2253. }
  2254. RefCursor(); /* move the cursor */
  2255. return(CC_NORM);
  2256. }
  2257. /*ARGSUSED*/
  2258. CCRETVAL
  2259. e_tobeg(Char c)
  2260. {
  2261. USE(c);
  2262. Cursor = InputBuf;
  2263. if (VImode) {
  2264. while (Isspace(*Cursor)) /* We want FIRST non space character */
  2265. Cursor++;
  2266. if (ActionFlag & TCSHOP_DELETE) {
  2267. c_delfini();
  2268. return(CC_REFRESH);
  2269. }
  2270. }
  2271. RefCursor(); /* move the cursor */
  2272. return(CC_NORM);
  2273. }
  2274. /*ARGSUSED*/
  2275. CCRETVAL
  2276. e_killend(Char c)
  2277. {
  2278. USE(c);
  2279. c_push_kill(Cursor, LastChar); /* copy it */
  2280. LastChar = Cursor; /* zap! -- delete to end */
  2281. if (Mark > Cursor)
  2282. Mark = Cursor;
  2283. MarkIsSet = 0;
  2284. return(CC_REFRESH);
  2285. }
  2286. /*ARGSUSED*/
  2287. CCRETVAL
  2288. e_killbeg(Char c)
  2289. {
  2290. USE(c);
  2291. c_push_kill(InputBuf, Cursor); /* copy it */
  2292. c_delbefore((int)(Cursor - InputBuf));
  2293. if (Mark && Mark > Cursor)
  2294. Mark -= Cursor-InputBuf;
  2295. return(CC_REFRESH);
  2296. }
  2297. /*ARGSUSED*/
  2298. CCRETVAL
  2299. e_killall(Char c)
  2300. {
  2301. USE(c);
  2302. c_push_kill(InputBuf, LastChar); /* copy it */
  2303. Cursor = Mark = LastChar = InputBuf; /* zap! -- delete all of it */
  2304. MarkIsSet = 0;
  2305. return(CC_REFRESH);
  2306. }
  2307. /*ARGSUSED*/
  2308. CCRETVAL
  2309. e_killregion(Char c)
  2310. {
  2311. USE(c);
  2312. if (!Mark)
  2313. return(CC_ERROR);
  2314. if (Mark > Cursor) {
  2315. c_push_kill(Cursor, Mark); /* copy it */
  2316. c_delafter((int)(Mark - Cursor)); /* delete it - UNUSED BY VI mode */
  2317. Mark = Cursor;
  2318. }
  2319. else { /* mark is before cursor */
  2320. c_push_kill(Mark, Cursor); /* copy it */
  2321. c_delbefore((int)(Cursor - Mark));
  2322. }
  2323. if (adrof(STRhighlight) && MarkIsSet) {
  2324. ClearLines();
  2325. ClearDisp();
  2326. }
  2327. MarkIsSet = 0;
  2328. return(CC_REFRESH);
  2329. }
  2330. /*ARGSUSED*/
  2331. CCRETVAL
  2332. e_copyregion(Char c)
  2333. {
  2334. USE(c);
  2335. if (!Mark)
  2336. return(CC_ERROR);
  2337. if (Mark > Cursor) {
  2338. c_push_kill(Cursor, Mark); /* copy it */
  2339. }
  2340. else { /* mark is before cursor */
  2341. c_push_kill(Mark, Cursor); /* copy it */
  2342. }
  2343. return(CC_NORM); /* don't even need to Refresh() */
  2344. }
  2345. /*ARGSUSED*/
  2346. CCRETVAL
  2347. e_charswitch(Char cc)
  2348. {
  2349. Char c;
  2350. USE(cc);
  2351. /* do nothing if we are at beginning of line or have only one char */
  2352. if (Cursor == &InputBuf[0] || LastChar == &InputBuf[1]) {
  2353. return(CC_ERROR);
  2354. }
  2355. if (Cursor < LastChar) {
  2356. Cursor++;
  2357. }
  2358. c = Cursor[-2];
  2359. Cursor[-2] = Cursor[-1];
  2360. Cursor[-1] = c;
  2361. return(CC_REFRESH);
  2362. }
  2363. /*ARGSUSED*/
  2364. CCRETVAL
  2365. e_gcharswitch(Char cc)
  2366. { /* gosmacs style ^T */
  2367. Char c;
  2368. USE(cc);
  2369. if (Cursor > &InputBuf[1]) {/* must have at least two chars entered */
  2370. c = Cursor[-2];
  2371. Cursor[-2] = Cursor[-1];
  2372. Cursor[-1] = c;
  2373. return(CC_REFRESH);
  2374. }
  2375. else {
  2376. return(CC_ERROR);
  2377. }
  2378. }
  2379. /*ARGSUSED*/
  2380. CCRETVAL
  2381. e_charback(Char c)
  2382. {
  2383. USE(c);
  2384. if (Cursor > InputBuf) {
  2385. if (Argument > Cursor - InputBuf)
  2386. Cursor = InputBuf;
  2387. else
  2388. Cursor -= Argument;
  2389. if (VImode)
  2390. if (ActionFlag & TCSHOP_DELETE) {
  2391. c_delfini();
  2392. return(CC_REFRESH);
  2393. }
  2394. RefCursor();
  2395. return(CC_NORM);
  2396. }
  2397. else {
  2398. return(CC_ERROR);
  2399. }
  2400. }
  2401. /*ARGSUSED*/
  2402. CCRETVAL
  2403. v_wordback(Char c)
  2404. {
  2405. USE(c);
  2406. if (Cursor == InputBuf)
  2407. return(CC_ERROR);
  2408. /* else */
  2409. Cursor = c_preword(Cursor, InputBuf, Argument, STRshwspace); /* bounds check */
  2410. if (ActionFlag & TCSHOP_DELETE) {
  2411. c_delfini();
  2412. return(CC_REFRESH);
  2413. }
  2414. RefCursor();
  2415. return(CC_NORM);
  2416. }
  2417. /*ARGSUSED*/
  2418. CCRETVAL
  2419. e_wordback(Char c)
  2420. {
  2421. USE(c);
  2422. if (Cursor == InputBuf)
  2423. return(CC_ERROR);
  2424. /* else */
  2425. Cursor = c_prev_word(Cursor, InputBuf, Argument); /* bounds check */
  2426. if (VImode)
  2427. if (ActionFlag & TCSHOP_DELETE) {
  2428. c_delfini();
  2429. return(CC_REFRESH);
  2430. }
  2431. RefCursor();
  2432. return(CC_NORM);
  2433. }
  2434. /*ARGSUSED*/
  2435. CCRETVAL
  2436. e_charfwd(Char c)
  2437. {
  2438. USE(c);
  2439. if (Cursor < LastChar) {
  2440. Cursor += Argument;
  2441. if (Cursor > LastChar)
  2442. Cursor = LastChar;
  2443. if (VImode)
  2444. if (ActionFlag & TCSHOP_DELETE) {
  2445. c_delfini();
  2446. return(CC_REFRESH);
  2447. }
  2448. RefCursor();
  2449. return(CC_NORM);
  2450. }
  2451. else {
  2452. return(CC_ERROR);
  2453. }
  2454. }
  2455. /*ARGSUSED*/
  2456. CCRETVAL
  2457. e_wordfwd(Char c)
  2458. {
  2459. USE(c);
  2460. if (Cursor == LastChar)
  2461. return(CC_ERROR);
  2462. /* else */
  2463. Cursor = c_next_word(Cursor, LastChar, Argument);
  2464. if (VImode)
  2465. if (ActionFlag & TCSHOP_DELETE) {
  2466. c_delfini();
  2467. return(CC_REFRESH);
  2468. }
  2469. RefCursor();
  2470. return(CC_NORM);
  2471. }
  2472. /*ARGSUSED*/
  2473. CCRETVAL
  2474. v_wordfwd(Char c)
  2475. {
  2476. USE(c);
  2477. if (Cursor == LastChar)
  2478. return(CC_ERROR);
  2479. /* else */
  2480. Cursor = c_nexword(Cursor, LastChar, Argument);
  2481. if (VImode)
  2482. if (ActionFlag & TCSHOP_DELETE) {
  2483. c_delfini();
  2484. return(CC_REFRESH);
  2485. }
  2486. RefCursor();
  2487. return(CC_NORM);
  2488. }
  2489. /*ARGSUSED*/
  2490. CCRETVAL
  2491. v_wordbegnext(Char c)
  2492. {
  2493. USE(c);
  2494. if (Cursor == LastChar)
  2495. return(CC_ERROR);
  2496. /* else */
  2497. Cursor = c_next_word(Cursor, LastChar, Argument);
  2498. if (Cursor < LastChar)
  2499. Cursor++;
  2500. if (VImode)
  2501. if (ActionFlag & TCSHOP_DELETE) {
  2502. c_delfini();
  2503. return(CC_REFRESH);
  2504. }
  2505. RefCursor();
  2506. return(CC_NORM);
  2507. }
  2508. /*ARGSUSED*/
  2509. static CCRETVAL
  2510. v_repeat_srch(int c)
  2511. {
  2512. CCRETVAL rv = CC_ERROR;
  2513. #ifdef SDEBUG
  2514. xprintf("dir %d patlen %d patbuf %S\n",
  2515. c, (int)patbuf.len, patbuf.s);
  2516. #endif
  2517. LastCmd = (KEYCMD) c; /* Hack to stop c_hsetpat */
  2518. LastChar = InputBuf;
  2519. switch (c) {
  2520. case F_DOWN_SEARCH_HIST:
  2521. rv = e_down_search_hist(0);
  2522. break;
  2523. case F_UP_SEARCH_HIST:
  2524. rv = e_up_search_hist(0);
  2525. break;
  2526. default:
  2527. break;
  2528. }
  2529. return rv;
  2530. }
  2531. static CCRETVAL
  2532. v_csearch_back(Char ch, int count, int tflag)
  2533. {
  2534. Char *cp;
  2535. cp = Cursor;
  2536. while (count--) {
  2537. if (*cp == ch)
  2538. cp--;
  2539. while (cp > InputBuf && *cp != ch)
  2540. cp--;
  2541. }
  2542. if (cp < InputBuf || (cp == InputBuf && *cp != ch))
  2543. return(CC_ERROR);
  2544. if (*cp == ch && tflag)
  2545. cp++;
  2546. Cursor = cp;
  2547. if (ActionFlag & TCSHOP_DELETE) {
  2548. Cursor++;
  2549. c_delfini();
  2550. return(CC_REFRESH);
  2551. }
  2552. RefCursor();
  2553. return(CC_NORM);
  2554. }
  2555. static CCRETVAL
  2556. v_csearch_fwd(Char ch, int count, int tflag)
  2557. {
  2558. Char *cp;
  2559. cp = Cursor;
  2560. while (count--) {
  2561. if(*cp == ch)
  2562. cp++;
  2563. while (cp < LastChar && *cp != ch)
  2564. cp++;
  2565. }
  2566. if (cp >= LastChar)
  2567. return(CC_ERROR);
  2568. if (*cp == ch && tflag)
  2569. cp--;
  2570. Cursor = cp;
  2571. if (ActionFlag & TCSHOP_DELETE) {
  2572. Cursor++;
  2573. c_delfini();
  2574. return(CC_REFRESH);
  2575. }
  2576. RefCursor();
  2577. return(CC_NORM);
  2578. }
  2579. /*ARGSUSED*/
  2580. static CCRETVAL
  2581. v_action(int c)
  2582. {
  2583. Char *cp, *kp;
  2584. if (ActionFlag == TCSHOP_DELETE) {
  2585. ActionFlag = TCSHOP_NOP;
  2586. ActionPos = 0;
  2587. UndoSize = 0;
  2588. kp = UndoBuf;
  2589. for (cp = InputBuf; cp < LastChar; cp++) {
  2590. *kp++ = *cp;
  2591. UndoSize++;
  2592. }
  2593. UndoAction = TCSHOP_INSERT;
  2594. UndoPtr = InputBuf;
  2595. LastChar = InputBuf;
  2596. Cursor = InputBuf;
  2597. if (c & TCSHOP_INSERT)
  2598. c_alternativ_key_map(0);
  2599. return(CC_REFRESH);
  2600. }
  2601. #ifdef notdef
  2602. else if (ActionFlag == TCSHOP_NOP) {
  2603. #endif
  2604. ActionPos = Cursor;
  2605. ActionFlag = c;
  2606. return(CC_ARGHACK); /* Do NOT clear out argument */
  2607. #ifdef notdef
  2608. }
  2609. else {
  2610. ActionFlag = 0;
  2611. ActionPos = 0;
  2612. return(CC_ERROR);
  2613. }
  2614. #endif
  2615. }
  2616. #ifdef COMMENT
  2617. /* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */
  2618. static void
  2619. c_get_word(Char **begin, Char **end)
  2620. {
  2621. Char *cp;
  2622. cp = &Cursor[0];
  2623. while (Argument--) {
  2624. while ((cp <= LastChar) && (isword(*cp)))
  2625. cp++;
  2626. *end = --cp;
  2627. while ((cp >= InputBuf) && (isword(*cp)))
  2628. cp--;
  2629. *begin = ++cp;
  2630. }
  2631. }
  2632. #endif /* COMMENT */
  2633. /*ARGSUSED*/
  2634. CCRETVAL
  2635. e_uppercase(Char c)
  2636. {
  2637. Char *cp, *end;
  2638. USE(c);
  2639. end = c_next_word(Cursor, LastChar, Argument);
  2640. for (cp = Cursor; cp < end; cp++) /* PWP: was cp=begin */
  2641. if (Islower(*cp))
  2642. *cp = Toupper(*cp);
  2643. Cursor = end;
  2644. if (Cursor > LastChar)
  2645. Cursor = LastChar;
  2646. return(CC_REFRESH);
  2647. }
  2648. /*ARGSUSED*/
  2649. CCRETVAL
  2650. e_capitolcase(Char c)
  2651. {
  2652. Char *cp, *end;
  2653. USE(c);
  2654. end = c_next_word(Cursor, LastChar, Argument);
  2655. cp = Cursor;
  2656. for (; cp < end; cp++) {
  2657. if (Isalpha(*cp)) {
  2658. if (Islower(*cp))
  2659. *cp = Toupper(*cp);
  2660. cp++;
  2661. break;
  2662. }
  2663. }
  2664. for (; cp < end; cp++)
  2665. if (Isupper(*cp))
  2666. *cp = Tolower(*cp);
  2667. Cursor = end;
  2668. if (Cursor > LastChar)
  2669. Cursor = LastChar;
  2670. return(CC_REFRESH);
  2671. }
  2672. /*ARGSUSED*/
  2673. CCRETVAL
  2674. e_lowercase(Char c)
  2675. {
  2676. Char *cp, *end;
  2677. USE(c);
  2678. end = c_next_word(Cursor, LastChar, Argument);
  2679. for (cp = Cursor; cp < end; cp++)
  2680. if (Isupper(*cp))
  2681. *cp = Tolower(*cp);
  2682. Cursor = end;
  2683. if (Cursor > LastChar)
  2684. Cursor = LastChar;
  2685. return(CC_REFRESH);
  2686. }
  2687. /*ARGSUSED*/
  2688. CCRETVAL
  2689. e_set_mark(Char c)
  2690. {
  2691. USE(c);
  2692. if (adrof(STRhighlight) && MarkIsSet && Mark != Cursor) {
  2693. ClearLines();
  2694. ClearDisp();
  2695. Refresh();
  2696. }
  2697. Mark = Cursor;
  2698. MarkIsSet = 1;
  2699. return(CC_NORM);
  2700. }
  2701. /*ARGSUSED*/
  2702. CCRETVAL
  2703. e_exchange_mark(Char c)
  2704. {
  2705. Char *cp;
  2706. USE(c);
  2707. cp = Cursor;
  2708. Cursor = Mark;
  2709. Mark = cp;
  2710. RefCursor();
  2711. return(CC_NORM);
  2712. }
  2713. /*ARGSUSED*/
  2714. CCRETVAL
  2715. e_argfour(Char c)
  2716. { /* multiply current argument by 4 */
  2717. USE(c);
  2718. if (Argument > 1000000)
  2719. return CC_ERROR;
  2720. DoingArg = 1;
  2721. Argument *= 4;
  2722. return(CC_ARGHACK);
  2723. }
  2724. static void
  2725. quote_mode_cleanup(void *unused)
  2726. {
  2727. USE(unused);
  2728. QuoteModeOff();
  2729. }
  2730. /*ARGSUSED*/
  2731. CCRETVAL
  2732. e_quote(Char c)
  2733. {
  2734. Char ch;
  2735. int num;
  2736. USE(c);
  2737. QuoteModeOn();
  2738. cleanup_push(&c, quote_mode_cleanup); /* Using &c just as a mark */
  2739. num = GetNextChar(&ch);
  2740. cleanup_until(&c);
  2741. if (num == 1)
  2742. return e_insert(ch);
  2743. else
  2744. return e_send_eof(0);
  2745. }
  2746. /*ARGSUSED*/
  2747. CCRETVAL
  2748. e_metanext(Char c)
  2749. {
  2750. USE(c);
  2751. MetaNext = 1;
  2752. return(CC_ARGHACK); /* preserve argument */
  2753. }
  2754. #ifdef notdef
  2755. /*ARGSUSED*/
  2756. CCRETVAL
  2757. e_extendnext(Char c)
  2758. {
  2759. CurrentKeyMap = CcAltMap;
  2760. return(CC_ARGHACK); /* preserve argument */
  2761. }
  2762. #endif
  2763. /*ARGSUSED*/
  2764. CCRETVAL
  2765. v_insbeg(Char c)
  2766. { /* move to beginning of line and start vi
  2767. * insert mode */
  2768. USE(c);
  2769. Cursor = InputBuf;
  2770. InsertPos = Cursor;
  2771. UndoPtr = Cursor;
  2772. UndoAction = TCSHOP_DELETE;
  2773. RefCursor(); /* move the cursor */
  2774. c_alternativ_key_map(0);
  2775. return(CC_NORM);
  2776. }
  2777. /*ARGSUSED*/
  2778. CCRETVAL
  2779. v_replone(Char c)
  2780. { /* vi mode overwrite one character */
  2781. USE(c);
  2782. c_alternativ_key_map(0);
  2783. inputmode = MODE_REPLACE_1;
  2784. UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */
  2785. UndoPtr = Cursor;
  2786. UndoSize = 0;
  2787. return(CC_NORM);
  2788. }
  2789. /*ARGSUSED*/
  2790. CCRETVAL
  2791. v_replmode(Char c)
  2792. { /* vi mode start overwriting */
  2793. USE(c);
  2794. c_alternativ_key_map(0);
  2795. inputmode = MODE_REPLACE;
  2796. UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */
  2797. UndoPtr = Cursor;
  2798. UndoSize = 0;
  2799. return(CC_NORM);
  2800. }
  2801. /*ARGSUSED*/
  2802. CCRETVAL
  2803. v_substchar(Char c)
  2804. { /* vi mode substitute for one char */
  2805. USE(c);
  2806. c_delafter(Argument);
  2807. c_alternativ_key_map(0);
  2808. return(CC_REFRESH);
  2809. }
  2810. /*ARGSUSED*/
  2811. CCRETVAL
  2812. v_substline(Char c)
  2813. { /* vi mode replace whole line */
  2814. USE(c);
  2815. (void) e_killall(0);
  2816. c_alternativ_key_map(0);
  2817. return(CC_REFRESH);
  2818. }
  2819. /*ARGSUSED*/
  2820. CCRETVAL
  2821. v_chgtoend(Char c)
  2822. { /* vi mode change to end of line */
  2823. USE(c);
  2824. (void) e_killend(0);
  2825. c_alternativ_key_map(0);
  2826. return(CC_REFRESH);
  2827. }
  2828. /*ARGSUSED*/
  2829. CCRETVAL
  2830. v_insert(Char c)
  2831. { /* vi mode start inserting */
  2832. USE(c);
  2833. c_alternativ_key_map(0);
  2834. InsertPos = Cursor;
  2835. UndoPtr = Cursor;
  2836. UndoAction = TCSHOP_DELETE;
  2837. return(CC_NORM);
  2838. }
  2839. /*ARGSUSED*/
  2840. CCRETVAL
  2841. v_add(Char c)
  2842. { /* vi mode start adding */
  2843. USE(c);
  2844. c_alternativ_key_map(0);
  2845. if (Cursor < LastChar)
  2846. {
  2847. Cursor++;
  2848. if (Cursor > LastChar)
  2849. Cursor = LastChar;
  2850. RefCursor();
  2851. }
  2852. InsertPos = Cursor;
  2853. UndoPtr = Cursor;
  2854. UndoAction = TCSHOP_DELETE;
  2855. return(CC_NORM);
  2856. }
  2857. /*ARGSUSED*/
  2858. CCRETVAL
  2859. v_addend(Char c)
  2860. { /* vi mode to add at end of line */
  2861. USE(c);
  2862. c_alternativ_key_map(0);
  2863. Cursor = LastChar;
  2864. InsertPos = LastChar; /* Mark where insertion begins */
  2865. UndoPtr = LastChar;
  2866. UndoAction = TCSHOP_DELETE;
  2867. RefCursor();
  2868. return(CC_NORM);
  2869. }
  2870. /*ARGSUSED*/
  2871. CCRETVAL
  2872. v_change_case(Char cc)
  2873. {
  2874. Char c;
  2875. USE(cc);
  2876. if (Cursor < LastChar) {
  2877. #ifndef WINNT_NATIVE
  2878. c = *Cursor;
  2879. #else
  2880. c = CHAR & *Cursor;
  2881. #endif /* WINNT_NATIVE */
  2882. if (Isupper(c))
  2883. *Cursor++ = Tolower(c);
  2884. else if (Islower(c))
  2885. *Cursor++ = Toupper(c);
  2886. else
  2887. Cursor++;
  2888. RefPlusOne(1); /* fast refresh for one char */
  2889. return(CC_NORM);
  2890. }
  2891. return(CC_ERROR);
  2892. }
  2893. /*ARGSUSED*/
  2894. CCRETVAL
  2895. e_expand(Char c)
  2896. {
  2897. Char *p;
  2898. USE(c);
  2899. for (p = InputBuf; Isspace(*p); p++)
  2900. continue;
  2901. if (p == LastChar)
  2902. return(CC_ERROR);
  2903. justpr++;
  2904. Expand++;
  2905. return(e_newline(0));
  2906. }
  2907. /*ARGSUSED*/
  2908. CCRETVAL
  2909. e_startover(Char c)
  2910. { /* erase all of current line, start again */
  2911. USE(c);
  2912. ResetInLine(0); /* reset the input pointers */
  2913. return(CC_REFRESH);
  2914. }
  2915. /*ARGSUSED*/
  2916. CCRETVAL
  2917. e_redisp(Char c)
  2918. {
  2919. USE(c);
  2920. ClearLines();
  2921. ClearDisp();
  2922. return(CC_REFRESH);
  2923. }
  2924. /*ARGSUSED*/
  2925. CCRETVAL
  2926. e_cleardisp(Char c)
  2927. {
  2928. USE(c);
  2929. ClearScreen(); /* clear the whole real screen */
  2930. ClearDisp(); /* reset everything */
  2931. return(CC_REFRESH);
  2932. }
  2933. /*ARGSUSED*/
  2934. CCRETVAL
  2935. e_tty_int(Char c)
  2936. {
  2937. USE(c);
  2938. #if defined(_MINIX) || defined(WINNT_NATIVE)
  2939. /* SAK PATCH: erase all of current line, start again */
  2940. ResetInLine(0); /* reset the input pointers */
  2941. xputchar('\n');
  2942. ClearDisp();
  2943. return (CC_REFRESH);
  2944. #else /* !_MINIX && !WINNT_NATIVE */
  2945. /* do no editing */
  2946. return (CC_NORM);
  2947. #endif /* _MINIX || WINNT_NATIVE */
  2948. }
  2949. /*
  2950. * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi)
  2951. * Function to send a character back to the input stream in cooked
  2952. * mode. Only works if we have TIOCSTI
  2953. */
  2954. /*ARGSUSED*/
  2955. CCRETVAL
  2956. e_stuff_char(Char c)
  2957. {
  2958. #ifdef TIOCSTI
  2959. int was_raw = Tty_raw_mode;
  2960. char buf[MB_LEN_MAX];
  2961. size_t i, len;
  2962. if (was_raw)
  2963. (void) Cookedmode();
  2964. (void) xwrite(SHIN, "\n", 1);
  2965. len = one_wctomb(buf, c & CHAR);
  2966. for (i = 0; i < len; i++)
  2967. (void) ioctl(SHIN, TIOCSTI, (ioctl_t) &buf[i]);
  2968. if (was_raw)
  2969. (void) Rawmode();
  2970. return(e_redisp(c));
  2971. #else /* !TIOCSTI */
  2972. return(CC_ERROR);
  2973. #endif /* !TIOCSTI */
  2974. }
  2975. /*ARGSUSED*/
  2976. CCRETVAL
  2977. e_insovr(Char c)
  2978. {
  2979. USE(c);
  2980. inputmode = (inputmode == MODE_INSERT ? MODE_REPLACE : MODE_INSERT);
  2981. return(CC_NORM);
  2982. }
  2983. /*ARGSUSED*/
  2984. CCRETVAL
  2985. e_tty_dsusp(Char c)
  2986. {
  2987. USE(c);
  2988. /* do no editing */
  2989. return(CC_NORM);
  2990. }
  2991. /*ARGSUSED*/
  2992. CCRETVAL
  2993. e_tty_flusho(Char c)
  2994. {
  2995. USE(c);
  2996. /* do no editing */
  2997. return(CC_NORM);
  2998. }
  2999. /*ARGSUSED*/
  3000. CCRETVAL
  3001. e_tty_quit(Char c)
  3002. {
  3003. USE(c);
  3004. /* do no editing */
  3005. return(CC_NORM);
  3006. }
  3007. /*ARGSUSED*/
  3008. CCRETVAL
  3009. e_tty_tsusp(Char c)
  3010. {
  3011. USE(c);
  3012. /* do no editing */
  3013. return(CC_NORM);
  3014. }
  3015. /*ARGSUSED*/
  3016. CCRETVAL
  3017. e_tty_stopo(Char c)
  3018. {
  3019. USE(c);
  3020. /* do no editing */
  3021. return(CC_NORM);
  3022. }
  3023. /* returns the number of (attempted) expansions */
  3024. int
  3025. ExpandHistory(void)
  3026. {
  3027. *LastChar = '\0'; /* just in case */
  3028. return c_substitute();
  3029. }
  3030. /*ARGSUSED*/
  3031. CCRETVAL
  3032. e_expand_history(Char c)
  3033. {
  3034. USE(c);
  3035. (void)ExpandHistory();
  3036. return(CC_NORM);
  3037. }
  3038. /*ARGSUSED*/
  3039. CCRETVAL
  3040. e_magic_space(Char c)
  3041. {
  3042. USE(c);
  3043. *LastChar = '\0'; /* just in case */
  3044. (void)c_substitute();
  3045. return(e_insert(' '));
  3046. }
  3047. /*ARGSUSED*/
  3048. CCRETVAL
  3049. e_inc_fwd(Char c)
  3050. {
  3051. CCRETVAL ret;
  3052. USE(c);
  3053. patbuf.len = 0;
  3054. MarkIsSet = 0;
  3055. ret = e_inc_search(F_DOWN_SEARCH_HIST);
  3056. if (adrof(STRhighlight) && IncMatchLen) {
  3057. IncMatchLen = 0;
  3058. ClearLines();
  3059. ClearDisp();
  3060. Refresh();
  3061. }
  3062. IncMatchLen = 0;
  3063. return ret;
  3064. }
  3065. /*ARGSUSED*/
  3066. CCRETVAL
  3067. e_inc_back(Char c)
  3068. {
  3069. CCRETVAL ret;
  3070. USE(c);
  3071. patbuf.len = 0;
  3072. MarkIsSet = 0;
  3073. ret = e_inc_search(F_UP_SEARCH_HIST);
  3074. if (adrof(STRhighlight) && IncMatchLen) {
  3075. IncMatchLen = 0;
  3076. ClearLines();
  3077. ClearDisp();
  3078. Refresh();
  3079. }
  3080. IncMatchLen = 0;
  3081. return ret;
  3082. }
  3083. /*ARGSUSED*/
  3084. CCRETVAL
  3085. e_copyprev(Char c)
  3086. {
  3087. Char *cp, *oldc, *dp;
  3088. USE(c);
  3089. if (Cursor == InputBuf)
  3090. return(CC_ERROR);
  3091. /* else */
  3092. oldc = Cursor;
  3093. /* does a bounds check */
  3094. cp = c_prev_word(Cursor, InputBuf, Argument);
  3095. c_insert((int)(oldc - cp));
  3096. for (dp = oldc; cp < oldc && dp < LastChar; cp++)
  3097. *dp++ = *cp;
  3098. Cursor = dp; /* put cursor at end */
  3099. return(CC_REFRESH);
  3100. }
  3101. /*ARGSUSED*/
  3102. CCRETVAL
  3103. e_tty_starto(Char c)
  3104. {
  3105. USE(c);
  3106. /* do no editing */
  3107. return(CC_NORM);
  3108. }
  3109. /*ARGSUSED*/
  3110. CCRETVAL
  3111. e_load_average(Char c)
  3112. {
  3113. USE(c);
  3114. PastBottom();
  3115. #ifdef TIOCSTAT
  3116. /*
  3117. * Here we pass &c to the ioctl because some os's (NetBSD) expect it
  3118. * there even if they don't use it. (lukem@netbsd.org)
  3119. */
  3120. if (ioctl(SHIN, TIOCSTAT, (ioctl_t) &c) < 0)
  3121. #endif
  3122. xprintf("%s", CGETS(5, 1, "Load average unavailable\n"));
  3123. return(CC_REFRESH);
  3124. }
  3125. /*ARGSUSED*/
  3126. CCRETVAL
  3127. v_chgmeta(Char c)
  3128. {
  3129. USE(c);
  3130. /*
  3131. * Delete with insert == change: first we delete and then we leave in
  3132. * insert mode.
  3133. */
  3134. return(v_action(TCSHOP_DELETE|TCSHOP_INSERT));
  3135. }
  3136. /*ARGSUSED*/
  3137. CCRETVAL
  3138. v_delmeta(Char c)
  3139. {
  3140. USE(c);
  3141. return(v_action(TCSHOP_DELETE));
  3142. }
  3143. /*ARGSUSED*/
  3144. CCRETVAL
  3145. v_endword(Char c)
  3146. {
  3147. USE(c);
  3148. if (Cursor == LastChar)
  3149. return(CC_ERROR);
  3150. /* else */
  3151. Cursor = c_endword(Cursor, LastChar, Argument, STRshwspace);
  3152. if (ActionFlag & TCSHOP_DELETE)
  3153. {
  3154. Cursor++;
  3155. c_delfini();
  3156. return(CC_REFRESH);
  3157. }
  3158. RefCursor();
  3159. return(CC_NORM);
  3160. }
  3161. /*ARGSUSED*/
  3162. CCRETVAL
  3163. v_eword(Char c)
  3164. {
  3165. USE(c);
  3166. if (Cursor == LastChar)
  3167. return(CC_ERROR);
  3168. /* else */
  3169. Cursor = c_eword(Cursor, LastChar, Argument);
  3170. if (ActionFlag & TCSHOP_DELETE) {
  3171. Cursor++;
  3172. c_delfini();
  3173. return(CC_REFRESH);
  3174. }
  3175. RefCursor();
  3176. return(CC_NORM);
  3177. }
  3178. /*ARGSUSED*/
  3179. CCRETVAL
  3180. v_char_fwd(Char c)
  3181. {
  3182. Char ch;
  3183. USE(c);
  3184. if (GetNextChar(&ch) != 1)
  3185. return e_send_eof(0);
  3186. srch_dir = CHAR_FWD;
  3187. srch_char = ch;
  3188. return v_csearch_fwd(ch, Argument, 0);
  3189. }
  3190. /*ARGSUSED*/
  3191. CCRETVAL
  3192. v_char_back(Char c)
  3193. {
  3194. Char ch;
  3195. USE(c);
  3196. if (GetNextChar(&ch) != 1)
  3197. return e_send_eof(0);
  3198. srch_dir = CHAR_BACK;
  3199. srch_char = ch;
  3200. return v_csearch_back(ch, Argument, 0);
  3201. }
  3202. /*ARGSUSED*/
  3203. CCRETVAL
  3204. v_charto_fwd(Char c)
  3205. {
  3206. Char ch;
  3207. USE(c);
  3208. if (GetNextChar(&ch) != 1)
  3209. return e_send_eof(0);
  3210. return v_csearch_fwd(ch, Argument, 1);
  3211. }
  3212. /*ARGSUSED*/
  3213. CCRETVAL
  3214. v_charto_back(Char c)
  3215. {
  3216. Char ch;
  3217. USE(c);
  3218. if (GetNextChar(&ch) != 1)
  3219. return e_send_eof(0);
  3220. return v_csearch_back(ch, Argument, 1);
  3221. }
  3222. /*ARGSUSED*/
  3223. CCRETVAL
  3224. v_rchar_fwd(Char c)
  3225. {
  3226. USE(c);
  3227. if (srch_char == 0)
  3228. return CC_ERROR;
  3229. return srch_dir == CHAR_FWD ? v_csearch_fwd(srch_char, Argument, 0) :
  3230. v_csearch_back(srch_char, Argument, 0);
  3231. }
  3232. /*ARGSUSED*/
  3233. CCRETVAL
  3234. v_rchar_back(Char c)
  3235. {
  3236. USE(c);
  3237. if (srch_char == 0)
  3238. return CC_ERROR;
  3239. return srch_dir == CHAR_BACK ? v_csearch_fwd(srch_char, Argument, 0) :
  3240. v_csearch_back(srch_char, Argument, 0);
  3241. }
  3242. /*ARGSUSED*/
  3243. CCRETVAL
  3244. v_undo(Char c)
  3245. {
  3246. int loop;
  3247. Char *kp, *cp;
  3248. Char temp;
  3249. int size;
  3250. USE(c);
  3251. switch (UndoAction) {
  3252. case TCSHOP_DELETE|TCSHOP_INSERT:
  3253. case TCSHOP_DELETE:
  3254. if (UndoSize == 0) return(CC_NORM);
  3255. cp = UndoPtr;
  3256. kp = UndoBuf;
  3257. for (loop=0; loop < UndoSize; loop++) /* copy the chars */
  3258. *kp++ = *cp++; /* into UndoBuf */
  3259. for (cp = UndoPtr; cp <= LastChar; cp++)
  3260. *cp = cp[UndoSize];
  3261. LastChar -= UndoSize;
  3262. Cursor = UndoPtr;
  3263. UndoAction = TCSHOP_INSERT;
  3264. break;
  3265. case TCSHOP_INSERT:
  3266. if (UndoSize == 0) return(CC_NORM);
  3267. cp = UndoPtr;
  3268. Cursor = UndoPtr;
  3269. kp = UndoBuf;
  3270. c_insert(UndoSize); /* open the space, */
  3271. for (loop = 0; loop < UndoSize; loop++) /* copy the chars */
  3272. *cp++ = *kp++;
  3273. UndoAction = TCSHOP_DELETE;
  3274. break;
  3275. case TCSHOP_CHANGE:
  3276. if (UndoSize == 0) return(CC_NORM);
  3277. cp = UndoPtr;
  3278. Cursor = UndoPtr;
  3279. kp = UndoBuf;
  3280. size = (int)(Cursor-LastChar); /* NOT NSL independant */
  3281. if (size < UndoSize)
  3282. size = UndoSize;
  3283. for(loop = 0; loop < size; loop++) {
  3284. temp = *kp;
  3285. *kp++ = *cp;
  3286. *cp++ = temp;
  3287. }
  3288. break;
  3289. default:
  3290. return(CC_ERROR);
  3291. }
  3292. return(CC_REFRESH);
  3293. }
  3294. /*ARGSUSED*/
  3295. CCRETVAL
  3296. v_ush_meta(Char c)
  3297. {
  3298. USE(c);
  3299. return v_search(F_UP_SEARCH_HIST);
  3300. }
  3301. /*ARGSUSED*/
  3302. CCRETVAL
  3303. v_dsh_meta(Char c)
  3304. {
  3305. USE(c);
  3306. return v_search(F_DOWN_SEARCH_HIST);
  3307. }
  3308. /*ARGSUSED*/
  3309. CCRETVAL
  3310. v_rsrch_fwd(Char c)
  3311. {
  3312. USE(c);
  3313. if (patbuf.len == 0) return(CC_ERROR);
  3314. return(v_repeat_srch(searchdir));
  3315. }
  3316. /*ARGSUSED*/
  3317. CCRETVAL
  3318. v_rsrch_back(Char c)
  3319. {
  3320. USE(c);
  3321. if (patbuf.len == 0) return(CC_ERROR);
  3322. return(v_repeat_srch(searchdir == F_UP_SEARCH_HIST ?
  3323. F_DOWN_SEARCH_HIST : F_UP_SEARCH_HIST));
  3324. }
  3325. #ifndef WINNT_NATIVE
  3326. /* Since ed.defns.h is generated from ed.defns.c, these empty
  3327. functions will keep the F_NUM_FNS consistent
  3328. */
  3329. CCRETVAL
  3330. e_copy_to_clipboard(Char c)
  3331. {
  3332. USE(c);
  3333. return CC_ERROR;
  3334. }
  3335. CCRETVAL
  3336. e_paste_from_clipboard(Char c)
  3337. {
  3338. USE(c);
  3339. return (CC_ERROR);
  3340. }
  3341. CCRETVAL
  3342. e_dosify_next(Char c)
  3343. {
  3344. USE(c);
  3345. return (CC_ERROR);
  3346. }
  3347. CCRETVAL
  3348. e_dosify_prev(Char c)
  3349. {
  3350. USE(c);
  3351. return (CC_ERROR);
  3352. }
  3353. CCRETVAL
  3354. e_page_up(Char c)
  3355. {
  3356. USE(c);
  3357. return (CC_ERROR);
  3358. }
  3359. CCRETVAL
  3360. e_page_down(Char c)
  3361. {
  3362. USE(c);
  3363. return (CC_ERROR);
  3364. }
  3365. #endif /* !WINNT_NATIVE */
  3366. #ifdef notdef
  3367. void
  3368. MoveCursor(int n) /* move cursor + right - left char */
  3369. {
  3370. Cursor = Cursor + n;
  3371. if (Cursor < InputBuf)
  3372. Cursor = InputBuf;
  3373. if (Cursor > LastChar)
  3374. Cursor = LastChar;
  3375. return;
  3376. }
  3377. Char *
  3378. GetCursor(void)
  3379. {
  3380. return(Cursor);
  3381. }
  3382. int
  3383. PutCursor(Char *p)
  3384. {
  3385. if (p < InputBuf || p > LastChar)
  3386. return 1; /* Error */
  3387. Cursor = p;
  3388. return 0;
  3389. }
  3390. #endif