733 lines
17 KiB
C++
733 lines
17 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
Help.cxx
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Barry J. Gilhuly *** W-Barry *** May 91
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
ULIB, User Mode
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
This program calls Win32 API's to modify the STDIN and STDOUT handles as
|
|||
|
well as to spawn processes and create a pipe.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "ulib.hxx"
|
|||
|
#include "ulibcl.hxx"
|
|||
|
#include "error.hxx"
|
|||
|
#include "arg.hxx"
|
|||
|
#include "array.hxx"
|
|||
|
#include "dir.hxx"
|
|||
|
#include "file.hxx"
|
|||
|
#include "filestrm.hxx"
|
|||
|
#include "filter.hxx"
|
|||
|
#include "iterator.hxx"
|
|||
|
#include "keyboard.hxx"
|
|||
|
#include "path.hxx"
|
|||
|
#include "pipe.hxx"
|
|||
|
#include "rtmsg.h"
|
|||
|
#include "screen.hxx"
|
|||
|
#include "system.hxx"
|
|||
|
#include "smsg.hxx"
|
|||
|
#include "help.hxx"
|
|||
|
|
|||
|
|
|||
|
extern "C" {
|
|||
|
#include <ctype.h>
|
|||
|
#include <stdio.h>
|
|||
|
#include <string.h>
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ERRSTACK *perrstk;
|
|||
|
STREAM_MESSAGE *psmsg; // Create a pointer to the stream message
|
|||
|
// class for program output.
|
|||
|
USHORT Errlev; // The current program error level
|
|||
|
|
|||
|
DEFINE_CONSTRUCTOR( HELP, PROGRAM );
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HELP::Destruct(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Cleans up after finishing with an FC object.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DELETE( perrstk );
|
|||
|
DELETE( psmsg );
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HELP::Initialize(
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initializes an FC object.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
BOOLEAN - Indicates if the initialization succeeded.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
{
|
|||
|
ARGUMENT_LEXEMIZER ArgLex;
|
|||
|
ARRAY LexArray;
|
|||
|
ARRAY ArrayOfArg;
|
|||
|
|
|||
|
PATH_ARGUMENT ProgramName;
|
|||
|
FLAG_ARGUMENT FlagRequestHelp;
|
|||
|
DSTRING CommentString;
|
|||
|
|
|||
|
if( !LexArray.Initialize() ) {
|
|||
|
KdPrint(( "LexArray.Initialize() Failed!\n" ));
|
|||
|
}
|
|||
|
if( !ArgLex.Initialize(&LexArray) ) {
|
|||
|
KdPrint(( "ArgLex.Initialize() Failed!\n" ));
|
|||
|
}
|
|||
|
|
|||
|
// Allow only the '/' as a valid switch
|
|||
|
ArgLex.PutSwitches("/");
|
|||
|
ArgLex.SetCaseSensitive( FALSE );
|
|||
|
|
|||
|
if( !ArgLex.PrepareToParse() ) {
|
|||
|
KdPrint(( "ArgLex.PrepareToParse() Failed!\n" ));
|
|||
|
}
|
|||
|
|
|||
|
if( !ProgramName.Initialize("*") ||
|
|||
|
!FlagRequestHelp.Initialize("/?") ||
|
|||
|
!_FileName.Initialize("*") ) {
|
|||
|
|
|||
|
KdPrint(( "Unable to Initialize some or all of the Arguments!\n" ));
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if( !ArrayOfArg.Initialize() ) {
|
|||
|
KdPrint(( "ArrayOfArg.Initialize() Failed\n" ));
|
|||
|
}
|
|||
|
|
|||
|
if( !ArrayOfArg.Put(&ProgramName) ||
|
|||
|
!ArrayOfArg.Put(&FlagRequestHelp) ||
|
|||
|
!ArrayOfArg.Put(&_FileName) ) {
|
|||
|
|
|||
|
KdPrint(( "ArrayOfArg.Put() Failed!\n" ));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if( !( ArgLex.DoParsing( &ArrayOfArg ) ) ) {
|
|||
|
/*
|
|||
|
* Ignore (for now) any unrecognized switches on the command line since
|
|||
|
* that is what the Dos version does... However, it become advisable for
|
|||
|
* HELP to advise the user that there were too many parameters on the
|
|||
|
* command line... If this ever comes to pass, the TOO_MANY_PARAMETERS
|
|||
|
* message must be added to the resource file.
|
|||
|
*
|
|||
|
PWSTRING InvalidArg;
|
|||
|
|
|||
|
KdPrint(( "HELP: invalid Switch(s)\n" ));
|
|||
|
InvalidArg = ArgLex.QueryInvalidArgument();
|
|||
|
|
|||
|
psmsg->Set( MSG_HELP_TOO_MANY_PARAMETERS );
|
|||
|
psmsg->Display( "%W", InvalidArg );
|
|||
|
|
|||
|
DELETE( InvalidArg );
|
|||
|
return( FALSE );
|
|||
|
*
|
|||
|
*/
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// It should now be safe to test the arguments for their values...
|
|||
|
if( FlagRequestHelp.QueryFlag() ) {
|
|||
|
|
|||
|
// Send help message
|
|||
|
KdPrint(( "Help....\n" ));
|
|||
|
psmsg->Set( MSG_HELP_HELP_MESSAGE );
|
|||
|
psmsg->Display( "" );
|
|||
|
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set up the comment character
|
|||
|
//
|
|||
|
CommentString.Initialize( "" );
|
|||
|
SYSTEM::QueryResourceString( &CommentString, MSG_HELP_HELP_COMMENT, "" );
|
|||
|
_CommentChar = CommentString.QueryChAt( 0 );
|
|||
|
|
|||
|
LexArray.DeleteAllMembers();
|
|||
|
|
|||
|
return( TRUE );
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
HELP::GetHelp(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Decide which type of help to provide to the user.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
There are two cases when the program gets here: Either the command
|
|||
|
line was completely empty and the user therefore wants the entire
|
|||
|
help file to be output, or help has been requested for as single
|
|||
|
command.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PPATH pHelpPath;
|
|||
|
DSTRING HelpName;
|
|||
|
PFSN_FILE pHelpFile;
|
|||
|
|
|||
|
// Find the help file...
|
|||
|
SYSTEM::QueryResourceString( &HelpName, MSG_HELP_HELP_FILE_NAME, "" );
|
|||
|
|
|||
|
if( ( pHelpPath = SYSTEM::SearchPath( &HelpName ) ) == NULL ) {
|
|||
|
// Output unable to find helpfile...
|
|||
|
KdPrint(( "Unable to find helpfile...\n" ));
|
|||
|
psmsg->Set( MSG_HELP_HELP_FILE_NOT_FOUND );
|
|||
|
psmsg->Display( "" );
|
|||
|
Errlev = HELP_ERROR;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Get a file node to the Help file and open a stream...
|
|||
|
if( ( pHelpFile = SYSTEM::QueryFile( pHelpPath ) ) == NULL ) {
|
|||
|
KdPrint(( "Unable to create FSN_NODE for helpfile\n" ));
|
|||
|
psmsg->Set( MSG_HELP_HELP_FILE_ERROR );
|
|||
|
psmsg->Display( "" );
|
|||
|
DELETE( pHelpPath );
|
|||
|
Errlev = HELP_ERROR;
|
|||
|
return;
|
|||
|
}
|
|||
|
DELETE( pHelpPath );
|
|||
|
|
|||
|
if( ( _HelpStream = pHelpFile->QueryStream( READ_ACCESS ) ) == NULL ) {
|
|||
|
KdPrint(( "Unable to open stream to help file...\n" ));
|
|||
|
psmsg->Set( MSG_HELP_HELP_FILE_ERROR );
|
|||
|
psmsg->Display( "" );
|
|||
|
DELETE( pHelpFile );
|
|||
|
Errlev = HELP_ERROR;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Test if there is a command...
|
|||
|
if( _FileName.IsValueSet() ) {
|
|||
|
PrintCmd();
|
|||
|
} else {
|
|||
|
PrintList();
|
|||
|
}
|
|||
|
|
|||
|
DELETE( pHelpFile );
|
|||
|
DELETE( _HelpStream );
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
HELP::PrintCmd(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Search the help file for the command - if its there, exec it, otherwise
|
|||
|
print an error message and return.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
BOOLEAN flag;
|
|||
|
CHNUM CmdLen;
|
|||
|
LONG result;
|
|||
|
PWSTRING String;
|
|||
|
DSTRING CmdStr;
|
|||
|
DSTRING Command;
|
|||
|
LPWSTR pCmd;
|
|||
|
STR ApiCommand[ MAX_PATH ];
|
|||
|
STARTUPINFO StartupInfo;
|
|||
|
PROCESS_INFORMATION ProcessInfo;
|
|||
|
BOOLEAN dot_com = FALSE;
|
|||
|
|
|||
|
DSTRING CmdCommand;
|
|||
|
DSTRING ExternalCommand;
|
|||
|
DSTRING DotComExtension;
|
|||
|
FSTRING fstring;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the strings to be used...
|
|||
|
//
|
|||
|
CmdStr.Initialize( "" );
|
|||
|
Command.Initialize( _FileName.GetString() );
|
|||
|
CmdLen = Command.QueryChCount();
|
|||
|
|
|||
|
// Test if the command is on the list...(recognized)
|
|||
|
flag = FALSE;
|
|||
|
while( !_HelpStream->IsAtEnd() ) {
|
|||
|
|
|||
|
if( ( String = NEW DSTRING ) == NULL ) {
|
|||
|
KdPrint(( "Unable to create string for QueryLine()\n" ));
|
|||
|
return;
|
|||
|
}
|
|||
|
String->Initialize( "" );
|
|||
|
|
|||
|
|
|||
|
// Help file is ANSI.
|
|||
|
WSTRING::SetAnsiConversions();
|
|||
|
if( !_HelpStream->ReadLine( String ) ) {
|
|||
|
KdPrint(( "Unable to read line but file isn't empty...\n" ));
|
|||
|
}
|
|||
|
WSTRING::SetOemConversions();
|
|||
|
|
|||
|
if( !isspace( String->QueryChAt( 0 ) ) ) { // if a command starts this line...
|
|||
|
result = String->Stricmp( &Command, 0, CmdLen, 0, CmdLen );
|
|||
|
if( !result ) {
|
|||
|
flag = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
if( result > 0 ) {
|
|||
|
break; // We've passed it...
|
|||
|
}
|
|||
|
}
|
|||
|
DELETE( String );
|
|||
|
|
|||
|
}
|
|||
|
DELETE( String );
|
|||
|
|
|||
|
if( !flag ) {
|
|||
|
KdPrint(( "Help not available for this subject\n" ));
|
|||
|
psmsg->Set( MSG_HELP_HELP_UNAVAILABLE );
|
|||
|
psmsg->Display( "%W", &Command );
|
|||
|
Errlev = NO_HELP_FOUND;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set up the StartupInfo block...
|
|||
|
//
|
|||
|
memset(&StartupInfo, 0, sizeof( STARTUPINFO ) );
|
|||
|
StartupInfo.cb = sizeof( STARTUPINFO );
|
|||
|
|
|||
|
//
|
|||
|
// The command has now been recognized - if it is internal, exec
|
|||
|
// it with Cmd.exe, otherwise, just attempt to exec it...
|
|||
|
//
|
|||
|
if( IsInternal( &Command ) ) {
|
|||
|
|
|||
|
// Exec with Cmd.exe
|
|||
|
SYSTEM::QueryResourceString( &CmdStr, MSG_HELP_EXECUTE_WITH_CMD, "%W", _FileName.GetString() );
|
|||
|
pCmd = CmdStr.QueryWSTR();
|
|||
|
flag = CreateProcess( NULL,
|
|||
|
pCmd,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
TRUE,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
&StartupInfo,
|
|||
|
&ProcessInfo
|
|||
|
);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
if( !ExternalCommand.Initialize( _FileName.GetString() ) ) {
|
|||
|
KdPrint(( "ExternalCommand.Initialize() failed \n" ));
|
|||
|
return;
|
|||
|
}
|
|||
|
//
|
|||
|
// Find out if we have to add '.COM' to the command to be
|
|||
|
// be executed
|
|||
|
//
|
|||
|
if( IsExternalDotComCommand( &ExternalCommand ) ) {
|
|||
|
//
|
|||
|
// Append '.COM' to the command
|
|||
|
//
|
|||
|
if( !DotComExtension.Initialize( ".COM" ) ) {
|
|||
|
KdPrint(( "DotComExtension.Initialize() failed \n" ));
|
|||
|
return;
|
|||
|
}
|
|||
|
ExternalCommand.Strcat( &DotComExtension );
|
|||
|
dot_com = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
for (;;) {
|
|||
|
|
|||
|
//
|
|||
|
// Exec just the command...
|
|||
|
SYSTEM::QueryResourceString( &CmdStr, MSG_HELP_EXECUTE_WITHOUT_CMD, "%W", &ExternalCommand );
|
|||
|
pCmd = CmdStr.QueryWSTR();
|
|||
|
flag = CreateProcess( NULL,
|
|||
|
pCmd,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
TRUE,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
&StartupInfo,
|
|||
|
&ProcessInfo
|
|||
|
);
|
|||
|
|
|||
|
// If this command wasn't an "official" dot_com but the
|
|||
|
// CreateProcess failed then try the create process again
|
|||
|
// with the .COM extension. We do this so that apps that
|
|||
|
// add stuff to the DOSHELP file won't be disappointed just
|
|||
|
// because they end in COM.
|
|||
|
|
|||
|
if (!flag && !dot_com) {
|
|||
|
|
|||
|
ExternalCommand.Strcat(fstring.Initialize((PWSTR) L".COM"));
|
|||
|
dot_com = TRUE;
|
|||
|
|
|||
|
} else {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
FREE( pCmd );
|
|||
|
|
|||
|
if( !flag ) {
|
|||
|
// Failed to create the process...
|
|||
|
KdPrint(( " Unable to run the exe...\n" ));
|
|||
|
psmsg->Set( MSG_HELP_HELP_UNAVAILABLE );
|
|||
|
psmsg->Display( "%W", &Command );
|
|||
|
Errlev = NO_HELP_FOUND;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Wait for the process to complete...
|
|||
|
WaitForSingleObject( ProcessInfo.hProcess, (DWORD)-1 );
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
HELP::PrintList(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Search the help file for the command - if its there, exec it, otherwise
|
|||
|
print an error message and return.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
BOOLEAN StatusOk; // status value
|
|||
|
PKEYBOARD InStream;
|
|||
|
PSCREEN OutStream;
|
|||
|
PWSTRING String;
|
|||
|
SCREEN Screen;
|
|||
|
USHORT idx;
|
|||
|
USHORT ScrRows;
|
|||
|
|
|||
|
//
|
|||
|
// Get a pointer to the input stream, so we can tell when a character
|
|||
|
// is typed.
|
|||
|
//
|
|||
|
if( !( InStream = KEYBOARD::Cast( Get_Standard_Input_Stream() ) ) ) {
|
|||
|
KdPrint(( "Unable to flush keyboard - skipping more...\n" ));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if the Stdout is a Screen Object. If it isn't, then we don't
|
|||
|
// want to pause or print the general help message....
|
|||
|
//
|
|||
|
OutStream = SCREEN::Cast( Get_Standard_Output_Stream() );
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the screen object and get the number of rows. The number
|
|||
|
// of cols is inconsequential.
|
|||
|
//
|
|||
|
Screen.Initialize();
|
|||
|
Screen.QueryScreenSize( &ScrRows, &idx );
|
|||
|
|
|||
|
|
|||
|
for( ;; ) {
|
|||
|
|
|||
|
if( OutStream ) {
|
|||
|
//
|
|||
|
// Output the general message string...
|
|||
|
//
|
|||
|
psmsg->Set( MSG_HELP_GENERAL_HELP );
|
|||
|
psmsg->Display( "" );
|
|||
|
}
|
|||
|
|
|||
|
for( idx = ScrRows - USED_ROWS; idx; ) {
|
|||
|
|
|||
|
//
|
|||
|
// Read a line from the file and write it to the stream...
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
if( _HelpStream->IsAtEnd() ) {
|
|||
|
|
|||
|
//
|
|||
|
// End of the HELP file...
|
|||
|
//
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if( ( String = NEW DSTRING ) == NULL ) {
|
|||
|
KdPrint(( "Unable to create string for QueryLine()\n" ));
|
|||
|
return;
|
|||
|
}
|
|||
|
String->Initialize( "" );
|
|||
|
|
|||
|
|
|||
|
// The help file contains ANSI strings.
|
|||
|
|
|||
|
WSTRING::SetAnsiConversions();
|
|||
|
|
|||
|
if( !_HelpStream->ReadLine( String ) ) {
|
|||
|
KdPrint(( "Unable to read line but file isn't empty...\n" ));
|
|||
|
}
|
|||
|
|
|||
|
WSTRING::SetOemConversions();
|
|||
|
|
|||
|
//
|
|||
|
// Print the latest line, if it isn't a comment... (preceded by '@')
|
|||
|
//
|
|||
|
if( String->QueryChAt( 0 ) != _CommentChar ) {
|
|||
|
|
|||
|
psmsg->Set( MSG_HELP_HELP_FILE_DATA );
|
|||
|
psmsg->Display( "%W", String );
|
|||
|
|
|||
|
//
|
|||
|
// Used a line - decrement the count
|
|||
|
//
|
|||
|
idx--;
|
|||
|
|
|||
|
}
|
|||
|
DELETE( String );
|
|||
|
|
|||
|
}
|
|||
|
//
|
|||
|
// If we are able, or if we need to, wait for any response from
|
|||
|
// the keyboard...
|
|||
|
//
|
|||
|
if( OutStream && InStream ) {
|
|||
|
|
|||
|
//
|
|||
|
// Output the '--- MORE ---' string...
|
|||
|
//
|
|||
|
psmsg->Set( MSG_HELP_MORE );
|
|||
|
psmsg->Display( "" );
|
|||
|
|
|||
|
InStream->Flush(); // Kill any keys waiting in the buffer
|
|||
|
while( InStream->IsKeyAvailable( &StatusOk ) && !StatusOk ) {
|
|||
|
;
|
|||
|
}
|
|||
|
InStream->Flush(); // remove keys waiting in the buffer
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HELP::IsInternal(
|
|||
|
PWSTRING pCmdString
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initializes an FC object.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
BOOLEAN - Indicates if the initialization succeeded.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PWSTRING pString;
|
|||
|
USHORT idx;
|
|||
|
LONG result;
|
|||
|
|
|||
|
pString = NEW DSTRING;
|
|||
|
idx = 0;
|
|||
|
while( Internal_Commands[ idx ] != NULL ) {
|
|||
|
pString->Initialize( Internal_Commands[ idx ] );
|
|||
|
result = pString->Stricmp( pCmdString );
|
|||
|
if( !result ) {
|
|||
|
DELETE( pString );
|
|||
|
return( TRUE );
|
|||
|
}
|
|||
|
if( result > 0 ) { // The Compare has returned that the command
|
|||
|
// string is lexically greater then the current
|
|||
|
// value - therefore, since the list is alphabetic
|
|||
|
// the command won't be found.
|
|||
|
DELETE( pString );
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
idx++;
|
|||
|
}
|
|||
|
DELETE( pString );
|
|||
|
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HELP::IsExternalDotComCommand(
|
|||
|
PWSTRING pCmdString
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Determines if pCmdString refers to an external utility whose name
|
|||
|
has .com extension
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pCmdString - Pointer to a WSTRING that contains the utility name
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
BOOLEAN - Returns TRUE if pCmdString refers to an external utility
|
|||
|
that whose name has .com extension.
|
|||
|
Returns FALSE otherwise.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PWSTRING pString;
|
|||
|
USHORT idx;
|
|||
|
LONG result;
|
|||
|
|
|||
|
pString = NEW DSTRING;
|
|||
|
idx = 0;
|
|||
|
while( ExternalDotComCommands[ idx ] != NULL ) {
|
|||
|
pString->Initialize( ExternalDotComCommands[ idx ] );
|
|||
|
result = pString->Stricmp( pCmdString );
|
|||
|
if( !result ) {
|
|||
|
DELETE( pString );
|
|||
|
return( TRUE );
|
|||
|
}
|
|||
|
if( result > 0 ) { // The Compare has returned that the command
|
|||
|
// string is lexically greater then the current
|
|||
|
// value - therefore, since the list is alphabetic
|
|||
|
// the command won't be found.
|
|||
|
DELETE( pString );
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
idx++;
|
|||
|
}
|
|||
|
DELETE( pString );
|
|||
|
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
int _CRTAPI1
|
|||
|
main(
|
|||
|
)
|
|||
|
{
|
|||
|
DEFINE_CLASS_DESCRIPTOR( HELP );
|
|||
|
|
|||
|
{
|
|||
|
HELP Help;
|
|||
|
|
|||
|
perrstk = NEW ERRSTACK;
|
|||
|
psmsg = NEW STREAM_MESSAGE;
|
|||
|
Errlev = NO_ERRORS;
|
|||
|
|
|||
|
psmsg->Initialize( Get_Standard_Output_Stream(),
|
|||
|
Get_Standard_Input_Stream() );
|
|||
|
|
|||
|
if( !SYSTEM::IsCorrectVersion() ) {
|
|||
|
KdPrint(( "Incorrect Version Number...\n" ));
|
|||
|
psmsg->Set( MSG_HELP_INCORRECT_VERSION );
|
|||
|
psmsg->Display( "" );
|
|||
|
Help.Destruct();
|
|||
|
return( NO_ERRORS );
|
|||
|
}
|
|||
|
if( !( Help.Initialize() ) ) {
|
|||
|
//
|
|||
|
// The Command line didn't initialize properly, die nicely
|
|||
|
// without printing any error messages - Main doesn't know
|
|||
|
// why the Initialization failed...
|
|||
|
//
|
|||
|
Help.Destruct();
|
|||
|
return( NO_ERRORS );
|
|||
|
}
|
|||
|
|
|||
|
// Do file comparison stuff...
|
|||
|
Help.GetHelp();
|
|||
|
Help.Destruct();
|
|||
|
return( Errlev );
|
|||
|
}
|
|||
|
}
|