878 lines
20 KiB
C++
878 lines
20 KiB
C++
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
More
|
||
|
||
Abstract:
|
||
|
||
"More" pager
|
||
|
||
Author:
|
||
|
||
Ramon Juan San Andres (ramonsa) 11-Apr-1990
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
#include "ulib.hxx"
|
||
#include "arg.hxx"
|
||
#include "arrayit.hxx"
|
||
#include "error.hxx"
|
||
#include "file.hxx"
|
||
#include "filestrm.hxx"
|
||
#include "keyboard.hxx"
|
||
#include "rtmsg.h"
|
||
#include "pager.hxx"
|
||
#include "path.hxx"
|
||
#include "smsg.hxx"
|
||
#include "system.hxx"
|
||
#include "more.hxx"
|
||
|
||
#define NULL_CHARACTER ((CHAR)'\0')
|
||
#define CTRLC_CHARACTER ((CHAR)0x03)
|
||
|
||
//
|
||
// Required by ULIB
|
||
//
|
||
ERRSTACK *perrstk;
|
||
|
||
|
||
|
||
|
||
VOID _CRTAPI1
|
||
main (
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Main function of the more pager.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
|
||
{
|
||
|
||
// Initialize stuff
|
||
//
|
||
DEFINE_CLASS_DESCRIPTOR( MORE );
|
||
|
||
//
|
||
// Now do the paging
|
||
//
|
||
{
|
||
MORE More;
|
||
|
||
//
|
||
// Initialize the MORE object.
|
||
//
|
||
if( More.Initialize() ) {
|
||
|
||
//
|
||
// Do the paging
|
||
//
|
||
More.DoPaging();
|
||
}
|
||
}
|
||
}
|
||
|
||
DEFINE_CONSTRUCTOR( MORE, PROGRAM );
|
||
|
||
|
||
|
||
BOOLEAN
|
||
MORE::Initialize (
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initializes the MORE object
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Initialize program object
|
||
//
|
||
if( !PROGRAM::Initialize( MORE_MESSAGE_USAGE, MORE_ERROR_NO_MEMORY, EXIT_ERROR ) ) {
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Initialize whatever needs initialization
|
||
//
|
||
InitializeThings();
|
||
|
||
//
|
||
// Do the argument parsing
|
||
//
|
||
SetArguments();
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
MORE::~MORE (
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Destructs a MORE object
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Deallocate the global structures previously allocated
|
||
//
|
||
DeallocateThings();
|
||
|
||
//
|
||
// Exit without error
|
||
//
|
||
exit( EXIT_NORMAL );
|
||
|
||
}
|
||
|
||
VOID
|
||
MORE::InitializeThings (
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initializes the global variables that need initialization
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
if ( //
|
||
// Initialize the library
|
||
//
|
||
!(_Keyboard = NEW KEYBOARD)
|
||
|
||
|
||
) {
|
||
|
||
exit( EXIT_ERROR );
|
||
|
||
}
|
||
|
||
// MORE translates from MBCS to Unicode according to the
|
||
// current console codepage.
|
||
//
|
||
WSTRING::SetConsoleConversions();
|
||
|
||
if ( //
|
||
// Pager stuff
|
||
//
|
||
!DEFINE_CLASS_DESCRIPTOR( PAGER ) ||
|
||
//
|
||
// Misc. Strings
|
||
//
|
||
((_LineDelimiters = NEW DSTRING) == NULL ) ||
|
||
!_LineDelimiters->Initialize( "\r\n" ) ||
|
||
((_Percent = NEW DSTRING) == NULL ) ||
|
||
((_Line = NEW DSTRING) == NULL ) ||
|
||
((_OtherPrompt = NEW DSTRING) == NULL )
|
||
) {
|
||
|
||
Fatal();
|
||
|
||
}
|
||
|
||
//
|
||
// Get the strings containing valid user options
|
||
//
|
||
if ( (( _Help = QueryMessageString( MORE_HELP )) == NULL ) ||
|
||
(( _DisplayLinesOption = QueryMessageString( MORE_OPTION_DISPLAYLINES )) == NULL ) ||
|
||
(( _SkipLinesOption = QueryMessageString( MORE_OPTION_SKIPLINES )) == NULL ) ||
|
||
(( _NextFileOption = QueryMessageString( MORE_OPTION_NEXTFILE )) == NULL ) ||
|
||
(( _ShowLineNumberOption = QueryMessageString( MORE_OPTION_SHOWLINENUMBER )) == NULL ) ||
|
||
(( _QuitOption = QueryMessageString( MORE_OPTION_QUIT )) == NULL ) ||
|
||
(( _Help1Option = QueryMessageString( MORE_OPTION_HELP1 )) == NULL ) ||
|
||
(( _Help2Option = QueryMessageString( MORE_OPTION_HELP2 )) == NULL ) ) {
|
||
|
||
Fatal();
|
||
}
|
||
|
||
_Keyboard->Initialize();
|
||
_Quit = FALSE;
|
||
_ExtendedModeSwitch = FALSE;
|
||
_ClearScreenSwitch = FALSE;
|
||
_ExpandFormFeedSwitch = FALSE;
|
||
_SqueezeBlanksSwitch = FALSE;
|
||
_HelpSwitch = FALSE;
|
||
_StartAtLine = 0;
|
||
_FilesArgument = NULL;
|
||
|
||
}
|
||
|
||
VOID
|
||
MORE::DeallocateThings (
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Deallocates the global variables that need deallocation
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DELETE( _Keyboard );
|
||
|
||
DELETE( _FilesArgument );
|
||
DELETE( _LineDelimiters );
|
||
DELETE( _Percent );
|
||
DELETE( _Line );
|
||
DELETE( _Help );
|
||
|
||
//
|
||
// Delete the strings containing valid user options
|
||
//
|
||
DELETE( _DisplayLinesOption );
|
||
DELETE( _SkipLinesOption );
|
||
DELETE( _NextFileOption );
|
||
DELETE( _ShowLineNumberOption );
|
||
DELETE( _QuitOption );
|
||
DELETE( _Help1Option );
|
||
DELETE( _Help2Option );
|
||
|
||
}
|
||
|
||
VOID
|
||
MORE::DoPaging (
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Does the paging.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
PPATH Path;
|
||
PITERATOR Iterator;
|
||
BOOLEAN IsFirstFile = TRUE;
|
||
ULONG FilesLeft;
|
||
PFSN_FILE FsnFile;
|
||
PFILE_STREAM FileStream;
|
||
|
||
FilesLeft = _FilesArgument->QueryPathCount();
|
||
|
||
if ( FilesLeft > 0 ) {
|
||
|
||
//
|
||
// We have a list of files, we will page each one in turn
|
||
//
|
||
// Get an iterator for going thru the file list
|
||
//
|
||
if ((Iterator = _FilesArgument->GetPathArray()->QueryIterator()) == NULL ) {
|
||
|
||
Fatal();
|
||
}
|
||
|
||
Path = (PPATH)Iterator->GetNext();
|
||
|
||
//
|
||
// Iterate thru all the files in the array
|
||
//
|
||
while ( Path && !_Quit) {
|
||
|
||
//
|
||
// Get a new stream out of the file name
|
||
//
|
||
if ((FsnFile = SYSTEM::QueryFile( Path )) == NULL ||
|
||
(FileStream = FsnFile->QueryStream( READ_ACCESS )) == NULL ) {
|
||
Fatal( EXIT_ERROR, MORE_ERROR_CANNOT_ACCESS, "%W", Path->GetPathString() );
|
||
}
|
||
|
||
PageStream( FileStream,
|
||
FsnFile,
|
||
IsFirstFile ? _StartAtLine : 0, --FilesLeft );
|
||
|
||
DELETE( FileStream );
|
||
DELETE( FsnFile );
|
||
|
||
Path = (PPATH)Iterator->GetNext();
|
||
IsFirstFile = FALSE;
|
||
}
|
||
|
||
DELETE( Iterator );
|
||
|
||
} else {
|
||
|
||
//
|
||
// The user did'nt specify a file list, so we will page
|
||
// standard input.
|
||
//
|
||
PageStream( GetStandardInput(),
|
||
NULL,
|
||
_StartAtLine,
|
||
0 );
|
||
}
|
||
}
|
||
|
||
VOID
|
||
MORE::PageStream (
|
||
IN PSTREAM Stream,
|
||
IN PFSN_FILE FsnFile,
|
||
IN ULONG FirstLineToDisplay,
|
||
IN ULONG FilesLeft
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Pages a stream
|
||
|
||
Arguments:
|
||
|
||
Stream - Supplies pointer to stream
|
||
FsnFile - Supplies pointer to file object
|
||
FirstLineToDisplay - Supplies first line to display
|
||
FilesLeft - Files remaining to be displayed
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PAGER Pager;
|
||
ULONG LinesToDisplay;
|
||
BOOLEAN ClearScreen;
|
||
BOOLEAN StayInFile;
|
||
|
||
//
|
||
// Initialize the pager
|
||
//
|
||
if (!Pager.Initialize( Stream, this)) {
|
||
|
||
Fatal();
|
||
|
||
}
|
||
|
||
//
|
||
// Skip to the first line to be displayed
|
||
//
|
||
if ( FirstLineToDisplay > 0 ) {
|
||
Pager.SkipLines( FirstLineToDisplay, _TabExp );
|
||
}
|
||
|
||
LinesToDisplay = Pager.QueryLinesPerPage() - 1;
|
||
ClearScreen = _ClearScreenSwitch;
|
||
StayInFile = TRUE;
|
||
|
||
while (StayInFile && Pager.ThereIsMoreToPage() && !_Quit) {
|
||
|
||
// If QueryLinesPerPage() returns 0 then undo the -1 operation.
|
||
|
||
if (LinesToDisplay == (ULONG) -1) {
|
||
LinesToDisplay = 0;
|
||
}
|
||
|
||
//
|
||
// Display a group of lines
|
||
//
|
||
Pager.DisplayPage( LinesToDisplay,
|
||
ClearScreen,
|
||
_SqueezeBlanksSwitch,
|
||
_ExpandFormFeedSwitch,
|
||
_TabExp );
|
||
|
||
//
|
||
// If not at end of stream, we wait for an option
|
||
//
|
||
if (Pager.ThereIsMoreToPage() || (FilesLeft > 0)) {
|
||
|
||
StayInFile = DoOption( FsnFile, &Pager, &LinesToDisplay, &ClearScreen );
|
||
}
|
||
}
|
||
}
|
||
|
||
BOOLEAN
|
||
MORE::DoOption (
|
||
IN PFSN_FILE FsnFile,
|
||
IN PPAGER Pager,
|
||
OUT PULONG LinesInPage,
|
||
OUT PBOOLEAN ClearScreen
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Gets an option from the user
|
||
|
||
Arguments:
|
||
|
||
FsnFile - Supplies pointer to file object
|
||
Pager - Supplies pointer to pager
|
||
LinesInpage - Supplies pointer to lines to display in next page
|
||
ClearScreen - Supplies pointer to Clearscreen flag.
|
||
|
||
Return Value:
|
||
|
||
TRUE if paging should continue for this file,
|
||
FALSE otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
WCHAR Char;
|
||
DSTRING String;
|
||
BOOLEAN ShowLineNumber = FALSE;
|
||
BOOLEAN ShowHelp = FALSE;
|
||
LONG Number;
|
||
|
||
|
||
String.Initialize( " " );
|
||
|
||
while ( TRUE ) {
|
||
|
||
//
|
||
// Display prompt
|
||
//
|
||
Prompt( FsnFile, Pager, ShowLineNumber, ShowHelp, 0 );
|
||
|
||
ShowHelp = FALSE;
|
||
ShowLineNumber = FALSE;
|
||
|
||
//
|
||
// Get option from the user
|
||
//
|
||
_Keyboard->DisableLineMode();
|
||
_Keyboard->ReadChar( &Char );
|
||
_Keyboard->EnableLineMode();
|
||
String.SetChAt(Char, 0);
|
||
String.Strupr();
|
||
Pager->ClearLine();
|
||
|
||
//
|
||
// If Ctl-C, get out
|
||
//
|
||
if ( Char == CTRLC_CHARACTER ) {
|
||
|
||
_Keyboard->EnableLineMode();
|
||
GenerateConsoleCtrlEvent( CTRL_C_EVENT, 0 );
|
||
_Quit = TRUE;
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
//
|
||
// If not in extended mode, any key just advances one page
|
||
//
|
||
if ( !_ExtendedModeSwitch ) {
|
||
*LinesInPage = Pager->QueryLinesPerPage() - 1;
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
//
|
||
// Now take the proper action
|
||
//
|
||
if ( String.QueryChAt(0) == (WCHAR)CARRIAGERETURN ) {
|
||
|
||
//
|
||
// Display next line of the file
|
||
//
|
||
*LinesInPage = 1;
|
||
*ClearScreen = FALSE;
|
||
return TRUE;
|
||
|
||
} else if ( String.QueryChAt(0) == (WCHAR)' ' ) {
|
||
|
||
//
|
||
// Display next page
|
||
//
|
||
*ClearScreen = _ClearScreenSwitch;
|
||
*LinesInPage = Pager->QueryLinesPerPage() - 1;
|
||
return TRUE;
|
||
|
||
} else if ( String.Stricmp(_DisplayLinesOption) == 0 ) {
|
||
|
||
//
|
||
// Display a certain number of lines. Get the number of lines
|
||
// to display
|
||
//
|
||
Prompt( FsnFile, Pager, ShowLineNumber, ShowHelp, MORE_LINEPROMPT );
|
||
|
||
|
||
*LinesInPage = ReadNumber();
|
||
|
||
//if ( ReadLine( _Keyboard, &String ) &&
|
||
// String.QueryNumber((PLONG)LinesInPage) ) {
|
||
//
|
||
// (*LinesInPage)--;
|
||
//
|
||
//} else {
|
||
// *LinesInPage = 0;
|
||
//}
|
||
|
||
Pager->ClearLine();
|
||
|
||
*ClearScreen = FALSE;
|
||
return TRUE;
|
||
|
||
} else if ( String.Stricmp(_SkipLinesOption) == 0 ) {
|
||
|
||
//
|
||
// Skip a certain number of lines and then display a page.
|
||
//
|
||
Prompt( FsnFile, Pager, ShowLineNumber, ShowHelp, MORE_LINEPROMPT );
|
||
|
||
Number = ReadNumber( );
|
||
if ( Number ) {
|
||
Pager->SkipLines( Number, _TabExp );
|
||
}
|
||
|
||
Pager->ClearLine();
|
||
|
||
*LinesInPage = Pager->QueryLinesPerPage() - 1;
|
||
return TRUE;
|
||
|
||
} else if ( String.Stricmp(_NextFileOption) == 0 ) {
|
||
|
||
//
|
||
// Stop paging this file
|
||
//
|
||
return FALSE;
|
||
|
||
} else if ( String.Stricmp(_QuitOption) == 0 ) {
|
||
|
||
//
|
||
// Quit the program
|
||
//
|
||
_Quit = TRUE;
|
||
return FALSE;
|
||
|
||
} else if ( String.Stricmp(_ShowLineNumberOption) == 0) {
|
||
|
||
//
|
||
// Prompt again, showing the line number within the file
|
||
//
|
||
ShowLineNumber = TRUE;
|
||
|
||
} else if ( ( String.Stricmp(_Help1Option) == 0) ||
|
||
( String.Stricmp(_Help2Option) == 0)) {
|
||
|
||
//
|
||
// Prompt again, showing a message line
|
||
//
|
||
ShowHelp = TRUE;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
VOID
|
||
MORE::Prompt (
|
||
IN PFSN_FILE FsnFile,
|
||
IN PPAGER Pager,
|
||
IN BOOLEAN ShowLineNumber,
|
||
IN BOOLEAN ShowHelp,
|
||
IN MSGID OtherMsgId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Displays prompt. The prompt consists of a "base" prompt (e.g.
|
||
"-- More --" plus various optional strings:
|
||
|
||
- Percentage of the file displayed so far.
|
||
- Line number within the file
|
||
- Help
|
||
- Other (e.g prompt for a number )
|
||
|
||
|
||
Arguments:
|
||
|
||
FsnFile - Supplies pointer to file object
|
||
Pager - Supplies pointer to pager
|
||
ShowLineNumber - Supplies flag which if TRUE causes the current
|
||
line numnber to be displayed
|
||
HelpMsg - Supplies flag which if TRUE causes a brief help
|
||
to be displayed
|
||
|
||
OtherMsg - Supplies MsgId of any other string to be displayed
|
||
|
||
Return Value:
|
||
|
||
none
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
CHAR NullBuffer = NULL_CHARACTER;
|
||
PVOID PercentMsg;
|
||
PVOID LineMsg;
|
||
PVOID HelpMsg;
|
||
PVOID OtherMsg;
|
||
|
||
//
|
||
// Obtain all the strings that form part of the prompt
|
||
//
|
||
if ( FsnFile != NULL ) {
|
||
SYSTEM::QueryResourceString( _Percent, MORE_PERCENT, "%d", Pager->QueryCurrentByte() * 100 / FsnFile->QuerySize());
|
||
_Percent->QuerySTR( 0, TO_END, (PSTR)_StringBuffer0, STRING_BUFFER_SIZE);
|
||
PercentMsg = (PVOID)_StringBuffer0;
|
||
} else {
|
||
PercentMsg = (PVOID)&NullBuffer;
|
||
}
|
||
|
||
if (ShowLineNumber) {
|
||
SYSTEM::QueryResourceString( _Line, MORE_LINE, "%d", Pager->QueryCurrentLine());
|
||
_Line->QuerySTR( 0, TO_END, (PSTR)_StringBuffer1, STRING_BUFFER_SIZE);
|
||
LineMsg = (PVOID)_StringBuffer1;
|
||
} else {
|
||
LineMsg = (PVOID)&NullBuffer;
|
||
}
|
||
|
||
if (ShowHelp) {
|
||
_Help->QuerySTR(0, TO_END, (PSTR)_StringBuffer2, STRING_BUFFER_SIZE);
|
||
HelpMsg = (PVOID)_StringBuffer2;
|
||
} else {
|
||
HelpMsg = (PVOID)&NullBuffer;
|
||
}
|
||
|
||
if (OtherMsgId != 0) {
|
||
SYSTEM::QueryResourceString( _OtherPrompt, OtherMsgId, "" );
|
||
_OtherPrompt->QuerySTR(0, TO_END, (PSTR)_StringBuffer3, STRING_BUFFER_SIZE);
|
||
OtherMsg = (PVOID)_StringBuffer3;
|
||
} else {
|
||
OtherMsg = (PVOID)&NullBuffer;
|
||
}
|
||
|
||
//
|
||
// Now display the prompt
|
||
//
|
||
DisplayMessage( MORE_PROMPT, NORMAL_MESSAGE, "%s%s%s%s", PercentMsg, LineMsg, HelpMsg, OtherMsg );
|
||
}
|
||
|
||
PWSTRING
|
||
MORE::QueryMessageString (
|
||
IN MSGID MsgId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Obtains a string object initialized to the contents of some message
|
||
|
||
Arguments:
|
||
|
||
MsgId - Supplies ID of the message
|
||
|
||
Return Value:
|
||
|
||
Pointer to initialized string object
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PWSTRING String;
|
||
|
||
if ( ((String = NEW DSTRING) == NULL ) ||
|
||
!(SYSTEM::QueryResourceString( String, MsgId, "" )) ) {
|
||
|
||
DELETE( String );
|
||
String = NULL;
|
||
}
|
||
|
||
return String;
|
||
|
||
}
|
||
|
||
ULONG
|
||
MORE::ReadNumber (
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads a number from the keyboard.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
Number read
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
DSTRING NumberString;
|
||
DSTRING CharString;
|
||
PSTREAM StandardOut;
|
||
ULONG Number = 0;
|
||
LONG LongNumber;
|
||
WCHAR Char;
|
||
BOOLEAN Done = FALSE;
|
||
ULONG DigitCount = 0;
|
||
|
||
StandardOut = GetStandardOutput();
|
||
|
||
NumberString.Initialize( "" );
|
||
CharString.Initialize( " " );
|
||
|
||
while ( !Done ) {
|
||
|
||
_Keyboard->DisableLineMode();
|
||
_Keyboard->ReadChar( &Char );
|
||
_Keyboard->EnableLineMode();
|
||
|
||
switch ( Char ) {
|
||
|
||
case '0':
|
||
case '1':
|
||
case '2':
|
||
case '3':
|
||
case '4':
|
||
case '5':
|
||
case '6':
|
||
case '7':
|
||
case '8':
|
||
case '9':
|
||
CharString.SetChAt( Char, 0 );
|
||
NumberString.Strcat( &CharString );
|
||
StandardOut->WriteChar( Char );
|
||
DigitCount++;
|
||
break;
|
||
|
||
case '\b':
|
||
if ( DigitCount > 0 ) {
|
||
NumberString.Truncate( NumberString.QueryChCount() - 1 );
|
||
StandardOut->WriteChar( Char );
|
||
StandardOut->WriteChar( ' ' );
|
||
StandardOut->WriteChar( Char );
|
||
DigitCount--;
|
||
}
|
||
break;
|
||
|
||
|
||
case '\r':
|
||
case '\n':
|
||
Done = TRUE;
|
||
break;
|
||
|
||
case CTRLC_CHARACTER:
|
||
_Quit = TRUE;
|
||
Done = TRUE;
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
|
||
|
||
}
|
||
}
|
||
|
||
if ( NumberString.QueryChCount() > 0 ) {
|
||
|
||
if ( NumberString.QueryNumber( &LongNumber ) ) {
|
||
|
||
Number = (ULONG)LongNumber;
|
||
}
|
||
}
|
||
|
||
return Number;
|
||
}
|