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.

601 lines
18 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: hsplit.c
  3. *
  4. * Structure parser - struct field name-offset tabel generator.
  5. *
  6. * Copyright (c) 1985-96, Microsoft Corporation
  7. *
  8. * 09/05/96 GerardoB Created
  9. \***************************************************************************/
  10. #include "hsplit.h"
  11. /*
  12. * Maximum size of tags (gphst) table including possible user defined tags
  13. */
  14. #define HSTAGTABLESIZE (sizeof(ghstPredefined) + ((32 - HST_MASKBITCOUNT) * sizeof(HSTAG)))
  15. /***************************************************************************\
  16. * hsAddTag
  17. *
  18. \***************************************************************************/
  19. PHSTAG hsAddTag (char * pszTag, DWORD dwMask)
  20. {
  21. PHSTAG phst;
  22. DWORD dwTagSize;
  23. /*
  24. * Make sure we still have mask bits to uniquely identified this tag
  25. */
  26. if (((dwMask | HST_EXTRACT) == HST_EXTRACT) && (gdwLastTagMask == HST_MAXMASK)) {
  27. hsLogMsg(HSLM_ERROR, "Too many user defined tags. Max allowed: %d", 32 - HST_MASKBITCOUNT);
  28. return NULL;
  29. }
  30. /*
  31. * Create the table the first time around.
  32. */
  33. if (gphst == ghstPredefined) {
  34. gphst = (PHSTAG) LocalAlloc(LPTR, HSTAGTABLESIZE);
  35. if (gphst == NULL) {
  36. hsLogMsg(HSLM_APIERROR, "LocalAlloc");
  37. hsLogMsg(HSLM_ERROR, "hsAddTag Allocation failed. Size:%#lx", HSTAGTABLESIZE);
  38. return NULL;
  39. }
  40. CopyMemory(gphst, &ghstPredefined, sizeof(ghstPredefined));
  41. }
  42. /*
  43. * If the string is in the table, we update the mask.
  44. */
  45. dwTagSize = strlen(pszTag);
  46. phst = hsFindTagInList(gphst, pszTag, dwTagSize);
  47. if (phst == NULL) {
  48. /*
  49. * New string. Find next available entry in the table
  50. */
  51. phst = gphst;
  52. while (phst->dwLabelSize != 0) {
  53. phst++;
  54. }
  55. }
  56. /*
  57. * Initialize it
  58. */
  59. phst->dwLabelSize = dwTagSize;
  60. phst->pszLabel = pszTag;
  61. /*
  62. * If generating a mask, use the next available bit in the tag mask
  63. * else use the one supplied by the caller
  64. */
  65. if ((dwMask | HST_EXTRACT) == HST_EXTRACT) {
  66. gdwLastTagMask *= 2;
  67. phst->dwMask = (gdwLastTagMask | dwMask);
  68. } else {
  69. phst->dwMask = dwMask;
  70. }
  71. /*
  72. * Add this tag's mask to the filter mask so lines mark with this tag
  73. * will be included
  74. */
  75. gdwFilterMask |= (phst->dwMask & HST_USERTAGSMASK);
  76. return phst;
  77. }
  78. /***************************************************************************\
  79. * hsIsSwitch
  80. *
  81. \***************************************************************************/
  82. __inline BOOL hsIsSwitch(char c)
  83. {
  84. return (c == '/') || (c == '-');
  85. }
  86. /***************************************************************************\
  87. * hsAddUserDefinedTag
  88. *
  89. \***************************************************************************/
  90. BOOL hsAddUserDefinedTag(DWORD* pdwMask, int* pargc, char*** pargv)
  91. {
  92. DWORD dwRetMask = *pdwMask;
  93. PHSTAG phst;
  94. if (*pargc < 2) {
  95. return FALSE; // invalid switch
  96. }
  97. /*
  98. * Allow multiple tags to be specified for one switch
  99. * i.e., -t tag1 <tag2 tag2....>
  100. */
  101. do {
  102. (*pargc)--, (*pargv)++;
  103. /*
  104. * Add tag to table
  105. */
  106. phst = hsAddTag(**pargv, *pdwMask);
  107. if (phst == NULL) {
  108. return 0;
  109. }
  110. dwRetMask |= phst->dwMask;
  111. } while ((*pargc >= 2) && !hsIsSwitch(**(*pargv + 1)));
  112. /*
  113. * save the new mask
  114. */
  115. *pdwMask = dwRetMask;
  116. return TRUE;
  117. }
  118. /***************************************************************************\
  119. * hsAddExtractFile
  120. *
  121. \***************************************************************************/
  122. BOOL hsAddExtractFile(char* pszExtractFile, DWORD dwMask, BOOL bAppend)
  123. {
  124. PHSEXTRACT pe;
  125. pe = LocalAlloc(LPTR, sizeof(HSEXTRACT));
  126. if (pe == NULL) {
  127. return FALSE;
  128. }
  129. pe->pszFile = pszExtractFile;
  130. pe->dwMask = dwMask;
  131. pe->hfile = CreateFile(pszExtractFile, GENERIC_WRITE, 0, NULL,
  132. (bAppend ? OPEN_EXISTING : CREATE_ALWAYS),
  133. FILE_ATTRIBUTE_NORMAL, NULL);
  134. if (pe->hfile == INVALID_HANDLE_VALUE) {
  135. hsLogMsg(HSLM_APIERROR | HSLM_NOLINE, "CreateFile failed for file %s",
  136. pszExtractFile);
  137. LocalFree(pe);
  138. return FALSE;
  139. }
  140. if (bAppend) {
  141. if (0xFFFFFFFF == SetFilePointer (pe->hfile, 0, 0, FILE_END)) {
  142. hsLogMsg(HSLM_APIERROR | HSLM_NOLINE, "SetFilePointer failed for file %s",
  143. pszExtractFile);
  144. CloseHandle(pe->hfile);
  145. LocalFree(pe);
  146. return FALSE;
  147. }
  148. }
  149. /*
  150. * link it in the list of extract files
  151. */
  152. pe->pNext = gpExtractFile;
  153. gpExtractFile = pe;
  154. return TRUE;
  155. }
  156. /***************************************************************************\
  157. * hsProcessParameters
  158. *
  159. \***************************************************************************/
  160. int hsProcessParameters(int argc, LPSTR argv[])
  161. {
  162. char c, *p;
  163. DWORD dwMask;
  164. int argcParm = argc;
  165. PHSTAG phst;
  166. /*
  167. * Compatibility. Assume default project the first time this
  168. * function is called
  169. */
  170. if (!(gdwOptions & HSO_APPENDOUTPUT)) {
  171. gdwOptions |= HSO_OLDPROJSW_N;
  172. }
  173. /*
  174. * Loop through parameters.
  175. */
  176. while (--argc) {
  177. p = *++argv;
  178. if (hsIsSwitch(*p)) {
  179. while (c = *++p) {
  180. switch (toupper(c)) {
  181. /*
  182. * Compatibility.
  183. * Chicago/Nashvilled header.
  184. */
  185. case '4':
  186. gdwOptions &= ~HSO_OLDPROJSW;
  187. gdwOptions |= HSO_OLDPROJSW_4;
  188. break;
  189. /*
  190. * Old bt2 and btb switches to replace internal and
  191. * both block tags.
  192. */
  193. case 'B':
  194. p++;
  195. if (toupper(*p++) != 'T') {
  196. goto InvalidSwitch;
  197. }
  198. if (toupper(*p) == 'B') {
  199. dwMask = HST_BOTH | HST_USERBOTHBLOCK;
  200. gdwOptions |= HSO_USERBOTHBLOCK;
  201. } else if (*p == '2') {
  202. dwMask = HST_INTERNAL | HST_USERINTERNALBLOCK;
  203. gdwOptions |= HSO_USERINTERNALBLOCK;
  204. } else {
  205. goto InvalidSwitch;
  206. }
  207. if (argc < 3) {
  208. goto InvalidSwitch;
  209. }
  210. /*
  211. * Add these strings as tags and mark them as blocks
  212. */
  213. argc--, argv++;
  214. phst = hsAddTag(*argv, HST_BEGIN | dwMask);
  215. if (phst == NULL) {
  216. return 0;
  217. }
  218. argc--, argv++;
  219. phst = hsAddTag(*argv, HST_END | dwMask);
  220. if (phst == NULL) {
  221. return 0;
  222. }
  223. break;
  224. /*
  225. * Tag marker
  226. */
  227. case 'C':
  228. if (argc < 2) {
  229. goto InvalidSwitch;
  230. }
  231. argc--, argv++;
  232. gpszTagMarker = *argv;
  233. *gszMarkerCharAndEOL = *gpszTagMarker;
  234. gdwTagMarkerSize = strlen(gpszTagMarker);
  235. if (gdwTagMarkerSize == 0) {
  236. goto InvalidSwitch;
  237. }
  238. break;
  239. /*
  240. * Compatibility.
  241. * NT SUR header
  242. */
  243. case 'E':
  244. gdwOptions &= ~HSO_OLDPROJSW;
  245. gdwOptions |= HSO_OLDPROJSW_E;
  246. break;
  247. /*
  248. * Input file
  249. */
  250. case 'I':
  251. if (argc < 2) {
  252. goto InvalidSwitch;
  253. }
  254. argc--, argv++;
  255. gpszInputFile = *argv;
  256. goto ProcessInputFile;
  257. break;
  258. /*
  259. * Extract file
  260. */
  261. case 'X':
  262. {
  263. char* pszExtractFile;
  264. BOOL bAppend = FALSE;
  265. if (toupper(*(p+1)) == 'A') {
  266. p++;
  267. bAppend = TRUE;
  268. }
  269. if (argc < 3) {
  270. goto InvalidSwitch;
  271. }
  272. argc--, argv++;
  273. pszExtractFile = *argv;
  274. dwMask = HST_EXTRACT;
  275. if (!hsAddUserDefinedTag(&dwMask, &argc, &argv))
  276. goto InvalidSwitch;
  277. hsAddExtractFile(pszExtractFile, dwMask, bAppend);
  278. break;
  279. }
  280. /*
  281. * Old lt2 and ltb switches to replace internal and
  282. * both tags.
  283. */
  284. case 'L':
  285. p++;
  286. if (toupper(*p++) != 'T') {
  287. goto InvalidSwitch;
  288. }
  289. if (toupper(*p) == 'B') {
  290. dwMask = HST_BOTH | HST_USERBOTHTAG;
  291. gdwOptions |= HSO_USERBOTHTAG;
  292. } else if (*p == '2') {
  293. dwMask = HST_INTERNAL | HST_USERINTERNALTAG;
  294. gdwOptions |= HSO_USERINTERNALTAG;
  295. } else {
  296. goto InvalidSwitch;
  297. }
  298. if (!hsAddUserDefinedTag(&dwMask, &argc, &argv))
  299. goto InvalidSwitch;
  300. break;
  301. /*
  302. * Compatibility.
  303. * NT header
  304. */
  305. case 'N':
  306. gdwOptions &= ~HSO_OLDPROJSW;
  307. gdwOptions |= HSO_OLDPROJSW_N;
  308. break;
  309. /*
  310. * Ouput files
  311. */
  312. case 'O':
  313. if (argc < 3) {
  314. goto InvalidSwitch;
  315. }
  316. argc--, argv++;
  317. gpszPublicFile = *argv;
  318. argc--, argv++;
  319. gpszInternalFile = *argv;
  320. break;
  321. /*
  322. * Compatibility.
  323. * NT SURPlus header
  324. */
  325. case 'P':
  326. gdwOptions &= ~HSO_OLDPROJSW;
  327. gdwOptions |= HSO_OLDPROJSW_P;
  328. break;
  329. /*
  330. * Split only. Process internal/both tags only. Tags
  331. * including other tags as well (i.e., internal_NT)
  332. * are treated as untagged.
  333. */
  334. case 'S':
  335. gdwOptions |= HSO_SPLITONLY;
  336. break;
  337. /*
  338. * User defined tags.
  339. */
  340. case 'T':
  341. switch (toupper(*++p)) {
  342. /*
  343. * Include lines mark with this tag
  344. */
  345. case 'A':
  346. dwMask = 0;
  347. break;
  348. /*
  349. * Ignore lines marked with this tag (i.e, treated
  350. * as untagged)
  351. */
  352. case 'I':
  353. dwMask = HST_IGNORE;
  354. break;
  355. /*
  356. * Skip lines marked with this tag (i.e., not
  357. * included in header files)
  358. */
  359. case 'S':
  360. dwMask = HST_SKIP;
  361. break;
  362. default:
  363. goto InvalidSwitch;
  364. }
  365. if (!hsAddUserDefinedTag(&dwMask, &argc, &argv))
  366. goto InvalidSwitch;
  367. break;
  368. /*
  369. * Version
  370. */
  371. case 'V':
  372. if (argc < 2) {
  373. goto InvalidSwitch;
  374. }
  375. argc--, argv++;
  376. if (!hsVersionFromString (*argv, strlen(*argv), &gdwVersion)) {
  377. goto InvalidSwitch;
  378. }
  379. break;
  380. /*
  381. * Unknown tags are to be skipped, as opposed to ignored.
  382. */
  383. case 'U':
  384. gdwOptions |= HSO_SKIPUNKNOWN;
  385. break;
  386. /*
  387. * Invalid switch
  388. */
  389. default:
  390. InvalidSwitch:
  391. hsLogMsg(HSLM_ERROR | HSLM_NOLINE, "Invalid switch or parameter: %c", c);
  392. // Fall through
  393. /*
  394. * Help
  395. */
  396. case '?':
  397. goto PrintHelp;
  398. } /* switch (toupper(c)) */
  399. } /* while (c = *++p) */
  400. } else { /* hsIsSwitch(*p) { */
  401. /*
  402. * No switch specified. Process this input file
  403. */
  404. gpszInputFile = *argv;
  405. break;
  406. }
  407. } /* while (--argc) */
  408. ProcessInputFile:
  409. /*
  410. * Make sure we got input and ouput files.
  411. */
  412. if ((gpszInputFile == NULL)
  413. || (gpszPublicFile == NULL)
  414. || (gpszInternalFile == NULL)) {
  415. hsLogMsg(HSLM_ERROR | HSLM_NOLINE, "Missing input or ouput file");
  416. goto PrintHelp;
  417. }
  418. /*
  419. * Add compatibility tags for default projects (first call only)
  420. */
  421. if ((gdwOptions & HSO_OLDPROJSW) && !(gdwOptions & HSO_APPENDOUTPUT)) {
  422. if (!(gdwOptions & HSO_OLDPROJSW_4)) {
  423. phst = hsAddTag(gszNT, 0);
  424. if (phst == NULL) {
  425. return 0;
  426. }
  427. phst->dwMask |= HST_MAPOLD;
  428. dwMask = phst->dwMask;
  429. }
  430. if (gdwOptions & HSO_OLDPROJSW_E) {
  431. hsAddTag(gszCairo, dwMask);
  432. hsAddTag(gszSur, dwMask);
  433. hsAddTag(gszWin40, dwMask);
  434. hsAddTag(gsz35, dwMask);
  435. } else if (gdwOptions & HSO_OLDPROJSW_P) {
  436. hsAddTag(gszWin40, dwMask);
  437. hsAddTag(gszWin40a, dwMask);
  438. hsAddTag(gszCairo, dwMask);
  439. hsAddTag(gszSur, dwMask);
  440. hsAddTag(gszSurplus, dwMask);
  441. hsAddTag(gsz35, dwMask);
  442. } else if (gdwOptions & HSO_OLDPROJSW_4) {
  443. gdwOptions |= HSO_INCINTERNAL;
  444. phst = hsAddTag(gszChicago, 0);
  445. if (phst == NULL) {
  446. return 0;
  447. }
  448. phst->dwMask |= HST_MAPOLD;
  449. dwMask = phst->dwMask;
  450. hsAddTag(gszNashville, dwMask);
  451. hsAddTag(gszWin40, dwMask);
  452. hsAddTag(gszWin40a, dwMask);
  453. } else if (!(gdwOptions & HSO_APPENDOUTPUT)) {
  454. gdwOptions |= HSO_OLDPROJSW_N;
  455. }
  456. } /* (gdOptions & HSO_OLDPROJW) */
  457. /*
  458. * Compatibility. If doing split only, don't include internal tags
  459. * in public file
  460. */
  461. if (gdwOptions & HSO_SPLITONLY) {
  462. gdwOptions &= ~HSO_INCINTERNAL;
  463. }
  464. return argcParm - argc;
  465. PrintHelp:
  466. hsLogMsg(HSLM_DEFAULT, "Header Split Utility. Version 2.1");
  467. hsLogMsg(HSLM_NOLABEL, "Usage: hsplit [options] <-o PublicFile InternalFile> [-i] File1 [-i] File2...");
  468. hsLogMsg(HSLM_NOLABEL, "\t[-4] Generate chicago/nashville headers");
  469. hsLogMsg(HSLM_NOLABEL, "\t[-bt2 BeginStr EndStr] Replace begin_internal/end_internal - Obsolete");
  470. hsLogMsg(HSLM_NOLABEL, "\t[-btb BeginStr EndStr] Replace begin_both/end_both tags - Obsolete");
  471. hsLogMsg(HSLM_NOLABEL, "\t[-c TagMarker] Replace tag marker. default \";\"");
  472. hsLogMsg(HSLM_NOLABEL, "\t[-e] Generate NT sur headers");
  473. hsLogMsg(HSLM_NOLABEL, "\t[[-i] file1 file2 ..] Input files - Required");
  474. hsLogMsg(HSLM_NOLABEL, "\t[-lt2 str] Replace internal tag - Obsolete");
  475. hsLogMsg(HSLM_NOLABEL, "\t[-ltb str] Replace both tag - Obsolete");
  476. hsLogMsg(HSLM_NOLABEL, "\t[-n] Generate NT headers - default");
  477. hsLogMsg(HSLM_NOLABEL, "\t[-x[a] ExtractHeader ExtractTag] Extract files and tags files");
  478. hsLogMsg(HSLM_NOLABEL, "\t[-o PublicHeader InternalHeader] Output files - Required");
  479. hsLogMsg(HSLM_NOLABEL, "\t[-p] Generate NT surplus headers");
  480. hsLogMsg(HSLM_NOLABEL, "\t[-s] Process internal and both tags only");
  481. hsLogMsg(HSLM_NOLABEL, "\t[-ta tag1 tag2 ..] Include lines using these tags");
  482. hsLogMsg(HSLM_NOLABEL, "\t[-ti tag1 tag2 ..] Ignore these tags");
  483. hsLogMsg(HSLM_NOLABEL, "\t[-ts tag1 tag2 ..] Skip lines using these tags");
  484. hsLogMsg(HSLM_NOLABEL, "\t[-u] Skip unknown tags. Default: ignore");
  485. hsLogMsg(HSLM_NOLABEL, "\t[-v] Version number. Default: LATEST_WIN32_WINNT_VERSION");
  486. hsLogMsg(HSLM_NOLABEL, "\r\nTags Format:");
  487. hsLogMsg(HSLM_NOLABEL, "\t<TagMarker>[begin/end][_public/internal][[_tag1][_tag2]...][_if_(str)_version | _version]");
  488. return 0;
  489. }
  490. /***************************************************************************\
  491. * main
  492. *
  493. \***************************************************************************/
  494. int __cdecl main (int argc, char *argv[])
  495. {
  496. int argcProcessed;
  497. /*
  498. * Each loop processes one input file
  499. */
  500. do {
  501. argcProcessed = hsProcessParameters(argc, argv);
  502. if (argcProcessed == 0) {
  503. break;
  504. }
  505. if (!hsOpenWorkingFiles()
  506. || !hsSplit()) {
  507. return TRUE;
  508. }
  509. hsCloseWorkingFiles();
  510. gdwOptions |= HSO_APPENDOUTPUT;
  511. argc -= argcProcessed;
  512. argv += argcProcessed;
  513. } while (argc > 1);
  514. return FALSE;
  515. }