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