427 lines
13 KiB
C++
427 lines
13 KiB
C++
/*++
|
||
|
||
Copyright (c) 1991-2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
print.cxx
|
||
|
||
Abstract:
|
||
|
||
|
||
Author:
|
||
|
||
Jaime F. Sasson - jaimes - 14-Jun-1991
|
||
|
||
Environment:
|
||
|
||
ULIB, User Mode
|
||
|
||
--*/
|
||
|
||
#include "ulib.hxx"
|
||
#include "arg.hxx"
|
||
#include "path.hxx"
|
||
#include "wstring.hxx"
|
||
#include "system.hxx"
|
||
#include "array.hxx"
|
||
#include "arrayit.hxx"
|
||
#include "smsg.hxx"
|
||
#include "stream.hxx"
|
||
#include "rtmsg.h"
|
||
#include "prtstrm.hxx"
|
||
#include "file.hxx"
|
||
#include "print.hxx"
|
||
|
||
extern "C" {
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
}
|
||
|
||
PSTREAM Get_Standard_Input_Stream();
|
||
PSTREAM Get_Standard_Output_Stream();
|
||
|
||
DEFINE_CONSTRUCTOR( PRINT, PROGRAM );
|
||
|
||
|
||
BOOLEAN
|
||
PRINT::Initialize(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initializes a PRINT class.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - Indicates if the initialization succeeded.
|
||
|
||
|
||
--*/
|
||
|
||
|
||
{
|
||
ARGUMENT_LEXEMIZER ArgLex;
|
||
ARRAY LexArray;
|
||
|
||
ARRAY ArgumentArray;
|
||
FLAG_ARGUMENT FlagDisplayHelp;
|
||
|
||
STRING_ARGUMENT ProgramNameArgument;
|
||
PWSTRING InvalidArgument;
|
||
|
||
PATH_ARGUMENT DeviceArgument;
|
||
PPATH DevicePath;
|
||
PCWSTRING DeviceString;
|
||
PPATH FilePath;
|
||
PCWSTRING FileString;
|
||
PARRAY PathArray;
|
||
PARRAY_ITERATOR PathArrayIterator;
|
||
PFSN_FILE FsnFile;
|
||
|
||
|
||
_StandardOutput = Get_Standard_Output_Stream();
|
||
|
||
if (_StandardOutput == NULL) {
|
||
DebugPrint("PRINT: Out of memory\n");
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Initialize MESSAGE class
|
||
//
|
||
_Message.Initialize( _StandardOutput, Get_Standard_Input_Stream() );
|
||
|
||
//
|
||
// Parse command line
|
||
//
|
||
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 );
|
||
ArgLex.PutStartQuotes( "\"" );
|
||
ArgLex.PutEndQuotes( "\"" );
|
||
|
||
if( !ArgLex.PrepareToParse() ) {
|
||
DebugAbort( "ArgLex.PrepareToParse() failed \n" );
|
||
return( FALSE );
|
||
}
|
||
if ( !ArgumentArray.Initialize() ) {
|
||
DebugAbort( "ArgumentArray.Initialize() failed \n" );
|
||
return( FALSE );
|
||
}
|
||
if( !ProgramNameArgument.Initialize("*") ||
|
||
!DeviceArgument.Initialize( "/D:*" ) ||
|
||
!_BufferSize.Initialize( "/B:*" ) ||
|
||
!_Ticks1.Initialize( "/U:*" ) ||
|
||
!_Ticks2.Initialize( "/M:*" ) ||
|
||
!_Ticks3.Initialize( "/S:*" ) ||
|
||
!_NumberOfFiles.Initialize( "/Q:*" ) ||
|
||
!_FlagRemoveFiles.Initialize( "/T" ) ||
|
||
!_Files.Initialize( "*", FALSE, TRUE ) ||
|
||
!_FlagCancelPrinting.Initialize( "/C" ) ||
|
||
!_FlagAddFiles.Initialize( "/P" ) ||
|
||
!FlagDisplayHelp.Initialize( "/?" ) ) {
|
||
DebugAbort( "Unable to initialize flag or string arguments \n" );
|
||
return( FALSE );
|
||
}
|
||
if( !ArgumentArray.Put( &ProgramNameArgument ) ||
|
||
!ArgumentArray.Put( &DeviceArgument ) ||
|
||
!ArgumentArray.Put( &_BufferSize ) ||
|
||
!ArgumentArray.Put( &_Ticks1 ) ||
|
||
!ArgumentArray.Put( &_Ticks2 ) ||
|
||
!ArgumentArray.Put( &_Ticks3 ) ||
|
||
!ArgumentArray.Put( &_NumberOfFiles ) ||
|
||
!ArgumentArray.Put( &_FlagRemoveFiles ) ||
|
||
!ArgumentArray.Put( &_Files ) ||
|
||
!ArgumentArray.Put( &_FlagCancelPrinting ) ||
|
||
!ArgumentArray.Put( &_FlagAddFiles ) ||
|
||
!ArgumentArray.Put( &FlagDisplayHelp ) ) {
|
||
DebugAbort( "ArgumentArray.Put() failed \n" );
|
||
return( FALSE );
|
||
}
|
||
if( !ArgLex.DoParsing( &ArgumentArray ) ) {
|
||
InvalidArgument = ArgLex.QueryInvalidArgument();
|
||
DebugPtrAssert( InvalidArgument );
|
||
_Message.Set( MSG_PRINT_INVALID_SWITCH );
|
||
_Message.Display( "%W", InvalidArgument );
|
||
return( FALSE );
|
||
}
|
||
|
||
//
|
||
// /B: /U: /M: /S: /Q: /T: /C: and /P: are not implemented
|
||
// if one of these arguments was found in the command line
|
||
// then inform user, and don't print anything
|
||
//
|
||
if( _BufferSize.IsValueSet() ) {
|
||
_Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
|
||
_Message.Display( "%s", "/B:" );
|
||
return( FALSE );
|
||
}
|
||
if( _Ticks1.IsValueSet() ) {
|
||
_Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
|
||
_Message.Display( "%s", "/U:" );
|
||
return( FALSE );
|
||
}
|
||
if( _Ticks2.IsValueSet() ) {
|
||
_Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
|
||
_Message.Display( "%s", "/M:" );
|
||
return( FALSE );
|
||
}
|
||
if( _Ticks3.IsValueSet() ) {
|
||
_Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
|
||
_Message.Display( "%s", "/S:" );
|
||
return( FALSE );
|
||
}
|
||
if( _NumberOfFiles.IsValueSet() ) {
|
||
_Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
|
||
_Message.Display( "%s", "/Q:" );
|
||
return( FALSE );
|
||
}
|
||
if( _FlagRemoveFiles.IsValueSet() ) {
|
||
_Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
|
||
_Message.Display( "%s", "/T:" );
|
||
return( FALSE );
|
||
}
|
||
if( _FlagCancelPrinting.IsValueSet() ) {
|
||
_Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
|
||
_Message.Display( "%s", "/C:" );
|
||
return( FALSE );
|
||
}
|
||
if( _FlagAddFiles.IsValueSet() ) {
|
||
_Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
|
||
_Message.Display( "%s", "/P:" );
|
||
return( FALSE );
|
||
}
|
||
|
||
//
|
||
// Displays help message if /? was found in the command line
|
||
//
|
||
if( FlagDisplayHelp.QueryFlag() ) {
|
||
_Message.Set( MSG_PRINT_HELP_MESSAGE );
|
||
_Message.Display( " " );
|
||
return( FALSE );
|
||
}
|
||
|
||
//
|
||
// If no filename was specified, display error message
|
||
//
|
||
if( _Files.QueryPathCount() == 0 ) {
|
||
_Message.Set( MSG_PRINT_NO_FILE );
|
||
_Message.Display( " " );
|
||
return( FALSE );
|
||
}
|
||
|
||
//
|
||
// Get device name if one exists. Otherwise use PRN as default
|
||
//
|
||
if( !DeviceArgument.IsValueSet() ) {
|
||
DevicePath = NEW( PATH );
|
||
DebugPtrAssert( DevicePath );
|
||
if( !DevicePath->Initialize( (LPWSTR)L"PRN" ) ) {
|
||
_Message.Set( MSG_PRINT_UNABLE_INIT_DEVICE );
|
||
_Message.Display( "%s", "PRN" );
|
||
return( FALSE );
|
||
}
|
||
} else {
|
||
DevicePath = DeviceArgument.GetPath();
|
||
DebugPtrAssert( DevicePath );
|
||
}
|
||
if( !_Printer.Initialize( DevicePath ) ) {
|
||
DeviceString = DevicePath->GetPathString();
|
||
DebugPtrAssert( DeviceString );
|
||
_Message.Set( MSG_PRINT_UNABLE_INIT_DEVICE );
|
||
_Message.Display( "%W", DeviceString );
|
||
if( !DeviceArgument.IsValueSet() ) {
|
||
DELETE( DevicePath );
|
||
}
|
||
return( FALSE );
|
||
}
|
||
|
||
//
|
||
// Get FSNODE of each file and put them in an array
|
||
//
|
||
PathArray = _Files.GetPathArray();
|
||
DebugPtrAssert( PathArray );
|
||
PathArrayIterator = ( PARRAY_ITERATOR )PathArray->QueryIterator();
|
||
DebugPtrAssert( PathArrayIterator );
|
||
|
||
if( !_FsnFileArray.Initialize() ) {
|
||
DebugAbort( "_FsnFileArray.Initialize() failed \n" );
|
||
return( FALSE );
|
||
}
|
||
while( ( FilePath = ( PPATH )PathArrayIterator->GetNext() ) != NULL ) {
|
||
FsnFile = SYSTEM::QueryFile( FilePath );
|
||
if( FsnFile != NULL ) {
|
||
_FsnFileArray.Put( ( POBJECT )FsnFile );
|
||
} else {
|
||
FileString = FilePath->GetPathString();
|
||
_Message.Set( MSG_PRINT_FILE_NOT_FOUND );
|
||
_Message.Display( "%W", FileString );
|
||
}
|
||
}
|
||
DELETE( PathArrayIterator );
|
||
return( TRUE );
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
PRINT::PrintFiles(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Prints the files specified by the user.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - TRUE if all files were printed.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PFSN_FILE FsnFile;
|
||
PSTREAM FileStream;
|
||
PARRAY_ITERATOR ArrayIterator;
|
||
PBYTE Buffer;
|
||
ULONG Size;
|
||
ULONG BytesRead;
|
||
ULONG BytesWritten;
|
||
PCPATH FilePath;
|
||
PCWSTRING FileName;
|
||
INT _BufferStreamType;
|
||
INT BytesConverted;
|
||
INT cbStuff;
|
||
LPSTR lpStuffANSI;
|
||
BOOL fUsedDefault;
|
||
|
||
|
||
Size = 512;
|
||
Buffer = ( PBYTE )MALLOC( ( size_t )Size );
|
||
lpStuffANSI = ( LPSTR )MALLOC( ( size_t )Size );
|
||
if (Buffer == NULL || lpStuffANSI == NULL) {
|
||
DebugPrint("PRINT: Out of memory\n");
|
||
return FALSE;
|
||
}
|
||
ArrayIterator = ( PARRAY_ITERATOR )_FsnFileArray.QueryIterator();
|
||
if (ArrayIterator == NULL) {
|
||
DebugPrint("PRINT: ArrayIterator equals NULL\n");
|
||
return FALSE;
|
||
}
|
||
while( ( FsnFile = ( PFSN_FILE )ArrayIterator->GetNext() ) != NULL ) {
|
||
FileStream = ( PSTREAM )FsnFile->QueryStream( READ_ACCESS );
|
||
if (FileStream == NULL) {
|
||
DebugPrint("PRINT: FileStream equals NULL\n");
|
||
return FALSE;
|
||
}
|
||
|
||
FileName = FsnFile->GetPath()->GetPathString();
|
||
if( FileName != NULL ) {
|
||
_Message.Set( MSG_PRINT_PRINTING );
|
||
_Message.Display( "%W", FileName );
|
||
}
|
||
|
||
_BufferStreamType = -1;
|
||
while( !FileStream->IsAtEnd() ) {
|
||
FileStream->Read( Buffer, Size, &BytesRead );
|
||
// is file unicode?
|
||
if (_BufferStreamType < 0) {
|
||
if (IsTextUnicode((LPTSTR)Buffer, (INT)BytesRead,
|
||
NULL) ) {
|
||
_BufferStreamType = 1;
|
||
} else {
|
||
_BufferStreamType = 0;
|
||
}
|
||
}
|
||
// does the buffer need to be converted?
|
||
if (_BufferStreamType == 1) {
|
||
|
||
cbStuff = Size;
|
||
BytesConverted = WideCharToMultiByte(CP_ACP,0,
|
||
(LPTSTR)Buffer,BytesRead/sizeof(WCHAR),
|
||
lpStuffANSI,cbStuff,NULL,&fUsedDefault) ;
|
||
DebugAssert(cbStuff>0);
|
||
DebugAssert(BytesConverted >= 0);
|
||
_Printer.Write((PBYTE)lpStuffANSI,BytesConverted,&BytesWritten );
|
||
} else {
|
||
_Printer.Write( Buffer, BytesRead, &BytesWritten );
|
||
}
|
||
}
|
||
_Printer.WriteByte( '\f' );
|
||
DELETE( FileStream );
|
||
}
|
||
DELETE( ArrayIterator );
|
||
return( TRUE );
|
||
}
|
||
|
||
|
||
|
||
|
||
BOOL
|
||
PRINT::Terminate(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Deletes objects created during initialization.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
return( TRUE );
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
ULONG __cdecl
|
||
main()
|
||
|
||
{
|
||
DEFINE_CLASS_DESCRIPTOR( PRINT );
|
||
|
||
|
||
{
|
||
|
||
PRINT Print;
|
||
|
||
|
||
if( Print.Initialize() ) {
|
||
Print.PrintFiles();
|
||
}
|
||
// Print.Terminate();
|
||
return( 0 );
|
||
}
|
||
}
|