[MKHIVE] Minor improvements.
[reactos.git] / sdk / 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;
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 */