mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
315 lines
8.5 KiB
315 lines
8.5 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sort.cxx
|
|
|
|
Abstract:
|
|
|
|
This module contains the implentation of the sort utility
|
|
(Dos 5.0 compatible).
|
|
It sorts the input and writes the results to the screen, a file, or
|
|
another device.
|
|
|
|
SORT [/R] [/+n] [/?] < [drive1:][path1]filename1 [> [drive2:][path2]filename2]
|
|
[command |] SORT [/R] [/+n] [> [drive2:][path2]filename2]
|
|
|
|
/? Displays a help message.
|
|
/R Reverses the sort order; that is, sorts Z to A,
|
|
then 9 to 0.
|
|
/+n Sorts the file according to characters in
|
|
column n.
|
|
[drive1:][path1]filename1 Specifies a file to be sorted.
|
|
[drive2:][path2]filename2 Specifies a file where the sorted input is to be
|
|
stored.
|
|
command Specifies a comman whose output is to be sorted.
|
|
|
|
|
|
Author:
|
|
|
|
Jaime F. Sasson
|
|
|
|
Environment:
|
|
|
|
ULIB, User Mode
|
|
|
|
--*/
|
|
|
|
#include "ulib.hxx"
|
|
#include "ulibcl.hxx"
|
|
#include "stream.hxx"
|
|
#include "error.hxx"
|
|
#include "arg.hxx"
|
|
#include "wstring.hxx"
|
|
#include "substrng.hxx"
|
|
#include "array.hxx"
|
|
#include "arrayit.hxx"
|
|
#include "smsg.hxx"
|
|
#include "rtmsg.h"
|
|
#include "stringar.hxx"
|
|
#include "sort.hxx"
|
|
|
|
extern "C" {
|
|
#include <stdio.h>
|
|
}
|
|
|
|
|
|
ERRSTACK* perrstk;
|
|
|
|
|
|
DEFINE_CONSTRUCTOR( SORT, PROGRAM );
|
|
|
|
|
|
BOOLEAN
|
|
SORT::Initialize(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes a SORT object.
|
|
The initialization consists of:
|
|
.Initialization of STREAM_MESSAGE object;
|
|
.Parse the command line;
|
|
.Display the help message if the argument /? was present in the
|
|
command line;
|
|
.Initialize the flag that indicates if the sort is to be performed
|
|
in ascending or descending order;
|
|
.Initialize the variable that indicates the position in the string
|
|
that is to be sorted.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - Returns TRUE if the initialization succeeded and the sort
|
|
is to be performed. Returns FALSE otherwise (invalid argument,
|
|
or /? found in the command line)
|
|
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
ARGUMENT_LEXEMIZER ArgLex;
|
|
ARRAY LexArray;
|
|
ARRAY ArgumentArray;
|
|
STRING_ARGUMENT ProgramNameArgument;
|
|
FLAG_ARGUMENT FlagReverseSortOrder;
|
|
LONG_ARGUMENT Column;
|
|
FLAG_ARGUMENT FlagDisplayHelp;
|
|
|
|
|
|
_Standard_Output_Stream = Get_Standard_Output_Stream();
|
|
_Standard_Input_Stream = Get_Standard_Input_Stream();
|
|
_Standard_Error_Stream = Get_Standard_Error_Stream();
|
|
|
|
if (NULL == (_Message = NEW STREAM_MESSAGE)) {
|
|
DebugAbort( "Operator new failed.\n" );
|
|
return( FALSE );
|
|
}
|
|
|
|
_Message->Initialize( _Standard_Output_Stream, _Standard_Input_Stream,
|
|
_Standard_Error_Stream );
|
|
|
|
if ( !LexArray.Initialize( ) ) {
|
|
DebugAbort( "LexArray.Initialize() failed \n" );
|
|
return( FALSE );
|
|
}
|
|
if ( !ArgLex.Initialize( &LexArray ) ) {
|
|
DebugAbort( "ArgLex.Initialize() failed \n" );
|
|
return( FALSE );
|
|
}
|
|
ArgLex.PutSwitches( "/" );
|
|
ArgLex.SetCaseSensitive( FALSE );
|
|
if( !ArgLex.PrepareToParse() ) {
|
|
DebugAbort( "ArgLex.PrepareToParse() failed \n" );
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( !ArgumentArray.Initialize() ) {
|
|
DebugAbort( "ArgumentArray.Initialize() failed \n" );
|
|
return( FALSE );
|
|
}
|
|
if( !ProgramNameArgument.Initialize("*") ||
|
|
!FlagReverseSortOrder.Initialize( "/R" ) ||
|
|
!Column.Initialize( "/+*" ) ||
|
|
!FlagDisplayHelp.Initialize( "/?" )) {
|
|
DebugAbort( "Unable to initialize flag or string arguments \n" );
|
|
return( FALSE );
|
|
}
|
|
if( !ArgumentArray.Put( &ProgramNameArgument ) ||
|
|
!ArgumentArray.Put( &FlagReverseSortOrder ) ||
|
|
!ArgumentArray.Put( &Column ) ||
|
|
!ArgumentArray.Put( &FlagDisplayHelp ) ) {
|
|
DebugAbort( "ArgumentArray.Put() failed \n" );
|
|
return( FALSE );
|
|
}
|
|
if( !ArgLex.DoParsing( &ArgumentArray ) ) {
|
|
_Message->Set( MSG_SORT_INVALID_SWITCH, ERROR_MESSAGE );
|
|
_Message->Display( " " );
|
|
return( FALSE );
|
|
}
|
|
if( FlagDisplayHelp.QueryFlag() ) {
|
|
_Message->Set( MSG_SORT_HELP_MESSAGE );
|
|
_Message->Display( " " );
|
|
return( FALSE );
|
|
}
|
|
|
|
_AscendingOrder = !FlagReverseSortOrder.QueryFlag();
|
|
_Position = ( Column.IsValueSet() ) ? Column.QueryLong() : 1;
|
|
if( _Position <= 0 ) {
|
|
_Message->Set( MSG_SORT_VALUE_NOT_IN_RANGE, ERROR_MESSAGE );
|
|
_Message->Display( " " );
|
|
return( FALSE );
|
|
}
|
|
if( !_EndOfLineString.Initialize( (LPWSTR)L"\r\n" ) ) {
|
|
DebugPrint( "_EndOfLineString.Initialize() failed" );
|
|
return( FALSE );
|
|
}
|
|
_Position--;
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
SORT::ReadSortAndWriteStrings(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sorts and displays all strings read from standard input.
|
|
The following steps are executed:
|
|
.initialize the array that will contain the strings to be sorted;
|
|
.read all the strings from standard input and save the in the
|
|
array;
|
|
.sort the strings;
|
|
.write them to the standard output.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - return always TRUE.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSTRING String;
|
|
PWSTRING StringToWrite;
|
|
WCHAR Wchar;
|
|
PITERATOR Iterator;
|
|
STRING_ARRAY StringArray;
|
|
CHNUM Length;
|
|
CHNUM l;
|
|
|
|
if( !StringArray.Initialize( _Position ) ) {
|
|
DebugAbort( "ArgumentArray.Put() failed \n" );
|
|
return( FALSE );
|
|
}
|
|
while( !_Standard_Input_Stream->IsAtEnd() ) {
|
|
if( ( String = NEW( DSTRING ) ) == NULL || !String->Initialize( "" ) ) {
|
|
_Message->Set( MSG_INSUFFICIENT_MEMORY, ERROR_MESSAGE );
|
|
_Message->Display();
|
|
DebugAbort( "String->Initialize() failed \n" );
|
|
return( FALSE );
|
|
}
|
|
if( !_Standard_Input_Stream->ReadLine( String ) ) {
|
|
DELETE( String );
|
|
_Message->Set( MSG_INSUFFICIENT_MEMORY, ERROR_MESSAGE );
|
|
_Message->Display();
|
|
DebugAbort( "ReadString() failed \n" );
|
|
return( FALSE );
|
|
}
|
|
|
|
// Don't count a null string if IsAtEnd is true
|
|
// to handle ^Z properly on input.
|
|
|
|
if (String->QueryChCount() == 0 &&
|
|
_Standard_Input_Stream->IsAtEnd()) {
|
|
|
|
break;
|
|
}
|
|
|
|
// If there's a ^Z in this string then we need to
|
|
// make this the end of input, regardless of whether
|
|
// or not there's more stuff left in the file.
|
|
|
|
l = String->Strchr(0x1A);
|
|
if (l != INVALID_CHNUM) {
|
|
String->Truncate(l);
|
|
|
|
if (l != 0) {
|
|
if (!StringArray.Put(String)) {
|
|
_Message->Set( MSG_INSUFFICIENT_MEMORY, ERROR_MESSAGE );
|
|
_Message->Display();
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if( StringArray.Put( String ) == NULL ) {
|
|
|
|
_Message->Set( MSG_INSUFFICIENT_MEMORY, ERROR_MESSAGE );
|
|
_Message->Display();
|
|
|
|
DebugAbort( "StringArray.Put() failed \n" );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
if( !StringArray.Sort( _AscendingOrder ) ) {
|
|
DebugAbort( "StringArray.Sort() failed \n" );
|
|
return( FALSE );
|
|
}
|
|
if( ( Iterator = StringArray.QueryIterator() ) == NULL ) {
|
|
DebugAbort( "StringArray.QueryIterator() failed \n" );
|
|
_Message->Set( MSG_INSUFFICIENT_MEMORY, ERROR_MESSAGE );
|
|
_Message->Display();
|
|
return( FALSE );
|
|
}
|
|
while( ( StringToWrite = ( PWSTRING )Iterator->GetNext() ) != NULL ) {
|
|
StringToWrite->Strcat( &_EndOfLineString );
|
|
Length = StringToWrite->QueryChCount();
|
|
if( !_Standard_Output_Stream->WriteString( StringToWrite, 0, Length ) ) {
|
|
DebugAbort( "_Standard_Output_Stream->WriteString() failed \n" );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
DELETE( Iterator );
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
ULONG _CRTAPI1
|
|
main()
|
|
|
|
{
|
|
DEFINE_CLASS_DESCRIPTOR( SORT );
|
|
|
|
{
|
|
SORT Sort;
|
|
|
|
perrstk = NEW ERRSTACK;
|
|
|
|
if( Sort.Initialize() ) {
|
|
Sort.ReadSortAndWriteStrings();
|
|
}
|
|
DELETE( perrstk );
|
|
}
|
|
return( 0 );
|
|
}
|