Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

761 lines
21 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: soparse.c
  3. *
  4. * Copyright (c) 1985-96, Microsoft Corporation
  5. *
  6. * 04/09/96 GerardoB Created
  7. \***************************************************************************/
  8. #include "structo.h"
  9. /*********************************************************************
  10. * Function Prototypes
  11. \***************************************************************************/
  12. /*********************************************************************
  13. * soFindChar
  14. \***************************************************************************/
  15. char * soFindChar (char * pmap, char * pmapEnd, char c)
  16. {
  17. while (pmap < pmapEnd) {
  18. if (*pmap != c) {
  19. pmap++;
  20. } else {
  21. return pmap;
  22. }
  23. }
  24. return NULL;
  25. }
  26. /*********************************************************************
  27. * soFindTag
  28. \***************************************************************************/
  29. char * soFindTag (char * pmap, char * pmapEnd, char * pszTag)
  30. {
  31. char * pszNext;
  32. char * pmapTag;
  33. do {
  34. /*
  35. * Find first char
  36. */
  37. pmapTag = soFindChar (pmap, pmapEnd, *pszTag);
  38. if (pmapTag == NULL) {
  39. return NULL;
  40. }
  41. pmap = pmapTag + 1;
  42. pszNext = pszTag + 1;
  43. /*
  44. * First found, compare the rest
  45. */
  46. while (pmap < pmapEnd) {
  47. if (*pmap != *pszNext) {
  48. break;
  49. } else {
  50. pmap++;
  51. pszNext++;
  52. if (*pszNext == '\0') {
  53. return pmapTag;
  54. }
  55. }
  56. }
  57. } while (pmap < pmapEnd);
  58. return NULL;
  59. }
  60. /*********************************************************************
  61. * soFindFirstCharInTag
  62. *
  63. * Finds the first occurrence of any character in pszTag
  64. \***************************************************************************/
  65. char * soFindFirstCharInTag (char * pmap, char * pmapEnd, char * pszTag)
  66. {
  67. char * pszNext;
  68. while (pmap < pmapEnd) {
  69. /*
  70. * Compare current char to all chars in pszTag
  71. */
  72. pszNext = pszTag;
  73. do {
  74. if (*pmap == *pszNext++) {
  75. return pmap;
  76. }
  77. } while (*pszNext != '\0');
  78. pmap++;
  79. }
  80. return NULL;
  81. }
  82. /*********************************************************************
  83. * soFindBlockEnd
  84. *
  85. * Finds the end of a {} () etc block
  86. \***************************************************************************/
  87. char * soFindBlockEnd (char * pmap, char * pmapEnd, char * pszBlockChars)
  88. {
  89. if (*pmap != *pszBlockChars) {
  90. soLogMsg(SOLM_ERROR, "Not at the beginning of block");
  91. return NULL;
  92. }
  93. do {
  94. /*
  95. * Find next block char (i.e, { or })
  96. */
  97. pmap++;
  98. pmap = soFindFirstCharInTag (pmap, pmapEnd, pszBlockChars);
  99. if (pmap == NULL) {
  100. break;
  101. }
  102. /*
  103. * If at the end of the block, done
  104. */
  105. if (*pmap == *(pszBlockChars + 1)) {
  106. return pmap;
  107. }
  108. /*
  109. * Nested block, recurse.
  110. */
  111. pmap = soFindBlockEnd (pmap, pmapEnd, pszBlockChars);
  112. } while (pmap != NULL);
  113. soLogMsg(SOLM_ERROR, "Failed to find block end");
  114. return NULL;
  115. }
  116. /*********************************************************************
  117. * soIsIdentifierChar
  118. \***************************************************************************/
  119. BOOL soIsIdentifierChar (char c)
  120. {
  121. return ( ((c >= 'a') && (c <= 'z'))
  122. || ((c >= 'A') && (c <= 'Z'))
  123. || ((c >= '0') && (c <= '9'))
  124. || (c == '_'));
  125. }
  126. /*********************************************************************
  127. * soSkipBlanks
  128. \***************************************************************************/
  129. char * soSkipBlanks(char * pmap, char * pmapEnd)
  130. {
  131. while (pmap < pmapEnd) {
  132. switch (*pmap) {
  133. case ' ':
  134. case '\r':
  135. case '\n':
  136. pmap++;
  137. break;
  138. default:
  139. return pmap;
  140. }
  141. }
  142. return NULL;
  143. }
  144. /*********************************************************************
  145. * soSkipToIdentifier
  146. *
  147. * Finds the beginning of the next identifier or return pmap if
  148. * already on an indetifier
  149. \***************************************************************************/
  150. char * soSkipToIdentifier(char * pmap, char * pmapEnd)
  151. {
  152. while (pmap < pmapEnd) {
  153. if (soIsIdentifierChar(*pmap)) {
  154. return pmap;
  155. } else {
  156. pmap++;
  157. }
  158. }
  159. return NULL;
  160. }
  161. /*********************************************************************
  162. * soSkipIdentifier
  163. *
  164. * Finds the end of the current identifier
  165. \***************************************************************************/
  166. char * soSkipIdentifier(char * pmap, char * pmapEnd)
  167. {
  168. while (pmap < pmapEnd) {
  169. if (soIsIdentifierChar(*pmap)) {
  170. pmap++;
  171. } else {
  172. return pmap;
  173. }
  174. }
  175. return pmapEnd;
  176. }
  177. /*********************************************************************
  178. * soGetIdentifier
  179. *
  180. * Returns the beginning of the current or next identifier and its size
  181. \***************************************************************************/
  182. char * soGetIdentifier (char * pmap, char * pmapEnd, UINT * puSize)
  183. {
  184. char * pTag, * pTagEnd;
  185. pTag = soSkipToIdentifier(pmap, pmapEnd);
  186. if (pTag == NULL) {
  187. return NULL;
  188. }
  189. pTagEnd = soSkipIdentifier(pTag, pmapEnd);
  190. *puSize = (UINT)(pTagEnd - pTag);
  191. return pTag;
  192. }
  193. /*********************************************************************
  194. * soCopyTagName
  195. \***************************************************************************/
  196. char * soCopyTagName (char * pTagName, UINT uTagSize)
  197. {
  198. char * pszName;
  199. pszName = (char *) LocalAlloc(LPTR, uTagSize+1);
  200. if (pszName == NULL) {
  201. soLogMsg(SOLM_APIERROR, "LocalAlloc");
  202. soLogMsg(SOLM_ERROR, "soCopytagName allocation failed. Size:%d", uTagSize);
  203. return NULL;
  204. }
  205. strncpy(pszName, pTagName, uTagSize);
  206. return pszName;
  207. }
  208. /*********************************************************************
  209. * soFindBlock
  210. \***************************************************************************/
  211. BOOL soFindBlock (char * pmap, char *pmapEnd, char * pszBlockChars, PBLOCK pb)
  212. {
  213. static char gszBlockBeginChar [] = " ;";
  214. /*
  215. * Find the beginning of the block or a ;
  216. */
  217. *gszBlockBeginChar = *pszBlockChars;
  218. pb->pBegin = soFindFirstCharInTag (pmap, pmapEnd, gszBlockBeginChar);
  219. if (pb->pBegin == NULL) {
  220. soLogMsg(SOLM_ERROR, "Failed to find beginning of block");
  221. return FALSE;
  222. }
  223. /*
  224. * If no block found, done
  225. */
  226. if (*(pb->pBegin) == ';') {
  227. /*
  228. * Make pb->pBegin point to whatever follows
  229. */
  230. (pb->pBegin)++;
  231. pb->pEnd = pb->pBegin;
  232. return TRUE;
  233. }
  234. /*
  235. * Find the end of block
  236. */
  237. pb->pEnd = soFindBlockEnd(pb->pBegin, pmapEnd, pszBlockChars);
  238. if (pb->pEnd == NULL) {
  239. return FALSE;
  240. }
  241. return TRUE;
  242. }
  243. /*********************************************************************
  244. * soGetStructListEntry
  245. \***************************************************************************/
  246. PSTRUCTLIST soGetStructListEntry (char * pTag, UINT uTagSize, PSTRUCTLIST psl)
  247. {
  248. while (psl->uSize != 0) {
  249. if ((psl->uSize == uTagSize) && !strncmp(pTag, psl->pszName, uTagSize)) {
  250. (psl->uCount)++;
  251. return psl;
  252. }
  253. psl++;
  254. }
  255. return NULL;
  256. }
  257. /*********************************************************************
  258. * soGetBlockName
  259. *
  260. * Finds the beginning, end, name and name size of a structure or union.
  261. * if any after pmap.
  262. *
  263. \***************************************************************************/
  264. BOOL soGetBlockName (char * pmap, char * pmapEnd, PBLOCK pb)
  265. {
  266. char * pNextTag;
  267. if (!soFindBlock (pmap, pmapEnd, "{}", pb)) {
  268. return FALSE;
  269. }
  270. /*
  271. * If there was no block (the structure body is not here), done
  272. */
  273. if (pb->pBegin == pb->pEnd) {
  274. pb->pName = NULL;
  275. return TRUE;
  276. }
  277. pNextTag = soSkipBlanks(pb->pEnd + 1, pmapEnd);
  278. if (pNextTag == NULL) {
  279. /*
  280. * It might be at the end of the file..... but it was expecting
  281. * a name or a ;
  282. */
  283. soLogMsg(SOLM_ERROR, "Failed to find union terminator or name");
  284. return FALSE;
  285. }
  286. /*
  287. * If it's unamed, done
  288. */
  289. if (*pNextTag == ';') {
  290. pb->pName = NULL;
  291. return TRUE;
  292. }
  293. pb->pName = soGetIdentifier(pNextTag, pmapEnd, &(pb->uNameSize));
  294. if (pb->pName == NULL) {
  295. soLogMsg(SOLM_ERROR, "Failed to get block name");
  296. return FALSE;
  297. }
  298. return TRUE;
  299. }
  300. /*********************************************************************
  301. * soFreepfiPointers
  302. *
  303. \***************************************************************************/
  304. void soFreepfiPointers (PFIELDINFO pfi)
  305. {
  306. if (pfi->dwFlags & SOFI_ALLOCATED) {
  307. LocalFree(pfi->pType);
  308. }
  309. if (pfi->dwFlags & SOFI_ARRAYALLOCATED) {
  310. LocalFree(pfi->pArray);
  311. }
  312. }
  313. /*********************************************************************
  314. * soParseField
  315. *
  316. \***************************************************************************/
  317. char * soParseField (PWORKINGFILES pwf, PFIELDINFO pfi, char * pTag, char * pTagEnd)
  318. {
  319. static char gszpvoid [] = "void *";
  320. static char gszdword [] = "DWORD";
  321. BOOL fUseFieldOffset, fBitField, fTypeFound, fArray;
  322. BLOCK block;
  323. char * pTagName, * pszFieldName;
  324. char * pNextTag, * pType;
  325. UINT uTags, uTagSize, uTagsToName, uTypeSize;
  326. fUseFieldOffset = TRUE;
  327. uTags = 0;
  328. uTagsToName = 1;
  329. fTypeFound = FALSE;
  330. do {
  331. /*
  332. * Find next indetifier, move past it and get the following char
  333. */
  334. uTags++;
  335. pTagName = soGetIdentifier(pTag+1, pwf->pmapEnd, &uTagSize);
  336. if (pTagName == NULL) {
  337. soLogMsg(SOLM_ERROR, "Failed to get field name");
  338. return NULL;
  339. }
  340. pTag = pTagName + uTagSize;
  341. if (pTag >= pTagEnd) {
  342. break;
  343. }
  344. pNextTag = soSkipBlanks(pTag, pTagEnd);
  345. if (pNextTag == NULL) {
  346. soLogMsg(SOLM_ERROR, "Failed to get field termination");
  347. return NULL;
  348. }
  349. /*
  350. * Type check.
  351. * (LATER: Let's see how long we can get away with assuming that the type
  352. * is the first tag....)
  353. * Remember where the type is
  354. */
  355. if (!fTypeFound) {
  356. pType = pTagName;
  357. uTypeSize = uTagSize;
  358. fTypeFound = TRUE;
  359. }
  360. if (uTags == 1) {
  361. if (!strncmp(pTagName, "union", uTagSize)) {
  362. /*
  363. * Get the union name
  364. */
  365. if (!soGetBlockName(pTagName, pwf->pmapEnd, &block)) {
  366. return NULL;
  367. }
  368. if (block.pName != NULL) {
  369. /*
  370. * Named union. Add this name to the table
  371. */
  372. pTagName = block.pName;
  373. uTagSize = block.uNameSize;
  374. fUseFieldOffset = FALSE;
  375. fTypeFound = FALSE;
  376. break;
  377. } else {
  378. /*
  379. * Parse and add the fields in this union
  380. */
  381. fTypeFound = FALSE;
  382. }
  383. } else if (!strncmp(pTagName, "struct", uTagSize)) {
  384. /*
  385. * Get the structure name
  386. */
  387. if (!soGetBlockName(pTagName, pwf->pmapEnd, &block)) {
  388. return NULL;
  389. }
  390. if (block.pBegin == block.pEnd) {
  391. /*
  392. * The structure body is not here. We need one more
  393. * identifier to get to the field name. Also, this
  394. * field must (?) be a pointer to the struct we're
  395. * parsing
  396. */
  397. uTagsToName++;
  398. pType = gszpvoid;
  399. uTypeSize = sizeof(gszpvoid) - 1;
  400. } else if (block.pName != NULL) {
  401. /*
  402. * Named structure. Add this name to the table
  403. */
  404. pTagName = block.pName;
  405. uTagSize = block.uNameSize;
  406. fUseFieldOffset = FALSE;
  407. fTypeFound = FALSE;
  408. break;
  409. } else {
  410. /*
  411. * Parse and add the fields in this struct
  412. */
  413. fTypeFound = FALSE;
  414. }
  415. } else {
  416. /*
  417. * Cannot get the offset of strucutres like RECT, POINT, etc.
  418. */
  419. fUseFieldOffset = (NULL == soGetStructListEntry(pTagName, uTagSize, gpslEmbeddedStructs));
  420. }
  421. } else { /* if (uTags == 1) */
  422. /*
  423. * Does this look like a function prototype?
  424. */
  425. if (*pTagName == '(') {
  426. pTag = soFindChar (pTagName + 1, pwf->pmapEnd, ')');
  427. if (pTag == NULL) {
  428. soLogMsg(SOLM_ERROR, "Failed to find closing paren");
  429. return NULL;
  430. }
  431. pTag++;
  432. uTagSize = (UINT)(pTag - pTagName);
  433. fUseFieldOffset = FALSE;
  434. break;
  435. }
  436. } /* if (uTags == 1) */
  437. /*
  438. * If this is followed by a terminator, this must be the field name
  439. */
  440. } while ( (*pNextTag != ';') && (*pNextTag != '[')
  441. && (*pNextTag != '}') && (*pNextTag != ':'));
  442. if (pTag >= pTagEnd) {
  443. return pTag;
  444. }
  445. fBitField = (*pNextTag == ':');
  446. fArray = (*pNextTag == '[');
  447. /*
  448. * Cannot use FIELD_OFFSET on bit fields or unamed structs
  449. */
  450. fUseFieldOffset &= (!fBitField && (uTags > uTagsToName));
  451. /*
  452. * If this is a bit field, make the size be part of the name
  453. */
  454. if (fBitField) {
  455. pNextTag = soSkipBlanks(pNextTag + 1, pTagEnd);
  456. if (pNextTag == NULL) {
  457. soLogMsg(SOLM_ERROR, "Failed to get bit field size");
  458. return NULL;
  459. }
  460. pNextTag = soSkipIdentifier(pNextTag + 1, pTagEnd);
  461. if (pNextTag == NULL) {
  462. soLogMsg(SOLM_ERROR, "Failed to skip bit field size");
  463. return NULL;
  464. }
  465. uTagSize = (UINT)(pNextTag - pTagName);
  466. }
  467. /*
  468. * Copy field name
  469. */
  470. pszFieldName = soCopyTagName (pTagName, uTagSize);
  471. if (pszFieldName == NULL) {
  472. return NULL;
  473. }
  474. if (fUseFieldOffset) {
  475. /*
  476. * Use FIELD_OFFSET macro
  477. */
  478. if (!soWriteFile(pwf->hfileOutput, gszStructFieldOffsetFmt, pszFieldName, pfi->pszStructName, pszFieldName)) {
  479. return NULL;
  480. }
  481. } else {
  482. /*
  483. * If this is the first field or if this is a bit field
  484. * preceded by another bit field
  485. */
  486. if ((pfi->pType == NULL)
  487. || (fBitField && (pfi->dwFlags & SOFI_BIT))) {
  488. /*
  489. * Write 0 or the mask to signal a 0 relative offset from
  490. * the previous field
  491. */
  492. if (!soWriteFile(pwf->hfileOutput, gszStructAbsoluteOffsetFmt, pszFieldName,
  493. ((pfi->dwFlags & SOFI_BIT) ? 0x80000000 : 0))) {
  494. return NULL;
  495. }
  496. } else {
  497. /*
  498. * Write a relative offset from the previous field
  499. * Copy type name if not done already
  500. */
  501. if (!(pfi->dwFlags & SOFI_ALLOCATED)) {
  502. pfi->pType = soCopyTagName (pfi->pType, pfi->uTypeSize);
  503. if (pfi->pType == NULL) {
  504. return NULL;
  505. }
  506. pfi->dwFlags |= SOFI_ALLOCATED;
  507. }
  508. /*
  509. * If the last field was NOT an array
  510. */
  511. if (!(pfi->dwFlags & SOFI_ARRAY)) {
  512. if (!soWriteFile(pwf->hfileOutput, gszStructRelativeOffsetFmt, pszFieldName, pfi->pType)) {
  513. return NULL;
  514. }
  515. } else {
  516. /*
  517. * Copy the array size if not done already
  518. */
  519. if (!(pfi->dwFlags & SOFI_ARRAYALLOCATED)) {
  520. pfi->pArray = soCopyTagName (pfi->pArray, pfi->uArraySize);
  521. if (pfi->pArray == NULL) {
  522. return NULL;
  523. }
  524. pfi->dwFlags |= SOFI_ARRAYALLOCATED;
  525. }
  526. if (!soWriteFile(pwf->hfileOutput, gszStructArrayRelativeOffsetFmt, pszFieldName, pfi->pType, pfi->pArray)) {
  527. return NULL;
  528. }
  529. } /* if ((pfi->pType == NULL) || (pfi->dwFlags & SOFI_BIT)) */
  530. }
  531. } /* if (fUseFieldOffset) */
  532. /*
  533. * Save the field info wich migth be needed to calculate the offset
  534. * to following fields. See gszStruct*RelativeOffsetFmt.
  535. */
  536. soFreepfiPointers(pfi);
  537. pfi->dwFlags = 0;
  538. if (fBitField) {
  539. /*
  540. * LATER: Let's see how long we can get away with assuming that
  541. * bit fields take a DWORD. This only matters when a !fUseFieldOffset
  542. * is preceded by a bit field.
  543. */
  544. pfi->dwFlags = SOFI_BIT;
  545. pfi->pType = gszdword;
  546. pfi->uTypeSize = sizeof(gszdword) - 1;
  547. } else {
  548. pfi->pType = pType;
  549. pfi->uTypeSize = uTypeSize;
  550. if (fArray) {
  551. pfi->dwFlags = SOFI_ARRAY;
  552. if (!soFindBlock (pNextTag, pwf->pmapEnd, "[]", &block)) {
  553. return NULL;
  554. }
  555. if (block.pBegin + 1 >= block.pEnd) {
  556. soLogMsg(SOLM_ERROR, "Missing array size", pfi->pszStructName, pszFieldName);
  557. return NULL;
  558. }
  559. pfi->pArray = pNextTag + 1;
  560. pfi->uArraySize = (UINT)(block.pEnd - block.pBegin - 1);
  561. }
  562. } /* if (fBitField) */
  563. LocalFree(pszFieldName);
  564. /*
  565. * Move past the end of this field
  566. */
  567. pTag = soFindChar (pTagName + 1, pwf->pmapEnd, ';');
  568. if (pTag == NULL) {
  569. soLogMsg(SOLM_ERROR, "Failed to find ';' after field name");
  570. return NULL;
  571. }
  572. pTag++;
  573. return pTag;
  574. soLogMsg(SOLM_ERROR, ". Struct:%s Field:%s", pfi->pszStructName, pszFieldName);
  575. }
  576. /*********************************************************************
  577. * soParseStruct
  578. \***************************************************************************/
  579. char * soParseStruct (PWORKINGFILES pwf)
  580. {
  581. BLOCK block;
  582. char * pTag, ** ppszStruct;
  583. FIELDINFO fi;
  584. PSTRUCTLIST psl;
  585. if (!soGetBlockName(pwf->pmap, pwf->pmapEnd, &block)) {
  586. return NULL;
  587. }
  588. /*
  589. * If there was no block (the structure body is not here), done
  590. */
  591. if (block.pBegin == block.pEnd) {
  592. return block.pBegin;
  593. }
  594. /*
  595. * Fail if no name.
  596. */
  597. if (block.pName == NULL) {
  598. soLogMsg(SOLM_ERROR, "Failed to get structure name");
  599. return NULL;
  600. }
  601. /*
  602. * If there is a struct list, check if in the list
  603. * If in the list, check that we haven't found it already.
  604. * If not in the list, done.
  605. */
  606. if (pwf->psl != NULL) {
  607. psl = soGetStructListEntry(block.pName, block.uNameSize, pwf->psl);
  608. if (psl != NULL) {
  609. if (psl->uCount > 1) {
  610. soLogMsg(SOLM_ERROR, "Struct %s already defined", psl->pszName);
  611. return NULL;
  612. }
  613. } else {
  614. return block.pEnd;
  615. }
  616. }
  617. /*
  618. * Make a null terminated string for the name.
  619. */
  620. ZeroMemory(&fi, sizeof(fi));
  621. fi.pszStructName = soCopyTagName (block.pName, block.uNameSize);
  622. if (fi.pszStructName == NULL) {
  623. return NULL;
  624. }
  625. /*
  626. * If building list only, done
  627. */
  628. if (pwf->dwOptions & SOWF_LISTONLY) {
  629. if (!soWriteFile(pwf->hfileOutput, "%s\r\n", fi.pszStructName)) {
  630. goto CleanupAndFail;
  631. }
  632. goto DoneWithThisOne;
  633. }
  634. /*
  635. * Write structure offsets table definition and entry in strucutres table
  636. */
  637. if (!soWriteFile(pwf->hfileOutput, gszStructDefFmt, gszStructDef, fi.pszStructName, gszStructBegin)) {
  638. goto CleanupAndFail;
  639. }
  640. if (!soWriteFile(pwf->hfileTemp, gszTableEntryFmt, fi.pszStructName, fi.pszStructName, fi.pszStructName)) {
  641. goto CleanupAndFail;
  642. }
  643. /*
  644. * Parse the fields
  645. */
  646. pTag = block.pBegin + 1;
  647. while (pTag < block.pEnd) {
  648. pTag = soParseField (pwf, &fi, pTag, block.pEnd);
  649. if (pTag == NULL) {
  650. goto CleanupAndFail;
  651. }
  652. }
  653. /*
  654. * Write structure last record and end
  655. */
  656. if (!soWriteFile(pwf->hfileOutput, "%s%s%s", gszStructLastRecord, fi.pszStructName, gszStructEnd)) {
  657. goto CleanupAndFail;
  658. }
  659. DoneWithThisOne:
  660. (pwf->uTablesCount)++;
  661. LocalFree(fi.pszStructName);
  662. soFreepfiPointers(&fi);
  663. /*
  664. * Move past the end of the structure
  665. */
  666. pTag = soFindChar(block.pName + block.uNameSize, pwf->pmapEnd, ';');
  667. return (pTag != NULL ? pTag + 1 : NULL);
  668. CleanupAndFail:
  669. LocalFree(fi.pszStructName);
  670. soFreepfiPointers(&fi);
  671. return NULL;
  672. }