Leaked source code of windows server 2003
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.

1403 lines
40 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: hsparse.c
  3. *
  4. * Copyright (c) 1985-96, Microsoft Corporation
  5. *
  6. * 09/05/96 GerardoB Created
  7. \***************************************************************************/
  8. #include "hsplit.h"
  9. /***************************************************************************\
  10. * Globals
  11. \***************************************************************************/
  12. /*
  13. * #if - #endif strings
  14. * Compatibility: no space after #if and ( -- breaks wcshdr.exe
  15. */
  16. static char gszIfStart [] = "\r\n#if(" ;
  17. static char gszIfStop [] = ")";
  18. static char gszDefCompOperator [] = ">=";
  19. static char gszLessThan [] = "<";
  20. static char gszEndStart [] = "\r\n#endif /* ";
  21. static char gszEndStop [] = " */";
  22. static char gszNewLine [] = "\r\n";
  23. /*********************************************************************
  24. * hsWriteNewLine
  25. \***************************************************************************/
  26. __inline BOOL hsWriteNewLine (DWORD dwMask)
  27. {
  28. return hsWriteHeaderFiles(gszNewLine, sizeof(gszNewLine)-1, dwMask);
  29. }
  30. /***************************************************************************\
  31. * hsFindFirstSubTag
  32. \***************************************************************************/
  33. char * hsFindFirstSubTag(char * pmap)
  34. {
  35. /*
  36. * pmap points to the beginning of the tag marker. So skip it
  37. * and any spaces after it
  38. */
  39. pmap += gdwTagMarkerSize;
  40. while (pmap < gpmapEnd) {
  41. if (*pmap == ' ') {
  42. pmap++;
  43. } else {
  44. return pmap;
  45. }
  46. }
  47. hsLogMsg(HSLM_EOFERROR, "hsFindFirstSubTag");
  48. return NULL;
  49. }
  50. /*********************************************************************
  51. * hsFindFirstCharInString
  52. *
  53. * Finds the first occurrence of any character in psz
  54. \***************************************************************************/
  55. char * hsFindFirstCharInString (char * pmap, char * psz)
  56. {
  57. char * pszNext;
  58. while (pmap < gpmapEnd) {
  59. /*
  60. * Compare current char to all chars in psz
  61. */
  62. pszNext = psz;
  63. do {
  64. if (*pmap == *pszNext++) {
  65. return pmap;
  66. }
  67. } while (*pszNext != '\0');
  68. pmap++;
  69. }
  70. return NULL;
  71. }
  72. /*********************************************************************
  73. * hsFindEndOfString
  74. \***************************************************************************/
  75. __inline char * hsFindEndOfString (char * pmap)
  76. {
  77. return hsFindFirstCharInString(pmap, " " "\r");
  78. }
  79. /***************************************************************************\
  80. * hsIsString
  81. \***************************************************************************/
  82. BOOL hsIsString (char * pmap, char * psz)
  83. {
  84. while (*psz != '\0') {
  85. if (pmap >= gpmapEnd) {
  86. return FALSE;
  87. }
  88. if (*pmap++ != *psz++) {
  89. return FALSE;
  90. }
  91. }
  92. return TRUE;
  93. }
  94. /***************************************************************************\
  95. * hsFindTagMarker
  96. \***************************************************************************/
  97. char * hsFindTagMarker(char * pmap, char ** ppmapLineStart)
  98. {
  99. char * pmapMarker;
  100. while (pmap < gpmapEnd) {
  101. /*
  102. * If this is the first character of the marker
  103. */
  104. if (*pmap == *gpszTagMarker) {
  105. /*
  106. * If this is the marker, find the last one in this line
  107. */
  108. if (hsIsString(pmap + 1, gpszTagMarker + 1)) {
  109. pmapMarker = pmap++;
  110. do {
  111. /*
  112. * Find the EOL or the first char of the next marker
  113. */
  114. pmap = hsFindFirstCharInString(pmap, gszMarkerCharAndEOL);
  115. /*
  116. * If EOL or end of map, return
  117. */
  118. if ((pmap == NULL) || (*pmap != *gpszTagMarker)) {
  119. return pmapMarker;
  120. }
  121. /*
  122. * If this is the marker, update pmapMarker
  123. */
  124. if (hsIsString(pmap + 1, gpszTagMarker + 1)) {
  125. pmapMarker = pmap;
  126. }
  127. /*
  128. * It wasn't a marker, keep looking for EOL
  129. */
  130. pmap++;
  131. } while (TRUE);
  132. } else {
  133. /*
  134. * This wasn't the marker, continue parsing
  135. */
  136. pmap++;
  137. continue;
  138. }
  139. } /* if (*pmap == *gpszTagMarker) */
  140. /*
  141. * If this is the end of a line, update *ppmapLineStart and
  142. * gdwLineNumber. The line begins before the EOL
  143. */
  144. if (*pmap++ == '\r') {
  145. if (pmap >= gpmapEnd) {
  146. hsLogMsg(HSLM_EOFERROR, "hsFindTagMarker");
  147. return NULL;
  148. }
  149. if (*pmap++ != '\n') {
  150. hsLogMsg(HSLM_ERROR, "Missing \\n after \\r");
  151. return FALSE;
  152. }
  153. *ppmapLineStart = pmap - 2;
  154. gdwLineNumber++;
  155. continue;
  156. }
  157. } /* while (pmap < pmapEnd) */
  158. return NULL;
  159. }
  160. /***************************************************************************\
  161. * hsSkipTag
  162. \***************************************************************************/
  163. char * hsSkipTag(char * pmap)
  164. {
  165. while (pmap < gpmapEnd) {
  166. switch (*pmap) {
  167. case '_':
  168. case ' ':
  169. case '\r':
  170. return pmap;
  171. default:
  172. pmap++;
  173. }
  174. }
  175. hsLogMsg(HSLM_EOFERROR, "hsSkipTag");
  176. return NULL;
  177. }
  178. /***************************************************************************\
  179. * hsSkipEmptyLines
  180. * If there are multiple empty lines, skip all but one
  181. \***************************************************************************/
  182. char * hsSkipEmptyLines(char * pmap)
  183. {
  184. char * pmapCurrentLine, *pmapLastEmptyLine;
  185. pmapCurrentLine = pmapLastEmptyLine = pmap;
  186. pmap++;
  187. while (pmap < gpmapEnd) {
  188. switch (*pmap) {
  189. case '\r':
  190. gdwLineNumber++;
  191. pmapLastEmptyLine = pmapCurrentLine;
  192. pmapCurrentLine = pmap;
  193. case '\n':
  194. case ' ':
  195. pmap++;
  196. break;
  197. default:
  198. /*
  199. * If we've found more than one line,
  200. * adjust line number since we're not skipping
  201. * the last line we found
  202. */
  203. if (pmapCurrentLine != pmapLastEmptyLine) {
  204. gdwLineNumber--;
  205. }
  206. return pmapLastEmptyLine;
  207. }
  208. }
  209. return gpmapEnd;
  210. }
  211. /***************************************************************************\
  212. * hsIsEmpty
  213. * Returns TRUE if there is nothing but spaces and \r\n
  214. \***************************************************************************/
  215. BOOL hsIsEmpty(char * pmap, char * pmapEnd)
  216. {
  217. while (pmap < pmapEnd) {
  218. switch (*pmap++) {
  219. case '\n':
  220. case '\r':
  221. case ' ':
  222. break;
  223. default:
  224. return FALSE;
  225. }
  226. }
  227. return TRUE;
  228. }
  229. /***************************************************************************\
  230. * hsLastRealChar
  231. * Returns a pointer past the last non-space non-line-break char.
  232. * If there are multiple empty lines, returns a pointer past the last line break
  233. \***************************************************************************/
  234. char * hsLastRealChar(char * pmapLinesStart, char * pmap)
  235. {
  236. char * pmapCurrentLine, *pmapLastEmptyLine;
  237. pmap--;
  238. pmapCurrentLine = pmapLastEmptyLine = NULL;
  239. while (pmapLinesStart < pmap) {
  240. switch (*pmap) {
  241. case '\n':
  242. pmapLastEmptyLine = pmapCurrentLine;
  243. pmapCurrentLine = pmap;
  244. case '\r':
  245. case ' ':
  246. pmap--;
  247. break;
  248. default:
  249. goto FoundIt;
  250. }
  251. }
  252. FoundIt:
  253. /*
  254. * If we found multiple lines or spaces,
  255. * then return a pointer to the last empty line
  256. * else if we didn't reach pmapLinesStart, we're at the last real char
  257. * else we're on an empty line
  258. */
  259. if (pmapLastEmptyLine != pmapCurrentLine) {
  260. if (pmapLastEmptyLine != NULL) {
  261. return pmapLastEmptyLine + 1;
  262. } else {
  263. return pmapCurrentLine + 1;
  264. }
  265. } else if (pmap > pmapLinesStart) {
  266. return pmap + 1;
  267. } else {
  268. return pmapLinesStart;
  269. }
  270. }
  271. /***************************************************************************\
  272. * hsFindEOL
  273. *
  274. \***************************************************************************/
  275. char * hsFindEOL(char * pmap)
  276. {
  277. while (pmap < gpmapEnd) {
  278. if (*pmap++ == '\r') {
  279. if (pmap >= gpmapEnd) {
  280. hsLogMsg(HSLM_EOFERROR, "hsFindEOL");
  281. return NULL;
  282. }
  283. if (*pmap != '\n') {
  284. hsLogMsg(HSLM_ERROR, "Missing \\n after \\r");
  285. return NULL;
  286. }
  287. gdwLineNumber++;
  288. return pmap - 1;
  289. }
  290. }
  291. return NULL;
  292. }
  293. /***************************************************************************\
  294. * hsFindTagInList
  295. *
  296. \***************************************************************************/
  297. PHSTAG hsFindTagInList (PHSTAG phst, char * pmapTag, DWORD dwTagSize)
  298. {
  299. while (phst->dwLabelSize != 0) {
  300. if ((phst->dwLabelSize == dwTagSize)
  301. && !_strnicmp(phst->pszLabel, pmapTag, dwTagSize)) {
  302. return phst;
  303. }
  304. phst++;
  305. }
  306. return NULL;
  307. }
  308. /***************************************************************************\
  309. * hsSkipBlockTagIfPresent
  310. *
  311. \***************************************************************************/
  312. char * hsSkipBlockTagIfPresent (char * pmap, DWORD * pdwMask)
  313. {
  314. static char gszBegin [] = "begin";
  315. static char gszEnd [] = "end";
  316. char * pmapTag;
  317. DWORD dwTagSize;
  318. PHSTAG phst;
  319. /*
  320. * Remember the beginning of the tag
  321. */
  322. pmapTag = pmap;
  323. /*
  324. * Compatibility. Deal with old lt? and bt? switches.
  325. * If the whole tag was added to the tag list, get the flags
  326. * and stop parsing.
  327. */
  328. if (gdwOptions & (HSO_USERBLOCK | HSO_USERHEADERTAG)) {
  329. pmap = hsFindEndOfString(pmap);
  330. if ((pmap != NULL) && (pmap != pmapTag)) {
  331. phst = hsFindTagInList (gphst, pmapTag, (DWORD)(pmap - pmapTag));
  332. if (phst != NULL) {
  333. *pdwMask |= phst->dwMask;
  334. return pmap;
  335. }
  336. }
  337. /*
  338. * Didn't find the string in the table so restore pmap and continue
  339. */
  340. pmap = pmapTag;
  341. }
  342. /*
  343. * Find the end of the current tag
  344. */
  345. pmap = hsSkipTag(pmap);
  346. if ((pmap == NULL) || (pmap == pmapTag)) {
  347. return pmap;
  348. }
  349. dwTagSize = (DWORD)(pmap - pmapTag);
  350. /*
  351. * If at separator, skip so the caller won't have to deal with it
  352. */
  353. if (*pmap == '_') {
  354. pmap++;
  355. }
  356. /*
  357. * begin tag
  358. */
  359. if ((HSCSZSIZE(gszBegin) == dwTagSize)
  360. && !_strnicmp(gszBegin, pmapTag, dwTagSize)) {
  361. *pdwMask |= HST_BEGIN;
  362. return pmap;
  363. }
  364. /*
  365. * end tag
  366. */
  367. if ((HSCSZSIZE(gszEnd) == dwTagSize)
  368. && !_strnicmp(gszEnd, pmapTag, dwTagSize)) {
  369. *pdwMask |= HST_END;
  370. return pmap;
  371. }
  372. return pmapTag;
  373. }
  374. /***************************************************************************\
  375. * hsPopBlock
  376. *
  377. \***************************************************************************/
  378. BOOL hsPopBlock (void)
  379. {
  380. /*
  381. * Check for underflow
  382. */
  383. if (gphsbStackTop <= ghsbStack) {
  384. hsLogMsg(HSLM_ERROR, "Block stack underflow!");
  385. return FALSE;
  386. }
  387. if (gphsbStackTop->pszifLabel != NULL) {
  388. LocalFree(gphsbStackTop->pszifLabel);
  389. }
  390. gphsbStackTop--;
  391. return TRUE;
  392. }
  393. /***************************************************************************\
  394. * hsPushBlock
  395. *
  396. \***************************************************************************/
  397. BOOL hsPushBlock(void)
  398. {
  399. /*
  400. * Make sure we got room in the block stack
  401. */
  402. if (gphsbStackTop >= HSBSTACKLIMIT) {
  403. hsLogMsg(HSLM_ERROR, "Too many nested blocks. Artificial limit:%#lx", HSBSTACKSIZE);
  404. return FALSE;
  405. }
  406. /*
  407. * Grow the stack and initialize the new entry
  408. */
  409. gphsbStackTop++;
  410. ZeroMemory(gphsbStackTop, sizeof(*gphsbStackTop));
  411. gphsbStackTop->dwLineNumber = gdwLineNumber;
  412. /*
  413. * propagate the mask
  414. */
  415. gphsbStackTop->dwMask |= (gphsbStackTop - 1)->dwMask;
  416. return TRUE;
  417. }
  418. /***************************************************************************\
  419. * hsSkipBlock
  420. *
  421. \***************************************************************************/
  422. char * hsSkipBlock(char * pmap)
  423. {
  424. char * pmapLineStart;
  425. DWORD dwMask;
  426. while (pmap < gpmapEnd) {
  427. /*
  428. * Find the next marker (; by default)
  429. */
  430. pmap = hsFindTagMarker(pmap, &pmapLineStart);
  431. if (pmap == NULL) {
  432. return NULL;
  433. }
  434. /*
  435. * Skip the marker and any spaces after it
  436. */
  437. pmap = hsFindFirstSubTag(pmap);
  438. if (pmap == NULL) {
  439. return NULL;
  440. }
  441. /*
  442. * Check if this is the beginning-end of a block
  443. */
  444. dwMask = 0;
  445. pmap = hsSkipBlockTagIfPresent(pmap, &dwMask);
  446. if (pmap == NULL) {
  447. return NULL;
  448. }
  449. /*
  450. * If it found the beginning of another block, push it in the
  451. * the stack and skip it.
  452. */
  453. if (dwMask & HST_BEGIN) {
  454. if (!hsPushBlock()) {
  455. return NULL;
  456. }
  457. pmap = hsSkipBlock(pmap);
  458. if (pmap == NULL) {
  459. return NULL;
  460. }
  461. } else if (dwMask & HST_END) {
  462. /*
  463. * It found the end of the block; pop it out of the stack
  464. * and return the beginning of the next line
  465. */
  466. if (!hsPopBlock()) {
  467. return NULL;
  468. }
  469. return hsFindEOL(pmap);
  470. }
  471. /*
  472. * It wasn't a block tag so keep going
  473. */
  474. pmap++;
  475. }
  476. return NULL;
  477. }
  478. /***************************************************************************\
  479. * hsBuildifString
  480. *
  481. \***************************************************************************/
  482. BOOL hsBuildifString(char * pString, DWORD dwStringSize, char * pCompOperator, DWORD dwCompOperatorSize)
  483. {
  484. char * psz;
  485. /*
  486. * Use default operator if none was provided.
  487. */
  488. if (pCompOperator == NULL) {
  489. pCompOperator = gszDefCompOperator;
  490. dwCompOperatorSize = HSCSZSIZE(gszDefCompOperator);
  491. }
  492. /*
  493. * Make a NULL terminated copy. Allocate enough space for the
  494. * "label CompOperator version" string: 2 spaces + 10 digits (0xl#) +
  495. * null termination
  496. */
  497. psz = (char *) LocalAlloc(LPTR, dwStringSize + dwCompOperatorSize + 13);
  498. if (psz == NULL) {
  499. hsLogMsg(HSLM_APIERROR, "LocalAlloc");
  500. hsLogMsg(HSLM_ERROR, "hsBuildifString allocation failed. Size:%#lx", dwStringSize+ dwCompOperatorSize + 13);
  501. return FALSE;
  502. }
  503. /*
  504. * Save it in the stack.
  505. */
  506. gphsbStackTop->pszifLabel = psz;
  507. /*
  508. * Build the string (the right side of the comparison (version) will
  509. * be added later when available.
  510. */
  511. strncpy(psz, pString, dwStringSize);
  512. psz += dwStringSize;
  513. *psz++ = ' ';
  514. strncpy(psz, pCompOperator, dwCompOperatorSize);
  515. psz += dwCompOperatorSize;
  516. *psz++ = ' ';
  517. return TRUE;
  518. }
  519. /***************************************************************************\
  520. * hsParseAndBuildifString
  521. *
  522. \***************************************************************************/
  523. char * hsParseAndBuildifString(char * pmap, BOOL fSkip)
  524. {
  525. BOOL fEnclosed;
  526. char * pmapTag, * pCompOperator;
  527. DWORD dwTagSize, dwCompOperatorSize;
  528. /*
  529. * Skip the tag concatenator (_)
  530. */
  531. if (*pmap++ != '_') {
  532. hsLogMsg(HSLM_ERROR, "Expected '_' after if tag");
  533. return NULL;
  534. }
  535. if (pmap >= gpmapEnd) {
  536. hsLogMsg(HSLM_EOFERROR, "hsParseAndBuildifString");
  537. return NULL;
  538. }
  539. /*
  540. * Find the end of the string. If it starts wiht '(', then the string
  541. * is enclosed in parens. This is for strings that use _ (like _WIN32_WINDOWS)
  542. */
  543. pmapTag = pmap;
  544. fEnclosed = (*pmap == '(');
  545. if (fEnclosed) {
  546. pmapTag = ++pmap;
  547. pmap = hsFindFirstCharInString(pmap, ")" " " "\r");
  548. if ((pmap == NULL) || (*pmap != ')')) {
  549. hsLogMsg(HSLM_ERROR, "Expected ')' after if_(");
  550. return NULL;
  551. }
  552. } else {
  553. pmap = hsSkipTag(pmap);
  554. if ((pmap == NULL) || (pmap == pmapTag)) {
  555. hsLogMsg(HSLM_ERROR, "Expected string after if_");
  556. return NULL;
  557. }
  558. }
  559. dwTagSize = (DWORD)(pmap - pmapTag);
  560. /*
  561. * Skip the ')'
  562. */
  563. if (fEnclosed) {
  564. pmap++;
  565. if (pmap >= gpmapEnd) {
  566. hsLogMsg(HSLM_EOFERROR, "hsParseAndBuildifString");
  567. return NULL;
  568. }
  569. }
  570. /*
  571. * If a comparison operator follows, use it
  572. */
  573. if ((pmap + 1 < gpmapEnd) && (*pmap == '_')) {
  574. switch (*(pmap + 1)) {
  575. case '=':
  576. case '>':
  577. case '<':
  578. pCompOperator = ++pmap;
  579. pmap = hsSkipTag(pmap);
  580. if ((pmap == NULL) || (pmap == pCompOperator)) {
  581. hsLogMsg(HSLM_EOFERROR, "hsParseAndBuildifString");
  582. return NULL;
  583. }
  584. dwCompOperatorSize = (DWORD)(pmap - pCompOperator);
  585. break;
  586. default:
  587. pCompOperator = NULL;
  588. break;
  589. }
  590. }
  591. /*
  592. * Build the stirng a copy it into the block stack
  593. */
  594. if (!fSkip) {
  595. if (!hsBuildifString(pmapTag, (DWORD)dwTagSize, pCompOperator, (DWORD)dwCompOperatorSize)) {
  596. return NULL;
  597. }
  598. }
  599. return pmap;
  600. }
  601. /***************************************************************************\
  602. * hsMapOldTag
  603. *
  604. \***************************************************************************/
  605. BOOL hsMapOldTag(char * pmapTag, DWORD dwTagSize, DWORD * pdwTagMask, DWORD * pdwVersion)
  606. {
  607. static char gszifWinver [] = "WINVER";
  608. static char gszif_WIN32_WINDOWS [] = "_WIN32_WINDOWS";
  609. static char gszif_WIN32_WINNT [] = "_WIN32_WINNT";
  610. char * pszLabel;
  611. UINT uSize;
  612. /*
  613. * Old tags must have a block or header bit set. Otherwise, they
  614. * should be ignored
  615. */
  616. if (!(*pdwTagMask & (HST_BOTH | HST_BLOCK))) {
  617. *pdwTagMask |= HST_IGNORE;
  618. return TRUE;
  619. }
  620. /*
  621. * No mapping needed if at the end of a block or HST_SKIP is the only
  622. * additional flag set.
  623. */
  624. if ((*pdwTagMask & HST_END)
  625. || ((*pdwTagMask & ~(HST_BLOCK | HST_USERBLOCK | HST_BOTH | HST_USERHEADERTAG))
  626. == (HST_SKIP | HST_MAPOLD))) {
  627. return TRUE;
  628. }
  629. /*
  630. * winver maps to if_winver
  631. */
  632. if (*pdwTagMask & HST_WINVER) {
  633. /*
  634. * Compatibility
  635. */
  636. if (!(gdwOptions & HSO_OLDPROJSW_4)
  637. && (*pdwTagMask & HST_INTERNAL)
  638. && !(gdwOptions & HSO_OLDPROJSW_E)) {
  639. *pdwTagMask |= HST_SKIP;
  640. return TRUE;
  641. }
  642. pszLabel = gszifWinver;
  643. uSize = HSCSZSIZE(gszifWinver);
  644. goto AddIf;
  645. }
  646. /*
  647. * nashville maps to if_(_WIN32_WINDOWS)_40a
  648. */
  649. if ((dwTagSize == HSCSZSIZE(gszNashville)) && !_strnicmp(pmapTag, gszNashville, dwTagSize)) {
  650. *pdwVersion = 0x40a;
  651. pszLabel = gszif_WIN32_WINDOWS;
  652. uSize = HSCSZSIZE(gszif_WIN32_WINDOWS);
  653. goto AddIf;
  654. }
  655. /*
  656. * sur and surplus map to if_(_WIN32_WINNT)_400 if public
  657. */
  658. if ((dwTagSize == HSCSZSIZE(gszSur)) && !_strnicmp(pmapTag, gszSur, dwTagSize)
  659. || (dwTagSize == HSCSZSIZE(gszSurplus)) && !_strnicmp(pmapTag, gszSurplus, dwTagSize)) {
  660. if (*pdwTagMask & HST_INTERNAL) {
  661. return TRUE;
  662. }
  663. *pdwVersion = 0x400;
  664. pszLabel = gszif_WIN32_WINNT;
  665. uSize = HSCSZSIZE(gszif_WIN32_WINNT);
  666. goto AddIf;
  667. }
  668. /*
  669. * 35 is excluded when building for old switch e and p
  670. */
  671. if ((dwTagSize == HSCSZSIZE(gsz35)) && !_strnicmp(pmapTag, gsz35, dwTagSize)) {
  672. *pdwTagMask |= HST_SKIP;
  673. return TRUE;
  674. }
  675. return TRUE;
  676. AddIf:
  677. *pdwTagMask |= HST_IF;
  678. /*
  679. * If we're not in a block, push one to save the string
  680. */
  681. if (!(*pdwTagMask & HST_BEGIN)) {
  682. if (!hsPushBlock()) {
  683. return FALSE;
  684. }
  685. }
  686. if (!hsBuildifString(pszLabel, uSize, NULL, 0)) {
  687. return FALSE;
  688. }
  689. return TRUE;
  690. }
  691. /***************************************************************************\
  692. * hsParseTag
  693. *
  694. \***************************************************************************/
  695. DWORD hsParseTag(char * pmap, DWORD * pdwVersion)
  696. {
  697. char * pmapTag;
  698. DWORD dwTagMask = HST_DEFAULT;
  699. DWORD dwTagSize;
  700. PHSTAG phst;
  701. *pdwVersion = 0;
  702. /*
  703. * Skip the marker and any spaces after it
  704. */
  705. pmap = hsFindFirstSubTag(pmap);
  706. if (pmap == NULL) {
  707. return HST_DEFAULT;
  708. }
  709. /*
  710. * Check for begin-end of block
  711. */
  712. pmap = hsSkipBlockTagIfPresent(pmap, &dwTagMask);
  713. if (pmap == NULL) {
  714. return HST_DEFAULT;
  715. }
  716. /*
  717. * If this the beginning of a block, push in the stack
  718. * skip the tag concatenator (_)
  719. */
  720. if (dwTagMask & HST_BEGIN) {
  721. if (!hsPushBlock()) {
  722. return HST_ERROR;
  723. }
  724. }
  725. /*
  726. * Build tag mask. Tags are concatenated by underscores (_); each
  727. * iteration of this loop processes one "sub-tag"
  728. */
  729. do {
  730. /*
  731. * Find current tag end. Bail if at last one.
  732. */
  733. pmapTag = pmap;
  734. pmap = hsSkipTag(pmap);
  735. if ((pmap == NULL) || (pmap == pmapTag)) {
  736. break;
  737. }
  738. /*
  739. * Look up the tag
  740. */
  741. dwTagSize = (DWORD)(pmap - pmapTag);
  742. phst = hsFindTagInList (gphst, pmapTag, dwTagSize);
  743. if (phst != NULL) {
  744. dwTagMask |= phst->dwMask;
  745. /*
  746. * Compatibility
  747. * If this is an old tag, map it.
  748. * No mapping needed if doing split only (tag is going to be
  749. * ignored)
  750. */
  751. if ((dwTagMask & HST_MAPOLD)
  752. && !(gdwOptions & HSO_SPLITONLY)) {
  753. if (!hsMapOldTag(pmapTag, dwTagSize, &dwTagMask, pdwVersion)) {
  754. return HST_ERROR;
  755. }
  756. } else {
  757. /*
  758. * If this is an if tag, copy the block string
  759. */
  760. if (phst->dwMask & HST_IF) {
  761. BOOL fEndBlock;
  762. /*
  763. * If not in a block, push a fake one in to save the string
  764. */
  765. if (!(dwTagMask & HST_BLOCK)) {
  766. if (!hsPushBlock()) {
  767. return HST_ERROR;
  768. }
  769. }
  770. /*
  771. * If we're at the end of a block, we want to skip
  772. * the if string (already taken care of at begin tag)
  773. */
  774. fEndBlock = (dwTagMask & HST_END);
  775. if (fEndBlock) {
  776. dwTagMask &= ~HST_IF;
  777. }
  778. pmap = hsParseAndBuildifString(pmap, fEndBlock);
  779. if (pmap == NULL) {
  780. return HST_ERROR;
  781. }
  782. }
  783. } /* if ((dwTagMask & HST_MAPOLD)... */
  784. } else {
  785. /*
  786. * If this is not the version number, then this is an unkown tag
  787. */
  788. if (!hsVersionFromString (pmapTag, dwTagSize, pdwVersion)) {
  789. dwTagMask |= HST_UNKNOWN;
  790. }
  791. } /* if (phst != NULL) */
  792. } while (*pmap++ == '_');
  793. /*
  794. * Bail if we didn't find any tags
  795. */
  796. if (dwTagMask == HST_DEFAULT) {
  797. return HST_DEFAULT;
  798. }
  799. /*
  800. * Unknown tags are to be skipped or ignored
  801. */
  802. if (dwTagMask & HST_UNKNOWN) {
  803. if (gdwOptions & HSO_SKIPUNKNOWN) {
  804. dwTagMask |= HST_SKIP;
  805. } else {
  806. goto IgnoreTag;
  807. }
  808. }
  809. /*
  810. * Ignore the tag if marked as such
  811. */
  812. if (dwTagMask & HST_IGNORE) {
  813. goto IgnoreTag;
  814. }
  815. /*
  816. * Compatibility hack. public_winver_40a is not included for old -n and
  817. * it's internal for old -e. 400 is goes to both headers for -n
  818. */
  819. if (dwTagMask & HST_WINVER) {
  820. if (*pdwVersion == 0x40a) {
  821. if (gdwOptions & HSO_OLDPROJSW_E) {
  822. dwTagMask |= HST_INTERNAL;
  823. dwTagMask &= ~HST_PUBLIC;
  824. } else if (gdwOptions & HSO_OLDPROJSW_N) {
  825. dwTagMask |= HST_SKIP;
  826. }
  827. } else if ((*pdwVersion == 0x400)
  828. && (gdwOptions & HSO_OLDPROJSW_N)) {
  829. dwTagMask |= HST_INTERNALNOTCOMP | HST_BOTH;
  830. }
  831. }
  832. /*
  833. * if using old lt2, ltb, bt2 or btb switches,
  834. * then both/internal tag/block must be skipped
  835. */
  836. if ((gdwOptions & (HSO_USERBLOCK | HSO_USERHEADERTAG))
  837. && !(dwTagMask & ~(HST_BLOCK | HST_BOTH))) {
  838. if ((gdwOptions & HSO_USERINTERNALBLOCK)
  839. && ((dwTagMask == (HST_BEGIN | HST_INTERNAL))
  840. || (dwTagMask == (HST_END | HST_INTERNAL)))) {
  841. dwTagMask &= HST_BLOCK;
  842. dwTagMask |= HST_SKIP;
  843. } else if ((gdwOptions & HSO_USERBOTHBLOCK)
  844. && ((dwTagMask == (HST_BEGIN | HST_BOTH))
  845. || (dwTagMask == (HST_END | HST_BOTH)))) {
  846. dwTagMask &= HST_BLOCK;
  847. dwTagMask |= HST_SKIP;
  848. } else if ((gdwOptions & HSO_USERINTERNALTAG)
  849. && (dwTagMask == HST_INTERNAL)) {
  850. dwTagMask = HST_SKIP;
  851. } else if ((gdwOptions & HSO_USERBOTHTAG)
  852. && (dwTagMask == HST_BOTH)) {
  853. dwTagMask = HST_SKIP;
  854. }
  855. } /* if ((gdwOptions & (HSO_USERBLOCK | HSO_USERHEADERTAG))... */
  856. /*
  857. * If doing split only, anything other than both/internal is treated
  858. * as untagged. If we pushed a block, pop it out as it will be ignored
  859. */
  860. if (gdwOptions & HSO_SPLITONLY) {
  861. if (dwTagMask & ~(HST_BLOCK | HST_USERBLOCK | HST_BOTH | HST_USERHEADERTAG)) {
  862. goto IgnoreTag;
  863. }
  864. *pdwVersion = 0;
  865. }
  866. /*
  867. * If this is the beginning of a block, save the mask in the block stack
  868. */
  869. if (dwTagMask & HST_BEGIN) {
  870. gphsbStackTop->dwMask |= dwTagMask;
  871. }
  872. return dwTagMask;
  873. IgnoreTag:
  874. /*
  875. * If a block was pushed, pop it out.
  876. */
  877. if (dwTagMask & HST_BEGIN) {
  878. if (!hsPopBlock()) {
  879. return HST_ERROR;
  880. }
  881. }
  882. *pdwVersion = 0;
  883. return HST_DEFAULT;
  884. }
  885. /***************************************************************************\
  886. * hsBeginEndBlock
  887. *
  888. \***************************************************************************/
  889. BOOL hsBeginEndBlock (DWORD dwMask, DWORD dwVersion)
  890. {
  891. char * psz;
  892. UINT uPasses;
  893. /*
  894. * Compatibility. If writting this block to the internal header
  895. * using the not comp (ie., from >= to <), then do two passes
  896. * writing one header each time.
  897. */
  898. if (dwMask & HST_INTERNALNOTCOMP) {
  899. uPasses = 2;
  900. if (dwMask & HST_BEGIN) {
  901. /*
  902. * Write public header first
  903. */
  904. dwMask &= ~HST_INTERNAL;
  905. } else {
  906. /*
  907. * Write internal header first
  908. */
  909. dwMask &= ~HST_PUBLIC;
  910. }
  911. } else {
  912. uPasses = 1;
  913. }
  914. /*
  915. * Add version to the string
  916. */
  917. if (dwMask & HST_BEGIN) {
  918. /*
  919. * Beginning of block or if
  920. * If there is no if string, done
  921. */
  922. if (gphsbStackTop->pszifLabel == NULL) {
  923. return TRUE;
  924. }
  925. /*
  926. * Something is fishy is dwVersion is 0
  927. */
  928. if (dwVersion == 0) {
  929. hsLogMsg(HSLM_ERROR, "if tag without version");
  930. return FALSE;
  931. }
  932. sprintf(gphsbStackTop->pszifLabel + strlen(gphsbStackTop->pszifLabel),
  933. "%#06lx", dwVersion);
  934. }
  935. /*
  936. * Write headers
  937. */
  938. do {
  939. if (dwMask & HST_BEGIN) {
  940. /*
  941. * Write #if to output file
  942. */
  943. if (!hsWriteHeaderFiles(gszIfStart, HSCSZSIZE(gszIfStart), dwMask)
  944. || !hsWriteHeaderFiles(gphsbStackTop->pszifLabel, lstrlen(gphsbStackTop->pszifLabel), dwMask)
  945. || !hsWriteHeaderFiles(gszIfStop, HSCSZSIZE(gszIfStop), dwMask)) {
  946. return FALSE;
  947. }
  948. } else {
  949. /*
  950. * End of block or if
  951. * If there is an if string, Write #endif to output file
  952. */
  953. if (gphsbStackTop->pszifLabel != NULL) {
  954. if (!hsWriteHeaderFiles(gszEndStart, HSCSZSIZE(gszEndStart), dwMask)
  955. || !hsWriteHeaderFiles(gphsbStackTop->pszifLabel, lstrlen(gphsbStackTop->pszifLabel), dwMask)
  956. || !hsWriteHeaderFiles(gszEndStop, HSCSZSIZE(gszEndStop), dwMask)) {
  957. return FALSE;
  958. }
  959. }
  960. }
  961. /*
  962. * If doing a second pass, fix the mask and the string
  963. */
  964. if (uPasses > 1) {
  965. psz = gphsbStackTop->pszifLabel;
  966. if (dwMask & HST_BEGIN) {
  967. /*
  968. * Write internal header now
  969. */
  970. dwMask &= ~HST_PUBLIC;
  971. dwMask |= HST_INTERNAL;
  972. /*
  973. * From >= to <
  974. */
  975. while (*psz != '>') {
  976. psz++;
  977. }
  978. *psz++ = '<';
  979. *psz = ' ';
  980. } else {
  981. /*
  982. * Write public header now
  983. */
  984. dwMask &= ~HST_INTERNAL;
  985. dwMask |= HST_PUBLIC;
  986. /*
  987. * From < to >=
  988. */
  989. while (*psz != '<') {
  990. psz++;
  991. }
  992. *psz++ = '>';
  993. *psz = '=';
  994. }
  995. }
  996. } while (--uPasses != 0);
  997. /*
  998. * Clean up the block if at the end
  999. */
  1000. if (dwMask & HST_END) {
  1001. if (!hsPopBlock()) {
  1002. return FALSE;
  1003. }
  1004. }
  1005. return TRUE;
  1006. }
  1007. /***************************************************************************\
  1008. * hsSplit
  1009. *
  1010. \***************************************************************************/
  1011. BOOL hsSplit (void)
  1012. {
  1013. BOOL fSkip;
  1014. char * pmap, *pmapLineStart, *pmapLastLineStart, *pmapMarker, *pmapLastChar;
  1015. DWORD dwMask, dwVersion, dwPreviousMask, dwLastMask;
  1016. /*
  1017. * Initialize block stack top, map pointer, etc
  1018. */
  1019. ZeroMemory(gphsbStackTop, sizeof(*gphsbStackTop));
  1020. dwLastMask = 0;
  1021. pmap = pmapLineStart = pmapLastLineStart = gpmapStart;
  1022. gdwLineNumber = 1;
  1023. while (pmap < gpmapEnd) {
  1024. /*
  1025. * Find the marker and the line it is on
  1026. */
  1027. pmap = hsFindTagMarker(pmap, &pmapLineStart);
  1028. if (pmap == NULL) {
  1029. break;
  1030. }
  1031. /*
  1032. * Parse the tag
  1033. */
  1034. dwMask = hsParseTag(pmap, &dwVersion);
  1035. if (dwMask & HST_ERROR) {
  1036. return FALSE;
  1037. }
  1038. /*
  1039. * If this wasn't a tag (just the tag marker), continue
  1040. */
  1041. if ((dwMask == HST_DEFAULT) && (dwVersion == 0)) {
  1042. pmap++;
  1043. continue;
  1044. }
  1045. /*
  1046. * Write any previous non-empty (untagged) lines.
  1047. * If we're about to start a block, make sure to use the right mask.
  1048. */
  1049. dwPreviousMask = ((dwMask & (HST_BEGIN | HST_IF)) ? (gphsbStackTop - 1)->dwMask : gphsbStackTop->dwMask);
  1050. pmapLastChar = hsLastRealChar(pmapLastLineStart, pmapLineStart);
  1051. if (pmapLastLineStart < pmapLastChar) {
  1052. /*
  1053. * Empty lines between internal (block) tags go to the internal file
  1054. */
  1055. if (!(dwPreviousMask & HST_BOTH)
  1056. && ((dwMask & HST_BOTH) == HST_INTERNAL)
  1057. && ((dwLastMask & HST_BOTH) == HST_INTERNAL)
  1058. && hsIsEmpty(pmapLastLineStart, pmapLastChar)) {
  1059. dwPreviousMask |= HST_INTERNAL;
  1060. }
  1061. if (!hsWriteHeaderFiles(pmapLastLineStart, (DWORD)(pmapLastChar - pmapLastLineStart), dwPreviousMask)) {
  1062. return FALSE;
  1063. }
  1064. }
  1065. /*
  1066. * Determine if this tag is to be skipped.
  1067. * If we're at the END tag, then we include it since the block was
  1068. * already included.
  1069. * If gdwFilterMask contains any user-defined tags, then they must
  1070. * be present or the block is to be skipped -- note that this only
  1071. * applies for not HST_SKIP | HST_IGNORE blocks.
  1072. */
  1073. fSkip = (!(dwMask & HST_END)
  1074. && ((dwMask & HST_SKIP)
  1075. || (gdwVersion < dwVersion)
  1076. || ((gdwFilterMask & HST_USERTAGSMASK)
  1077. && ((gdwFilterMask & dwMask & HST_USERTAGSMASK) != (dwMask & HST_USERTAGSMASK)))));
  1078. /*
  1079. * If it is to be skipped, do it
  1080. */
  1081. if (fSkip) {
  1082. /*
  1083. * If it's a block, skip the marker and the skip the block
  1084. * Otherwise, skip the current line
  1085. */
  1086. if (dwMask & HST_BEGIN) {
  1087. pmap = hsSkipBlock(++pmap);
  1088. } else {
  1089. /*
  1090. * If this was an if tag with no begin-end block, pop
  1091. * the fake block out of the stack.
  1092. */
  1093. if (dwMask & HST_IF) {
  1094. if (!hsPopBlock()) {
  1095. return FALSE;
  1096. }
  1097. }
  1098. /*
  1099. * Go to the beginning of the next line.
  1100. */
  1101. pmap = hsFindEOL(pmap);
  1102. }
  1103. if (pmap == NULL) {
  1104. return TRUE;
  1105. }
  1106. goto SkipEmptyLines;
  1107. }
  1108. /*
  1109. * remember the marker position and the tag
  1110. */
  1111. pmapMarker = pmap;
  1112. dwLastMask = dwMask;
  1113. /*
  1114. * For old switch 4, internal tags go into the public header
  1115. */
  1116. if ((gdwOptions & HSO_INCINTERNAL) && ((dwMask & HST_BOTH) == HST_INTERNAL)) {
  1117. dwMask |= HST_INCINTERNAL;
  1118. if (dwMask & HST_BEGIN) {
  1119. gphsbStackTop->dwMask |= HST_INCINTERNAL;
  1120. }
  1121. }
  1122. /*
  1123. * If this is the end of a block, write the #endif statement
  1124. * else, if this is the beginning of a block or an if tag, add the
  1125. * #if statement.
  1126. */
  1127. if (dwMask & HST_END) {
  1128. if (!hsBeginEndBlock(dwMask, dwVersion)) {
  1129. return FALSE;
  1130. }
  1131. } else if (dwMask & (HST_BEGIN | HST_IF)) {
  1132. if (!hsBeginEndBlock(dwMask | HST_BEGIN, dwVersion)) {
  1133. return FALSE;
  1134. }
  1135. }
  1136. //
  1137. // Later: If we're inside a block and find a tag the needs to go to a file
  1138. // that doesn't have the ifdef, then we might want to add it to that file.
  1139. // Few issues: more than one nesting. if add #if.. make sure to add #endif when
  1140. // block ends. Also hsBeginEnd doesn't expect to get called more than once
  1141. // per block. It would append the version twice.
  1142. //
  1143. // else if ((gphsbStackTop->pszifLabel != NULL)
  1144. // && ((gphsbStackTop->dwMask & HST_BOTH) != (dwMask & HST_BOTH))) {
  1145. //
  1146. // if ((gphsbStackTop->dwMask & HST_BOTH) == HST_INTERNAL) {
  1147. // hsLogMsg(HSLM_DEFAULT, "Public. Line:%d Block line:%d", gdwLineNumber, gphsbStackTop->dwLineNumber);
  1148. // } else if (!(gphsbStackTop->dwMask & HST_INTERNAL)
  1149. // && ((dwMask & HST_BOTH) == HST_INTERNAL)) {
  1150. // hsLogMsg(HSLM_DEFAULT, "Internal. Line:%d Block line:%d", gdwLineNumber, gphsbStackTop->dwLineNumber);
  1151. // }
  1152. // }
  1153. /*
  1154. * Write the line up to the tag marker
  1155. * If the line begins with the tag marker, then there is nothing to write
  1156. * Compatibility: Don't copy any trailing spaces (breaks mc.exe).
  1157. */
  1158. if (pmapLineStart + 2 < pmapMarker) {
  1159. pmapLastChar = hsLastRealChar(pmapLineStart, pmapMarker);
  1160. if (pmapLineStart < pmapLastChar) {
  1161. if (!hsWriteHeaderFiles(pmapLineStart, (DWORD)(pmapLastChar - pmapLineStart), dwMask)) {
  1162. return FALSE;
  1163. }
  1164. }
  1165. }
  1166. /*
  1167. * If this is an if tag without a begin-end block,
  1168. * write the #endif statement
  1169. */
  1170. if ((dwMask & HST_IF) && !(dwMask & HST_BLOCK)) {
  1171. if (!hsBeginEndBlock(dwMask | HST_END, dwVersion)) {
  1172. return FALSE;
  1173. }
  1174. }
  1175. /*
  1176. * Skip the tag (go to the beginning of the next line)
  1177. */
  1178. pmap = hsFindEOL(pmapMarker);
  1179. if (pmap == NULL) {
  1180. return TRUE;
  1181. }
  1182. /*
  1183. * If including internal tags in the public header, add the tag
  1184. * as a comment.
  1185. */
  1186. if (dwMask & HST_INCINTERNAL) {
  1187. /*
  1188. * Start a new line if at the end of a block
  1189. */
  1190. if (dwMask & HST_END) {
  1191. if (!hsWriteNewLine(dwMask)) {
  1192. return FALSE;
  1193. }
  1194. }
  1195. if (!hsWriteHeaderFiles(" // ", 4, dwMask)
  1196. || !hsWriteHeaderFiles(pmapMarker, (DWORD)(pmap - pmapMarker), dwMask)) {
  1197. return FALSE;
  1198. }
  1199. }
  1200. SkipEmptyLines:
  1201. /*
  1202. * Update line pointers and move past beginning of new line
  1203. */
  1204. pmapLastLineStart = pmapLineStart = hsSkipEmptyLines(pmap);
  1205. pmap = pmapLastLineStart + 2;
  1206. } /* while (pmap < gpmapEnd) */
  1207. /*
  1208. * This is not good if we were inside a block
  1209. */
  1210. if (gphsbStackTop > ghsbStack) {
  1211. hsLogMsg(HSLM_ERROR, "Missing end block");
  1212. hsLogMsg(HSLM_ERROR | HSLM_NOLINE, "Last block Line: %d. if Label:'%s'. Mask: %#lx",
  1213. gphsbStackTop->dwLineNumber, gphsbStackTop->pszifLabel, gphsbStackTop->dwMask);
  1214. return FALSE;
  1215. }
  1216. /*
  1217. * Write last (untagged) lines to public header.
  1218. */
  1219. if (pmapLastLineStart < gpmapEnd) {
  1220. if (!hsWriteHeaderFiles(pmapLastLineStart, (DWORD)(gpmapEnd - pmapLastLineStart), HST_DEFAULT)) {
  1221. return FALSE;
  1222. }
  1223. }
  1224. /*
  1225. * Terminate the last line
  1226. */
  1227. if (!hsWriteNewLine(HST_BOTH)) {
  1228. return FALSE;
  1229. }
  1230. return TRUE;
  1231. }