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