key.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. /* $NetBSD: key.c,v 1.13 2002/03/18 16:00:55 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[] = "@(#)key.c 8.1 (Berkeley) 6/4/93";
  41. #else
  42. __RCSID("$NetBSD: key.c,v 1.13 2002/03/18 16:00:55 christos Exp $");
  43. #endif
  44. #endif /* not lint && not SCCSID */
  45. /*
  46. * key.c: This module contains the procedures for maintaining
  47. * the extended-key map.
  48. *
  49. * An extended-key (key) is a sequence of keystrokes introduced
  50. * with an sequence introducer and consisting of an arbitrary
  51. * number of characters. This module maintains a map (the el->el_key.map)
  52. * to convert these extended-key sequences into input strs
  53. * (XK_STR), editor functions (XK_CMD), or unix commands (XK_EXE).
  54. *
  55. * Warning:
  56. * If key is a substr of some other keys, then the longer
  57. * keys are lost!! That is, if the keys "abcd" and "abcef"
  58. * are in el->el_key.map, adding the key "abc" will cause the first two
  59. * definitions to be lost.
  60. *
  61. * Restrictions:
  62. * -------------
  63. * 1) It is not possible to have one key that is a
  64. * substr of another.
  65. */
  66. #include <string.h>
  67. #include <stdlib.h>
  68. #include "el.h"
  69. /*
  70. * The Nodes of the el->el_key.map. The el->el_key.map is a linked list
  71. * of these node elements
  72. */
  73. struct key_node_t {
  74. char ch; /* single character of key */
  75. int type; /* node type */
  76. key_value_t val; /* command code or pointer to str, */
  77. /* if this is a leaf */
  78. struct key_node_t *next; /* ptr to next char of this key */
  79. struct key_node_t *sibling; /* ptr to another key with same prefix*/
  80. };
  81. private int node_trav(EditLine *, key_node_t *, char *,
  82. key_value_t *);
  83. private int node__try(EditLine *, key_node_t *, const char *,
  84. key_value_t *, int);
  85. private key_node_t *node__get(int);
  86. private void node__put(EditLine *, key_node_t *);
  87. private int node__delete(EditLine *, key_node_t **, const char *);
  88. private int node_lookup(EditLine *, const char *, key_node_t *,
  89. int);
  90. private int node_enum(EditLine *, key_node_t *, int);
  91. private int key__decode_char(char *, int, int);
  92. #define KEY_BUFSIZ EL_BUFSIZ
  93. /* key_init():
  94. * Initialize the key maps
  95. */
  96. protected int
  97. key_init(EditLine *el)
  98. {
  99. el->el_key.buf = (char *) el_malloc(KEY_BUFSIZ);
  100. if (el->el_key.buf == NULL)
  101. return (-1);
  102. el->el_key.map = NULL;
  103. key_reset(el);
  104. return (0);
  105. }
  106. /* key_end():
  107. * Free the key maps
  108. */
  109. protected void
  110. key_end(EditLine *el)
  111. {
  112. el_free((ptr_t) el->el_key.buf);
  113. el->el_key.buf = NULL;
  114. node__put(el, el->el_key.map);
  115. el->el_key.map = NULL;
  116. }
  117. /* key_map_cmd():
  118. * Associate cmd with a key value
  119. */
  120. protected key_value_t *
  121. key_map_cmd(EditLine *el, int cmd)
  122. {
  123. el->el_key.val.cmd = (el_action_t) cmd;
  124. return (&el->el_key.val);
  125. }
  126. /* key_map_str():
  127. * Associate str with a key value
  128. */
  129. protected key_value_t *
  130. key_map_str(EditLine *el, char *str)
  131. {
  132. el->el_key.val.str = str;
  133. return (&el->el_key.val);
  134. }
  135. /* key_reset():
  136. * Takes all nodes on el->el_key.map and puts them on free list. Then
  137. * initializes el->el_key.map with arrow keys
  138. * [Always bind the ansi arrow keys?]
  139. */
  140. protected void
  141. key_reset(EditLine *el)
  142. {
  143. node__put(el, el->el_key.map);
  144. el->el_key.map = NULL;
  145. return;
  146. }
  147. /* key_get():
  148. * Calls the recursive function with entry point el->el_key.map
  149. * Looks up *ch in map and then reads characters until a
  150. * complete match is found or a mismatch occurs. Returns the
  151. * type of the match found (XK_STR, XK_CMD, or XK_EXE).
  152. * Returns NULL in val.str and XK_STR for no match.
  153. * The last character read is returned in *ch.
  154. */
  155. protected int
  156. key_get(EditLine *el, char *ch, key_value_t *val)
  157. {
  158. return (node_trav(el, el->el_key.map, ch, val));
  159. }
  160. /* key_add():
  161. * Adds key to the el->el_key.map and associates the value in val with it.
  162. * If key is already is in el->el_key.map, the new code is applied to the
  163. * existing key. Ntype specifies if code is a command, an
  164. * out str or a unix command.
  165. */
  166. protected void
  167. key_add(EditLine *el, const char *key, key_value_t *val, int ntype)
  168. {
  169. if (key[0] == '\0') {
  170. (void) fprintf(el->el_errfile,
  171. "key_add: Null extended-key not allowed.\n");
  172. return;
  173. }
  174. if (ntype == XK_CMD && val->cmd == ED_SEQUENCE_LEAD_IN) {
  175. (void) fprintf(el->el_errfile,
  176. "key_add: sequence-lead-in command not allowed\n");
  177. return;
  178. }
  179. if (el->el_key.map == NULL)
  180. /* tree is initially empty. Set up new node to match key[0] */
  181. el->el_key.map = node__get(key[0]);
  182. /* it is properly initialized */
  183. /* Now recurse through el->el_key.map */
  184. (void) node__try(el, el->el_key.map, key, val, ntype);
  185. return;
  186. }
  187. /* key_clear():
  188. *
  189. */
  190. protected void
  191. key_clear(EditLine *el, el_action_t *map, const char *in)
  192. {
  193. if ((map[(unsigned char)*in] == ED_SEQUENCE_LEAD_IN) &&
  194. ((map == el->el_map.key &&
  195. el->el_map.alt[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN) ||
  196. (map == el->el_map.alt &&
  197. el->el_map.key[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN)))
  198. (void) key_delete(el, in);
  199. }
  200. /* key_delete():
  201. * Delete the key and all longer keys staring with key, if
  202. * they exists.
  203. */
  204. protected int
  205. key_delete(EditLine *el, const char *key)
  206. {
  207. if (key[0] == '\0') {
  208. (void) fprintf(el->el_errfile,
  209. "key_delete: Null extended-key not allowed.\n");
  210. return (-1);
  211. }
  212. if (el->el_key.map == NULL)
  213. return (0);
  214. (void) node__delete(el, &el->el_key.map, key);
  215. return (0);
  216. }
  217. /* key_print():
  218. * Print the binding associated with key key.
  219. * Print entire el->el_key.map if null
  220. */
  221. protected void
  222. key_print(EditLine *el, const char *key)
  223. {
  224. /* do nothing if el->el_key.map is empty and null key specified */
  225. if (el->el_key.map == NULL && *key == 0)
  226. return;
  227. el->el_key.buf[0] = '"';
  228. if (node_lookup(el, key, el->el_key.map, 1) <= -1)
  229. /* key is not bound */
  230. (void) fprintf(el->el_errfile, "Unbound extended key \"%s\"\n",
  231. key);
  232. return;
  233. }
  234. /* node_trav():
  235. * recursively traverses node in tree until match or mismatch is
  236. * found. May read in more characters.
  237. */
  238. private int
  239. node_trav(EditLine *el, key_node_t *ptr, char *ch, key_value_t *val)
  240. {
  241. if (ptr->ch == *ch) {
  242. /* match found */
  243. if (ptr->next) {
  244. /* key not complete so get next char */
  245. if (el_getc(el, ch) != 1) { /* if EOF or error */
  246. val->cmd = ED_END_OF_FILE;
  247. return (XK_CMD);
  248. /* PWP: Pretend we just read an end-of-file */
  249. }
  250. return (node_trav(el, ptr->next, ch, val));
  251. } else {
  252. *val = ptr->val;
  253. if (ptr->type != XK_CMD)
  254. *ch = '\0';
  255. return (ptr->type);
  256. }
  257. } else {
  258. /* no match found here */
  259. if (ptr->sibling) {
  260. /* try next sibling */
  261. return (node_trav(el, ptr->sibling, ch, val));
  262. } else {
  263. /* no next sibling -- mismatch */
  264. val->str = NULL;
  265. return (XK_STR);
  266. }
  267. }
  268. }
  269. /* node__try():
  270. * Find a node that matches *str or allocate a new one
  271. */
  272. private int
  273. node__try(EditLine *el, key_node_t *ptr, const char *str, key_value_t *val, int ntype)
  274. {
  275. if (ptr->ch != *str) {
  276. key_node_t *xm;
  277. for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
  278. if (xm->sibling->ch == *str)
  279. break;
  280. if (xm->sibling == NULL)
  281. xm->sibling = node__get(*str); /* setup new node */
  282. ptr = xm->sibling;
  283. }
  284. if (*++str == '\0') {
  285. /* we're there */
  286. if (ptr->next != NULL) {
  287. node__put(el, ptr->next);
  288. /* lose longer keys with this prefix */
  289. ptr->next = NULL;
  290. }
  291. switch (ptr->type) {
  292. case XK_CMD:
  293. case XK_NOD:
  294. break;
  295. case XK_STR:
  296. case XK_EXE:
  297. if (ptr->val.str)
  298. el_free((ptr_t) ptr->val.str);
  299. break;
  300. default:
  301. EL_ABORT((el->el_errfile, "Bad XK_ type %d\n",
  302. ptr->type));
  303. break;
  304. }
  305. switch (ptr->type = ntype) {
  306. case XK_CMD:
  307. ptr->val = *val;
  308. break;
  309. case XK_STR:
  310. case XK_EXE:
  311. ptr->val.str = strdup(val->str);
  312. break;
  313. default:
  314. EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype));
  315. break;
  316. }
  317. } else {
  318. /* still more chars to go */
  319. if (ptr->next == NULL)
  320. ptr->next = node__get(*str); /* setup new node */
  321. (void) node__try(el, ptr->next, str, val, ntype);
  322. }
  323. return (0);
  324. }
  325. /* node__delete():
  326. * Delete node that matches str
  327. */
  328. private int
  329. node__delete(EditLine *el, key_node_t **inptr, const char *str)
  330. {
  331. key_node_t *ptr;
  332. key_node_t *prev_ptr = NULL;
  333. ptr = *inptr;
  334. if (ptr->ch != *str) {
  335. key_node_t *xm;
  336. for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
  337. if (xm->sibling->ch == *str)
  338. break;
  339. if (xm->sibling == NULL)
  340. return (0);
  341. prev_ptr = xm;
  342. ptr = xm->sibling;
  343. }
  344. if (*++str == '\0') {
  345. /* we're there */
  346. if (prev_ptr == NULL)
  347. *inptr = ptr->sibling;
  348. else
  349. prev_ptr->sibling = ptr->sibling;
  350. ptr->sibling = NULL;
  351. node__put(el, ptr);
  352. return (1);
  353. } else if (ptr->next != NULL &&
  354. node__delete(el, &ptr->next, str) == 1) {
  355. if (ptr->next != NULL)
  356. return (0);
  357. if (prev_ptr == NULL)
  358. *inptr = ptr->sibling;
  359. else
  360. prev_ptr->sibling = ptr->sibling;
  361. ptr->sibling = NULL;
  362. node__put(el, ptr);
  363. return (1);
  364. } else {
  365. return (0);
  366. }
  367. }
  368. /* node__put():
  369. * Puts a tree of nodes onto free list using free(3).
  370. */
  371. private void
  372. node__put(EditLine *el, key_node_t *ptr)
  373. {
  374. if (ptr == NULL)
  375. return;
  376. if (ptr->next != NULL) {
  377. node__put(el, ptr->next);
  378. ptr->next = NULL;
  379. }
  380. node__put(el, ptr->sibling);
  381. switch (ptr->type) {
  382. case XK_CMD:
  383. case XK_NOD:
  384. break;
  385. case XK_EXE:
  386. case XK_STR:
  387. if (ptr->val.str != NULL)
  388. el_free((ptr_t) ptr->val.str);
  389. break;
  390. default:
  391. EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ptr->type));
  392. break;
  393. }
  394. el_free((ptr_t) ptr);
  395. }
  396. /* node__get():
  397. * Returns pointer to an key_node_t for ch.
  398. */
  399. private key_node_t *
  400. node__get(int ch)
  401. {
  402. key_node_t *ptr;
  403. ptr = (key_node_t *) el_malloc((size_t) sizeof(key_node_t));
  404. if (ptr == NULL)
  405. return NULL;
  406. ptr->ch = ch;
  407. ptr->type = XK_NOD;
  408. ptr->val.str = NULL;
  409. ptr->next = NULL;
  410. ptr->sibling = NULL;
  411. return (ptr);
  412. }
  413. /* node_lookup():
  414. * look for the str starting at node ptr.
  415. * Print if last node
  416. */
  417. private int
  418. node_lookup(EditLine *el, const char *str, key_node_t *ptr, int cnt)
  419. {
  420. int ncnt;
  421. if (ptr == NULL)
  422. return (-1); /* cannot have null ptr */
  423. if (*str == 0) {
  424. /* no more chars in str. node_enum from here. */
  425. (void) node_enum(el, ptr, cnt);
  426. return (0);
  427. } else {
  428. /* If match put this char into el->el_key.buf. Recurse */
  429. if (ptr->ch == *str) {
  430. /* match found */
  431. ncnt = key__decode_char(el->el_key.buf, cnt,
  432. (unsigned char) ptr->ch);
  433. if (ptr->next != NULL)
  434. /* not yet at leaf */
  435. return (node_lookup(el, str + 1, ptr->next,
  436. ncnt + 1));
  437. else {
  438. /* next node is null so key should be complete */
  439. if (str[1] == 0) {
  440. el->el_key.buf[ncnt + 1] = '"';
  441. el->el_key.buf[ncnt + 2] = '\0';
  442. key_kprint(el, el->el_key.buf,
  443. &ptr->val, ptr->type);
  444. return (0);
  445. } else
  446. return (-1);
  447. /* mismatch -- str still has chars */
  448. }
  449. } else {
  450. /* no match found try sibling */
  451. if (ptr->sibling)
  452. return (node_lookup(el, str, ptr->sibling,
  453. cnt));
  454. else
  455. return (-1);
  456. }
  457. }
  458. }
  459. /* node_enum():
  460. * Traverse the node printing the characters it is bound in buffer
  461. */
  462. private int
  463. node_enum(EditLine *el, key_node_t *ptr, int cnt)
  464. {
  465. int ncnt;
  466. if (cnt >= KEY_BUFSIZ - 5) { /* buffer too small */
  467. el->el_key.buf[++cnt] = '"';
  468. el->el_key.buf[++cnt] = '\0';
  469. (void) fprintf(el->el_errfile,
  470. "Some extended keys too long for internal print buffer");
  471. (void) fprintf(el->el_errfile, " \"%s...\"\n", el->el_key.buf);
  472. return (0);
  473. }
  474. if (ptr == NULL) {
  475. #ifdef DEBUG_EDIT
  476. (void) fprintf(el->el_errfile,
  477. "node_enum: BUG!! Null ptr passed\n!");
  478. #endif
  479. return (-1);
  480. }
  481. /* put this char at end of str */
  482. ncnt = key__decode_char(el->el_key.buf, cnt, (unsigned char) ptr->ch);
  483. if (ptr->next == NULL) {
  484. /* print this key and function */
  485. el->el_key.buf[ncnt + 1] = '"';
  486. el->el_key.buf[ncnt + 2] = '\0';
  487. key_kprint(el, el->el_key.buf, &ptr->val, ptr->type);
  488. } else
  489. (void) node_enum(el, ptr->next, ncnt + 1);
  490. /* go to sibling if there is one */
  491. if (ptr->sibling)
  492. (void) node_enum(el, ptr->sibling, cnt);
  493. return (0);
  494. }
  495. /* key_kprint():
  496. * Print the specified key and its associated
  497. * function specified by val
  498. */
  499. protected void
  500. key_kprint(EditLine *el, const char *key, key_value_t *val, int ntype)
  501. {
  502. el_bindings_t *fp;
  503. char unparsbuf[EL_BUFSIZ];
  504. static const char fmt[] = "%-15s-> %s\n";
  505. if (val != NULL)
  506. switch (ntype) {
  507. case XK_STR:
  508. case XK_EXE:
  509. (void) fprintf(el->el_outfile, fmt, key,
  510. key__decode_str(val->str, unparsbuf,
  511. ntype == XK_STR ? "\"\"" : "[]"));
  512. break;
  513. case XK_CMD:
  514. for (fp = el->el_map.help; fp->name; fp++)
  515. if (val->cmd == fp->func) {
  516. (void) fprintf(el->el_outfile, fmt,
  517. key, fp->name);
  518. break;
  519. }
  520. #ifdef DEBUG_KEY
  521. if (fp->name == NULL)
  522. (void) fprintf(el->el_outfile,
  523. "BUG! Command not found.\n");
  524. #endif
  525. break;
  526. default:
  527. EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype));
  528. break;
  529. }
  530. else
  531. (void) fprintf(el->el_outfile, fmt, key, "no input");
  532. }
  533. /* key__decode_char():
  534. * Put a printable form of char in buf.
  535. */
  536. private int
  537. key__decode_char(char *buf, int cnt, int ch)
  538. {
  539. if (ch == 0) {
  540. buf[cnt++] = '^';
  541. buf[cnt] = '@';
  542. return (cnt);
  543. }
  544. if (iscntrl(ch)) {
  545. buf[cnt++] = '^';
  546. if (ch == '\177')
  547. buf[cnt] = '?';
  548. else
  549. buf[cnt] = ch | 0100;
  550. } else if (ch == '^') {
  551. buf[cnt++] = '\\';
  552. buf[cnt] = '^';
  553. } else if (ch == '\\') {
  554. buf[cnt++] = '\\';
  555. buf[cnt] = '\\';
  556. } else if (ch == ' ' || (isprint(ch) && !isspace(ch))) {
  557. buf[cnt] = ch;
  558. } else {
  559. buf[cnt++] = '\\';
  560. buf[cnt++] = (((unsigned int) ch >> 6) & 7) + '0';
  561. buf[cnt++] = (((unsigned int) ch >> 3) & 7) + '0';
  562. buf[cnt] = (ch & 7) + '0';
  563. }
  564. return (cnt);
  565. }
  566. /* key__decode_str():
  567. * Make a printable version of the ey
  568. */
  569. protected char *
  570. key__decode_str(const char *str, char *buf, const char *sep)
  571. {
  572. char *b;
  573. const char *p;
  574. b = buf;
  575. if (sep[0] != '\0')
  576. *b++ = sep[0];
  577. if (*str == 0) {
  578. *b++ = '^';
  579. *b++ = '@';
  580. if (sep[0] != '\0' && sep[1] != '\0')
  581. *b++ = sep[1];
  582. *b++ = 0;
  583. return (buf);
  584. }
  585. for (p = str; *p != 0; p++) {
  586. if (iscntrl((unsigned char) *p)) {
  587. *b++ = '^';
  588. if (*p == '\177')
  589. *b++ = '?';
  590. else
  591. *b++ = *p | 0100;
  592. } else if (*p == '^' || *p == '\\') {
  593. *b++ = '\\';
  594. *b++ = *p;
  595. } else if (*p == ' ' || (isprint((unsigned char) *p) &&
  596. !isspace((unsigned char) *p))) {
  597. *b++ = *p;
  598. } else {
  599. *b++ = '\\';
  600. *b++ = (((unsigned int) *p >> 6) & 7) + '0';
  601. *b++ = (((unsigned int) *p >> 3) & 7) + '0';
  602. *b++ = (*p & 7) + '0';
  603. }
  604. }
  605. if (sep[0] != '\0' && sep[1] != '\0')
  606. *b++ = sep[1];
  607. *b++ = 0;
  608. return (buf); /* should check for overflow */
  609. }