762 lines
21 KiB
C
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;
|
||
|
|
||
|
}
|