[KBDTOOL]
[reactos.git] / reactos / tools / kbdtool / parser.c
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, LigatureChar;
730
731 /* Zero out the layout */
732 memset(LayoutData, 0, sizeof(LAYOUT));
733
734 /* Read each line */
735 Entry = &LayoutData->Entry[0];
736 while (NextLine(gBuf, 256, gfpInput))
737 {
738 /* Search for token */
739 if (sscanf(gBuf, "%s", Token) != 1) continue;
740
741 /* Make sure it's not just a comment */
742 if (*Token == ';') continue;
743
744 /* Make sure it's not a keyword */
745 KeyWord = isKeyWord(Token);
746 if (KeyWord < KEYWORD_COUNT) break;
747
748 /* Now read the entry */
749 TokenCount = sscanf(gBuf, " %x %s %s", &ScanCode, Token, Cap);
750 if (TokenCount == 3)
751 {
752 /* Full entry with cap */
753 FullEntry = TRUE;
754 }
755 else if (TokenCount != 2)
756 {
757 /* Fail, invalid LAYOUT entry */
758 printf("There are not enough columns in the layout list.\n");
759 exit(1);
760 }
761 else
762 {
763 /* Simplified layout with no cap */
764 FullEntry = FALSE;
765 }
766
767 /* One more */
768 DPRINT1("RAW ENTRY: [%x %s %s]\n", ScanCode, Token, Cap);
769 Entry++;
770 if (++ScanCodeCount >= 110)
771 {
772 /* Too many! */
773 printf("ScanCode %02x - too many scancodes here to parse.\n", ScanCode);
774 exit(1);
775 }
776
777 /* Fill out this entry */
778 Entry->ScanCode = ScanCode;
779 Entry->LineCount = gLineCount;
780
781 /* Loop scancode table */
782 for (i = 0; i < 110; i++)
783 {
784 /* Get the current code */
785 CurrentCode = ScVk[i].ScanCode;
786 if (CurrentCode == 0xFFFF)
787 {
788 /* New code */
789 if (Verbose) printf("A new scancode is being defined: 0x%2X, %s\n", Entry->ScanCode, Token);
790
791 /* Fill out the entry */
792 Entry->VirtualKey = getVKNum(Token);
793 break;
794 }
795 else if (ScanCode == CurrentCode)
796 {
797 /* Make sure we didn't already process it */
798 if (ScVk[i].Processed)
799 {
800 /* Fail */
801 printf("Scancode %X was previously defined.\n", ScanCode);
802 exit(1);
803 }
804
805 /* Check if there is a valid virtual key */
806 if (ScVk[i].VirtualKey == 0xFFFF)
807 {
808 /* Fail */
809 printf("The Scancode you tried to use (%X) is reserved.\n", ScanCode);
810 exit(1);
811 }
812
813 /* Fill out the entry */
814 Entry->OriginalVirtualKey = ScVk[i].VirtualKey;
815 Entry->Name = ScVk[i].Name;
816 break;
817 }
818 }
819
820 /* The entry is now processed */
821 Entry->Processed = TRUE;
822 ScVk[i].Processed = TRUE;
823
824 /* Get the virtual key from the entry */
825 VirtualKey = getVKNum(Token);
826 Entry->VirtualKey = VirtualKey;
827 DPRINT1("ENTRY: [%x %x %x %s] with ",
828 Entry->VirtualKey, Entry->OriginalVirtualKey, Entry->ScanCode, Entry->Name);
829
830 /* Make sure it's valid */
831 if (VirtualKey == 0xFFFF)
832 {
833 /* Warn the user */
834 if (Verbose) printf("An invalid Virtual Key '%s' was defined.\n", Token);
835 continue;
836 }
837
838 /* Is this a full entry */
839 if (FullEntry)
840 {
841 /* Do we have SGCAP data? Set cap mode to 2 */
842 if (!strcmp(Cap, "SGCAP")) *Cap = '2';
843
844 /* Read the cap mode */
845 if (sscanf(Cap, "%1d[012]", &Entry->Cap) != 1)
846 {
847 /* Invalid cap mode */
848 printf("invalid Cap specified (%s). Must be 0, 1, or 2.\n", Cap);
849 exit(1);
850 }
851 }
852
853 /* Read the states */
854 Count = sscanf(gBuf,
855 " %*s %*s %*s %s %s %s %s %s %s %s %s",
856 State[0],
857 State[1],
858 State[2],
859 State[3],
860 State[4],
861 State[5],
862 State[6],
863 State[7]);
864 Entry->StateCount = Count;
865 DPRINT1("%d STATES: [", Count);
866
867 /* Check if there are less than 2 states */
868 if ((Count < 2) && (FullEntry))
869 {
870 /* Fail */
871 printf("You must have at least 2 characters.\n");
872 exit(1);
873 }
874
875 /* Loop all states */
876 for (i = 0; i < Count; i++)
877 {
878 /* Check if this is an undefined state */
879 DPRINT1("%s ", State[i]);
880 if (!strcmp(State[i], "-1"))
881 {
882 /* No data for this state */
883 Entry->CharData[i] = -1;
884 continue;
885 }
886
887 /* Otherwise, check what kind of character this is */
888 CharacterType = getCharacterInfo(State[i],
889 &Entry->CharData[i],
890 &LigatureChar);
891 if (CharacterType == CHAR_DEAD_KEY)
892 {
893 /* Save it as such */
894 Entry->DeadCharData[i] = 1;
895 }
896 else if (CharacterType == CHAR_OTHER_KEY)
897 {
898 /* Save it as such */
899 Entry->OtherCharData[i] = 1;
900 }
901 }
902
903 /* Check for sanity checks */
904 DPRINT1("]\n");
905 if (SanityCheck)
906 {
907 /* Not yet handled... */
908 printf("Sanity checks not yet handled!\n");
909 exit(1);
910 }
911
912 /* Check if we had SGCAP data */
913 if (Entry->Cap & 2)
914 {
915 /* Not yet handled... */
916 printf("SGCAP state not yet handled!\n");
917 exit(1);
918 }
919 }
920
921 /* Process the scan code table */
922 Entry = &LayoutData->Entry[ScanCodeCount];
923 for (i = 0; i < 110; i++)
924 {
925 /* Get the scan code */
926 CurrentCode = ScVk[i].ScanCode;
927 if (CurrentCode == 0xFFFF) break;
928
929 /* Check if this entry had been processed */
930 if (ScVk[i].Processed)
931 {
932 /* Skip it */
933 ScVk[i].Processed = FALSE;
934 }
935 else
936 {
937 /* Do we have too many? */
938 if (++ScanCodeCount >= 110)
939 {
940 /* Fail */
941 printf("ScanCode %02x - too many scancodes here to parse.\n", CurrentCode);
942 exit(1);
943 }
944
945 /* Build an entry for it */
946 Entry++;
947 Entry->ScanCode = CurrentCode;
948 Entry->VirtualKey = ScVk[i].VirtualKey;
949 Entry->OriginalVirtualKey = ScVk[i].VirtualKey;
950 Entry->Name = ScVk[i].Name;
951 Entry->Processed = TRUE;
952 Entry->LineCount = 0;
953 DPRINT1("AUTOMATIC ENTRY: [%x %x %s]\n",
954 Entry->VirtualKey, Entry->ScanCode, Entry->Name);
955 }
956 }
957
958 /* Skip what's left */
959 return KeyWord;
960 }
961
962 ULONG
963 DoParsing(VOID)
964 {
965 ULONG KeyWords[KEYWORD_COUNT];
966 ULONG KeyWord;
967 ULONG StateCount;
968 ULONG ShiftStates[8];
969 PKEYNAME DescriptionData = NULL, LanguageData = NULL;
970 PKEYNAME KeyNameData = NULL, KeyNameExtData = NULL, KeyNameDeadData = NULL;
971 PVOID AttributeData = NULL, LigatureData = NULL, DeadKeyData = NULL;
972
973 /* Parse keywords */
974 gLineCount = 0;
975 KeyWord = SkipLines();
976 if (KeyWord >= KEYWORD_COUNT)
977 {
978 /* Invalid keyword count, fail */
979 fclose(gfpInput);
980 printf("No keywords were found in '%s'.\n", gpszFileName);
981 exit(1);
982 }
983
984 /* Now parse the keywords */
985 memset(KeyWords, 0, sizeof(KeyWords));
986 while (KeyWord < (KEYWORD_COUNT - 1))
987 {
988 /* Save this keyword */
989 KeyWords[KeyWord]++;
990
991 /* Check for duplicate entires, other than DEADKEY, which is okay */
992 if ((KeyWord != 9) && (KeyWords[KeyWord] > 1) && (Verbose))
993 {
994 /* On a verbose run, warn the user */
995 printf("The '%s' keyword appeared multiple times.\n",
996 KeyWordList[KeyWord]);
997 }
998
999 /* Now parse this keyword */
1000 switch (KeyWord)
1001 {
1002 /* KBD */
1003 case 0:
1004
1005 DPRINT1("Found KBD section\n");
1006 KeyWord = DoKBD();
1007 break;
1008
1009 /* VERSION */
1010 case 1:
1011
1012 DPRINT1("Found VERSION section\n");
1013 KeyWord = DoVERSION();
1014 break;
1015
1016 /* COPYRIGHT */
1017 case 2:
1018
1019 DPRINT1("Found COPYRIGHT section\n");
1020 KeyWord = DoCOPYRIGHT();
1021 break;
1022
1023 /* COMPANY */
1024 case 3:
1025
1026 DPRINT1("Found COMPANY section\n");
1027 KeyWord = DoCOMPANY();
1028 break;
1029
1030 /* LOCALENAME */
1031 case 4:
1032
1033 DPRINT1("Found LOCALENAME section\n");
1034 KeyWord = DoLOCALENAME();
1035 break;
1036
1037 /* MODIFIERS */
1038 case 5:
1039
1040 DPRINT1("Found MODIFIERS section\n");
1041 KeyWord = DoMODIFIERS();
1042 break;
1043
1044 /* SHIFTSTATE */
1045 case 6:
1046
1047 DPRINT1("Found SHIFTSTATE section\n");
1048 KeyWord = DoSHIFTSTATE(&StateCount, ShiftStates);
1049 if (StateCount < 2)
1050 {
1051 /* Fail */
1052 fclose(gfpInput);
1053 printf("ERROR");
1054 exit(1);
1055 }
1056 break;
1057
1058 /* ATTRIBUTES */
1059 case 7:
1060
1061 DPRINT1("Found ATTRIBUTES section\n");
1062 KeyWord = DoATTRIBUTES(&AttributeData);
1063 break;
1064
1065 /* LAYOUT */
1066 case 8:
1067
1068 DPRINT1("Found LAYOUT section\n");
1069 KeyWord = DoLAYOUT(&g_Layout,
1070 &LigatureData,
1071 ShiftStates,
1072 StateCount);
1073 break;
1074
1075 /* DEADKEY */
1076 case 9:
1077
1078 DPRINT1("Found DEADKEY section\n");
1079 KeyWord = DoDEADKEY(&DeadKeyData);
1080 break;
1081
1082 /* LIGATURE */
1083 case 10:
1084
1085 DPRINT1("Found LIGATURE section\n");
1086 KeyWord = DoLIGATURE(&LigatureData);
1087 break;
1088
1089 /* KEYNAME */
1090 case 11:
1091
1092 DPRINT1("Found KEYNAME section\n");
1093 KeyWord = DoKEYNAME(&KeyNameData);
1094 break;
1095
1096 /* KEYNAME_EXT */
1097 case 12:
1098
1099 DPRINT1("Found KEYNAME_EXT section\n");
1100 KeyWord = DoKEYNAME(&KeyNameExtData);
1101 break;
1102
1103 /* KEYNAME_DEAD */
1104 case 13:
1105
1106 DPRINT1("Found KEYNAME_DEAD section\n");
1107 KeyWord = DoKEYNAME(&KeyNameDeadData);
1108 break;
1109
1110 /* DESCRIPTIONS */
1111 case 14:
1112
1113 DPRINT1("Found DESCRIPTIONS section\n");
1114 KeyWord = DoDESCRIPTIONS(&DescriptionData);
1115 break;
1116
1117 /* LANGUAGENAMES */
1118 case 15:
1119
1120 DPRINT1("Found LANGUAGENAMES section\n");
1121 KeyWord = DoLANGUAGENAMES(&LanguageData);
1122 break;
1123
1124 /* ENDKBD */
1125 case 16:
1126
1127 DPRINT1("Found ENDKBD section\n");
1128 KeyWord = SkipLines();
1129 break;
1130
1131
1132 default:
1133 break;
1134 }
1135 }
1136
1137 /* We are done */
1138 fclose(gfpInput);
1139
1140 /* Now enter the output phase */
1141 return DoOutput(StateCount,
1142 ShiftStates,
1143 DescriptionData,
1144 LanguageData,
1145 AttributeData,
1146 DeadKeyData,
1147 LigatureData,
1148 KeyNameData,
1149 KeyNameExtData,
1150 KeyNameDeadData);
1151 }
1152 /* EOF */