chared.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. /* $NetBSD: chared.c,v 1.15 2002/03/18 16:00:50 christos Exp $ */
  2. /*-
  3. * Copyright (c) 1992, 1993
  4. * The Regents of the University of California. All rights reserved.
  5. *
  6. * This code is derived from software contributed to Berkeley by
  7. * Christos Zoulas of Cornell University.
  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. All advertising materials mentioning features or use of this software
  18. * must display the following acknowledgement:
  19. * This product includes software developed by the University of
  20. * California, Berkeley and its contributors.
  21. * 4. Neither the name of the University nor the names of its contributors
  22. * may be used to endorse or promote products derived from this software
  23. * without specific prior written permission.
  24. *
  25. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35. * SUCH DAMAGE.
  36. */
  37. #include "config.h"
  38. #if !defined(lint) && !defined(SCCSID)
  39. #if 0
  40. static char sccsid[] = "@(#)chared.c 8.1 (Berkeley) 6/4/93";
  41. #else
  42. __RCSID("$NetBSD: chared.c,v 1.15 2002/03/18 16:00:50 christos Exp $");
  43. #endif
  44. #endif /* not lint && not SCCSID */
  45. /*
  46. * chared.c: Character editor utilities
  47. */
  48. #include <stdlib.h>
  49. #include "el.h"
  50. /* value to leave unused in line buffer */
  51. #define EL_LEAVE 2
  52. /* cv_undo():
  53. * Handle state for the vi undo command
  54. */
  55. protected void
  56. cv_undo(EditLine *el,int action, size_t size, char *ptr)
  57. {
  58. c_undo_t *vu = &el->el_chared.c_undo;
  59. vu->action = action;
  60. vu->ptr = ptr;
  61. vu->isize = size;
  62. (void) memcpy(vu->buf, vu->ptr, size);
  63. #ifdef DEBUG_UNDO
  64. (void) fprintf(el->el_errfile, "Undo buffer \"%s\" size = +%d -%d\n",
  65. vu->ptr, vu->isize, vu->dsize);
  66. #endif
  67. }
  68. /* c_insert():
  69. * Insert num characters
  70. */
  71. protected void
  72. c_insert(EditLine *el, int num)
  73. {
  74. char *cp;
  75. if (el->el_line.lastchar + num >= el->el_line.limit)
  76. return; /* can't go past end of buffer */
  77. if (el->el_line.cursor < el->el_line.lastchar) {
  78. /* if I must move chars */
  79. for (cp = el->el_line.lastchar; cp >= el->el_line.cursor; cp--)
  80. cp[num] = *cp;
  81. }
  82. el->el_line.lastchar += num;
  83. }
  84. /* c_delafter():
  85. * Delete num characters after the cursor
  86. */
  87. protected void
  88. c_delafter(EditLine *el, int num)
  89. {
  90. if (el->el_line.cursor + num > el->el_line.lastchar)
  91. num = el->el_line.lastchar - el->el_line.cursor;
  92. if (num > 0) {
  93. char *cp;
  94. if (el->el_map.current != el->el_map.emacs)
  95. cv_undo(el, INSERT, (size_t)num, el->el_line.cursor);
  96. for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
  97. *cp = cp[num];
  98. el->el_line.lastchar -= num;
  99. }
  100. }
  101. /* c_delbefore():
  102. * Delete num characters before the cursor
  103. */
  104. protected void
  105. c_delbefore(EditLine *el, int num)
  106. {
  107. if (el->el_line.cursor - num < el->el_line.buffer)
  108. num = el->el_line.cursor - el->el_line.buffer;
  109. if (num > 0) {
  110. char *cp;
  111. if (el->el_map.current != el->el_map.emacs)
  112. cv_undo(el, INSERT, (size_t)num,
  113. el->el_line.cursor - num);
  114. for (cp = el->el_line.cursor - num;
  115. cp <= el->el_line.lastchar;
  116. cp++)
  117. *cp = cp[num];
  118. el->el_line.lastchar -= num;
  119. }
  120. }
  121. /* ce__isword():
  122. * Return if p is part of a word according to emacs
  123. */
  124. protected int
  125. ce__isword(int p)
  126. {
  127. return (isalpha(p) || isdigit(p) || strchr("*?_-.[]~=", p) != NULL);
  128. }
  129. /* cv__isword():
  130. * Return if p is part of a word according to vi
  131. */
  132. protected int
  133. cv__isword(int p)
  134. {
  135. return (!isspace(p));
  136. }
  137. /* c__prev_word():
  138. * Find the previous word
  139. */
  140. protected char *
  141. c__prev_word(char *p, char *low, int n, int (*wtest)(int))
  142. {
  143. p--;
  144. while (n--) {
  145. while ((p >= low) && !(*wtest)((unsigned char) *p))
  146. p--;
  147. while ((p >= low) && (*wtest)((unsigned char) *p))
  148. p--;
  149. }
  150. /* cp now points to one character before the word */
  151. p++;
  152. if (p < low)
  153. p = low;
  154. /* cp now points where we want it */
  155. return (p);
  156. }
  157. /* c__next_word():
  158. * Find the next word
  159. */
  160. protected char *
  161. c__next_word(char *p, char *high, int n, int (*wtest)(int))
  162. {
  163. while (n--) {
  164. while ((p < high) && !(*wtest)((unsigned char) *p))
  165. p++;
  166. while ((p < high) && (*wtest)((unsigned char) *p))
  167. p++;
  168. }
  169. if (p > high)
  170. p = high;
  171. /* p now points where we want it */
  172. return (p);
  173. }
  174. /* cv_next_word():
  175. * Find the next word vi style
  176. */
  177. protected char *
  178. cv_next_word(EditLine *el, char *p, char *high, int n, int (*wtest)(int))
  179. {
  180. int test;
  181. while (n--) {
  182. test = (*wtest)((unsigned char) *p);
  183. while ((p < high) && (*wtest)((unsigned char) *p) == test)
  184. p++;
  185. /*
  186. * vi historically deletes with cw only the word preserving the
  187. * trailing whitespace! This is not what 'w' does..
  188. */
  189. if (el->el_chared.c_vcmd.action != (DELETE|INSERT))
  190. while ((p < high) && isspace((unsigned char) *p))
  191. p++;
  192. }
  193. /* p now points where we want it */
  194. if (p > high)
  195. return (high);
  196. else
  197. return (p);
  198. }
  199. /* cv_prev_word():
  200. * Find the previous word vi style
  201. */
  202. protected char *
  203. cv_prev_word(EditLine *el, char *p, char *low, int n, int (*wtest)(int))
  204. {
  205. int test;
  206. while (n--) {
  207. p--;
  208. /*
  209. * vi historically deletes with cb only the word preserving the
  210. * leading whitespace! This is not what 'b' does..
  211. */
  212. if (el->el_chared.c_vcmd.action != (DELETE|INSERT))
  213. while ((p > low) && isspace((unsigned char) *p))
  214. p--;
  215. test = (*wtest)((unsigned char) *p);
  216. while ((p >= low) && (*wtest)((unsigned char) *p) == test)
  217. p--;
  218. p++;
  219. while (isspace((unsigned char) *p))
  220. p++;
  221. }
  222. /* p now points where we want it */
  223. if (p < low)
  224. return (low);
  225. else
  226. return (p);
  227. }
  228. #ifdef notdef
  229. /* c__number():
  230. * Ignore character p points to, return number appearing after that.
  231. * A '$' by itself means a big number; "$-" is for negative; '^' means 1.
  232. * Return p pointing to last char used.
  233. */
  234. protected char *
  235. c__number(
  236. char *p, /* character position */
  237. int *num, /* Return value */
  238. int dval) /* dval is the number to subtract from like $-3 */
  239. {
  240. int i;
  241. int sign = 1;
  242. if (*++p == '^') {
  243. *num = 1;
  244. return (p);
  245. }
  246. if (*p == '$') {
  247. if (*++p != '-') {
  248. *num = 0x7fffffff; /* Handle $ */
  249. return (--p);
  250. }
  251. sign = -1; /* Handle $- */
  252. ++p;
  253. }
  254. for (i = 0; isdigit((unsigned char) *p); i = 10 * i + *p++ - '0')
  255. continue;
  256. *num = (sign < 0 ? dval - i : i);
  257. return (--p);
  258. }
  259. #endif
  260. /* cv_delfini():
  261. * Finish vi delete action
  262. */
  263. protected void
  264. cv_delfini(EditLine *el)
  265. {
  266. int size;
  267. int oaction;
  268. if (el->el_chared.c_vcmd.action & INSERT)
  269. el->el_map.current = el->el_map.key;
  270. oaction = el->el_chared.c_vcmd.action;
  271. el->el_chared.c_vcmd.action = NOP;
  272. if (el->el_chared.c_vcmd.pos == 0)
  273. return;
  274. if (el->el_line.cursor > el->el_chared.c_vcmd.pos) {
  275. size = (int) (el->el_line.cursor - el->el_chared.c_vcmd.pos);
  276. c_delbefore(el, size);
  277. el->el_line.cursor = el->el_chared.c_vcmd.pos;
  278. re_refresh_cursor(el);
  279. } else if (el->el_line.cursor < el->el_chared.c_vcmd.pos) {
  280. size = (int)(el->el_chared.c_vcmd.pos - el->el_line.cursor);
  281. c_delafter(el, size);
  282. } else {
  283. size = 1;
  284. c_delafter(el, size);
  285. }
  286. switch (oaction) {
  287. case DELETE|INSERT:
  288. el->el_chared.c_undo.action = DELETE|INSERT;
  289. break;
  290. case DELETE:
  291. el->el_chared.c_undo.action = INSERT;
  292. break;
  293. case NOP:
  294. case INSERT:
  295. default:
  296. EL_ABORT((el->el_errfile, "Bad oaction %d\n", oaction));
  297. break;
  298. }
  299. el->el_chared.c_undo.ptr = el->el_line.cursor;
  300. el->el_chared.c_undo.dsize = size;
  301. }
  302. #ifdef notdef
  303. /* ce__endword():
  304. * Go to the end of this word according to emacs
  305. */
  306. protected char *
  307. ce__endword(char *p, char *high, int n)
  308. {
  309. p++;
  310. while (n--) {
  311. while ((p < high) && isspace((unsigned char) *p))
  312. p++;
  313. while ((p < high) && !isspace((unsigned char) *p))
  314. p++;
  315. }
  316. p--;
  317. return (p);
  318. }
  319. #endif
  320. /* cv__endword():
  321. * Go to the end of this word according to vi
  322. */
  323. protected char *
  324. cv__endword(char *p, char *high, int n)
  325. {
  326. p++;
  327. while (n--) {
  328. while ((p < high) && isspace((unsigned char) *p))
  329. p++;
  330. if (isalnum((unsigned char) *p))
  331. while ((p < high) && isalnum((unsigned char) *p))
  332. p++;
  333. else
  334. while ((p < high) && !(isspace((unsigned char) *p) ||
  335. isalnum((unsigned char) *p)))
  336. p++;
  337. }
  338. p--;
  339. return (p);
  340. }
  341. /* ch_init():
  342. * Initialize the character editor
  343. */
  344. protected int
  345. ch_init(EditLine *el)
  346. {
  347. el->el_line.buffer = (char *) el_malloc(EL_BUFSIZ);
  348. if (el->el_line.buffer == NULL)
  349. return (-1);
  350. (void) memset(el->el_line.buffer, 0, EL_BUFSIZ);
  351. el->el_line.cursor = el->el_line.buffer;
  352. el->el_line.lastchar = el->el_line.buffer;
  353. el->el_line.limit = &el->el_line.buffer[EL_BUFSIZ - 2];
  354. el->el_chared.c_undo.buf = (char *) el_malloc(EL_BUFSIZ);
  355. if (el->el_chared.c_undo.buf == NULL)
  356. return (-1);
  357. (void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ);
  358. el->el_chared.c_undo.action = NOP;
  359. el->el_chared.c_undo.isize = 0;
  360. el->el_chared.c_undo.dsize = 0;
  361. el->el_chared.c_undo.ptr = el->el_line.buffer;
  362. el->el_chared.c_vcmd.action = NOP;
  363. el->el_chared.c_vcmd.pos = el->el_line.buffer;
  364. el->el_chared.c_vcmd.ins = el->el_line.buffer;
  365. el->el_chared.c_kill.buf = (char *) el_malloc(EL_BUFSIZ);
  366. if (el->el_chared.c_kill.buf == NULL)
  367. return (-1);
  368. (void) memset(el->el_chared.c_kill.buf, 0, EL_BUFSIZ);
  369. el->el_chared.c_kill.mark = el->el_line.buffer;
  370. el->el_chared.c_kill.last = el->el_chared.c_kill.buf;
  371. el->el_map.current = el->el_map.key;
  372. el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */
  373. el->el_state.doingarg = 0;
  374. el->el_state.metanext = 0;
  375. el->el_state.argument = 1;
  376. el->el_state.lastcmd = ED_UNASSIGNED;
  377. el->el_chared.c_macro.nline = NULL;
  378. el->el_chared.c_macro.level = -1;
  379. el->el_chared.c_macro.macro = (char **) el_malloc(EL_MAXMACRO *
  380. sizeof(char *));
  381. if (el->el_chared.c_macro.macro == NULL)
  382. return (-1);
  383. return (0);
  384. }
  385. /* ch_reset():
  386. * Reset the character editor
  387. */
  388. protected void
  389. ch_reset(EditLine *el)
  390. {
  391. el->el_line.cursor = el->el_line.buffer;
  392. el->el_line.lastchar = el->el_line.buffer;
  393. el->el_chared.c_undo.action = NOP;
  394. el->el_chared.c_undo.isize = 0;
  395. el->el_chared.c_undo.dsize = 0;
  396. el->el_chared.c_undo.ptr = el->el_line.buffer;
  397. el->el_chared.c_vcmd.action = NOP;
  398. el->el_chared.c_vcmd.pos = el->el_line.buffer;
  399. el->el_chared.c_vcmd.ins = el->el_line.buffer;
  400. el->el_chared.c_kill.mark = el->el_line.buffer;
  401. el->el_map.current = el->el_map.key;
  402. el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */
  403. el->el_state.doingarg = 0;
  404. el->el_state.metanext = 0;
  405. el->el_state.argument = 1;
  406. el->el_state.lastcmd = ED_UNASSIGNED;
  407. el->el_chared.c_macro.level = -1;
  408. el->el_history.eventno = 0;
  409. }
  410. /* ch_enlargebufs():
  411. * Enlarge line buffer to be able to hold twice as much characters.
  412. * Returns 1 if successful, 0 if not.
  413. */
  414. protected int
  415. ch_enlargebufs(el, addlen)
  416. EditLine *el;
  417. size_t addlen;
  418. {
  419. size_t sz, newsz;
  420. char *newbuffer, *oldbuf, *oldkbuf;
  421. sz = el->el_line.limit - el->el_line.buffer + EL_LEAVE;
  422. newsz = sz * 2;
  423. /*
  424. * If newly required length is longer than current buffer, we need
  425. * to make the buffer big enough to hold both old and new stuff.
  426. */
  427. if (addlen > sz) {
  428. while(newsz - sz < addlen)
  429. newsz *= 2;
  430. }
  431. /*
  432. * Reallocate line buffer.
  433. */
  434. newbuffer = el_realloc(el->el_line.buffer, newsz);
  435. if (!newbuffer)
  436. return 0;
  437. /* zero the newly added memory, leave old data in */
  438. (void) memset(&newbuffer[sz], 0, newsz - sz);
  439. oldbuf = el->el_line.buffer;
  440. el->el_line.buffer = newbuffer;
  441. el->el_line.cursor = newbuffer + (el->el_line.cursor - oldbuf);
  442. el->el_line.lastchar = newbuffer + (el->el_line.lastchar - oldbuf);
  443. el->el_line.limit = &newbuffer[newsz - EL_LEAVE];
  444. /*
  445. * Reallocate kill buffer.
  446. */
  447. newbuffer = el_realloc(el->el_chared.c_kill.buf, newsz);
  448. if (!newbuffer)
  449. return 0;
  450. /* zero the newly added memory, leave old data in */
  451. (void) memset(&newbuffer[sz], 0, newsz - sz);
  452. oldkbuf = el->el_chared.c_kill.buf;
  453. el->el_chared.c_kill.buf = newbuffer;
  454. el->el_chared.c_kill.last = newbuffer +
  455. (el->el_chared.c_kill.last - oldkbuf);
  456. el->el_chared.c_kill.mark = el->el_line.buffer +
  457. (el->el_chared.c_kill.mark - oldbuf);
  458. /*
  459. * Reallocate undo buffer.
  460. */
  461. newbuffer = el_realloc(el->el_chared.c_undo.buf, newsz);
  462. if (!newbuffer)
  463. return 0;
  464. /* zero the newly added memory, leave old data in */
  465. (void) memset(&newbuffer[sz], 0, newsz - sz);
  466. el->el_chared.c_undo.ptr = el->el_line.buffer +
  467. (el->el_chared.c_undo.ptr - oldbuf);
  468. el->el_chared.c_undo.buf = newbuffer;
  469. if (!hist_enlargebuf(el, sz, newsz))
  470. return 0;
  471. return 1;
  472. }
  473. /* ch_end():
  474. * Free the data structures used by the editor
  475. */
  476. protected void
  477. ch_end(EditLine *el)
  478. {
  479. el_free((ptr_t) el->el_line.buffer);
  480. el->el_line.buffer = NULL;
  481. el->el_line.limit = NULL;
  482. el_free((ptr_t) el->el_chared.c_undo.buf);
  483. el->el_chared.c_undo.buf = NULL;
  484. el_free((ptr_t) el->el_chared.c_kill.buf);
  485. el->el_chared.c_kill.buf = NULL;
  486. el_free((ptr_t) el->el_chared.c_macro.macro);
  487. el->el_chared.c_macro.macro = NULL;
  488. ch_reset(el);
  489. }
  490. /* el_insertstr():
  491. * Insert string at cursorI
  492. */
  493. public int
  494. el_insertstr(EditLine *el, const char *s)
  495. {
  496. size_t len;
  497. if ((len = strlen(s)) == 0)
  498. return (-1);
  499. if (el->el_line.lastchar + len >= el->el_line.limit) {
  500. if (!ch_enlargebufs(el, len))
  501. return (-1);
  502. }
  503. c_insert(el, (int)len);
  504. while (*s)
  505. *el->el_line.cursor++ = *s++;
  506. return (0);
  507. }
  508. /* el_deletestr():
  509. * Delete num characters before the cursor
  510. */
  511. public void
  512. el_deletestr(EditLine *el, int n)
  513. {
  514. if (n <= 0)
  515. return;
  516. if (el->el_line.cursor < &el->el_line.buffer[n])
  517. return;
  518. c_delbefore(el, n); /* delete before dot */
  519. el->el_line.cursor -= n;
  520. if (el->el_line.cursor < el->el_line.buffer)
  521. el->el_line.cursor = el->el_line.buffer;
  522. }
  523. /* c_gets():
  524. * Get a string
  525. */
  526. protected int
  527. c_gets(EditLine *el, char *buf)
  528. {
  529. char ch;
  530. int len = 0;
  531. for (ch = 0; ch == 0;) {
  532. if (el_getc(el, &ch) != 1)
  533. return (ed_end_of_file(el, 0));
  534. switch (ch) {
  535. case 0010: /* Delete and backspace */
  536. case 0177:
  537. if (len > 1) {
  538. *el->el_line.cursor-- = '\0';
  539. el->el_line.lastchar = el->el_line.cursor;
  540. buf[len--] = '\0';
  541. } else {
  542. el->el_line.buffer[0] = '\0';
  543. el->el_line.lastchar = el->el_line.buffer;
  544. el->el_line.cursor = el->el_line.buffer;
  545. return (CC_REFRESH);
  546. }
  547. re_refresh(el);
  548. ch = 0;
  549. break;
  550. case 0033: /* ESC */
  551. case '\r': /* Newline */
  552. case '\n':
  553. break;
  554. default:
  555. if (len >= EL_BUFSIZ)
  556. term_beep(el);
  557. else {
  558. buf[len++] = ch;
  559. *el->el_line.cursor++ = ch;
  560. el->el_line.lastchar = el->el_line.cursor;
  561. }
  562. re_refresh(el);
  563. ch = 0;
  564. break;
  565. }
  566. }
  567. buf[len] = ch;
  568. return (len);
  569. }
  570. /* c_hpos():
  571. * Return the current horizontal position of the cursor
  572. */
  573. protected int
  574. c_hpos(EditLine *el)
  575. {
  576. char *ptr;
  577. /*
  578. * Find how many characters till the beginning of this line.
  579. */
  580. if (el->el_line.cursor == el->el_line.buffer)
  581. return (0);
  582. else {
  583. for (ptr = el->el_line.cursor - 1;
  584. ptr >= el->el_line.buffer && *ptr != '\n';
  585. ptr--)
  586. continue;
  587. return (el->el_line.cursor - ptr - 1);
  588. }
  589. }