• 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, 0660);
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