/contrib/tcsh/tc.bind.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 536 lines · 454 code · 49 blank · 33 comment · 95 complexity · f417853c94b2be8d07bc3bea82ba7ff8 MD5 · raw file

  1. /* $Header: /p/tcsh/cvsroot/tcsh/tc.bind.c,v 3.45 2009/06/25 21:15:37 christos Exp $ */
  2. /*
  3. * tc.bind.c: Key binding 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. #include "sh.h"
  34. RCSID("$tcsh: tc.bind.c,v 3.45 2009/06/25 21:15:37 christos Exp $")
  35. #include "ed.h"
  36. #include "ed.defns.h"
  37. static void printkey (const KEYCMD *, CStr *);
  38. static KEYCMD parsecmd (Char *);
  39. static void bad_spec (const Char *);
  40. static CStr *parsestring (const Char *, CStr *);
  41. static CStr *parsebind (const Char *, CStr *);
  42. static void print_all_keys (void);
  43. static void printkeys (KEYCMD *, int, int);
  44. static void bindkey_usage (void);
  45. static void list_functions (void);
  46. extern int MapsAreInited;
  47. /*ARGSUSED*/
  48. void
  49. dobindkey(Char **v, struct command *c)
  50. {
  51. KEYCMD *map;
  52. int ntype, no, removeb, key, bindk;
  53. Char *par;
  54. Char p;
  55. KEYCMD cmd;
  56. CStr in;
  57. CStr out;
  58. uChar ch;
  59. USE(c);
  60. if (!MapsAreInited)
  61. ed_InitMaps();
  62. map = CcKeyMap;
  63. ntype = XK_CMD;
  64. key = removeb = bindk = 0;
  65. for (no = 1, par = v[no];
  66. par != NULL && (*par++ & CHAR) == '-'; no++, par = v[no]) {
  67. if ((p = (*par & CHAR)) == '-') {
  68. no++;
  69. break;
  70. }
  71. else
  72. switch (p) {
  73. case 'b':
  74. bindk = 1;
  75. break;
  76. case 'k':
  77. key = 1;
  78. break;
  79. case 'a':
  80. map = CcAltMap;
  81. break;
  82. case 's':
  83. ntype = XK_STR;
  84. break;
  85. case 'c':
  86. ntype = XK_EXE;
  87. break;
  88. case 'r':
  89. removeb = 1;
  90. break;
  91. case 'v':
  92. ed_InitVIMaps();
  93. return;
  94. case 'e':
  95. ed_InitEmacsMaps();
  96. return;
  97. case 'd':
  98. #ifdef VIDEFAULT
  99. ed_InitVIMaps();
  100. #else /* EMACSDEFAULT */
  101. ed_InitEmacsMaps();
  102. #endif /* VIDEFAULT */
  103. return;
  104. case 'l':
  105. list_functions();
  106. return;
  107. default:
  108. bindkey_usage();
  109. return;
  110. }
  111. }
  112. if (!v[no]) {
  113. print_all_keys();
  114. return;
  115. }
  116. if (key) {
  117. if (!IsArrowKey(v[no]))
  118. xprintf(CGETS(20, 1, "Invalid key name `%S'\n"), v[no]);
  119. in.buf = Strsave(v[no++]);
  120. in.len = Strlen(in.buf);
  121. }
  122. else {
  123. if (bindk) {
  124. if (parsebind(v[no++], &in) == NULL)
  125. return;
  126. }
  127. else {
  128. if (parsestring(v[no++], &in) == NULL)
  129. return;
  130. }
  131. }
  132. cleanup_push(in.buf, xfree);
  133. #ifndef WINNT_NATIVE
  134. if (in.buf[0] > 0xFF) {
  135. bad_spec(in.buf);
  136. cleanup_until(in.buf);
  137. return;
  138. }
  139. #endif
  140. ch = (uChar) in.buf[0];
  141. if (removeb) {
  142. if (key)
  143. (void) ClearArrowKeys(&in);
  144. else if (in.len > 1) {
  145. (void) DeleteXkey(&in);
  146. }
  147. else if (map[ch] == F_XKEY) {
  148. (void) DeleteXkey(&in);
  149. map[ch] = F_UNASSIGNED;
  150. }
  151. else {
  152. map[ch] = F_UNASSIGNED;
  153. }
  154. cleanup_until(in.buf);
  155. return;
  156. }
  157. if (!v[no]) {
  158. if (key)
  159. PrintArrowKeys(&in);
  160. else
  161. printkey(map, &in);
  162. cleanup_until(in.buf);
  163. return;
  164. }
  165. if (v[no + 1]) {
  166. bindkey_usage();
  167. cleanup_until(in.buf);
  168. return;
  169. }
  170. switch (ntype) {
  171. case XK_STR:
  172. case XK_EXE:
  173. if (parsestring(v[no], &out) == NULL) {
  174. cleanup_until(in.buf);
  175. return;
  176. }
  177. cleanup_push(out.buf, xfree);
  178. if (key) {
  179. if (SetArrowKeys(&in, XmapStr(&out), ntype) == -1)
  180. xprintf(CGETS(20, 2, "Bad key name: %S\n"), in.buf);
  181. else
  182. cleanup_ignore(out.buf);
  183. }
  184. else
  185. AddXkey(&in, XmapStr(&out), ntype);
  186. map[ch] = F_XKEY;
  187. break;
  188. case XK_CMD:
  189. if ((cmd = parsecmd(v[no])) == 0) {
  190. cleanup_until(in.buf);
  191. return;
  192. }
  193. if (key)
  194. (void) SetArrowKeys(&in, XmapCmd((int) cmd), ntype);
  195. else {
  196. if (in.len > 1) {
  197. AddXkey(&in, XmapCmd((int) cmd), ntype);
  198. map[ch] = F_XKEY;
  199. }
  200. else {
  201. ClearXkey(map, &in);
  202. map[ch] = cmd;
  203. }
  204. }
  205. break;
  206. default:
  207. abort();
  208. break;
  209. }
  210. cleanup_until(in.buf);
  211. if (key)
  212. BindArrowKeys();
  213. }
  214. static void
  215. printkey(const KEYCMD *map, CStr *in)
  216. {
  217. struct KeyFuncs *fp;
  218. if (in->len < 2) {
  219. unsigned char *unparsed;
  220. unparsed = unparsestring(in, STRQQ);
  221. cleanup_push(unparsed, xfree);
  222. for (fp = FuncNames; fp->name; fp++) {
  223. if (fp->func == map[(uChar) *(in->buf)]) {
  224. xprintf("%s\t->\t%s\n", unparsed, fp->name);
  225. }
  226. }
  227. cleanup_until(unparsed);
  228. }
  229. else
  230. PrintXkey(in);
  231. }
  232. static KEYCMD
  233. parsecmd(Char *str)
  234. {
  235. struct KeyFuncs *fp;
  236. for (fp = FuncNames; fp->name; fp++) {
  237. if (strcmp(short2str(str), fp->name) == 0) {
  238. return (KEYCMD) fp->func;
  239. }
  240. }
  241. xprintf(CGETS(20, 3, "Bad command name: %S\n"), str);
  242. return 0;
  243. }
  244. static void
  245. bad_spec(const Char *str)
  246. {
  247. xprintf(CGETS(20, 4, "Bad key spec %S\n"), str);
  248. }
  249. static CStr *
  250. parsebind(const Char *s, CStr *str)
  251. {
  252. struct Strbuf b = Strbuf_INIT;
  253. cleanup_push(&b, Strbuf_cleanup);
  254. if (Iscntrl(*s)) {
  255. Strbuf_append1(&b, *s);
  256. goto end;
  257. }
  258. switch (*s) {
  259. case '^':
  260. s++;
  261. #ifdef IS_ASCII
  262. Strbuf_append1(&b, (*s == '?') ? '\177' : ((*s & CHAR) & 0237));
  263. #else
  264. Strbuf_append1(&b, (*s == '?') ? CTL_ESC('\177')
  265. : _toebcdic[_toascii[*s & CHAR] & 0237]);
  266. #endif
  267. break;
  268. case 'F':
  269. case 'M':
  270. case 'X':
  271. case 'C':
  272. #ifdef WINNT_NATIVE
  273. case 'N':
  274. #endif /* WINNT_NATIVE */
  275. if (s[1] != '-' || s[2] == '\0')
  276. goto bad_spec;
  277. s += 2;
  278. switch (s[-2]) {
  279. case 'F': case 'f': /* Turn into ^[str */
  280. Strbuf_append1(&b, CTL_ESC('\033'));
  281. Strbuf_append(&b, s);
  282. break;
  283. case 'C': case 'c': /* Turn into ^c */
  284. #ifdef IS_ASCII
  285. Strbuf_append1(&b, (*s == '?') ? '\177' : ((*s & CHAR) & 0237));
  286. #else
  287. Strbuf_append1(&b, (*s == '?') ? CTL_ESC('\177')
  288. : _toebcdic[_toascii[*s & CHAR] & 0237]);
  289. #endif
  290. break;
  291. case 'X' : case 'x': /* Turn into ^Xc */
  292. #ifdef IS_ASCII
  293. Strbuf_append1(&b, 'X' & 0237);
  294. #else
  295. Strbuf_append1(&b, _toebcdic[_toascii['X'] & 0237]);
  296. #endif
  297. Strbuf_append1(&b, *s);
  298. break;
  299. case 'M' : case 'm': /* Turn into 0x80|c */
  300. if (!NoNLSRebind) {
  301. Strbuf_append1(&b, CTL_ESC('\033'));
  302. Strbuf_append1(&b, *s);
  303. } else {
  304. #ifdef IS_ASCII
  305. Strbuf_append1(&b, *s | 0x80);
  306. #else
  307. Strbuf_append1(&b, _toebcdic[_toascii[*s] | 0x80]);
  308. #endif
  309. }
  310. break;
  311. #ifdef WINNT_NATIVE
  312. case 'N' : case 'n': /* NT */
  313. {
  314. Char bnt;
  315. bnt = nt_translate_bindkey(s);
  316. if (bnt != 0)
  317. Strbuf_append1(&b, bnt);
  318. else
  319. bad_spec(s);
  320. }
  321. break;
  322. #endif /* WINNT_NATIVE */
  323. default:
  324. abort();
  325. }
  326. break;
  327. default:
  328. goto bad_spec;
  329. }
  330. end:
  331. cleanup_ignore(&b);
  332. cleanup_until(&b);
  333. Strbuf_terminate(&b);
  334. str->buf = xrealloc(b.s, (b.len + 1) * sizeof (*str->buf));
  335. str->len = b.len;
  336. return str;
  337. bad_spec:
  338. bad_spec(s);
  339. cleanup_until(&b);
  340. return NULL;
  341. }
  342. static CStr *
  343. parsestring(const Char *str, CStr *buf)
  344. {
  345. struct Strbuf b = Strbuf_INIT;
  346. const Char *p;
  347. eChar es;
  348. if (*str == 0) {
  349. xprintf("%s", CGETS(20, 5, "Null string specification\n"));
  350. return NULL;
  351. }
  352. cleanup_push(&b, Strbuf_cleanup);
  353. for (p = str; *p != 0; p++) {
  354. if ((*p & CHAR) == '\\' || (*p & CHAR) == '^') {
  355. if ((es = parseescape(&p)) == CHAR_ERR) {
  356. cleanup_until(&b);
  357. return 0;
  358. } else
  359. Strbuf_append1(&b, es);
  360. }
  361. else
  362. Strbuf_append1(&b, *p & CHAR);
  363. }
  364. cleanup_ignore(&b);
  365. cleanup_until(&b);
  366. Strbuf_terminate(&b);
  367. buf->buf = xrealloc(b.s, (b.len + 1) * sizeof (*buf->buf));
  368. buf->len = b.len;
  369. return buf;
  370. }
  371. static void
  372. print_all_keys(void)
  373. {
  374. int prev, i;
  375. CStr nilstr;
  376. nilstr.buf = NULL;
  377. nilstr.len = 0;
  378. xprintf("%s", CGETS(20, 6, "Standard key bindings\n"));
  379. prev = 0;
  380. for (i = 0; i < 256; i++) {
  381. if (CcKeyMap[prev] == CcKeyMap[i])
  382. continue;
  383. printkeys(CcKeyMap, prev, i - 1);
  384. prev = i;
  385. }
  386. printkeys(CcKeyMap, prev, i - 1);
  387. xprintf("%s", CGETS(20, 7, "Alternative key bindings\n"));
  388. prev = 0;
  389. for (i = 0; i < 256; i++) {
  390. if (CcAltMap[prev] == CcAltMap[i])
  391. continue;
  392. printkeys(CcAltMap, prev, i - 1);
  393. prev = i;
  394. }
  395. printkeys(CcAltMap, prev, i - 1);
  396. xprintf("%s", CGETS(20, 8, "Multi-character bindings\n"));
  397. PrintXkey(NULL); /* print all Xkey bindings */
  398. xprintf("%s", CGETS(20, 9, "Arrow key bindings\n"));
  399. PrintArrowKeys(&nilstr);
  400. }
  401. static void
  402. printkeys(KEYCMD *map, int first, int last)
  403. {
  404. struct KeyFuncs *fp;
  405. Char firstbuf[2], lastbuf[2];
  406. CStr fb, lb;
  407. unsigned char *unparsed;
  408. fb.buf = firstbuf;
  409. lb.buf = lastbuf;
  410. firstbuf[0] = (Char) first;
  411. firstbuf[1] = 0;
  412. lastbuf[0] = (Char) last;
  413. lastbuf[1] = 0;
  414. fb.len = 1;
  415. lb.len = 1;
  416. unparsed = unparsestring(&fb, STRQQ);
  417. cleanup_push(unparsed, xfree);
  418. if (map[first] == F_UNASSIGNED) {
  419. if (first == last)
  420. xprintf(CGETS(20, 10, "%-15s-> is undefined\n"), unparsed);
  421. cleanup_until(unparsed);
  422. return;
  423. }
  424. for (fp = FuncNames; fp->name; fp++) {
  425. if (fp->func == map[first]) {
  426. if (first == last)
  427. xprintf("%-15s-> %s\n", unparsed, fp->name);
  428. else {
  429. unsigned char *p;
  430. p = unparsestring(&lb, STRQQ);
  431. cleanup_push(p, xfree);
  432. xprintf("%-4s to %-7s-> %s\n", unparsed, p, fp->name);
  433. }
  434. cleanup_until(unparsed);
  435. return;
  436. }
  437. }
  438. xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"), unparsed);
  439. if (map == CcKeyMap)
  440. xprintf("CcKeyMap[%d] == %d\n", first, CcKeyMap[first]);
  441. else
  442. xprintf("CcAltMap[%d] == %d\n", first, CcAltMap[first]);
  443. cleanup_until(unparsed);
  444. }
  445. static void
  446. bindkey_usage(void)
  447. {
  448. xprintf("%s", CGETS(20, 12,
  449. "Usage: bindkey [options] [--] [KEY [COMMAND]]\n"));
  450. xprintf("%s", CGETS(20, 13,
  451. " -a list or bind KEY in alternative key map\n"));
  452. xprintf("%s", CGETS(20, 14,
  453. " -b interpret KEY as a C-, M-, F- or X- key name\n"));
  454. xprintf("%s", CGETS(20, 15,
  455. " -s interpret COMMAND as a literal string to be output\n"));
  456. xprintf("%s", CGETS(20, 16,
  457. " -c interpret COMMAND as a builtin or external command\n"));
  458. xprintf("%s", CGETS(20, 17,
  459. " -v bind all keys to vi bindings\n"));
  460. xprintf("%s", CGETS(20, 18,
  461. " -e bind all keys to emacs bindings\n"));
  462. xprintf("%s", CGETS(20, 19,
  463. " -d bind all keys to default editor's bindings\n"));
  464. xprintf("%s", CGETS(20, 20,
  465. " -l list editor commands with descriptions\n"));
  466. xprintf("%s", CGETS(20, 21,
  467. " -r remove KEY's binding\n"));
  468. xprintf("%s", CGETS(20, 22,
  469. " -k interpret KEY as a symbolic arrow-key name\n"));
  470. xprintf("%s", CGETS(20, 23,
  471. " -- force a break from option processing\n"));
  472. xprintf("%s", CGETS(20, 24,
  473. " -u (or any invalid option) this message\n"));
  474. xprintf("\n");
  475. xprintf("%s", CGETS(20, 25,
  476. "Without KEY or COMMAND, prints all bindings\n"));
  477. xprintf("%s", CGETS(20, 26,
  478. "Without COMMAND, prints the binding for KEY.\n"));
  479. }
  480. static void
  481. list_functions(void)
  482. {
  483. struct KeyFuncs *fp;
  484. for (fp = FuncNames; fp->name; fp++) {
  485. xprintf("%s\n %s\n", fp->name, fp->desc);
  486. }
  487. }