2313 lines
45 KiB
C++
2313 lines
45 KiB
C++
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
Argument
|
||
|
||
Abstract:
|
||
|
||
Argument processing for the MODE utility.
|
||
|
||
The functions in this file:
|
||
|
||
1.- Parse the MODE command line.
|
||
2.- Perform some basic argument validation.
|
||
3.- Make a request packet that will be eventually routed to a
|
||
device handler.
|
||
|
||
|
||
Author:
|
||
|
||
Ramon Juan San Andres (ramonsa) 26-Jun-1991
|
||
|
||
Notes:
|
||
|
||
Due to the complexity of the MODE command line, and the fact that
|
||
we have to support both the DOS5 syntax (tagged parameters) and
|
||
the old DOS syntax (positional parameters), MODE does not use
|
||
the standard ULIB argument parsing. MODE does its own parsing
|
||
instead.
|
||
|
||
The mode command-line can take any of the following forms:
|
||
|
||
MODE [/?]
|
||
|
||
MODE [device] [/STATUS]
|
||
|
||
MODE device cp PREPARE=string
|
||
|
||
MODE device cp REFRESH
|
||
|
||
MODE device cp SELECT=codepage
|
||
|
||
MODE device cp [/STATUS]
|
||
|
||
MODE LPTn[:] [c][,l][,r]]
|
||
|
||
MODE LPTn[:] [COLS=c] [LINES=l] [RETRY=r]
|
||
|
||
MODE LPTn[:]=COMm[:]
|
||
|
||
MODE COMm[:] [b[,p[,d[,s[,r]]]]]
|
||
|
||
MODE COMm[:] [BAUD=b] [PARITY=p] [DATA=d] [STOP=s] [RETRY=r]
|
||
[to=on|off] [xon=on|off] [odsr=on|off] [octs=on|off]
|
||
|
||
MODE [c[,l]]
|
||
|
||
MODE CON[:] [COLS=c] [LINES=l]
|
||
|
||
MODE CON[:] [RATE=r DELAY=d]
|
||
|
||
|
||
where:
|
||
|
||
|
||
device := LPTn[:] | COMm[:] | CON[:]
|
||
cp := CP | CODEPAGE
|
||
|
||
|
||
|
||
The argument parsing of MODE does a syntax-directed translation of
|
||
the command line into a request packet. The translation is based on
|
||
the following language. Note that some terminal symbols (in uppercase)
|
||
might be language dependent.
|
||
|
||
|
||
mode := MODE { statusline | lptline | comline | conline | videoline }
|
||
|
||
statusline := /STA*
|
||
|
||
lptline := lptdev { lptredir | lptsetold | lptsetnew | lptcp | lptstatus }
|
||
lptred := =comdev
|
||
lptset := { n[,n][,c] | [COLS=n] [LINES=n] [RETRY=c] }
|
||
lptcp := cpstuff
|
||
lptstatus := { /STA* | }
|
||
|
||
comline := comdev { comset | comstatus }
|
||
comset := { n[,c[,n[,f[,c]]]] | [BAUD=n] [PARITY=c] [DATA=n] [STOP=f] [RETRY=c] }
|
||
[to=on|off] [xon=on|off] [odsr=on|off] [octs=on|off]
|
||
comstatus := { /STA* | }
|
||
|
||
conline := condev { conrc | contyp | concp | constatus }
|
||
conrc := [COLS=n] [LINES=n]
|
||
contyp := RATE=n DELAY=n
|
||
concp := cpstuff
|
||
constatus := { /STA* | }
|
||
|
||
videoline := n[,n]
|
||
|
||
cpstuff := cp { prepare | refresh | select | cpstatus}
|
||
cp := CP | CODEPAGE
|
||
prepare := PREPARE=*
|
||
refresh := REFRESH
|
||
select := SELECT=n
|
||
cpstatus := { /STA* | }
|
||
|
||
comdev := COMn[:]
|
||
lptdev := LPTn[:]
|
||
condev := CON[:]
|
||
|
||
n := Integer number
|
||
f := floating point number
|
||
c := character
|
||
|
||
|
||
|
||
The functions in this file parse the language shown above. Most of
|
||
the functions have names that correspond to non-terminal symbols in
|
||
the language.
|
||
|
||
|
||
There are 3 main functions used for reading the command line:
|
||
|
||
Match() - This function matches a pattern against whatever
|
||
is in the command line at the current position.
|
||
|
||
Note that this does not advance our current position
|
||
within the command line.
|
||
|
||
If the pattern has a magic character, then the
|
||
variables MatchBegin and MatchEnd delimit the
|
||
substring of the command line that matched that
|
||
magic character.
|
||
|
||
|
||
Advance() - This functions advances our current position within
|
||
the command line. The amount by which the position
|
||
is advanced is determined by the the last Match().
|
||
|
||
|
||
EndOfInput()- Returns TRUE if the command line has been consumed.
|
||
|
||
|
||
|
||
e.g. If the command line has the string "MODE COM1: 1200"
|
||
|
||
This is what the following sequence would do
|
||
|
||
Match( "*" ); // TRUE (matches "MODE")
|
||
Advance();
|
||
|
||
//
|
||
// Note that Match() does not advance our position
|
||
//
|
||
MATCH( "LPT" ); // FALSE (no match)
|
||
MATCH( "COM#" ); // TRUE (matches "COM" )
|
||
//
|
||
// At this point, MatchBegin and MatchEnd delimit the
|
||
// substring "1"
|
||
//
|
||
MATCH( "FOO" ); // FALSE (no match)
|
||
|
||
MATCH( "C*" ); // TRUE (matches "COM1:");
|
||
//
|
||
// At this point, MatchBegin and MatchEnd delimit the
|
||
// substring "OM1:"
|
||
//
|
||
Advance();
|
||
|
||
Match( "#" ); // TRUE (matches "1200");
|
||
Advance();
|
||
|
||
EndOfInput(); // TRUE
|
||
|
||
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
|
||
#include "mode.hxx"
|
||
#include "common.hxx"
|
||
#include "lpt.hxx"
|
||
#include "com.hxx"
|
||
#include "cons.hxx"
|
||
|
||
|
||
extern "C" {
|
||
|
||
#include <ctype.h>
|
||
#include <string.h>
|
||
|
||
}
|
||
|
||
|
||
//
|
||
//Static data
|
||
//
|
||
PWSTRING CmdLine; // The command line
|
||
CHNUM CharIndex; // Index of current character
|
||
CHNUM AdvanceIndex; // Index of next parameter
|
||
CHNUM ParmIndex; // Index of current parameter
|
||
CHNUM MatchBegin; // First index of match
|
||
CHNUM MatchEnd; // Last index of match
|
||
|
||
//
|
||
// Patterns.
|
||
//
|
||
// Most patterns contain terminal symbols. Certain characters in a
|
||
// pattern have a magic meaning:
|
||
//
|
||
// '*' Matches everything up to the end of the parameter (parameters are
|
||
// delimited by blank space).
|
||
//
|
||
// '#' Matches a sequence of digits
|
||
//
|
||
// '@' Matches a single character
|
||
//
|
||
// '[' Starts an optional sequence. If the first character in the
|
||
// the sequence matches, then all the sequence should match. If
|
||
// the first character in the sequence does not match, then the
|
||
// sequence is skipped.
|
||
//
|
||
// ']' End of optional sequence
|
||
//
|
||
//
|
||
|
||
|
||
//
|
||
// Prototypoes
|
||
//
|
||
|
||
PREQUEST_HEADER
|
||
LptLine (
|
||
);
|
||
|
||
PREQUEST_HEADER
|
||
LptRedir (
|
||
IN ULONG DeviceNumber
|
||
);
|
||
|
||
PREQUEST_HEADER
|
||
LptSet (
|
||
IN ULONG DeviceNumber
|
||
);
|
||
|
||
PREQUEST_HEADER
|
||
LptCp (
|
||
IN ULONG DeviceNumber
|
||
);
|
||
|
||
PREQUEST_HEADER
|
||
ComLine (
|
||
);
|
||
|
||
PREQUEST_HEADER
|
||
ComSet (
|
||
IN ULONG DeviceNumber
|
||
);
|
||
|
||
PREQUEST_HEADER
|
||
ConLine (
|
||
);
|
||
|
||
PREQUEST_HEADER
|
||
ConRc (
|
||
);
|
||
|
||
PREQUEST_HEADER
|
||
ConTyp (
|
||
);
|
||
|
||
PREQUEST_HEADER
|
||
ConCp (
|
||
);
|
||
|
||
PREQUEST_HEADER
|
||
VideoLine (
|
||
);
|
||
|
||
PREQUEST_HEADER
|
||
CpStuff (
|
||
IN DEVICE_TTYPE DeviceType,
|
||
IN ULONG DeviceNumber
|
||
);
|
||
|
||
BOOLEAN
|
||
AllocateResource(
|
||
);
|
||
|
||
VOID
|
||
DeallocateResource(
|
||
);
|
||
|
||
BOOLEAN
|
||
Match(
|
||
IN PCSTR Pattern
|
||
);
|
||
|
||
BOOLEAN
|
||
Match(
|
||
IN PCWSTRING Pattern
|
||
);
|
||
|
||
VOID
|
||
Advance(
|
||
);
|
||
|
||
BOOLEAN
|
||
EndOfInput(
|
||
);
|
||
|
||
PREQUEST_HEADER
|
||
MakeRequest(
|
||
IN DEVICE_TTYPE DeviceType,
|
||
IN LONG DeviceNumber,
|
||
IN REQUEST_TYPE RequestType,
|
||
IN ULONG Size
|
||
);
|
||
|
||
ULONG
|
||
GetNumber(
|
||
);
|
||
|
||
|
||
|
||
|
||
INLINE
|
||
BOOLEAN
|
||
EndOfInput(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Finds out if we are at the end of the command line.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - TRUE if at the end of input, FALSE otherwise
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
return (CharIndex >= CmdLine->QueryChCount());
|
||
|
||
}
|
||
|
||
PREQUEST_HEADER
|
||
GetRequest(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Parses the command line and makes a device request.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
Pointer to the device request.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PREQUEST_HEADER Request = NULL;
|
||
DSTRING Switches;
|
||
|
||
//
|
||
// Allocate strings (i.e. patterns ) from the resource
|
||
//
|
||
|
||
//
|
||
// Get the command line and parse it
|
||
//
|
||
if (Switches.Initialize("/-") &&
|
||
AllocateResource() &&
|
||
CmdLine->Initialize( GetCommandLine() )) {
|
||
|
||
//
|
||
// Before anything else, we look for a help switch somewhere
|
||
// in the command line. This kind of stinks, but this is how
|
||
// MODE works under DOS, se let's be compatible...
|
||
//
|
||
CharIndex = 0;
|
||
|
||
while ( TRUE ) {
|
||
|
||
//
|
||
// Look for a switch
|
||
//
|
||
CharIndex = CmdLine->Strcspn( &Switches, CharIndex );
|
||
|
||
if ( CharIndex != INVALID_CHNUM ) {
|
||
|
||
//
|
||
// There is a switch, see if it is the help switch
|
||
//
|
||
CharIndex++;
|
||
|
||
if ( Match( "?" )) {
|
||
|
||
//
|
||
// This is a help switch, Display help
|
||
//
|
||
DisplayMessageAndExit( MODE_MESSAGE_HELP, NULL, EXIT_SUCCESS );
|
||
|
||
}
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// No help requested, now we can parse the command line. First we
|
||
// initialize our indeces.
|
||
//
|
||
ParmIndex = 0;
|
||
CharIndex = 0;
|
||
AdvanceIndex = 0;
|
||
|
||
//
|
||
// Match the program name
|
||
//
|
||
Advance();
|
||
|
||
Match( "*" );
|
||
Advance();
|
||
|
||
//
|
||
// If there are no parameters, or the only parameter is the
|
||
// status switch, then this is a request for the status of
|
||
// all devices.
|
||
//
|
||
if ( EndOfInput() ) {
|
||
|
||
Request = MakeRequest( DEVICE_TYPE_ALL,
|
||
ALL_DEVICES,
|
||
REQUEST_TYPE_STATUS,
|
||
sizeof( REQUEST_HEADER ) );
|
||
|
||
} else if ( Match( "/STA*" ) ) {
|
||
|
||
Advance();
|
||
|
||
if ( !EndOfInput() ) {
|
||
|
||
ParseError();
|
||
}
|
||
|
||
Request = MakeRequest( DEVICE_TYPE_ALL,
|
||
ALL_DEVICES,
|
||
REQUEST_TYPE_STATUS,
|
||
sizeof( REQUEST_HEADER ) );
|
||
|
||
|
||
} else if ( Match( "LPT#[:]" ) ) {
|
||
|
||
//
|
||
// lptline
|
||
//
|
||
Request = LptLine();
|
||
|
||
} else if ( Match( "COM#[:]" ) ) {
|
||
|
||
//
|
||
// comline
|
||
//
|
||
Request = ComLine();
|
||
|
||
} else if ( Match( "CON[:]" ) ) {
|
||
|
||
//
|
||
// conline
|
||
//
|
||
Request = ConLine();
|
||
|
||
} else if ( Match( "#" ) ) {
|
||
|
||
//
|
||
// videoline
|
||
//
|
||
Request = VideoLine();
|
||
|
||
} else {
|
||
|
||
//
|
||
// Parse error
|
||
//
|
||
ParseError();
|
||
}
|
||
|
||
} else {
|
||
|
||
DisplayMessageAndExit( MODE_ERROR_NO_MEMORY, NULL, (ULONG)EXIT_ERROR );
|
||
|
||
}
|
||
|
||
//
|
||
// Deallocate strings from resource
|
||
//
|
||
DeallocateResource();
|
||
|
||
//
|
||
// Return the request
|
||
//
|
||
return Request;
|
||
|
||
}
|
||
|
||
PREQUEST_HEADER
|
||
LptLine (
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes care of parsing the lptline non-terminal symbol
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
Pointer to the device request.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
PREQUEST_HEADER Request;
|
||
ULONG DeviceNumber;
|
||
|
||
//
|
||
// Note that at this point we have matched the lpt device.
|
||
// Get the device number;
|
||
//
|
||
DeviceNumber = GetNumber();
|
||
|
||
Advance();
|
||
|
||
if ( EndOfInput() ) {
|
||
|
||
//
|
||
// End redirection
|
||
//
|
||
Request = MakeRequest( DEVICE_TYPE_LPT,
|
||
DeviceNumber,
|
||
REQUEST_TYPE_LPT_ENDREDIR,
|
||
sizeof( REQUEST_HEADER ) );
|
||
|
||
} else if ( Match( "/STA*" ) ) {
|
||
|
||
//
|
||
// Status request
|
||
//
|
||
Request = MakeRequest( DEVICE_TYPE_LPT,
|
||
DeviceNumber,
|
||
REQUEST_TYPE_STATUS,
|
||
sizeof( REQUEST_HEADER ) );
|
||
|
||
} else if ( Match ( "=" ) ) {
|
||
|
||
//
|
||
// lptredir
|
||
//
|
||
Request = LptRedir( DeviceNumber );
|
||
|
||
} else if ( Match( "#" ) || Match( "COLS=#" ) ||
|
||
Match( "LINES=#" ) || Match( "RETRY=@" ) ) {
|
||
|
||
//
|
||
// lptset
|
||
//
|
||
Request = LptSet( DeviceNumber );
|
||
|
||
} else if ( Match( "CP" ) || Match( "CODEPAGE" ) ) {
|
||
|
||
//
|
||
// lptcp
|
||
//
|
||
Request = LptCp( DeviceNumber );
|
||
|
||
} else {
|
||
|
||
//
|
||
// Error
|
||
//
|
||
ParseError();
|
||
|
||
}
|
||
|
||
return Request;
|
||
|
||
}
|
||
|
||
PREQUEST_HEADER
|
||
LptRedir (
|
||
IN ULONG DeviceNumber
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes care of parsing the lptredir non-terminal symbol
|
||
|
||
Arguments:
|
||
|
||
DeviceNumber - Supplies the device number
|
||
|
||
Return Value:
|
||
|
||
Pointer to the device request.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
PREQUEST_HEADER Request;
|
||
PLPT_REQUEST LptRequest;
|
||
ULONG ComDevice;
|
||
|
||
Advance();
|
||
|
||
//
|
||
// Can only redirect to COM devices
|
||
//
|
||
if ( Match( "COM#[:]" ) ) {
|
||
|
||
ComDevice = GetNumber();
|
||
|
||
Request = MakeRequest( DEVICE_TYPE_LPT,
|
||
DeviceNumber,
|
||
REQUEST_TYPE_LPT_REDIRECT,
|
||
sizeof(LPT_REQUEST ) );
|
||
|
||
LptRequest = (PLPT_REQUEST)Request;
|
||
|
||
LptRequest->Data.Redirect.DeviceType = DEVICE_TYPE_COM;
|
||
LptRequest->Data.Redirect.DeviceNumber = ComDevice;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Error
|
||
//
|
||
ParseError();
|
||
|
||
}
|
||
|
||
return Request;
|
||
}
|
||
|
||
PREQUEST_HEADER
|
||
LptSet (
|
||
IN ULONG DeviceNumber
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes care of parsing the lptset non-terminal symbol
|
||
|
||
Arguments:
|
||
|
||
DeviceNumber - Supplies the device number
|
||
|
||
Return Value:
|
||
|
||
Pointer to the device request.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
PREQUEST_HEADER Request;
|
||
PLPT_REQUEST LptRequest;
|
||
BOOLEAN SetCols = FALSE;
|
||
BOOLEAN SetLines = FALSE;
|
||
BOOLEAN SetRetry = FALSE;
|
||
ULONG Cols;
|
||
ULONG Lines;
|
||
WCHAR Retry;
|
||
|
||
|
||
if ( Match( "#" ) ) {
|
||
|
||
//
|
||
// Old syntax, where parameter are positional and comma-delimited.
|
||
//
|
||
// We will use the following automata for parsing the input
|
||
// (eoi = end of input)
|
||
//
|
||
//
|
||
// eoi
|
||
// [Cols]------------->[End]
|
||
// | ^
|
||
// |, |eoi
|
||
// v |
|
||
// [X]-----------+
|
||
// | ^
|
||
// | # |eoi
|
||
// +-->[Lines]--+
|
||
// | | ^
|
||
// | |, |
|
||
// |<----+ |
|
||
// | |
|
||
// |, |eoi
|
||
// | |
|
||
// v |
|
||
// [Y]-----------+
|
||
// | ^
|
||
// | @ |eoi
|
||
// +-->[Retry]--+
|
||
//
|
||
//
|
||
|
||
Cols = GetNumber();
|
||
SetCols = TRUE;
|
||
Advance();
|
||
|
||
//
|
||
// X:
|
||
//
|
||
if ( !Match( "," ) ) {
|
||
goto Eoi;
|
||
}
|
||
Advance();
|
||
|
||
if ( Match( "#" ) ) {
|
||
|
||
// n
|
||
// Lines
|
||
//
|
||
Lines = GetNumber();
|
||
SetLines = TRUE;
|
||
Advance();
|
||
}
|
||
|
||
//
|
||
// Y:
|
||
//
|
||
if ( !Match ( "," ) ) {
|
||
goto Eoi;
|
||
}
|
||
|
||
if ( Match( "@" ) ) {
|
||
|
||
//
|
||
// Retry
|
||
//
|
||
Retry = CmdLine->QueryChAt( MatchBegin );
|
||
SetRetry = TRUE;
|
||
Advance();
|
||
}
|
||
|
||
Eoi:
|
||
if ( !EndOfInput() ) {
|
||
|
||
//
|
||
// Error
|
||
//
|
||
ParseError();
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// New syntax, where parameters are tagged. The language assumes
|
||
// that all parameters are optional (as long as there is at least
|
||
// one present). If some is required, it is up to the Device
|
||
// handler to complain latter on.
|
||
//
|
||
|
||
while ( !EndOfInput() ) {
|
||
|
||
if ( Match( "COLS=#" ) ) {
|
||
//
|
||
// COLS=
|
||
//
|
||
Cols = GetNumber();
|
||
SetCols = TRUE;
|
||
Advance();
|
||
|
||
} else if ( Match( "LINES=#" ) ) {
|
||
//
|
||
// LINES=
|
||
//
|
||
Lines = GetNumber();
|
||
SetLines = TRUE;
|
||
Advance();
|
||
|
||
} else if ( Match( "RETRY=@" ) ) {
|
||
//
|
||
// RETRY=
|
||
//
|
||
Retry = CmdLine->QueryChAt( MatchBegin );
|
||
SetRetry = TRUE;
|
||
Advance();
|
||
|
||
} else {
|
||
|
||
ParseError();
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Now that we parsed all the parameters, we make the request
|
||
// packet.
|
||
//
|
||
Request = MakeRequest( DEVICE_TYPE_LPT,
|
||
DeviceNumber,
|
||
REQUEST_TYPE_LPT_SETUP,
|
||
sizeof(LPT_REQUEST ) );
|
||
|
||
LptRequest = (PLPT_REQUEST)Request;
|
||
|
||
LptRequest->Data.Setup.SetCol = SetCols;
|
||
LptRequest->Data.Setup.SetLines = SetLines;
|
||
LptRequest->Data.Setup.SetRetry = SetRetry;
|
||
LptRequest->Data.Setup.Col = Cols;
|
||
LptRequest->Data.Setup.Lines = Lines;
|
||
LptRequest->Data.Setup.Retry = Retry;
|
||
|
||
return Request;
|
||
}
|
||
|
||
PREQUEST_HEADER
|
||
LptCp (
|
||
IN ULONG DeviceNumber
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes care of parsing the lptcp non-terminal symbol
|
||
|
||
Arguments:
|
||
|
||
DeviceNumber - Supplies the device number
|
||
|
||
Return Value:
|
||
|
||
Pointer to the device request.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// Since this is the same for LPT and CON, we use the same
|
||
// function to handle both.
|
||
//
|
||
return CpStuff( DEVICE_TYPE_LPT, DeviceNumber );
|
||
|
||
}
|
||
|
||
PREQUEST_HEADER
|
||
ComLine (
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes care of parsing the comline non-terminal symbol
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
Pointer to the device request.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
PREQUEST_HEADER Request;
|
||
ULONG DeviceNumber;
|
||
|
||
//
|
||
// Note that we have already matched the COM device.
|
||
// Get the device number;
|
||
//
|
||
DeviceNumber = GetNumber();
|
||
|
||
Advance();
|
||
|
||
if ( Match( "/STA*" ) || EndOfInput() ) {
|
||
|
||
//
|
||
// Status request
|
||
//
|
||
Request = MakeRequest( DEVICE_TYPE_COM,
|
||
DeviceNumber,
|
||
REQUEST_TYPE_STATUS,
|
||
sizeof( REQUEST_HEADER ) );
|
||
|
||
|
||
} else {
|
||
|
||
//
|
||
// comset
|
||
//
|
||
Request = ComSet( DeviceNumber );
|
||
|
||
}
|
||
|
||
return Request;
|
||
|
||
}
|
||
|
||
PREQUEST_HEADER
|
||
ComSet (
|
||
IN ULONG DeviceNumber
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes care of parsing the comset non-terminal symbol
|
||
|
||
Arguments:
|
||
|
||
DeviceNumber - Supplies the device number
|
||
|
||
Return Value:
|
||
|
||
Pointer to the device request.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
PREQUEST_HEADER Request;
|
||
PCOM_REQUEST ComRequest;
|
||
|
||
|
||
BOOLEAN SetBaud = FALSE;
|
||
BOOLEAN SetDataBits = FALSE;
|
||
BOOLEAN SetStopBits = FALSE;
|
||
BOOLEAN SetParity = FALSE;
|
||
BOOLEAN SetRetry = FALSE;
|
||
BOOLEAN SetTimeOut = FALSE;
|
||
BOOLEAN SetXon = FALSE;
|
||
BOOLEAN SetOdsr = FALSE;
|
||
BOOLEAN SetIdsr = FALSE;
|
||
BOOLEAN SetOcts = FALSE;
|
||
BOOLEAN SetDtrControl = FALSE;
|
||
BOOLEAN SetRtsControl = FALSE;
|
||
|
||
ULONG Baud;
|
||
ULONG DataBits;
|
||
STOPBITS StopBits;
|
||
PARITY Parity;
|
||
WCHAR Retry;
|
||
BOOLEAN TimeOut;
|
||
BOOLEAN Xon;
|
||
BOOLEAN Odsr;
|
||
BOOLEAN Idsr;
|
||
BOOLEAN Octs;
|
||
DTR_CONTROL DtrControl;
|
||
RTS_CONTROL RtsControl;
|
||
|
||
|
||
if ( Match( "#" ) ) {
|
||
|
||
//
|
||
// Old syntax, where parameter are positional and comma-delimited.
|
||
//
|
||
// We will use the following automata for parsing the input
|
||
// (eoi = end of input):
|
||
//
|
||
// eoi
|
||
// [Baud]------------->[End]
|
||
// | ^
|
||
// |, |eoi
|
||
// v |
|
||
// [a]-----------+
|
||
// | ^
|
||
// | @ |eoi
|
||
// +-->[Parity]-+
|
||
// | | ^
|
||
// | |, |
|
||
// |<----+ |
|
||
// | |
|
||
// |, |eoi
|
||
// | |
|
||
// v |
|
||
// [b]-----------+
|
||
// | ^
|
||
// | # |eoi
|
||
// +-->[Data]---+
|
||
// | | ^
|
||
// | |, |
|
||
// |<----+ |
|
||
// | |
|
||
// |, |eoi
|
||
// v |
|
||
// [c]-----------+
|
||
// | ^
|
||
// | # |eoi
|
||
// +-->[Stop]---+
|
||
//
|
||
|
||
//
|
||
// Assume xon=off
|
||
//
|
||
|
||
SetXon = TRUE;
|
||
SetOdsr = TRUE;
|
||
SetOcts = TRUE;
|
||
SetDtrControl = TRUE;
|
||
SetRtsControl = TRUE;
|
||
Xon = FALSE;
|
||
Odsr = FALSE;
|
||
Octs = FALSE;
|
||
DtrControl = DTR_ENABLE;
|
||
RtsControl = RTS_ENABLE;
|
||
|
||
Baud = ConvertBaudRate( GetNumber() );
|
||
SetBaud = TRUE;
|
||
Advance();
|
||
|
||
//
|
||
// A:
|
||
//
|
||
if ( !Match( "," ) ) {
|
||
goto Eoi;
|
||
}
|
||
Advance();
|
||
|
||
if ( !Match( "," ) && Match( "@" ) ) {
|
||
|
||
//
|
||
// Parity
|
||
//
|
||
Parity = ConvertParity( CmdLine->QueryChAt( MatchBegin ) );
|
||
SetParity = TRUE;
|
||
Advance();
|
||
}
|
||
|
||
//
|
||
// B:
|
||
//
|
||
if ( !Match( "," )) {
|
||
goto Eoi;
|
||
}
|
||
Advance();
|
||
|
||
if ( Match( "#" )) {
|
||
|
||
//
|
||
// Data bits
|
||
//
|
||
DataBits = ConvertDataBits( GetNumber() );
|
||
SetDataBits = TRUE;
|
||
Advance();
|
||
}
|
||
|
||
//
|
||
// C:
|
||
//
|
||
if ( !Match( "," )) {
|
||
goto Eoi;
|
||
}
|
||
Advance();
|
||
|
||
if ( Match( "1.5" ) ) {
|
||
StopBits = COMM_STOPBITS_15;
|
||
SetStopBits = TRUE;
|
||
Advance();
|
||
} else if ( Match( "#" ) ) {
|
||
StopBits = ConvertStopBits( GetNumber() );
|
||
SetStopBits = TRUE;
|
||
Advance();
|
||
}
|
||
|
||
if (!Match( "," )) {
|
||
goto Eoi;
|
||
}
|
||
|
||
Advance();
|
||
|
||
if ( Match( "x" )) {
|
||
|
||
//
|
||
// XON=ON
|
||
//
|
||
SetXon = TRUE;
|
||
SetOdsr = TRUE;
|
||
SetOcts = TRUE;
|
||
SetDtrControl = TRUE;
|
||
SetRtsControl = TRUE;
|
||
Xon = TRUE;
|
||
Odsr = FALSE;
|
||
Octs = FALSE;
|
||
DtrControl = DTR_ENABLE;
|
||
RtsControl = RTS_ENABLE;
|
||
Advance();
|
||
|
||
} else if ( Match( "p" )) {
|
||
|
||
//
|
||
// Permanent retry - Hardware handshaking
|
||
//
|
||
|
||
SetXon = TRUE;
|
||
SetOdsr = TRUE;
|
||
SetOcts = TRUE;
|
||
SetDtrControl = TRUE;
|
||
SetRtsControl = TRUE;
|
||
Xon = FALSE;
|
||
Odsr = TRUE;
|
||
Octs = TRUE;
|
||
DtrControl = DTR_HANDSHAKE;
|
||
RtsControl = RTS_HANDSHAKE;
|
||
Advance();
|
||
|
||
} else {
|
||
|
||
//
|
||
// XON=OFF
|
||
//
|
||
SetXon = TRUE;
|
||
SetOdsr = TRUE;
|
||
SetOcts = TRUE;
|
||
SetDtrControl = TRUE;
|
||
SetRtsControl = TRUE;
|
||
Xon = FALSE;
|
||
Odsr = FALSE;
|
||
Octs = FALSE;
|
||
DtrControl = DTR_ENABLE;
|
||
RtsControl = RTS_ENABLE;
|
||
}
|
||
|
||
Eoi:
|
||
if ( !EndOfInput() ) {
|
||
|
||
//
|
||
// Error
|
||
//
|
||
ParseError();
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// New syntax, where parameters are tagged. The language assumes
|
||
// that all parameters are optional (as long as there is at least
|
||
// one present). If some is required, it is up to the Device
|
||
// handler to complain latter on.
|
||
//
|
||
|
||
|
||
while ( !EndOfInput() ) {
|
||
|
||
if ( Match( "BAUD=#" ) ) {
|
||
//
|
||
// BAUD=
|
||
//
|
||
Baud = ConvertBaudRate( GetNumber() );
|
||
SetBaud = TRUE;
|
||
Advance();
|
||
|
||
} else if ( Match( "PARITY=@" ) ) {
|
||
//
|
||
// PARITY=
|
||
//
|
||
Parity = ConvertParity( CmdLine->QueryChAt( MatchBegin ) );
|
||
SetParity = TRUE;
|
||
Advance();
|
||
|
||
} else if ( Match( "DATA=#" ) ) {
|
||
//
|
||
// DATA=
|
||
//
|
||
DataBits = ConvertDataBits( GetNumber() );
|
||
SetDataBits = TRUE;
|
||
Advance();
|
||
|
||
} else if ( Match( "STOP=1.5" ) ) {
|
||
//
|
||
// STOP=1.5
|
||
//
|
||
StopBits = COMM_STOPBITS_15;
|
||
SetStopBits = TRUE;
|
||
Advance();
|
||
|
||
} else if ( Match( "STOP=#" ) ) {
|
||
//
|
||
// STOP=
|
||
//
|
||
StopBits = ConvertStopBits( GetNumber() );
|
||
SetStopBits = TRUE;
|
||
Advance();
|
||
|
||
} else if ( Match( "RETRY=@" ) ) {
|
||
//
|
||
// RETRY=
|
||
//
|
||
Retry = ConvertRetry( CmdLine->QueryChAt( MatchBegin ) );
|
||
SetRetry = TRUE;
|
||
Advance();
|
||
|
||
} else if ( Match( "TO=ON" ) ) {
|
||
//
|
||
// TO=ON
|
||
//
|
||
SetTimeOut = TRUE;
|
||
TimeOut = FALSE; // FALSE means finite timeout
|
||
Advance();
|
||
|
||
} else if ( Match( "TO=OFF" ) ) {
|
||
//
|
||
// TO=OFF
|
||
//
|
||
SetTimeOut = TRUE;
|
||
TimeOut = TRUE; // TRUE means infinite timeout
|
||
Advance();
|
||
|
||
} else if ( Match( "XON=ON" ) ) {
|
||
//
|
||
// XON=ON
|
||
//
|
||
SetXon = TRUE;
|
||
Xon = TRUE;
|
||
Advance();
|
||
|
||
} else if ( Match( "XON=OFF" ) ) {
|
||
//
|
||
// XON=OFF
|
||
//
|
||
SetXon = TRUE;
|
||
Xon = FALSE;
|
||
Advance();
|
||
|
||
} else if ( Match( "ODSR=ON" ) ) {
|
||
//
|
||
// ODSR=ON
|
||
//
|
||
SetOdsr = TRUE;
|
||
Odsr = TRUE;
|
||
Advance();
|
||
|
||
} else if ( Match( "ODSR=OFF" ) ) {
|
||
//
|
||
// ODSR=OFF
|
||
//
|
||
SetOdsr = TRUE;
|
||
Odsr = FALSE;
|
||
Advance();
|
||
|
||
} else if ( Match( "IDSR=ON" ) ) {
|
||
//
|
||
// IDSR=ON
|
||
//
|
||
SetIdsr = TRUE;
|
||
Idsr = TRUE;
|
||
Advance();
|
||
|
||
} else if ( Match( "IDSR=OFF" ) ) {
|
||
//
|
||
// IDSR=OFF
|
||
//
|
||
SetIdsr = TRUE;
|
||
Idsr = FALSE;
|
||
Advance();
|
||
|
||
} else if ( Match( "OCTS=ON" ) ) {
|
||
//
|
||
// OCS=ON
|
||
//
|
||
SetOcts = TRUE;
|
||
Octs = TRUE;
|
||
Advance();
|
||
|
||
} else if ( Match( "OCTS=OFF" ) ) {
|
||
//
|
||
// OCS=OFF
|
||
//
|
||
SetOcts = TRUE;
|
||
Octs = FALSE;
|
||
Advance();
|
||
|
||
} else if ( Match( "DTR=*" ) ) {
|
||
//
|
||
// DTR=
|
||
//
|
||
DtrControl = ConvertDtrControl( CmdLine, MatchBegin, MatchEnd ) ;
|
||
SetDtrControl = TRUE;
|
||
Advance();
|
||
|
||
} else if ( Match( "RTS=*" ) ) {
|
||
//
|
||
// RTS=
|
||
//
|
||
RtsControl = ConvertRtsControl( CmdLine, MatchBegin, MatchEnd ) ;
|
||
SetRtsControl = TRUE;
|
||
Advance();
|
||
|
||
} else {
|
||
|
||
ParseError();
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Now that parsing is done, we can make the request packet.
|
||
//
|
||
Request = MakeRequest( DEVICE_TYPE_COM,
|
||
DeviceNumber,
|
||
REQUEST_TYPE_COM_SET,
|
||
sizeof(COM_REQUEST ) );
|
||
|
||
ComRequest = (PCOM_REQUEST)Request;
|
||
|
||
ComRequest->Data.Set.SetBaud = SetBaud;
|
||
ComRequest->Data.Set.SetDataBits = SetDataBits;
|
||
ComRequest->Data.Set.SetStopBits = SetStopBits;
|
||
ComRequest->Data.Set.SetParity = SetParity;
|
||
ComRequest->Data.Set.SetRetry = SetRetry;
|
||
ComRequest->Data.Set.SetTimeOut = SetTimeOut;
|
||
ComRequest->Data.Set.SetXon = SetXon;
|
||
ComRequest->Data.Set.SetOdsr = SetOdsr;
|
||
ComRequest->Data.Set.SetIdsr = SetIdsr;
|
||
ComRequest->Data.Set.SetOcts = SetOcts;
|
||
ComRequest->Data.Set.SetDtrControl = SetDtrControl;
|
||
ComRequest->Data.Set.SetRtsControl = SetRtsControl;
|
||
|
||
|
||
ComRequest->Data.Set.Baud = Baud;
|
||
ComRequest->Data.Set.DataBits = DataBits;
|
||
ComRequest->Data.Set.StopBits = StopBits;
|
||
ComRequest->Data.Set.Parity = Parity;
|
||
ComRequest->Data.Set.Retry = Retry;
|
||
ComRequest->Data.Set.TimeOut = TimeOut;
|
||
ComRequest->Data.Set.Xon = Xon;
|
||
ComRequest->Data.Set.Odsr = Odsr;
|
||
ComRequest->Data.Set.Idsr = Idsr;
|
||
ComRequest->Data.Set.Octs = Octs;
|
||
ComRequest->Data.Set.DtrControl = DtrControl;
|
||
ComRequest->Data.Set.RtsControl = RtsControl;
|
||
|
||
return Request;
|
||
|
||
}
|
||
|
||
PREQUEST_HEADER
|
||
ConLine (
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes care of parsing ConLine
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
Pointer to the device request.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
PREQUEST_HEADER Request;
|
||
|
||
Advance();
|
||
|
||
if ( Match( "/STA*" ) || EndOfInput() ) {
|
||
|
||
//
|
||
// Status request
|
||
//
|
||
Request = MakeRequest( DEVICE_TYPE_CON,
|
||
0,
|
||
REQUEST_TYPE_STATUS,
|
||
sizeof( REQUEST_HEADER ) );
|
||
|
||
|
||
} else if ( Match( "COLS=#" ) || Match( "LINES=#" ) ) {
|
||
|
||
//
|
||
// conrc
|
||
//
|
||
Request = ConRc();
|
||
|
||
} else if ( Match( "RATE=#" ) || Match( "DELAY=#" ) ) {
|
||
|
||
//
|
||
// contyp
|
||
//
|
||
Request = ConTyp();
|
||
|
||
} else if ( Match( "CP" ) || Match( "CODEPAGE" ) ) {
|
||
|
||
//
|
||
// concp
|
||
//
|
||
Request = ConCp();
|
||
|
||
} else {
|
||
|
||
//
|
||
// Error
|
||
//
|
||
ParseError();
|
||
|
||
}
|
||
|
||
return Request;
|
||
|
||
}
|
||
|
||
PREQUEST_HEADER
|
||
ConRc (
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes care of parsing the conrc non-terminal
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
Pointer to the device request.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
PREQUEST_HEADER Request;
|
||
PCON_REQUEST ConRequest;
|
||
|
||
BOOLEAN SetCol = FALSE;
|
||
BOOLEAN SetLines = FALSE;
|
||
|
||
ULONG Col;
|
||
ULONG Lines;
|
||
|
||
while ( !EndOfInput() ) {
|
||
|
||
if ( Match( "LINES=#" )) {
|
||
//
|
||
// LINES=
|
||
//
|
||
Lines = GetNumber();
|
||
SetLines = TRUE;
|
||
Advance();
|
||
|
||
} else if ( Match( "COLS=#" )) {
|
||
//
|
||
// COLS=
|
||
//
|
||
Col = GetNumber();
|
||
SetCol = TRUE;
|
||
Advance();
|
||
|
||
} else {
|
||
|
||
ParseError();
|
||
}
|
||
}
|
||
|
||
//
|
||
// We are done parsing, we make the request packet.
|
||
//
|
||
Request = MakeRequest( DEVICE_TYPE_CON,
|
||
0,
|
||
REQUEST_TYPE_CON_SET_ROWCOL,
|
||
sizeof(CON_REQUEST ) );
|
||
|
||
ConRequest = (PCON_REQUEST)Request;
|
||
|
||
ConRequest->Data.RowCol.SetCol = SetCol;
|
||
ConRequest->Data.RowCol.SetLines = SetLines;
|
||
ConRequest->Data.RowCol.Col = Col;
|
||
ConRequest->Data.RowCol.Lines = Lines;
|
||
|
||
return Request;
|
||
|
||
}
|
||
|
||
PREQUEST_HEADER
|
||
ConTyp (
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes care of parsing the contyp non-terminal
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
Pointer to the device request.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
PREQUEST_HEADER Request;
|
||
PCON_REQUEST ConRequest;
|
||
|
||
BOOLEAN SetRate = FALSE;
|
||
BOOLEAN SetDelay = FALSE;
|
||
|
||
ULONG Rate;
|
||
ULONG Delay;
|
||
|
||
|
||
//
|
||
// RATE=
|
||
//
|
||
if ( Match( "RATE=#" )) {
|
||
Rate = GetNumber();
|
||
SetRate = TRUE;
|
||
Advance();
|
||
}
|
||
|
||
//
|
||
// DELAY=
|
||
//
|
||
if ( Match( "DELAY=#" )) {
|
||
Delay = GetNumber();
|
||
SetDelay = TRUE;
|
||
Advance();
|
||
}
|
||
|
||
if ( !EndOfInput() ) {
|
||
//
|
||
// Error
|
||
//
|
||
ParseError();
|
||
}
|
||
|
||
//
|
||
// We are don parsing, we make the request packet.
|
||
//
|
||
Request = MakeRequest( DEVICE_TYPE_CON,
|
||
0,
|
||
REQUEST_TYPE_CON_SET_TYPEMATIC,
|
||
sizeof(CON_REQUEST ) );
|
||
|
||
ConRequest = (PCON_REQUEST)Request;
|
||
|
||
ConRequest->Data.Typematic.SetRate = SetRate;
|
||
ConRequest->Data.Typematic.SetDelay = SetDelay;
|
||
ConRequest->Data.Typematic.Rate = Rate;
|
||
ConRequest->Data.Typematic.Delay = Delay;
|
||
|
||
return Request;
|
||
|
||
}
|
||
|
||
PREQUEST_HEADER
|
||
ConCp (
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes care of parsing the concp non-terminal symbol
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
Pointer to the device request.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
return CpStuff( DEVICE_TYPE_CON, 0 );
|
||
|
||
}
|
||
|
||
PREQUEST_HEADER
|
||
VideoLine (
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes care of parsing the videoline non-terminal symbol
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
Pointer to the device request.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PREQUEST_HEADER Request;
|
||
PCON_REQUEST ConRequest;
|
||
|
||
BOOLEAN SetCol = FALSE;
|
||
BOOLEAN SetLines = FALSE;
|
||
|
||
ULONG Col;
|
||
ULONG Lines;
|
||
|
||
//
|
||
// This is in the old syntax, where parameter are positional
|
||
// and comma-delimited.
|
||
//
|
||
// We will use the following automata for parsing the input
|
||
// (eoi = end of input):
|
||
//
|
||
// eoi
|
||
// [Cols]--------->[End]
|
||
// | ^
|
||
// |, |
|
||
// v |
|
||
// [ ] |
|
||
// | |
|
||
// |# |
|
||
// | |
|
||
// v eoi |
|
||
// [Lines]-----+
|
||
//
|
||
|
||
|
||
if ( Match( "#" )) {
|
||
//
|
||
// Cols
|
||
//
|
||
Col = GetNumber();
|
||
SetCol = TRUE;
|
||
Advance();
|
||
}
|
||
|
||
if ( Match( "," ) ) {
|
||
|
||
Advance();
|
||
|
||
if ( Match( "#" )) {
|
||
|
||
Lines = GetNumber();
|
||
SetLines = TRUE;
|
||
Advance();
|
||
|
||
} else {
|
||
|
||
ParseError();
|
||
|
||
}
|
||
}
|
||
|
||
if ( !EndOfInput() ) {
|
||
//
|
||
// Error
|
||
//
|
||
ParseError();
|
||
}
|
||
|
||
|
||
//
|
||
// We are done parsing, make the request packet
|
||
//
|
||
Request = MakeRequest( DEVICE_TYPE_CON,
|
||
0,
|
||
REQUEST_TYPE_CON_SET_ROWCOL,
|
||
sizeof(CON_REQUEST ) );
|
||
|
||
ConRequest = (PCON_REQUEST)Request;
|
||
|
||
ConRequest->Data.RowCol.SetCol = SetCol;
|
||
ConRequest->Data.RowCol.SetLines = SetLines;
|
||
ConRequest->Data.RowCol.Col = Col;
|
||
ConRequest->Data.RowCol.Lines = Lines;
|
||
|
||
return Request;
|
||
|
||
}
|
||
|
||
PREQUEST_HEADER
|
||
CpStuff (
|
||
IN DEVICE_TTYPE DeviceType,
|
||
IN ULONG DeviceNumber
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes care of parsing the cpstuff non-terminal symbol
|
||
|
||
Arguments:
|
||
|
||
DeviceType - Supplies device type
|
||
DeviceNumber - Supplies device number
|
||
|
||
Return Value:
|
||
|
||
Pointer to the device request.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PREQUEST_HEADER Request;
|
||
PCON_REQUEST ConRequest;
|
||
|
||
Advance();
|
||
|
||
if ( Match( "PREPARE=*" ) ) {
|
||
|
||
//
|
||
//
|
||
// PREPARE=
|
||
//
|
||
// This is a No-Op
|
||
//
|
||
Request = MakeRequest( DeviceType,
|
||
DeviceNumber,
|
||
REQUEST_TYPE_CODEPAGE_PREPARE,
|
||
sizeof( REQUEST_HEADER ) );
|
||
|
||
} else if ( Match( "SELECT=#" ) ) {
|
||
|
||
//
|
||
//
|
||
// SELECT=
|
||
//
|
||
// Note that this relies on the fact that codepage requests
|
||
// are identical for all devices.
|
||
//
|
||
|
||
Request = MakeRequest( DeviceType,
|
||
DeviceNumber,
|
||
REQUEST_TYPE_CODEPAGE_SELECT,
|
||
sizeof( CON_REQUEST ) );
|
||
|
||
ConRequest = (PCON_REQUEST)Request;
|
||
|
||
ConRequest->Data.CpSelect.Codepage = GetNumber();
|
||
|
||
} else if ( Match( "/STA*" ) || EndOfInput() ) {
|
||
|
||
//
|
||
// /STATUS
|
||
//
|
||
Request = MakeRequest( DeviceType,
|
||
DeviceNumber,
|
||
REQUEST_TYPE_CODEPAGE_STATUS,
|
||
sizeof( REQUEST_HEADER ) );
|
||
|
||
} else if ( Match( "REFRESH" ) ) {
|
||
|
||
//
|
||
//
|
||
// REFRESH
|
||
//
|
||
// This is a No-Op
|
||
//
|
||
Request = MakeRequest( DeviceType,
|
||
DeviceNumber,
|
||
REQUEST_TYPE_CODEPAGE_REFRESH,
|
||
sizeof( REQUEST_HEADER ) );
|
||
|
||
} else {
|
||
|
||
ParseError();
|
||
|
||
}
|
||
|
||
return Request;
|
||
|
||
}
|
||
|
||
BOOLEAN
|
||
AllocateResource(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allocate strings from the resource
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
CmdLine = NEW DSTRING;
|
||
|
||
return (NULL == CmdLine) ? FALSE : TRUE;
|
||
|
||
}
|
||
|
||
VOID
|
||
DeallocateResource(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Deallocate strings from the resource
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DELETE( CmdLine );
|
||
|
||
}
|
||
|
||
BOOLEAN
|
||
Match(
|
||
IN PCSTR Pattern
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function matches a pattern against whatever
|
||
is in the command line at the current position.
|
||
|
||
Note that this does not advance our current position
|
||
within the command line.
|
||
|
||
If the pattern has a magic character, then the
|
||
variables MatchBegin and MatchEnd delimit the
|
||
substring of the command line that matched that
|
||
magic character.
|
||
|
||
Arguments:
|
||
|
||
Pattern - Supplies pointer to the pattern to match
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - TRUE if the pattern matched, FALSE otherwise
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DSTRING PatternString;
|
||
BOOLEAN StatusOk;
|
||
|
||
StatusOk = PatternString.Initialize( Pattern );
|
||
|
||
DebugAssert( StatusOk );
|
||
|
||
if ( StatusOk ) {
|
||
|
||
return Match( &PatternString );
|
||
|
||
} else {
|
||
|
||
DisplayMessageAndExit( MODE_ERROR_NO_MEMORY, NULL, (ULONG)EXIT_ERROR );
|
||
|
||
}
|
||
//NOTREACHED
|
||
return StatusOk;
|
||
}
|
||
|
||
BOOLEAN
|
||
Match(
|
||
IN PCWSTRING Pattern
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function matches a pattern against whatever
|
||
is in the command line at the current position.
|
||
|
||
Note that this does not advance our current position
|
||
within the command line.
|
||
|
||
If the pattern has a magic character, then the
|
||
variables MatchBegin and MatchEnd delimit the
|
||
substring of the command line that matched that
|
||
magic character.
|
||
|
||
Arguments:
|
||
|
||
Pattern - Supplies pointer to the pattern to match
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - TRUE if the pattern matched, FALSE otherwise
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
CHNUM CmdIndex; // Index within command line
|
||
CHNUM PatternIndex; // Index within pattern
|
||
WCHAR PatternChar; // Character in pattern
|
||
WCHAR CmdChar; // Character in command line;
|
||
|
||
DebugPtrAssert( Pattern );
|
||
|
||
CmdIndex = CharIndex;
|
||
PatternIndex = 0;
|
||
|
||
while ( (PatternChar = Pattern->QueryChAt( PatternIndex )) != INVALID_CHAR ) {
|
||
|
||
switch ( PatternChar ) {
|
||
|
||
case '#':
|
||
|
||
//
|
||
// Match a number
|
||
//
|
||
MatchBegin = CmdIndex;
|
||
MatchEnd = MatchBegin;
|
||
|
||
//
|
||
// Get all consecutive digits
|
||
//
|
||
while ( ((CmdChar = CmdLine->QueryChAt( MatchEnd )) != INVALID_CHAR) &&
|
||
isdigit( (char)CmdChar ) ) {
|
||
MatchEnd++;
|
||
}
|
||
MatchEnd--;
|
||
|
||
if ( MatchBegin > MatchEnd ) {
|
||
//
|
||
// No number
|
||
//
|
||
return FALSE;
|
||
}
|
||
|
||
CmdIndex = MatchEnd + 1;
|
||
PatternIndex++;
|
||
|
||
break;
|
||
|
||
|
||
case '@':
|
||
|
||
//
|
||
// Match one character
|
||
//
|
||
if ( CmdIndex >= CmdLine->QueryChCount() ) {
|
||
return FALSE;
|
||
}
|
||
|
||
MatchBegin = MatchEnd = CmdIndex;
|
||
CmdIndex++;
|
||
PatternIndex++;
|
||
|
||
break;
|
||
|
||
|
||
case '*':
|
||
|
||
//
|
||
// Match everything up to next blank (or end of input)
|
||
//
|
||
MatchBegin = CmdIndex;
|
||
MatchEnd = MatchBegin;
|
||
|
||
while ( ( (CmdChar = CmdLine->QueryChAt( MatchEnd )) != INVALID_CHAR ) &&
|
||
( CmdChar != (WCHAR)' ' ) ) {
|
||
|
||
MatchEnd++;
|
||
}
|
||
MatchEnd--;
|
||
|
||
CmdIndex = MatchEnd+1;
|
||
PatternIndex++;
|
||
|
||
break;
|
||
|
||
case '[':
|
||
|
||
//
|
||
// Optional sequence
|
||
//
|
||
PatternIndex++;
|
||
|
||
PatternChar = Pattern->QueryChAt( PatternIndex );
|
||
CmdChar = CmdLine->QueryChAt( CmdIndex );
|
||
|
||
//
|
||
// If the first charcter in the input does not match the
|
||
// first character in the optional sequence, we just
|
||
// skip the optional sequence.
|
||
//
|
||
if ( ( CmdChar == INVALID_CHAR ) ||
|
||
( CmdChar == ' ') ||
|
||
( towupper(CmdChar) != towupper(PatternChar) ) ) {
|
||
|
||
while ( PatternChar != ']' ) {
|
||
PatternIndex++;
|
||
PatternChar = Pattern->QueryChAt( PatternIndex );
|
||
}
|
||
PatternIndex++;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Since the first character in the sequence matched, now
|
||
// everything must match.
|
||
//
|
||
while ( PatternChar != ']' ) {
|
||
|
||
if ( towupper(PatternChar) != towupper(CmdChar) ) {
|
||
return FALSE;
|
||
}
|
||
CmdIndex++;
|
||
PatternIndex++;
|
||
CmdChar = CmdLine->QueryChAt( CmdIndex );
|
||
PatternChar = Pattern->QueryChAt( PatternIndex );
|
||
}
|
||
|
||
PatternIndex++;
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
//
|
||
// Both characters must match
|
||
//
|
||
CmdChar = CmdLine->QueryChAt( CmdIndex );
|
||
|
||
if ( ( CmdChar == INVALID_CHAR ) ||
|
||
( towupper(CmdChar) != towupper(PatternChar) ) ) {
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
CmdIndex++;
|
||
PatternIndex++;
|
||
|
||
break;
|
||
|
||
}
|
||
}
|
||
|
||
AdvanceIndex = CmdIndex;
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
VOID
|
||
Advance(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Advances our pointers to the beginning of the next lexeme
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
CharIndex = AdvanceIndex;
|
||
|
||
//
|
||
// Skip blank space
|
||
//
|
||
if ( CmdLine->QueryChAt( CharIndex ) == ' ' ) {
|
||
|
||
while ( CmdLine->QueryChAt( CharIndex ) == ' ' ) {
|
||
|
||
CharIndex++;
|
||
}
|
||
|
||
ParmIndex = CharIndex;
|
||
|
||
}
|
||
}
|
||
|
||
VOID
|
||
ParseError(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Display Invalid parameter error message and exits
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
DSTRING Parameter;
|
||
CHNUM ParmEnd;
|
||
|
||
//
|
||
// Look for end of parameter
|
||
//
|
||
ParmEnd = CmdLine->Strchr( ' ', ParmIndex );
|
||
|
||
|
||
Parameter.Initialize( CmdLine,
|
||
ParmIndex,
|
||
(ParmEnd == INVALID_CHNUM) ? TO_END : ParmEnd - ParmIndex );
|
||
|
||
DisplayMessageAndExit( MODE_ERROR_INVALID_PARAMETER,
|
||
&Parameter,
|
||
(ULONG)EXIT_ERROR );
|
||
|
||
}
|
||
|
||
PREQUEST_HEADER
|
||
MakeRequest(
|
||
IN DEVICE_TTYPE DeviceType,
|
||
IN LONG DeviceNumber,
|
||
IN REQUEST_TYPE RequestType,
|
||
IN ULONG Size
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Makes a request and initializes its header.
|
||
|
||
Arguments:
|
||
|
||
DeviceType - Supplies the type of device
|
||
DeviceNumber - Supplies the device number
|
||
RequestType - Supplies the type of request
|
||
Size - Supplies size of the request packet
|
||
|
||
Return Value:
|
||
|
||
Pointer to the device request.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PREQUEST_HEADER Request;
|
||
|
||
DebugAssert( Size >= sizeof( REQUEST_HEADER )) ;
|
||
|
||
Request = (PREQUEST_HEADER)MALLOC( (unsigned int)Size );
|
||
|
||
DebugPtrAssert( Request );
|
||
|
||
if ( !Request ) {
|
||
DisplayMessageAndExit( MODE_ERROR_NO_MEMORY, NULL, (ULONG)EXIT_ERROR );
|
||
}
|
||
|
||
Request->DeviceType = DeviceType;
|
||
Request->DeviceNumber = DeviceNumber;
|
||
Request->DeviceName = NULL;
|
||
Request->RequestType = RequestType;
|
||
|
||
return Request;
|
||
|
||
}
|
||
|
||
ULONG
|
||
GetNumber(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Converts the substring delimited by MatchBegin and MatchEnd into
|
||
a number.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
ULONG - The matched string converted to a number
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
LONG Number;
|
||
|
||
|
||
DebugAssert( MatchEnd >= MatchBegin );
|
||
|
||
if ( !CmdLine->QueryNumber( &Number, MatchBegin, (MatchEnd-MatchBegin)+1 ) ) {
|
||
ParseError();
|
||
}
|
||
|
||
return (ULONG)Number;
|
||
|
||
}
|