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