552 lines
12 KiB
C++
552 lines
12 KiB
C++
//
|
|
// MODULE: APGTSHTX.CPP
|
|
//
|
|
// PURPOSE: Template file decoder
|
|
//
|
|
// PROJECT: Generic Troubleshooter DLL for Microsoft AnswerPoint
|
|
//
|
|
// COMPANY: Saltmine Creative, Inc. (206)-633-4743 support@saltmine.com
|
|
//
|
|
// AUTHOR: Roman Mach
|
|
//
|
|
// ORIGINAL DATE: 8-2-96
|
|
//
|
|
// NOTES:
|
|
// 1. Based on Print Troubleshooter DLL
|
|
//
|
|
// Version Date By Comments
|
|
//--------------------------------------------------------------------
|
|
// V0.1 - RM Original
|
|
// V0.15 8/15/96 VM New htx format
|
|
// V0.2 6/4/97 RWM Local Version for Memphis
|
|
// V0.3 04/09/98 JM/OK+ Local Version for NT5
|
|
//
|
|
#include "stdafx.h"
|
|
//#include <windows.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <search.h>
|
|
#include <dos.h>
|
|
#include <ctype.h>
|
|
#include <limits.h>
|
|
#include <time.h>
|
|
|
|
#include "apgts.h"
|
|
#include "ErrorEnums.h"
|
|
#include "bnts.h"
|
|
#include "BackupInfo.h"
|
|
#include "cachegen.h"
|
|
#include "apgtsinf.h"
|
|
#include "apgtscmd.h"
|
|
#include "apgtshtx.h"
|
|
|
|
#include "TSHOOT.h"
|
|
|
|
#include "chmread.h"
|
|
//
|
|
//
|
|
CHTMLInputTemplate::CHTMLInputTemplate(const TCHAR *filename)
|
|
{
|
|
// initialize a few things
|
|
m_dwErr = 0;
|
|
m_cur_stack_count=0;
|
|
m_command_start = NULL;
|
|
_tcscpy(m_filename,filename);
|
|
m_cHeaderItems = 0;
|
|
m_infer = NULL;
|
|
m_strResPath = _T("");
|
|
}
|
|
|
|
//
|
|
//
|
|
CHTMLInputTemplate::~CHTMLInputTemplate()
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
//
|
|
// must be locked to use
|
|
//
|
|
VOID CHTMLInputTemplate::SetInfer(CInfer *infer, TCHAR *vroot)
|
|
{
|
|
m_infer = infer;
|
|
_tcscpy(m_vroot, vroot);
|
|
}
|
|
//
|
|
//
|
|
DWORD CHTMLInputTemplate::Initialize(LPCTSTR szResPath, CString strFile)
|
|
{
|
|
CHAR *filestr;
|
|
|
|
m_dwErr = 0;
|
|
m_strResPath = szResPath;
|
|
m_strFile = strFile;
|
|
|
|
if (strFile.GetLength())
|
|
{
|
|
// m_filename is CHM file path and name
|
|
// and strFile - file name within CHM
|
|
if (S_OK != ::ReadChmFile(m_filename, strFile, (void**)&filestr, &m_dwSize))
|
|
{
|
|
m_dwErr = EV_GTS_ERROR_ITMPL_ENDMISTAG;//fix!
|
|
return m_dwErr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// m_filename is a free standing file
|
|
DWORD nBytesRead;
|
|
HANDLE hFile;
|
|
BOOL bResult;
|
|
hFile = CreateFile( m_filename,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL );
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
//???
|
|
//ReportError(TSERR_RESOURCE);
|
|
|
|
m_dwErr = EV_GTS_ERROR_ITMPL_ENDMISTAG;//fix!
|
|
return m_dwErr;
|
|
}
|
|
|
|
m_dwSize = GetFileSize(hFile, NULL);
|
|
filestr = (CHAR *)malloc(m_dwSize+1);
|
|
|
|
if (!((m_dwSize != 0xFFFFFFFF) && (m_dwSize != 0)) || filestr == NULL)
|
|
{
|
|
CloseHandle(hFile);
|
|
m_dwErr = EV_GTS_ERROR_ITMPL_ENDMISTAG;//fix!
|
|
return m_dwErr;
|
|
}
|
|
|
|
bResult = ReadFile(hFile, filestr, m_dwSize, &nBytesRead, NULL);
|
|
|
|
if(!(bResult && nBytesRead == m_dwSize))
|
|
{
|
|
CloseHandle(hFile);
|
|
free(filestr);
|
|
m_dwErr = EV_GTS_ERROR_ITMPL_ENDMISTAG;//fix!
|
|
return m_dwErr;
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
hFile = NULL;
|
|
}
|
|
|
|
filestr[m_dwSize] = '\0';
|
|
|
|
#ifdef _UNICODE
|
|
WCHAR *wfilestr = (WCHAR *)malloc((m_dwSize + 1) * sizeof (WCHAR));
|
|
WCHAR *wchopstr = (WCHAR *)malloc((m_dwSize + 1) * sizeof (WCHAR));
|
|
MultiByteToWideChar( CP_ACP, 0, filestr, -1, wfilestr, m_dwSize );
|
|
MultiByteToWideChar( CP_ACP, 0, filestr, -1, wchopstr, m_dwSize );
|
|
m_startstr = wfilestr;
|
|
m_chopstr = wchopstr;
|
|
#else
|
|
m_startstr = filestr;
|
|
m_chopstr = (CHAR *)malloc(m_dwSize+1);
|
|
strcpy(m_chopstr, filestr);
|
|
#endif
|
|
|
|
// get locations of start and end blocks
|
|
ScanFile();
|
|
|
|
// copy blocks into ram for speed
|
|
BuildInMem();
|
|
|
|
// free memory
|
|
free(filestr);
|
|
|
|
#ifdef _UNICODE
|
|
free(wfilestr);
|
|
#endif
|
|
free(m_chopstr);
|
|
|
|
return m_dwErr;
|
|
}
|
|
|
|
//
|
|
//
|
|
VOID CHTMLInputTemplate::Destroy()
|
|
{
|
|
HTXCommand *command, *nextcommand;
|
|
|
|
// free holders
|
|
command = m_command_start;
|
|
nextcommand = command;
|
|
while (command != NULL) {
|
|
nextcommand = command->GetNext();
|
|
delete command;
|
|
command = nextcommand;
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
DWORD CHTMLInputTemplate::Reload()
|
|
{
|
|
Destroy();
|
|
return Initialize((LPCTSTR) m_strResPath, m_strFile);
|
|
}
|
|
|
|
//
|
|
//
|
|
void CHTMLInputTemplate::ScanFile()
|
|
{
|
|
UINT start, end;
|
|
TCHAR *ptr, *sptr, *eptr, var_name[30];
|
|
HTXCommand *tmpCommand, *prevCommand;
|
|
UINT var_index;
|
|
|
|
sptr = m_chopstr;
|
|
m_cur_command = new HTXCommand(HTX_TYPESTART,_T(""));
|
|
end = start = 0;
|
|
m_cur_command->SetStart(start);
|
|
m_cur_command->SetEnd(end);
|
|
|
|
m_command_start = m_cur_command;
|
|
|
|
// this is bad: if the user does not terminate each command on a separate line
|
|
// the file will misbehave, should at least write out a warning or something...
|
|
|
|
sptr = _tcstok(sptr, _T("\r\n"));
|
|
if (sptr)
|
|
{
|
|
do
|
|
{
|
|
if ((sptr = _tcsstr(sptr,HTX_COMMAND_START)) != NULL)
|
|
{
|
|
if ((ptr = _tcsstr(sptr,HTX_ENDIFSTR))!=NULL)
|
|
{
|
|
tmpCommand = new HTXCommand(HTX_TYPEENDIF,HTX_ENDIFSTR);
|
|
prevCommand = Pop();
|
|
if (prevCommand->GetType() != HTX_TYPEIF)
|
|
{
|
|
m_dwErr = EV_GTS_ERROR_ITMPL_IFMISTAG;
|
|
break;
|
|
}
|
|
prevCommand->SetEndIf(tmpCommand);
|
|
}
|
|
else if ((ptr = _tcsstr(sptr,HTX_ENDFORSTR))!=NULL)
|
|
{
|
|
tmpCommand = new HTXCommand(HTX_TYPEENDFOR,HTX_ENDFORSTR);
|
|
prevCommand = Pop();
|
|
if (prevCommand->GetType() != HTX_TYPEFORANY)
|
|
{
|
|
m_dwErr = EV_GTS_ERROR_ITMPL_FORMISTAG;
|
|
break;
|
|
}
|
|
prevCommand->SetEndFor(tmpCommand);
|
|
}
|
|
else if ((ptr = _tcsstr(sptr,HTX_ELSESTR))!=NULL)
|
|
{
|
|
tmpCommand = new HTXCommand(HTX_TYPEELSE,HTX_ELSESTR);
|
|
prevCommand = Pop();
|
|
if (prevCommand->GetType() != HTX_TYPEIF)
|
|
{
|
|
m_dwErr = EV_GTS_ERROR_ITMPL_IFMISTAG;
|
|
break;
|
|
}
|
|
prevCommand->SetElse(tmpCommand);
|
|
Push(prevCommand);
|
|
}
|
|
else if ((ptr = _tcsstr(sptr,HTX_IFSTR))!=NULL)
|
|
{
|
|
// get the variable
|
|
ptr = _tcsninc(ptr, _tcslen(HTX_IFSTR));
|
|
if( _stscanf(ptr,_T("%s"),var_name) <= 0)
|
|
m_dwErr = EV_GTS_ERROR_ITMPL_IFMISTAG;
|
|
if ((var_index = CheckVariable(var_name)) == FALSE )
|
|
{
|
|
m_dwErr = EV_GTS_ERROR_ITMPL_VARIABLE;
|
|
break;
|
|
}
|
|
tmpCommand = new HTXIfCommand(HTX_TYPEIF,HTX_IFSTR,var_index);
|
|
Push(tmpCommand);
|
|
}
|
|
else if ((ptr = _tcsstr(sptr,HTX_FORANYSTR))!=NULL)
|
|
{
|
|
// get variable
|
|
ptr = _tcsninc(ptr, _tcslen(HTX_FORANYSTR));
|
|
if( _stscanf(ptr,_T("%s"),var_name) <= 0)
|
|
m_dwErr = EV_GTS_ERROR_ITMPL_FORMISTAG;
|
|
if ((var_index = CheckVariable(var_name)) == FALSE )
|
|
{
|
|
m_dwErr = EV_GTS_ERROR_ITMPL_VARIABLE;
|
|
break;
|
|
}
|
|
tmpCommand = new HTXForCommand(HTX_TYPEFORANY,HTX_FORANYSTR, var_index);
|
|
Push(tmpCommand);
|
|
}
|
|
else if ((ptr = _tcsstr(sptr,HTX_DISPLAYSTR))!=NULL)
|
|
{
|
|
// get variable
|
|
ptr = _tcsninc(ptr, _tcslen(HTX_DISPLAYSTR));
|
|
if( _stscanf(ptr,_T("%s"),var_name) <= 0)
|
|
m_dwErr = EV_GTS_ERROR_ITMPL_FORMISTAG;
|
|
if ((var_index = CheckVariable(var_name)) == FALSE )
|
|
{
|
|
m_dwErr = EV_GTS_ERROR_ITMPL_VARIABLE;
|
|
break;
|
|
}
|
|
tmpCommand = new HTXDisplayCommand(HTX_TYPEDISPLAY,HTX_DISPLAYSTR, var_index);
|
|
}
|
|
else if ((ptr = _tcsstr(sptr, HTX_RESOURCESTR)) != NULL)
|
|
{
|
|
ptr = _tcsninc(ptr, _tcslen(HTX_RESOURCESTR));
|
|
if (_stscanf(ptr, _T("%s"), var_name) <= 0)
|
|
m_dwErr = EV_GTS_ERROR_ITMPL_FORMISTAG;
|
|
if ((var_index = CheckVariable(var_name)) == FALSE)
|
|
{
|
|
m_dwErr = EV_GTS_ERROR_ITMPL_VARIABLE;
|
|
break;
|
|
}
|
|
m_cHeaderItems++;
|
|
tmpCommand = new HTXResourceCommand(HTX_TYPERESOURCE, HTX_RESOURCESTR);
|
|
((HTXResourceCommand *) tmpCommand)->GetResName(var_name);
|
|
}
|
|
else
|
|
continue;
|
|
|
|
// get the command terminator
|
|
if ((eptr = _tcsstr(ptr,HTX_COMMAND_END)) == NULL)
|
|
{
|
|
m_dwErr = EV_GTS_ERROR_ITMPL_ENDMISTAG;
|
|
eptr = ptr; // try to recover
|
|
}
|
|
eptr = _tcsninc(eptr, _tcslen(HTX_COMMAND_END));
|
|
|
|
if (tmpCommand == NULL)
|
|
{
|
|
m_dwErr = EV_GTS_ERROR_ITMPL_NOMEM;
|
|
return;
|
|
}
|
|
|
|
// Add command to command list
|
|
if (m_command_start == NULL)
|
|
{
|
|
m_command_start = tmpCommand;
|
|
m_cur_command = tmpCommand;
|
|
}
|
|
else
|
|
{
|
|
m_cur_command->SetNext(tmpCommand);
|
|
m_cur_command = tmpCommand;
|
|
}
|
|
|
|
CString strCHM = ::ExtractCHM(m_filename);
|
|
tmpCommand->GetResource(m_strResPath, strCHM);
|
|
|
|
start = (UINT)(sptr - m_chopstr); // / sizeof (TCHAR);
|
|
end = (UINT)(eptr - m_chopstr); // / sizeof (TCHAR);
|
|
|
|
tmpCommand->SetStart(start);
|
|
tmpCommand->SetEnd(end);
|
|
}
|
|
} while ((sptr = _tcstok(NULL, _T("\r\n"))) != NULL);
|
|
}
|
|
|
|
|
|
if (m_cur_stack_count > 0) // missing and endfor or an endif
|
|
m_dwErr = EV_GTS_ERROR_ITMPL_ENDMISTAG;
|
|
}
|
|
|
|
/*
|
|
* METHOD: BuildInMem
|
|
*
|
|
* PURPOSE: This method will read the HTML between commands (after) and associate
|
|
* it with the command. As a command is executed the HTML after the
|
|
* command is printed
|
|
*
|
|
*/
|
|
UINT CHTMLInputTemplate::BuildInMem()
|
|
{
|
|
HTXCommand *cur_com, *last_command;
|
|
|
|
if (m_dwErr)
|
|
return (TRUE);
|
|
|
|
// copy strings from file to
|
|
// note duplication of effort (before and after strings may be same string)
|
|
cur_com = m_command_start;
|
|
last_command = cur_com;
|
|
while (cur_com != NULL) {
|
|
if (cur_com->GetNext() == NULL) {
|
|
if (cur_com->ReadAfterStr(cur_com->GetEnd(), m_dwSize, m_startstr))
|
|
return (m_dwErr = EV_GTS_ERROR_ITMPL_NOMEM);
|
|
}
|
|
else {
|
|
if (cur_com->ReadAfterStr(cur_com->GetEnd(), cur_com->GetNext()->GetStart(), m_startstr))
|
|
return (m_dwErr = EV_GTS_ERROR_ITMPL_NOMEM);
|
|
}
|
|
last_command = cur_com;
|
|
cur_com = cur_com->GetNext();
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
//
|
|
bool CHTMLInputTemplate::IsFileName(TCHAR *name)
|
|
{
|
|
bool bFileName;
|
|
if (name[0] != _T('$'))
|
|
bFileName = false;
|
|
else if (NULL == _tcsstr(name, _T(".")))
|
|
bFileName = false;
|
|
else
|
|
bFileName = true;
|
|
return bFileName;
|
|
}
|
|
/*
|
|
* METHOD: CheckVariable
|
|
*
|
|
* PURPOSE: This routine will check to see if the variable name is a valid one
|
|
* and if it is will return a UINT that represents that variable.
|
|
* Integers are used in other routines when refering to a variable (for
|
|
* speed).
|
|
*
|
|
*/
|
|
|
|
UINT CHTMLInputTemplate::CheckVariable(TCHAR *var_name)
|
|
{
|
|
if (!_tcsncmp(DATA_PROBLEM_ASK,var_name, _tcslen(var_name))) {
|
|
return (PROBLEM_ASK_INDEX);
|
|
}
|
|
else if (!_tcsncmp(DATA_RECOMMENDATIONS,var_name, _tcslen(var_name))) {
|
|
return (RECOMMENDATIONS_INDEX);
|
|
}
|
|
else if (!_tcsncmp(DATA_QUESTIONS,var_name, _tcslen(var_name))) {
|
|
return (QUESTIONS_INDEX);
|
|
}
|
|
else if (!_tcsncmp(DATA_STATE,var_name, _tcslen(var_name))) {
|
|
return (STATE_INDEX);
|
|
}
|
|
else if (!_tcsncmp(DATA_BACK,var_name, _tcslen(var_name))) {
|
|
return (BACK_INDEX);
|
|
}
|
|
else if (!_tcsncmp(DATA_TROUBLE_SHOOTERS, var_name, _tcslen(var_name))) {
|
|
return (TROUBLE_SHOOTER_INDEX);
|
|
}
|
|
else if (IsFileName(var_name)) {
|
|
return (RESOURCE_INDEX);
|
|
}
|
|
else return (FALSE);
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
//
|
|
UINT CHTMLInputTemplate::GetStatus()
|
|
{
|
|
return (m_dwErr);
|
|
}
|
|
|
|
CHTMLInputTemplate::Push(HTXCommand *command)
|
|
{
|
|
if (m_cur_stack_count >9)
|
|
return(FALSE);
|
|
m_command_stack[m_cur_stack_count] = command;
|
|
m_cur_stack_count++;
|
|
return(TRUE);
|
|
}
|
|
|
|
HTXCommand *CHTMLInputTemplate::Pop()
|
|
{
|
|
if (m_cur_stack_count <= 0)
|
|
return(NULL);
|
|
return(m_command_stack[--m_cur_stack_count]);
|
|
}
|
|
|
|
//
|
|
//
|
|
HTXCommand *CHTMLInputTemplate::GetFirstCommand()
|
|
{
|
|
return(m_command_start);
|
|
}
|
|
|
|
/*
|
|
* ROUTINE: SetType
|
|
*
|
|
* PURPOSE: This set the TroubleShooter Type in the template
|
|
* The type field is printed after the header information
|
|
*
|
|
*/
|
|
void CHTMLInputTemplate::SetType(LPCTSTR type)
|
|
{
|
|
_stprintf(m_tstype, _T("%s"),type);
|
|
}
|
|
/*
|
|
* ROUTINE: Print
|
|
*
|
|
* PURPOSE: Prints out the Template. This functions executes the
|
|
* commands in the template and generates the output page.
|
|
*
|
|
*/
|
|
CHTMLInputTemplate::Print(UINT nargs, CString *cstr)
|
|
{
|
|
HTXCommand *cur_com;
|
|
CString strTxt;
|
|
|
|
if (m_dwErr){
|
|
strTxt.LoadString(IDS__ER_HTX_PARSE);
|
|
*cstr += strTxt;
|
|
return(FALSE);
|
|
}
|
|
|
|
cur_com = m_command_start; // get the start command
|
|
cur_com = cur_com->Execute(cstr,m_infer); // This prints the header
|
|
|
|
if (m_cHeaderItems)
|
|
{ // The first command prints script. Don't start the form.
|
|
int count = m_cHeaderItems;
|
|
do
|
|
{
|
|
cur_com = cur_com->GetNext();
|
|
cur_com = cur_com->Execute(cstr, m_infer);
|
|
count--;
|
|
} while (count > 0);
|
|
AfxFormatString1(strTxt, IDS_FORM_START, m_tstype);
|
|
*cstr += strTxt;
|
|
cur_com = cur_com->GetNext();
|
|
}
|
|
else
|
|
{
|
|
AfxFormatString1(strTxt, IDS_FORM_START, m_tstype);
|
|
*cstr += strTxt;
|
|
cur_com = cur_com->GetNext();
|
|
}
|
|
while (cur_com != NULL) {
|
|
cur_com = cur_com->Execute(cstr, m_infer);
|
|
cur_com = cur_com->GetNext();
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
// for testing
|
|
//
|
|
|
|
void CHTMLInputTemplate::DumpContentsToStdout()
|
|
{
|
|
HTXCommand *cur_com;
|
|
|
|
cur_com = GetFirstCommand();
|
|
while( cur_com != NULL){
|
|
_tprintf(_T("(%d) before: [%s]\n"), cur_com->GetType(), cur_com->GetBeforeStr());
|
|
_tprintf(_T("(%d) after: [%s]\n"), cur_com->GetType(), cur_com->GetAfterStr());
|
|
_tprintf(_T("\n"));
|
|
cur_com = cur_com->GetNext();
|
|
}
|
|
}
|