reactos/sdk/tools/kbdtool/parser.c
2021-06-11 15:33:08 +03:00

1162 lines
30 KiB
C

/*
* PROJECT: ReactOS Build Tools [Keyboard Layout Compiler]
* LICENSE: BSD - See COPYING.BSD in the top level directory
* FILE: tools/kbdtool/parser.c
* PURPOSE: Parsing Logic
* PROGRAMMERS: ReactOS Foundation
*/
/* INCLUDES *******************************************************************/
#include "kbdtool.h"
/* GLOBALS ********************************************************************/
/* Internal parser data about everything that was parsed */
CHAR gBuf[256];
CHAR gKBDName[10];
CHAR gCopyright[256];
CHAR gDescription[256];
CHAR gCompany[256];
CHAR gLocaleName[256];
CHAR gVKeyName[32];
ULONG gID = 0;
ULONG gKbdLayoutVersion;
LAYOUT g_Layout;
ULONG gLineCount;
/* Table of keywords the parser recognizes */
PCHAR KeyWordList[KEYWORD_COUNT] =
{
"KBD",
"VERSION",
"COPYRIGHT",
"COMPANY",
"LOCALENAME",
"MODIIFERS",
"SHIFTSTATE",
"ATTRIBUTES",
"LAYOUT",
"DEADKEY",
"LIGATURE",
"KEYNAME",
"KEYNAME_EXT",
"KEYNAME_DEAD",
"DESCRIPTIONS",
"LANGUAGENAMES",
"ENDKBD",
};
/* FUNCTIONS ******************************************************************/
ULONG
isKeyWord(PCHAR p)
{
ULONG i;
/* Check if we know this keyword */
for (i = 0; i < KEYWORD_COUNT; i++) if (strcmp(KeyWordList[i], p) == 0) break;
/* If we didn't find anything, i will be KEYWORD_COUNT, which is invalid */
return i;
}
PCHAR
getVKName(IN ULONG VirtualKey,
IN BOOLEAN Prefix)
{
ULONG i;
/* Loop for standard virtual key */
if (((VirtualKey >= 'A') && (VirtualKey <= 'Z')) ||
((VirtualKey >= '0') && (VirtualKey <= '9')))
{
/* Fill out the name */
gVKeyName[0] = '\'';
gVKeyName[1] = VirtualKey;
gVKeyName[2] = '\'';
gVKeyName[3] = '\0';
return gVKeyName;
}
/* Check if a prefix is required */
if (Prefix)
{
/* Add it */
strcpy(gVKeyName, "VK_");
}
else
{
/* Otherwise, don't add anything */
strcpy(gVKeyName, "");
}
/* Loop all virtual keys */
for (i = 0; i < 36; i++)
{
/* Check if this key matches */
if (VKName[i].VirtualKey == VirtualKey)
{
/* Copy the key's name into the buffer */
strcat(gVKeyName, VKName[i].Name);
return gVKeyName;
}
}
/* If we got here, then we failed, so print out an error name */
strcpy(gVKeyName, "#ERROR#");
return gVKeyName;
}
ULONG
getVKNum(IN PCHAR p)
{
ULONG Length;
ULONG i;
ULONG KeyNumber;
/* Compute the length of the string */
Length = strlen(p);
if (!Length) return -1;
/* Check if this is is a simple key */
if (Length == 1)
{
/* If it's a number, return it now */
if ((*p >= '0') && (*p <= '9')) return *p;
/* Otherwise, convert the letter to upper case */
*p = toupper(*p);
/* And make sure it's a valid letter */
if ((*p >= 'A') && (*p <='Z')) return *p;
/* Otherwise, fail */
return -1;
}
/* Otherwise, scan our virtual key names */
for (i = 0; i < 36; i++)
{
/* Check if we have a match */
if (!strcmp(VKName[i].Name, p)) return VKName[i].VirtualKey;
}
/* Check if this is a hex string */
if ((*p == '0') && ((*(p + 1) == 'x') || (*(p + 1) == 'X')))
{
/* Get the key number from the hex string */
*(p + 1) = 'x';
if (sscanf(p, "0x%x", &KeyNumber) == 1) return KeyNumber;
}
/* No hope: fail */
return -1;
}
UCHAR
getCharacterInfo(IN PCHAR State,
OUT PULONG EntryChar,
OUT PCHAR LigatureChar)
{
ULONG Length;
ULONG CharInfo = CHAR_NORMAL_KEY;
UCHAR StateChar;
ULONG CharCode;
/* Calculate the length of the state */
Length = strlen(State);
/* Check if this is at least a simple key state */
if (Length > 1)
{
/* Read the first character and check if it's a dead key */
StateChar = State[Length - 1];
if (StateChar == '@')
{
/* This is a dead key */
CharInfo = CHAR_DEAD_KEY;
}
else if (StateChar == '%')
{
/* This is another key */
CharInfo = CHAR_OTHER_KEY;
}
}
/* Check if this is a numerical key state */
if ((Length - 1) >= 2)
{
/* Scan for extended character code entry */
if ((sscanf(State, "%6x", &CharCode) == 1) &&
(((Length == 5) && (State[0] == '0')) ||
((Length == 6) && ((State[0] == '0') && (State[1] == '0')))))
{
/* Handle a ligature key */
CharInfo = CHAR_LIGATURE_KEY;
/* Not yet handled */
printf("Ligatured character entries not yet supported!\n");
exit(1);
}
else
{
/* Get the normal character entry */
if (sscanf(State, "%4x", &CharCode) == 1)
{
/* Does the caller want the key? */
if (EntryChar) *EntryChar = CharCode;
}
else
{
/* The entry is totally invalid */
if (Verbose) printf("An unparseable character entry '%s' was found.\n", State);
if (EntryChar) *EntryChar = 0;
CharInfo = CHAR_INVALID_KEY;
}
}
}
else
{
/* Save the key if the caller requested it */
if (EntryChar) *EntryChar = *State;
}
/* Return the type of character this is */
return CharInfo;
}
BOOLEAN
NextLine(PCHAR LineBuffer,
ULONG BufferSize,
FILE *File)
{
PCHAR p, pp;
/* Scan each line */
while (fgets(LineBuffer, BufferSize, File))
{
/* Remember it */
gLineCount++;
/* Reset the pointer at the beginning of the line */
p = LineBuffer;
/* Now bypass all whitespace (and tabspace) */
while ((*p) && ((*p == ' ') || (*p == '\t'))) p++;
/* If this is an old-style comment, skip the line */
if (*p == ';') continue;
/* Otherwise, check for new-style comment */
pp = strstr(p, "//");
if (pp)
{
/* We have a comment, so terminate there (unless the whole line is one) */
if (pp == p) continue;
*pp = '\0';
}
else
{
/* No comment, so find the new line and terminate there */
p = strchr(p, '\n');
if (p) *p = '\0';
}
/* We have a line! */
return TRUE;
}
/* No line found */
return FALSE;
}
ULONG
SkipLines(VOID)
{
ULONG KeyWord;
CHAR KeyWordChars[32];
/* Scan each line, skipping it if it's not a keyword */
while (NextLine(gBuf, sizeof(gBuf), gfpInput))
{
/* Read a single word */
if (sscanf(gBuf, "%s", KeyWordChars) == 1)
{
/* If the word is a keyword, stop skipping lines */
KeyWord = isKeyWord(KeyWordChars);
if (KeyWord < KEYWORD_COUNT) return KeyWord;
}
}
/* We skipped all the possible lines, not finding anything */
return KEYWORD_COUNT;
}
ULONG
DoKBD(VOID)
{
/* On Unicode files, we need to find the Unicode marker (FEEF) */
ASSERT(UnicodeFile == FALSE);
/* Initial values */
*gKBDName = '\0';
*gDescription = '\0';
/* Scan for the values */
if (sscanf(gBuf, "KBD %8s \"%40[^\"]\" %d", gKBDName, gDescription, &gID) < 2)
{
/* Couldn't find them */
printf("Unable to read keyboard name or description.\n");
exit(1);
}
/* Debug only */
DPRINT1("KBD Name: [%8s] Description: [%40s] ID: [%d]\n", gKBDName, gDescription, gID);
return SkipLines();
}
ULONG
DoVERSION(VOID)
{
/* Scan for the value */
if (sscanf(gBuf, "VERSION %d", &gKbdLayoutVersion) < 1)
{
/* Couldn't find them */
printf("Unable to read keyboard version information.\n");
}
/* Debug only */
DPRINT1("VERSION [%d]\n", gKbdLayoutVersion);
return SkipLines();
}
ULONG
DoCOPYRIGHT(VOID)
{
/* Initial values */
*gCopyright = '\0';
/* Scan for the value */
if (sscanf(gBuf, "COPYRIGHT \"%40[^\"]\"", gCopyright) < 1)
{
/* Couldn't find them */
printf("Unable to read the specified COPYRIGHT string.\n");
}
/* Debug only */
DPRINT1("COPYRIGHT [%40s]\n", gCopyright);
return SkipLines();
}
ULONG
DoCOMPANY(VOID)
{
/* Initial values */
*gCompany = '\0';
/* Scan for the value */
if (sscanf(gBuf, "COMPANY \"%85[^\"]\"", gCompany) < 1)
{
/* Couldn't find them */
printf("Unable to read the specified COMPANY name.\n");
}
/* Debug only */
DPRINT1("COMPANY [%85s]\n", gCompany);
return SkipLines();
}
ULONG
DoLOCALENAME(VOID)
{
/* Initial values */
*gLocaleName = '\0';
/* Scan for the value */
if (sscanf(gBuf, "LOCALENAME \"%40[^\"]\"", gLocaleName) < 1)
{
/* Couldn't find them */
printf("Unable to read the specified COPYRIGHT string.\n");
}
/* Debug only */
DPRINT1("LOCALENAME [%40s]\n", gLocaleName);
return SkipLines();
}
ULONG
DoDESCRIPTIONS(IN PKEYNAME* DescriptionData)
{
ULONG KeyWord = 0;
CHAR Token[32];
ULONG LanguageCode;
PCHAR p, pp;
PKEYNAME Description;
/* Assume nothing */
*DescriptionData = 0;
/* Start scanning */
while (NextLine(gBuf, 256, gfpInput))
{
/* Search for token */
if (sscanf(gBuf, "%s", Token) != 1) continue;
/* Make sure it's not just a comment */
if (*Token == ';') continue;
/* Make sure it's not a keyword */
KeyWord = isKeyWord(Token);
if (KeyWord < KEYWORD_COUNT) break;
/* Now scan for the language code */
if (sscanf(Token, " %4x", &LanguageCode) != 1)
{
/* Skip */
printf("An invalid LANGID was specified.\n");
continue;
}
/* Now get the actual description */
if (sscanf(gBuf, " %*4x %s[^\n]", Token) != 1)
{
/* Skip */
printf("A language description is missing.\n");
continue;
}
/* Get the description string and find the ending */
p = strstr(gBuf, Token);
pp = strchr(p, '\n');
if (!pp) pp = strchr(p, '\r');
/* Terminate the description string here */
if (pp) *pp = 0;
/* Now allocate the description */
Description = malloc(sizeof(KEYNAME));
if (!Description)
{
/* Fail */
printf("Unable to allocate the KEYNAME struct (out of memory?).\n");
exit(1);
}
/* Fill out the structure */
Description->Code = LanguageCode;
Description->Name = strdup(p);
Description->Next = NULL;
/* Debug only */
DPRINT1("LANGID: [%4x] Description: [%s]\n", Description->Code, Description->Name);
/* Point to it and advance the pointer */
*DescriptionData = Description;
DescriptionData = &Description->Next;
}
/* We are done */
return KeyWord;
}
ULONG
DoLANGUAGENAMES(IN PKEYNAME* LanguageData)
{
ULONG KeyWord = 0;
CHAR Token[32];
ULONG LanguageCode;
PCHAR p, pp;
PKEYNAME Language;
/* Assume nothing */
*LanguageData = 0;
/* Start scanning */
while (NextLine(gBuf, 256, gfpInput))
{
/* Search for token */
if (sscanf(gBuf, "%s", Token) != 1) continue;
/* Make sure it's not just a comment */
if (*Token == ';') continue;
/* Make sure it's not a keyword */
KeyWord = isKeyWord(Token);
if (KeyWord < KEYWORD_COUNT) break;
/* Now scan for the language code */
if (sscanf(Token, " %4x", &LanguageCode) != 1)
{
/* Skip */
printf("An invalid LANGID was specified.\n");
continue;
}
/* Now get the actual language */
if (sscanf(gBuf, " %*4x %s[^\n]", Token) != 1)
{
/* Skip */
printf("A language name is missing\n");
continue;
}
/* Get the language string and find the ending */
p = strstr(gBuf, Token);
pp = strchr(p, '\n');
if (!pp) pp = strchr(p, '\r');
/* Terminate the language string here */
if (pp) *pp = 0;
/* Now allocate the language */
Language = malloc(sizeof(KEYNAME));
if (!Language)
{
/* Fail */
printf("Unable to allocate the KEYNAME struct (out of memory?).\n");
exit(1);
}
/* Fill out the structure */
Language->Code = LanguageCode;
Language->Name = strdup(p);
Language->Next = NULL;
/* Debug only */
DPRINT1("LANGID: [%4x] Name: [%s]\n", Language->Code, Language->Name);
/* Point to it and advance the pointer */
*LanguageData = Language;
LanguageData = &Language->Next;
}
/* We are done */
return KeyWord;
}
ULONG
DoKEYNAME(IN PKEYNAME* KeyNameData)
{
ULONG KeyWord = 0;
CHAR Token[32];
ULONG CharacterCode;
PCHAR p, pp;
PKEYNAME KeyName;
/* Assume nothing */
*KeyNameData = 0;
/* Start scanning */
while (NextLine(gBuf, 256, gfpInput))
{
/* Search for token */
if (sscanf(gBuf, "%s", Token) != 1) continue;
/* Make sure it's not just a comment */
if (*Token == ';') continue;
/* Make sure it's not a keyword */
KeyWord = isKeyWord(Token);
if (KeyWord < KEYWORD_COUNT) break;
/* Now scan for the character code */
if (sscanf(Token, " %4x", &CharacterCode) != 1)
{
/* Skip */
printf("An invalid character code was specified.\n");
continue;
}
/* Now get the actual key name */
if (sscanf(gBuf, " %*4x %s[^\n]", Token) != 1)
{
/* Skip */
printf("A key name is missing\n");
continue;
}
/* Get the key name string and find the ending */
p = strstr(gBuf, Token);
pp = strchr(p, '\n');
if (!pp) pp = strchr(p, '\r');
/* Terminate the key name string here */
if (pp) *pp = 0;
/* Now allocate the language */
KeyName = malloc(sizeof(KEYNAME));
if (!KeyName)
{
/* Fail */
printf("Unable to allocate the KEYNAME struct (out of memory?).\n");
exit(1);
}
/* Fill out the structure */
KeyName->Code = CharacterCode;
KeyName->Name = strdup(p);
KeyName->Next = NULL;
/* Debug only */
DPRINT1("CHARCODE: [%4x] Name: [%s]\n", KeyName->Code, KeyName->Name);
/* Point to it and advance the pointer */
*KeyNameData = KeyName;
KeyNameData = &KeyName->Next;
}
/* We are done */
return KeyWord;
}
ULONG
DoSHIFTSTATE(IN PULONG StateCount,
IN OUT PULONG ShiftStates)
{
ULONG KeyWord;
ULONG i;
ULONG ShiftState;
CHAR Token[32];
/* Reset the shift states */
for (i = 0; i < 8; i++) ShiftStates[i] = -1;
/* Start with no states */
*StateCount = 0;
/* Scan for shift states */
while (NextLine(gBuf, 256, gfpInput))
{
/* Search for token */
if (sscanf(gBuf, "%s", Token) != 1) continue;
/* Make sure it's not a keyword */
KeyWord = isKeyWord(Token);
if (KeyWord < KEYWORD_COUNT) break;
/* Now scan for the shift state */
if (sscanf(gBuf, " %1s[012367]", Token) != 1)
{
/* We failed -- should we warn? */
if (Verbose) printf("An invalid shift state '%s' was found (use 0, 1, 2, 3, 6, or 7.)\n", Token);
continue;
}
/* Now read the state */
ShiftState = atoi(Token);
/* Scan existing states */
for (i = 0; i < *StateCount; i++)
{
/* Check for duplicate */
if ((ShiftStates[i] == ShiftState) && (Verbose))
{
/* Warn user */
printf("The state '%d' was duplicated for this Virtual Key.\n", ShiftStates[i]);
break;
}
}
/* Make sure we won't overflow */
if (*StateCount < 8)
{
/* Save this state */
ShiftStates[(*StateCount)++] = ShiftState;
}
else
{
/* Too many states -- should we warn? */
if (Verbose) printf("There were too many states (you defined %d).\n", *StateCount);
}
}
/* Debug only */
DPRINT1("Found %d Shift States: [", *StateCount);
for (i = 0; i < *StateCount; i++) DPRINT1("%d ", ShiftStates[i]);
DPRINT1("]\n");
/* We are done */
return KeyWord;
}
ULONG
DoLIGATURE(PVOID LigatureData)
{
printf("LIGATURE support is not yet implemented. Please bug Arch to fix it\n");
return SkipLines();
}
ULONG
DoATTRIBUTES(PVOID AttributeData)
{
printf("ATTRIBUTES support is not yet implemented. Please bug Arch to fix it\n");
return SkipLines();
}
ULONG
DoMODIFIERS(VOID)
{
printf("MODIFIERS support is not yet implemented. Please bug Arch to fix it\n");
return SkipLines();
}
ULONG
DoDEADKEY(PVOID DeadKeyData)
{
printf("DEADKEY support is not yet implemented. Please bug Arch to fix it\n");
return SkipLines();
}
ULONG
DoLAYOUT(IN PLAYOUT LayoutData,
IN PVOID LigatureData,
IN PULONG ShiftStates,
IN ULONG StateCount)
{
CHAR Token[32];
CHAR Cap[8];
ULONG KeyWord;
ULONG ScanCode, CurrentCode;
ULONG TokenCount;
ULONG VirtualKey;
ULONG i;
ULONG Count;
BOOLEAN FullEntry;
CHAR State[8][8];
ULONG ScanCodeCount = -1;
PLAYOUTENTRY Entry;
UCHAR CharacterType;
CHAR LigatureChar;
/* Zero out the layout */
memset(LayoutData, 0, sizeof(LAYOUT));
/* Read each line */
Entry = &LayoutData->Entry[0];
while (NextLine(gBuf, 256, gfpInput))
{
/* Search for token */
if (sscanf(gBuf, "%s", Token) != 1) continue;
/* Make sure it's not just a comment */
if (*Token == ';') continue;
/* Make sure it's not a keyword */
KeyWord = isKeyWord(Token);
if (KeyWord < KEYWORD_COUNT) break;
/* Now read the entry */
TokenCount = sscanf(gBuf, " %x %s %s", &ScanCode, Token, Cap);
if (TokenCount == 3)
{
/* Full entry with cap */
FullEntry = TRUE;
}
else if (TokenCount != 2)
{
/* Fail, invalid LAYOUT entry */
printf("There are not enough columns in the layout list.\n");
exit(1);
}
else
{
/* Simplified layout with no cap */
FullEntry = FALSE;
}
/* One more */
DPRINT1("RAW ENTRY: [%x %s %s]\n", ScanCode, Token, Cap);
Entry++;
if (++ScanCodeCount >= 110)
{
/* Too many! */
printf("ScanCode %02x - too many scancodes here to parse.\n", ScanCode);
exit(1);
}
/* Fill out this entry */
Entry->ScanCode = ScanCode;
Entry->LineCount = gLineCount;
/* Loop scancode table */
for (i = 0; i < 110; i++)
{
/* Get the current code */
CurrentCode = ScVk[i].ScanCode;
if (CurrentCode == 0xFFFF)
{
/* New code */
if (Verbose) printf("A new scancode is being defined: 0x%2X, %s\n", Entry->ScanCode, Token);
/* Fill out the entry */
Entry->VirtualKey = getVKNum(Token);
break;
}
else if (ScanCode == CurrentCode)
{
/* Make sure we didn't already process it */
if (ScVk[i].Processed)
{
/* Fail */
printf("Scancode %X was previously defined.\n", ScanCode);
exit(1);
}
/* Check if there is a valid virtual key */
if (ScVk[i].VirtualKey == 0xFFFF)
{
/* Fail */
printf("The Scancode you tried to use (%X) is reserved.\n", ScanCode);
exit(1);
}
/* Fill out the entry */
Entry->OriginalVirtualKey = ScVk[i].VirtualKey;
Entry->Name = ScVk[i].Name;
break;
}
}
/* The entry is now processed */
Entry->Processed = TRUE;
ScVk[i].Processed = TRUE;
/* Get the virtual key from the entry */
VirtualKey = getVKNum(Token);
Entry->VirtualKey = VirtualKey;
DPRINT1("ENTRY: [%x %x %x %s] with ",
Entry->VirtualKey, Entry->OriginalVirtualKey, Entry->ScanCode, Entry->Name);
/* Make sure it's valid */
if (VirtualKey == 0xFFFF)
{
/* Warn the user */
if (Verbose) printf("An invalid Virtual Key '%s' was defined.\n", Token);
continue;
}
/* Is this a full entry */
if (FullEntry)
{
/* Do we have SGCAP data? Set cap mode to 2 */
if (!strcmp(Cap, "SGCAP")) *Cap = '2';
/* Read the cap mode */
if (sscanf(Cap, "%1d[012]", &Entry->Cap) != 1)
{
/* Invalid cap mode */
printf("invalid Cap specified (%s). Must be 0, 1, or 2.\n", Cap);
exit(1);
}
}
/* Read the states */
Count = sscanf(gBuf,
" %*s %*s %*s %s %s %s %s %s %s %s %s",
State[0],
State[1],
State[2],
State[3],
State[4],
State[5],
State[6],
State[7]);
Entry->StateCount = Count;
DPRINT1("%d STATES: [", Count);
/* Check if there are less than 2 states */
if ((Count < 2) && (FullEntry))
{
/* Fail */
printf("You must have at least 2 characters.\n");
exit(1);
}
/* Loop all states */
for (i = 0; i < Count; i++)
{
/* Check if this is an undefined state */
DPRINT1("%s ", State[i]);
if (!strcmp(State[i], "-1"))
{
/* No data for this state */
Entry->CharData[i] = -1;
continue;
}
/* Otherwise, check what kind of character this is */
CharacterType = getCharacterInfo(State[i],
&Entry->CharData[i],
&LigatureChar);
if (CharacterType == CHAR_DEAD_KEY)
{
/* Save it as such */
Entry->DeadCharData[i] = 1;
}
else if (CharacterType == CHAR_OTHER_KEY)
{
/* Save it as such */
Entry->OtherCharData[i] = 1;
}
}
/* Check for sanity checks */
DPRINT1("]\n");
if (SanityCheck)
{
/* Not yet handled... */
printf("Sanity checks not yet handled!\n");
exit(1);
}
/* Check if we had SGCAP data */
if (Entry->Cap & 2)
{
/* Not yet handled... */
printf("SGCAP state not yet handled!\n");
exit(1);
}
}
/* Check if we have found any ScanCode in the file */
if (ScanCodeCount == -1)
{
printf("No ScanCode found!\n");
exit(1);
}
/* Process the scan code table */
Entry = &LayoutData->Entry[ScanCodeCount];
for (i = 0; i < 110; i++)
{
/* Get the scan code */
CurrentCode = ScVk[i].ScanCode;
if (CurrentCode == 0xFFFF) break;
/* Check if this entry had been processed */
if (ScVk[i].Processed)
{
/* Skip it */
ScVk[i].Processed = FALSE;
}
else
{
/* Do we have too many? */
if (++ScanCodeCount >= 110)
{
/* Fail */
printf("ScanCode %02x - too many scancodes here to parse.\n", CurrentCode);
exit(1);
}
/* Build an entry for it */
Entry++;
Entry->ScanCode = CurrentCode;
Entry->VirtualKey = ScVk[i].VirtualKey;
Entry->OriginalVirtualKey = ScVk[i].VirtualKey;
Entry->Name = ScVk[i].Name;
Entry->Processed = TRUE;
Entry->LineCount = 0;
DPRINT1("AUTOMATIC ENTRY: [%x %x %s]\n",
Entry->VirtualKey, Entry->ScanCode, Entry->Name);
}
}
/* Skip what's left */
return KeyWord;
}
ULONG
DoParsing(VOID)
{
ULONG KeyWords[KEYWORD_COUNT];
ULONG KeyWord;
ULONG StateCount;
ULONG ShiftStates[8];
PKEYNAME DescriptionData = NULL, LanguageData = NULL;
PKEYNAME KeyNameData = NULL, KeyNameExtData = NULL, KeyNameDeadData = NULL;
PVOID AttributeData = NULL, LigatureData = NULL, DeadKeyData = NULL;
/* Parse keywords */
gLineCount = 0;
KeyWord = SkipLines();
if (KeyWord >= KEYWORD_COUNT)
{
/* Invalid keyword count, fail */
fclose(gfpInput);
printf("No keywords were found in '%s'.\n", gpszFileName);
exit(1);
}
/* Now parse the keywords */
memset(KeyWords, 0, sizeof(KeyWords));
while (KeyWord < (KEYWORD_COUNT - 1))
{
/* Save this keyword */
KeyWords[KeyWord]++;
/* Check for duplicate entires, other than DEADKEY, which is okay */
if ((KeyWord != 9) && (KeyWords[KeyWord] > 1) && (Verbose))
{
/* On a verbose run, warn the user */
printf("The '%s' keyword appeared multiple times.\n",
KeyWordList[KeyWord]);
}
/* Now parse this keyword */
switch (KeyWord)
{
/* KBD */
case 0:
DPRINT1("Found KBD section\n");
KeyWord = DoKBD();
break;
/* VERSION */
case 1:
DPRINT1("Found VERSION section\n");
KeyWord = DoVERSION();
break;
/* COPYRIGHT */
case 2:
DPRINT1("Found COPYRIGHT section\n");
KeyWord = DoCOPYRIGHT();
break;
/* COMPANY */
case 3:
DPRINT1("Found COMPANY section\n");
KeyWord = DoCOMPANY();
break;
/* LOCALENAME */
case 4:
DPRINT1("Found LOCALENAME section\n");
KeyWord = DoLOCALENAME();
break;
/* MODIFIERS */
case 5:
DPRINT1("Found MODIFIERS section\n");
KeyWord = DoMODIFIERS();
break;
/* SHIFTSTATE */
case 6:
DPRINT1("Found SHIFTSTATE section\n");
KeyWord = DoSHIFTSTATE(&StateCount, ShiftStates);
if (StateCount < 2)
{
/* Fail */
fclose(gfpInput);
printf("ERROR");
exit(1);
}
break;
/* ATTRIBUTES */
case 7:
DPRINT1("Found ATTRIBUTES section\n");
KeyWord = DoATTRIBUTES(&AttributeData);
break;
/* LAYOUT */
case 8:
DPRINT1("Found LAYOUT section\n");
KeyWord = DoLAYOUT(&g_Layout,
&LigatureData,
ShiftStates,
StateCount);
break;
/* DEADKEY */
case 9:
DPRINT1("Found DEADKEY section\n");
KeyWord = DoDEADKEY(&DeadKeyData);
break;
/* LIGATURE */
case 10:
DPRINT1("Found LIGATURE section\n");
KeyWord = DoLIGATURE(&LigatureData);
break;
/* KEYNAME */
case 11:
DPRINT1("Found KEYNAME section\n");
KeyWord = DoKEYNAME(&KeyNameData);
break;
/* KEYNAME_EXT */
case 12:
DPRINT1("Found KEYNAME_EXT section\n");
KeyWord = DoKEYNAME(&KeyNameExtData);
break;
/* KEYNAME_DEAD */
case 13:
DPRINT1("Found KEYNAME_DEAD section\n");
KeyWord = DoKEYNAME(&KeyNameDeadData);
break;
/* DESCRIPTIONS */
case 14:
DPRINT1("Found DESCRIPTIONS section\n");
KeyWord = DoDESCRIPTIONS(&DescriptionData);
break;
/* LANGUAGENAMES */
case 15:
DPRINT1("Found LANGUAGENAMES section\n");
KeyWord = DoLANGUAGENAMES(&LanguageData);
break;
/* ENDKBD */
case 16:
DPRINT1("Found ENDKBD section\n");
KeyWord = SkipLines();
break;
default:
break;
}
}
/* We are done */
fclose(gfpInput);
/* Now enter the output phase */
return DoOutput(StateCount,
ShiftStates,
DescriptionData,
LanguageData,
AttributeData,
DeadKeyData,
LigatureData,
KeyNameData,
KeyNameExtData,
KeyNameDeadData);
}
/* EOF */