1 /* 2 * PROJECT: ReactOS Build Tools [Keyboard Layout Compiler] 3 * LICENSE: BSD - See COPYING.BSD in the top level directory 4 * FILE: tools/kbdtool/parser.c 5 * PURPOSE: Parsing Logic 6 * PROGRAMMERS: ReactOS Foundation 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "kbdtool.h" 12 13 /* GLOBALS ********************************************************************/ 14 15 /* Internal parser data about everything that was parsed */ 16 CHAR gBuf[256]; 17 CHAR gKBDName[10]; 18 CHAR gCopyright[256]; 19 CHAR gDescription[256]; 20 CHAR gCompany[256]; 21 CHAR gLocaleName[256]; 22 CHAR gVKeyName[32]; 23 ULONG gID = 0; 24 ULONG gKbdLayoutVersion; 25 LAYOUT g_Layout; 26 ULONG gLineCount; 27 28 /* Table of keywords the parser recognizes */ 29 PCHAR KeyWordList[KEYWORD_COUNT] = 30 { 31 "KBD", 32 "VERSION", 33 "COPYRIGHT", 34 "COMPANY", 35 "LOCALENAME", 36 "MODIIFERS", 37 "SHIFTSTATE", 38 "ATTRIBUTES", 39 "LAYOUT", 40 "DEADKEY", 41 "LIGATURE", 42 "KEYNAME", 43 "KEYNAME_EXT", 44 "KEYNAME_DEAD", 45 "DESCRIPTIONS", 46 "LANGUAGENAMES", 47 "ENDKBD", 48 }; 49 50 /* FUNCTIONS ******************************************************************/ 51 52 ULONG 53 isKeyWord(PCHAR p) 54 { 55 ULONG i; 56 57 /* Check if we know this keyword */ 58 for (i = 0; i < KEYWORD_COUNT; i++) if (strcmp(KeyWordList[i], p) == 0) break; 59 60 /* If we didn't find anything, i will be KEYWORD_COUNT, which is invalid */ 61 return i; 62 } 63 64 PCHAR 65 getVKName(IN ULONG VirtualKey, 66 IN BOOLEAN Prefix) 67 { 68 ULONG i; 69 70 /* Loop for standard virtual key */ 71 if (((VirtualKey >= 'A') && (VirtualKey <= 'Z')) || 72 ((VirtualKey >= '0') && (VirtualKey <= '9'))) 73 { 74 /* Fill out the name */ 75 gVKeyName[0] = '\''; 76 gVKeyName[1] = VirtualKey; 77 gVKeyName[2] = '\''; 78 gVKeyName[3] = '\0'; 79 return gVKeyName; 80 } 81 82 /* Check if a prefix is required */ 83 if (Prefix) 84 { 85 /* Add it */ 86 strcpy(gVKeyName, "VK_"); 87 } 88 else 89 { 90 /* Otherwise, don't add anything */ 91 strcpy(gVKeyName, ""); 92 } 93 94 /* Loop all virtual keys */ 95 for (i = 0; i < 36; i++) 96 { 97 /* Check if this key matches */ 98 if (VKName[i].VirtualKey == VirtualKey) 99 { 100 /* Copy the key's name into the buffer */ 101 strcat(gVKeyName, VKName[i].Name); 102 return gVKeyName; 103 } 104 } 105 106 /* If we got here, then we failed, so print out an error name */ 107 strcpy(gVKeyName, "#ERROR#"); 108 return gVKeyName; 109 } 110 111 ULONG 112 getVKNum(IN PCHAR p) 113 { 114 ULONG Length; 115 ULONG i; 116 ULONG KeyNumber; 117 118 /* Compute the length of the string */ 119 Length = strlen(p); 120 if (!Length) return -1; 121 122 /* Check if this is is a simple key */ 123 if (Length == 1) 124 { 125 /* If it's a number, return it now */ 126 if ((*p >= '0') && (*p <= '9')) return *p; 127 128 /* Otherwise, convert the letter to upper case */ 129 *p = toupper(*p); 130 131 /* And make sure it's a valid letter */ 132 if ((*p >= 'A') && (*p <='Z')) return *p; 133 134 /* Otherwise, fail */ 135 return -1; 136 } 137 138 /* Otherwise, scan our virtual key names */ 139 for (i = 0; i < 36; i++) 140 { 141 /* Check if we have a match */ 142 if (!strcmp(VKName[i].Name, p)) return VKName[i].VirtualKey; 143 } 144 145 /* Check if this is a hex string */ 146 if ((*p == '0') && ((*(p + 1) == 'x') || (*(p + 1) == 'X'))) 147 { 148 /* Get the key number from the hex string */ 149 *(p + 1) = 'x'; 150 if (sscanf(p, "0x%x", &KeyNumber) == 1) return KeyNumber; 151 } 152 153 /* No hope: fail */ 154 return -1; 155 } 156 157 UCHAR 158 getCharacterInfo(IN PCHAR State, 159 OUT PULONG EntryChar, 160 OUT PCHAR LigatureChar) 161 { 162 ULONG Length; 163 ULONG CharInfo = CHAR_NORMAL_KEY; 164 UCHAR StateChar; 165 ULONG CharCode; 166 167 /* Calculate the length of the state */ 168 Length = strlen(State); 169 170 /* Check if this is at least a simple key state */ 171 if (Length > 1) 172 { 173 /* Read the first character and check if it's a dead key */ 174 StateChar = State[Length - 1]; 175 if (StateChar == '@') 176 { 177 /* This is a dead key */ 178 CharInfo = CHAR_DEAD_KEY; 179 } 180 else if (StateChar == '%') 181 { 182 /* This is another key */ 183 CharInfo = CHAR_OTHER_KEY; 184 } 185 } 186 187 /* Check if this is a numerical key state */ 188 if ((Length - 1) >= 2) 189 { 190 /* Scan for extended character code entry */ 191 if ((sscanf(State, "%6x", &CharCode) == 1) && 192 (((Length == 5) && (State[0] == '0')) || 193 ((Length == 6) && ((State[0] == '0') && (State[1] == '0'))))) 194 { 195 /* Handle a ligature key */ 196 CharInfo = CHAR_LIGATURE_KEY; 197 198 /* Not yet handled */ 199 printf("Ligatured character entries not yet supported!\n"); 200 exit(1); 201 } 202 else 203 { 204 /* Get the normal character entry */ 205 if (sscanf(State, "%4x", &CharCode) == 1) 206 { 207 /* Does the caller want the key? */ 208 if (EntryChar) *EntryChar = CharCode; 209 } 210 else 211 { 212 /* The entry is totally invalid */ 213 if (Verbose) printf("An unparseable character entry '%s' was found.\n", State); 214 if (EntryChar) *EntryChar = 0; 215 CharInfo = CHAR_INVALID_KEY; 216 } 217 } 218 } 219 else 220 { 221 /* Save the key if the caller requested it */ 222 if (EntryChar) *EntryChar = *State; 223 } 224 225 /* Return the type of character this is */ 226 return CharInfo; 227 } 228 229 BOOLEAN 230 NextLine(PCHAR LineBuffer, 231 ULONG BufferSize, 232 FILE *File) 233 { 234 PCHAR p, pp; 235 236 /* Scan each line */ 237 while (fgets(LineBuffer, BufferSize, File)) 238 { 239 /* Remember it */ 240 gLineCount++; 241 242 /* Reset the pointer at the beginning of the line */ 243 p = LineBuffer; 244 245 /* Now bypass all whitespace (and tabspace) */ 246 while ((*p) && ((*p == ' ') || (*p == '\t'))) p++; 247 248 /* If this is an old-style comment, skip the line */ 249 if (*p == ';') continue; 250 251 /* Otherwise, check for new-style comment */ 252 pp = strstr(p, "//"); 253 if (pp) 254 { 255 /* We have a comment, so terminate there (unless the whole line is one) */ 256 if (pp == p) continue; 257 *pp = '\0'; 258 } 259 else 260 { 261 /* No comment, so find the new line and terminate there */ 262 p = strchr(p, '\n'); 263 if (p) *p = '\0'; 264 } 265 266 /* We have a line! */ 267 return TRUE; 268 } 269 270 /* No line found */ 271 return FALSE; 272 } 273 274 ULONG 275 SkipLines(VOID) 276 { 277 ULONG KeyWord; 278 CHAR KeyWordChars[32]; 279 280 /* Scan each line, skipping it if it's not a keyword */ 281 while (NextLine(gBuf, sizeof(gBuf), gfpInput)) 282 { 283 /* Read a single word */ 284 if (sscanf(gBuf, "%s", KeyWordChars) == 1) 285 { 286 /* If the word is a keyword, stop skipping lines */ 287 KeyWord = isKeyWord(KeyWordChars); 288 if (KeyWord < KEYWORD_COUNT) return KeyWord; 289 } 290 } 291 292 /* We skipped all the possible lines, not finding anything */ 293 return KEYWORD_COUNT; 294 } 295 296 ULONG 297 DoKBD(VOID) 298 { 299 /* On Unicode files, we need to find the Unicode marker (FEEF) */ 300 ASSERT(UnicodeFile == FALSE); 301 302 /* Initial values */ 303 *gKBDName = '\0'; 304 *gDescription = '\0'; 305 306 /* Scan for the values */ 307 if (sscanf(gBuf, "KBD %8s \"%40[^\"]\" %d", gKBDName, gDescription, &gID) < 2) 308 { 309 /* Couldn't find them */ 310 printf("Unable to read keyboard name or description.\n"); 311 exit(1); 312 } 313 314 /* Debug only */ 315 DPRINT1("KBD Name: [%8s] Description: [%40s] ID: [%d]\n", gKBDName, gDescription, gID); 316 return SkipLines(); 317 } 318 319 ULONG 320 DoVERSION(VOID) 321 { 322 /* Scan for the value */ 323 if (sscanf(gBuf, "VERSION %d", &gKbdLayoutVersion) < 1) 324 { 325 /* Couldn't find them */ 326 printf("Unable to read keyboard version information.\n"); 327 } 328 329 /* Debug only */ 330 DPRINT1("VERSION [%d]\n", gKbdLayoutVersion); 331 return SkipLines(); 332 } 333 334 ULONG 335 DoCOPYRIGHT(VOID) 336 { 337 /* Initial values */ 338 *gCopyright = '\0'; 339 340 /* Scan for the value */ 341 if (sscanf(gBuf, "COPYRIGHT \"%40[^\"]\"", gCopyright) < 1) 342 { 343 /* Couldn't find them */ 344 printf("Unable to read the specified COPYRIGHT string.\n"); 345 } 346 347 /* Debug only */ 348 DPRINT1("COPYRIGHT [%40s]\n", gCopyright); 349 return SkipLines(); 350 } 351 352 ULONG 353 DoCOMPANY(VOID) 354 { 355 /* Initial values */ 356 *gCompany = '\0'; 357 358 /* Scan for the value */ 359 if (sscanf(gBuf, "COMPANY \"%85[^\"]\"", gCompany) < 1) 360 { 361 /* Couldn't find them */ 362 printf("Unable to read the specified COMPANY name.\n"); 363 } 364 365 /* Debug only */ 366 DPRINT1("COMPANY [%85s]\n", gCompany); 367 return SkipLines(); 368 } 369 370 ULONG 371 DoLOCALENAME(VOID) 372 { 373 /* Initial values */ 374 *gLocaleName = '\0'; 375 376 /* Scan for the value */ 377 if (sscanf(gBuf, "LOCALENAME \"%40[^\"]\"", gLocaleName) < 1) 378 { 379 /* Couldn't find them */ 380 printf("Unable to read the specified COPYRIGHT string.\n"); 381 } 382 383 /* Debug only */ 384 DPRINT1("LOCALENAME [%40s]\n", gLocaleName); 385 return SkipLines(); 386 } 387 388 ULONG 389 DoDESCRIPTIONS(IN PKEYNAME* DescriptionData) 390 { 391 ULONG KeyWord = 0; 392 CHAR Token[32]; 393 ULONG LanguageCode; 394 PCHAR p, pp; 395 PKEYNAME Description; 396 397 /* Assume nothing */ 398 *DescriptionData = 0; 399 400 /* Start scanning */ 401 while (NextLine(gBuf, 256, gfpInput)) 402 { 403 /* Search for token */ 404 if (sscanf(gBuf, "%s", Token) != 1) continue; 405 406 /* Make sure it's not just a comment */ 407 if (*Token == ';') continue; 408 409 /* Make sure it's not a keyword */ 410 KeyWord = isKeyWord(Token); 411 if (KeyWord < KEYWORD_COUNT) break; 412 413 /* Now scan for the language code */ 414 if (sscanf(Token, " %4x", &LanguageCode) != 1) 415 { 416 /* Skip */ 417 printf("An invalid LANGID was specified.\n"); 418 continue; 419 } 420 421 /* Now get the actual description */ 422 if (sscanf(gBuf, " %*4x %s[^\n]", Token) != 1) 423 { 424 /* Skip */ 425 printf("A language description is missing.\n"); 426 continue; 427 } 428 429 /* Get the description string and find the ending */ 430 p = strstr(gBuf, Token); 431 pp = strchr(p, '\n'); 432 if (!pp) pp = strchr(p, '\r'); 433 434 /* Terminate the description string here */ 435 if (pp) *pp = 0; 436 437 /* Now allocate the description */ 438 Description = malloc(sizeof(KEYNAME)); 439 if (!Description) 440 { 441 /* Fail */ 442 printf("Unable to allocate the KEYNAME struct (out of memory?).\n"); 443 exit(1); 444 } 445 446 /* Fill out the structure */ 447 Description->Code = LanguageCode; 448 Description->Name = strdup(p); 449 Description->Next = NULL; 450 451 /* Debug only */ 452 DPRINT1("LANGID: [%4x] Description: [%s]\n", Description->Code, Description->Name); 453 454 /* Point to it and advance the pointer */ 455 *DescriptionData = Description; 456 DescriptionData = &Description->Next; 457 } 458 459 /* We are done */ 460 return KeyWord; 461 } 462 463 ULONG 464 DoLANGUAGENAMES(IN PKEYNAME* LanguageData) 465 { 466 ULONG KeyWord = 0; 467 CHAR Token[32]; 468 ULONG LanguageCode; 469 PCHAR p, pp; 470 PKEYNAME Language; 471 472 /* Assume nothing */ 473 *LanguageData = 0; 474 475 /* Start scanning */ 476 while (NextLine(gBuf, 256, gfpInput)) 477 { 478 /* Search for token */ 479 if (sscanf(gBuf, "%s", Token) != 1) continue; 480 481 /* Make sure it's not just a comment */ 482 if (*Token == ';') continue; 483 484 /* Make sure it's not a keyword */ 485 KeyWord = isKeyWord(Token); 486 if (KeyWord < KEYWORD_COUNT) break; 487 488 /* Now scan for the language code */ 489 if (sscanf(Token, " %4x", &LanguageCode) != 1) 490 { 491 /* Skip */ 492 printf("An invalid LANGID was specified.\n"); 493 continue; 494 } 495 496 /* Now get the actual language */ 497 if (sscanf(gBuf, " %*4x %s[^\n]", Token) != 1) 498 { 499 /* Skip */ 500 printf("A language name is missing\n"); 501 continue; 502 } 503 504 /* Get the language string and find the ending */ 505 p = strstr(gBuf, Token); 506 pp = strchr(p, '\n'); 507 if (!pp) pp = strchr(p, '\r'); 508 509 /* Terminate the language string here */ 510 if (pp) *pp = 0; 511 512 /* Now allocate the language */ 513 Language = malloc(sizeof(KEYNAME)); 514 if (!Language) 515 { 516 /* Fail */ 517 printf("Unable to allocate the KEYNAME struct (out of memory?).\n"); 518 exit(1); 519 } 520 521 /* Fill out the structure */ 522 Language->Code = LanguageCode; 523 Language->Name = strdup(p); 524 Language->Next = NULL; 525 526 /* Debug only */ 527 DPRINT1("LANGID: [%4x] Name: [%s]\n", Language->Code, Language->Name); 528 529 /* Point to it and advance the pointer */ 530 *LanguageData = Language; 531 LanguageData = &Language->Next; 532 } 533 534 /* We are done */ 535 return KeyWord; 536 } 537 538 ULONG 539 DoKEYNAME(IN PKEYNAME* KeyNameData) 540 { 541 ULONG KeyWord = 0; 542 CHAR Token[32]; 543 ULONG CharacterCode; 544 PCHAR p, pp; 545 PKEYNAME KeyName; 546 547 /* Assume nothing */ 548 *KeyNameData = 0; 549 550 /* Start scanning */ 551 while (NextLine(gBuf, 256, gfpInput)) 552 { 553 /* Search for token */ 554 if (sscanf(gBuf, "%s", Token) != 1) continue; 555 556 /* Make sure it's not just a comment */ 557 if (*Token == ';') continue; 558 559 /* Make sure it's not a keyword */ 560 KeyWord = isKeyWord(Token); 561 if (KeyWord < KEYWORD_COUNT) break; 562 563 /* Now scan for the character code */ 564 if (sscanf(Token, " %4x", &CharacterCode) != 1) 565 { 566 /* Skip */ 567 printf("An invalid character code was specified.\n"); 568 continue; 569 } 570 571 /* Now get the actual key name */ 572 if (sscanf(gBuf, " %*4x %s[^\n]", Token) != 1) 573 { 574 /* Skip */ 575 printf("A key name is missing\n"); 576 continue; 577 } 578 579 /* Get the key name string and find the ending */ 580 p = strstr(gBuf, Token); 581 pp = strchr(p, '\n'); 582 if (!pp) pp = strchr(p, '\r'); 583 584 /* Terminate the key name string here */ 585 if (pp) *pp = 0; 586 587 /* Now allocate the language */ 588 KeyName = malloc(sizeof(KEYNAME)); 589 if (!KeyName) 590 { 591 /* Fail */ 592 printf("Unable to allocate the KEYNAME struct (out of memory?).\n"); 593 exit(1); 594 } 595 596 /* Fill out the structure */ 597 KeyName->Code = CharacterCode; 598 KeyName->Name = strdup(p); 599 KeyName->Next = NULL; 600 601 /* Debug only */ 602 DPRINT1("CHARCODE: [%4x] Name: [%s]\n", KeyName->Code, KeyName->Name); 603 604 /* Point to it and advance the pointer */ 605 *KeyNameData = KeyName; 606 KeyNameData = &KeyName->Next; 607 } 608 609 /* We are done */ 610 return KeyWord; 611 } 612 613 ULONG 614 DoSHIFTSTATE(IN PULONG StateCount, 615 IN OUT PULONG ShiftStates) 616 { 617 ULONG KeyWord; 618 ULONG i; 619 ULONG ShiftState; 620 CHAR Token[32]; 621 622 /* Reset the shift states */ 623 for (i = 0; i < 8; i++) ShiftStates[i] = -1; 624 625 /* Start with no states */ 626 *StateCount = 0; 627 628 /* Scan for shift states */ 629 while (NextLine(gBuf, 256, gfpInput)) 630 { 631 /* Search for token */ 632 if (sscanf(gBuf, "%s", Token) != 1) continue; 633 634 /* Make sure it's not a keyword */ 635 KeyWord = isKeyWord(Token); 636 if (KeyWord < KEYWORD_COUNT) break; 637 638 /* Now scan for the shift state */ 639 if (sscanf(gBuf, " %1s[012367]", Token) != 1) 640 { 641 /* We failed -- should we warn? */ 642 if (Verbose) printf("An invalid shift state '%s' was found (use 0, 1, 2, 3, 6, or 7.)\n", Token); 643 continue; 644 } 645 646 /* Now read the state */ 647 ShiftState = atoi(Token); 648 649 /* Scan existing states */ 650 for (i = 0; i < *StateCount; i++) 651 { 652 /* Check for duplicate */ 653 if ((ShiftStates[i] == ShiftState) && (Verbose)) 654 { 655 /* Warn user */ 656 printf("The state '%d' was duplicated for this Virtual Key.\n", ShiftStates[i]); 657 break; 658 } 659 } 660 661 /* Make sure we won't overflow */ 662 if (*StateCount < 8) 663 { 664 /* Save this state */ 665 ShiftStates[(*StateCount)++] = ShiftState; 666 } 667 else 668 { 669 /* Too many states -- should we warn? */ 670 if (Verbose) printf("There were too many states (you defined %d).\n", *StateCount); 671 } 672 } 673 674 /* Debug only */ 675 DPRINT1("Found %d Shift States: [", *StateCount); 676 for (i = 0; i < *StateCount; i++) DPRINT1("%d ", ShiftStates[i]); 677 DPRINT1("]\n"); 678 679 /* We are done */ 680 return KeyWord; 681 } 682 683 ULONG 684 DoLIGATURE(PVOID LigatureData) 685 { 686 printf("LIGATURE support is not yet implemented. Please bug Arch to fix it\n"); 687 return SkipLines(); 688 } 689 690 ULONG 691 DoATTRIBUTES(PVOID AttributeData) 692 { 693 printf("ATTRIBUTES support is not yet implemented. Please bug Arch to fix it\n"); 694 return SkipLines(); 695 } 696 697 ULONG 698 DoMODIFIERS(VOID) 699 { 700 printf("MODIFIERS support is not yet implemented. Please bug Arch to fix it\n"); 701 return SkipLines(); 702 } 703 704 ULONG 705 DoDEADKEY(PVOID DeadKeyData) 706 { 707 printf("DEADKEY support is not yet implemented. Please bug Arch to fix it\n"); 708 return SkipLines(); 709 } 710 711 ULONG 712 DoLAYOUT(IN PLAYOUT LayoutData, 713 IN PVOID LigatureData, 714 IN PULONG ShiftStates, 715 IN ULONG StateCount) 716 { 717 CHAR Token[32]; 718 CHAR Cap[8]; 719 ULONG KeyWord; 720 ULONG ScanCode, CurrentCode; 721 ULONG TokenCount; 722 ULONG VirtualKey; 723 ULONG i; 724 ULONG Count; 725 BOOLEAN FullEntry; 726 CHAR State[8][8]; 727 ULONG ScanCodeCount = -1; 728 PLAYOUTENTRY Entry; 729 UCHAR CharacterType; 730 CHAR LigatureChar; 731 732 /* Zero out the layout */ 733 memset(LayoutData, 0, sizeof(LAYOUT)); 734 735 /* Read each line */ 736 Entry = &LayoutData->Entry[0]; 737 while (NextLine(gBuf, 256, gfpInput)) 738 { 739 /* Search for token */ 740 if (sscanf(gBuf, "%s", Token) != 1) continue; 741 742 /* Make sure it's not just a comment */ 743 if (*Token == ';') continue; 744 745 /* Make sure it's not a keyword */ 746 KeyWord = isKeyWord(Token); 747 if (KeyWord < KEYWORD_COUNT) break; 748 749 /* Now read the entry */ 750 TokenCount = sscanf(gBuf, " %x %s %s", &ScanCode, Token, Cap); 751 if (TokenCount == 3) 752 { 753 /* Full entry with cap */ 754 FullEntry = TRUE; 755 } 756 else if (TokenCount != 2) 757 { 758 /* Fail, invalid LAYOUT entry */ 759 printf("There are not enough columns in the layout list.\n"); 760 exit(1); 761 } 762 else 763 { 764 /* Simplified layout with no cap */ 765 FullEntry = FALSE; 766 } 767 768 /* One more */ 769 DPRINT1("RAW ENTRY: [%x %s %s]\n", ScanCode, Token, Cap); 770 Entry++; 771 if (++ScanCodeCount >= 110) 772 { 773 /* Too many! */ 774 printf("ScanCode %02x - too many scancodes here to parse.\n", ScanCode); 775 exit(1); 776 } 777 778 /* Fill out this entry */ 779 Entry->ScanCode = ScanCode; 780 Entry->LineCount = gLineCount; 781 782 /* Loop scancode table */ 783 for (i = 0; i < 110; i++) 784 { 785 /* Get the current code */ 786 CurrentCode = ScVk[i].ScanCode; 787 if (CurrentCode == 0xFFFF) 788 { 789 /* New code */ 790 if (Verbose) printf("A new scancode is being defined: 0x%2X, %s\n", Entry->ScanCode, Token); 791 792 /* Fill out the entry */ 793 Entry->VirtualKey = getVKNum(Token); 794 break; 795 } 796 else if (ScanCode == CurrentCode) 797 { 798 /* Make sure we didn't already process it */ 799 if (ScVk[i].Processed) 800 { 801 /* Fail */ 802 printf("Scancode %X was previously defined.\n", ScanCode); 803 exit(1); 804 } 805 806 /* Check if there is a valid virtual key */ 807 if (ScVk[i].VirtualKey == 0xFFFF) 808 { 809 /* Fail */ 810 printf("The Scancode you tried to use (%X) is reserved.\n", ScanCode); 811 exit(1); 812 } 813 814 /* Fill out the entry */ 815 Entry->OriginalVirtualKey = ScVk[i].VirtualKey; 816 Entry->Name = ScVk[i].Name; 817 break; 818 } 819 } 820 821 /* The entry is now processed */ 822 Entry->Processed = TRUE; 823 ScVk[i].Processed = TRUE; 824 825 /* Get the virtual key from the entry */ 826 VirtualKey = getVKNum(Token); 827 Entry->VirtualKey = VirtualKey; 828 DPRINT1("ENTRY: [%x %x %x %s] with ", 829 Entry->VirtualKey, Entry->OriginalVirtualKey, Entry->ScanCode, Entry->Name); 830 831 /* Make sure it's valid */ 832 if (VirtualKey == 0xFFFF) 833 { 834 /* Warn the user */ 835 if (Verbose) printf("An invalid Virtual Key '%s' was defined.\n", Token); 836 continue; 837 } 838 839 /* Is this a full entry */ 840 if (FullEntry) 841 { 842 /* Do we have SGCAP data? Set cap mode to 2 */ 843 if (!strcmp(Cap, "SGCAP")) *Cap = '2'; 844 845 /* Read the cap mode */ 846 if (sscanf(Cap, "%1d[012]", &Entry->Cap) != 1) 847 { 848 /* Invalid cap mode */ 849 printf("invalid Cap specified (%s). Must be 0, 1, or 2.\n", Cap); 850 exit(1); 851 } 852 } 853 854 /* Read the states */ 855 Count = sscanf(gBuf, 856 " %*s %*s %*s %s %s %s %s %s %s %s %s", 857 State[0], 858 State[1], 859 State[2], 860 State[3], 861 State[4], 862 State[5], 863 State[6], 864 State[7]); 865 Entry->StateCount = Count; 866 DPRINT1("%d STATES: [", Count); 867 868 /* Check if there are less than 2 states */ 869 if ((Count < 2) && (FullEntry)) 870 { 871 /* Fail */ 872 printf("You must have at least 2 characters.\n"); 873 exit(1); 874 } 875 876 /* Loop all states */ 877 for (i = 0; i < Count; i++) 878 { 879 /* Check if this is an undefined state */ 880 DPRINT1("%s ", State[i]); 881 if (!strcmp(State[i], "-1")) 882 { 883 /* No data for this state */ 884 Entry->CharData[i] = -1; 885 continue; 886 } 887 888 /* Otherwise, check what kind of character this is */ 889 CharacterType = getCharacterInfo(State[i], 890 &Entry->CharData[i], 891 &LigatureChar); 892 if (CharacterType == CHAR_DEAD_KEY) 893 { 894 /* Save it as such */ 895 Entry->DeadCharData[i] = 1; 896 } 897 else if (CharacterType == CHAR_OTHER_KEY) 898 { 899 /* Save it as such */ 900 Entry->OtherCharData[i] = 1; 901 } 902 } 903 904 /* Check for sanity checks */ 905 DPRINT1("]\n"); 906 if (SanityCheck) 907 { 908 /* Not yet handled... */ 909 printf("Sanity checks not yet handled!\n"); 910 exit(1); 911 } 912 913 /* Check if we had SGCAP data */ 914 if (Entry->Cap & 2) 915 { 916 /* Not yet handled... */ 917 printf("SGCAP state not yet handled!\n"); 918 exit(1); 919 } 920 } 921 922 /* Check if we have found any ScanCode in the file */ 923 924 if (ScanCodeCount == -1) 925 { 926 printf("No ScanCode found!\n"); 927 exit(1); 928 } 929 930 /* Process the scan code table */ 931 Entry = &LayoutData->Entry[ScanCodeCount]; 932 for (i = 0; i < 110; i++) 933 { 934 /* Get the scan code */ 935 CurrentCode = ScVk[i].ScanCode; 936 if (CurrentCode == 0xFFFF) break; 937 938 /* Check if this entry had been processed */ 939 if (ScVk[i].Processed) 940 { 941 /* Skip it */ 942 ScVk[i].Processed = FALSE; 943 } 944 else 945 { 946 /* Do we have too many? */ 947 if (++ScanCodeCount >= 110) 948 { 949 /* Fail */ 950 printf("ScanCode %02x - too many scancodes here to parse.\n", CurrentCode); 951 exit(1); 952 } 953 954 /* Build an entry for it */ 955 Entry++; 956 Entry->ScanCode = CurrentCode; 957 Entry->VirtualKey = ScVk[i].VirtualKey; 958 Entry->OriginalVirtualKey = ScVk[i].VirtualKey; 959 Entry->Name = ScVk[i].Name; 960 Entry->Processed = TRUE; 961 Entry->LineCount = 0; 962 DPRINT1("AUTOMATIC ENTRY: [%x %x %s]\n", 963 Entry->VirtualKey, Entry->ScanCode, Entry->Name); 964 } 965 } 966 967 /* Skip what's left */ 968 return KeyWord; 969 } 970 971 ULONG 972 DoParsing(VOID) 973 { 974 ULONG KeyWords[KEYWORD_COUNT]; 975 ULONG KeyWord; 976 ULONG StateCount; 977 ULONG ShiftStates[8]; 978 PKEYNAME DescriptionData = NULL, LanguageData = NULL; 979 PKEYNAME KeyNameData = NULL, KeyNameExtData = NULL, KeyNameDeadData = NULL; 980 PVOID AttributeData = NULL, LigatureData = NULL, DeadKeyData = NULL; 981 982 /* Parse keywords */ 983 gLineCount = 0; 984 KeyWord = SkipLines(); 985 if (KeyWord >= KEYWORD_COUNT) 986 { 987 /* Invalid keyword count, fail */ 988 fclose(gfpInput); 989 printf("No keywords were found in '%s'.\n", gpszFileName); 990 exit(1); 991 } 992 993 /* Now parse the keywords */ 994 memset(KeyWords, 0, sizeof(KeyWords)); 995 while (KeyWord < (KEYWORD_COUNT - 1)) 996 { 997 /* Save this keyword */ 998 KeyWords[KeyWord]++; 999 1000 /* Check for duplicate entires, other than DEADKEY, which is okay */ 1001 if ((KeyWord != 9) && (KeyWords[KeyWord] > 1) && (Verbose)) 1002 { 1003 /* On a verbose run, warn the user */ 1004 printf("The '%s' keyword appeared multiple times.\n", 1005 KeyWordList[KeyWord]); 1006 } 1007 1008 /* Now parse this keyword */ 1009 switch (KeyWord) 1010 { 1011 /* KBD */ 1012 case 0: 1013 1014 DPRINT1("Found KBD section\n"); 1015 KeyWord = DoKBD(); 1016 break; 1017 1018 /* VERSION */ 1019 case 1: 1020 1021 DPRINT1("Found VERSION section\n"); 1022 KeyWord = DoVERSION(); 1023 break; 1024 1025 /* COPYRIGHT */ 1026 case 2: 1027 1028 DPRINT1("Found COPYRIGHT section\n"); 1029 KeyWord = DoCOPYRIGHT(); 1030 break; 1031 1032 /* COMPANY */ 1033 case 3: 1034 1035 DPRINT1("Found COMPANY section\n"); 1036 KeyWord = DoCOMPANY(); 1037 break; 1038 1039 /* LOCALENAME */ 1040 case 4: 1041 1042 DPRINT1("Found LOCALENAME section\n"); 1043 KeyWord = DoLOCALENAME(); 1044 break; 1045 1046 /* MODIFIERS */ 1047 case 5: 1048 1049 DPRINT1("Found MODIFIERS section\n"); 1050 KeyWord = DoMODIFIERS(); 1051 break; 1052 1053 /* SHIFTSTATE */ 1054 case 6: 1055 1056 DPRINT1("Found SHIFTSTATE section\n"); 1057 KeyWord = DoSHIFTSTATE(&StateCount, ShiftStates); 1058 if (StateCount < 2) 1059 { 1060 /* Fail */ 1061 fclose(gfpInput); 1062 printf("ERROR"); 1063 exit(1); 1064 } 1065 break; 1066 1067 /* ATTRIBUTES */ 1068 case 7: 1069 1070 DPRINT1("Found ATTRIBUTES section\n"); 1071 KeyWord = DoATTRIBUTES(&AttributeData); 1072 break; 1073 1074 /* LAYOUT */ 1075 case 8: 1076 1077 DPRINT1("Found LAYOUT section\n"); 1078 KeyWord = DoLAYOUT(&g_Layout, 1079 &LigatureData, 1080 ShiftStates, 1081 StateCount); 1082 break; 1083 1084 /* DEADKEY */ 1085 case 9: 1086 1087 DPRINT1("Found DEADKEY section\n"); 1088 KeyWord = DoDEADKEY(&DeadKeyData); 1089 break; 1090 1091 /* LIGATURE */ 1092 case 10: 1093 1094 DPRINT1("Found LIGATURE section\n"); 1095 KeyWord = DoLIGATURE(&LigatureData); 1096 break; 1097 1098 /* KEYNAME */ 1099 case 11: 1100 1101 DPRINT1("Found KEYNAME section\n"); 1102 KeyWord = DoKEYNAME(&KeyNameData); 1103 break; 1104 1105 /* KEYNAME_EXT */ 1106 case 12: 1107 1108 DPRINT1("Found KEYNAME_EXT section\n"); 1109 KeyWord = DoKEYNAME(&KeyNameExtData); 1110 break; 1111 1112 /* KEYNAME_DEAD */ 1113 case 13: 1114 1115 DPRINT1("Found KEYNAME_DEAD section\n"); 1116 KeyWord = DoKEYNAME(&KeyNameDeadData); 1117 break; 1118 1119 /* DESCRIPTIONS */ 1120 case 14: 1121 1122 DPRINT1("Found DESCRIPTIONS section\n"); 1123 KeyWord = DoDESCRIPTIONS(&DescriptionData); 1124 break; 1125 1126 /* LANGUAGENAMES */ 1127 case 15: 1128 1129 DPRINT1("Found LANGUAGENAMES section\n"); 1130 KeyWord = DoLANGUAGENAMES(&LanguageData); 1131 break; 1132 1133 /* ENDKBD */ 1134 case 16: 1135 1136 DPRINT1("Found ENDKBD section\n"); 1137 KeyWord = SkipLines(); 1138 break; 1139 1140 1141 default: 1142 break; 1143 } 1144 } 1145 1146 /* We are done */ 1147 fclose(gfpInput); 1148 1149 /* Now enter the output phase */ 1150 return DoOutput(StateCount, 1151 ShiftStates, 1152 DescriptionData, 1153 LanguageData, 1154 AttributeData, 1155 DeadKeyData, 1156 LigatureData, 1157 KeyNameData, 1158 KeyNameExtData, 1159 KeyNameDeadData); 1160 } 1161 /* EOF */ 1162