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.

965 lines
35 KiB

  1. /* lpr.c - fancy paginator for laserprinters
  2. *
  3. * Author: Mark Taylor
  4. *
  5. * Modifications:
  6. *
  7. * 12/85 Mark Zbikowski rewrite to work cleaner
  8. * 4/3/86 MZ Single print jobs will advance page
  9. * 4/3/86 MZ use tools.ini for default printer setup
  10. * 4/20/86 Mike Hanson add banner, etc (add features to make like
  11. * lpr from PS, extensively reorganized, etc)
  12. * 6/6/86 Jay Sipelstein added S and L options to printer desc.
  13. * Trim trailing blanks and blank lines.
  14. * Set mode before raw printing.
  15. * 7/8/86 Byron Bishop Add -q to cause print queue to be printed.
  16. * Fixed bug so -# and -e flags take priority
  17. * over default settings. Runs of blanks
  18. * replaced by escape sequences to reduce
  19. * file size.
  20. * 8/31/86 Craig Wittenberg Added support for PostScript. Used the VMI
  21. * on the LaserJet instead of line/inch to get 62
  22. * lines on one page (two for header). Cleaned
  23. * up iLine (now rowLine) and indentation.
  24. * 10/10/86 John Rae-Grant Added -g flag to allow gutter in portrait mode.
  25. * $USER can now be a list of directories to
  26. * search for tools.ini in. Default printer can
  27. * be specified in tools.ini file. Modified
  28. * landscape mode page numbering to avoid three
  29. * hole punch obliteration.
  30. * 1/27/87 Craig Wittenberg Cleaned up whole program; no change in
  31. * functionality.
  32. * 1/28/87 Thom Landsberger Added CB and CZ (=default) flags to the LJ
  33. * printer description to support the 'Z' font
  34. * cartridge in landscape mode
  35. * 3/23/87 Thom Landsberger Port to Xenix 286 and 68k; environment
  36. * setting of parameters accepted as default
  37. * and with higher priority than tools.ini/.pprrc;
  38. * implemented -m, -M, -c command switches;
  39. * restructured command interpretation.
  40. * 4/10/87 Craig Wittenberg interrupt signal ignored if that is the
  41. * status when ppr is started
  42. * 4/14/87 Thom Landsberger only pure digit strings accepted as
  43. * numeric command line arguments
  44. * 6/05/87 Thom Landsberger double sided printing on HP LJ 2000;
  45. * '/' no switch character on Xenix;
  46. * 'ppr -q -' now does print from stdin.
  47. * 7/5/87 Craig Wittenberg changed fDuplex? names to f?Duplex so they
  48. * compile in 68k Xenix. Invoked ftp with command
  49. * line arguments rather than printing the commands
  50. * to stdin. -t now removes label (used to require
  51. * -m "").
  52. *
  53. * Ppr reads /etc/default/ppr if there is not
  54. * $HOME/.pprrc. Duplex printing now does not
  55. * print on the back of the banner page (even if
  56. * not raw). Added -s flag: disables messages
  57. * which indicate ppr's progress. Changed the PS
  58. * setup to avoid VMErrors. Allowed the default
  59. * printer in the tools.ini/.pprrc file to have
  60. * options (e.g. default=lpt1, LJ L). Changed the
  61. * default printer on Xenix from net9 to net.
  62. *
  63. * ~8/1/87 Ralph Ryan Ported to OS/2 LanManager
  64. *
  65. * 11/24/87 Craig Wittenberg Rearranged sources - mostly to isloate the OS
  66. * specific network routines in lplow.c
  67. * Ppr now uses clem as the transfer machine for
  68. * DOS print jobs when /usr/eu/bin/ppr is not
  69. * present (indicating a machine in another
  70. * division).
  71. *
  72. * 12/2/87 Alan Bauer Version 2.5
  73. * Final porting to OS/2 LAN Manager. Mainly
  74. * polished up network routines to work properly
  75. * Released to OS/2 people, DOSENV, NEWENV, and
  76. * new 68K version.
  77. *
  78. * 3/17/88 Alan Bauer Version 2.6
  79. * Fixed so that the username is still printed in
  80. * lower left corner of the file listing when the
  81. * "no banner" option is specified (ppr -b0).
  82. * Ppr -? now prints to stdout rather than stderr.
  83. * Now supports ppr -q for OS/2.
  84. *
  85. * 4/04/88 Alan Bauer Version 2.7
  86. * Added -c<n> option to print <n> copies of the
  87. * specified files.
  88. * Seperates large print jobs into roughly 100K
  89. * amounts.
  90. * Better feed back on PRINTING progress.
  91. * Fixed so that an empty password is now passed to
  92. * mkalias correctly (Xenix 386 version).
  93. * Now map ppr -p "xenix name" to
  94. * "mkalias name name printing [password]".
  95. * Errors opening input files no longer abort; just
  96. * go on to the next file.
  97. *
  98. * 4/05/88 Alan Bauer Version 2.71
  99. * Fixed problem with last file to be printed
  100. * putting the current print job over 100K,
  101. * therefore causing new print job to be performed
  102. * (with no more files to be printed).
  103. *
  104. * 4/13/88 Alan Bauer Version 2.8
  105. * Added ability to specify options in TOOLS.INI
  106. * file.
  107. *
  108. * 5/19/88 Alan Bauer Version 2.81
  109. * Fixed General Protection Fault in OS/2 dealing
  110. * with login usernames which are more than 12
  111. * characters long.
  112. *
  113. * 6/20/88 Alan Bauer Version 2.82
  114. * Fixed LANMAN error message handling problems
  115. * and a bug where ppr failed if redirection to
  116. * the same printer as established in the environ-
  117. * ment variable was already set up.
  118. *
  119. * 3/3/89 Robert Hess Version 2.9
  120. * Completely changed PostScript support.
  121. * Added 'PC' (Portrait Condensed) and 'PSF'
  122. * (PostScriptFile) printer specific switches.
  123. *
  124. * 3/22/89 Robert Hess Version 2.10
  125. * Modifications to how 'FormFeed' was handled
  126. * for PostScript usage.
  127. *
  128. * 7/12/89 Robert Hess Version 2.11
  129. * Fixed a bug that prevented lengthy Postscript
  130. * files to be printed.
  131. *
  132. * 9/14/89 Robert Hess Version 2.12
  133. * Fixed -M option in PostScript code.
  134. * Fixed the 'opts=<option>' parsing from
  135. * TOOLS.INI (wasn't allowing leading spaces)
  136. *
  137. * 10/6/89 Robert Hess Version 2.12b
  138. * Minor fix, repaired linking to include
  139. * SetArgV.OBJ (to automatically expand
  140. * wildcards in filenames - ooops!), and
  141. * added error handling to the '-q' command.
  142. *
  143. * 10/20/89 Robert Hess Version 2.13
  144. * Date and time of *FILE* is now printed at
  145. * the bottom of the page for PostScript.
  146. * (...ooops...)
  147. *
  148. * 12/06/89 Robert Hess Version 2.14
  149. * Added switches -v (verify, for debugging),
  150. * and -w (column width).
  151. *
  152. * 4/9/90 Scott Means Version 2.15
  153. * Support of non-printable IBM characters and
  154. * added progress indicator.
  155. *
  156. * 4/18/90 Robert Hess Version 2.2
  157. * Re-Wrote postscript header code to allow
  158. * full sensing of actual printer area, and
  159. * corrected several bugs in old header.
  160. * Fixed 'pathname' for network drives
  161. * Fixed '-t' switch for Postscript mode
  162. * Added 'psuedo' printer name support.
  163. *
  164. * 6/15/90 Robert Hess Version 2.3
  165. * Added better implementation of 'extended
  166. * ascii' mode. Added more debugging code
  167. * for network usage. Added R and C printer
  168. * switches to better support odd sized paper.
  169. * Improved 'usage' text.
  170. * Switched to using some TOOLSVR api calls.
  171. * General cleanup and bug fixes.
  172. * Enlisted into \\ToolSvr\Build project.
  173. *
  174. * 7/26/90 Robert Hess Version 2.3a
  175. * Fixed a couple bugs. Added '-l' option for
  176. * listing out contents of TOOLS.INI. Final
  177. * cleanup prior to general release.
  178. *
  179. */
  180. #include <stdio.h>
  181. #include <stdlib.h>
  182. #include <stdarg.h>
  183. #include <string.h>
  184. #include <process.h>
  185. #include <signal.h>
  186. #include <ctype.h>
  187. #include <windows.h>
  188. #include <tools.h>
  189. #include "lpr.h"
  190. /* 175 columns:
  191. * 0 1 174
  192. * single page: <bar> 173 columns of text <bar>
  193. * 0 1 86 87 88 173 174
  194. * double page: <bar> 86 columns of text <bar> 86 columns of text <bar>
  195. */
  196. long lcbOutLPR = 0l; // total amount printed in this job
  197. int cCol = 0; // number of columns being displayed
  198. int cColCom = 0; /* number of columns as specified in
  199. command line. */
  200. int colTabCom = 0; /* number of spaces per tab specified
  201. in command line. Number of spaces
  202. per tab, colTab, is declared in
  203. lpfile.c */
  204. int colGutter = 0; // number of spaces in gutter
  205. int colText = 0; // column where text starts
  206. int cCopies = 1; // number of copies to print
  207. int colWidth; // printable spaces in each column
  208. int defWidth = 0; // <- NEW... to override colWidth calculation
  209. int colMac = colLJMax; // maximum columns on a page
  210. int rowMac = rowLJMax; // maximum rows on a page
  211. int rowPage; /* number of printable lines per page
  212. including header on top */
  213. char *aszSymSet[] = { // supported Laserjet symbol sets
  214. "\033&l1o5.8C\033(0U\033(s0p16.67h8.5v0T",
  215. "\033&l1o5.8C\033(8U\033(s0p16.67h8.5v0T",
  216. "\033&l1o5.8C\033(10U\033(s0p16.67h8.5v0T"
  217. };
  218. BOOL fNumber = FALSE; // TRUE => show line numbers
  219. BOOL fDelete = FALSE; // TRUE => delete file after printing
  220. BOOL fRaw = FALSE; // TRUE => print in raw mode
  221. BOOL fBorder = TRUE; // TRUE => print borders
  222. BOOL fLabel = TRUE; // TRUE => print page heading
  223. BOOL fLaser = TRUE; // TRUE => print on an HP LaserJet
  224. BOOL fPostScript = FALSE; // TRUE => print on postscript printer
  225. BOOL fPSF = FALSE; // TRUE => Use alternate PS Header
  226. char szPSF[MAX_PATH] = ""; // pathname of alternate PS Header
  227. BOOL fPCondensed = FALSE; // TRUE => Condensed portrait mode PS
  228. BOOL fConfidential = FALSE; // TRUE => stamp pages and banner
  229. BOOL fVDuplex = FALSE; // TRUE => double sided, vertical bind
  230. BOOL fHDuplex = FALSE; // TRUE => ditto, but horizontal bind
  231. BOOL fSilent = FALSE; // TRUE => no messages
  232. int cBanner = -1; // # of banners; <0 only 1 group
  233. char chBanner = ' '; // used to form banner characters
  234. char *szBanner = NULL; // banner string, use fname if NULL
  235. char *szStamp = NULL; // additional label put on each page
  236. BOOL fForceFF = TRUE; // TRUE => end at top of page
  237. BOOL fPortrait = FALSE; // TRUE => print in portrait mode
  238. BOOL fQueue = FALSE; // TRUE => list print queue
  239. USHORT usSymSet = 0; // symbol set to use on Laserjet
  240. // FALSE => select Roman-8 symbol set
  241. USHORT usCodePage = 0; // 0 = convert extended ascii to '.'
  242. BOOL fVerify = FALSE; // TRUE => dump out data on what we are doing
  243. BOOL fList = FALSE; // TRUE => use with fVerify to prevent printing
  244. char szPass[cchArgMax] = "";
  245. static void Usage(void);
  246. static void DoArgs(int *, char **[]);
  247. void Abort(void);
  248. void DoIniOptions(void);
  249. int __cdecl main(argc, argv)
  250. int argc;
  251. char **argv;
  252. {
  253. intptr_t err;
  254. int iCopies;
  255. #ifdef notdefined
  256. if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  257. // if not ignored upon startup, set our abort handler
  258. signal(SIGINT, (void (_cdecl *)(int))Abort);
  259. #endif
  260. // hack to get verify and list to work *before* command line is parsed
  261. ConvertAppToOem( argc, argv );
  262. if( argc > 1 ) {
  263. if (argv[1][1] == 'v') {
  264. fVerify = TRUE;
  265. }
  266. if (argv[1][1] == 'l') {
  267. fList = TRUE;
  268. }
  269. if (fVerify) {
  270. fprintf (stdout, "\n");
  271. }
  272. }
  273. DoIniOptions();
  274. if (fVerify) {
  275. fprintf (stdout, "Seen on Command Line:\n");
  276. }
  277. DoArgs(&argc, &argv);
  278. SetupPrinter();
  279. SetupRedir();
  280. // -------------- modifications to switches and precalculated values
  281. // don't allow guttering in landscape mode
  282. if (!fPortrait)
  283. colGutter = 0;
  284. // set global for start of text
  285. colText = colGutter + (fNumber ? cchLNMax : 0);
  286. // set # columns if set in command line.
  287. if (cColCom)
  288. cCol = cColCom;
  289. else if (cCol == 0)
  290. cCol = fPortrait ? 1 : 2;
  291. // set # of spaces per tab if set in command line.
  292. if (colTabCom)
  293. colTab = colTabCom;
  294. colWidth = colMac;
  295. if (fPostScript && fPCondensed) {
  296. colWidth = colMac *= 2;
  297. }
  298. if (defWidth > 0) colWidth = defWidth;
  299. if (fLaser && usCodePage == 850) {
  300. usSymSet = BEGINLANDIBMPC; // for the LaserJet
  301. }
  302. if (cCol != 1) {
  303. // more than one column: divide into separate columns with divider
  304. colWidth = (colMac-1) / cCol - 1;
  305. if (defWidth > 0) colWidth = defWidth;
  306. colMac = (colWidth + 1) * cCol + 1;
  307. }
  308. // rowPage includes border line(s) at top of page
  309. rowPage = rowMac;
  310. if (fBorder || fLabel) {
  311. if (!fLaser && !fPostScript && fPortrait) {
  312. // same bottom margin as old Xenix ppr
  313. rowPage -= 5;
  314. } else {
  315. // don't print on bottom line
  316. rowPage -= 1;
  317. }
  318. }
  319. if (!fLaser && !fPostScript && cBanner == -1) {
  320. // line printer for which the default banner setup is required
  321. cBanner = -2;
  322. }
  323. // ----------------- end modification of switches
  324. if (fVerify) fprintf (stdout, "\n"); // just to clean things up a little
  325. fprintf(stdout, "PPR version: "VERSION"\n");
  326. fprintf(stdout, "----------------------------------------------------------------------------\n");
  327. if (argc == 0) {
  328. /* No file names were listed... assume user wants <stdin> */
  329. if (!fQueue && !fList) {
  330. // print stdin
  331. fprintf (stdout, "Printing from: <stdin> Press <Ctrl-Z> to end.\n");
  332. MyOpenPrinter();
  333. FileOut("");
  334. MyClosePrinter();
  335. }
  336. } else {
  337. // print file(s)
  338. MyOpenPrinter();
  339. while (argc) {
  340. // print more copies if wanted
  341. for(iCopies = 1; iCopies <= cCopies; iCopies++) {
  342. FileOut(*argv);
  343. // end this print job if more than 100K has been printed
  344. // thus far. Then start next print job.
  345. if (lcbOutLPR > 100000 && argc != 1) {
  346. lcbOutLPR = 0l;
  347. MyClosePrinter();
  348. fFirstFile = TRUE;
  349. MyOpenPrinter(); // ready to start next job
  350. }
  351. }
  352. argc--;
  353. argv++;
  354. }
  355. MyClosePrinter();
  356. }
  357. /* if user wants to print queue, spawn a process to do the printing.
  358. The process will inherit the current environment including the
  359. redirection of szPName.
  360. */
  361. if (fQueue) {
  362. fprintf (stdout, "[Net Print %s]:\n", szNet);
  363. err = _spawnlp(P_WAIT,"net","net","print",szNet,NULL);
  364. if (err)
  365. if (err == -1)
  366. fprintf (stdout, "- Error : Unable to Spawn Queue Status Request -\n");
  367. else
  368. fprintf (stdout, "- Error Returned from Queue Status Request: %d - \n", err);
  369. }
  370. ResetRedir();
  371. return 0;
  372. } /* main */
  373. void Abort()
  374. /* SIGINT handler to abort printing gracefully
  375. *
  376. * Warning: Never returns (exits via Fatal).
  377. */
  378. {
  379. Fatal("terminated by user", NULL);
  380. } /* Abort */
  381. static void Usage()
  382. {
  383. fprintf(stdout, "PPR version: "VERSION" by: "ANALYST"\n");
  384. fprintf(stdout, "Usage: ppr [-switches] files(s)\n");
  385. fprintf(stdout, "-<digit> :Print in columns (1-9) -n : Print line numbers\n");
  386. fprintf(stdout, "-b <n> :Print <n> banners -o <n> : Offset <n> for gutter\n");
  387. fprintf(stdout, "-c <n> :Print <n> copies -q : List print queue status\n");
  388. fprintf(stdout, "-D :Delete file after print -s : Supress progress message\n");
  389. fprintf(stdout, "-e <n> :Expand tabs to <n> -t : Supress page headers\n");
  390. fprintf(stdout, "-f :NO formfeed at end -r : Print in raw mode\n");
  391. fprintf(stdout, "-h <string>:Use <string> for header -v : Verbose (for debugging)\n");
  392. fprintf(stdout, "-m <string>:Stamp <string> on page -w <n> : Page width in characters\n");
  393. fprintf(stdout, "-M :\"Microsoft Confidential\" -p <string>: Printer description\n");
  394. fprintf(stdout, "\n");
  395. fprintf(stdout, "Printer Description: ppr -p \"<port>,<type> <options>,<columns>,<tabstops>\"\n");
  396. fprintf(stdout, "Types & Options:\n");
  397. fprintf(stdout, "LP : Line Printer DV : Duplex printing vert.\n");
  398. fprintf(stdout, "LJ : HPLaserJet DH : Duplex printing horz.\n");
  399. fprintf(stdout, "PS : PostScript F : No force form feed\n");
  400. fprintf(stdout, "PSF <file>: PostScript w/header L : Landscape\n");
  401. fprintf(stdout, "CZ : 'Z' Cartridge P : Portrait\n");
  402. fprintf(stdout, "CB : 'B' Cartridge PC : Portrait Condensed\n");
  403. fprintf(stdout, "CP <n> : Set CodePage S : Force form feed\n");
  404. fprintf(stdout, "EA : Set CodePage to 850 # : Number of rows\n");
  405. fprintf(stdout, "See PPR.HLP for further information and usage descriptions.\n");
  406. exit(1);
  407. }
  408. // VARARGS
  409. void __cdecl Fatal(char *sz, ...)
  410. {
  411. va_list args;
  412. va_start(args, sz);
  413. fprintf(stderr, "ppr: ");
  414. vfprintf(stderr, sz, args);
  415. fprintf(stderr, "\n");
  416. va_end(args);
  417. MyClosePrinter();
  418. ResetRedir();
  419. exit(1);
  420. }
  421. void __cdecl Error(char *sz, ...)
  422. {
  423. va_list args;
  424. va_start(args, sz);
  425. fprintf(stderr, "ppr: ");
  426. vfprintf(stderr, sz, args);
  427. fprintf(stderr, "\n");
  428. va_end(args);
  429. }
  430. char * SzGetArg(ppch, pargc, pargv)
  431. char **ppch;
  432. int *pargc;
  433. char **pargv[];
  434. // return the string following the current switch; no whitespace required
  435. {
  436. char *tmp;
  437. if (*(*ppch+1))
  438. {
  439. (*ppch)++;
  440. tmp = *ppch;
  441. *ppch += strlen(*ppch) - 1;
  442. // return(*ppch);
  443. return( tmp );
  444. }
  445. else
  446. {
  447. (*pargv)++;
  448. if (--*pargc)
  449. return((*pargv)[0]);
  450. else
  451. return(NULL);
  452. }
  453. }
  454. int WGetArg(ppch, pargc, pargv, nDefault, szXpl)
  455. // return the number following the current switch; no whitespace required
  456. char **ppch;
  457. int *pargc;
  458. char **pargv[];
  459. int nDefault;
  460. char * szXpl;
  461. {
  462. int nRet;
  463. char chSwitch;
  464. chSwitch = **ppch;
  465. if (*(*ppch+1))
  466. {
  467. nRet = atoi(++*ppch);
  468. *ppch += strlen(*ppch) - 1;
  469. }
  470. else
  471. {
  472. if ((*pargc>1) &&
  473. strlen((*pargv)[1]) == strspn((*pargv)[1], "0123456789") )
  474. {
  475. (*pargc)--;
  476. nRet = atoi((++*pargv)[0]);
  477. }
  478. else
  479. nRet = nDefault;
  480. }
  481. if (nRet<0)
  482. {
  483. Fatal("negative %s (switch %c)", szXpl, chSwitch);
  484. return 0;
  485. }
  486. else
  487. return(nRet);
  488. }
  489. void DoIniOptions() // Get any options from the TOOLS.INI file (OPTS=...)
  490. {
  491. #define cargsMax 25
  492. FILE *pfile;
  493. char *szT;
  494. char rgbSW[cchArgMax];
  495. int argc;
  496. char *pchSp;
  497. char *argvT[cargsMax]; // structure to build to be like argv
  498. char **pargvT = argvT;
  499. // if ((pfile = swopen()) != NULL) {
  500. if ((pfile = swopen("$INIT:Tools.INI", "ppr")) != NULL) {
  501. /* 'PPR' tag was found in 'TOOLS.INI' */
  502. if (fVerify || fList) {
  503. fprintf (stdout, "TOOLS.INI contains the following entries:\n");
  504. fprintf (stdout, "[ppr]\n");
  505. }
  506. while (swread(rgbSW, cchArgMax, pfile) != 0) {
  507. /* a 'switch line' was found in the file */
  508. szT = rgbSW + strspn(rgbSW, " \t"); // skip spaces and tabs
  509. if (fVerify || fList) {
  510. fprintf (stdout, " %s \n", szT);
  511. }
  512. // an entry "opts=<options>" will cause the options
  513. // to be set from the parameter file.
  514. if (_strnicmp(szT, OPTS, strlen(OPTS)) == 0) {
  515. if ((szT = strchr(szT, '=')) != NULL) {
  516. szT++; // advance past '='
  517. while (szT[0] == ' ') szT++; // advance past beginning spaces
  518. if(*szT) {
  519. argvT[0] = 0;
  520. for (argc = 1; argc < cargsMax && szT[0] != '\0'; argc++)
  521. {
  522. argvT[argc] = szT;
  523. pchSp = strchr(szT, ' ');
  524. if (pchSp == '\0')
  525. break;
  526. *pchSp = 0;
  527. szT = pchSp + 1;
  528. while (szT[0] == ' ') {
  529. szT++;
  530. }
  531. }
  532. argc++;
  533. argvT[argc] = '\0';
  534. DoArgs(&argc, &pargvT);
  535. }
  536. }
  537. }
  538. }
  539. swclose(pfile);
  540. }
  541. }
  542. static void DoArgs(pargc, pargv) // Parse the argument string.
  543. int * pargc;
  544. char **pargv[];
  545. {
  546. int argc, vArgc; // vArgc - for verify mode
  547. char **argv, **vArgv;
  548. char *p;
  549. argc = vArgc = *pargc;
  550. argv = vArgv = *pargv;
  551. argc--;
  552. argv++;
  553. p = argv[0];
  554. while (argc && (*p == '/' || (*p=='-' && *(p+1)!='\0')))
  555. {
  556. while (*++p)
  557. {
  558. switch (tolower(*p))
  559. {
  560. case 'a':
  561. chBanner = *++p;
  562. break;
  563. case 'b':
  564. cBanner = WGetArg(&p, &argc, &argv, 1, "number of banners");
  565. break;
  566. case 'c':
  567. cCopies= WGetArg(&p, &argc, &argv, 1, "number of copies");
  568. break;
  569. case 'd':
  570. case 'D':
  571. if (*p=='D') // <-- since we did a 'tolower'
  572. fDelete = TRUE;
  573. break;
  574. case 'e':
  575. colTabCom = WGetArg(&p, &argc, &argv, 8, "tabs");
  576. break;
  577. case 'f':
  578. fForceFF = FALSE;
  579. break;
  580. case 'g':
  581. case 'o':
  582. colGutter = WGetArg(&p, &argc, &argv, colGutDef, "offset");
  583. break;
  584. case 'h':
  585. szBanner = SzGetArg(&p, &argc, &argv);
  586. break;
  587. case 'l':
  588. fList = TRUE;
  589. break;
  590. case 'm':
  591. case 'M':
  592. fBorder = TRUE;
  593. fLabel = TRUE;
  594. if (*p=='M') // <-- since we did a 'tolower'
  595. fConfidential = TRUE;
  596. else
  597. szStamp = SzGetArg(&p, &argc, &argv);
  598. break;
  599. case 'n':
  600. fNumber = TRUE;
  601. break;
  602. case 'p':
  603. szPDesc = SzGetArg(&p, &argc, &argv);
  604. break;
  605. case 'q': // Enable print of queue
  606. fQueue = TRUE;
  607. break;
  608. case 'r':
  609. fRaw = TRUE;
  610. break;
  611. case 's':
  612. fSilent = TRUE;
  613. break;
  614. case 't':
  615. if (!fConfidential && szStamp==NULL)
  616. {
  617. fBorder = FALSE;
  618. fLabel = FALSE;
  619. }
  620. break;
  621. case 'v':
  622. fVerify = TRUE;
  623. break;
  624. case 'w':
  625. defWidth = WGetArg(&p, &argc, &argv, 80, "Width of column");
  626. break;
  627. case 'x':
  628. usCodePage = 850;
  629. break;
  630. case '1': case '2':
  631. case '3': case '4':
  632. case '5': case '6':
  633. case '7': case '8':
  634. case '9':
  635. cColCom = *p - '0';
  636. break;
  637. default :
  638. Error("invalid switch: %s\n", p);
  639. case '?':
  640. case 'z':
  641. Usage();
  642. break;
  643. }
  644. }
  645. argc--;
  646. argv++;
  647. p = argv[0];
  648. }
  649. if (fVerify) {
  650. vArgv++; // skip over program name, or null entry
  651. while (--vArgc) fprintf (stdout, "%s ", *(vArgv++));
  652. fprintf (stdout, "\n\n");
  653. }
  654. *pargv = argv;
  655. *pargc = argc;
  656. }
  657. void DoOptSz(szOpt)
  658. /* scan and handle printer options
  659. *
  660. * Entry: szOpt - string containing printer options
  661. *
  662. * Exit: global flags set according to printer options
  663. *
  664. * An option string has the format:
  665. * [, [(LJ [P] [L] [CB|CZ] [D|DV|DH]) | (LP [# lines]) | (PS [P] [L])] [F] [S] [, [tabstop] [, [# columns]]]]
  666. *
  667. * Note: Although this is called by the lpprint module,
  668. * It is here because it deals with command line arguments
  669. * and setting the global print control flags.
  670. */
  671. register char * szOpt;
  672. {
  673. char szBuf[cchArgMax];
  674. BOOL fLJ = FALSE;
  675. BOOL fLP = FALSE;
  676. BOOL fPS = FALSE;
  677. if (*szOpt++ == ',')
  678. {
  679. while (*szOpt != ',' && *szOpt)
  680. {
  681. szOpt = SzGetSzSz(szOpt, szBuf);
  682. /* First the different printer types*/
  683. // Laser Jet
  684. if (_strcmpi(szBuf, "lj") == 0 && !fLP && !fPS)
  685. {
  686. fLJ = TRUE;
  687. fLaser = TRUE;
  688. fPostScript = FALSE;
  689. // don't set border here so -t works
  690. fPortrait = FALSE;
  691. colMac = colLJMax;
  692. rowMac = rowLJMax;
  693. }
  694. // Line Printer
  695. else if (_strcmpi(szBuf, "lp") == 0 && !fLJ && !fPS)
  696. {
  697. fLP = TRUE;
  698. fLaser = FALSE;
  699. fPostScript = FALSE;
  700. fBorder = FALSE;
  701. fPortrait = TRUE;
  702. colMac = colLPMax;
  703. rowMac = rowLPMax;
  704. }
  705. // PostScript with custom header
  706. else if (_strcmpi(szBuf, "psf") == 0 && !fLP && !fLJ)
  707. {
  708. fPS = TRUE;
  709. fLaser = FALSE;
  710. fPostScript = TRUE;
  711. fPortrait = FALSE;
  712. fPCondensed = FALSE;
  713. colMac = colPSMax;
  714. rowMac = rowPSMax;
  715. fPSF = TRUE;
  716. szOpt = SzGetSzSz(szOpt, szPSF);
  717. }
  718. // PostScript
  719. else if (_strcmpi(szBuf, "ps") == 0 && !fLP && !fLJ)
  720. {
  721. fPS = TRUE;
  722. fLaser = FALSE;
  723. fPostScript = TRUE;
  724. // don't set border here so -t works
  725. fPortrait = FALSE;
  726. fPCondensed = FALSE;
  727. colMac = colPSMax;
  728. rowMac = rowPSMax;
  729. }
  730. /* Now the modifiers */
  731. // Column width to print in
  732. else if (_strcmpi(szBuf, "c") == 0) {
  733. szOpt = SzGetSzSz(szOpt, szBuf);
  734. if (atoi(szBuf) != 0) {
  735. defWidth = atoi(szBuf);
  736. } else {
  737. Fatal ("Non-Numeric Columns specified.");
  738. }
  739. }
  740. // LaserJet with the 'B' cartridge
  741. else if (_strcmpi(szBuf, "cb") == 0 && fLJ)
  742. usSymSet = BEGINLANDROMAN8;
  743. // LaserJet emulation of 'IBM' text
  744. else if (_strcmpi(szBuf, "ci") == 0 && fLJ) {
  745. usSymSet = BEGINLANDIBMPC; // for the LaserJet
  746. usCodePage = 850;
  747. }
  748. // Code Page specification
  749. else if (_strcmpi(szBuf, "cp") == 0) {
  750. szOpt = SzGetSzSz(szOpt, szBuf);
  751. if (atoi(szBuf) != 0) {
  752. usCodePage = (USHORT)atoi(szBuf);
  753. } else {
  754. Fatal ("Non-Numeric CodePage specified.");
  755. }
  756. }
  757. // LaserJet with the 'Z' cartridge
  758. else if (_strcmpi(szBuf, "cz") == 0 && fLJ)
  759. usSymSet = BEGINLANDUSASCII;
  760. // Prep for double sided printing, binding on long edge
  761. else if ((_strcmpi(szBuf, "d") == 0 || _strcmpi(szBuf, "dv") == 0))
  762. fVDuplex = TRUE;
  763. // Prep for double sided printing, binding on short edge
  764. else if (_strcmpi(szBuf, "dh") == 0)
  765. fHDuplex = TRUE;
  766. // Extended Ascii printing - shortcut to CP 850
  767. else if (_strcmpi(szBuf, "ea") == 0) {
  768. usCodePage = 850;
  769. }
  770. // Turn off forced form feed
  771. else if (_strcmpi(szBuf, "f") == 0)
  772. fForceFF = FALSE;
  773. // Landscape
  774. else if (_strcmpi(szBuf, "l") == 0 && (fLJ || fPS))
  775. {
  776. fPortrait = FALSE;
  777. colMac = fLJ ? colLJMax : colPSMax;
  778. }
  779. // Portrait
  780. else if (_strcmpi(szBuf, "p") == 0 && (fLJ || fPS))
  781. {
  782. fPortrait = TRUE;
  783. fBorder = FALSE;
  784. colMac = fLJ ? colLJPortMax : colPSPortMax;
  785. }
  786. // Portrait Condensed
  787. else if (_strcmpi(szBuf, "pc") == 0 && (fLJ || fPS))
  788. {
  789. fPortrait = TRUE;
  790. fPCondensed = TRUE;
  791. fBorder = TRUE;
  792. colMac = fLJ ? colLJPortMax : colPSPortMax;
  793. if (cColCom == 0) cColCom = 2;
  794. }
  795. // Number of rows (same as just # by itself, but more descriptive)
  796. else if (_strcmpi(szBuf, "r") == 0) {
  797. szOpt = SzGetSzSz(szOpt, szBuf);
  798. if (atoi(szBuf) != 0) {
  799. rowMac = atoi(szBuf);
  800. if (rowMac > rowMax)
  801. Fatal ("Too many rows (%d) specified.", rowMac);
  802. } else {
  803. Fatal ("Non-Numeric Rows specified.");
  804. }
  805. }
  806. // Force Form Feed
  807. else if (_strcmpi(szBuf, "s") == 0)
  808. fForceFF = TRUE;
  809. // Number of rows
  810. else if (isdigit(szBuf[0]) && fLP) {
  811. rowMac = atoi(szBuf);
  812. if (rowMac > rowMax)
  813. Fatal("page size %d to long", rowMac);
  814. }
  815. else if (_strcmpi(szBuf, "") == 0)
  816. // empty string
  817. ;
  818. else
  819. Fatal("unrecognized printer type option %s", szBuf);
  820. }
  821. /* After the first comma - Tab stop specification */
  822. if (*szOpt++ == ',')
  823. { // tabstop
  824. szOpt = SzGetSzSz(szOpt, szBuf);
  825. if (isdigit(szBuf[0]))
  826. colTab = atoi(szBuf);
  827. else if (szBuf[0] != '\0')
  828. Fatal("tabstop %s is not a number", szBuf);
  829. /* After the second comma - Column specification (1-9) */
  830. if (*szOpt++ == ',')
  831. { // # columns (1 - 9)
  832. szOpt = SzGetSzSz(szOpt, szBuf);
  833. if (isdigit(szBuf[0])) // 0 means default # col
  834. cCol = szBuf[0] - '0';
  835. else if (szBuf[0] != '\0')
  836. Fatal("number columns (%s) must be digit 1-9",szBuf);
  837. }
  838. }
  839. }
  840. }