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.

877 lines
23 KiB

  1. /* WCSHDR
  2. * generate UNICODE, ANSI & NEUTRAL typedefs and prototypes from a master file
  3. *
  4. * string% = string{W,A,}
  5. * LPTSTR% = {LPWSTR,LPSTR,LPTSTR}
  6. * TCHAR% = {WCHAR,CHAR,TCHAR}
  7. * LPTCH% = {LPWCH,LPCH,LPTCH}
  8. * If whitespace follows the symbol, a space is appended as required to
  9. * prevent shortening, and thus screwwing layout.
  10. *
  11. * History:
  12. * 04-Mar-1991 IanJa Wrote it.
  13. * 19-Mar-1991 IanJa Not all fgets() implementations append '\0' upon EOF.
  14. * 29-Mar-1991 IanJa Workaround NT fgets bug ("\r\n" not collapsed to "\n"),
  15. * & Command line, Usage and Version numbers added.
  16. * 13-May-1991 IanJa All neutrality achieved by #define - no neutral structs
  17. * 14-May-1991 IanJa Minor improvements to version display, help
  18. * 21-May-1991 IanJa Realloc() pbs->pStart when required
  19. * 27-May-1991 GregoryW bug fix, add LPTSTRID, LPTSTRNULL
  20. * 13-Jun-1991 IanJa Convert #define's too. Eg: #define Fn%(a) FnEx%(0, a)
  21. * 19-Jun-1991 IanJa improve #define treatment & simplify main loop
  22. * 12-Aug-1991 IanJa fix multi-line #defines, NEAR & FAR typedefs
  23. * 12-Aug-1991 IanJa fix braceless typedefs with %s; add LPTSTR2
  24. * 13-Aug-1991 IanJa add braceless typedefs #defines
  25. * 21-Aug-1991 IanJa fix string% substitutions for #defines
  26. * 21-Aug-1991 IanJa add BCHAR% -> BYTE or WCHAR as per BodinD request
  27. * 26-Aug-1991 IanJa init pbs->iType (NT-mode bug fix)
  28. * 26-Aug-1991 IanJa workaround NT fgets bug (CR LF not collapsed to NL)
  29. * 17-Nov-1992 v-griffk map #defines to typedef's on structs
  30. * for debugger support
  31. * 08-Sep-1993 IanJa add pLastParen for complex function typedefs such as
  32. * typedef BOOL ( CALLBACK * FOO% ) (BLAH% blah) ;
  33. * 24-Feb-1994 IanJa add CONV_FLUSH for blocks starting #if, #endif etc.
  34. * #if (WINVER > 0x400)
  35. * foo%(void);
  36. * #endif
  37. * 11-Nov-1994 RaymondC propagate ;internal-ness to trailers
  38. */
  39. char *Version = "WCSHDR v1.20 1994-11-11:";
  40. #include <excpt.h>
  41. #include <ntdef.h>
  42. #include <stdio.h>
  43. #include <ctype.h>
  44. #include <string.h>
  45. #include <stdlib.h>
  46. #define TRUE 1
  47. #define FALSE 0
  48. #define INITIAL_STORE_SIZE 2048
  49. #define EXTRA_STORE_SIZE 1024
  50. #define FN_NAME_SIZE 100
  51. #define CONV_NONE 0
  52. #define CONV_FN_PROTO 1
  53. #define CONV_TYPEDEF 2
  54. #define CONV_DEFINE 3
  55. #define CONV_FLUSH 4
  56. #define ASSERT(pbs, exp) if (!(exp)) AssertFail(__FILE__, __LINE__, pbs, #exp);
  57. typedef int BOOL;
  58. typedef char *PSZ;
  59. typedef struct {
  60. char *pStart; // 1st char in store
  61. char *pLastLine; // 1st char of last line in store
  62. int line; // number of lines read
  63. char *pEnd; /* '\0' at end of store */
  64. size_t cbSize;
  65. size_t cbFree;
  66. int iType; // FnPrototype, Typedef, #define or none
  67. int nParen; // nesting index: ( & { increment; ) & } decrement
  68. char *p1stParen; // Pointer to first '(' or '{' in current block.
  69. char *pLastParen; // Pointer to last '(' or '{' in current block.
  70. char *pSymNam; // copy of function name, null-terminated
  71. int cbSymNam; // bytes available for fn name
  72. char *pszInternal; // "" if external or "\t// ;internal" if internal
  73. } BLOCKSTORE, *PBLOCKSTORE;
  74. void ArgProcess(int argc, PSZ argv[]);
  75. void Usage(void);
  76. void InitBS(PBLOCKSTORE);
  77. void SetInternalnessBS(PBLOCKSTORE);
  78. BOOL ReadLineBS(PBLOCKSTORE);
  79. void WriteBS(PBLOCKSTORE);
  80. void WriteAllTypesBS(PBLOCKSTORE, int);
  81. int ConversionRequiredBS(PBLOCKSTORE);
  82. void GetSymNameBS(PBLOCKSTORE, int);
  83. BOOL WriteRedefinedTypeNamesBS(PBLOCKSTORE);
  84. void WriteConvertBS(PBLOCKSTORE, int, BOOL);
  85. void EmptyBS(PBLOCKSTORE);
  86. DECLSPEC_NORETURN void error_exit(PBLOCKSTORE pbs, int exitval);
  87. void PrintSubstitute(PBLOCKSTORE, PSZ, PSZ, int, BOOL);
  88. void AssertFail(PSZ pszfnam, int lineno, PBLOCKSTORE pbs, PSZ pszExp);
  89. #define NEUT 0
  90. #define ANSI 1
  91. #define UNIC 2
  92. /*
  93. * Command line flags
  94. */
  95. int fDebug = FALSE;
  96. void
  97. __cdecl main(
  98. int argc,
  99. PSZ argv[])
  100. {
  101. /*
  102. * block store.
  103. * lines from input are saved in here until we know
  104. * enough about how to process them.
  105. */
  106. BLOCKSTORE bs;
  107. int BlockType;
  108. ArgProcess(argc, argv);
  109. /*
  110. * buffer is empty
  111. */
  112. InitBS(&bs);
  113. if (fDebug) {
  114. fprintf(stderr, "About to start main loop\n");
  115. }
  116. while (ReadLineBS(&bs)) {
  117. /*
  118. * if line is blank then we have a complete block not requiring
  119. * any conversion.
  120. */
  121. if (bs.pLastLine[strspn(bs.pLastLine, " \t\r")] == '\n') {
  122. WriteBS(&bs);
  123. EmptyBS(&bs);
  124. continue;
  125. }
  126. if ((BlockType = ConversionRequiredBS(&bs)) != 0) {
  127. WriteAllTypesBS(&bs, BlockType);
  128. }
  129. }
  130. /*
  131. * Flush last BlockStore
  132. */
  133. WriteBS(&bs);
  134. }
  135. void
  136. WriteAllTypesBS(PBLOCKSTORE pbs, int BlockType)
  137. {
  138. if (fDebug) {
  139. fprintf(stderr, "WriteAllTypes(%p, %d)\n", pbs, BlockType);
  140. }
  141. switch (BlockType) {
  142. case CONV_NONE:
  143. /*
  144. * No conversion required, keep accumulating block.
  145. */
  146. return;
  147. case CONV_DEFINE:
  148. case CONV_FN_PROTO:
  149. SetInternalnessBS(pbs);
  150. GetSymNameBS(pbs, BlockType);
  151. WriteConvertBS(pbs, ANSI, TRUE);
  152. WriteConvertBS(pbs, UNIC, TRUE);
  153. ASSERT(pbs, pbs->pszInternal);
  154. /*
  155. * UNICODE defn.
  156. */
  157. fprintf(stdout, "#ifdef UNICODE%s\n#define %s %sW%s\n",
  158. pbs->pszInternal, pbs->pSymNam, pbs->pSymNam, pbs->pszInternal);
  159. /*
  160. * ANSI defn.
  161. */
  162. fprintf(stdout, "#else%s\n#define %s %sA%s\n",
  163. pbs->pszInternal, pbs->pSymNam, pbs->pSymNam, pbs->pszInternal);
  164. fprintf(stdout, "#endif // !UNICODE%s\n", pbs->pszInternal);
  165. /*
  166. * Neutral defn.
  167. */
  168. break;
  169. case CONV_TYPEDEF:
  170. SetInternalnessBS(pbs);
  171. WriteConvertBS(pbs, ANSI, FALSE);
  172. WriteConvertBS(pbs, UNIC, FALSE);
  173. WriteRedefinedTypeNamesBS(pbs);
  174. break;
  175. case CONV_FLUSH:
  176. WriteBS(pbs);
  177. EmptyBS(pbs);
  178. break;
  179. default:
  180. fprintf(stderr, "Don't understand block");
  181. error_exit(pbs, 2);
  182. }
  183. EmptyBS(pbs);
  184. }
  185. BOOL
  186. ReadLineBS(PBLOCKSTORE pbs)
  187. {
  188. int cbLine;
  189. if (fDebug) {
  190. fprintf(stderr, "ReadLineBS(%p)\n", pbs);
  191. }
  192. /*
  193. * Not all implementations of fgets() put a '\0' in the buffer upon EOF.
  194. * This will cause ReadLineBS() to leave the BlockStore untouched when
  195. * it returns FALSE.
  196. * We must ensure that BlockStore contents are valid whenever this routine
  197. * is called. InitBS() and EmptyBS() must set contents to '\0' !!
  198. */
  199. if (fgets(pbs->pEnd, pbs->cbFree, stdin) == NULL) {
  200. return FALSE;
  201. }
  202. cbLine = strlen(pbs->pEnd);
  203. if (fDebug) {
  204. fprintf(stderr, "read %d characters: \"%s\"\n", cbLine, pbs->pEnd);
  205. }
  206. pbs->pLastLine = pbs->pEnd;
  207. pbs->pEnd += cbLine;
  208. pbs->cbFree -= cbLine;
  209. pbs->line++;
  210. if (pbs->cbFree <= 1) {
  211. PSZ p;
  212. p = realloc(pbs->pStart, pbs->cbSize + EXTRA_STORE_SIZE);
  213. /*
  214. * Fatal Errror if allocation failed
  215. */
  216. ASSERT(pbs, p != NULL);
  217. if (p == NULL) {
  218. fprintf(stderr, "Reallocate BlockStore to %d bytes failed",
  219. pbs->cbSize + EXTRA_STORE_SIZE);
  220. error_exit(pbs, 2);
  221. }
  222. /*
  223. * adjust the pointers and counts
  224. */
  225. pbs->pLastLine = p + (pbs->pLastLine - pbs->pStart);
  226. pbs->pEnd = p + (pbs->pEnd - pbs->pStart);
  227. pbs->cbSize += EXTRA_STORE_SIZE;
  228. pbs->cbFree += EXTRA_STORE_SIZE;
  229. pbs->pStart = p;
  230. }
  231. return TRUE;
  232. }
  233. void
  234. WriteBS(PBLOCKSTORE pbs)
  235. {
  236. if (fDebug) {
  237. fprintf(stderr, "WriteBS(%p)\n", pbs);
  238. }
  239. fputs(pbs->pStart, stdout);
  240. }
  241. /*
  242. * Each time a new line is read in, this function is called to determine
  243. * whether a complete block has been accumulated for conversion and output.
  244. */
  245. int
  246. ConversionRequiredBS(PBLOCKSTORE pbs)
  247. {
  248. PSZ p;
  249. if (fDebug) {
  250. fprintf(stderr, "ConversionRequiredBS(%p)\n", pbs);
  251. }
  252. if (pbs->iType == CONV_NONE) {
  253. if (strncmp(pbs->pStart, "#define", 7) == 0) {
  254. /*
  255. * The block starts with #define
  256. */
  257. pbs->iType = CONV_DEFINE;
  258. } else if (pbs->pStart[0] == '#') {
  259. /*
  260. * The block starts with #if, #else, #endif etc.
  261. */
  262. return CONV_FLUSH;
  263. }
  264. }
  265. if (pbs->iType != CONV_DEFINE) {
  266. /*
  267. * Scan this line for parentheses and braces to identify
  268. * a complete Function Prototype or Structure definition.
  269. * NOTE: comments containing unbalanced parentheses or braces
  270. * will mess this up!
  271. */
  272. for (p = pbs->pLastLine; p <= pbs->pEnd; p++) {
  273. if ((*p == '(') || (*p == '{')) {
  274. pbs->pLastParen = p;
  275. if (pbs->p1stParen == NULL) {
  276. pbs->p1stParen = p;
  277. }
  278. pbs->nParen++;
  279. } else if ((*p == ')') || (*p == '}')) {
  280. pbs->nParen--;
  281. }
  282. if ((*p == ';') && (pbs->nParen == 0)) {
  283. /*
  284. * We have a function prototype or a typedef
  285. * (Balanced brackets and a semi-colon)
  286. */
  287. if (pbs->p1stParen && *(pbs->p1stParen) == '(') {
  288. pbs->iType = CONV_FN_PROTO;
  289. } else {
  290. pbs->iType = CONV_TYPEDEF;
  291. }
  292. goto CheckPercents;
  293. }
  294. }
  295. /*
  296. * Not a #define, nor a complete Typedef or Function prototype.
  297. */
  298. if (fDebug) {
  299. fprintf(stderr, " CONV_NONE (incomplete fn.proto/typedef)\n");
  300. }
  301. return CONV_NONE;
  302. } else if (pbs->iType == CONV_DEFINE) {
  303. /*
  304. * We know the block is a #define - we must detect the end
  305. * (it can extend for more than one line using backslashes)
  306. */
  307. if ((p = strrchr(pbs->pStart, '\\')) != NULL) {
  308. /*
  309. * There is a backslash on the line: if is it the last
  310. * non-whitespace character on the line, then this #define
  311. * is continuing on to the next line.
  312. */
  313. p++;
  314. p += strspn(p, " \t\r\n");
  315. if (*p == '\0') {
  316. /*
  317. * No conversion required *yet*. Continue accumulating
  318. * the multi-line #define statement.
  319. */
  320. if (fDebug) {
  321. fprintf(stderr, " CONV_NONE (incomplete #define)\n");
  322. }
  323. return CONV_NONE; // ...yet
  324. }
  325. }
  326. }
  327. CheckPercents:
  328. /*
  329. * We have a complete block of known type pbs->iType. We will need
  330. * to convert this block if it contains any %'s, so search for '%'
  331. */
  332. p = pbs->pStart;
  333. while ((p = strchr(p, '%')) != NULL) {
  334. if (!isalnum(p[1])) {
  335. if (fDebug) {
  336. fprintf(stderr, " return %d (%% found)\n", pbs->iType);
  337. }
  338. return pbs->iType;
  339. }
  340. /*
  341. * We found a %, but it followed by an alphanumeric character,
  342. * so can't require wcshdr.exe substitution. Look for more '%'s
  343. */
  344. p++;
  345. }
  346. if (fDebug) {
  347. fprintf(stderr, " CONV_FLUSH (no %%'s)\n");
  348. }
  349. return CONV_FLUSH;
  350. }
  351. BOOL
  352. GetDefinedNameBS(PBLOCKSTORE pbs) {
  353. PSZ pPercent = pbs->p1stParen - 1;
  354. PSZ pStartNam;
  355. if (fDebug) {
  356. fprintf(stderr, "GetDefinedNameBS(%p)\n", pbs);
  357. }
  358. /*
  359. * Scan forwards for name (starting from beyond the "#define")
  360. */
  361. pStartNam = pbs->pStart + 7;
  362. while (isspace(*pStartNam)) {
  363. pStartNam++;
  364. }
  365. /*
  366. * Scan forwards for '%', starting at beginning of literal name
  367. */
  368. for (pPercent = pStartNam; *pPercent; pPercent++) {
  369. if (*pPercent == '%') {
  370. /*
  371. * Make sure we have enough space to store the literal name
  372. */
  373. if ((pPercent - pStartNam) > pbs->cbSymNam) {
  374. fprintf(stderr, "REALLOCATE DEFINED NAME BUFFER!");
  375. error_exit(pbs, 2);
  376. }
  377. /*
  378. * store the literal name
  379. */
  380. *pPercent = '\0';
  381. strcpy(pbs->pSymNam, pStartNam);
  382. *pPercent = '%';
  383. return TRUE;
  384. }
  385. }
  386. /*
  387. * didn't find percent!
  388. */
  389. fprintf(stderr, "DEFINED NAME ???");
  390. error_exit(pbs, 2);
  391. }
  392. BOOL
  393. GetFnNameBS(PBLOCKSTORE pbs)
  394. {
  395. PSZ pPercent = pbs->pLastParen - 1;
  396. PSZ pStartNam;
  397. if (fDebug) {
  398. fprintf(stderr, "GetFnNameBS(%p)\n", pbs);
  399. }
  400. /*
  401. * Scan backwards for '%'
  402. */
  403. while (*pPercent != '%') {
  404. if (--pPercent <= pbs->pStart) {
  405. fprintf(stderr, "FUNCTION NAME ???");
  406. error_exit(pbs, 2);
  407. }
  408. }
  409. /*
  410. * Scan back for start of function name
  411. */
  412. for (pStartNam = pPercent - 1; pStartNam >= pbs->pStart; pStartNam--) {
  413. if (!isalnum(*pStartNam) && *pStartNam != '_')
  414. break;
  415. }
  416. pStartNam++;
  417. /*
  418. * Make sure we have enough space to store the function name
  419. */
  420. if ((pPercent - pStartNam) > pbs->cbSymNam) {
  421. fprintf(stderr, "REALLOCATE FN NAME BUFFER!");
  422. error_exit(pbs, 2);
  423. }
  424. /*
  425. * store the function name
  426. */
  427. *pPercent = '\0';
  428. strcpy(pbs->pSymNam, pStartNam);
  429. *pPercent = '%';
  430. return TRUE;
  431. }
  432. void
  433. GetSymNameBS(PBLOCKSTORE pbs, int iType)
  434. {
  435. if (iType == CONV_DEFINE) {
  436. GetDefinedNameBS(pbs);
  437. } else {
  438. GetFnNameBS(pbs);
  439. }
  440. }
  441. BOOL
  442. WriteRedefinedTypeNamesBS(PBLOCKSTORE pbs)
  443. {
  444. PSZ pFirstName = NULL;
  445. PSZ pToken;
  446. PSZ pPercent;
  447. BOOL fSkipFirst;
  448. if (fDebug) {
  449. fprintf(stderr, "WriteRedefinedTypeNamesBS(%p)\n", pbs);
  450. }
  451. ASSERT(pbs, pbs->pszInternal);
  452. if (pbs->p1stParen && (*(pbs->p1stParen) == '{')) {
  453. /*
  454. * Scan backwards for the closing brace
  455. */
  456. for (pToken = pbs->pEnd; *pToken != '}'; pToken--) {
  457. if (pToken <= pbs->pStart) {
  458. /*
  459. * No closing brace found!?
  460. */
  461. fprintf(stderr, "CLOSING BRACE ???");
  462. error_exit(pbs, 2);
  463. }
  464. }
  465. pToken++;
  466. fSkipFirst = FALSE;
  467. } else {
  468. /*
  469. * skip past "typedef"
  470. */
  471. pToken = pbs->pStart + 7;
  472. /*
  473. * Skip the first name
  474. */
  475. fSkipFirst = TRUE;
  476. }
  477. /*
  478. * UNICODE pass
  479. */
  480. fprintf(stdout, "#ifdef UNICODE%s\n", pbs->pszInternal);
  481. while (pToken = strtok(pToken, ",; \t*\n\r")) {
  482. if (fDebug) {
  483. fprintf(stderr, "token: \"%s\"\n", pToken);
  484. }
  485. /*
  486. * Write out the #define for UNICODE, excluding "NEAR" & "FAR"
  487. */
  488. if ( (_stricmp(pToken, "NEAR") == 0)
  489. || (_stricmp(pToken, "FAR") == 0)) {
  490. goto NextUnicodeToken;
  491. }
  492. if (fSkipFirst) {
  493. fSkipFirst = FALSE;
  494. goto NextUnicodeToken;
  495. } else if (pFirstName == NULL) {
  496. pFirstName = pToken;
  497. }
  498. pPercent = pToken + strlen(pToken) - 1;
  499. if (*pPercent == '%') {
  500. fprintf(stdout, "typedef ");
  501. PrintSubstitute(pbs, pToken, pPercent, UNIC, FALSE);
  502. fputs(" ", stdout);
  503. PrintSubstitute(pbs, pToken, pPercent, NEUT, FALSE);
  504. fprintf(stdout, ";%s\n", pbs->pszInternal);
  505. }
  506. NextUnicodeToken:
  507. pToken = NULL;
  508. }
  509. if (pFirstName == NULL) {
  510. fprintf(stderr, "TYPE NAME ???");
  511. error_exit(pbs, 2);
  512. }
  513. fprintf(stdout, "#else%s\n", pbs->pszInternal);
  514. if (fDebug) {
  515. fprintf(stderr, "FirstName = %s\n", pFirstName);
  516. }
  517. /*
  518. * ANSI pass
  519. */
  520. pToken = pFirstName;
  521. while ((pToken += strspn(pToken, "%,; \t*\n\r")) < pbs->pEnd) {
  522. /*
  523. * Write out the #define for ANSI, excluding "NEAR" and "FAR"
  524. */
  525. if ( (_stricmp(pToken, "NEAR") == 0)
  526. || (_stricmp(pToken, "FAR") == 0)) {
  527. goto NextAnsiToken;
  528. }
  529. pPercent = pToken + strlen(pToken) - 1;
  530. if (*pPercent == '%') {
  531. fprintf(stdout, "typedef ");
  532. PrintSubstitute(pbs, pToken, pPercent, ANSI, FALSE);
  533. fputs(" ", stdout);
  534. PrintSubstitute(pbs, pToken, pPercent, NEUT, FALSE);
  535. fprintf(stdout, ";%s\n", pbs->pszInternal);
  536. }
  537. NextAnsiToken:
  538. while (*pToken++) {
  539. ;
  540. }
  541. }
  542. fprintf(stdout, "#endif // UNICODE%s\n", pbs->pszInternal);
  543. return TRUE;
  544. }
  545. void
  546. WriteConvertBS(PBLOCKSTORE pbs, int Type, int fVertAlign)
  547. {
  548. PSZ p = pbs->pStart;
  549. PSZ pPercent;
  550. if (fDebug) {
  551. fprintf(stderr, "WriteConvertBS(%p, %d, %d)\n", pbs, Type, fVertAlign);
  552. }
  553. while ((pPercent = strchr(p, '%')) != NULL) {
  554. if (isalnum(pPercent[1])) {
  555. goto ContinueSearch;
  556. }
  557. /*
  558. * print the substitution
  559. */
  560. PrintSubstitute(pbs, p, pPercent, Type, fVertAlign);
  561. /*
  562. * Advance beyond the %
  563. */
  564. ContinueSearch:
  565. p = pPercent+1;
  566. }
  567. /*
  568. * Print remainder of store
  569. */
  570. fputs(p, stdout);
  571. }
  572. void
  573. EmptyBS(PBLOCKSTORE pbs)
  574. {
  575. if (fDebug) {
  576. fprintf(stderr, "EmptyBS(%p)\n", pbs);
  577. }
  578. pbs->pEnd = pbs->pStart;
  579. pbs->pLastLine = pbs->pStart;
  580. pbs->cbFree = pbs->cbSize;
  581. if (pbs->pStart) {
  582. *(pbs->pStart) = '\0';
  583. }
  584. pbs->iType = CONV_NONE;
  585. pbs->p1stParen = NULL;
  586. pbs->pLastParen = NULL;
  587. pbs->nParen = 0;
  588. if (pbs->pSymNam) {
  589. *(pbs->pSymNam) = '\0';
  590. }
  591. }
  592. void
  593. InitBS(PBLOCKSTORE pbs) {
  594. pbs->line = 0;
  595. pbs->pStart = malloc(INITIAL_STORE_SIZE);
  596. ASSERT(pbs, pbs->pStart != NULL);
  597. pbs->pLastLine = pbs->pStart;
  598. pbs->pEnd = pbs->pStart;
  599. *(pbs->pStart) = '\0';
  600. pbs->iType = CONV_NONE;
  601. pbs->p1stParen = NULL;
  602. pbs->pLastParen = NULL;
  603. pbs->nParen = 0;
  604. pbs->pszInternal = 0;
  605. pbs->cbSize = INITIAL_STORE_SIZE;
  606. pbs->cbFree = INITIAL_STORE_SIZE;
  607. pbs->pSymNam = malloc(FN_NAME_SIZE);
  608. ASSERT(pbs, pbs->pSymNam != NULL);
  609. pbs->cbSymNam = FN_NAME_SIZE;
  610. *(pbs->pSymNam) = '\0';
  611. }
  612. void
  613. SetInternalnessBS(PBLOCKSTORE pbs) {
  614. if (strstr(pbs->pStart, ";internal")) {
  615. pbs->pszInternal = "\t// ;internal";
  616. } else {
  617. pbs->pszInternal = "";
  618. }
  619. }
  620. void
  621. AssertFail(
  622. PSZ pszfnam,
  623. int lineno,
  624. PBLOCKSTORE pbs,
  625. PSZ pszExp)
  626. {
  627. fprintf(stderr, "ASSERT failed: file %s, line %d:\n", pszfnam, lineno);
  628. fprintf(stderr, "input line %d: \"%s\"\n", pbs->line, pszExp);
  629. }
  630. void
  631. ArgProcess(
  632. int argc,
  633. PSZ argv[])
  634. {
  635. int ArgIndex;
  636. PSZ pszArg;
  637. for (ArgIndex = 1; ArgIndex < argc; ArgIndex++) {
  638. pszArg = argv[ArgIndex];
  639. if ((*pszArg == '-') || (*pszArg == '/')) {
  640. switch (pszArg[1]) {
  641. case '?':
  642. fprintf(stderr, "%s\n", Version);
  643. Usage();
  644. exit(0);
  645. case 'd':
  646. case 'D':
  647. fDebug = TRUE;
  648. break;
  649. default:
  650. fprintf(stderr, "%s Invalid switch: %s\n", Version, pszArg);
  651. Usage();
  652. exit(1);
  653. }
  654. }
  655. }
  656. }
  657. void Usage(void)
  658. {
  659. fprintf(stderr, "usage: WCSHDR [-?] display this message\n");
  660. fprintf(stderr, " [-d] debug (to stderr)\n");
  661. fprintf(stderr, " reads stdin, writes to stdout\n");
  662. }
  663. void
  664. DECLSPEC_NORETURN
  665. error_exit(PBLOCKSTORE pbs, int exitval) {
  666. fprintf(stderr, " (line %d)\n", pbs->line);
  667. exit(exitval);
  668. }
  669. /*
  670. * Substitutions performed on strings ending '%'
  671. *
  672. */
  673. typedef struct {
  674. int cchTemplate;
  675. PSZ pszTemplate;
  676. PSZ apszSub[3];
  677. } SUBSTR, *PSUBSTR;
  678. /*
  679. * Strings that are replaced:
  680. * BCHAR%
  681. * TCHAR%
  682. * LPTCH%
  683. * LPTSTR%
  684. * LPTSTR2%
  685. * LPTSTRID%
  686. * LPTSTRNULL%
  687. * %
  688. *
  689. * "%" MUST comes last (before the null terminator)
  690. *
  691. * The other strings must be ordered from sensibly:
  692. * if FRED% came before BIGFRED% in Substrs[], then the Substitute()
  693. * procedure would match input BIGFRED% to FRED%, not BIGFRED%. The
  694. * simplest way to avoid this is to arrange strings in descending lengths.
  695. */
  696. SUBSTR Substrs[] = {
  697. { 10, "LPTSTRNULL%", "LPTSTRNULL", "LPSTRNULL", "LPWSTRNULL" },
  698. { 8, "LPTSTRID%", "LPTSTRID", "LPSTRID", "LPWSTRID" },
  699. { 7, "LPTSTR2%", "LPTSTR2", "LPSTR2", "LPWSTR2" },
  700. { 7, "LPCTSTR%", "LPCTSTR", "LPCSTR", "LPCWSTR" },
  701. { 6, "LPTSTR%", "LPTSTR", "LPSTR", "LPWSTR" },
  702. { 5, "TCHAR%", "TCHAR", "CHAR", "WCHAR" },
  703. { 5, "BCHAR%", "BCHAR", "BYTE", "WCHAR" },
  704. { 5, "LPTCH%", "LPTCH", "LPCH", "LPWCH" },
  705. { 0, "%", "", "A", "W" },
  706. { 0, NULL, NULL, NULL, NULL }
  707. };
  708. PSZ special_pad[] = {
  709. " ", // Neutral
  710. " ", // ANSI
  711. " " // UNICODE
  712. };
  713. PSZ normal_pad[] = {
  714. " ", // Neutral
  715. "", // ANSI
  716. "" // UNICODE
  717. };
  718. void PrintSubstitute(
  719. PBLOCKSTORE pbs, // just for error reporting
  720. PSZ pStart, // where to start substitution
  721. PSZ pPercent, // ptr to '%' at end of input string
  722. int Type, // NEUT, ANSI or UNIC
  723. BOOL fVertAlign) // attempt to maintain vertical alignment?
  724. {
  725. PSUBSTR pSub;
  726. char chTmp;
  727. PSZ pChangedPart = NULL;
  728. if (fDebug) {
  729. fprintf(stderr, "PrintSubstitute(%p, %p, %p, %d, %d)\n",
  730. pbs, pStart, pPercent, Type, fVertAlign);
  731. }
  732. for (pSub = Substrs; pSub->pszTemplate; pSub++) {
  733. int cch = pSub->cchTemplate;
  734. if ((pPercent - cch) < pStart) {
  735. continue;
  736. }
  737. if (strncmp(pPercent - cch, pSub->pszTemplate, cch+1) == 0) {
  738. pChangedPart = pPercent-cch;
  739. /*
  740. * print out unaltered bit
  741. */
  742. chTmp = *pChangedPart;
  743. *pChangedPart = '\0';
  744. fputs(pStart, stdout);
  745. *pChangedPart = chTmp;
  746. /*
  747. * print out replacement bit
  748. */
  749. fputs(pSub->apszSub[Type], stdout);
  750. break;
  751. }
  752. }
  753. if (pChangedPart == NULL) {
  754. /*
  755. * NO match was found in Substrs[] !!!
  756. */
  757. fprintf(stderr, "Can't substitute");
  758. error_exit(pbs, 2);
  759. }
  760. /*
  761. * preserve alignment if required.
  762. * (not for function prototypes, and only if whitespace follows
  763. */
  764. if (!fVertAlign &&
  765. ((pPercent[1] == ' ') || (pPercent[1] == '\t'))) {
  766. if (pChangedPart != pPercent) {
  767. fputs(special_pad[Type], stdout);
  768. } else {
  769. fputs(normal_pad[Type], stdout);
  770. }
  771. }
  772. }