#include #include #include #include #define assert(x, y) if(!(x)) { fprint(2, y); fprint(2, "\n"); exits("assert"); } enum { NMAX = 256, }; char *head = "" "/*\n" " * This is automatically generated by %s from /lib/keyboard\n" " * Edit /lib/keyboard instead.\n" " */\n"; /* * this code does not assumes (as does latin1.c) that * ld is 1 or 2 characters. * as for the jn = 0; s->c = 0; s->next = s->nchar = 0; return s; } void insert(Scroll *scroll, Rune r, char *keyb, char *orig) { /* into scroll, insert keyb as meaning r */ Scroll *s; int len, i; len = strlen(keyb); assert(len > 0, "length bug"); /* if down to one character, insert in tables. */ if(len == 1) { s = scroll; for(i=0; i < s->n; i++) if(s->si[i] == keyb[0]) { fprint(2, "table duplicate: %s\n", orig); return; } s->si[s->n] = keyb[0]; s->so[s->n] = r; assert(s->n < NMAX-1, "too many runes in si/so"); s->n++; return; } /* otherwise, recur */ /* if there is no next-character list, create one */ s = scroll->nchar; if(s == 0) { s = scroll->nchar = newscroll(); s->c = keyb[0]; } while(s && s->c != keyb[0]) s = s->next; /* if the next character isn't on the list, insert it */ if(s == 0) { s = newscroll(); s->c = keyb[0]; s->next = scroll->nchar; scroll->nchar = s; } assert(s != 0, "program bug1"); assert(s->c == keyb[0], "program bug2"); /* recur */ insert(s, r, keyb+1, orig); } void cprintchar(int c) { /* print a character c safe for a C string. */ switch(c) { case '\'': case '\"': case '\\': print("\\%c", c); break; case '\t': print("\\t"); break; default: if(isascii(c) && isprint(c)) print("%c", c); else print("\\x%.2x", c); break; } } void scrolldump(Scroll *scroll, char *prefix) { /* * this function modifies prefix temporarily. * prefix must be large enough to hold the maximum * keyboard sequence length. */ int i, len; Scroll *s; char *p; if(scroll == 0) return; prefix[len=strlen(prefix)] = scroll->c; prefix[len+1] = '\0'; /* * first print larger sequences, * then print current sequences * then print other same length sequences * * this takes care of the jnchar != 0) scrolldump(s->nchar, prefix); /* print current sequences */ /* "\"", "AEIOUY\"aeiouy", L"ÄËÏÖÜŸ¨äëïöüÿ", */ if(s->n > 0) { print("\t\""); for(p=prefix; *p; p++) cprintchar(*p); print("\", \""); for(i=0; i < s->n; i++) { /* am i forgetting something here ? */ cprintchar(s->si[i]); } print("\", L\""); for(i=0; i < s->n; i++) { /* am i forgetting something here ? */ if(s->so[i] < Runeself) cprintchar(s->so[i]); else print("%C", s->so[i]); } print("\",\n"); } /* print other same-length sequences. */ /* kill changed prefix first */ prefix[len] = '\0'; scrolldump(scroll->next, prefix); } void readfile(char *fname) { Biobuf *b; char *line, *p; char *seq; int inseq; Rune r; if((b = Bopen(fname, OREAD)) == 0) { fprint(2, "cannot open \"%s\": %r\n", fname); exits("open"); } while((line = Brdline(b, '\n')) != 0) { if(line[0] == '#') continue; r = 0; for(p=line; *p != '\0' && p < line+4; p++) { if(!isascii(*p)) break; if(isdigit(*p)) { r = r * 16 + *p - '0'; } else if(isxdigit(*p)) { r = r * 16 + toupper(*p) - 'A' + 10; } else break; } if(*p == '\0' || !isascii(*p) || !isspace(*p)) { fprint(2, "bad line: %s\n", line); continue; } /* 00AE Or rO ® registered trade mark sign */ inseq = 0; seq = 0; for(;*p != '\0' && isascii(*p); p++) { if(isspace(*p)) { if(inseq) { *p = '\0'; inseq = 0; insert(&scrollhead, r, seq, seq); } } else { if(!inseq) { seq = p; inseq = 1; } } } if(inseq) { *p = '\0'; insert(&scrollhead, r, seq, seq); } } } void main(int argc, char **argv) { char buf[128]; /* MAX sequence length */ if(argc > 2) { fprint(2, "usage: %s [infile]\n", argv[0]); exits("usage"); } if(argc == 2) readfile(argv[1]); else readfile("/fd/0"); assert(scrollhead.next == 0, "readfile problem BUG"); buf[0] = '\0'; scrolldump(scrollhead.nchar, buf); exits(0); }