Annotation of src/usr.bin/mg/kbd.c, Revision 1.37
1.37 ! guenther 1: /* $OpenBSD: kbd.c,v 1.36 2022/12/26 19:16:02 jmc 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:
1.31 lum 18: #ifdef MGLOG
19: #include "log.h"
20: #endif
21:
1.1 deraadt 22: #define METABIT 0x80
1.3 millert 23:
24: #define PROMPTL 80
1.9 mickey 25: char prompt[PROMPTL] = "", *promptp = prompt;
1.1 deraadt 26:
1.24 kjell 27: static int mgwrap(PF, int, int);
28:
1.34 florian 29: static int use_metakey = TRUE;
30: static int pushed = FALSE;
31: static int pushedc;
1.3 millert 32:
1.18 deraadt 33: struct map_element *ele;
1.34 florian 34: struct key key;
35: int rptcount;
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:
1.2 millert 82: if (flag && !pushed) {
1.5 art 83: if (prompt[0] != '\0' && ttwait(2000)) {
1.3 millert 84: /* avoid problems with % */
85: ewprintf("%s", prompt);
86: /* put the cursor back */
1.26 lum 87: update(CMODE);
1.22 kjell 88: epresf = KCLEAR;
1.1 deraadt 89: }
1.2 millert 90: if (promptp > prompt)
91: *(promptp - 1) = ' ';
1.1 deraadt 92: }
1.2 millert 93: if (pushed) {
1.1 deraadt 94: c = pushedc;
95: pushed = FALSE;
1.2 millert 96: } else
1.12 deraadt 97: c = ttgetc();
1.23 kjell 98:
99: if (bs_map) {
1.2 millert 100: if (c == CCHR('H'))
101: c = CCHR('?');
102: else if (c == CCHR('?'))
103: c = CCHR('H');
1.23 kjell 104: }
1.2 millert 105: if (use_metakey && (c & METABIT)) {
1.1 deraadt 106: pushedc = c & ~METABIT;
107: pushed = TRUE;
108: c = CCHR('[');
109: }
1.2 millert 110: if (flag && promptp < &prompt[PROMPTL - 5]) {
1.20 kjell 111: promptp = getkeyname(promptp,
1.9 mickey 112: sizeof(prompt) - (promptp - prompt) - 1, c);
1.2 millert 113: *promptp++ = '-';
114: *promptp = '\0';
1.1 deraadt 115: }
1.16 db 116: return (c);
1.1 deraadt 117: }
118:
119: /*
120: * doscan scans a keymap for a keyboard character and returns a pointer
121: * to the function associated with that character. Sets ele to the
122: * keymap element the keyboard was found in as a side effect.
123: */
1.2 millert 124: PF
1.14 vincent 125: doscan(KEYMAP *map, int c, KEYMAP **newmap)
1.2 millert 126: {
1.18 deraadt 127: struct map_element *elec = &map->map_element[0];
128: struct map_element *last = &map->map_element[map->map_num];
1.16 db 129: PF ret;
1.1 deraadt 130:
1.2 millert 131: while (elec < last && c > elec->k_num)
132: elec++;
1.3 millert 133:
134: /* used by prefix and binding code */
135: ele = elec;
1.2 millert 136: if (elec >= last || c < elec->k_base)
1.7 art 137: ret = map->map_default;
138: else
139: ret = elec->k_funcp[c - elec->k_base];
140: if (ret == NULL && newmap != NULL)
141: *newmap = elec->k_prefmap;
142:
1.16 db 143: return (ret);
1.1 deraadt 144: }
145:
1.2 millert 146: int
1.14 vincent 147: doin(void)
1.1 deraadt 148: {
1.3 millert 149: KEYMAP *curmap;
150: PF funct;
1.1 deraadt 151:
1.2 millert 152: *(promptp = prompt) = '\0';
153: curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
154: key.k_count = 0;
155: while ((funct = doscan(curmap, (key.k_chars[key.k_count++] =
1.7 art 156: getkey(TRUE)), &curmap)) == NULL)
1.16 db 157: /* nothing */;
1.31 lum 158:
159: #ifdef MGLOG
1.32 lum 160: if (!mglog(funct, curmap))
1.31 lum 161: ewprintf("Problem with logging");
162: #endif
1.25 lum 163:
1.2 millert 164: if (macrodef && macrocount < MAXMACRO)
165: macro[macrocount++].m_funct = funct;
1.25 lum 166:
1.24 kjell 167: return (mgwrap(funct, 0, 1));
1.1 deraadt 168: }
169:
1.2 millert 170: int
1.14 vincent 171: rescan(int f, int n)
1.1 deraadt 172: {
1.3 millert 173: int c;
174: KEYMAP *curmap;
175: int i;
176: PF fp = NULL;
1.21 kjell 177: int md = curbp->b_nmodes;
1.2 millert 178:
179: for (;;) {
180: if (ISUPPER(key.k_chars[key.k_count - 1])) {
181: c = TOLOWER(key.k_chars[key.k_count - 1]);
1.21 kjell 182: curmap = curbp->b_modes[md]->p_map;
1.2 millert 183: for (i = 0; i < key.k_count - 1; i++) {
1.24 kjell 184: if ((fp = doscan(curmap, (key.k_chars[i]),
185: &curmap)) != NULL)
1.2 millert 186: break;
187: }
1.6 art 188: if (fp == NULL) {
1.7 art 189: if ((fp = doscan(curmap, c, NULL)) == NULL)
1.2 millert 190: while ((fp = doscan(curmap,
191: key.k_chars[key.k_count++] =
1.7 art 192: getkey(TRUE), &curmap)) == NULL)
1.16 db 193: /* nothing */;
1.2 millert 194: if (fp != rescan) {
195: if (macrodef && macrocount <= MAXMACRO)
1.10 mickey 196: macro[macrocount - 1].m_funct
1.3 millert 197: = fp;
1.24 kjell 198: return (mgwrap(fp, f, n));
1.2 millert 199: }
200: }
201: }
202: /* try previous mode */
1.21 kjell 203: if (--md < 0)
1.16 db 204: return (ABORT);
1.21 kjell 205: curmap = curbp->b_modes[md]->p_map;
1.2 millert 206: for (i = 0; i < key.k_count; i++) {
1.7 art 207: if ((fp = doscan(curmap, (key.k_chars[i]), &curmap)) != NULL)
1.2 millert 208: break;
209: }
1.6 art 210: if (fp == NULL) {
1.10 mickey 211: while ((fp = doscan(curmap, key.k_chars[i++] =
1.7 art 212: getkey(TRUE), &curmap)) == NULL)
1.16 db 213: /* nothing */;
1.2 millert 214: key.k_count = i;
215: }
216: if (fp != rescan && i >= key.k_count - 1) {
217: if (macrodef && macrocount <= MAXMACRO)
218: macro[macrocount - 1].m_funct = fp;
1.24 kjell 219: return (mgwrap(fp, f, n));
1.1 deraadt 220: }
221: }
1.2 millert 222: }
223:
224: int
1.14 vincent 225: universal_argument(int f, int n)
1.2 millert 226: {
1.3 millert 227: KEYMAP *curmap;
228: PF funct;
1.16 db 229: int c, nn = 4;
1.2 millert 230:
231: if (f & FFUNIV)
232: nn *= n;
233: for (;;) {
234: key.k_chars[0] = c = getkey(TRUE);
235: key.k_count = 1;
236: if (c == '-')
1.16 db 237: return (negative_argument(f, nn));
1.2 millert 238: if (c >= '0' && c <= '9')
1.16 db 239: return (digit_argument(f, nn));
1.2 millert 240: curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
1.7 art 241: while ((funct = doscan(curmap, c, &curmap)) == NULL) {
1.2 millert 242: key.k_chars[key.k_count++] = c = getkey(TRUE);
243: }
244: if (funct != universal_argument) {
245: if (macrodef && macrocount < MAXMACRO - 1) {
246: if (f & FFARG)
247: macrocount--;
248: macro[macrocount++].m_count = nn;
249: macro[macrocount++].m_funct = funct;
250: }
1.24 kjell 251: return (mgwrap(funct, FFUNIV, nn));
1.2 millert 252: }
253: nn <<= 2;
1.1 deraadt 254: }
255: }
256:
1.2 millert 257: int
1.14 vincent 258: digit_argument(int f, int n)
1.1 deraadt 259: {
1.3 millert 260: KEYMAP *curmap;
261: PF funct;
262: int nn, c;
1.2 millert 263:
264: nn = key.k_chars[key.k_count - 1] - '0';
265: for (;;) {
266: c = getkey(TRUE);
267: if (c < '0' || c > '9')
268: break;
269: nn *= 10;
270: nn += c - '0';
271: }
272: key.k_chars[0] = c;
1.1 deraadt 273: key.k_count = 1;
274: curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
1.7 art 275: while ((funct = doscan(curmap, c, &curmap)) == NULL) {
1.2 millert 276: key.k_chars[key.k_count++] = c = getkey(TRUE);
1.1 deraadt 277: }
1.2 millert 278: if (macrodef && macrocount < MAXMACRO - 1) {
279: if (f & FFARG)
280: macrocount--;
281: else
282: macro[macrocount - 1].m_funct = universal_argument;
1.1 deraadt 283: macro[macrocount++].m_count = nn;
284: macro[macrocount++].m_funct = funct;
285: }
1.24 kjell 286: return (mgwrap(funct, FFOTHARG, nn));
1.1 deraadt 287: }
288:
1.2 millert 289: int
1.14 vincent 290: negative_argument(int f, int n)
1.1 deraadt 291: {
1.3 millert 292: KEYMAP *curmap;
293: PF funct;
294: int c;
295: int nn = 0;
1.2 millert 296:
297: for (;;) {
298: c = getkey(TRUE);
299: if (c < '0' || c > '9')
300: break;
301: nn *= 10;
302: nn += c - '0';
303: }
304: if (nn)
305: nn = -nn;
306: else
307: nn = -n;
308: key.k_chars[0] = c;
309: key.k_count = 1;
310: curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
1.7 art 311: while ((funct = doscan(curmap, c, &curmap)) == NULL) {
1.2 millert 312: key.k_chars[key.k_count++] = c = getkey(TRUE);
313: }
314: if (macrodef && macrocount < MAXMACRO - 1) {
315: if (f & FFARG)
316: macrocount--;
317: else
318: macro[macrocount - 1].m_funct = universal_argument;
319: macro[macrocount++].m_count = nn;
320: macro[macrocount++].m_funct = funct;
321: }
1.24 kjell 322: return (mgwrap(funct, FFNEGARG, nn));
1.1 deraadt 323: }
324:
325: /*
326: * Insert a character. While defining a macro, create a "LINE" containing
327: * all inserted characters.
328: */
1.2 millert 329: int
1.14 vincent 330: selfinsert(int f, int n)
1.1 deraadt 331: {
1.18 deraadt 332: struct line *lp;
1.3 millert 333: int c;
334: int count;
1.1 deraadt 335:
1.2 millert 336: if (n < 0)
1.16 db 337: return (FALSE);
1.2 millert 338: if (n == 0)
1.16 db 339: return (TRUE);
1.2 millert 340: c = key.k_chars[key.k_count - 1];
1.25 lum 341:
1.2 millert 342: if (macrodef && macrocount < MAXMACRO) {
343: if (f & FFARG)
344: macrocount -= 2;
1.3 millert 345:
346: /* last command was insert -- tack on the end */
347: if (lastflag & CFINS) {
1.2 millert 348: macrocount--;
1.11 vincent 349: /* Ensure the line can handle the new characters */
1.2 millert 350: if (maclcur->l_size < maclcur->l_used + n) {
1.11 vincent 351: if (lrealloc(maclcur, maclcur->l_used + n) ==
352: FALSE)
1.16 db 353: return (FALSE);
1.2 millert 354: }
1.11 vincent 355: maclcur->l_used += n;
356: /* Copy in the new data */
357: for (count = maclcur->l_used - n;
1.13 deraadt 358: count < maclcur->l_used; count++)
1.11 vincent 359: maclcur->l_text[count] = c;
1.2 millert 360: } else {
361: macro[macrocount - 1].m_funct = insert;
1.11 vincent 362: if ((lp = lalloc(n)) == NULL)
1.16 db 363: return (FALSE);
1.2 millert 364: lp->l_bp = maclcur;
365: lp->l_fp = maclcur->l_fp;
366: maclcur->l_fp = lp;
367: maclcur = lp;
368: for (count = 0; count < n; count++)
369: lp->l_text[count] = c;
370: }
371: thisflag |= CFINS;
372: }
1.35 lum 373: if (c == *curbp->b_nlchr) {
1.2 millert 374: do {
375: count = lnewline();
376: } while (--n && count == TRUE);
1.16 db 377: return (count);
1.2 millert 378: }
1.3 millert 379:
380: /* overwrite mode */
381: if (curbp->b_flag & BFOVERWRITE) {
1.2 millert 382: lchange(WFEDIT);
383: while (curwp->w_doto < llength(curwp->w_dotp) && n--)
384: lputc(curwp->w_dotp, curwp->w_doto++, c);
385: if (n <= 0)
1.16 db 386: return (TRUE);
1.2 millert 387: }
1.16 db 388: return (linsert(n, c));
1.33 lum 389: }
390:
391: /*
392: * selfinsert() can't be called directly from a startup file or by
393: * 'eval-current-buffer' since it is by design, meant to be called interactively
394: * as characters are typed in a buffer. ask_selfinsert() allows selfinsert() to
395: * be used by excline(). Having ask_selfinsert() helps with regression testing.
396: * No manual page entry since use case is a bit obscure. See 'insert' command.
397: */
398: int
399: ask_selfinsert(int f, int n)
400: {
401: char *c, cbuf[2];
402:
403: if ((c = eread("Insert a character: ", cbuf, sizeof(cbuf),
404: EFNEW)) == NULL || (c[0] == '\0'))
405: return (ABORT);
406:
407: key.k_chars[0] = *c;
408: key.k_chars[1] = '\0';
409: key.k_count = 1;
410:
411: return (selfinsert(FFRAND, 1));
1.1 deraadt 412: }
413:
414: /*
1.16 db 415: * This could be implemented as a keymap with everything defined as self-insert.
1.1 deraadt 416: */
1.2 millert 417: int
1.14 vincent 418: quote(int f, int n)
1.1 deraadt 419: {
1.3 millert 420: int c;
1.1 deraadt 421:
1.2 millert 422: key.k_count = 1;
423: if ((key.k_chars[0] = getkey(TRUE)) >= '0' && key.k_chars[0] <= '7') {
424: key.k_chars[0] -= '0';
425: if ((c = getkey(TRUE)) >= '0' && c <= '7') {
426: key.k_chars[0] <<= 3;
427: key.k_chars[0] += c - '0';
428: if ((c = getkey(TRUE)) >= '0' && c <= '7') {
429: key.k_chars[0] <<= 3;
430: key.k_chars[0] += c - '0';
431: } else
432: ungetkey(c);
433: } else
434: ungetkey(c);
435: }
1.16 db 436: return (selfinsert(f, n));
1.24 kjell 437: }
438:
439: /*
1.36 jmc 440: * Wrapper function to count invocation repeats.
1.24 kjell 441: * We ignore any function whose sole purpose is to get us
442: * to the intended function.
443: */
444: static int
445: mgwrap(PF funct, int f, int n)
446: {
447: static PF ofp;
1.30 jasper 448:
1.24 kjell 449: if (funct != rescan &&
450: funct != negative_argument &&
451: funct != digit_argument &&
452: funct != universal_argument) {
453: if (funct == ofp)
454: rptcount++;
455: else
456: rptcount = 0;
457: ofp = funct;
458: }
1.30 jasper 459:
1.24 kjell 460: return ((*funct)(f, n));
1.1 deraadt 461: }