windows-nt/Source/XPSP1/NT/sdktools/structo/soparse.c
2020-09-26 16:20:57 +08:00

762 lines
21 KiB
C

/****************************** Module Header ******************************\
* Module Name: soparse.c
*
* Copyright (c) 1985-96, Microsoft Corporation
*
* 04/09/96 GerardoB Created
\***************************************************************************/
#include "structo.h"
/*********************************************************************
* Function Prototypes
\***************************************************************************/
/*********************************************************************
* soFindChar
\***************************************************************************/
char * soFindChar (char * pmap, char * pmapEnd, char c)
{
while (pmap < pmapEnd) {
if (*pmap != c) {
pmap++;
} else {
return pmap;
}
}
return NULL;
}
/*********************************************************************
* soFindTag
\***************************************************************************/
char * soFindTag (char * pmap, char * pmapEnd, char * pszTag)
{
char * pszNext;
char * pmapTag;
do {
/*
* Find first char
*/
pmapTag = soFindChar (pmap, pmapEnd, *pszTag);
if (pmapTag == NULL) {
return NULL;
}
pmap = pmapTag + 1;
pszNext = pszTag + 1;
/*
* First found, compare the rest
*/
while (pmap < pmapEnd) {
if (*pmap != *pszNext) {
break;
} else {
pmap++;
pszNext++;
if (*pszNext == '\0') {
return pmapTag;
}
}
}
} while (pmap < pmapEnd);
return NULL;
}
/*********************************************************************
* soFindFirstCharInTag
*
* Finds the first occurrence of any character in pszTag
\***************************************************************************/
char * soFindFirstCharInTag (char * pmap, char * pmapEnd, char * pszTag)
{
char * pszNext;
while (pmap < pmapEnd) {
/*
* Compare current char to all chars in pszTag
*/
pszNext = pszTag;
do {
if (*pmap == *pszNext++) {
return pmap;
}
} while (*pszNext != '\0');
pmap++;
}
return NULL;
}
/*********************************************************************
* soFindBlockEnd
*
* Finds the end of a {} () etc block
\***************************************************************************/
char * soFindBlockEnd (char * pmap, char * pmapEnd, char * pszBlockChars)
{
if (*pmap != *pszBlockChars) {
soLogMsg(SOLM_ERROR, "Not at the beginning of block");
return NULL;
}
do {
/*
* Find next block char (i.e, { or })
*/
pmap++;
pmap = soFindFirstCharInTag (pmap, pmapEnd, pszBlockChars);
if (pmap == NULL) {
break;
}
/*
* If at the end of the block, done
*/
if (*pmap == *(pszBlockChars + 1)) {
return pmap;
}
/*
* Nested block, recurse.
*/
pmap = soFindBlockEnd (pmap, pmapEnd, pszBlockChars);
} while (pmap != NULL);
soLogMsg(SOLM_ERROR, "Failed to find block end");
return NULL;
}
/*********************************************************************
* soIsIdentifierChar
\***************************************************************************/
BOOL soIsIdentifierChar (char c)
{
return ( ((c >= 'a') && (c <= 'z'))
|| ((c >= 'A') && (c <= 'Z'))
|| ((c >= '0') && (c <= '9'))
|| (c == '_'));
}
/*********************************************************************
* soSkipBlanks
\***************************************************************************/
char * soSkipBlanks(char * pmap, char * pmapEnd)
{
while (pmap < pmapEnd) {
switch (*pmap) {
case ' ':
case '\r':
case '\n':
pmap++;
break;
default:
return pmap;
}
}
return NULL;
}
/*********************************************************************
* soSkipToIdentifier
*
* Finds the beginning of the next identifier or return pmap if
* already on an indetifier
\***************************************************************************/
char * soSkipToIdentifier(char * pmap, char * pmapEnd)
{
while (pmap < pmapEnd) {
if (soIsIdentifierChar(*pmap)) {
return pmap;
} else {
pmap++;
}
}
return NULL;
}
/*********************************************************************
* soSkipIdentifier
*
* Finds the end of the current identifier
\***************************************************************************/
char * soSkipIdentifier(char * pmap, char * pmapEnd)
{
while (pmap < pmapEnd) {
if (soIsIdentifierChar(*pmap)) {
pmap++;
} else {
return pmap;
}
}
return pmapEnd;
}
/*********************************************************************
* soGetIdentifier
*
* Returns the beginning of the current or next identifier and its size
\***************************************************************************/
char * soGetIdentifier (char * pmap, char * pmapEnd, UINT * puSize)
{
char * pTag, * pTagEnd;
pTag = soSkipToIdentifier(pmap, pmapEnd);
if (pTag == NULL) {
return NULL;
}
pTagEnd = soSkipIdentifier(pTag, pmapEnd);
*puSize = (UINT)(pTagEnd - pTag);
return pTag;
}
/*********************************************************************
* soCopyTagName
\***************************************************************************/
char * soCopyTagName (char * pTagName, UINT uTagSize)
{
char * pszName;
pszName = (char *) LocalAlloc(LPTR, uTagSize+1);
if (pszName == NULL) {
soLogMsg(SOLM_APIERROR, "LocalAlloc");
soLogMsg(SOLM_ERROR, "soCopytagName allocation failed. Size:%d", uTagSize);
return NULL;
}
strncpy(pszName, pTagName, uTagSize);
return pszName;
}
/*********************************************************************
* soFindBlock
\***************************************************************************/
BOOL soFindBlock (char * pmap, char *pmapEnd, char * pszBlockChars, PBLOCK pb)
{
static char gszBlockBeginChar [] = " ;";
/*
* Find the beginning of the block or a ;
*/
*gszBlockBeginChar = *pszBlockChars;
pb->pBegin = soFindFirstCharInTag (pmap, pmapEnd, gszBlockBeginChar);
if (pb->pBegin == NULL) {
soLogMsg(SOLM_ERROR, "Failed to find beginning of block");
return FALSE;
}
/*
* If no block found, done
*/
if (*(pb->pBegin) == ';') {
/*
* Make pb->pBegin point to whatever follows
*/
(pb->pBegin)++;
pb->pEnd = pb->pBegin;
return TRUE;
}
/*
* Find the end of block
*/
pb->pEnd = soFindBlockEnd(pb->pBegin, pmapEnd, pszBlockChars);
if (pb->pEnd == NULL) {
return FALSE;
}
return TRUE;
}
/*********************************************************************
* soGetStructListEntry
\***************************************************************************/
PSTRUCTLIST soGetStructListEntry (char * pTag, UINT uTagSize, PSTRUCTLIST psl)
{
while (psl->uSize != 0) {
if ((psl->uSize == uTagSize) && !strncmp(pTag, psl->pszName, uTagSize)) {
(psl->uCount)++;
return psl;
}
psl++;
}
return NULL;
}
/*********************************************************************
* soGetBlockName
*
* Finds the beginning, end, name and name size of a structure or union.
* if any after pmap.
*
\***************************************************************************/
BOOL soGetBlockName (char * pmap, char * pmapEnd, PBLOCK pb)
{
char * pNextTag;
if (!soFindBlock (pmap, pmapEnd, "{}", pb)) {
return FALSE;
}
/*
* If there was no block (the structure body is not here), done
*/
if (pb->pBegin == pb->pEnd) {
pb->pName = NULL;
return TRUE;
}
pNextTag = soSkipBlanks(pb->pEnd + 1, pmapEnd);
if (pNextTag == NULL) {
/*
* It might be at the end of the file..... but it was expecting
* a name or a ;
*/
soLogMsg(SOLM_ERROR, "Failed to find union terminator or name");
return FALSE;
}
/*
* If it's unamed, done
*/
if (*pNextTag == ';') {
pb->pName = NULL;
return TRUE;
}
pb->pName = soGetIdentifier(pNextTag, pmapEnd, &(pb->uNameSize));
if (pb->pName == NULL) {
soLogMsg(SOLM_ERROR, "Failed to get block name");
return FALSE;
}
return TRUE;
}
/*********************************************************************
* soFreepfiPointers
*
\***************************************************************************/
void soFreepfiPointers (PFIELDINFO pfi)
{
if (pfi->dwFlags & SOFI_ALLOCATED) {
LocalFree(pfi->pType);
}
if (pfi->dwFlags & SOFI_ARRAYALLOCATED) {
LocalFree(pfi->pArray);
}
}
/*********************************************************************
* soParseField
*
\***************************************************************************/
char * soParseField (PWORKINGFILES pwf, PFIELDINFO pfi, char * pTag, char * pTagEnd)
{
static char gszpvoid [] = "void *";
static char gszdword [] = "DWORD";
BOOL fUseFieldOffset, fBitField, fTypeFound, fArray;
BLOCK block;
char * pTagName, * pszFieldName;
char * pNextTag, * pType;
UINT uTags, uTagSize, uTagsToName, uTypeSize;
fUseFieldOffset = TRUE;
uTags = 0;
uTagsToName = 1;
fTypeFound = FALSE;
do {
/*
* Find next indetifier, move past it and get the following char
*/
uTags++;
pTagName = soGetIdentifier(pTag+1, pwf->pmapEnd, &uTagSize);
if (pTagName == NULL) {
soLogMsg(SOLM_ERROR, "Failed to get field name");
return NULL;
}
pTag = pTagName + uTagSize;
if (pTag >= pTagEnd) {
break;
}
pNextTag = soSkipBlanks(pTag, pTagEnd);
if (pNextTag == NULL) {
soLogMsg(SOLM_ERROR, "Failed to get field termination");
return NULL;
}
/*
* Type check.
* (LATER: Let's see how long we can get away with assuming that the type
* is the first tag....)
* Remember where the type is
*/
if (!fTypeFound) {
pType = pTagName;
uTypeSize = uTagSize;
fTypeFound = TRUE;
}
if (uTags == 1) {
if (!strncmp(pTagName, "union", uTagSize)) {
/*
* Get the union name
*/
if (!soGetBlockName(pTagName, pwf->pmapEnd, &block)) {
return NULL;
}
if (block.pName != NULL) {
/*
* Named union. Add this name to the table
*/
pTagName = block.pName;
uTagSize = block.uNameSize;
fUseFieldOffset = FALSE;
fTypeFound = FALSE;
break;
} else {
/*
* Parse and add the fields in this union
*/
fTypeFound = FALSE;
}
} else if (!strncmp(pTagName, "struct", uTagSize)) {
/*
* Get the structure name
*/
if (!soGetBlockName(pTagName, pwf->pmapEnd, &block)) {
return NULL;
}
if (block.pBegin == block.pEnd) {
/*
* The structure body is not here. We need one more
* identifier to get to the field name. Also, this
* field must (?) be a pointer to the struct we're
* parsing
*/
uTagsToName++;
pType = gszpvoid;
uTypeSize = sizeof(gszpvoid) - 1;
} else if (block.pName != NULL) {
/*
* Named structure. Add this name to the table
*/
pTagName = block.pName;
uTagSize = block.uNameSize;
fUseFieldOffset = FALSE;
fTypeFound = FALSE;
break;
} else {
/*
* Parse and add the fields in this struct
*/
fTypeFound = FALSE;
}
} else {
/*
* Cannot get the offset of strucutres like RECT, POINT, etc.
*/
fUseFieldOffset = (NULL == soGetStructListEntry(pTagName, uTagSize, gpslEmbeddedStructs));
}
} else { /* if (uTags == 1) */
/*
* Does this look like a function prototype?
*/
if (*pTagName == '(') {
pTag = soFindChar (pTagName + 1, pwf->pmapEnd, ')');
if (pTag == NULL) {
soLogMsg(SOLM_ERROR, "Failed to find closing paren");
return NULL;
}
pTag++;
uTagSize = (UINT)(pTag - pTagName);
fUseFieldOffset = FALSE;
break;
}
} /* if (uTags == 1) */
/*
* If this is followed by a terminator, this must be the field name
*/
} while ( (*pNextTag != ';') && (*pNextTag != '[')
&& (*pNextTag != '}') && (*pNextTag != ':'));
if (pTag >= pTagEnd) {
return pTag;
}
fBitField = (*pNextTag == ':');
fArray = (*pNextTag == '[');
/*
* Cannot use FIELD_OFFSET on bit fields or unamed structs
*/
fUseFieldOffset &= (!fBitField && (uTags > uTagsToName));
/*
* If this is a bit field, make the size be part of the name
*/
if (fBitField) {
pNextTag = soSkipBlanks(pNextTag + 1, pTagEnd);
if (pNextTag == NULL) {
soLogMsg(SOLM_ERROR, "Failed to get bit field size");
return NULL;
}
pNextTag = soSkipIdentifier(pNextTag + 1, pTagEnd);
if (pNextTag == NULL) {
soLogMsg(SOLM_ERROR, "Failed to skip bit field size");
return NULL;
}
uTagSize = (UINT)(pNextTag - pTagName);
}
/*
* Copy field name
*/
pszFieldName = soCopyTagName (pTagName, uTagSize);
if (pszFieldName == NULL) {
return NULL;
}
if (fUseFieldOffset) {
/*
* Use FIELD_OFFSET macro
*/
if (!soWriteFile(pwf->hfileOutput, gszStructFieldOffsetFmt, pszFieldName, pfi->pszStructName, pszFieldName)) {
return NULL;
}
} else {
/*
* If this is the first field or if this is a bit field
* preceded by another bit field
*/
if ((pfi->pType == NULL)
|| (fBitField && (pfi->dwFlags & SOFI_BIT))) {
/*
* Write 0 or the mask to signal a 0 relative offset from
* the previous field
*/
if (!soWriteFile(pwf->hfileOutput, gszStructAbsoluteOffsetFmt, pszFieldName,
((pfi->dwFlags & SOFI_BIT) ? 0x80000000 : 0))) {
return NULL;
}
} else {
/*
* Write a relative offset from the previous field
* Copy type name if not done already
*/
if (!(pfi->dwFlags & SOFI_ALLOCATED)) {
pfi->pType = soCopyTagName (pfi->pType, pfi->uTypeSize);
if (pfi->pType == NULL) {
return NULL;
}
pfi->dwFlags |= SOFI_ALLOCATED;
}
/*
* If the last field was NOT an array
*/
if (!(pfi->dwFlags & SOFI_ARRAY)) {
if (!soWriteFile(pwf->hfileOutput, gszStructRelativeOffsetFmt, pszFieldName, pfi->pType)) {
return NULL;
}
} else {
/*
* Copy the array size if not done already
*/
if (!(pfi->dwFlags & SOFI_ARRAYALLOCATED)) {
pfi->pArray = soCopyTagName (pfi->pArray, pfi->uArraySize);
if (pfi->pArray == NULL) {
return NULL;
}
pfi->dwFlags |= SOFI_ARRAYALLOCATED;
}
if (!soWriteFile(pwf->hfileOutput, gszStructArrayRelativeOffsetFmt, pszFieldName, pfi->pType, pfi->pArray)) {
return NULL;
}
} /* if ((pfi->pType == NULL) || (pfi->dwFlags & SOFI_BIT)) */
}
} /* if (fUseFieldOffset) */
/*
* Save the field info wich migth be needed to calculate the offset
* to following fields. See gszStruct*RelativeOffsetFmt.
*/
soFreepfiPointers(pfi);
pfi->dwFlags = 0;
if (fBitField) {
/*
* LATER: Let's see how long we can get away with assuming that
* bit fields take a DWORD. This only matters when a !fUseFieldOffset
* is preceded by a bit field.
*/
pfi->dwFlags = SOFI_BIT;
pfi->pType = gszdword;
pfi->uTypeSize = sizeof(gszdword) - 1;
} else {
pfi->pType = pType;
pfi->uTypeSize = uTypeSize;
if (fArray) {
pfi->dwFlags = SOFI_ARRAY;
if (!soFindBlock (pNextTag, pwf->pmapEnd, "[]", &block)) {
return NULL;
}
if (block.pBegin + 1 >= block.pEnd) {
soLogMsg(SOLM_ERROR, "Missing array size", pfi->pszStructName, pszFieldName);
return NULL;
}
pfi->pArray = pNextTag + 1;
pfi->uArraySize = (UINT)(block.pEnd - block.pBegin - 1);
}
} /* if (fBitField) */
LocalFree(pszFieldName);
/*
* Move past the end of this field
*/
pTag = soFindChar (pTagName + 1, pwf->pmapEnd, ';');
if (pTag == NULL) {
soLogMsg(SOLM_ERROR, "Failed to find ';' after field name");
return NULL;
}
pTag++;
return pTag;
soLogMsg(SOLM_ERROR, ". Struct:%s Field:%s", pfi->pszStructName, pszFieldName);
}
/*********************************************************************
* soParseStruct
\***************************************************************************/
char * soParseStruct (PWORKINGFILES pwf)
{
BLOCK block;
char * pTag, ** ppszStruct;
FIELDINFO fi;
PSTRUCTLIST psl;
if (!soGetBlockName(pwf->pmap, pwf->pmapEnd, &block)) {
return NULL;
}
/*
* If there was no block (the structure body is not here), done
*/
if (block.pBegin == block.pEnd) {
return block.pBegin;
}
/*
* Fail if no name.
*/
if (block.pName == NULL) {
soLogMsg(SOLM_ERROR, "Failed to get structure name");
return NULL;
}
/*
* If there is a struct list, check if in the list
* If in the list, check that we haven't found it already.
* If not in the list, done.
*/
if (pwf->psl != NULL) {
psl = soGetStructListEntry(block.pName, block.uNameSize, pwf->psl);
if (psl != NULL) {
if (psl->uCount > 1) {
soLogMsg(SOLM_ERROR, "Struct %s already defined", psl->pszName);
return NULL;
}
} else {
return block.pEnd;
}
}
/*
* Make a null terminated string for the name.
*/
ZeroMemory(&fi, sizeof(fi));
fi.pszStructName = soCopyTagName (block.pName, block.uNameSize);
if (fi.pszStructName == NULL) {
return NULL;
}
/*
* If building list only, done
*/
if (pwf->dwOptions & SOWF_LISTONLY) {
if (!soWriteFile(pwf->hfileOutput, "%s\r\n", fi.pszStructName)) {
goto CleanupAndFail;
}
goto DoneWithThisOne;
}
/*
* Write structure offsets table definition and entry in strucutres table
*/
if (!soWriteFile(pwf->hfileOutput, gszStructDefFmt, gszStructDef, fi.pszStructName, gszStructBegin)) {
goto CleanupAndFail;
}
if (!soWriteFile(pwf->hfileTemp, gszTableEntryFmt, fi.pszStructName, fi.pszStructName, fi.pszStructName)) {
goto CleanupAndFail;
}
/*
* Parse the fields
*/
pTag = block.pBegin + 1;
while (pTag < block.pEnd) {
pTag = soParseField (pwf, &fi, pTag, block.pEnd);
if (pTag == NULL) {
goto CleanupAndFail;
}
}
/*
* Write structure last record and end
*/
if (!soWriteFile(pwf->hfileOutput, "%s%s%s", gszStructLastRecord, fi.pszStructName, gszStructEnd)) {
goto CleanupAndFail;
}
DoneWithThisOne:
(pwf->uTablesCount)++;
LocalFree(fi.pszStructName);
soFreepfiPointers(&fi);
/*
* Move past the end of the structure
*/
pTag = soFindChar(block.pName + block.uNameSize, pwf->pmapEnd, ';');
return (pTag != NULL ? pTag + 1 : NULL);
CleanupAndFail:
LocalFree(fi.pszStructName);
soFreepfiPointers(&fi);
return NULL;
}