Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 *  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,
};