/* * $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 --- */