File: [local] / src / usr.bin / mg / kbd.c (download)
Revision 1.34, Sun Feb 9 10:13:13 2020 UTC (4 years, 4 months ago) by florian
Branch: MAIN
CVS Tags: OPENBSD_6_8_BASE, OPENBSD_6_8, OPENBSD_6_7_BASE, OPENBSD_6_7 Changes since 1.33: +6 -6 lines
Do not define variables in def.h since this will lead to duplicate definitions
in every source file that includes def.h
Found by gcc10 in portable in gentoo and fedora.
Patch from Ulrich Mueller (ulm AT gentoo.org) via Han Boetes, thanks!
Ok tb
|
/* $OpenBSD: kbd.c,v 1.34 2020/02/09 10:13:13 florian Exp $ */
/* This file is in the public domain. */
/*
* Terminal independent keyboard handling.
*/
#include <sys/queue.h>
#include <signal.h>
#include <stdio.h>
#include "def.h"
#include "kbd.h"
#include "key.h"
#include "macro.h"
#ifdef MGLOG
#include "log.h"
#endif
#define METABIT 0x80
#define PROMPTL 80
char prompt[PROMPTL] = "", *promptp = prompt;
static int mgwrap(PF, int, int);
static int use_metakey = TRUE;
static int pushed = FALSE;
static int pushedc;
struct map_element *ele;
struct key key;
int rptcount;
/*
* Toggle the value of use_metakey
*/
int
do_meta(int f, int n)
{
if (f & FFARG)
use_metakey = n > 0;
else
use_metakey = !use_metakey;
ewprintf("Meta keys %sabled", use_metakey ? "en" : "dis");
return (TRUE);
}
static int bs_map = 0;
/*
* Toggle backspace mapping
*/
int
bsmap(int f, int n)
{
if (f & FFARG)
bs_map = n > 0;
else
bs_map = !bs_map;
ewprintf("Backspace mapping %sabled", bs_map ? "en" : "dis");
return (TRUE);
}
void
ungetkey(int c)
{
if (use_metakey && pushed && c == CCHR('['))
pushedc |= METABIT;
else
pushedc = c;
pushed = TRUE;
}
int
getkey(int flag)
{
int c;
if (flag && !pushed) {
if (prompt[0] != '\0' && ttwait(2000)) {
/* avoid problems with % */
ewprintf("%s", prompt);
/* put the cursor back */
update(CMODE);
epresf = KCLEAR;
}
if (promptp > prompt)
*(promptp - 1) = ' ';
}
if (pushed) {
c = pushedc;
pushed = FALSE;
} else
c = ttgetc();
if (bs_map) {
if (c == CCHR('H'))
c = CCHR('?');
else if (c == CCHR('?'))
c = CCHR('H');
}
if (use_metakey && (c & METABIT)) {
pushedc = c & ~METABIT;
pushed = TRUE;
c = CCHR('[');
}
if (flag && promptp < &prompt[PROMPTL - 5]) {
promptp = getkeyname(promptp,
sizeof(prompt) - (promptp - prompt) - 1, c);
*promptp++ = '-';
*promptp = '\0';
}
return (c);
}
/*
* doscan scans a keymap for a keyboard character and returns a pointer
* to the function associated with that character. Sets ele to the
* keymap element the keyboard was found in as a side effect.
*/
PF
doscan(KEYMAP *map, int c, KEYMAP **newmap)
{
struct map_element *elec = &map->map_element[0];
struct map_element *last = &map->map_element[map->map_num];
PF ret;
while (elec < last && c > elec->k_num)
elec++;
/* used by prefix and binding code */
ele = elec;
if (elec >= last || c < elec->k_base)
ret = map->map_default;
else
ret = elec->k_funcp[c - elec->k_base];
if (ret == NULL && newmap != NULL)
*newmap = elec->k_prefmap;
return (ret);
}
int
doin(void)
{
KEYMAP *curmap;
PF funct;
*(promptp = prompt) = '\0';
curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
key.k_count = 0;
while ((funct = doscan(curmap, (key.k_chars[key.k_count++] =
getkey(TRUE)), &curmap)) == NULL)
/* nothing */;
#ifdef MGLOG
if (!mglog(funct, curmap))
ewprintf("Problem with logging");
#endif
if (macrodef && macrocount < MAXMACRO)
macro[macrocount++].m_funct = funct;
return (mgwrap(funct, 0, 1));
}
int
rescan(int f, int n)
{
int c;
KEYMAP *curmap;
int i;
PF fp = NULL;
int md = curbp->b_nmodes;
for (;;) {
if (ISUPPER(key.k_chars[key.k_count - 1])) {
c = TOLOWER(key.k_chars[key.k_count - 1]);
curmap = curbp->b_modes[md]->p_map;
for (i = 0; i < key.k_count - 1; i++) {
if ((fp = doscan(curmap, (key.k_chars[i]),
&curmap)) != NULL)
break;
}
if (fp == NULL) {
if ((fp = doscan(curmap, c, NULL)) == NULL)
while ((fp = doscan(curmap,
key.k_chars[key.k_count++] =
getkey(TRUE), &curmap)) == NULL)
/* nothing */;
if (fp != rescan) {
if (macrodef && macrocount <= MAXMACRO)
macro[macrocount - 1].m_funct
= fp;
return (mgwrap(fp, f, n));
}
}
}
/* try previous mode */
if (--md < 0)
return (ABORT);
curmap = curbp->b_modes[md]->p_map;
for (i = 0; i < key.k_count; i++) {
if ((fp = doscan(curmap, (key.k_chars[i]), &curmap)) != NULL)
break;
}
if (fp == NULL) {
while ((fp = doscan(curmap, key.k_chars[i++] =
getkey(TRUE), &curmap)) == NULL)
/* nothing */;
key.k_count = i;
}
if (fp != rescan && i >= key.k_count - 1) {
if (macrodef && macrocount <= MAXMACRO)
macro[macrocount - 1].m_funct = fp;
return (mgwrap(fp, f, n));
}
}
}
int
universal_argument(int f, int n)
{
KEYMAP *curmap;
PF funct;
int c, nn = 4;
if (f & FFUNIV)
nn *= n;
for (;;) {
key.k_chars[0] = c = getkey(TRUE);
key.k_count = 1;
if (c == '-')
return (negative_argument(f, nn));
if (c >= '0' && c <= '9')
return (digit_argument(f, nn));
curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
while ((funct = doscan(curmap, c, &curmap)) == NULL) {
key.k_chars[key.k_count++] = c = getkey(TRUE);
}
if (funct != universal_argument) {
if (macrodef && macrocount < MAXMACRO - 1) {
if (f & FFARG)
macrocount--;
macro[macrocount++].m_count = nn;
macro[macrocount++].m_funct = funct;
}
return (mgwrap(funct, FFUNIV, nn));
}
nn <<= 2;
}
}
/* ARGSUSED */
int
digit_argument(int f, int n)
{
KEYMAP *curmap;
PF funct;
int nn, c;
nn = key.k_chars[key.k_count - 1] - '0';
for (;;) {
c = getkey(TRUE);
if (c < '0' || c > '9')
break;
nn *= 10;
nn += c - '0';
}
key.k_chars[0] = c;
key.k_count = 1;
curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
while ((funct = doscan(curmap, c, &curmap)) == NULL) {
key.k_chars[key.k_count++] = c = getkey(TRUE);
}
if (macrodef && macrocount < MAXMACRO - 1) {
if (f & FFARG)
macrocount--;
else
macro[macrocount - 1].m_funct = universal_argument;
macro[macrocount++].m_count = nn;
macro[macrocount++].m_funct = funct;
}
return (mgwrap(funct, FFOTHARG, nn));
}
int
negative_argument(int f, int n)
{
KEYMAP *curmap;
PF funct;
int c;
int nn = 0;
for (;;) {
c = getkey(TRUE);
if (c < '0' || c > '9')
break;
nn *= 10;
nn += c - '0';
}
if (nn)
nn = -nn;
else
nn = -n;
key.k_chars[0] = c;
key.k_count = 1;
curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
while ((funct = doscan(curmap, c, &curmap)) == NULL) {
key.k_chars[key.k_count++] = c = getkey(TRUE);
}
if (macrodef && macrocount < MAXMACRO - 1) {
if (f & FFARG)
macrocount--;
else
macro[macrocount - 1].m_funct = universal_argument;
macro[macrocount++].m_count = nn;
macro[macrocount++].m_funct = funct;
}
return (mgwrap(funct, FFNEGARG, nn));
}
/*
* Insert a character. While defining a macro, create a "LINE" containing
* all inserted characters.
*/
int
selfinsert(int f, int n)
{
struct line *lp;
int c;
int count;
if (n < 0)
return (FALSE);
if (n == 0)
return (TRUE);
c = key.k_chars[key.k_count - 1];
if (macrodef && macrocount < MAXMACRO) {
if (f & FFARG)
macrocount -= 2;
/* last command was insert -- tack on the end */
if (lastflag & CFINS) {
macrocount--;
/* Ensure the line can handle the new characters */
if (maclcur->l_size < maclcur->l_used + n) {
if (lrealloc(maclcur, maclcur->l_used + n) ==
FALSE)
return (FALSE);
}
maclcur->l_used += n;
/* Copy in the new data */
for (count = maclcur->l_used - n;
count < maclcur->l_used; count++)
maclcur->l_text[count] = c;
} else {
macro[macrocount - 1].m_funct = insert;
if ((lp = lalloc(n)) == NULL)
return (FALSE);
lp->l_bp = maclcur;
lp->l_fp = maclcur->l_fp;
maclcur->l_fp = lp;
maclcur = lp;
for (count = 0; count < n; count++)
lp->l_text[count] = c;
}
thisflag |= CFINS;
}
if (c == '\n') {
do {
count = lnewline();
} while (--n && count == TRUE);
return (count);
}
/* overwrite mode */
if (curbp->b_flag & BFOVERWRITE) {
lchange(WFEDIT);
while (curwp->w_doto < llength(curwp->w_dotp) && n--)
lputc(curwp->w_dotp, curwp->w_doto++, c);
if (n <= 0)
return (TRUE);
}
return (linsert(n, c));
}
/*
* selfinsert() can't be called directly from a startup file or by
* 'eval-current-buffer' since it is by design, meant to be called interactively
* as characters are typed in a buffer. ask_selfinsert() allows selfinsert() to
* be used by excline(). Having ask_selfinsert() helps with regression testing.
* No manual page entry since use case is a bit obscure. See 'insert' command.
*/
int
ask_selfinsert(int f, int n)
{
char *c, cbuf[2];
if ((c = eread("Insert a character: ", cbuf, sizeof(cbuf),
EFNEW)) == NULL || (c[0] == '\0'))
return (ABORT);
key.k_chars[0] = *c;
key.k_chars[1] = '\0';
key.k_count = 1;
return (selfinsert(FFRAND, 1));
}
/*
* This could be implemented as a keymap with everything defined as self-insert.
*/
int
quote(int f, int n)
{
int c;
key.k_count = 1;
if ((key.k_chars[0] = getkey(TRUE)) >= '0' && key.k_chars[0] <= '7') {
key.k_chars[0] -= '0';
if ((c = getkey(TRUE)) >= '0' && c <= '7') {
key.k_chars[0] <<= 3;
key.k_chars[0] += c - '0';
if ((c = getkey(TRUE)) >= '0' && c <= '7') {
key.k_chars[0] <<= 3;
key.k_chars[0] += c - '0';
} else
ungetkey(c);
} else
ungetkey(c);
}
return (selfinsert(f, n));
}
/*
* Wraper function to count invocation repeats.
* We ignore any function whose sole purpose is to get us
* to the intended function.
*/
static int
mgwrap(PF funct, int f, int n)
{
static PF ofp;
if (funct != rescan &&
funct != negative_argument &&
funct != digit_argument &&
funct != universal_argument) {
if (funct == ofp)
rptcount++;
else
rptcount = 0;
ofp = funct;
}
return ((*funct)(f, n));
}