/****************************** 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; }