/*
* keyboard map
*/
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
enum{
Qdir,
Qdata,
};
Dirtab kbmaptab[]={
".", {Qdir, 0, QTDIR}, 0, 0555,
"kbmap", {Qdata, 0}, 0, 0600,
};
#define NKBFILE sizeof(kbmaptab)/sizeof(kbmaptab[0])
#define KBLINELEN (3*NUMSIZE+1) /* t code val\n */
static Chan *
kbmapattach(char *spec)
{
return devattach(L'κ', spec);
}
static Walkqid*
kbmapwalk(Chan *c, Chan *nc, char **name, int nname)
{
return devwalk(c, nc, name, nname, kbmaptab, NKBFILE, devgen);
}
static int
kbmapstat(Chan *c, uchar *dp, int n)
{
return devstat(c, dp, n, kbmaptab, NKBFILE, devgen);
}
static Chan*
kbmapopen(Chan *c, int omode)
{
if(!iseve())
error(Eperm);
return devopen(c, omode, kbmaptab, NKBFILE, devgen);
}
static void
kbmapclose(Chan *c)
{
if(c->aux){
free(c->aux);
c->aux = nil;
}
}
static long
kbmapread(Chan *c, void *a, long n, vlong offset)
{
char *bp;
char tmp[KBLINELEN+1];
int t, sc;
Rune r;
if(c->qid.type == QTDIR)
return devdirread(c, a, n, kbmaptab, NKBFILE, devgen);
switch((int)(c->qid.path)){
case Qdata:
if(kbdgetmap(offset/KBLINELEN, &t, &sc, &r)) {
bp = tmp;
bp += readnum(0, bp, NUMSIZE, t, NUMSIZE);
bp += readnum(0, bp, NUMSIZE, sc, NUMSIZE);
bp += readnum(0, bp, NUMSIZE, r, NUMSIZE);
*bp++ = '\n';
*bp = 0;
n = readstr(offset%KBLINELEN, a, n, tmp);
} else
n = 0;
break;
default:
n=0;
break;
}
return n;
}
static long
kbmapwrite(Chan *c, void *a, long n, vlong)
{
char line[100], *lp, *b;
int key, m, l;
Rune r;
if(c->qid.type == QTDIR)
error(Eperm);
switch((int)(c->qid.path)){
case Qdata:
b = a;
l = n;
lp = line;
if(c->aux){
strcpy(line, c->aux);
lp = line+strlen(line);
free(c->aux);
c->aux = nil;
}
while(--l >= 0) {
*lp++ = *b++;
if(lp[-1] == '\n' || lp == &line[sizeof(line)-1]) {
*lp = 0;
if(*line == 0)
error(Ebadarg);
if(*line == '\n' || *line == '#'){
lp = line;
continue;
}
lp = line;
while(*lp == ' ' || *lp == '\t')
lp++;
m = strtoul(line, &lp, 0);
key = strtoul(lp, &lp, 0);
while(*lp == ' ' || *lp == '\t')
lp++;
r = 0;
if(*lp == '\'' && lp[1])
chartorune(&r, lp+1);
else if(*lp == '^' && lp[1]){
chartorune(&r, lp+1);
if(0x40 <= r && r < 0x60)
r -= 0x40;
else
error(Ebadarg);
}else if(*lp == 'M' && ('1' <= lp[1] && lp[1] <= '5'))
r = 0xF900+lp[1]-'0';
else if(*lp>='0' && *lp<='9') /* includes 0x... */
r = strtoul(lp, &lp, 0);
else
error(Ebadarg);
kbdputmap(m, key, r);
lp = line;
}
}
if(lp != line){
l = lp-line;
c->aux = lp = smalloc(l+1);
memmove(lp, line, l);
lp[l] = 0;
}
break;
default:
error(Ebadusefd);
}
return n;
}
Dev kbmapdevtab = {
L'κ',
"kbmap",
devreset,
devinit,
devshutdown,
kbmapattach,
kbmapwalk,
kbmapstat,
kbmapopen,
devcreate,
kbmapclose,
kbmapread,
devbread,
kbmapwrite,
devbwrite,
devremove,
devwstat,
};
|