512 lines
12 KiB
C++
512 lines
12 KiB
C++
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
Argument
|
||
|
||
Abstract:
|
||
|
||
Argument processing for the "MORE" pager
|
||
|
||
Author:
|
||
|
||
Ramon Juan San Andres (ramonsa) 24-Apr-1990
|
||
|
||
Notes:
|
||
|
||
The arguments accepted by the more pager are:
|
||
|
||
Extended mode switch.- This allows all other options. Without this
|
||
switch, no other options are allowed.
|
||
|
||
Help switch.- Displays usage.
|
||
|
||
ClearScreen switch.- Clears the screen before displaying each page.
|
||
|
||
SqueezeBlank switch.- Squeezes consecutive blank lines into a single
|
||
line.
|
||
|
||
ExpandFormFeed switch.- FormFeeds are expanded to fill the rest of
|
||
the screen.
|
||
|
||
Start at line.- Paging starts at the specified line of the
|
||
first file.
|
||
|
||
Tab expansion.- Expand tabs to this number of blanks
|
||
|
||
File list.- List of files to page.
|
||
|
||
|
||
The more pager obtains its arguments from two sources:
|
||
|
||
1.- An environment variable ( "MORE" )
|
||
2.- The command line.
|
||
|
||
The environment variable may specify any options, except a file
|
||
list.
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
|
||
#include "ulib.hxx"
|
||
#include "arg.hxx"
|
||
#include "arrayit.hxx"
|
||
#include "rtmsg.h"
|
||
#include "path.hxx"
|
||
#include "smsg.hxx"
|
||
#include "system.hxx"
|
||
#include "more.hxx"
|
||
|
||
#define ENABLE_EXTENSIONS_VALUE L"EnableExtensions"
|
||
#define COMMAND_PROCESSOR_KEY L"Software\\Microsoft\\Command Processor"
|
||
|
||
//
|
||
// Static variables
|
||
//
|
||
//
|
||
PFLAG_ARGUMENT ExtendedModeArgument;
|
||
PFLAG_ARGUMENT ClearScreenArgument;
|
||
PFLAG_ARGUMENT ExpandFormFeedArgument;
|
||
PFLAG_ARGUMENT SqueezeBlanksArgument;
|
||
PFLAG_ARGUMENT Help1Argument;
|
||
PFLAG_ARGUMENT Help2Argument;
|
||
PLONG_ARGUMENT StartAtLineArgument;
|
||
PLONG_ARGUMENT TabExpArgument;
|
||
|
||
|
||
|
||
VOID
|
||
MORE::SetArguments(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Obtains the arguments for the "more" pager.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
FLAG_ARGUMENT LocalExtendedModeArgument;
|
||
FLAG_ARGUMENT LocalClearScreenArgument;
|
||
FLAG_ARGUMENT LocalExpandFormFeedArgument;
|
||
FLAG_ARGUMENT LocalSqueezeBlanksArgument;
|
||
FLAG_ARGUMENT LocalHelp1Argument;
|
||
FLAG_ARGUMENT LocalHelp2Argument;
|
||
LONG_ARGUMENT LocalStartAtLineArgument;
|
||
LONG_ARGUMENT LocalTabExpArgument;
|
||
|
||
ExtendedModeArgument = &LocalExtendedModeArgument;
|
||
ClearScreenArgument = &LocalClearScreenArgument;
|
||
ExpandFormFeedArgument = &LocalExpandFormFeedArgument;
|
||
SqueezeBlanksArgument = &LocalSqueezeBlanksArgument;
|
||
Help1Argument = &LocalHelp1Argument;
|
||
Help2Argument = &LocalHelp2Argument;
|
||
StartAtLineArgument = &LocalStartAtLineArgument;
|
||
TabExpArgument = &LocalTabExpArgument;
|
||
|
||
//
|
||
// Get arguments from the environment variable
|
||
//
|
||
GetArgumentsMore();
|
||
|
||
//
|
||
// Get the arguments from the command line.
|
||
//
|
||
GetArgumentsCmd();
|
||
|
||
//
|
||
// Determine if there is a need to enable command extension
|
||
//
|
||
GetRegistryInfo();
|
||
|
||
//
|
||
// Verify the arguments
|
||
//
|
||
CheckArgumentConsistency();
|
||
|
||
}
|
||
|
||
VOID
|
||
MORE::GetArgumentsMore(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Obtains the arguments from the "More" environment variable.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
ARRAY ArgArray;
|
||
PWSTRING MoreVariableName;
|
||
PWSTRING MoreVariableValue;
|
||
|
||
//
|
||
// Get the name of the MORE environment variable and the argument
|
||
//
|
||
if ( (MoreVariableName = QueryMessageString( MORE_ENVIRONMENT_VARIABLE_NAME )) == NULL ) {
|
||
|
||
Fatal();
|
||
}
|
||
|
||
//
|
||
// Get the value of the MORE environment variable.
|
||
//
|
||
MoreVariableValue = SYSTEM::QueryEnvironmentVariable( MoreVariableName );
|
||
|
||
if ( MoreVariableValue != NULL ) {
|
||
|
||
//
|
||
// Now prepare for parsing
|
||
//
|
||
if ( //
|
||
// Initialize tha arguments
|
||
//
|
||
!(ArgArray.Initialize( 7, 7 )) ||
|
||
!(ExtendedModeArgument->Initialize( "/E" )) ||
|
||
!(ClearScreenArgument->Initialize( "/C" )) ||
|
||
!(ExpandFormFeedArgument->Initialize( "/P" )) ||
|
||
!(SqueezeBlanksArgument->Initialize( "/S" )) ||
|
||
!(Help1Argument->Initialize( "/?" )) ||
|
||
!(Help2Argument->Initialize( "/H" )) ||
|
||
!(StartAtLineArgument->Initialize( "+*" )) ||
|
||
!(TabExpArgument->Initialize( "/t*" )) ||
|
||
//
|
||
// Put the arguments in the argument array
|
||
//
|
||
!(ArgArray.Put( ExtendedModeArgument )) ||
|
||
!(ArgArray.Put( ClearScreenArgument )) ||
|
||
!(ArgArray.Put( ExpandFormFeedArgument )) ||
|
||
!(ArgArray.Put( SqueezeBlanksArgument )) ||
|
||
!(ArgArray.Put( Help1Argument )) ||
|
||
!(ArgArray.Put( Help2Argument )) ||
|
||
!(ArgArray.Put( StartAtLineArgument )) ||
|
||
!(ArgArray.Put( TabExpArgument ))
|
||
) {
|
||
|
||
Fatal();
|
||
}
|
||
|
||
//
|
||
// Parse the arguments
|
||
//
|
||
ParseArguments( MoreVariableValue, &ArgArray );
|
||
|
||
//
|
||
// Set the global structures
|
||
//
|
||
_ExtendedModeSwitch = ExtendedModeArgument->QueryFlag();
|
||
_ClearScreenSwitch = ClearScreenArgument->QueryFlag();
|
||
_ExpandFormFeedSwitch = ExpandFormFeedArgument->QueryFlag();
|
||
_SqueezeBlanksSwitch = SqueezeBlanksArgument->QueryFlag();
|
||
_HelpSwitch = (BOOLEAN)(Help1Argument->QueryFlag() || Help2Argument->QueryFlag());
|
||
if ( StartAtLineArgument->IsValueSet() ) {
|
||
_StartAtLine = StartAtLineArgument->QueryLong();
|
||
}
|
||
if ( TabExpArgument->IsValueSet() ) {
|
||
_TabExp = TabExpArgument->QueryLong();
|
||
}
|
||
|
||
//
|
||
// Clean up
|
||
//
|
||
DELETE( MoreVariableValue );
|
||
}
|
||
|
||
DELETE( MoreVariableName );
|
||
|
||
}
|
||
|
||
VOID
|
||
MORE::GetArgumentsCmd(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Obtains the arguments from the Command line
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
ARRAY ArgArray;
|
||
DSTRING CmdLine;
|
||
PATH_ARGUMENT ProgramNameArgument;
|
||
|
||
//
|
||
// Prepare for parsing
|
||
//
|
||
if (//
|
||
// Initialize the arguments
|
||
//
|
||
!(CmdLine.Initialize( GetCommandLine() )) ||
|
||
!(ArgArray.Initialize( 9, 9 )) ||
|
||
!(ProgramNameArgument.Initialize( "*" )) ||
|
||
!(ExtendedModeArgument->Initialize( "/E" )) ||
|
||
!(ClearScreenArgument->Initialize( "/C" )) ||
|
||
!(ExpandFormFeedArgument->Initialize( "/P" )) ||
|
||
!(SqueezeBlanksArgument->Initialize( "/S" )) ||
|
||
!(Help1Argument->Initialize( "/?" )) ||
|
||
!(Help2Argument->Initialize( "/H" )) ||
|
||
!(StartAtLineArgument->Initialize( "+*" )) ||
|
||
!(TabExpArgument->Initialize( "/t*" )) ||
|
||
((_FilesArgument = NEW MULTIPLE_PATH_ARGUMENT) == NULL) ||
|
||
!(_FilesArgument->Initialize( "*", TRUE, TRUE )) ||
|
||
|
||
//
|
||
// Put the arguments in the argument array
|
||
//
|
||
!(ArgArray.Put( &ProgramNameArgument )) ||
|
||
!(ArgArray.Put( ExtendedModeArgument )) ||
|
||
!(ArgArray.Put( ClearScreenArgument )) ||
|
||
!(ArgArray.Put( ExpandFormFeedArgument )) ||
|
||
!(ArgArray.Put( SqueezeBlanksArgument )) ||
|
||
!(ArgArray.Put( Help1Argument )) ||
|
||
!(ArgArray.Put( Help2Argument )) ||
|
||
!(ArgArray.Put( StartAtLineArgument )) ||
|
||
!(ArgArray.Put( TabExpArgument )) ||
|
||
!(ArgArray.Put( _FilesArgument )) ) {
|
||
|
||
Fatal();
|
||
}
|
||
|
||
//
|
||
// Parse the arguments
|
||
//
|
||
ParseArguments( &CmdLine, &ArgArray );
|
||
|
||
//
|
||
// Set the global structures
|
||
//
|
||
_ExtendedModeSwitch |= ExtendedModeArgument->QueryFlag();
|
||
_ClearScreenSwitch |= ClearScreenArgument->QueryFlag();
|
||
_ExpandFormFeedSwitch |= ExpandFormFeedArgument->QueryFlag();
|
||
_SqueezeBlanksSwitch |= SqueezeBlanksArgument->QueryFlag();
|
||
_HelpSwitch |= Help1Argument->QueryFlag() || Help2Argument->QueryFlag();
|
||
|
||
if ( StartAtLineArgument->IsValueSet() ) {
|
||
_StartAtLine = StartAtLineArgument->QueryLong();
|
||
}
|
||
if ( TabExpArgument->IsValueSet() ) {
|
||
_TabExp = TabExpArgument->QueryLong();
|
||
}
|
||
|
||
}
|
||
|
||
VOID
|
||
MORE::ParseArguments(
|
||
IN PWSTRING CmdLine,
|
||
OUT PARRAY ArgArray
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Parses a group of arguments
|
||
|
||
Arguments:
|
||
|
||
CmdLine - Supplies pointer to a command line to parse
|
||
ArgArray - Supplies pointer to array of arguments
|
||
|
||
Return Value:
|
||
|
||
none
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
ARGUMENT_LEXEMIZER ArgLex;
|
||
ARRAY LexArray;
|
||
PWSTRING InvalidParameter;
|
||
|
||
//
|
||
// Initialize lexeme array and the lexemizer.
|
||
//
|
||
if ( !(LexArray.Initialize( 8, 8 )) ||
|
||
!(ArgLex.Initialize( &LexArray )) ) {
|
||
|
||
Fatal();
|
||
|
||
}
|
||
|
||
//
|
||
// Set our parsing preferences
|
||
//
|
||
ArgLex.PutMultipleSwitch( "/ECPSH?" );
|
||
ArgLex.PutSwitches( "/" );
|
||
ArgLex.PutSeparators( " /\t" );
|
||
ArgLex.SetCaseSensitive( FALSE );
|
||
ArgLex.PutStartQuotes( "\"" );
|
||
ArgLex.PutEndQuotes( "\"" );
|
||
|
||
//
|
||
// Parse the arguments
|
||
//
|
||
if ( !(ArgLex.PrepareToParse( CmdLine ))) {
|
||
|
||
Fatal( EXIT_ERROR, MORE_ERROR_GENERAL, "" );
|
||
|
||
}
|
||
|
||
if ( !ArgLex.DoParsing( ArgArray ) ) {
|
||
|
||
_Message.Set(MSG_INVALID_PARAMETER);
|
||
_Message.Display("%W", InvalidParameter = ArgLex.QueryInvalidArgument() );
|
||
DELETE(InvalidParameter);
|
||
ExitProcess( 0 );
|
||
}
|
||
|
||
LexArray.DeleteAllMembers( );
|
||
|
||
|
||
}
|
||
|
||
VOID
|
||
MORE::CheckArgumentConsistency (
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Checks the consistency of the arguments
|
||
|
||
Arguments:
|
||
|
||
none
|
||
|
||
Return Value:
|
||
|
||
none
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
BOOLEAN ExtendedSwitches;
|
||
|
||
if ( _HelpSwitch ) {
|
||
|
||
//
|
||
// Help wanted
|
||
//
|
||
Usage();
|
||
}
|
||
|
||
ExtendedSwitches = (BOOLEAN)( _ClearScreenSwitch ||
|
||
_ExpandFormFeedSwitch ||
|
||
_SqueezeBlanksSwitch ||
|
||
TabExpArgument->IsValueSet() ||
|
||
( _StartAtLine > (LONG)0 ) ||
|
||
_FilesArgument->WildCardExpansionFailed() ||
|
||
( _FilesArgument->QueryPathCount() > (ULONG)0));
|
||
|
||
//
|
||
// If the "extended" flag was not specified, then no other argument
|
||
// is allowed.
|
||
//
|
||
if ( !_ExtendedModeSwitch &&
|
||
ExtendedSwitches ) {
|
||
|
||
Fatal( EXIT_ERROR, MORE_ERROR_TOO_MANY_ARGUMENTS, "" );
|
||
|
||
}
|
||
|
||
//
|
||
// Error out if invalid file specified
|
||
//
|
||
if ( _FilesArgument->WildCardExpansionFailed() ) {
|
||
Fatal( EXIT_ERROR, MORE_ERROR_CANNOT_ACCESS, "%W", _FilesArgument->GetLexemeThatFailed() );
|
||
}
|
||
|
||
}
|
||
|
||
VOID
|
||
MORE::GetRegistryInfo(
|
||
)
|
||
{
|
||
ULONG valueType;
|
||
DWORD value;
|
||
ULONG valueLength = sizeof(value);
|
||
HKEY key;
|
||
LONG status;
|
||
|
||
|
||
if (_ExtendedModeSwitch)
|
||
return;
|
||
|
||
status = RegOpenKeyEx(HKEY_CURRENT_USER,
|
||
COMMAND_PROCESSOR_KEY,
|
||
0,
|
||
KEY_READ,
|
||
&key);
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
return;
|
||
}
|
||
|
||
status = RegQueryValueEx(key,
|
||
ENABLE_EXTENSIONS_VALUE,
|
||
NULL,
|
||
&valueType,
|
||
(LPBYTE)&value,
|
||
&valueLength);
|
||
|
||
if (status != ERROR_SUCCESS ||
|
||
valueType != REG_DWORD ||
|
||
valueLength != sizeof(DWORD)) {
|
||
return;
|
||
}
|
||
_ExtendedModeSwitch = (BOOLEAN)value;
|
||
}
|
||
|
||
|