blob: abd202fb764ee06ce00b3cb65f82c284204b9c3d [file] [log] [blame]
/*
* Parse /lib/keyboard to create latin1.h table for kernel.
* mklatinkbd -r prints an array of integers rather than a Rune string literal.
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
int rflag;
int xflag;
enum {
MAXLD = 2, /* latin1.c assumes this is 2 */
};
char *head = ""
"/*\n"
" * This is automatically generated by %s from /lib/keyboard\n"
" * Edit /lib/keyboard instead.\n"
" */\n";
/*
* latin1.c assumes that strlen(ld) is at most 2.
* It also assumes that latintab[i].ld can be a prefix of latintab[j].ld
* only when j < i. We ensure this by sorting the output by prefix length.
* The so array is indexed by the character value.
*/
typedef struct Trie Trie;
struct Trie {
int n; /* of characters r */
char seq[MAXLD+1+1];
Rune r[256];
Trie *link[256];
};
Trie *root;
Trie*
mktrie(char *seq)
{
uchar *q;
Trie **tp;
if(root == nil) {
root = malloc(sizeof *root);
memset(root, 0, sizeof *root);
}
assert(seq[0] != '\0');
tp = &root;
for(q=(uchar*)seq; *(q+1) != '\0'; q++) {
tp = &(*tp)->link[*q];
if(*tp == nil) {
*tp = malloc(sizeof(**tp));
assert(*tp != nil);
memset(*tp, 0, sizeof(**tp));
strcpy((*tp)->seq, seq);
(*tp)->seq[q+1-(uchar*)seq] = '\0';
}
}
assert(*tp != nil);
return *tp;
}
/* add character sequence s meaning rune r */
void
insert(char *s, Rune r)
{
uchar lastc;
int len;
Trie *t;
len = strlen(s);
lastc = (uchar)s[len-1];
t = mktrie(s);
if(t->r[lastc]) {
fprint(2, "warning: table duplicate: %s is %C and %C\n", s, t->r[lastc], r);
return;
}
t->r[lastc] = r;
t->n++;
}
void
cprintchar(Biobuf *b, int c)
{
/* print a byte c safe for a C string. */
switch(c) {
case '\'':
case '\"':
case '\\':
Bprint(b, "\\%c", c);
break;
case '\t':
Bprint(b, "\\t");
break;
default:
if(isascii(c) && isprint(c))
Bprint(b, "%c", c);
else
Bprint(b, "\\x%.2x", c);
break;
}
}
void
cprints(Biobuf *b, char *p)
{
while(*p != '\0')
cprintchar(b, *p++);
}
void
xprint(Biobuf *b, int c)
{
}
void
printtrie(Biobuf *b, Trie *t)
{
int i;
char *p;
for(i=0; i<256; i++)
if(t->link[i])
printtrie(b, t->link[i]);
if(t->n == 0)
return;
if(xflag) {
for(i=0; i<256; i++) {
if(t->r[i] == 0)
continue;
Bprint(b, "<Multi_key>");
for(p=t->seq; *p; p++)
Bprint(b, " %k", *p);
Bprint(b, " %k : \"%C\" U%04X\n", i, t->r[i], t->r[i]);
}
return;
}
Bprint(b, "\t\"");
cprints(b, t->seq);
Bprint(b, "\", \"");
for(i=0; i<256; i++)
if(t->r[i])
cprintchar(b, i);
Bprint(b, "\",\t");
if(rflag) {
Bprint(b, "{");
for(i=0; i<256; i++)
if(t->r[i])
Bprint(b, " 0x%.4ux,", t->r[i]);
Bprint(b, " }");
} else {
Bprint(b, "L\"");
for(i=0; i<256; i++)
if(t->r[i])
Bprint(b, "%C", t->r[i]);
Bprint(b, "\"");
}
Bprint(b, ",\n");
}
void
readfile(char *fname)
{
Biobuf *b;
char *line, *p;
char *seq;
int inseq;
int lineno;
Rune r;
if((b = Bopen(fname, OREAD)) == 0) {
fprint(2, "cannot open \"%s\": %r\n", fname);
exits("open");
}
lineno = 0;
while((line = Brdline(b, '\n')) != 0) {
lineno++;
if(line[0] == '#')
continue;
r = strtol(line, nil, 16);
p = strchr(line, ' ');
if(r == 0 || p != line+4 || p[0] != ' ' || p[1] != ' ') {
fprint(2, "%s:%d: cannot parse line\n", fname, lineno);
continue;
}
p = line+6;
/* 00AE Or rO ® registered trade mark sign */
for(inseq=1, seq=p; (uchar)*p < Runeself; p++) {
if(*p == '\0' || isspace(*p)) {
if(inseq && p-seq >= 2) {
*p = '\0';
inseq = 0;
insert(seq, r);
*p = ' ';
}
if(*p == '\0')
break;
} else {
if(!inseq) {
seq = p;
inseq = 1;
}
}
}
}
}
void
usage(void)
{
fprint(2, "usage: mklatinkbd [-r] [/lib/keyboard]\n");
exits("usage");
}
int kfmt(Fmt*);
void
main(int argc, char **argv)
{
int i;
Biobuf bout;
ARGBEGIN{
case 'r': /* print rune values */
rflag = 1;
break;
case 'x':
xflag = 1;
break;
default:
usage();
}ARGEND
if(argc > 1)
usage();
fmtinstall('k', kfmt);
readfile(argc == 1 ? argv[0] : "/dev/stdin");
Binit(&bout, 1, OWRITE);
if(xflag) {
Bprint(&bout, "# Generated by mklatinkbd -x; do not edit.\n");
for(i=0x20; i<0x10000; i++)
Bprint(&bout, "<Multi_key> <X> <%x> <%x> <%x> <%x> : \"%C\" U%04X\n",
(i>>12)&0xf, (i>>8)&0xf, (i>>4)&0xf, i&0xf, i, i);
}
if(root)
printtrie(&bout, root);
exits(0);
}
// X11 key names
struct {
int c;
char *s;
} xkey[] = {
' ', "space",
'!', "exclam",
'"', "quotedbl",
'#', "numbersign",
'$', "dollar",
'%', "percent",
'&', "ampersand",
'\'', "apostrophe",
'(', "parenleft",
')', "parenright",
'*', "asterisk",
'+', "plus",
',', "comma",
'-', "minus",
'.', "period",
'/', "slash",
':', "colon",
';', "semicolon",
'<', "less",
'=', "equal",
'>', "greater",
'?', "question",
'@', "at",
'[', "bracketleft",
'\\', "backslash",
',', "bracketright",
'^', "asciicircum",
'_', "underscore",
'`', "grave",
'{', "braceleft",
'|', "bar",
'}', "braceright",
'~', "asciitilde",
0, 0
};
int
kfmt(Fmt *f)
{
int i, c;
c = va_arg(f->args, int);
for(i=0; xkey[i].s; i++)
if(xkey[i].c == c)
return fmtprint(f, "<%s>", xkey[i].s);
return fmtprint(f, "<%c>", c);
}