xref: /plan9/sys/src/cmd/aux/mklatinkbd.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1 /*
2  * Parse /lib/keyboard to create latin1.h table for kernel.
3  * mklatinkbd -r prints an array of integers rather than a Rune string literal.
4  */
5 
6 #include <u.h>
7 #include <libc.h>
8 #include <bio.h>
9 #include <ctype.h>
10 
11 int rflag;
12 
13 enum {
14 	MAXLD = 2,	/* latin1.c assumes this is 2 */
15 };
16 
17 char *head = ""
18 "/*\n"
19 " * This is automatically generated by %s from /lib/keyboard\n"
20 " * Edit /lib/keyboard instead.\n"
21 " */\n";
22 
23 /*
24  * latin1.c assumes that strlen(ld) is at most 2.
25  * It also assumes that latintab[i].ld can be a prefix of latintab[j].ld
26  * only when j < i.  We ensure this by sorting the output by prefix length.
27  * The so array is indexed by the character value.
28  */
29 
30 typedef struct Trie	Trie;
31 struct Trie {
32 	int n; /* of characters r */
33 	char seq[MAXLD+1];
34 	Rune r[256];
35 	Trie *link[256];
36 };
37 
38 Trie *root;
39 
40 Trie*
mktrie(char * seq)41 mktrie(char *seq)
42 {
43 	uchar *q;
44 	Trie **tp;
45 
46 	if(root == nil) {
47 		root = malloc(sizeof *root);
48 		memset(root, 0, sizeof *root);
49 	}
50 
51 	assert(seq[0] != '\0');
52 
53 	tp = &root;
54 	for(q=(uchar*)seq; *(q+1) != '\0'; q++) {
55 		tp = &(*tp)->link[*q];
56 		if(*tp == nil) {
57 			*tp = malloc(sizeof(**tp));
58 			assert(*tp != nil);
59 			memset(*tp, 0, sizeof(**tp));
60 			strcpy((*tp)->seq, seq);
61 			(*tp)->seq[q+1-(uchar*)seq] = '\0';
62 		}
63 	}
64 
65 	assert(*tp != nil);
66 	return *tp;
67 }
68 
69 /* add character sequence s meaning rune r */
70 void
insert(char * s,Rune r)71 insert(char *s, Rune r)
72 {
73 	uchar lastc;
74 	int len;
75 	Trie *t;
76 
77 	len = strlen(s);
78 	lastc = (uchar)s[len-1];
79 
80 	t = mktrie(s);
81 	if(t->r[lastc]) {
82 		fprint(2, "warning: table duplicate: %s is %C and %C\n", s, t->r[lastc], r);
83 		return;
84 	}
85 	t->r[lastc] = r;
86 	t->n++;
87 }
88 
89 void
cprintchar(Biobuf * b,int c)90 cprintchar(Biobuf *b, int c)
91 {
92 	/* print a byte c safe for a C string. */
93 	switch(c) {
94 	case '\'':
95 	case '\"':
96 	case '\\':
97 		Bprint(b, "\\%c", c);
98 		break;
99 	case '\t':
100 		Bprint(b, "\\t");
101 		break;
102 	default:
103 		if(isascii(c) && isprint(c))
104 			Bprint(b, "%c", c);
105 		else
106 			Bprint(b, "\\x%.2x", c);
107 		break;
108 	}
109 }
110 
111 void
cprints(Biobuf * b,char * p)112 cprints(Biobuf *b, char *p)
113 {
114 	while(*p != '\0')
115 		cprintchar(b, *p++);
116 }
117 
118 
119 void
printtrie(Biobuf * b,Trie * t)120 printtrie(Biobuf *b, Trie *t)
121 {
122 	int i;
123 
124 	for(i=0; i<256; i++)
125 		if(t->link[i])
126 			printtrie(b, t->link[i]);
127 
128 	if(t->n > 0) {
129 		Bprint(b, "\t\"");
130 		cprints(b, t->seq);
131 		Bprint(b, "\", \"");
132 		for(i=0; i<256; i++)
133 			if(t->r[i])
134 				cprintchar(b, i);
135 		Bprint(b, "\",\t");
136 		if(rflag) {
137 			Bprint(b, "{");
138 			for(i=0; i<256; i++)
139 				if(t->r[i])
140 					Bprint(b, " 0x%.4ux,", t->r[i]);
141 			Bprint(b, " }");
142 		} else {
143 			Bprint(b, "L\"");
144 			for(i=0; i<256; i++)
145 				if(t->r[i])
146 					Bprint(b, "%C", t->r[i]);
147 			Bprint(b, "\"");
148 		}
149 		Bprint(b, ",\n");
150 	}
151 }
152 
153 void
readfile(char * fname)154 readfile(char *fname)
155 {
156 	Biobuf *b;
157 	char *line, *p;
158 	char *seq;
159 	int inseq;
160 	int lineno;
161 	Rune r;
162 
163 	if((b = Bopen(fname, OREAD)) == 0) {
164 		fprint(2, "cannot open \"%s\": %r\n", fname);
165 		exits("open");
166 	}
167 
168 	lineno = 0;
169 	while((line = Brdline(b, '\n')) != 0) {
170 		lineno++;
171 		if(line[0] == '#')
172 			continue;
173 
174 		r = strtol(line, nil, 16);
175 		p = strchr(line, ' ');
176 		if(r == 0 || p != line+4 || p[0] != ' ' || p[1] != ' ') {
177 			fprint(2, "%s:%d: cannot parse line\n", fname, lineno);
178 			continue;
179 		}
180 
181 		p = line+6;
182 /*	00AE  Or rO       ®	registered trade mark sign	*/
183 		for(inseq=1, seq=p; (uchar)*p < Runeself; p++) {
184 			if(*p == '\0' || isspace(*p)) {
185 				if(inseq && p-seq >= 2) {
186 					*p = '\0';
187 					inseq = 0;
188 					insert(seq, r);
189 					*p = ' ';
190 				}
191 				if(*p == '\0')
192 					break;
193 			} else {
194 				if(!inseq) {
195 					seq = p;
196 					inseq = 1;
197 				}
198 			}
199 		}
200 	}
201 }
202 
203 void
usage(void)204 usage(void)
205 {
206 	fprint(2, "usage: mklatinkbd [-r] [/lib/keyboard]\n");
207 	exits("usage");
208 }
209 
210 void
main(int argc,char ** argv)211 main(int argc, char **argv)
212 {
213 	Biobuf bout;
214 
215 	ARGBEGIN{
216 	case 'r':	/* print rune values */
217 		rflag = 1;
218 		break;
219 	default:
220 		usage();
221 	}ARGEND
222 
223 	if(argc > 1)
224 		usage();
225 
226 	readfile(argc == 1 ? argv[0] : "/fd/0");
227 
228 	Binit(&bout, 1, OWRITE);
229 	if(root)
230 		printtrie(&bout, root);
231 	exits(0);
232 }
233