NT4/private/ntos/dd/parallel/printapp.c
2020-09-30 17:12:29 +02:00

249 lines
7.2 KiB
C

/****************************************************************************
Controlled direct printing application.
All of the following can be controlled, via command line switches:
* File to print - first file name given
* Port to print to - second file name given (defaults to lpt1)
* Size of data blocks to send to the printer (default 1)
* Delay between blocks (if any) (default 0)
* Retry delay, in milliseconds (default 10,000- 10 seconds)
* Maximum number of retries (default 6)
Switches:
-BlockSize:nnn Data Block size
-GapDelay:nnn Size of inter-block delay
-RetryWait:nnn Amount of time to wait before retrying a failed write
-MaxRetries:nnn Maximum Number of Retries
*****************************************************************************/
#include <Windows.H>
#include <stdio.h>
#include <stdlib.h>
static char acBigBuffer[32768], acDefaultPrinter[] = "lpt1",
*pcInputFileName = NULL, *pcOutputFileName = NULL,
*pcAppName = NULL;
static DWORD dwBlockSize = 1, dwGapDelay = 0, dwRetryWait = 10000,
dwMaxRetries = 6;
/******************************************************************************
Static Function: BailOut
Purpose: Reports command line errors, gives correct usage,
and exits.
Change History:
03-28-1991 BobK Coded it
******************************************************************************/
static void BailOut(char *pcComplaint)
{
printf("\nCOMMAND LINE ERROR: %s\n\n", pcComplaint);
printf("Usage: %s [switches] input-file [destination]\n\n", pcAppName);
printf("\tSwitches [defaults]:\n");
printf("\t\t-b:nnn\tset data block size to nnn [1]\n");
printf("\t\t-d:nnn\tset delay between blocks in milliseconds [0]\n");
printf("\t\t-w:nnn\tset wait before retrying, in milliseconds [10000]\n");
printf("\t\t-r:nnn\tset maximum number of retries [6]\n");
exit(0);
}
/******************************************************************************
Main Entry point
This processes the command line parameters, then reads the input file,
and pumps the data to the output file, under the set conditions.
Change History:
03-28-1991 BobK Grew it from a quick-and-dirty app
******************************************************************************/
void main(unsigned argc, char **argv)
{
HANDLE hfIn, hfOut;
DWORD dwBytesRead, dwBytesWritten;
unsigned uIndex;
/*
Process any command line switches
*/
pcAppName = *argv;
for (uIndex = 1;
uIndex < argc && (*(argv[uIndex]) == '-' || *(argv[uIndex]) == '/');
uIndex++)
switch (argv[uIndex][1])
{
case 'b':
case 'B':
if (2 != sscanf(argv[uIndex], "%2c%d", acBigBuffer,
&dwBlockSize))
BailOut("Invalid Block Size (-B) switch used");
break;
case 'd':
case 'D':
if (2 != sscanf(argv[uIndex], "%2c%d", acBigBuffer,
&dwGapDelay))
BailOut("Invalid Inter-Record Gap Delay (-d) switch used");
break;
case 'w':
case 'W':
if (2 != sscanf(argv[uIndex], "%2c%d", acBigBuffer,
&dwRetryWait))
BailOut("Invalid Retry Wait (-w) switch used");
break;
case 'r':
case 'R':
if (2 != sscanf(argv[uIndex], "%2c%d", acBigBuffer,
&dwMaxRetries))
BailOut("Invalid Maximum Retries (-r) switch used");
break;
default:
BailOut("Invalid switch given");
}
/*
Collect the input and output file names
*/
if (uIndex == argc)
BailOut("No File Name given to print");
pcInputFileName = argv[uIndex++];
pcOutputFileName = (uIndex == argc) ? acDefaultPrinter : argv[uIndex++];
if (uIndex < argc)
BailOut("Too many parameters given");
printf("\tBlockSize:%d\tGapDelay:%d\tRetryWait:%d\tMaxRetries:%d\n\nCopying"
" From %s to %s\n\n", dwBlockSize, dwGapDelay, dwRetryWait,
dwMaxRetries, pcInputFileName, pcOutputFileName);
/*
Open the files- exit if unsuccessful
*/
hfIn = CreateFile(pcInputFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, FALSE);
if (hfIn == (HANDLE) -1)
{
DWORD dwError;
dwError = GetLastError();
printf("Couldn't open - error code 0x%8.8X\n", pcInputFileName, dwError);
return;
}
hfOut = CreateFile(pcOutputFileName, GENERIC_WRITE, NULL, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
FALSE);
if (hfOut == (HANDLE) -1)
{
DWORD dwError;
dwError = GetLastError();
printf("Couldn't open %s- error code 0x%8.8X\n", pcOutputFileName,
dwError);
CloseHandle(hfIn);
return;
}
/*
Read the input file in chunks that are multiples of the given block size.
As much as will fit into the buffer is read at one time.
*/
while (ReadFile(hfIn, acBigBuffer,
dwBlockSize * (sizeof(acBigBuffer) / dwBlockSize),
&dwBytesRead, NULL)
&& dwBytesRead)
{
DWORD dwBytesLeft, dwRetries;
printf("Read a chunk of 0x%8.8X bytes\n", dwBytesRead);
/*
Write the file out, in chunks of the underlying block size. If a
write fails, retry it up to the maximum count. Note that on a failed
write, we adjust the pointer to account for what was written, and
attempt to write a full block from that point. This could result
in a short block at the end (but that could happen, anyway, at the
end of the input file, so it's no extra code).
*/
for (dwBytesLeft = dwBytesRead, dwRetries = 0;
dwBytesLeft;
dwBytesLeft -= dwBytesWritten)
{
if (WriteFile(hfOut, acBigBuffer + (dwBytesRead - dwBytesLeft),
dwBlockSize < dwBytesLeft ? dwBlockSize : dwBytesLeft,
&dwBytesWritten, NULL) &&
(dwBytesWritten == dwBlockSize ||
dwBytesWritten == dwBytesLeft))
{
printf("0x%8.8X bytes written (%d)",
(dwBytesRead + dwBytesWritten) - dwBytesLeft,
(dwBytesRead + dwBytesWritten) - dwBytesLeft);
printf("\t \r");
dwRetries = 0;
Sleep(dwGapDelay);
}
else
{
DWORD dwError;
dwError = GetLastError();
printf("\nWrite failed, Error Code 0x%8.8X\n", dwError);
printf("0x%8.8X bytes written (%d)",
(dwBytesRead + dwBytesWritten) - dwBytesLeft,
(dwBytesRead + dwBytesWritten) - dwBytesLeft);
printf("\tTime for a nap...\r");
if (dwRetries++ < dwMaxRetries)
Sleep(dwRetryWait);
else
{
printf("\nMaximum retries exceeded- aborting\n");
break;
}
}
}
if (dwBytesLeft)
break;
}
if (dwBytesRead)
printf("\nRead bombed, or write croaked?\n");
else
printf("\nGreat, it woiked!\n");
CloseHandle(hfIn);
CloseHandle(hfOut);
}