Annotation of src/usr.bin/mg/kbd.c, Revision 1.27
1.27 ! bcallah 1: /* $OpenBSD: kbd.c,v 1.26 2013/05/31 18:03:44 lum Exp $ */
1.17 kjell 2:
3: /* This file is in the public domain. */
1.4 niklas 4:
1.1 deraadt 5: /*
1.3 millert 6: * Terminal independent keyboard handling.
1.1 deraadt 7: */
1.27 ! bcallah 8:
! 9: #include <sys/queue.h>
! 10: #include <signal.h>
! 11: #include <stdio.h>
1.1 deraadt 12:
1.3 millert 13: #include "def.h"
14: #include "kbd.h"
15: #include "key.h"
1.1 deraadt 16: #include "macro.h"
17:
18: #ifndef METABIT
19: #define METABIT 0x80
1.3 millert 20: #endif /* !METABIT */
21:
22: #ifndef NO_DPROMPT
23: #define PROMPTL 80
1.9 mickey 24: char prompt[PROMPTL] = "", *promptp = prompt;
1.3 millert 25: #endif /* !NO_DPROMPT */
1.1 deraadt 26:
1.24 kjell 27: static int mgwrap(PF, int, int);
28:
1.3 millert 29: static int use_metakey = TRUE;
30: static int pushed = FALSE;
31: static int pushedc;
32:
1.18 deraadt 33: struct map_element *ele;
1.15 vincent 34:
35: struct key key;
1.1 deraadt 36:
37: /*
38: * Toggle the value of use_metakey
39: */
1.2 millert 40: int
1.14 vincent 41: do_meta(int f, int n)
1.1 deraadt 42: {
1.2 millert 43: if (f & FFARG)
44: use_metakey = n > 0;
45: else
46: use_metakey = !use_metakey;
1.1 deraadt 47: ewprintf("Meta keys %sabled", use_metakey ? "en" : "dis");
1.16 db 48: return (TRUE);
1.1 deraadt 49: }
50:
1.23 kjell 51: static int bs_map = 0;
52:
1.1 deraadt 53: /*
54: * Toggle backspace mapping
55: */
1.2 millert 56: int
1.14 vincent 57: bsmap(int f, int n)
1.1 deraadt 58: {
1.2 millert 59: if (f & FFARG)
60: bs_map = n > 0;
61: else
62: bs_map = !bs_map;
1.1 deraadt 63: ewprintf("Backspace mapping %sabled", bs_map ? "en" : "dis");
1.16 db 64: return (TRUE);
1.1 deraadt 65: }
66:
1.8 art 67: void
1.14 vincent 68: ungetkey(int c)
1.1 deraadt 69: {
1.2 millert 70: if (use_metakey && pushed && c == CCHR('['))
71: pushedc |= METABIT;
1.1 deraadt 72: else
73: pushedc = c;
74: pushed = TRUE;
75: }
76:
1.2 millert 77: int
1.14 vincent 78: getkey(int flag)
1.1 deraadt 79: {
1.3 millert 80: int c;
1.1 deraadt 81:
82: #ifndef NO_DPROMPT
1.2 millert 83: if (flag && !pushed) {
1.5 art 84: if (prompt[0] != '\0' && ttwait(2000)) {
1.3 millert 85: /* avoid problems with % */
86: ewprintf("%s", prompt);
87: /* put the cursor back */
1.26 lum 88: update(CMODE);
1.22 kjell 89: epresf = KCLEAR;
1.1 deraadt 90: }
1.2 millert 91: if (promptp > prompt)
92: *(promptp - 1) = ' ';
1.1 deraadt 93: }
1.3 millert 94: #endif /* !NO_DPROMPT */
1.2 millert 95: if (pushed) {
1.1 deraadt 96: c = pushedc;
97: pushed = FALSE;
1.2 millert 98: } else
1.12 deraadt 99: c = ttgetc();
1.23 kjell 100:
101: if (bs_map) {
1.2 millert 102: if (c == CCHR('H'))
103: c = CCHR('?');
104: else if (c == CCHR('?'))
105: c = CCHR('H');
1.23 kjell 106: }
1.2 millert 107: if (use_metakey && (c & METABIT)) {
1.1 deraadt 108: pushedc = c & ~METABIT;
109: pushed = TRUE;
110: c = CCHR('[');
111: }
112: #ifndef NO_DPROMPT
1.2 millert 113: if (flag && promptp < &prompt[PROMPTL - 5]) {
1.20 kjell 114: promptp = getkeyname(promptp,
1.9 mickey 115: sizeof(prompt) - (promptp - prompt) - 1, c);
1.2 millert 116: *promptp++ = '-';
117: *promptp = '\0';
1.1 deraadt 118: }
1.3 millert 119: #endif /* !NO_DPROMPT */
1.16 db 120: return (c);
1.1 deraadt 121: }
122:
123: /*
124: * doscan scans a keymap for a keyboard character and returns a pointer
125: * to the function associated with that character. Sets ele to the
126: * keymap element the keyboard was found in as a side effect.
127: */
1.2 millert 128: PF
1.14 vincent 129: doscan(KEYMAP *map, int c, KEYMAP **newmap)
1.2 millert 130: {
1.18 deraadt 131: struct map_element *elec = &map->map_element[0];
132: struct map_element *last = &map->map_element[map->map_num];
1.16 db 133: PF ret;
1.1 deraadt 134:
1.2 millert 135: while (elec < last && c > elec->k_num)
136: elec++;
1.3 millert 137:
138: /* used by prefix and binding code */
139: ele = elec;
1.2 millert 140: if (elec >= last || c < elec->k_base)
1.7 art 141: ret = map->map_default;
142: else
143: ret = elec->k_funcp[c - elec->k_base];
144: if (ret == NULL && newmap != NULL)
145: *newmap = elec->k_prefmap;
146:
1.16 db 147: return (ret);
1.1 deraadt 148: }
149:
1.2 millert 150: int
1.14 vincent 151: doin(void)
1.1 deraadt 152: {
1.3 millert 153: KEYMAP *curmap;
154: PF funct;
1.1 deraadt 155:
156: #ifndef NO_DPROMPT
1.2 millert 157: *(promptp = prompt) = '\0';
1.3 millert 158: #endif /* !NO_DPROMPT */
1.2 millert 159: curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
160: key.k_count = 0;
161: while ((funct = doscan(curmap, (key.k_chars[key.k_count++] =
1.7 art 162: getkey(TRUE)), &curmap)) == NULL)
1.16 db 163: /* nothing */;
1.25 lum 164:
1.2 millert 165: if (macrodef && macrocount < MAXMACRO)
166: macro[macrocount++].m_funct = funct;
1.25 lum 167:
1.24 kjell 168: return (mgwrap(funct, 0, 1));
1.1 deraadt 169: }
170:
1.2 millert 171: int
1.14 vincent 172: rescan(int f, int n)
1.1 deraadt 173: {
1.3 millert 174: int c;
175: KEYMAP *curmap;
176: int i;
177: PF fp = NULL;
1.21 kjell 178: int md = curbp->b_nmodes;
1.2 millert 179:
180: for (;;) {
181: if (ISUPPER(key.k_chars[key.k_count - 1])) {
182: c = TOLOWER(key.k_chars[key.k_count - 1]);
1.21 kjell 183: curmap = curbp->b_modes[md]->p_map;
1.2 millert 184: for (i = 0; i < key.k_count - 1; i++) {
1.24 kjell 185: if ((fp = doscan(curmap, (key.k_chars[i]),
186: &curmap)) != NULL)
1.2 millert 187: break;
188: }
1.6 art 189: if (fp == NULL) {
1.7 art 190: if ((fp = doscan(curmap, c, NULL)) == NULL)
1.2 millert 191: while ((fp = doscan(curmap,
192: key.k_chars[key.k_count++] =
1.7 art 193: getkey(TRUE), &curmap)) == NULL)
1.16 db 194: /* nothing */;
1.2 millert 195: if (fp != rescan) {
196: if (macrodef && macrocount <= MAXMACRO)
1.10 mickey 197: macro[macrocount - 1].m_funct
1.3 millert 198: = fp;
1.24 kjell 199: return (mgwrap(fp, f, n));
1.2 millert 200: }
201: }
202: }
203: /* try previous mode */
1.21 kjell 204: if (--md < 0)
1.16 db 205: return (ABORT);
1.21 kjell 206: curmap = curbp->b_modes[md]->p_map;
1.2 millert 207: for (i = 0; i < key.k_count; i++) {
1.7 art 208: if ((fp = doscan(curmap, (key.k_chars[i]), &curmap)) != NULL)
1.2 millert 209: break;
210: }
1.6 art 211: if (fp == NULL) {
1.10 mickey 212: while ((fp = doscan(curmap, key.k_chars[i++] =
1.7 art 213: getkey(TRUE), &curmap)) == NULL)
1.16 db 214: /* nothing */;
1.2 millert 215: key.k_count = i;
216: }
217: if (fp != rescan && i >= key.k_count - 1) {
218: if (macrodef && macrocount <= MAXMACRO)
219: macro[macrocount - 1].m_funct = fp;
1.24 kjell 220: return (mgwrap(fp, f, n));
1.1 deraadt 221: }
222: }
1.2 millert 223: }
224:
225: int
1.14 vincent 226: universal_argument(int f, int n)
1.2 millert 227: {
1.3 millert 228: KEYMAP *curmap;
229: PF funct;
1.16 db 230: int c, nn = 4;
1.2 millert 231:
232: if (f & FFUNIV)
233: nn *= n;
234: for (;;) {
235: key.k_chars[0] = c = getkey(TRUE);
236: key.k_count = 1;
237: if (c == '-')
1.16 db 238: return (negative_argument(f, nn));
1.2 millert 239: if (c >= '0' && c <= '9')
1.16 db 240: return (digit_argument(f, nn));
1.2 millert 241: curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
1.7 art 242: while ((funct = doscan(curmap, c, &curmap)) == NULL) {
1.2 millert 243: key.k_chars[key.k_count++] = c = getkey(TRUE);
244: }
245: if (funct != universal_argument) {
246: if (macrodef && macrocount < MAXMACRO - 1) {
247: if (f & FFARG)
248: macrocount--;
249: macro[macrocount++].m_count = nn;
250: macro[macrocount++].m_funct = funct;
251: }
1.24 kjell 252: return (mgwrap(funct, FFUNIV, nn));
1.2 millert 253: }
254: nn <<= 2;
1.1 deraadt 255: }
256: }
257:
1.2 millert 258: /* ARGSUSED */
259: int
1.14 vincent 260: digit_argument(int f, int n)
1.1 deraadt 261: {
1.3 millert 262: KEYMAP *curmap;
263: PF funct;
264: int nn, c;
1.2 millert 265:
266: nn = key.k_chars[key.k_count - 1] - '0';
267: for (;;) {
268: c = getkey(TRUE);
269: if (c < '0' || c > '9')
270: break;
271: nn *= 10;
272: nn += c - '0';
273: }
274: key.k_chars[0] = c;
1.1 deraadt 275: key.k_count = 1;
276: curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
1.7 art 277: while ((funct = doscan(curmap, c, &curmap)) == NULL) {
1.2 millert 278: key.k_chars[key.k_count++] = c = getkey(TRUE);
1.1 deraadt 279: }
1.2 millert 280: if (macrodef && macrocount < MAXMACRO - 1) {
281: if (f & FFARG)
282: macrocount--;
283: else
284: macro[macrocount - 1].m_funct = universal_argument;
1.1 deraadt 285: macro[macrocount++].m_count = nn;
286: macro[macrocount++].m_funct = funct;
287: }
1.24 kjell 288: return (mgwrap(funct, FFOTHARG, nn));
1.1 deraadt 289: }
290:
1.2 millert 291: int
1.14 vincent 292: negative_argument(int f, int n)
1.1 deraadt 293: {
1.3 millert 294: KEYMAP *curmap;
295: PF funct;
296: int c;
297: int nn = 0;
1.2 millert 298:
299: for (;;) {
300: c = getkey(TRUE);
301: if (c < '0' || c > '9')
302: break;
303: nn *= 10;
304: nn += c - '0';
305: }
306: if (nn)
307: nn = -nn;
308: else
309: nn = -n;
310: key.k_chars[0] = c;
311: key.k_count = 1;
312: curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
1.7 art 313: while ((funct = doscan(curmap, c, &curmap)) == NULL) {
1.2 millert 314: key.k_chars[key.k_count++] = c = getkey(TRUE);
315: }
316: if (macrodef && macrocount < MAXMACRO - 1) {
317: if (f & FFARG)
318: macrocount--;
319: else
320: macro[macrocount - 1].m_funct = universal_argument;
321: macro[macrocount++].m_count = nn;
322: macro[macrocount++].m_funct = funct;
323: }
1.24 kjell 324: return (mgwrap(funct, FFNEGARG, nn));
1.1 deraadt 325: }
326:
327: /*
328: * Insert a character. While defining a macro, create a "LINE" containing
329: * all inserted characters.
330: */
1.2 millert 331: int
1.14 vincent 332: selfinsert(int f, int n)
1.1 deraadt 333: {
1.18 deraadt 334: struct line *lp;
1.3 millert 335: int c;
336: int count;
1.1 deraadt 337:
1.2 millert 338: if (n < 0)
1.16 db 339: return (FALSE);
1.2 millert 340: if (n == 0)
1.16 db 341: return (TRUE);
1.2 millert 342: c = key.k_chars[key.k_count - 1];
1.25 lum 343:
1.2 millert 344: if (macrodef && macrocount < MAXMACRO) {
345: if (f & FFARG)
346: macrocount -= 2;
1.3 millert 347:
348: /* last command was insert -- tack on the end */
349: if (lastflag & CFINS) {
1.2 millert 350: macrocount--;
1.11 vincent 351: /* Ensure the line can handle the new characters */
1.2 millert 352: if (maclcur->l_size < maclcur->l_used + n) {
1.11 vincent 353: if (lrealloc(maclcur, maclcur->l_used + n) ==
354: FALSE)
1.16 db 355: return (FALSE);
1.2 millert 356: }
1.11 vincent 357: maclcur->l_used += n;
358: /* Copy in the new data */
359: for (count = maclcur->l_used - n;
1.13 deraadt 360: count < maclcur->l_used; count++)
1.11 vincent 361: maclcur->l_text[count] = c;
1.2 millert 362: } else {
363: macro[macrocount - 1].m_funct = insert;
1.11 vincent 364: if ((lp = lalloc(n)) == NULL)
1.16 db 365: return (FALSE);
1.2 millert 366: lp->l_bp = maclcur;
367: lp->l_fp = maclcur->l_fp;
368: maclcur->l_fp = lp;
369: maclcur = lp;
370: for (count = 0; count < n; count++)
371: lp->l_text[count] = c;
372: }
373: thisflag |= CFINS;
374: }
375: if (c == '\n') {
376: do {
377: count = lnewline();
378: } while (--n && count == TRUE);
1.16 db 379: return (count);
1.2 millert 380: }
1.3 millert 381:
382: /* overwrite mode */
383: if (curbp->b_flag & BFOVERWRITE) {
1.2 millert 384: lchange(WFEDIT);
385: while (curwp->w_doto < llength(curwp->w_dotp) && n--)
386: lputc(curwp->w_dotp, curwp->w_doto++, c);
387: if (n <= 0)
1.16 db 388: return (TRUE);
1.2 millert 389: }
1.16 db 390: return (linsert(n, c));
1.1 deraadt 391: }
392:
393: /*
1.16 db 394: * This could be implemented as a keymap with everything defined as self-insert.
1.1 deraadt 395: */
1.2 millert 396: int
1.14 vincent 397: quote(int f, int n)
1.1 deraadt 398: {
1.3 millert 399: int c;
1.1 deraadt 400:
1.2 millert 401: key.k_count = 1;
402: if ((key.k_chars[0] = getkey(TRUE)) >= '0' && key.k_chars[0] <= '7') {
403: key.k_chars[0] -= '0';
404: if ((c = getkey(TRUE)) >= '0' && c <= '7') {
405: key.k_chars[0] <<= 3;
406: key.k_chars[0] += c - '0';
407: if ((c = getkey(TRUE)) >= '0' && c <= '7') {
408: key.k_chars[0] <<= 3;
409: key.k_chars[0] += c - '0';
410: } else
411: ungetkey(c);
412: } else
413: ungetkey(c);
414: }
1.16 db 415: return (selfinsert(f, n));
1.24 kjell 416: }
417:
418: /*
419: * Wraper function to count invocation repeats.
420: * We ignore any function whose sole purpose is to get us
421: * to the intended function.
422: */
423: static int
424: mgwrap(PF funct, int f, int n)
425: {
426: static PF ofp;
427:
428: if (funct != rescan &&
429: funct != negative_argument &&
430: funct != digit_argument &&
431: funct != universal_argument) {
432: if (funct == ofp)
433: rptcount++;
434: else
435: rptcount = 0;
436: ofp = funct;
437: }
438:
439: return ((*funct)(f, n));
1.1 deraadt 440: }