xref: /reactos/sdk/tools/kbdtool/parser.c (revision 34593d93)
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
isKeyWord(PCHAR p)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
getVKName(IN ULONG VirtualKey,IN BOOLEAN Prefix)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
getVKNum(IN PCHAR p)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
getCharacterInfo(IN PCHAR State,OUT PULONG EntryChar,OUT PCHAR LigatureChar)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
NextLine(PCHAR LineBuffer,ULONG BufferSize,FILE * File)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
SkipLines(VOID)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
DoKBD(VOID)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
DoVERSION(VOID)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
DoCOPYRIGHT(VOID)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
DoCOMPANY(VOID)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
DoLOCALENAME(VOID)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
DoDESCRIPTIONS(IN PKEYNAME * DescriptionData)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
DoLANGUAGENAMES(IN PKEYNAME * LanguageData)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
DoKEYNAME(IN PKEYNAME * KeyNameData)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
DoSHIFTSTATE(IN PULONG StateCount,IN OUT PULONG ShiftStates)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
DoLIGATURE(PVOID LigatureData)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
DoATTRIBUTES(PVOID AttributeData)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
DoMODIFIERS(VOID)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
DoDEADKEY(PVOID DeadKeyData)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
DoLAYOUT(IN PLAYOUT LayoutData,IN PVOID LigatureData,IN PULONG ShiftStates,IN ULONG StateCount)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
DoParsing(VOID)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