mirror of https://github.com/lianthony/NT4.0
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
1315 lines
46 KiB
/************************************************************************
|
|
* *
|
|
* WMAIN.CPP *
|
|
* *
|
|
* Copyright (C) Microsoft Corporation 1993-1994 *
|
|
* All Rights reserved. *
|
|
* *
|
|
*************************************************************************
|
|
* *
|
|
* Module Intent *
|
|
* *
|
|
* This module contains initialization and the WinMain routine *
|
|
* *
|
|
* Command line parameters:
|
|
|
|
-x do not attempt to find parent
|
|
c RTF is in the clipboard
|
|
h run winhelp after compiling
|
|
n don't display grinder window
|
|
r file RTF file -- change extension to .HLP and create help file
|
|
t trusted caller -- assume RTF is valid
|
|
|
|
-f forage (help_file output_file)
|
|
a dump region map
|
|
b dump structs
|
|
c topics
|
|
d text
|
|
e bindings
|
|
f hash table
|
|
|
|
h klink
|
|
i alink
|
|
|
|
-b path BMROOT path
|
|
-o file specifies the help file to create
|
|
-p generate phrase file only (REVIEW: supported?)
|
|
-r run WinHelp after compiling
|
|
|
|
-t test commands
|
|
c file test .CNT file
|
|
m macro test macro (REVIEW: supported?)
|
|
|
|
-n no options
|
|
g no grinder
|
|
a no activation on completion
|
|
c no compression
|
|
|
|
|
|
************************************************************************/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#include <direct.h>
|
|
|
|
#include "cphrase.h"
|
|
#include "..\common\resource.h"
|
|
#include "..\common\coutput.h"
|
|
#include "..\ftsrch\ftsiface.h"
|
|
#include "ftsrch.h"
|
|
|
|
#define IsSwitchChar(ch) ((ch) == '-' || (ch) == '/')
|
|
|
|
extern HINDEX hFtsIndex;
|
|
extern HCOMPRESSOR hCompressor;
|
|
|
|
char const txtHcw[] = "hcw.exe";
|
|
extern COutput* pLogFile;
|
|
|
|
static BOOL STDCALL ParseCmdLine(PSTR lpszCmdLine, PSTR pszHpjFile);
|
|
|
|
static ERR err;
|
|
|
|
#if (defined(_DEBUG))
|
|
|
|
static PSTR szWarning1[] = {
|
|
"artless",
|
|
"bawdy",
|
|
"beslubbering",
|
|
"bootless",
|
|
"churlish",
|
|
"cockered",
|
|
"clouted",
|
|
"craven",
|
|
"currish",
|
|
"dankish",
|
|
"dissembling",
|
|
"droning",
|
|
"errant",
|
|
"fawning",
|
|
"fobbing",
|
|
"froward",
|
|
"frothy",
|
|
"gleeking",
|
|
"goatish",
|
|
"gorbellied",
|
|
"impertinent",
|
|
"infectious",
|
|
"jarring",
|
|
"loggerheaded",
|
|
"lumpish",
|
|
"mammering",
|
|
"mangled",
|
|
"mewling",
|
|
"paunchy",
|
|
"pribbling",
|
|
"puking",
|
|
"puny",
|
|
"quailing",
|
|
"rank",
|
|
"reeky",
|
|
"roguish",
|
|
"ruttish",
|
|
"saucy",
|
|
"spleeny",
|
|
"spongy",
|
|
"surly",
|
|
"tottering",
|
|
"unmuzzled",
|
|
"vain",
|
|
"venomed",
|
|
"villainous",
|
|
"warped",
|
|
"wayward",
|
|
"weedy",
|
|
"yeasty",
|
|
};
|
|
|
|
static PSTR szWarning2[] = {
|
|
"base-court",
|
|
"bat-fowling",
|
|
"beef-witted",
|
|
"beetle-headed",
|
|
"boil-brained",
|
|
"clapper-clawed",
|
|
"clay-brained",
|
|
"common-kissing",
|
|
"crook-pated",
|
|
"dismal-dreaming",
|
|
"dizzy-eyed",
|
|
"doghearted",
|
|
"dread-bolted",
|
|
"earth-vexing",
|
|
"elf-skinned",
|
|
"fat-kidneyed",
|
|
"fen-sucked",
|
|
"flap-mouthed",
|
|
"fly-bitten",
|
|
"folly-fallen",
|
|
"fool-born",
|
|
"full-gorged",
|
|
"guts-griping",
|
|
"half-faced",
|
|
"hasty-witted",
|
|
"hedge-born",
|
|
"hell-hated",
|
|
"idle-headed",
|
|
"ill-breeding",
|
|
"ill-nurtured",
|
|
"knotty-pated",
|
|
"milk-livered",
|
|
"motley-minded",
|
|
"onion-eyed",
|
|
"plume-plucked",
|
|
"pottle-deep",
|
|
"pox-marked",
|
|
"reeling-ripe",
|
|
"rough-hewn",
|
|
"rude-growing",
|
|
"rump-fed",
|
|
"shard-borne",
|
|
"sheep-biting",
|
|
"spur-galled",
|
|
"swag-bellied",
|
|
"tardy-gaited",
|
|
"tickle-brained",
|
|
"toad-spotted",
|
|
"unchin-snouted",
|
|
"weather-bitten",
|
|
};
|
|
|
|
static PSTR szWarning3[] = {
|
|
"apple-john",
|
|
"blathering",
|
|
"barnacley",
|
|
"maggot ridden",
|
|
"boar-pig like",
|
|
"bugbearing",
|
|
"bum-bailey",
|
|
"canker-blossom",
|
|
"clack-dish",
|
|
"clotpoling",
|
|
"coxcombing",
|
|
"codpiecing",
|
|
"death-tokening",
|
|
"dewberry",
|
|
"flap-dragon",
|
|
"flax-wench",
|
|
"flirt-gill",
|
|
"foot-licker",
|
|
"fustilarian",
|
|
"giglet",
|
|
"gudgeon",
|
|
"haggardly",
|
|
"harpy",
|
|
"hedge-pig",
|
|
"horn-beast",
|
|
"hugger-mugger",
|
|
"joltheaded",
|
|
"lewdster",
|
|
"louty",
|
|
"maggot-pie",
|
|
"malt-worm",
|
|
"mammet",
|
|
"measley",
|
|
"minnowing",
|
|
"miscreant",
|
|
"moldwarping",
|
|
"mumble-news",
|
|
"nut-hooking",
|
|
"pigeon-egging",
|
|
"pignuting",
|
|
"puttocking",
|
|
"pumpion",
|
|
"ratsbanish",
|
|
"scutly",
|
|
"skainsmately",
|
|
"strumpeting",
|
|
"varloting",
|
|
"vassaling",
|
|
"whey-facing",
|
|
"wagtailing",
|
|
};
|
|
|
|
#endif // DEBUG
|
|
|
|
BOOL STDCALL GetRtfInClipboard(CStr* pcsz);
|
|
|
|
#include <io.h> // For Zeck Debug code
|
|
#include <fcntl.h>
|
|
|
|
static PSTR pgszTitleBuf;
|
|
static LPTOP_LEVEL_EXCEPTION_FILTER OldFilter;
|
|
const int SWITCH_TO_HALL_SIZE = (1024 * 1024);
|
|
|
|
int STDCALL WinMain(HINSTANCE hinstCur, HINSTANCE hinstPrev,
|
|
PSTR lpszCmdLine, int iCmdShow)
|
|
{
|
|
char szRtfFile[MAX_PATH];
|
|
BOOL fFileFound = FALSE;
|
|
BOOL fBuildResult = FALSE;
|
|
|
|
DWORD dwTime = GetTickCount();
|
|
|
|
SetErrorMode( SEM_NOALIGNMENTFAULTEXCEPT );
|
|
|
|
// REVIEW: we should add an exception handler here for HardExit()
|
|
|
|
hinstApp = hinstCur;
|
|
pgszTitleBuf = AllocateResourceString(IDS_TITLE);
|
|
fDBCSSystem = IsDbcsSystem();
|
|
|
|
if (!strstr(lpszCmdLine, "-x") && !strstr(lpszCmdLine, "/x")) {
|
|
hwndParent = FindWindow(txtHCWClass, NULL);
|
|
if (!hwndParent) {
|
|
if (WinExec(txtHcw, SW_SHOW) < 32) {
|
|
MsgBox(IDS_NO_HCW);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// REVIEW (niklasb): The following code is unreachable, since
|
|
// hinstPrev is always NULL for Win32 apps.
|
|
|
|
|
|
// BUGBUG: We MUST prevent two copies of hcrtf running that both want
|
|
// to talk to HCW. Either that, or we should request an identifier from
|
|
// HCW so that we can indicate who we are when we send a message to HCW.
|
|
#if 0
|
|
if (hinstPrev) {
|
|
|
|
// If we are already running, then simply activate HCW.EXE
|
|
|
|
hwndParent = FindWindow(txtHCWClass, NULL);
|
|
ASSERT(hwndParent);
|
|
if (hwndParent)
|
|
ShowWindow(hwndParent, SW_NORMAL);
|
|
return 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
CStr* cszHpjFile = new CStr();
|
|
|
|
// ParseCmdLine returns FALSE for Forage commands
|
|
|
|
if (!ParseCmdLine(lpszCmdLine, cszHpjFile->psz)) {
|
|
DeleteTmpFiles();
|
|
if (hwndParent) {
|
|
PostMessage(hwndParent, WMP_BUILD_COMPLETE, FALSE, 0);
|
|
SetFocus(hwndParent);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if (!FInitializeHpj()) {
|
|
MsgBox(IDS_INTERNAL_ERROR);
|
|
return 1;
|
|
}
|
|
if (fGrind)
|
|
InitGrind();
|
|
|
|
struct _stat statbuf;
|
|
|
|
/*
|
|
* Make sure we'll be able to write the output file if everything
|
|
* works and we need it
|
|
*/
|
|
|
|
if (!_stat(szHlpFile, &statbuf)) {
|
|
|
|
// file exists, see what it is
|
|
|
|
if (statbuf.st_mode & S_IFDIR) {
|
|
VReportError(HCERR_DIRECTORY, &errHpj, szHlpFile);
|
|
return 1;
|
|
}
|
|
else if (!(statbuf.st_mode & S_IWRITE)) {
|
|
VReportError(HCERR_WRITE_PROTECTED, &errHpj, szHlpFile);
|
|
return 1;
|
|
}
|
|
else if (statbuf.st_mode & S_IFCHR) {
|
|
VReportError(HCERR_DEVICE, &errHpj, szHlpFile);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
try {
|
|
|
|
// parse the .HPJ project file
|
|
|
|
if (!FParseHpj(cszHpjFile->psz)) {
|
|
AbadonAllHope:
|
|
|
|
#ifdef _DEBUG
|
|
if (MessageBox(NULL, "Unable to parse the .HPJ file", "Click Retry to break into MSVC debugger",
|
|
MB_RETRYCANCEL) == IDRETRY)
|
|
DebugBreak();
|
|
#endif
|
|
AbandonPfsmg();
|
|
return 1;
|
|
}
|
|
|
|
doGrind();
|
|
|
|
delete cszHpjFile;
|
|
|
|
if (fForceNoCompression)
|
|
options.fsCompress &=
|
|
~(COMPRESS_TEXT_HALL | COMPRESS_TEXT_ZECK | COMPRESS_TEXT_PHRASE);
|
|
else if (options.fsCompress & COMPRESS_MAXIMUM) {
|
|
ptblRtfFiles->SetPosition(1); // re-initialize table position
|
|
DWORD cbFiles = 0;
|
|
while (ptblRtfFiles->GetString(szRtfFile)) {
|
|
HFILE hfile;
|
|
if ((hfile = _lopen(szRtfFile, OF_READ)) != HFILE_ERROR) {
|
|
cbFiles += GetFileSize((HANDLE) hfile, NULL);
|
|
_lclose(hfile);
|
|
if (cbFiles >= SWITCH_TO_HALL_SIZE) {
|
|
options.fsCompress &= ~COMPRESS_MAXIMUM;
|
|
options.fsCompress |=
|
|
(COMPRESS_TEXT_HALL | COMPRESS_TEXT_ZECK |
|
|
COMPRESS_BMP_RLE | COMPRESS_BMP_ZECK);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (cbFiles < SWITCH_TO_HALL_SIZE) {
|
|
options.fsCompress &= ~COMPRESS_MAXIMUM;
|
|
options.fsCompress |=
|
|
(COMPRESS_TEXT_PHRASE | COMPRESS_TEXT_ZECK |
|
|
COMPRESS_BMP_RLE | COMPRESS_BMP_ZECK);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* REVIEW: This function modifies the default character format
|
|
* according to .hpj option mapfontrange. It should move inside
|
|
* hpj.c like forcefont did.
|
|
*/
|
|
|
|
SetDefaultFontSize();
|
|
|
|
// Create the output file system and related files
|
|
|
|
if (!FCreatePfsmgSz(szHlpFile))
|
|
goto AbadonAllHope;
|
|
|
|
if (options.fsCompress & COMPRESS_TEXT_HALL && !LoadFtsDll()) {
|
|
|
|
// If we can't load ftsrch.dll, then shut off Hall compression
|
|
|
|
VReportError(HCERR_NO_HALL_COMPRESSION, &errHpj);
|
|
|
|
options.fsCompress &= ~COMPRESS_TEXT_HALL;
|
|
options.fsCompress |= COMPRESS_TEXT_ZECK;
|
|
}
|
|
|
|
if (options.fsCompress & COMPRESS_TEXT_HALL) {
|
|
hCompressor = pNewCompressor(0);
|
|
if (!hCompressor)
|
|
OOM();
|
|
}
|
|
|
|
// Prepare for phrase or Hall compression
|
|
|
|
if (!InitializePhraseGeneration(szHlpFile))
|
|
HardExit();
|
|
|
|
if (pphrase) { // we'll have a pphrase for phrase or Hall compression
|
|
|
|
#ifdef CHECK_HALL
|
|
poutPhrase = new COutput("phrase.txt");
|
|
#endif
|
|
#ifdef _DEBUG
|
|
// ptblCheck = new CTable();
|
|
#endif
|
|
|
|
/*
|
|
* Phrase pass -- used for either phrase or Hall compression.
|
|
* This makes a pass through all the .RTF files in order to parse
|
|
* all the text, titles, and entry macros.
|
|
*/
|
|
|
|
fPhraseParsing = TRUE;
|
|
|
|
// *** Pass 1 ***
|
|
|
|
pSeekPast = (SEEK_PAST*) lcCalloc(ptblRtfFiles->CountStrings() *
|
|
sizeof(SEEK_PAST));
|
|
|
|
iCurFile = -1;
|
|
ptblRtfFiles->SetPosition(1); // re-initialize table position
|
|
while (ptblRtfFiles->GetString(szRtfFile)) {
|
|
iCurFile++;
|
|
if (!hwndParent && hwndGrind) {
|
|
PSTR psz = StrRChr(szRtfFile, CH_BACKSLASH, fDBCSSystem);
|
|
SetWindowText(hwndGrind, (psz ? psz + 1 : szRtfFile));
|
|
}
|
|
else if (IsWindowVisible(hwndGrind) && options.fReport) {
|
|
wsprintf(szParentString,
|
|
GetStringResource(IDS_SCANNING),
|
|
szRtfFile);
|
|
SendStringToParent(szParentString);
|
|
doGrind();
|
|
}
|
|
switch (RcTextFromRTF(szRtfFile)) {
|
|
case RC_Success:
|
|
fFileFound = TRUE;
|
|
if (pSeekPast[iCurFile].pfntbl)
|
|
lcClearFree(&pSeekPast[iCurFile].pfntbl);
|
|
break;
|
|
|
|
case RC_Invalid:
|
|
|
|
// zero out the file so we don't reread it.
|
|
|
|
ptblRtfFiles->ReplaceString("",
|
|
ptblRtfFiles->GetPosition() - 1);
|
|
break;
|
|
|
|
case RC_OutOfMemory:
|
|
case RC_DiskFull:
|
|
default:
|
|
|
|
// REVIEW: has the problem been reported?
|
|
|
|
// Go to uncompressed compile?
|
|
|
|
HardExit();
|
|
}
|
|
}
|
|
fPhraseParsing = FALSE;
|
|
|
|
#ifdef CHECK_HALL
|
|
delete poutPhrase;
|
|
#endif
|
|
|
|
if (!fFileFound)
|
|
HardExit();
|
|
|
|
if (fPhraseOnly) {
|
|
CloseFilesPfsmg();
|
|
RemoveGrind();
|
|
DeleteTmpFiles();
|
|
if (hwndParent)
|
|
PostMessage(hwndParent, WMP_BUILD_COMPLETE, FALSE, 0);
|
|
SetFocus(hwndParent);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if ((options.fsCompress & COMPRESS_TEXT_PHRASE) &&
|
|
!FCreateKeyPhrFileSz(szHlpFile))
|
|
HardExit();
|
|
|
|
#ifdef CHECK_HALL
|
|
poutHall = new COutput("compress.txt");
|
|
#endif
|
|
if (options.fsFTS & FTS_ENABLED &&
|
|
!(options.fsCompress & COMPRESS_TEXT_PHRASE) &&
|
|
!(options.fsCompress & COMPRESS_TEXT_HALL)) {
|
|
VReportError(HCERR_NO_FTS, &errHpj);
|
|
options.fsFTS &= ~FTS_ENABLED;
|
|
}
|
|
else if (options.fsFTS & FTS_ENABLED) {
|
|
LANGID langid = kwlcid.langid;
|
|
|
|
if (!lcid) {
|
|
langid = GetUserDefaultLangID();
|
|
lcidFts = MAKELCID(langid, SORT_DEFAULT);
|
|
}
|
|
else
|
|
lcidFts = lcid;
|
|
|
|
struct stat statbuf;
|
|
DWORD timestamp;
|
|
if (stat(szHlpFile, &statbuf) == 0)
|
|
timestamp = statbuf.st_mtime;
|
|
else
|
|
timestamp = 0; // BUGBUG: we should fail here
|
|
|
|
charsetFts = defCharSet;
|
|
if (!charsetFts) {
|
|
switch (PRIMARYLANGID(langid)) {
|
|
|
|
case LANG_KOREAN:
|
|
charsetFts = HANGEUL_CHARSET;
|
|
break;
|
|
|
|
case LANG_CHINESE:
|
|
charsetFts = CHINESEBIG5_CHARSET;
|
|
break;
|
|
|
|
case LANG_JAPANESE:
|
|
charsetFts = SHIFTJIS_CHARSET;
|
|
break;
|
|
|
|
default:
|
|
charsetFts = DEFAULT_CHARSET;
|
|
break;
|
|
}
|
|
}
|
|
|
|
hFtsIndex = pNewIndex((PBYTE) szHlpFile, timestamp, 0,
|
|
charsetFts, lcidFts,
|
|
TOPIC_SEARCH | PHRASE_SEARCH);
|
|
|
|
// BUGBUG Need proper error message if above fails.
|
|
|
|
ASSERT(hFtsIndex);
|
|
}
|
|
|
|
if (options.fsCompress & COMPRESS_TEXT_HALL) {
|
|
PBYTE pbImage, pbIndex;
|
|
|
|
// Not only saves, but also gets the phrase table info needed for
|
|
// the pSetPhraseTable() call.
|
|
|
|
if (!SaveHallTables(&pbImage, &pbIndex))
|
|
HardExit();
|
|
|
|
pDeleteCompressor(hCompressor);
|
|
|
|
hCompressor = pNewCompressor(0);
|
|
if (!hCompressor)
|
|
OOM();
|
|
pSetPhraseTable(hCompressor, pbImage, jHdr.cbImageUncompressed,
|
|
pbIndex, jHdr.cbIndex);
|
|
}
|
|
|
|
// *** Final Pass through the RTF files ****
|
|
|
|
VAcqBufs(); // Acquire buffers
|
|
FInitDelayExecution();
|
|
|
|
ptblRtfFiles->SetPosition(1); // re-initialize table position
|
|
iCurFile = -1;
|
|
while (ptblRtfFiles->GetString(szRtfFile)) {
|
|
iCurFile++;
|
|
if (!*szRtfFile)
|
|
continue; // we encountered an error in the first pass
|
|
if (!hwndParent && hwndGrind) {
|
|
PSTR psz = StrRChr(szRtfFile, CH_BACKSLASH, fDBCSSystem);
|
|
CStr cszCopy((psz ? psz : szRtfFile));
|
|
CharLower(cszCopy);
|
|
SetWindowText(hwndGrind, cszCopy);
|
|
}
|
|
if (options.fReport) {
|
|
wsprintf(szParentString, GetStringResource(IDS_COMPILING),
|
|
szRtfFile);
|
|
SendStringToParent(szParentString);
|
|
}
|
|
switch (RcCompileRTF(szRtfFile)) {
|
|
case RC_Success:
|
|
case RC_Invalid:
|
|
break;
|
|
|
|
case RC_OutOfMemory:
|
|
case RC_DiskFull:
|
|
default:
|
|
HardExit();
|
|
break;
|
|
}
|
|
}
|
|
|
|
UnlinkHlpifNoFCP();
|
|
|
|
VForceTopicFCP();
|
|
VFlushBuffer(TRUE);
|
|
EndDelayExecution();
|
|
|
|
doGrind();
|
|
// if (options.fsCompress & COMPRESS_ZECK)
|
|
// FreeZeckGlobals();
|
|
|
|
SendStringToParent("\r\n"); // send a blank line
|
|
|
|
VOutFontTable();
|
|
|
|
if (!FResolveNextlist(fmsg.hfTopic) ||
|
|
!FResolveContextErrors() ||
|
|
!FOutAliasToCtxBtree())
|
|
HardExit();
|
|
|
|
VOutCtxOffsetTable();
|
|
VOutSystemFile();
|
|
CloseFilesPfsmg();
|
|
if (hFtsIndex)
|
|
pSaveIndex(hFtsIndex, NULL);
|
|
|
|
#ifdef CHECK_HALL
|
|
delete poutHall;
|
|
#endif
|
|
|
|
if (!iflags.fRtfInput) {
|
|
DWORD dwFinalTime = (GetTickCount() - dwTime) / 1000;
|
|
int minutes = (dwFinalTime / 60);
|
|
int seconds = (dwFinalTime - (minutes * 60L));
|
|
|
|
char szPlural[10];
|
|
strcpy(szPlural, GetStringResource(IDS_PLURAL));
|
|
|
|
wsprintf(szParentString, GetStringResource(IDS_STATS),
|
|
FormatNumber(hlpStats.cTopics), ((hlpStats.cTopics == 1) ? "" : szPlural),
|
|
FormatNumber(hlpStats.cJumps), ((hlpStats.cJumps == 1) ? "" : szPlural),
|
|
FormatNumber(hlpStats.cKeywords), ((hlpStats.cKeywords == 1) ? "" : szPlural),
|
|
FormatNumber(hlpStats.cBitmaps), ((hlpStats.cBitmaps == 1) ? "" : szPlural));
|
|
SendStringToParent(szParentString);
|
|
if (pLogFile) {
|
|
if (options.fDBCS)
|
|
pLogFile->outstring_eol(txtZeroLength);
|
|
pLogFile->outstring(szParentString);
|
|
}
|
|
|
|
wsprintf(szParentString, "\r\nFile size: %s\r\n", FormatNumber(cbHlpFile));
|
|
SendLogStringToParent();
|
|
if (cbGraphics) {
|
|
wsprintf(szParentString, "Bitmaps: %s bytes\r\n", FormatNumber(cbGraphics));
|
|
SendLogStringToParent();
|
|
}
|
|
ReportCharCounts();
|
|
|
|
wsprintf(szParentString, GetStringResource(IDS_COMPILE_TIME),
|
|
FormatNumber(minutes), ((minutes == 1) ? "" : szPlural),
|
|
seconds, ((seconds == 1) ? "" : szPlural));
|
|
SendLogStringToParent();
|
|
|
|
#if (defined(_DEBUG))
|
|
srand((UINT) GetTickCount());
|
|
int rd1 = rand() & 31;
|
|
int rd2 = rand() & 31;
|
|
int rd3 = rand() & 31;
|
|
|
|
wsprintf(szParentString, "%d note%s, %d %s %s %s warning%s\r\n",
|
|
errcount.cNotes, (PSTR) ((errcount.cNotes == 1) ? "" : szPlural),
|
|
errcount.cWarnings,
|
|
szWarning1[rd1], szWarning2[rd1], szWarning3[rd1],
|
|
|
|
(PSTR) ((errcount.cWarnings == 1) ? "" : szPlural));
|
|
#else
|
|
wsprintf(szParentString, GetStringResource(IDS_WARN_COUNT),
|
|
errcount.cNotes, (PSTR) ((errcount.cNotes == 1) ? "" : szPlural),
|
|
errcount.cWarnings, (PSTR) ((errcount.cWarnings == 1) ? "" : szPlural));
|
|
#endif
|
|
SendLogStringToParent();
|
|
|
|
#ifdef _DEBUG
|
|
|
|
SendLogStringToParent("\r\n");
|
|
if (idHighestUsedFont + 1 < lcSize(paCharSets)) {
|
|
int cbSaved = lcSize(paCharSets) - (idHighestUsedFont + 1);
|
|
wsprintf(szParentString, "Total Fonts: %d, Help File Fonts: %d, Removed %s font%s\r\n",
|
|
lcSize(paCharSets), idHighestUsedFont + 1,
|
|
FormatNumber(cbSaved), ((cbSaved == 1) ? "" : szPlural));
|
|
SendLogStringToParent();
|
|
}
|
|
lcReport(szParentString);
|
|
SendLogStringToParent();
|
|
|
|
if (fCompressionBusted)
|
|
SendLogStringToParent("\r\n\r\n*** Compression is broken!!! Phrase scan doesn't match phrase compression.\r\n\r\n");
|
|
#endif
|
|
}
|
|
|
|
if (fFatalWarning) {
|
|
remove(szHlpFile);
|
|
fBuildResult = FALSE;
|
|
}
|
|
|
|
else if (hwndParent || iflags.fRunHelp) {
|
|
if (!StrChr(szHlpFile, CH_BACKSLASH, fDBCSSystem)) {
|
|
|
|
// Add the full directory before sending it to HCW
|
|
|
|
PSTR psz = lcStrDup(szHlpFile);
|
|
GetCurrentDirectory(sizeof(szHlpFile), szHlpFile);
|
|
AddTrailingBackslash(szHlpFile);
|
|
strcat(szHlpFile, psz);
|
|
lcFree(psz);
|
|
}
|
|
if (iflags.fRunHelp) {
|
|
strcpy(szParentString, "winhelp ");
|
|
strcat(szParentString, szHlpFile);
|
|
WinExec(szParentString, SW_SHOW);
|
|
}
|
|
|
|
if (hwndParent) {
|
|
ASSERT(pszMap);
|
|
strcpy(pszMap, szHlpFile);
|
|
fBuildResult = TRUE;
|
|
}
|
|
}
|
|
|
|
} // end of try block
|
|
//catch (EXCEPTION_ERROR err) {
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
QFSHR qfshr = (QFSHR) hfsOut;
|
|
if (hfsOut && qfshr->fid != HFILE_ERROR)
|
|
_lclose(qfshr->fid);
|
|
remove(szHlpFile);
|
|
fBuildResult = FALSE;
|
|
err;
|
|
}
|
|
|
|
if (pLogFile)
|
|
delete pLogFile;
|
|
|
|
RemoveGrind();
|
|
FreeFtsDll();
|
|
|
|
DeleteTmpFiles();
|
|
|
|
if (hwndParent) {
|
|
SendMessage(hwndParent, WMP_ERROR_COUNT, errcount.cWarnings,
|
|
errcount.cNotes);
|
|
|
|
PostMessage(hwndParent, WMP_BUILD_COMPLETE, fBuildResult, 0);
|
|
|
|
// BUGBUG: SetForegroundWindow not supported in Win32s
|
|
|
|
if (!fNoActivation)
|
|
SetForegroundWindow(hwndParent);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: SendStringToParent
|
|
|
|
PURPOSE: Send a string to our parent
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
12-Apr-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
static const int GRIND_COUNT = 10;
|
|
|
|
void STDCALL SendStringToParent(PCSTR pszString)
|
|
{
|
|
if (!hwndParent) {
|
|
#ifdef _DEBUG
|
|
OutputDebugString(pszString);
|
|
#endif
|
|
return;
|
|
}
|
|
if (hwndGrind && ++cGrind > GRIND_COUNT) {
|
|
doGrind();
|
|
cGrind = 0;
|
|
}
|
|
if (!fTellParent) {
|
|
return;
|
|
}
|
|
ASSERT(strlen(pszString) < MAX_PASS_STRING);
|
|
|
|
if (!hfShare)
|
|
CreateSharedMemory();
|
|
|
|
strcpy(pszMap, pszString);
|
|
SendMessage(hwndParent, WMP_MSG, 0, 0);
|
|
}
|
|
|
|
void STDCALL SendStringToParent(int id)
|
|
{
|
|
if (!hwndParent) {
|
|
#ifdef _DEBUG
|
|
OutputDebugString(GetStringResource(id));
|
|
#endif
|
|
return;
|
|
}
|
|
SendStringToParent(GetStringResource(id));
|
|
}
|
|
|
|
void STDCALL SendLogStringToParent(PCSTR pszString)
|
|
{
|
|
SendStringToParent(pszString);
|
|
if (pLogFile)
|
|
pLogFile->outstring(pszString);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: ParseCmdLine
|
|
|
|
PURPOSE: Parse the command line
|
|
|
|
PARAMETERS:
|
|
lpszCmdLine
|
|
pszHpjFile
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
12-Aug-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
static BOOL STDCALL ParseCmdLine(PSTR lpszCmdLine, PSTR pszHpjFile)
|
|
{
|
|
CStr sz(lpszCmdLine); // bring it into near space
|
|
|
|
for (PSTR psz = sz.psz; psz != NULL && *psz != '\0'; ) {
|
|
if (IsSwitchChar(*psz)) {
|
|
psz++; // skip over the dash or slash
|
|
switch (tolower(*psz)) {
|
|
case 'x':
|
|
psz++;
|
|
while (isalpha(*psz)) {
|
|
switch(tolower(*psz)) {
|
|
case 'h': // run help when done
|
|
iflags.fRunHelp = TRUE;
|
|
break;
|
|
|
|
case 't': // trusted RTF provider
|
|
iflags.fTrusted = TRUE;
|
|
break;
|
|
|
|
case 'n': // don't display grinder window
|
|
iflags.fNoGrinder = TRUE;
|
|
break;
|
|
|
|
case 'r': // RTF file specified
|
|
iflags.fRtfInput = TRUE;
|
|
break;
|
|
|
|
case 'c': // RTF is in the clipboard
|
|
{
|
|
/*
|
|
* GetRtfInClipboard() may reallocate
|
|
* sz and in so doing move it to a
|
|
* different location. So, we save the
|
|
* offset from the beginning, and reset
|
|
* psz based on this offset.
|
|
*/
|
|
|
|
int offset = psz - sz.psz;
|
|
if (!GetRtfInClipboard(&sz))
|
|
return FALSE;
|
|
|
|
/*
|
|
* RTF filename will now be appended
|
|
* to the end of sz.
|
|
*/
|
|
|
|
iflags.fRtfInput = TRUE;
|
|
psz = sz.psz + offset;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
// BUGBUG: need to indicate it is an invalid test
|
|
// switch
|
|
|
|
wsprintf(szParentString,
|
|
GetStringResource(IDS_INVALID_X_SWITCH), *psz);
|
|
MessageBox(NULL, szParentString,
|
|
GetStringResource(IDS_VERSION), MB_OK);
|
|
break;
|
|
}
|
|
psz++;
|
|
}
|
|
break;
|
|
|
|
case 'o':
|
|
psz = GetArg(szHlpFile, FirstNonSpace(psz + 1, fDBCSSystem));
|
|
break;
|
|
|
|
case 'n': // No options
|
|
psz++;
|
|
do {
|
|
switch (tolower(*psz)) {
|
|
case 'a':
|
|
fNoActivation = TRUE;
|
|
break;
|
|
|
|
case 'g': // no grinder
|
|
fGrind = FALSE;
|
|
break;
|
|
|
|
case 'c': // no compression
|
|
fForceNoCompression = TRUE;
|
|
break;
|
|
}
|
|
psz++;
|
|
} while (isalpha(*psz));
|
|
break;
|
|
|
|
// REVIEW: obsolete...
|
|
|
|
case 'j':
|
|
fHallPassOne = TRUE;
|
|
psz++;
|
|
break;
|
|
|
|
case 'p':
|
|
fPhraseOnly = TRUE;
|
|
psz++;
|
|
break;
|
|
|
|
case 'f': // forage commands
|
|
psz++;
|
|
forage(psz);
|
|
return FALSE;
|
|
|
|
case 't': // test commands
|
|
switch (tolower(psz[1])) {
|
|
case 'c':
|
|
doCntTest(psz + 2);
|
|
return FALSE;
|
|
|
|
case 'm':
|
|
Execute(FirstNonSpace(psz + 2, fDBCSSystem));
|
|
return FALSE;
|
|
|
|
default:
|
|
|
|
// BUGBUG: need to indicate it is an invalid test
|
|
// switch
|
|
|
|
wsprintf(szScratchBuf,
|
|
GetStringResource(IDS_INVALID_SWITCH), *psz);
|
|
szMsgBox(szScratchBuf);
|
|
psz += 2;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 'b': { // BMROOT path
|
|
char szRoot[_MAX_PATH];
|
|
psz = GetArg(szRoot, FirstNonSpace(psz + 1, fDBCSSystem));
|
|
if (!options.ptblBmpRoot)
|
|
options.ptblBmpRoot = new CTable;
|
|
ParsePath(options.ptblBmpRoot, szRoot, (OPT) OPT_BMROOT);
|
|
}
|
|
break;
|
|
|
|
case 'r': // run help when done
|
|
iflags.fRunHelp = TRUE;
|
|
psz++;
|
|
break;
|
|
|
|
default:
|
|
wsprintf(szScratchBuf,
|
|
GetStringResource(IDS_INVALID_SWITCH), *psz);
|
|
szMsgBox(szScratchBuf);
|
|
psz++;
|
|
break;
|
|
}
|
|
|
|
while (*psz && *psz == ' ')
|
|
psz++;
|
|
}
|
|
|
|
// it wasn't a switch
|
|
|
|
else {
|
|
lstrcpy(pszHpjFile, psz);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Make certain we have an output filename
|
|
|
|
if (!szHlpFile[0]) {
|
|
strcpy(szHlpFile, pszHpjFile);
|
|
ChangeExtension(szHlpFile, IDS_EXT_HLP);
|
|
}
|
|
|
|
if (hfShare)
|
|
CloseHandle(hfShare);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void STDCALL OutSz(int id, PCSTR psz)
|
|
{
|
|
wsprintf(szParentString, GetStringResource(id), psz);
|
|
SendStringToParent(szParentString);
|
|
}
|
|
|
|
void STDCALL OutInt(int id, int iVal)
|
|
{
|
|
wsprintf(szParentString, GetStringResource(id), iVal);
|
|
SendStringToParent(szParentString);
|
|
}
|
|
|
|
void STDCALL OutInt(PCSTR pszFormat, int iVal)
|
|
{
|
|
wsprintf(szParentString, pszFormat, iVal);
|
|
SendStringToParent(szParentString);
|
|
}
|
|
|
|
void STDCALL OutLong(PCSTR pszFormat, int iVal)
|
|
{
|
|
wsprintf(szParentString, pszFormat, iVal);
|
|
SendStringToParent(szParentString);
|
|
}
|
|
|
|
void STDCALL OutLong(int id, int iVal)
|
|
{
|
|
wsprintf(szParentString, GetStringResource(id), iVal);
|
|
SendStringToParent(szParentString);
|
|
}
|
|
|
|
void STDCALL OutErrorRc(RC_TYPE rc, BOOL fPanic)
|
|
{
|
|
SendStringToParent("\t");
|
|
|
|
switch (rc) {
|
|
case RC_Invalid:
|
|
wsprintf(szParentString, GetStringResource(IDS_INVALID_FILE));
|
|
break;
|
|
|
|
case RC_NoExists:
|
|
wsprintf(szParentString, GetStringResource(IDS_FILE_NOT_FOUND));
|
|
break;
|
|
|
|
case RC_BadVersion:
|
|
wsprintf(szParentString, GetStringResource(IDS_INCOMPATIBLE));
|
|
break;
|
|
|
|
case RC_DiskFull:
|
|
wsprintf(szParentString, GetStringResource(IDS_DISK_FULL));
|
|
break;
|
|
|
|
case RC_NoFileHandles:
|
|
wsprintf(szParentString, GetStringResource(HCERR_NO_FILE_HANDLES));
|
|
break;
|
|
|
|
case RC_OutOfMemory:
|
|
wsprintf(szParentString, GetStringResource(HCERR_OOM));
|
|
break;
|
|
|
|
case RC_BadArg:
|
|
ASSERT(FALSE); // should never happen
|
|
break;
|
|
|
|
case RC_NoPermission:
|
|
wsprintf(szParentString, GetStringResource(IDS_ACCESS_DENIED));
|
|
break;
|
|
|
|
case RC_CantWrite:
|
|
wsprintf(szParentString, GetStringResource(IDS_CANT_WRITE));
|
|
break;
|
|
|
|
default:
|
|
wsprintf(szParentString, GetStringResource(IDS_FORAGE_ERROR), rc);
|
|
break;
|
|
}
|
|
|
|
strcat(szParentString, "\r\n");
|
|
SendStringToParent(szParentString);
|
|
if (pLogFile)
|
|
pLogFile->outstring(szParentString);
|
|
}
|
|
|
|
int STDCALL MsgBox(UINT idString)
|
|
{
|
|
return szMsgBox(GetStringResource(idString));
|
|
}
|
|
|
|
int STDCALL szMsgBox(PCSTR pszMsg)
|
|
{
|
|
return MessageBox(NULL, pszMsg, pgszTitleBuf, MB_OK | MB_ICONHAND);
|
|
}
|
|
|
|
BOOL STDCALL GetRtfInClipboard(CStr* pcsz)
|
|
{
|
|
if (OpenClipboard(NULL)) {
|
|
|
|
UINT clipfmt = 0;
|
|
|
|
do {
|
|
char szBuf[100];
|
|
clipfmt = EnumClipboardFormats(clipfmt);
|
|
if (clipfmt >= 0xC000) {
|
|
GetClipboardFormatName(clipfmt, szBuf, sizeof(szBuf));
|
|
if (_stricmp(szBuf, "Rich Text Format") == 0)
|
|
break;
|
|
}
|
|
} while (clipfmt != 0);
|
|
if (clipfmt != 0) {
|
|
|
|
// REVIEW: this would be faster if we used our virtual file class
|
|
|
|
FM fmTmp = FmNewTemp();
|
|
ConfirmOrDie(fmTmp);
|
|
HFILE hf = _lopen(fmTmp, OF_WRITE);
|
|
|
|
/*
|
|
* BUGBUG: need to complain when we can't open the temporary file
|
|
* or we run out of disk space.
|
|
*/
|
|
|
|
if (hf != HFILE_ERROR) {
|
|
PBYTE pb = (PBYTE) GetClipboardData(clipfmt);
|
|
int cb = GlobalSize((HGLOBAL) pb);
|
|
int cbWrite = _lwrite(hf, (LPCSTR) pb, cb);
|
|
_lclose(hf);
|
|
if (cb == cbWrite) {
|
|
*pcsz += " ";
|
|
*pcsz += fmTmp;
|
|
}
|
|
else
|
|
clipfmt = 0; // probably ran out of disk space
|
|
}
|
|
else
|
|
clipfmt = 0; // probably ran out of disk space
|
|
}
|
|
CloseClipboard();
|
|
return (BOOL) clipfmt;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: GetTmpDirectory
|
|
|
|
PURPOSE: Returns a pointer to the directory name to put temporary
|
|
files in. The name is guaranteed to end with a backslash or
|
|
colon.
|
|
|
|
PARAMETERS:
|
|
void
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
02-Jul-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
PCSTR STDCALL GetTmpDirectory(void)
|
|
{
|
|
static PSTR pszTmp = NULL;
|
|
|
|
if (options.pszTmpDir)
|
|
return options.pszTmpDir;
|
|
else if (pszTmp)
|
|
return pszTmp;
|
|
else {
|
|
char szTmpName[MAX_PATH];
|
|
|
|
GetTempPath(sizeof(szTmpName), szTmpName);
|
|
AddTrailingBackslash(szTmpName);
|
|
return (pszTmp = lcStrDup(szTmpName));
|
|
}
|
|
}
|
|
|
|
ERRORCODE (APIENTRY* pSaveIndex)(HINDEX lIndex, LPSTR pOutput);
|
|
HCOMPRESSOR (APIENTRY* pNewCompressor)(UINT);
|
|
ERRORCODE (APIENTRY* pScanText)(HCOMPRESSOR, PBYTE, UINT, UINT);
|
|
ERRORCODE (APIENTRY* pGetPhraseTable)(HCOMPRESSOR, PUINT, PBYTE *, PUINT, PBYTE *, PUINT);
|
|
ERRORCODE (APIENTRY* pSetPhraseTable)(HCOMPRESSOR, PBYTE, UINT, PBYTE, UINT);
|
|
INT (APIENTRY* pCompressText)(HCOMPRESSOR, PBYTE, UINT, PBYTE *, UINT);
|
|
INT (APIENTRY* pDecompressText)(HCOMPRESSOR, PBYTE, UINT, PBYTE);
|
|
ERRORCODE (APIENTRY* pDeleteCompressor)(HCOMPRESSOR);
|
|
HINDEX (APIENTRY* pNewIndex)(PBYTE, UINT, UINT, UINT, UINT, UINT);
|
|
ERRORCODE (APIENTRY* pScanTopicTitle)(HINDEX, PBYTE, UINT, UINT, HANDLE, UINT, UINT);
|
|
ERRORCODE (APIENTRY* pScanTopicText)(HINDEX, PBYTE, UINT, UINT, UINT);
|
|
|
|
BOOL STDCALL LoadFtsDll(void)
|
|
{
|
|
FM fm;
|
|
hmodFts = HmodFromName("ftsrch.dll", &fm);
|
|
if (!hmodFts) {
|
|
VReportError(HCERR_MISSING_FTSRCH, &errHpj);
|
|
return FALSE;
|
|
}
|
|
pNewCompressor =
|
|
(NEWCOMPRESSOR) GetProcAddress(hmodFts, "NewCompressor");
|
|
pScanText =
|
|
(SCANTEXT) GetProcAddress(hmodFts, "ScanText");
|
|
pGetPhraseTable =
|
|
(GETPHRASETABLE) GetProcAddress(hmodFts, "GetPhraseTable");
|
|
pSetPhraseTable =
|
|
(SETPHRASETABLE) GetProcAddress(hmodFts, "SetPhraseTable");
|
|
pCompressText =
|
|
(COMPRESSTEXT) GetProcAddress(hmodFts, "CompressText");
|
|
pDecompressText =
|
|
(DECOMPRESSTEXT) GetProcAddress(hmodFts, "DecompressText");
|
|
pDeleteCompressor =
|
|
(DELETECOMPRESSOR) GetProcAddress(hmodFts, "DeleteCompressor");
|
|
pScanTopicTitle =
|
|
(SCANTOPICTITLE) GetProcAddress(hmodFts, "ScanTopicTitle");
|
|
pScanTopicText =
|
|
(SCANTOPICTEXT) GetProcAddress(hmodFts, "ScanTopicText");
|
|
|
|
pNewIndex =
|
|
(NEWINDEX) GetProcAddress(hmodFts, "NewIndex");
|
|
pSaveIndex =
|
|
(SAVEINDEX) GetProcAddress(hmodFts, "SaveIndex");
|
|
|
|
if (!pNewCompressor || !pScanText || !pGetPhraseTable ||
|
|
!pSetPhraseTable || !pCompressText || !pDecompressText ||
|
|
!pDeleteCompressor || !pNewIndex || !pScanTopicTitle ||
|
|
!pScanTopicText) {
|
|
VReportError(HCERR_MISSING_FTSRCH, &errHpj);
|
|
FreeFtsDll();
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void STDCALL FreeFtsDll(void)
|
|
{
|
|
if (hmodFts) {
|
|
FreeLibrary(hmodFts);
|
|
hmodFts = NULL;
|
|
}
|
|
}
|
|
|
|
HINSTANCE STDCALL HmodFromName(PCSTR pszDllName, FM* pfm)
|
|
{
|
|
FM fm;
|
|
HINSTANCE hmodReturn = 0;
|
|
|
|
/*
|
|
* Look for the DLL starting with the directory of the current help
|
|
* file, then the current directory, directories specified in
|
|
* winhelp.ini, the windows\help directory and the PATH.
|
|
*/
|
|
|
|
fm = FmNewExistSzDir(pszDllName,
|
|
DIR_CUR_HELP | DIR_INI | DIR_PATH | DIR_CURRENT | DIR_SYSTEM);
|
|
|
|
if (fm) {
|
|
hmodReturn = LoadLibrary(fm);
|
|
}
|
|
|
|
if (!hmodReturn) {
|
|
char szNewName[MAX_PATH];
|
|
strcpy(szNewName, pszDllName);
|
|
CharUpper(szNewName); // so we can search for .dll names
|
|
|
|
// Only substitute extensions if we weren't told it was a .DLL file
|
|
|
|
if (!strstr(szNewName, "DLL")) {
|
|
ChangeExtension(szNewName, "DLL");
|
|
hmodReturn = HmodFromName(szNewName, &fm);
|
|
}
|
|
}
|
|
|
|
*pfm = fm;
|
|
return hmodReturn;
|
|
}
|