Source code of Windows XP (NT5)
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.

426 lines
13 KiB

  1. /*++
  2. Copyright (c) 1991-2000 Microsoft Corporation
  3. Module Name:
  4. print.cxx
  5. Abstract:
  6. Author:
  7. Jaime F. Sasson - jaimes - 14-Jun-1991
  8. Environment:
  9. ULIB, User Mode
  10. --*/
  11. #include "ulib.hxx"
  12. #include "arg.hxx"
  13. #include "path.hxx"
  14. #include "wstring.hxx"
  15. #include "system.hxx"
  16. #include "array.hxx"
  17. #include "arrayit.hxx"
  18. #include "smsg.hxx"
  19. #include "stream.hxx"
  20. #include "rtmsg.h"
  21. #include "prtstrm.hxx"
  22. #include "file.hxx"
  23. #include "print.hxx"
  24. extern "C" {
  25. #include <stdio.h>
  26. #include <string.h>
  27. }
  28. PSTREAM Get_Standard_Input_Stream();
  29. PSTREAM Get_Standard_Output_Stream();
  30. DEFINE_CONSTRUCTOR( PRINT, PROGRAM );
  31. BOOLEAN
  32. PRINT::Initialize(
  33. )
  34. /*++
  35. Routine Description:
  36. Initializes a PRINT class.
  37. Arguments:
  38. None.
  39. Return Value:
  40. BOOLEAN - Indicates if the initialization succeeded.
  41. --*/
  42. {
  43. ARGUMENT_LEXEMIZER ArgLex;
  44. ARRAY LexArray;
  45. ARRAY ArgumentArray;
  46. FLAG_ARGUMENT FlagDisplayHelp;
  47. STRING_ARGUMENT ProgramNameArgument;
  48. PWSTRING InvalidArgument;
  49. PATH_ARGUMENT DeviceArgument;
  50. PPATH DevicePath;
  51. PCWSTRING DeviceString;
  52. PPATH FilePath;
  53. PCWSTRING FileString;
  54. PARRAY PathArray;
  55. PARRAY_ITERATOR PathArrayIterator;
  56. PFSN_FILE FsnFile;
  57. _StandardOutput = Get_Standard_Output_Stream();
  58. if (_StandardOutput == NULL) {
  59. DebugPrint("PRINT: Out of memory\n");
  60. return FALSE;
  61. }
  62. //
  63. // Initialize MESSAGE class
  64. //
  65. _Message.Initialize( _StandardOutput, Get_Standard_Input_Stream() );
  66. //
  67. // Parse command line
  68. //
  69. if ( !LexArray.Initialize() ) {
  70. DebugAbort( "LexArray.Initialize() failed \n" );
  71. return( FALSE );
  72. }
  73. if ( !ArgLex.Initialize( &LexArray ) ) {
  74. DebugAbort( "ArgLex.Initialize() failed \n" );
  75. return( FALSE );
  76. }
  77. ArgLex.PutSwitches( "/" );
  78. ArgLex.SetCaseSensitive( FALSE );
  79. ArgLex.PutStartQuotes( "\"" );
  80. ArgLex.PutEndQuotes( "\"" );
  81. if( !ArgLex.PrepareToParse() ) {
  82. DebugAbort( "ArgLex.PrepareToParse() failed \n" );
  83. return( FALSE );
  84. }
  85. if ( !ArgumentArray.Initialize() ) {
  86. DebugAbort( "ArgumentArray.Initialize() failed \n" );
  87. return( FALSE );
  88. }
  89. if( !ProgramNameArgument.Initialize("*") ||
  90. !DeviceArgument.Initialize( "/D:*" ) ||
  91. !_BufferSize.Initialize( "/B:*" ) ||
  92. !_Ticks1.Initialize( "/U:*" ) ||
  93. !_Ticks2.Initialize( "/M:*" ) ||
  94. !_Ticks3.Initialize( "/S:*" ) ||
  95. !_NumberOfFiles.Initialize( "/Q:*" ) ||
  96. !_FlagRemoveFiles.Initialize( "/T" ) ||
  97. !_Files.Initialize( "*", FALSE, TRUE ) ||
  98. !_FlagCancelPrinting.Initialize( "/C" ) ||
  99. !_FlagAddFiles.Initialize( "/P" ) ||
  100. !FlagDisplayHelp.Initialize( "/?" ) ) {
  101. DebugAbort( "Unable to initialize flag or string arguments \n" );
  102. return( FALSE );
  103. }
  104. if( !ArgumentArray.Put( &ProgramNameArgument ) ||
  105. !ArgumentArray.Put( &DeviceArgument ) ||
  106. !ArgumentArray.Put( &_BufferSize ) ||
  107. !ArgumentArray.Put( &_Ticks1 ) ||
  108. !ArgumentArray.Put( &_Ticks2 ) ||
  109. !ArgumentArray.Put( &_Ticks3 ) ||
  110. !ArgumentArray.Put( &_NumberOfFiles ) ||
  111. !ArgumentArray.Put( &_FlagRemoveFiles ) ||
  112. !ArgumentArray.Put( &_Files ) ||
  113. !ArgumentArray.Put( &_FlagCancelPrinting ) ||
  114. !ArgumentArray.Put( &_FlagAddFiles ) ||
  115. !ArgumentArray.Put( &FlagDisplayHelp ) ) {
  116. DebugAbort( "ArgumentArray.Put() failed \n" );
  117. return( FALSE );
  118. }
  119. if( !ArgLex.DoParsing( &ArgumentArray ) ) {
  120. InvalidArgument = ArgLex.QueryInvalidArgument();
  121. DebugPtrAssert( InvalidArgument );
  122. _Message.Set( MSG_PRINT_INVALID_SWITCH );
  123. _Message.Display( "%W", InvalidArgument );
  124. return( FALSE );
  125. }
  126. //
  127. // /B: /U: /M: /S: /Q: /T: /C: and /P: are not implemented
  128. // if one of these arguments was found in the command line
  129. // then inform user, and don't print anything
  130. //
  131. if( _BufferSize.IsValueSet() ) {
  132. _Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
  133. _Message.Display( "%s", "/B:" );
  134. return( FALSE );
  135. }
  136. if( _Ticks1.IsValueSet() ) {
  137. _Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
  138. _Message.Display( "%s", "/U:" );
  139. return( FALSE );
  140. }
  141. if( _Ticks2.IsValueSet() ) {
  142. _Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
  143. _Message.Display( "%s", "/M:" );
  144. return( FALSE );
  145. }
  146. if( _Ticks3.IsValueSet() ) {
  147. _Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
  148. _Message.Display( "%s", "/S:" );
  149. return( FALSE );
  150. }
  151. if( _NumberOfFiles.IsValueSet() ) {
  152. _Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
  153. _Message.Display( "%s", "/Q:" );
  154. return( FALSE );
  155. }
  156. if( _FlagRemoveFiles.IsValueSet() ) {
  157. _Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
  158. _Message.Display( "%s", "/T:" );
  159. return( FALSE );
  160. }
  161. if( _FlagCancelPrinting.IsValueSet() ) {
  162. _Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
  163. _Message.Display( "%s", "/C:" );
  164. return( FALSE );
  165. }
  166. if( _FlagAddFiles.IsValueSet() ) {
  167. _Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
  168. _Message.Display( "%s", "/P:" );
  169. return( FALSE );
  170. }
  171. //
  172. // Displays help message if /? was found in the command line
  173. //
  174. if( FlagDisplayHelp.QueryFlag() ) {
  175. _Message.Set( MSG_PRINT_HELP_MESSAGE );
  176. _Message.Display( " " );
  177. return( FALSE );
  178. }
  179. //
  180. // If no filename was specified, display error message
  181. //
  182. if( _Files.QueryPathCount() == 0 ) {
  183. _Message.Set( MSG_PRINT_NO_FILE );
  184. _Message.Display( " " );
  185. return( FALSE );
  186. }
  187. //
  188. // Get device name if one exists. Otherwise use PRN as default
  189. //
  190. if( !DeviceArgument.IsValueSet() ) {
  191. DevicePath = NEW( PATH );
  192. DebugPtrAssert( DevicePath );
  193. if( !DevicePath->Initialize( (LPWSTR)L"PRN" ) ) {
  194. _Message.Set( MSG_PRINT_UNABLE_INIT_DEVICE );
  195. _Message.Display( "%s", "PRN" );
  196. return( FALSE );
  197. }
  198. } else {
  199. DevicePath = DeviceArgument.GetPath();
  200. DebugPtrAssert( DevicePath );
  201. }
  202. if( !_Printer.Initialize( DevicePath ) ) {
  203. DeviceString = DevicePath->GetPathString();
  204. DebugPtrAssert( DeviceString );
  205. _Message.Set( MSG_PRINT_UNABLE_INIT_DEVICE );
  206. _Message.Display( "%W", DeviceString );
  207. if( !DeviceArgument.IsValueSet() ) {
  208. DELETE( DevicePath );
  209. }
  210. return( FALSE );
  211. }
  212. //
  213. // Get FSNODE of each file and put them in an array
  214. //
  215. PathArray = _Files.GetPathArray();
  216. DebugPtrAssert( PathArray );
  217. PathArrayIterator = ( PARRAY_ITERATOR )PathArray->QueryIterator();
  218. DebugPtrAssert( PathArrayIterator );
  219. if( !_FsnFileArray.Initialize() ) {
  220. DebugAbort( "_FsnFileArray.Initialize() failed \n" );
  221. return( FALSE );
  222. }
  223. while( ( FilePath = ( PPATH )PathArrayIterator->GetNext() ) != NULL ) {
  224. FsnFile = SYSTEM::QueryFile( FilePath );
  225. if( FsnFile != NULL ) {
  226. _FsnFileArray.Put( ( POBJECT )FsnFile );
  227. } else {
  228. FileString = FilePath->GetPathString();
  229. _Message.Set( MSG_PRINT_FILE_NOT_FOUND );
  230. _Message.Display( "%W", FileString );
  231. }
  232. }
  233. DELETE( PathArrayIterator );
  234. return( TRUE );
  235. }
  236. BOOLEAN
  237. PRINT::PrintFiles(
  238. )
  239. /*++
  240. Routine Description:
  241. Prints the files specified by the user.
  242. Arguments:
  243. None.
  244. Return Value:
  245. BOOLEAN - TRUE if all files were printed.
  246. --*/
  247. {
  248. PFSN_FILE FsnFile;
  249. PSTREAM FileStream;
  250. PARRAY_ITERATOR ArrayIterator;
  251. PBYTE Buffer;
  252. ULONG Size;
  253. ULONG BytesRead;
  254. ULONG BytesWritten;
  255. PCPATH FilePath;
  256. PCWSTRING FileName;
  257. INT _BufferStreamType;
  258. INT BytesConverted;
  259. INT cbStuff;
  260. LPSTR lpStuffANSI;
  261. BOOL fUsedDefault;
  262. Size = 512;
  263. Buffer = ( PBYTE )MALLOC( ( size_t )Size );
  264. lpStuffANSI = ( LPSTR )MALLOC( ( size_t )Size );
  265. if (Buffer == NULL || lpStuffANSI == NULL) {
  266. DebugPrint("PRINT: Out of memory\n");
  267. return FALSE;
  268. }
  269. ArrayIterator = ( PARRAY_ITERATOR )_FsnFileArray.QueryIterator();
  270. if (ArrayIterator == NULL) {
  271. DebugPrint("PRINT: ArrayIterator equals NULL\n");
  272. return FALSE;
  273. }
  274. while( ( FsnFile = ( PFSN_FILE )ArrayIterator->GetNext() ) != NULL ) {
  275. FileStream = ( PSTREAM )FsnFile->QueryStream( READ_ACCESS );
  276. if (FileStream == NULL) {
  277. DebugPrint("PRINT: FileStream equals NULL\n");
  278. return FALSE;
  279. }
  280. FileName = FsnFile->GetPath()->GetPathString();
  281. if( FileName != NULL ) {
  282. _Message.Set( MSG_PRINT_PRINTING );
  283. _Message.Display( "%W", FileName );
  284. }
  285. _BufferStreamType = -1;
  286. while( !FileStream->IsAtEnd() ) {
  287. FileStream->Read( Buffer, Size, &BytesRead );
  288. // is file unicode?
  289. if (_BufferStreamType < 0) {
  290. if (IsTextUnicode((LPTSTR)Buffer, (INT)BytesRead,
  291. NULL) ) {
  292. _BufferStreamType = 1;
  293. } else {
  294. _BufferStreamType = 0;
  295. }
  296. }
  297. // does the buffer need to be converted?
  298. if (_BufferStreamType == 1) {
  299. cbStuff = Size;
  300. BytesConverted = WideCharToMultiByte(CP_ACP,0,
  301. (LPTSTR)Buffer,BytesRead/sizeof(WCHAR),
  302. lpStuffANSI,cbStuff,NULL,&fUsedDefault) ;
  303. DebugAssert(cbStuff>0);
  304. DebugAssert(BytesConverted >= 0);
  305. _Printer.Write((PBYTE)lpStuffANSI,BytesConverted,&BytesWritten );
  306. } else {
  307. _Printer.Write( Buffer, BytesRead, &BytesWritten );
  308. }
  309. }
  310. _Printer.WriteByte( '\f' );
  311. DELETE( FileStream );
  312. }
  313. DELETE( ArrayIterator );
  314. return( TRUE );
  315. }
  316. BOOL
  317. PRINT::Terminate(
  318. )
  319. /*++
  320. Routine Description:
  321. Deletes objects created during initialization.
  322. Arguments:
  323. None.
  324. Return Value:
  325. None.
  326. --*/
  327. {
  328. return( TRUE );
  329. }
  330. ULONG __cdecl
  331. main()
  332. {
  333. DEFINE_CLASS_DESCRIPTOR( PRINT );
  334. {
  335. PRINT Print;
  336. if( Print.Initialize() ) {
  337. Print.PrintFiles();
  338. }
  339. // Print.Terminate();
  340. return( 0 );
  341. }
  342. }