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