/*
* $Header: /home/gene/library/website/docsrc/psw/RCS/print-postscript.c,v 395.1 2008/04/20 17:25:47 gene Exp $
*
* Copyright (c) 2004 Gene Michael Stover. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
/*
* In Windows, print a PostScript file to a PostScript printer.
* With this version, the printer must understand PostScript in
* its firmware. It doesn't matter whether the printer's driver
* understands PostScript because we by-pass the driver.
*
* Documentation, executable file, & source code are at
* (primary site) and
* (mirror site).
*
* Index of relevant functions on MSDN is at
*
*
*/
/* Standard C */
#include
#include
#include
#include
#include
/* Microsloth Winders */
#include
/*
*/
enum { ACTION_PRINT, ACTION_ENUM_PRINTERS, ACTION_USAGE };
static int S_action = ACTION_PRINT;
/*
*/
static char *S_progname = "print-postscript";
/*
*/
static char *S_pathname = "standard input";
static FILE *S_strm = stdin;
static char *S_printername;
/*
*/
static char *S_datatype = "RAW";
static int
S_CommandLine (int argc, char *argv[])
{
int rc = 0, optind = 1;
while (rc == 0 && optind < argc && argv[optind][0] == '-') {
/* printf ("\nargv[%d] is \"%s\"", optind, argv[optind]); */
if (strcmp (argv[optind], "-f") == 0) {
S_pathname = argv[++optind];
S_strm = fopen (S_pathname, "r");
if (S_strm != NULL) {
/* good */
} else {
fprintf (stderr, "\n%s:%d: fopen: %s", __FILE__, __LINE__,
strerror (errno));
fprintf (stderr, "\n%s:%d: Can't open \"%s\" for input", __FILE__,
__LINE__, argv[optind]);
rc = 111;
}
} else if (strcmp (argv[optind], "--help") == 0 ||
strcmp (argv[optind], "-?") == 0 ||
strcmp (argv[optind], "-h") == 0 ||
strcmp (argv[optind], "/?") == 0 ||
strcmp (argv[optind], "/h") == 0 ||
strcmp (argv[optind], "/help") == 0) {
S_action = ACTION_USAGE;
} else if (strcmp (argv[optind], "-l") == 0) {
S_action = ACTION_ENUM_PRINTERS;
} else if (strcmp (argv[optind], "-t") == 0) {
S_datatype = argv[++optind];
} else {
fprintf (stderr, "\n%s:%d: Unexpected option, \"%s\".", __FILE__,
__LINE__, argv[optind]);
rc = 33;
}
++optind;
}
if (rc == 0 && S_action == ACTION_PRINT) {
if (optind < argc) {
S_printername = argv[optind++];
if (optind < argc) {
fprintf (stderr, "\n%s:%d: Ignoring excess command line arguments",
__FILE__, __LINE__);
}
} else {
fprintf (stderr, "\n%s:%d: Missing printer name on the command line",
__FILE__, __LINE__);
rc = 120;
}
} else {
/*
* There was a problem, or the action isn't to print. Either way,
* we don't bother to fetch a printer name.
*/
}
return rc;
}
static int
S_SetPostScript (HANDLE printer)
{
static char escape[] = "\033%-12345X@PJL \n";
static char postscript[] = "@PJL ENTER LANGUAGE = POSTSCRIPT \n";
int rc = 0;
DWORD written;
if (strcmp (S_datatype, "RAW") == 0) {
/*
* We'll send the PostScript file as raw data. This implies that
* the printer understands PostScript natively, not relying on
* a PostScript driver. So we first send commands to ensure
* that the printer is in PostScript mode.
*/
if (WritePrinter (printer, escape, strlen (escape), &written) &&
WritePrinter (printer, postscript, strlen (postscript), &written)) {
/* good */
} else {
fprintf (stderr, "\n%s:%d: WritePrinter failed (%lu)", __FILE__,
__LINE__, (unsigned long) GetLastError ());
rc = 3;
}
} else {
/*
* We're not sending raw data, so we rely on the driver to put the
* printer in the proper mode, or to process the PostScript itself.
*/
}
return rc;
}
static HANDLE
S_StartPrinter (char printername[])
{
HANDLE hnd = INVALID_HANDLE_VALUE;
DOC_INFO_1 di1;
DWORD job;
if (OpenPrinter (printername, &hnd, NULL)) {
di1.pDocName = S_pathname;
di1.pOutputFile = NULL;
di1.pDatatype = S_datatype;
job = StartDocPrinter (hnd, 1, (LPBYTE) &di1);
if (job != 0) {
if (S_SetPostScript (hnd) == 0) {
/* good */
} else {
fprintf (stderr, "\n%s:%d: S_SetPostScript failed", __FILE__,
__LINE__);
ClosePrinter (hnd);
hnd = INVALID_HANDLE_VALUE;
}
} else {
fprintf (stderr, "\n%s:%d: StartDocPrinter failed (%lu)", __FILE__,
__LINE__, (unsigned long) GetLastError ());
ClosePrinter (hnd);
hnd = INVALID_HANDLE_VALUE;
}
} else {
fprintf (stderr, "\n%s:%d: OpenPrinter failed (%lu)", __FILE__, __LINE__,
(unsigned long) GetLastError ());
}
return hnd;
}
static void
S_StopPrinter (HANDLE hnd)
{
if (EndDocPrinter (hnd)) {
/* good */
} else {
fprintf (stderr, "\n%s:%d: EndDocPrinter failed (%lu)", __FILE__,
__LINE__, (unsigned long) GetLastError ());
}
ClosePrinter (hnd);
}
static int
S_Loop (FILE *file, FILE *printer)
{
int rc = 0;
int count;
char buffer[1024];
static int buflen = sizeof buffer / sizeof buffer[0];
DWORD written;
do {
count = fread (buffer, sizeof buffer[0], buflen, file);
if (count >= 1) {
count *= sizeof buffer[0];
if (WritePrinter (printer, buffer, count, &written)) {
/* good so far */
} else {
fprintf (stderr, "%s:%d: WritePrinter failed (%lu)", __FILE__,
__LINE__, (unsigned long) GetLastError ());
rc = 12;
}
}
} while (rc == 0 && count >= 1);
return rc;
}
static int
S_Run (char pathname[])
{
int rc = 0;
HANDLE printer;
printer = S_StartPrinter (S_printername);
if (printer != INVALID_HANDLE_VALUE) {
if (S_SetPostScript (printer) == 0) {
if (S_Loop (S_strm, printer) == 0) {
/* good so far */
} else {
fprintf (stderr, "\n%s:%d: S_Loop failed", __FILE__, __LINE__);
rc = 11;
}
} else {
fprintf (stderr, "\n%s:%d: S_SetPostScript failed", __FILE__,
__LINE__);
rc = 111;
}
S_StopPrinter (printer);
} else {
fprintf (stderr, "\n%s:%d: fopen: %s", __FILE__, __LINE__,
strerror (errno));
rc = 11;
}
return rc;
}
static int
S_EnumPrintProcessorDatatypes (char processor[], char server[], FILE *fp)
{
int rc = 0;
static DWORD level = 1;
DATATYPES_INFO_1 *di1 = NULL;
DWORD sz = 0, count = 0, i;
EnumPrintProcessorDatatypes (server, processor, level, NULL, 0, &sz, &count);
if (sz > 0) {
di1 = malloc (sz);
if (di1 != NULL) {
if (EnumPrintProcessorDatatypes (server, processor, level, (LPBYTE) di1,
sz, &sz, &count)) {
fprintf (fp, "\n (Datatypes");
for (i = 0; i < count; ++i) {
fprintf (fp, " \"%s\"", di1[i].pName);
}
fprintf (fp, ")");
} else {
fprintf (stderr, "\n%s:%d: EnumPrintProcessorDatatypes failed (%lu)",
__FILE__, __LINE__, (unsigned long) GetLastError ());
rc = 333;
}
free (di1);
} else {
fprintf (stderr, "\n%s:%d: malloc: %s", __FILE__, __LINE__,
strerror (errno));
rc = 301;
}
} else {
fprintf (stderr, "\n%s:%d:", __FILE__, __LINE__);
fprintf (stderr, " EnumPrintProcessorDatatypes to get size failed (%lu)",
(unsigned long) GetLastError ());
rc = 333;
}
return rc;
}
static void
S_PrintPrintProcessor (char processor[], char server[], FILE *fp)
{
fprintf (fp, "(PrintProcessor");
fprintf (fp, "\n (name . \"%s\")", processor);
fprintf (fp, "\n (server . \"%s\")", server);
S_EnumPrintProcessorDatatypes (processor, server, fp);
fprintf (fp, ")");
}
static void
S_PrintPrinterInfo2 (PRINTER_INFO_2 *pi2, FILE *fp)
{
static char sep[] = "\n "; /* field separator */
fprintf (fp, "\n(PRINTER_INFO_2");
if (pi2->pServerName) {
fprintf (fp, "%s(pServerName . \"%s\")", sep, pi2->pServerName);
} else {
fprintf (fp, "%s(pServerName . NIL)", sep);
}
fprintf (fp, "%s(pPrinterName . \"%s\")", sep, pi2->pPrinterName);
fprintf (fp, "%s(pShareName . \"%s\")", sep, pi2->pShareName);
fprintf (fp, "%s(pPortName . \"%s\")", sep, pi2->pPortName);
fprintf (fp, "%s(pDriverName . \"%s\")", sep, pi2->pDriverName);
fprintf (fp, "%s(pComment . \"%s\")", sep, pi2->pComment);
fprintf (fp, "%s(pLocation . \"%s\")", sep, pi2->pLocation);
fprintf (fp, "%s(pDevMode . )", sep, pi2->pDevMode);
fprintf (fp, "%s(pSepFile . \"%s\")", sep, pi2->pSepFile);
fprintf (fp, "%s(pPrintProcessor . ", sep);
S_PrintPrintProcessor (pi2->pPrintProcessor, pi2->pServerName, fp);
fprintf (fp, ")");
fprintf (fp, "%s(pDatatype . \"%s\")", sep, pi2->pDatatype);
fprintf (fp, "%s(pParameters . \"%s\")", sep, pi2->pParameters);
fprintf (fp, "%s(pSecurityDescriptor . )",
sep, pi2->pSecurityDescriptor);
fprintf (fp, "%s(Attributes . 0x%lx)", sep, (unsigned long) pi2->Attributes);
fprintf (fp, "%s(Priority . 0x%04X)", sep, pi2->Priority);
fprintf (fp, "%sDefaultPriority . 0x%04X", sep, pi2->DefaultPriority);
fprintf (fp, "%s(StartTime . 0x%04X)", sep, pi2->StartTime);
fprintf (fp, "%s(UntilTime . 0x%04X)", sep, pi2->UntilTime);
fprintf (fp, "%s(Status . 0x%04X)", sep, pi2->Status);
fprintf (fp, "%s(cJobs . 0x%04X)", sep, pi2->cJobs);
fprintf (fp, "%(sAveragePPM . 0x%04X)", sep, pi2->AveragePPM);
fprintf (fp, ")");
}
static int
S_EnumPrinters ()
{
int rc = 0;
static DWORD flags = PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS;
static DWORD level = 2;
PRINTER_INFO_2 *pi2 = NULL;
DWORD sz = 0, count = 0, i;
EnumPrinters (flags, NULL, level, NULL, 0, &sz, &count);
if (sz > 0) {
pi2 = malloc (sz);
if (pi2 != NULL) {
if (EnumPrinters (flags, NULL, level, (LPBYTE) pi2, sz, &sz, &count)) {
for (i = 0; i < count; ++i) {
S_PrintPrinterInfo2 (&pi2[i], stdout);
}
} else {
fprintf (stderr, "\n%s:%d: EnumPrinters failed", __FILE__, __LINE__);
rc = 333;
}
free (pi2);
} else {
fprintf (stderr, "\n%s:%d: malloc: %s", __FILE__, __LINE__,
strerror (errno));
rc = 301;
}
} else {
fprintf (stderr, "\n%s:%d: EnumPrinters to get size failed", __FILE__,
__LINE__);
rc = 333;
}
return rc;
}
static void
S_Usage (char progname[])
{
printf ("\nprint-postscript, by Gene Michael Stover");
printf ("\nCopyright (c) 2004 Gene Michael Stover. All rights reserved.");
printf ("\nLicensed according to the Gnu General Public License");
printf (" agreement.");
printf ("\n");
printf ("\nUsage: %s --help", progname);
printf ("\n %s -?", progname);
printf ("\n %s -h", progname);
printf ("\n %s /?", progname);
printf ("\n %s /h", progname);
printf ("\n %s /help", progname);
printf ("\n %s [-f PATHNAME] PRINTERNAME", progname);
printf ("\n %s -l", progname);
printf ("\nDocumentation is at");
printf (" ");
printf (" and");
printf (" ");
printf ("\n");
}
static int
S_Dispatch (int action)
{
int rc = 0;
switch (action) {
case ACTION_PRINT:
if (S_Run (S_pathname) == 0) {
/* good */
} else {
fprintf (stderr, "\n%s:%d: S_Run failed", __FILE__, __LINE__);
rc = 4;
}
break;
case ACTION_ENUM_PRINTERS:
if (S_EnumPrinters () == 0) {
/* good */
} else {
fprintf (stderr, "\n%s:%d: S_EnumPrinters failed", __FILE__, __LINE__);
rc = 4;
}
break;
case ACTION_USAGE:
S_Usage (S_progname);
break;
default:
fprintf (stderr, "\n%s:%d:", __FILE__, __LINE__);
fprintf (stderr, " Don't know what to do with action %d.", action);
rc = 3;
}
return rc;
}
int
main (int argc, char *argv[])
{
int rc = 0;
if (S_CommandLine (argc, argv) == 0) {
if (S_Dispatch (S_action) == 0) {
/* good */
} else {
fprintf (stderr, "\n%s:%d: S_Run failed", __FILE__, __LINE__);
rc = 42;
}
} else {
fprintf (stderr, "\n%s:%d: S_CommandLine failed", __FILE__, __LINE__);
rc = 22;
}
return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
/* --- end of file --- */