Windows NT 4.0 source code leak
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.

1315 lines
46 KiB

4 years ago
  1. /************************************************************************
  2. * *
  3. * WMAIN.CPP *
  4. * *
  5. * Copyright (C) Microsoft Corporation 1993-1994 *
  6. * All Rights reserved. *
  7. * *
  8. *************************************************************************
  9. * *
  10. * Module Intent *
  11. * *
  12. * This module contains initialization and the WinMain routine *
  13. * *
  14. * Command line parameters:
  15. -x do not attempt to find parent
  16. c RTF is in the clipboard
  17. h run winhelp after compiling
  18. n don't display grinder window
  19. r file RTF file -- change extension to .HLP and create help file
  20. t trusted caller -- assume RTF is valid
  21. -f forage (help_file output_file)
  22. a dump region map
  23. b dump structs
  24. c topics
  25. d text
  26. e bindings
  27. f hash table
  28. h klink
  29. i alink
  30. -b path BMROOT path
  31. -o file specifies the help file to create
  32. -p generate phrase file only (REVIEW: supported?)
  33. -r run WinHelp after compiling
  34. -t test commands
  35. c file test .CNT file
  36. m macro test macro (REVIEW: supported?)
  37. -n no options
  38. g no grinder
  39. a no activation on completion
  40. c no compression
  41. ************************************************************************/
  42. #include "stdafx.h"
  43. #ifdef _DEBUG
  44. #undef THIS_FILE
  45. static char THIS_FILE[] = __FILE__;
  46. #endif
  47. #include <direct.h>
  48. #include "cphrase.h"
  49. #include "..\common\resource.h"
  50. #include "..\common\coutput.h"
  51. #include "..\ftsrch\ftsiface.h"
  52. #include "ftsrch.h"
  53. #define IsSwitchChar(ch) ((ch) == '-' || (ch) == '/')
  54. extern HINDEX hFtsIndex;
  55. extern HCOMPRESSOR hCompressor;
  56. char const txtHcw[] = "hcw.exe";
  57. extern COutput* pLogFile;
  58. static BOOL STDCALL ParseCmdLine(PSTR lpszCmdLine, PSTR pszHpjFile);
  59. static ERR err;
  60. #if (defined(_DEBUG))
  61. static PSTR szWarning1[] = {
  62. "artless",
  63. "bawdy",
  64. "beslubbering",
  65. "bootless",
  66. "churlish",
  67. "cockered",
  68. "clouted",
  69. "craven",
  70. "currish",
  71. "dankish",
  72. "dissembling",
  73. "droning",
  74. "errant",
  75. "fawning",
  76. "fobbing",
  77. "froward",
  78. "frothy",
  79. "gleeking",
  80. "goatish",
  81. "gorbellied",
  82. "impertinent",
  83. "infectious",
  84. "jarring",
  85. "loggerheaded",
  86. "lumpish",
  87. "mammering",
  88. "mangled",
  89. "mewling",
  90. "paunchy",
  91. "pribbling",
  92. "puking",
  93. "puny",
  94. "quailing",
  95. "rank",
  96. "reeky",
  97. "roguish",
  98. "ruttish",
  99. "saucy",
  100. "spleeny",
  101. "spongy",
  102. "surly",
  103. "tottering",
  104. "unmuzzled",
  105. "vain",
  106. "venomed",
  107. "villainous",
  108. "warped",
  109. "wayward",
  110. "weedy",
  111. "yeasty",
  112. };
  113. static PSTR szWarning2[] = {
  114. "base-court",
  115. "bat-fowling",
  116. "beef-witted",
  117. "beetle-headed",
  118. "boil-brained",
  119. "clapper-clawed",
  120. "clay-brained",
  121. "common-kissing",
  122. "crook-pated",
  123. "dismal-dreaming",
  124. "dizzy-eyed",
  125. "doghearted",
  126. "dread-bolted",
  127. "earth-vexing",
  128. "elf-skinned",
  129. "fat-kidneyed",
  130. "fen-sucked",
  131. "flap-mouthed",
  132. "fly-bitten",
  133. "folly-fallen",
  134. "fool-born",
  135. "full-gorged",
  136. "guts-griping",
  137. "half-faced",
  138. "hasty-witted",
  139. "hedge-born",
  140. "hell-hated",
  141. "idle-headed",
  142. "ill-breeding",
  143. "ill-nurtured",
  144. "knotty-pated",
  145. "milk-livered",
  146. "motley-minded",
  147. "onion-eyed",
  148. "plume-plucked",
  149. "pottle-deep",
  150. "pox-marked",
  151. "reeling-ripe",
  152. "rough-hewn",
  153. "rude-growing",
  154. "rump-fed",
  155. "shard-borne",
  156. "sheep-biting",
  157. "spur-galled",
  158. "swag-bellied",
  159. "tardy-gaited",
  160. "tickle-brained",
  161. "toad-spotted",
  162. "unchin-snouted",
  163. "weather-bitten",
  164. };
  165. static PSTR szWarning3[] = {
  166. "apple-john",
  167. "blathering",
  168. "barnacley",
  169. "maggot ridden",
  170. "boar-pig like",
  171. "bugbearing",
  172. "bum-bailey",
  173. "canker-blossom",
  174. "clack-dish",
  175. "clotpoling",
  176. "coxcombing",
  177. "codpiecing",
  178. "death-tokening",
  179. "dewberry",
  180. "flap-dragon",
  181. "flax-wench",
  182. "flirt-gill",
  183. "foot-licker",
  184. "fustilarian",
  185. "giglet",
  186. "gudgeon",
  187. "haggardly",
  188. "harpy",
  189. "hedge-pig",
  190. "horn-beast",
  191. "hugger-mugger",
  192. "joltheaded",
  193. "lewdster",
  194. "louty",
  195. "maggot-pie",
  196. "malt-worm",
  197. "mammet",
  198. "measley",
  199. "minnowing",
  200. "miscreant",
  201. "moldwarping",
  202. "mumble-news",
  203. "nut-hooking",
  204. "pigeon-egging",
  205. "pignuting",
  206. "puttocking",
  207. "pumpion",
  208. "ratsbanish",
  209. "scutly",
  210. "skainsmately",
  211. "strumpeting",
  212. "varloting",
  213. "vassaling",
  214. "whey-facing",
  215. "wagtailing",
  216. };
  217. #endif // DEBUG
  218. BOOL STDCALL GetRtfInClipboard(CStr* pcsz);
  219. #include <io.h> // For Zeck Debug code
  220. #include <fcntl.h>
  221. static PSTR pgszTitleBuf;
  222. static LPTOP_LEVEL_EXCEPTION_FILTER OldFilter;
  223. const int SWITCH_TO_HALL_SIZE = (1024 * 1024);
  224. int STDCALL WinMain(HINSTANCE hinstCur, HINSTANCE hinstPrev,
  225. PSTR lpszCmdLine, int iCmdShow)
  226. {
  227. char szRtfFile[MAX_PATH];
  228. BOOL fFileFound = FALSE;
  229. BOOL fBuildResult = FALSE;
  230. DWORD dwTime = GetTickCount();
  231. SetErrorMode( SEM_NOALIGNMENTFAULTEXCEPT );
  232. // REVIEW: we should add an exception handler here for HardExit()
  233. hinstApp = hinstCur;
  234. pgszTitleBuf = AllocateResourceString(IDS_TITLE);
  235. fDBCSSystem = IsDbcsSystem();
  236. if (!strstr(lpszCmdLine, "-x") && !strstr(lpszCmdLine, "/x")) {
  237. hwndParent = FindWindow(txtHCWClass, NULL);
  238. if (!hwndParent) {
  239. if (WinExec(txtHcw, SW_SHOW) < 32) {
  240. MsgBox(IDS_NO_HCW);
  241. return -1;
  242. }
  243. return 0;
  244. }
  245. // REVIEW (niklasb): The following code is unreachable, since
  246. // hinstPrev is always NULL for Win32 apps.
  247. // BUGBUG: We MUST prevent two copies of hcrtf running that both want
  248. // to talk to HCW. Either that, or we should request an identifier from
  249. // HCW so that we can indicate who we are when we send a message to HCW.
  250. #if 0
  251. if (hinstPrev) {
  252. // If we are already running, then simply activate HCW.EXE
  253. hwndParent = FindWindow(txtHCWClass, NULL);
  254. ASSERT(hwndParent);
  255. if (hwndParent)
  256. ShowWindow(hwndParent, SW_NORMAL);
  257. return 0;
  258. }
  259. #endif
  260. }
  261. CStr* cszHpjFile = new CStr();
  262. // ParseCmdLine returns FALSE for Forage commands
  263. if (!ParseCmdLine(lpszCmdLine, cszHpjFile->psz)) {
  264. DeleteTmpFiles();
  265. if (hwndParent) {
  266. PostMessage(hwndParent, WMP_BUILD_COMPLETE, FALSE, 0);
  267. SetFocus(hwndParent);
  268. }
  269. return 0;
  270. }
  271. if (!FInitializeHpj()) {
  272. MsgBox(IDS_INTERNAL_ERROR);
  273. return 1;
  274. }
  275. if (fGrind)
  276. InitGrind();
  277. struct _stat statbuf;
  278. /*
  279. * Make sure we'll be able to write the output file if everything
  280. * works and we need it
  281. */
  282. if (!_stat(szHlpFile, &statbuf)) {
  283. // file exists, see what it is
  284. if (statbuf.st_mode & S_IFDIR) {
  285. VReportError(HCERR_DIRECTORY, &errHpj, szHlpFile);
  286. return 1;
  287. }
  288. else if (!(statbuf.st_mode & S_IWRITE)) {
  289. VReportError(HCERR_WRITE_PROTECTED, &errHpj, szHlpFile);
  290. return 1;
  291. }
  292. else if (statbuf.st_mode & S_IFCHR) {
  293. VReportError(HCERR_DEVICE, &errHpj, szHlpFile);
  294. return 1;
  295. }
  296. }
  297. try {
  298. // parse the .HPJ project file
  299. if (!FParseHpj(cszHpjFile->psz)) {
  300. AbadonAllHope:
  301. #ifdef _DEBUG
  302. if (MessageBox(NULL, "Unable to parse the .HPJ file", "Click Retry to break into MSVC debugger",
  303. MB_RETRYCANCEL) == IDRETRY)
  304. DebugBreak();
  305. #endif
  306. AbandonPfsmg();
  307. return 1;
  308. }
  309. doGrind();
  310. delete cszHpjFile;
  311. if (fForceNoCompression)
  312. options.fsCompress &=
  313. ~(COMPRESS_TEXT_HALL | COMPRESS_TEXT_ZECK | COMPRESS_TEXT_PHRASE);
  314. else if (options.fsCompress & COMPRESS_MAXIMUM) {
  315. ptblRtfFiles->SetPosition(1); // re-initialize table position
  316. DWORD cbFiles = 0;
  317. while (ptblRtfFiles->GetString(szRtfFile)) {
  318. HFILE hfile;
  319. if ((hfile = _lopen(szRtfFile, OF_READ)) != HFILE_ERROR) {
  320. cbFiles += GetFileSize((HANDLE) hfile, NULL);
  321. _lclose(hfile);
  322. if (cbFiles >= SWITCH_TO_HALL_SIZE) {
  323. options.fsCompress &= ~COMPRESS_MAXIMUM;
  324. options.fsCompress |=
  325. (COMPRESS_TEXT_HALL | COMPRESS_TEXT_ZECK |
  326. COMPRESS_BMP_RLE | COMPRESS_BMP_ZECK);
  327. break;
  328. }
  329. }
  330. }
  331. if (cbFiles < SWITCH_TO_HALL_SIZE) {
  332. options.fsCompress &= ~COMPRESS_MAXIMUM;
  333. options.fsCompress |=
  334. (COMPRESS_TEXT_PHRASE | COMPRESS_TEXT_ZECK |
  335. COMPRESS_BMP_RLE | COMPRESS_BMP_ZECK);
  336. }
  337. }
  338. /*
  339. * REVIEW: This function modifies the default character format
  340. * according to .hpj option mapfontrange. It should move inside
  341. * hpj.c like forcefont did.
  342. */
  343. SetDefaultFontSize();
  344. // Create the output file system and related files
  345. if (!FCreatePfsmgSz(szHlpFile))
  346. goto AbadonAllHope;
  347. if (options.fsCompress & COMPRESS_TEXT_HALL && !LoadFtsDll()) {
  348. // If we can't load ftsrch.dll, then shut off Hall compression
  349. VReportError(HCERR_NO_HALL_COMPRESSION, &errHpj);
  350. options.fsCompress &= ~COMPRESS_TEXT_HALL;
  351. options.fsCompress |= COMPRESS_TEXT_ZECK;
  352. }
  353. if (options.fsCompress & COMPRESS_TEXT_HALL) {
  354. hCompressor = pNewCompressor(0);
  355. if (!hCompressor)
  356. OOM();
  357. }
  358. // Prepare for phrase or Hall compression
  359. if (!InitializePhraseGeneration(szHlpFile))
  360. HardExit();
  361. if (pphrase) { // we'll have a pphrase for phrase or Hall compression
  362. #ifdef CHECK_HALL
  363. poutPhrase = new COutput("phrase.txt");
  364. #endif
  365. #ifdef _DEBUG
  366. // ptblCheck = new CTable();
  367. #endif
  368. /*
  369. * Phrase pass -- used for either phrase or Hall compression.
  370. * This makes a pass through all the .RTF files in order to parse
  371. * all the text, titles, and entry macros.
  372. */
  373. fPhraseParsing = TRUE;
  374. // *** Pass 1 ***
  375. pSeekPast = (SEEK_PAST*) lcCalloc(ptblRtfFiles->CountStrings() *
  376. sizeof(SEEK_PAST));
  377. iCurFile = -1;
  378. ptblRtfFiles->SetPosition(1); // re-initialize table position
  379. while (ptblRtfFiles->GetString(szRtfFile)) {
  380. iCurFile++;
  381. if (!hwndParent && hwndGrind) {
  382. PSTR psz = StrRChr(szRtfFile, CH_BACKSLASH, fDBCSSystem);
  383. SetWindowText(hwndGrind, (psz ? psz + 1 : szRtfFile));
  384. }
  385. else if (IsWindowVisible(hwndGrind) && options.fReport) {
  386. wsprintf(szParentString,
  387. GetStringResource(IDS_SCANNING),
  388. szRtfFile);
  389. SendStringToParent(szParentString);
  390. doGrind();
  391. }
  392. switch (RcTextFromRTF(szRtfFile)) {
  393. case RC_Success:
  394. fFileFound = TRUE;
  395. if (pSeekPast[iCurFile].pfntbl)
  396. lcClearFree(&pSeekPast[iCurFile].pfntbl);
  397. break;
  398. case RC_Invalid:
  399. // zero out the file so we don't reread it.
  400. ptblRtfFiles->ReplaceString("",
  401. ptblRtfFiles->GetPosition() - 1);
  402. break;
  403. case RC_OutOfMemory:
  404. case RC_DiskFull:
  405. default:
  406. // REVIEW: has the problem been reported?
  407. // Go to uncompressed compile?
  408. HardExit();
  409. }
  410. }
  411. fPhraseParsing = FALSE;
  412. #ifdef CHECK_HALL
  413. delete poutPhrase;
  414. #endif
  415. if (!fFileFound)
  416. HardExit();
  417. if (fPhraseOnly) {
  418. CloseFilesPfsmg();
  419. RemoveGrind();
  420. DeleteTmpFiles();
  421. if (hwndParent)
  422. PostMessage(hwndParent, WMP_BUILD_COMPLETE, FALSE, 0);
  423. SetFocus(hwndParent);
  424. return 0;
  425. }
  426. }
  427. if ((options.fsCompress & COMPRESS_TEXT_PHRASE) &&
  428. !FCreateKeyPhrFileSz(szHlpFile))
  429. HardExit();
  430. #ifdef CHECK_HALL
  431. poutHall = new COutput("compress.txt");
  432. #endif
  433. if (options.fsFTS & FTS_ENABLED &&
  434. !(options.fsCompress & COMPRESS_TEXT_PHRASE) &&
  435. !(options.fsCompress & COMPRESS_TEXT_HALL)) {
  436. VReportError(HCERR_NO_FTS, &errHpj);
  437. options.fsFTS &= ~FTS_ENABLED;
  438. }
  439. else if (options.fsFTS & FTS_ENABLED) {
  440. LANGID langid = kwlcid.langid;
  441. if (!lcid) {
  442. langid = GetUserDefaultLangID();
  443. lcidFts = MAKELCID(langid, SORT_DEFAULT);
  444. }
  445. else
  446. lcidFts = lcid;
  447. struct stat statbuf;
  448. DWORD timestamp;
  449. if (stat(szHlpFile, &statbuf) == 0)
  450. timestamp = statbuf.st_mtime;
  451. else
  452. timestamp = 0; // BUGBUG: we should fail here
  453. charsetFts = defCharSet;
  454. if (!charsetFts) {
  455. switch (PRIMARYLANGID(langid)) {
  456. case LANG_KOREAN:
  457. charsetFts = HANGEUL_CHARSET;
  458. break;
  459. case LANG_CHINESE:
  460. charsetFts = CHINESEBIG5_CHARSET;
  461. break;
  462. case LANG_JAPANESE:
  463. charsetFts = SHIFTJIS_CHARSET;
  464. break;
  465. default:
  466. charsetFts = DEFAULT_CHARSET;
  467. break;
  468. }
  469. }
  470. hFtsIndex = pNewIndex((PBYTE) szHlpFile, timestamp, 0,
  471. charsetFts, lcidFts,
  472. TOPIC_SEARCH | PHRASE_SEARCH);
  473. // BUGBUG Need proper error message if above fails.
  474. ASSERT(hFtsIndex);
  475. }
  476. if (options.fsCompress & COMPRESS_TEXT_HALL) {
  477. PBYTE pbImage, pbIndex;
  478. // Not only saves, but also gets the phrase table info needed for
  479. // the pSetPhraseTable() call.
  480. if (!SaveHallTables(&pbImage, &pbIndex))
  481. HardExit();
  482. pDeleteCompressor(hCompressor);
  483. hCompressor = pNewCompressor(0);
  484. if (!hCompressor)
  485. OOM();
  486. pSetPhraseTable(hCompressor, pbImage, jHdr.cbImageUncompressed,
  487. pbIndex, jHdr.cbIndex);
  488. }
  489. // *** Final Pass through the RTF files ****
  490. VAcqBufs(); // Acquire buffers
  491. FInitDelayExecution();
  492. ptblRtfFiles->SetPosition(1); // re-initialize table position
  493. iCurFile = -1;
  494. while (ptblRtfFiles->GetString(szRtfFile)) {
  495. iCurFile++;
  496. if (!*szRtfFile)
  497. continue; // we encountered an error in the first pass
  498. if (!hwndParent && hwndGrind) {
  499. PSTR psz = StrRChr(szRtfFile, CH_BACKSLASH, fDBCSSystem);
  500. CStr cszCopy((psz ? psz : szRtfFile));
  501. CharLower(cszCopy);
  502. SetWindowText(hwndGrind, cszCopy);
  503. }
  504. if (options.fReport) {
  505. wsprintf(szParentString, GetStringResource(IDS_COMPILING),
  506. szRtfFile);
  507. SendStringToParent(szParentString);
  508. }
  509. switch (RcCompileRTF(szRtfFile)) {
  510. case RC_Success:
  511. case RC_Invalid:
  512. break;
  513. case RC_OutOfMemory:
  514. case RC_DiskFull:
  515. default:
  516. HardExit();
  517. break;
  518. }
  519. }
  520. UnlinkHlpifNoFCP();
  521. VForceTopicFCP();
  522. VFlushBuffer(TRUE);
  523. EndDelayExecution();
  524. doGrind();
  525. // if (options.fsCompress & COMPRESS_ZECK)
  526. // FreeZeckGlobals();
  527. SendStringToParent("\r\n"); // send a blank line
  528. VOutFontTable();
  529. if (!FResolveNextlist(fmsg.hfTopic) ||
  530. !FResolveContextErrors() ||
  531. !FOutAliasToCtxBtree())
  532. HardExit();
  533. VOutCtxOffsetTable();
  534. VOutSystemFile();
  535. CloseFilesPfsmg();
  536. if (hFtsIndex)
  537. pSaveIndex(hFtsIndex, NULL);
  538. #ifdef CHECK_HALL
  539. delete poutHall;
  540. #endif
  541. if (!iflags.fRtfInput) {
  542. DWORD dwFinalTime = (GetTickCount() - dwTime) / 1000;
  543. int minutes = (dwFinalTime / 60);
  544. int seconds = (dwFinalTime - (minutes * 60L));
  545. char szPlural[10];
  546. strcpy(szPlural, GetStringResource(IDS_PLURAL));
  547. wsprintf(szParentString, GetStringResource(IDS_STATS),
  548. FormatNumber(hlpStats.cTopics), ((hlpStats.cTopics == 1) ? "" : szPlural),
  549. FormatNumber(hlpStats.cJumps), ((hlpStats.cJumps == 1) ? "" : szPlural),
  550. FormatNumber(hlpStats.cKeywords), ((hlpStats.cKeywords == 1) ? "" : szPlural),
  551. FormatNumber(hlpStats.cBitmaps), ((hlpStats.cBitmaps == 1) ? "" : szPlural));
  552. SendStringToParent(szParentString);
  553. if (pLogFile) {
  554. if (options.fDBCS)
  555. pLogFile->outstring_eol(txtZeroLength);
  556. pLogFile->outstring(szParentString);
  557. }
  558. wsprintf(szParentString, "\r\nFile size: %s\r\n", FormatNumber(cbHlpFile));
  559. SendLogStringToParent();
  560. if (cbGraphics) {
  561. wsprintf(szParentString, "Bitmaps: %s bytes\r\n", FormatNumber(cbGraphics));
  562. SendLogStringToParent();
  563. }
  564. ReportCharCounts();
  565. wsprintf(szParentString, GetStringResource(IDS_COMPILE_TIME),
  566. FormatNumber(minutes), ((minutes == 1) ? "" : szPlural),
  567. seconds, ((seconds == 1) ? "" : szPlural));
  568. SendLogStringToParent();
  569. #if (defined(_DEBUG))
  570. srand((UINT) GetTickCount());
  571. int rd1 = rand() & 31;
  572. int rd2 = rand() & 31;
  573. int rd3 = rand() & 31;
  574. wsprintf(szParentString, "%d note%s, %d %s %s %s warning%s\r\n",
  575. errcount.cNotes, (PSTR) ((errcount.cNotes == 1) ? "" : szPlural),
  576. errcount.cWarnings,
  577. szWarning1[rd1], szWarning2[rd1], szWarning3[rd1],
  578. (PSTR) ((errcount.cWarnings == 1) ? "" : szPlural));
  579. #else
  580. wsprintf(szParentString, GetStringResource(IDS_WARN_COUNT),
  581. errcount.cNotes, (PSTR) ((errcount.cNotes == 1) ? "" : szPlural),
  582. errcount.cWarnings, (PSTR) ((errcount.cWarnings == 1) ? "" : szPlural));
  583. #endif
  584. SendLogStringToParent();
  585. #ifdef _DEBUG
  586. SendLogStringToParent("\r\n");
  587. if (idHighestUsedFont + 1 < lcSize(paCharSets)) {
  588. int cbSaved = lcSize(paCharSets) - (idHighestUsedFont + 1);
  589. wsprintf(szParentString, "Total Fonts: %d, Help File Fonts: %d, Removed %s font%s\r\n",
  590. lcSize(paCharSets), idHighestUsedFont + 1,
  591. FormatNumber(cbSaved), ((cbSaved == 1) ? "" : szPlural));
  592. SendLogStringToParent();
  593. }
  594. lcReport(szParentString);
  595. SendLogStringToParent();
  596. if (fCompressionBusted)
  597. SendLogStringToParent("\r\n\r\n*** Compression is broken!!! Phrase scan doesn't match phrase compression.\r\n\r\n");
  598. #endif
  599. }
  600. if (fFatalWarning) {
  601. remove(szHlpFile);
  602. fBuildResult = FALSE;
  603. }
  604. else if (hwndParent || iflags.fRunHelp) {
  605. if (!StrChr(szHlpFile, CH_BACKSLASH, fDBCSSystem)) {
  606. // Add the full directory before sending it to HCW
  607. PSTR psz = lcStrDup(szHlpFile);
  608. GetCurrentDirectory(sizeof(szHlpFile), szHlpFile);
  609. AddTrailingBackslash(szHlpFile);
  610. strcat(szHlpFile, psz);
  611. lcFree(psz);
  612. }
  613. if (iflags.fRunHelp) {
  614. strcpy(szParentString, "winhelp ");
  615. strcat(szParentString, szHlpFile);
  616. WinExec(szParentString, SW_SHOW);
  617. }
  618. if (hwndParent) {
  619. ASSERT(pszMap);
  620. strcpy(pszMap, szHlpFile);
  621. fBuildResult = TRUE;
  622. }
  623. }
  624. } // end of try block
  625. //catch (EXCEPTION_ERROR err) {
  626. except(EXCEPTION_EXECUTE_HANDLER) {
  627. QFSHR qfshr = (QFSHR) hfsOut;
  628. if (hfsOut && qfshr->fid != HFILE_ERROR)
  629. _lclose(qfshr->fid);
  630. remove(szHlpFile);
  631. fBuildResult = FALSE;
  632. err;
  633. }
  634. if (pLogFile)
  635. delete pLogFile;
  636. RemoveGrind();
  637. FreeFtsDll();
  638. DeleteTmpFiles();
  639. if (hwndParent) {
  640. SendMessage(hwndParent, WMP_ERROR_COUNT, errcount.cWarnings,
  641. errcount.cNotes);
  642. PostMessage(hwndParent, WMP_BUILD_COMPLETE, fBuildResult, 0);
  643. // BUGBUG: SetForegroundWindow not supported in Win32s
  644. if (!fNoActivation)
  645. SetForegroundWindow(hwndParent);
  646. }
  647. return 0;
  648. }
  649. /***************************************************************************
  650. FUNCTION: SendStringToParent
  651. PURPOSE: Send a string to our parent
  652. RETURNS:
  653. COMMENTS:
  654. MODIFICATION DATES:
  655. 12-Apr-1994 [ralphw]
  656. ***************************************************************************/
  657. static const int GRIND_COUNT = 10;
  658. void STDCALL SendStringToParent(PCSTR pszString)
  659. {
  660. if (!hwndParent) {
  661. #ifdef _DEBUG
  662. OutputDebugString(pszString);
  663. #endif
  664. return;
  665. }
  666. if (hwndGrind && ++cGrind > GRIND_COUNT) {
  667. doGrind();
  668. cGrind = 0;
  669. }
  670. if (!fTellParent) {
  671. return;
  672. }
  673. ASSERT(strlen(pszString) < MAX_PASS_STRING);
  674. if (!hfShare)
  675. CreateSharedMemory();
  676. strcpy(pszMap, pszString);
  677. SendMessage(hwndParent, WMP_MSG, 0, 0);
  678. }
  679. void STDCALL SendStringToParent(int id)
  680. {
  681. if (!hwndParent) {
  682. #ifdef _DEBUG
  683. OutputDebugString(GetStringResource(id));
  684. #endif
  685. return;
  686. }
  687. SendStringToParent(GetStringResource(id));
  688. }
  689. void STDCALL SendLogStringToParent(PCSTR pszString)
  690. {
  691. SendStringToParent(pszString);
  692. if (pLogFile)
  693. pLogFile->outstring(pszString);
  694. }
  695. /***************************************************************************
  696. FUNCTION: ParseCmdLine
  697. PURPOSE: Parse the command line
  698. PARAMETERS:
  699. lpszCmdLine
  700. pszHpjFile
  701. RETURNS:
  702. COMMENTS:
  703. MODIFICATION DATES:
  704. 12-Aug-1993 [ralphw]
  705. ***************************************************************************/
  706. static BOOL STDCALL ParseCmdLine(PSTR lpszCmdLine, PSTR pszHpjFile)
  707. {
  708. CStr sz(lpszCmdLine); // bring it into near space
  709. for (PSTR psz = sz.psz; psz != NULL && *psz != '\0'; ) {
  710. if (IsSwitchChar(*psz)) {
  711. psz++; // skip over the dash or slash
  712. switch (tolower(*psz)) {
  713. case 'x':
  714. psz++;
  715. while (isalpha(*psz)) {
  716. switch(tolower(*psz)) {
  717. case 'h': // run help when done
  718. iflags.fRunHelp = TRUE;
  719. break;
  720. case 't': // trusted RTF provider
  721. iflags.fTrusted = TRUE;
  722. break;
  723. case 'n': // don't display grinder window
  724. iflags.fNoGrinder = TRUE;
  725. break;
  726. case 'r': // RTF file specified
  727. iflags.fRtfInput = TRUE;
  728. break;
  729. case 'c': // RTF is in the clipboard
  730. {
  731. /*
  732. * GetRtfInClipboard() may reallocate
  733. * sz and in so doing move it to a
  734. * different location. So, we save the
  735. * offset from the beginning, and reset
  736. * psz based on this offset.
  737. */
  738. int offset = psz - sz.psz;
  739. if (!GetRtfInClipboard(&sz))
  740. return FALSE;
  741. /*
  742. * RTF filename will now be appended
  743. * to the end of sz.
  744. */
  745. iflags.fRtfInput = TRUE;
  746. psz = sz.psz + offset;
  747. }
  748. break;
  749. default:
  750. // BUGBUG: need to indicate it is an invalid test
  751. // switch
  752. wsprintf(szParentString,
  753. GetStringResource(IDS_INVALID_X_SWITCH), *psz);
  754. MessageBox(NULL, szParentString,
  755. GetStringResource(IDS_VERSION), MB_OK);
  756. break;
  757. }
  758. psz++;
  759. }
  760. break;
  761. case 'o':
  762. psz = GetArg(szHlpFile, FirstNonSpace(psz + 1, fDBCSSystem));
  763. break;
  764. case 'n': // No options
  765. psz++;
  766. do {
  767. switch (tolower(*psz)) {
  768. case 'a':
  769. fNoActivation = TRUE;
  770. break;
  771. case 'g': // no grinder
  772. fGrind = FALSE;
  773. break;
  774. case 'c': // no compression
  775. fForceNoCompression = TRUE;
  776. break;
  777. }
  778. psz++;
  779. } while (isalpha(*psz));
  780. break;
  781. // REVIEW: obsolete...
  782. case 'j':
  783. fHallPassOne = TRUE;
  784. psz++;
  785. break;
  786. case 'p':
  787. fPhraseOnly = TRUE;
  788. psz++;
  789. break;
  790. case 'f': // forage commands
  791. psz++;
  792. forage(psz);
  793. return FALSE;
  794. case 't': // test commands
  795. switch (tolower(psz[1])) {
  796. case 'c':
  797. doCntTest(psz + 2);
  798. return FALSE;
  799. case 'm':
  800. Execute(FirstNonSpace(psz + 2, fDBCSSystem));
  801. return FALSE;
  802. default:
  803. // BUGBUG: need to indicate it is an invalid test
  804. // switch
  805. wsprintf(szScratchBuf,
  806. GetStringResource(IDS_INVALID_SWITCH), *psz);
  807. szMsgBox(szScratchBuf);
  808. psz += 2;
  809. break;
  810. }
  811. break;
  812. case 'b': { // BMROOT path
  813. char szRoot[_MAX_PATH];
  814. psz = GetArg(szRoot, FirstNonSpace(psz + 1, fDBCSSystem));
  815. if (!options.ptblBmpRoot)
  816. options.ptblBmpRoot = new CTable;
  817. ParsePath(options.ptblBmpRoot, szRoot, (OPT) OPT_BMROOT);
  818. }
  819. break;
  820. case 'r': // run help when done
  821. iflags.fRunHelp = TRUE;
  822. psz++;
  823. break;
  824. default:
  825. wsprintf(szScratchBuf,
  826. GetStringResource(IDS_INVALID_SWITCH), *psz);
  827. szMsgBox(szScratchBuf);
  828. psz++;
  829. break;
  830. }
  831. while (*psz && *psz == ' ')
  832. psz++;
  833. }
  834. // it wasn't a switch
  835. else {
  836. lstrcpy(pszHpjFile, psz);
  837. break;
  838. }
  839. }
  840. // Make certain we have an output filename
  841. if (!szHlpFile[0]) {
  842. strcpy(szHlpFile, pszHpjFile);
  843. ChangeExtension(szHlpFile, IDS_EXT_HLP);
  844. }
  845. if (hfShare)
  846. CloseHandle(hfShare);
  847. return TRUE;
  848. }
  849. void STDCALL OutSz(int id, PCSTR psz)
  850. {
  851. wsprintf(szParentString, GetStringResource(id), psz);
  852. SendStringToParent(szParentString);
  853. }
  854. void STDCALL OutInt(int id, int iVal)
  855. {
  856. wsprintf(szParentString, GetStringResource(id), iVal);
  857. SendStringToParent(szParentString);
  858. }
  859. void STDCALL OutInt(PCSTR pszFormat, int iVal)
  860. {
  861. wsprintf(szParentString, pszFormat, iVal);
  862. SendStringToParent(szParentString);
  863. }
  864. void STDCALL OutLong(PCSTR pszFormat, int iVal)
  865. {
  866. wsprintf(szParentString, pszFormat, iVal);
  867. SendStringToParent(szParentString);
  868. }
  869. void STDCALL OutLong(int id, int iVal)
  870. {
  871. wsprintf(szParentString, GetStringResource(id), iVal);
  872. SendStringToParent(szParentString);
  873. }
  874. void STDCALL OutErrorRc(RC_TYPE rc, BOOL fPanic)
  875. {
  876. SendStringToParent("\t");
  877. switch (rc) {
  878. case RC_Invalid:
  879. wsprintf(szParentString, GetStringResource(IDS_INVALID_FILE));
  880. break;
  881. case RC_NoExists:
  882. wsprintf(szParentString, GetStringResource(IDS_FILE_NOT_FOUND));
  883. break;
  884. case RC_BadVersion:
  885. wsprintf(szParentString, GetStringResource(IDS_INCOMPATIBLE));
  886. break;
  887. case RC_DiskFull:
  888. wsprintf(szParentString, GetStringResource(IDS_DISK_FULL));
  889. break;
  890. case RC_NoFileHandles:
  891. wsprintf(szParentString, GetStringResource(HCERR_NO_FILE_HANDLES));
  892. break;
  893. case RC_OutOfMemory:
  894. wsprintf(szParentString, GetStringResource(HCERR_OOM));
  895. break;
  896. case RC_BadArg:
  897. ASSERT(FALSE); // should never happen
  898. break;
  899. case RC_NoPermission:
  900. wsprintf(szParentString, GetStringResource(IDS_ACCESS_DENIED));
  901. break;
  902. case RC_CantWrite:
  903. wsprintf(szParentString, GetStringResource(IDS_CANT_WRITE));
  904. break;
  905. default:
  906. wsprintf(szParentString, GetStringResource(IDS_FORAGE_ERROR), rc);
  907. break;
  908. }
  909. strcat(szParentString, "\r\n");
  910. SendStringToParent(szParentString);
  911. if (pLogFile)
  912. pLogFile->outstring(szParentString);
  913. }
  914. int STDCALL MsgBox(UINT idString)
  915. {
  916. return szMsgBox(GetStringResource(idString));
  917. }
  918. int STDCALL szMsgBox(PCSTR pszMsg)
  919. {
  920. return MessageBox(NULL, pszMsg, pgszTitleBuf, MB_OK | MB_ICONHAND);
  921. }
  922. BOOL STDCALL GetRtfInClipboard(CStr* pcsz)
  923. {
  924. if (OpenClipboard(NULL)) {
  925. UINT clipfmt = 0;
  926. do {
  927. char szBuf[100];
  928. clipfmt = EnumClipboardFormats(clipfmt);
  929. if (clipfmt >= 0xC000) {
  930. GetClipboardFormatName(clipfmt, szBuf, sizeof(szBuf));
  931. if (_stricmp(szBuf, "Rich Text Format") == 0)
  932. break;
  933. }
  934. } while (clipfmt != 0);
  935. if (clipfmt != 0) {
  936. // REVIEW: this would be faster if we used our virtual file class
  937. FM fmTmp = FmNewTemp();
  938. ConfirmOrDie(fmTmp);
  939. HFILE hf = _lopen(fmTmp, OF_WRITE);
  940. /*
  941. * BUGBUG: need to complain when we can't open the temporary file
  942. * or we run out of disk space.
  943. */
  944. if (hf != HFILE_ERROR) {
  945. PBYTE pb = (PBYTE) GetClipboardData(clipfmt);
  946. int cb = GlobalSize((HGLOBAL) pb);
  947. int cbWrite = _lwrite(hf, (LPCSTR) pb, cb);
  948. _lclose(hf);
  949. if (cb == cbWrite) {
  950. *pcsz += " ";
  951. *pcsz += fmTmp;
  952. }
  953. else
  954. clipfmt = 0; // probably ran out of disk space
  955. }
  956. else
  957. clipfmt = 0; // probably ran out of disk space
  958. }
  959. CloseClipboard();
  960. return (BOOL) clipfmt;
  961. }
  962. return FALSE;
  963. }
  964. /***************************************************************************
  965. FUNCTION: GetTmpDirectory
  966. PURPOSE: Returns a pointer to the directory name to put temporary
  967. files in. The name is guaranteed to end with a backslash or
  968. colon.
  969. PARAMETERS:
  970. void
  971. RETURNS:
  972. COMMENTS:
  973. MODIFICATION DATES:
  974. 02-Jul-1994 [ralphw]
  975. ***************************************************************************/
  976. PCSTR STDCALL GetTmpDirectory(void)
  977. {
  978. static PSTR pszTmp = NULL;
  979. if (options.pszTmpDir)
  980. return options.pszTmpDir;
  981. else if (pszTmp)
  982. return pszTmp;
  983. else {
  984. char szTmpName[MAX_PATH];
  985. GetTempPath(sizeof(szTmpName), szTmpName);
  986. AddTrailingBackslash(szTmpName);
  987. return (pszTmp = lcStrDup(szTmpName));
  988. }
  989. }
  990. ERRORCODE (APIENTRY* pSaveIndex)(HINDEX lIndex, LPSTR pOutput);
  991. HCOMPRESSOR (APIENTRY* pNewCompressor)(UINT);
  992. ERRORCODE (APIENTRY* pScanText)(HCOMPRESSOR, PBYTE, UINT, UINT);
  993. ERRORCODE (APIENTRY* pGetPhraseTable)(HCOMPRESSOR, PUINT, PBYTE *, PUINT, PBYTE *, PUINT);
  994. ERRORCODE (APIENTRY* pSetPhraseTable)(HCOMPRESSOR, PBYTE, UINT, PBYTE, UINT);
  995. INT (APIENTRY* pCompressText)(HCOMPRESSOR, PBYTE, UINT, PBYTE *, UINT);
  996. INT (APIENTRY* pDecompressText)(HCOMPRESSOR, PBYTE, UINT, PBYTE);
  997. ERRORCODE (APIENTRY* pDeleteCompressor)(HCOMPRESSOR);
  998. HINDEX (APIENTRY* pNewIndex)(PBYTE, UINT, UINT, UINT, UINT, UINT);
  999. ERRORCODE (APIENTRY* pScanTopicTitle)(HINDEX, PBYTE, UINT, UINT, HANDLE, UINT, UINT);
  1000. ERRORCODE (APIENTRY* pScanTopicText)(HINDEX, PBYTE, UINT, UINT, UINT);
  1001. BOOL STDCALL LoadFtsDll(void)
  1002. {
  1003. FM fm;
  1004. hmodFts = HmodFromName("ftsrch.dll", &fm);
  1005. if (!hmodFts) {
  1006. VReportError(HCERR_MISSING_FTSRCH, &errHpj);
  1007. return FALSE;
  1008. }
  1009. pNewCompressor =
  1010. (NEWCOMPRESSOR) GetProcAddress(hmodFts, "NewCompressor");
  1011. pScanText =
  1012. (SCANTEXT) GetProcAddress(hmodFts, "ScanText");
  1013. pGetPhraseTable =
  1014. (GETPHRASETABLE) GetProcAddress(hmodFts, "GetPhraseTable");
  1015. pSetPhraseTable =
  1016. (SETPHRASETABLE) GetProcAddress(hmodFts, "SetPhraseTable");
  1017. pCompressText =
  1018. (COMPRESSTEXT) GetProcAddress(hmodFts, "CompressText");
  1019. pDecompressText =
  1020. (DECOMPRESSTEXT) GetProcAddress(hmodFts, "DecompressText");
  1021. pDeleteCompressor =
  1022. (DELETECOMPRESSOR) GetProcAddress(hmodFts, "DeleteCompressor");
  1023. pScanTopicTitle =
  1024. (SCANTOPICTITLE) GetProcAddress(hmodFts, "ScanTopicTitle");
  1025. pScanTopicText =
  1026. (SCANTOPICTEXT) GetProcAddress(hmodFts, "ScanTopicText");
  1027. pNewIndex =
  1028. (NEWINDEX) GetProcAddress(hmodFts, "NewIndex");
  1029. pSaveIndex =
  1030. (SAVEINDEX) GetProcAddress(hmodFts, "SaveIndex");
  1031. if (!pNewCompressor || !pScanText || !pGetPhraseTable ||
  1032. !pSetPhraseTable || !pCompressText || !pDecompressText ||
  1033. !pDeleteCompressor || !pNewIndex || !pScanTopicTitle ||
  1034. !pScanTopicText) {
  1035. VReportError(HCERR_MISSING_FTSRCH, &errHpj);
  1036. FreeFtsDll();
  1037. return FALSE;
  1038. }
  1039. return TRUE;
  1040. }
  1041. void STDCALL FreeFtsDll(void)
  1042. {
  1043. if (hmodFts) {
  1044. FreeLibrary(hmodFts);
  1045. hmodFts = NULL;
  1046. }
  1047. }
  1048. HINSTANCE STDCALL HmodFromName(PCSTR pszDllName, FM* pfm)
  1049. {
  1050. FM fm;
  1051. HINSTANCE hmodReturn = 0;
  1052. /*
  1053. * Look for the DLL starting with the directory of the current help
  1054. * file, then the current directory, directories specified in
  1055. * winhelp.ini, the windows\help directory and the PATH.
  1056. */
  1057. fm = FmNewExistSzDir(pszDllName,
  1058. DIR_CUR_HELP | DIR_INI | DIR_PATH | DIR_CURRENT | DIR_SYSTEM);
  1059. if (fm) {
  1060. hmodReturn = LoadLibrary(fm);
  1061. }
  1062. if (!hmodReturn) {
  1063. char szNewName[MAX_PATH];
  1064. strcpy(szNewName, pszDllName);
  1065. CharUpper(szNewName); // so we can search for .dll names
  1066. // Only substitute extensions if we weren't told it was a .DLL file
  1067. if (!strstr(szNewName, "DLL")) {
  1068. ChangeExtension(szNewName, "DLL");
  1069. hmodReturn = HmodFromName(szNewName, &fm);
  1070. }
  1071. }
  1072. *pfm = fm;
  1073. return hmodReturn;
  1074. }