• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdio.h>
2 #include <string.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <fcntl.h>
6 #include <unistd.h>
7 #include <ui/KeycodeLabels.h>
8 #include <stdlib.h>
9 #include <ctype.h>
10 #include <map>
11 #include <string>
12 #include <utils/ByteOrder.h>
13 
14 using namespace std;
15 
16 enum {
17     LENDIAN,
18     BENDIAN
19 };
20 
21 /*
22  * 1: KeyEvent name
23  * 2: display_label
24  * 3: number
25  * 4..7: base, shift, alt, shift-alt
26  */
27 #define COLUMNS (3+4)
28 
29 struct KeyRecord
30 {
31     int lineno;
32     int values[COLUMNS];
33 };
34 
35 struct PropValue
36 {
PropValuePropValue37     PropValue() { lineno = -1; }
PropValuePropValue38     PropValue(const PropValue& that) { lineno=that.lineno; value=that.value; }
PropValuePropValue39     PropValue(int l, const string& v) { lineno = l; value = v; }
40 
41     int lineno;
42     string value;
43 };
44 
45 static int usage();
46 
47 //  0 -- ok
48 // >0 -- error
49 static int parse_key_line(const char* filename, int lineno, char* line,
50         KeyRecord* out);
51 static int write_kr(int fd, const KeyRecord& kr);
52 
53 int g_endian;
54 
55 int
main(int argc,char ** argv)56 main(int argc, char** argv)
57 {
58     int err;
59     if (argc != 3) {
60         return usage();
61     }
62 
63     const char* filename = argv[1];
64     const char* outfilename = argv[2];
65 
66     int in = open(filename, O_RDONLY);
67     if (in == -1) {
68         fprintf(stderr, "kcm: error opening file for read: %s\n", filename);
69         return 1;
70     }
71 
72     off_t size = lseek(in, 0, SEEK_END);
73     lseek(in, 0, SEEK_SET);
74 
75     char* input = (char*)malloc(size+1);
76     read(in, input, size);
77     input[size] = '\0';
78 
79     close(in);
80     in = -1;
81 
82     map<string,PropValue> properties;
83     map<int,KeyRecord> keys;
84     int errorcount = 0;
85     int lineno = 1;
86     char *thisline = input;
87     while (*thisline) {
88         KeyRecord kr;
89         char *nextline = thisline;
90 
91         while (*nextline != '\0' && *nextline != '\n' && *nextline != '\r') {
92             nextline++;
93         }
94 
95         // eat whitespace, but not newlines
96         while (*thisline != '\0' && (*thisline == ' ' || *thisline == '\t')) {
97             thisline++;
98         }
99 
100         // find the end of the line
101         char lineend = *nextline;
102         *nextline = '\0';
103         if (lineend == '\r' && nextline[1] == '\n') {
104             nextline++;
105         }
106 
107         if (*thisline == '\0' || *thisline == '\r' || *thisline == '\n'
108                  || *thisline == '#') {
109             // comment or blank line
110         }
111         else if (*thisline == '[') {
112             // property - syntax [name=value]
113             // look for =
114             char* prop = thisline+1;
115             char* end = prop;
116             while (*end != '\0' && *end != '=') {
117                 end++;
118             }
119             if (*end != '=') {
120                 fprintf(stderr, "%s:%d: invalid property line: %s\n",
121                         filename, lineno, thisline);
122                 errorcount++;
123             } else {
124                 *end = '\0';
125                 char* value = end+1;
126                 end = nextline;
127                 while (end > prop && *end != ']') {
128                     end--;
129                 }
130                 if (*end != ']') {
131                     fprintf(stderr, "%s:%d: property missing closing ]: %s\n",
132                             filename, lineno, thisline);
133                     errorcount++;
134                 } else {
135                     *end = '\0';
136                     properties[prop] = PropValue(lineno, value);
137                 }
138             }
139         }
140         else {
141             // key
142             err = parse_key_line(filename, lineno, thisline, &kr);
143             if (err == 0) {
144                 kr.lineno = lineno;
145 
146                 map<int,KeyRecord>::iterator old = keys.find(kr.values[0]);
147                 if (old != keys.end()) {
148                     fprintf(stderr, "%s:%d: keycode %d already defined\n",
149                             filename, lineno, kr.values[0]);
150                     fprintf(stderr, "%s:%d: previously defined here\n",
151                             filename, old->second.lineno);
152                     errorcount++;
153                 }
154 
155                 keys[kr.values[0]] = kr;
156             }
157             else if (err > 0) {
158                 errorcount += err;
159             }
160         }
161         lineno++;
162 
163         nextline++;
164         thisline = nextline;
165 
166         if (errorcount > 20) {
167             fprintf(stderr, "%s:%d: too many errors.  stopping.\n", filename,
168                     lineno);
169             return 1;
170         }
171     }
172 
173     free(input);
174 
175     map<string,PropValue>::iterator sit = properties.find("type");
176     if (sit == properties.end()) {
177         fprintf(stderr, "%s: key character map must contain type property.\n",
178 		argv[0]);
179         errorcount++;
180     }
181     PropValue pv = sit->second;
182     unsigned char kbdtype = 0;
183     if (pv.value == "NUMERIC") {
184         kbdtype = 1;
185     }
186     else if (pv.value == "Q14") {
187         kbdtype = 2;
188     }
189     else if (pv.value == "QWERTY") {
190         kbdtype = 3;
191     }
192     else {
193         fprintf(stderr, "%s:%d: keyboard type must be one of NUMERIC, Q14 "
194                 " or QWERTY, not %s\n", filename, pv.lineno, pv.value.c_str());
195     }
196 
197     if (errorcount != 0) {
198         return 1;
199     }
200 
201     int out = open(outfilename, O_RDWR|O_CREAT|O_TRUNC, 0664);
202     if (out == -1) {
203         fprintf(stderr, "kcm: error opening file for write: %s\n", outfilename);
204         return 1;
205     }
206 
207     int count = keys.size();
208 
209     map<int,KeyRecord>::iterator it;
210     int n;
211 
212     /**
213      * File Format:
214      *    Offset    Description     Value
215      *    0         magic string    "keychar"
216      *    8         endian marker   0x12345678
217      *    12        version         0x00000002
218      *    16        key count       number of key entries
219      *    20        keyboard type   NUMERIC, Q14, QWERTY, etc.
220      *    21        padding         0
221      *    32        the keys
222      */
223     err = write(out, "keychar", 8);
224     if (err == -1) goto bad_write;
225 
226     n = htodl(0x12345678);
227     err = write(out, &n, 4);
228     if (err == -1) goto bad_write;
229 
230     n = htodl(0x00000002);
231     err = write(out, &n, 4);
232     if (err == -1) goto bad_write;
233 
234     n = htodl(count);
235     err = write(out, &n, 4);
236     if (err == -1) goto bad_write;
237 
238     err = write(out, &kbdtype, 1);
239     if (err == -1) goto bad_write;
240 
241     char zero[11];
242     memset(zero, 0, 11);
243     err = write(out, zero, 11);
244     if (err == -1) goto bad_write;
245 
246     for (it = keys.begin(); it != keys.end(); it++) {
247         const KeyRecord& kr = it->second;
248         /*
249         printf("%2d/ [%d] [%d] [%d] [%d] [%d] [%d] [%d]\n", kr.lineno,
250                 kr.values[0], kr.values[1], kr.values[2], kr.values[3],
251                 kr.values[4], kr.values[5], kr.values[6]);
252         */
253         err = write_kr(out, kr);
254         if (err == -1) goto bad_write;
255     }
256 
257     close(out);
258     return 0;
259 
260 bad_write:
261     fprintf(stderr, "kcm: fatal error writing to file: %s\n", outfilename);
262     close(out);
263     unlink(outfilename);
264     return 1;
265 }
266 
usage()267 static int usage()
268 {
269     fprintf(stderr,
270             "usage: kcm INPUT OUTPUT\n"
271             "\n"
272             "INPUT   keycharmap file\n"
273             "OUTPUT  compiled keycharmap file\n"
274         );
275     return 1;
276 }
277 
278 static int
is_whitespace(const char * p)279 is_whitespace(const char* p)
280 {
281     while (*p) {
282         if (!isspace(*p)) {
283             return 0;
284         }
285         p++;
286     }
287     return 1;
288 }
289 
290 
291 static int
parse_keycode(const char * filename,int lineno,char * str,int * value)292 parse_keycode(const char* filename, int lineno, char* str, int* value)
293 {
294     const KeycodeLabel *list = KEYCODES;
295     while (list->literal) {
296         if (0 == strcmp(str, list->literal)) {
297             *value = list->value;
298             return 0;
299         }
300         list++;
301     }
302 
303     char* endptr;
304     *value = strtol(str, &endptr, 0);
305     if (*endptr != '\0') {
306         fprintf(stderr, "%s:%d: expected keycode label or number near: "
307                 "%s\n", filename, lineno, str);
308         return 1;
309     }
310 
311     if (*value == 0) {
312         fprintf(stderr, "%s:%d: 0 is not a valid keycode.\n",
313                 filename, lineno);
314         return 1;
315     }
316 
317     return 0;
318 }
319 
320 static int
parse_number(const char * filename,int lineno,char * str,int * value)321 parse_number(const char* filename, int lineno, char* str, int* value)
322 {
323     int len = strlen(str);
324 
325     if (len == 3 && str[0] == '\'' && str[2] == '\'') {
326         if (str[1] > 0 && str[1] < 127) {
327             *value = (int)str[1];
328             return 0;
329         } else {
330             fprintf(stderr, "%s:%d: only low ascii characters are allowed in"
331                     " quotes near: %s\n", filename, lineno, str);
332             return 1;
333         }
334     }
335 
336     char* endptr;
337     *value = strtol(str, &endptr, 0);
338     if (*endptr != '\0') {
339         fprintf(stderr, "%s:%d: expected number or quoted ascii but got: %s\n",
340                 filename, lineno, str);
341         return 1;
342     }
343 
344     if (*value >= 0xfffe || *value < 0) {
345         fprintf(stderr, "%s:%d: unicode char out of range (no negatives, "
346                 "nothing larger than 0xfffe): %s\n", filename, lineno, str);
347         return 1;
348     }
349 
350     return 0;
351 }
352 
353 static int
parse_key_line(const char * filename,int lineno,char * line,KeyRecord * out)354 parse_key_line(const char* filename, int lineno, char* line, KeyRecord* out)
355 {
356     char* p = line;
357 
358     int len = strlen(line);
359     char* s[COLUMNS];
360     for (int i=0; i<COLUMNS; i++) {
361         s[i] = (char*)malloc(len+1);
362     }
363 
364     for (int i = 0; i < COLUMNS; i++) {
365         while (*p != '\0' && isspace(*p)) {
366             p++;
367         }
368 
369         if (*p == '\0') {
370             fprintf(stderr, "%s:%d: not enough on this line: %s\n", filename,
371                     lineno, line);
372             return 1;
373         }
374 
375         char *p1 = p;
376         while (*p != '\0' && !isspace(*p)) {
377             p++;
378         }
379 
380         memcpy(s[i], p1, p - p1);
381         s[i][p - p1] = '\0';
382     }
383 
384     while (*p != '\0' && isspace(*p)) {
385         *p++;
386     }
387     if (*p != '\0') {
388         fprintf(stderr, "%s:%d: too much on one line near: %s\n", filename,
389                 lineno, p);
390         fprintf(stderr, "%s:%d: -->%s<--\n", filename, lineno, line);
391         return 1;
392     }
393 
394     int errorcount = parse_keycode(filename, lineno, s[0], &out->values[0]);
395     for (int i=1; i<COLUMNS && errorcount == 0; i++) {
396         errorcount += parse_number(filename, lineno, s[i], &out->values[i]);
397     }
398 
399     return errorcount;
400 }
401 
402 struct WrittenRecord
403 {
404     unsigned int keycode;       // 4 bytes
405     unsigned short values[COLUMNS - 1];   // 6*2 bytes = 12
406                                 // 16 bytes total
407 };
408 
409 static int
write_kr(int fd,const KeyRecord & kr)410 write_kr(int fd, const KeyRecord& kr)
411 {
412     WrittenRecord wr;
413 
414     wr.keycode = htodl(kr.values[0]);
415     for (int i=0; i<COLUMNS - 1; i++) {
416         wr.values[i] = htods(kr.values[i+1]);
417     }
418 
419     return write(fd, &wr, sizeof(WrittenRecord));
420 }
421 
422