windows-nt/Source/XPSP1/NT/base/fs/utils/mode/argument.cxx
2020-09-26 16:20:57 +08:00

2313 lines
45 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}