summaryrefslogblamecommitdiffstats
path: root/private/sdktools/ppr/ppr.c
blob: 90851abbfc9dfb4fa65078754741330f6cb1521d (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































                                                                                                                 
/*  lpr.c - fancy paginator for laserprinters
 *
 *  Author: Mark Taylor
 *
 *  Modifications:
 *
 *      12/85   Mark Zbikowski  rewrite to work cleaner
 *      4/3/86  MZ              Single print jobs will advance page
 *      4/3/86  MZ              use tools.ini for default printer setup
 *      4/20/86 Mike Hanson     add banner, etc (add features to make like
 *                              lpr from PS, extensively reorganized, etc)
 *      6/6/86  Jay Sipelstein  added S and L options to printer desc.
 *                              Trim trailing blanks and blank lines.
 *                              Set mode before raw printing.
 *      7/8/86  Byron Bishop    Add -q to cause print queue to be printed.
 *                              Fixed bug so -# and -e flags take priority
 *                              over default settings.  Runs of blanks
 *                              replaced by escape sequences to reduce
 *                              file size.
 *      8/31/86 Craig Wittenberg Added support for PostScript.  Used the VMI
 *                              on the LaserJet instead of line/inch to get 62
 *                              lines on one page (two for header).  Cleaned
 *                              up iLine (now rowLine) and indentation.
 *      10/10/86 John Rae-Grant Added -g flag to allow gutter in portrait mode.
 *                              $USER can now be a list of directories to
 *                              search for tools.ini in. Default printer can
 *                              be specified in tools.ini file.  Modified
 *                              landscape mode page numbering to avoid three
 *                              hole punch obliteration.
 *      1/27/87 Craig Wittenberg Cleaned up whole program; no change in
 *                              functionality.
 *      1/28/87 Thom Landsberger  Added CB and CZ (=default) flags to the LJ
 *                              printer description to support the 'Z' font
 *                              cartridge in landscape mode
 *      3/23/87 Thom Landsberger  Port to Xenix 286 and 68k;  environment
 *                              setting of parameters accepted as default
 *                              and with higher priority than tools.ini/.pprrc;
 *                              implemented -m, -M, -c command switches;
 *                              restructured command interpretation.
 *      4/10/87 Craig Wittenberg  interrupt signal ignored if that is the
 *                              status when ppr is started
 *      4/14/87 Thom Landsberger  only pure digit strings accepted as
 *                              numeric command line arguments
 *      6/05/87 Thom Landsberger  double sided printing on HP LJ 2000;
 *                              '/' no switch character on Xenix;
 *                              'ppr -q -' now does print from stdin.
 *      7/5/87  Craig Wittenberg changed fDuplex? names to f?Duplex so they
 *                              compile in 68k Xenix.  Invoked ftp with command
 *                              line arguments rather than printing the commands
 *                              to stdin.  -t now removes label (used to require
 *                              -m "").
 *
 *                              Ppr reads /etc/default/ppr if there is not
 *                              $HOME/.pprrc.  Duplex printing now does not
 *                              print on the back of the banner page (even if
 *                              not raw).  Added -s flag: disables messages
 *                              which indicate ppr's progress.  Changed the PS
 *                              setup to avoid VMErrors.  Allowed the default
 *                              printer in the tools.ini/.pprrc file to have
 *                              options (e.g. default=lpt1, LJ L).  Changed the
 *                              default printer on Xenix from net9 to net.
 *
 *      ~8/1/87 Ralph Ryan      Ported to OS/2 LanManager
 *
 *     11/24/87 Craig Wittenberg Rearranged sources - mostly to isloate the OS
 *                              specific network routines in lplow.c
 *                              Ppr now uses clem as the transfer machine for
 *                              DOS print jobs when /usr/eu/bin/ppr is not
 *                              present (indicating a machine in another
 *                              division).
 *
 *      12/2/87 Alan Bauer      Version 2.5
 *                              Final porting to OS/2 LAN Manager.  Mainly
 *                              polished up network routines to work properly
 *                              Released to OS/2 people, DOSENV, NEWENV, and
 *                              new 68K version.
 *
 *      3/17/88 Alan Bauer      Version 2.6
 *                              Fixed so that the username is still printed in
 *                              lower left corner of the file listing when the
 *                              "no banner" option is specified (ppr -b0).
 *                              Ppr -? now prints to stdout rather than stderr.
 *                              Now supports ppr -q for OS/2.
 *
 *      4/04/88 Alan Bauer      Version 2.7
 *                              Added -c<n> option to print <n> copies of the
 *                              specified files.
 *                              Seperates large print jobs into roughly 100K
 *                              amounts.
 *                              Better feed back on PRINTING progress.
 *                              Fixed so that an empty password is now passed to
 *                              mkalias correctly (Xenix 386 version).
 *                              Now map ppr -p "xenix name" to
 *                                    "mkalias name name printing [password]".
 *                              Errors opening input files no longer abort; just
 *                              go on to the next file.
 *
 *      4/05/88 Alan Bauer      Version 2.71
 *                              Fixed problem with last file to be printed
 *                              putting the current print job over 100K,
 *                              therefore causing new print job to be performed
 *                              (with no more files to be printed).
 *
 *      4/13/88 Alan Bauer      Version 2.8
 *                              Added ability to specify options in TOOLS.INI
 *                              file.
 *
 *      5/19/88 Alan Bauer      Version 2.81
 *                              Fixed General Protection Fault in OS/2 dealing
 *                              with login usernames which are more than 12
 *                              characters long.
 *
 *      6/20/88 Alan Bauer      Version 2.82
 *                              Fixed LANMAN error message handling problems
 *                              and a bug where ppr failed if redirection to
 *                              the same printer as established in the environ-
 *                              ment variable was already set up.
 *
 *      3/3/89 Robert Hess      Version 2.9
 *                              Completely changed PostScript support.
 *                              Added 'PC' (Portrait Condensed) and 'PSF'
 *                              (PostScriptFile) printer specific switches.
 *
 *      3/22/89 Robert Hess     Version 2.10
 *                              Modifications to how 'FormFeed' was handled
 *                              for PostScript usage.
 *
 *      7/12/89 Robert Hess     Version 2.11
 *                              Fixed a bug that prevented lengthy Postscript
 *                              files to be printed.
 *
 *      9/14/89 Robert Hess     Version 2.12
 *                              Fixed -M option in PostScript code.
 *                              Fixed the 'opts=<option>' parsing from
 *                              TOOLS.INI (wasn't allowing leading spaces)
 *
 *      10/6/89 Robert Hess     Version 2.12b
 *                              Minor fix, repaired linking to include
 *                              SetArgV.OBJ (to automatically expand
 *                              wildcards in filenames - ooops!), and
 *                              added error handling to the '-q' command.
 *
 *      10/20/89 Robert Hess    Version 2.13
 *                              Date and time of *FILE* is now printed at
 *                              the bottom of the page for PostScript.
 *                              (...ooops...)
 *
 *      12/06/89 Robert Hess    Version 2.14
 *                              Added switches -v (verify, for debugging),
 *                              and -w (column width).
 *
 *      4/9/90 Scott Means      Version 2.15
 *                              Support of non-printable IBM characters and
 *                              added progress indicator.
 *
 *      4/18/90 Robert Hess     Version 2.2
 *                              Re-Wrote postscript header code to allow
 *                              full sensing of actual printer area, and
 *                              corrected several bugs in old header.
 *                              Fixed 'pathname' for network drives
 *                              Fixed '-t' switch for Postscript mode
 *                              Added 'psuedo' printer name support.
 *
 *      6/15/90 Robert Hess     Version 2.3
 *                              Added better implementation of 'extended
 *                              ascii' mode. Added more debugging code
 *                              for network usage. Added R and C printer
 *                              switches to better support odd sized paper.
 *                              Improved 'usage' text.
 *                              Switched to using some TOOLSVR api calls.
 *                              General cleanup and bug fixes.
 *                              Enlisted into \\ToolSvr\Build project.
 *
 *      7/26/90 Robert Hess     Version 2.3a
 *                              Fixed a couple bugs. Added '-l' option for
 *                              listing out contents of TOOLS.INI. Final
 *                              cleanup prior to general release.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <process.h>
#include <signal.h>
#include <ctype.h>
#include <windows.h>
#include <tools.h>
#include "lpr.h"


/* 175 columns:
 *                        0   1                    174
 *  single page:        <bar> 173 columns of text <bar>
 *                        0   1               86   87  88              173 174
 *  double page:        <bar> 86 columns of text <bar> 86 columns of text <bar>
 */

long        lcbOutLPR = 0l;             //  total amount printed in this job
int         cCol = 0;                   //  number of columns being displayed
int         cColCom = 0;                /* number of columns as specified in
                                           command line.                      */
int         colTabCom = 0;              /* number of spaces per tab specified
                                           in command line.   Number of spaces
                                           per tab, colTab, is declared in
                                           lpfile.c                           */
int         colGutter = 0;              //  number of spaces in gutter
int         colText   = 0;              //  column where text starts
int         cCopies = 1;                //  number of copies to print
int         colWidth;                   //  printable spaces in each column

int         defWidth = 0; //  <- NEW... to override colWidth calculation

int         colMac = colLJMax;          //  maximum columns on a page
int         rowMac = rowLJMax;          //  maximum rows on a page
int         rowPage;                    /* number of printable lines per page
                                           including header on top            */

char *aszSymSet[] = {   // supported Laserjet symbol sets
    "\033&l1o5.8C\033(0U\033(s0p16.67h8.5v0T",
    "\033&l1o5.8C\033(8U\033(s0p16.67h8.5v0T",
    "\033&l1o5.8C\033(10U\033(s0p16.67h8.5v0T"
};

BOOL        fNumber = FALSE;            //  TRUE => show line numbers
BOOL        fDelete = FALSE;            //  TRUE => delete file after printing
BOOL        fRaw = FALSE;               //  TRUE => print in raw mode
BOOL        fBorder = TRUE;             //  TRUE => print borders
BOOL        fLabel = TRUE;              //  TRUE => print page heading
BOOL        fLaser = TRUE;              //  TRUE => print on an HP LaserJet
BOOL        fPostScript = FALSE;        //  TRUE => print on postscript printer

BOOL        fPSF = FALSE;               //  TRUE => Use alternate PS Header
char        szPSF[cchPthMax] = "";      //  pathname of alternate PS Header
BOOL        fPCondensed = FALSE;        //  TRUE => Condensed portrait mode PS

BOOL        fConfidential = FALSE;      //  TRUE => stamp pages and banner
BOOL        fVDuplex = FALSE;           //  TRUE => double sided, vertical bind
BOOL        fHDuplex = FALSE;           //  TRUE => ditto, but horizontal bind
BOOL        fSilent = FALSE;            //  TRUE => no messages
int         cBanner = -1;               //  # of banners; <0 only 1 group
char        chBanner = ' ';             //  used to form banner characters
char        *szBanner = NULL;           //  banner string, use fname if NULL
char        *szStamp = NULL;            //  additional label put on each page
BOOL        fForceFF = TRUE;            //  TRUE => end at top of page
BOOL        fPortrait = FALSE;          //  TRUE => print in portrait mode
BOOL        fQueue = FALSE;             //  TRUE => list print queue
USHORT      usSymSet = 0;               //  symbol set to use on Laserjet
                                        //  FALSE => select Roman-8 symbol set
USHORT      usCodePage = 0;             //  0 = convert extended ascii to '.'
BOOL        fVerify = FALSE; //  TRUE => dump out data on what we are doing
BOOL        fList   = FALSE; //  TRUE => use with fVerify to prevent printing

char        szPass[cchArgMax] = "";

static void Usage(void);
static void DoArgs(int *, char **[]);
void Abort(void);
void DoIniOptions(void);


int _CRTAPI1 main(argc, argv)
int argc;
char **argv;
    {
    int err, iCopies;

#ifdef notdefined
    if (signal(SIGINT, SIG_IGN) != SIG_IGN)
        //  if not ignored upon startup, set our abort handler
        signal(SIGINT, (void (_cdecl *)(int))Abort);
#endif

//  hack to get verify and list to work *before* command line is parsed
    ConvertAppToOem( argc, argv );
    if( argc > 1 ) {
        if (argv[1][1] == 'v') {
            fVerify = TRUE;
        }
        if (argv[1][1] == 'l') {
            fList   = TRUE;
        }
        if (fVerify) {
            fprintf (stdout, "\n");
        }
    }

    DoIniOptions();

    if (fVerify) {
        fprintf (stdout, "Seen on Command Line:\n");
    }

    DoArgs(&argc, &argv);
    SetupPrinter();
    SetupRedir();

    //  -------------- modifications to switches and precalculated values

    //  don't allow guttering in landscape mode
    if (!fPortrait)
        colGutter = 0;

    //  set global for start of text
    colText = colGutter + (fNumber ? cchLNMax : 0);

    //  set # columns if set in command line.
    if (cColCom)
        cCol = cColCom;
    else if (cCol == 0)
        cCol = fPortrait ? 1 : 2;

    //  set # of spaces per tab if set in command line.
    if (colTabCom)
        colTab = colTabCom;

    colWidth = colMac;
    if (fPostScript && fPCondensed) {
        colWidth = colMac *= 2;
    }

    if (defWidth > 0) colWidth = defWidth;

    if (fLaser && usCodePage == 850) {
        usSymSet = BEGINLANDIBMPC; // for the LaserJet
    }

    if (cCol != 1) {
        //  more than one column: divide into separate columns with divider
        colWidth = (colMac-1) / cCol - 1;
        if (defWidth > 0) colWidth = defWidth;
        colMac = (colWidth + 1) * cCol + 1;
    }

    //  rowPage includes border line(s) at top of page
    rowPage = rowMac;
    if (fBorder || fLabel) {
        if (!fLaser && !fPostScript && fPortrait) {
            //  same bottom margin as old Xenix ppr
            rowPage -= 5;
        } else {
            //  don't print on bottom line
            rowPage -= 1;
        }
    }

    if (!fLaser && !fPostScript && cBanner == -1) {
        //  line printer for which the default banner setup is required
        cBanner = -2;
    }

    //  ----------------- end modification of switches

    if (fVerify) fprintf (stdout, "\n"); //  just to clean things up a little
    fprintf(stdout, "PPR version: "VERSION"\n");
    fprintf(stdout, "----------------------------------------------------------------------------\n");

    if (argc == 0) {
        /* No file names were listed... assume user wants <stdin> */
        if (!fQueue && !fList) {
            //  print stdin
            fprintf (stdout, "Printing from: <stdin> Press <Ctrl-Z> to end.\n");
            MyOpenPrinter();
            FileOut("");
            MyClosePrinter();
        }
    } else {
        //  print file(s)
        MyOpenPrinter();
        while (argc) {
            //  print more copies if wanted
            for(iCopies = 1; iCopies <= cCopies; iCopies++) {
                FileOut(*argv);

                //  end this print job if more than 100K has been printed
                //  thus far.  Then start next print job.
                if (lcbOutLPR > 100000 && argc != 1) {
                    lcbOutLPR = 0l;
                    MyClosePrinter();
                    fFirstFile = TRUE;
                    MyOpenPrinter();          //  ready to start next job
                }
            }
            argc--;
            argv++;
        }
        MyClosePrinter();
    }

    /* if user wants to print queue, spawn a process to do the printing.
       The process will inherit the current environment including the
       redirection of szPName.
    */
    if (fQueue) {
        fprintf (stdout, "[Net Print %s]:\n", szNet);
        err = _spawnlp(P_WAIT,"net","net","print",szNet,NULL);
        if (err)
            if (err == -1)
                fprintf (stdout, "- Error : Unable to Spawn Queue Status Request -\n");
            else
                fprintf (stdout, "- Error Returned from Queue Status Request: %d - \n", err);
    }
    ResetRedir();
    return 0;
} /* main */




void Abort()
/*  SIGINT handler to abort printing gracefully
 *
 *      Warning: Never returns (exits via Fatal).
 */
{
    Fatal("terminated by user", NULL);
} /* Abort */




static void Usage()
{
    fprintf(stdout, "PPR version: "VERSION"   by: "ANALYST"\n");
    fprintf(stdout, "Usage: ppr [-switches] files(s)\n");
    fprintf(stdout, "-<digit>   :Print in columns (1-9)    -n         : Print line numbers\n");
    fprintf(stdout, "-b <n>     :Print <n> banners         -o <n>     : Offset <n> for gutter\n");
    fprintf(stdout, "-c <n>     :Print <n> copies          -q         : List print queue status\n");
    fprintf(stdout, "-D         :Delete file after print   -s         : Supress progress message\n");
    fprintf(stdout, "-e <n>     :Expand tabs to <n>        -t         : Supress page headers\n");
    fprintf(stdout, "-f         :NO formfeed at end        -r         : Print in raw mode\n");
    fprintf(stdout, "-h <string>:Use <string> for header   -v         : Verbose (for debugging)\n");
    fprintf(stdout, "-m <string>:Stamp <string> on page    -w <n>     : Page width in characters\n");
    fprintf(stdout, "-M         :\"Microsoft Confidential\"  -p <string>: Printer description\n");
    fprintf(stdout, "\n");
    fprintf(stdout, "Printer Description: ppr -p \"<port>,<type> <options>,<columns>,<tabstops>\"\n");
    fprintf(stdout, "Types & Options:\n");
    fprintf(stdout, "LP        : Line Printer              DV        : Duplex printing vert.\n");
    fprintf(stdout, "LJ        : HPLaserJet                DH        : Duplex printing horz.\n");
    fprintf(stdout, "PS        : PostScript                F         : No force form feed\n");
    fprintf(stdout, "PSF <file>: PostScript w/header       L         : Landscape\n");
    fprintf(stdout, "CZ        : 'Z' Cartridge             P         : Portrait\n");
    fprintf(stdout, "CB        : 'B' Cartridge             PC        : Portrait Condensed\n");
    fprintf(stdout, "CP <n>    : Set CodePage              S         : Force form feed\n");
    fprintf(stdout, "EA        : Set CodePage to 850       #         : Number of rows\n");
    fprintf(stdout, "See PPR.HLP for further information and usage descriptions.\n");

    exit(1);
}



//  VARARGS
void Fatal(char *sz, ...)
{
    va_list args;

    va_start(args, sz);
    fprintf(stderr, "ppr: ");
    vfprintf(stderr, sz, args);
    fprintf(stderr, "\n");
    va_end(args);
    MyClosePrinter();
    ResetRedir();
    exit(1);
}


void Error(char *sz, ...)
{
    va_list args;

    va_start(args, sz);
    fprintf(stderr, "ppr: ");
    vfprintf(stderr, sz, args);
    fprintf(stderr, "\n");
    va_end(args);
}


char * SzGetArg(ppch, pargc, pargv)
char **ppch;
int *pargc;
char **pargv[];
//  return the string following the current switch; no whitespace required
        {
        char *tmp;
        if (*(*ppch+1))
                {
                (*ppch)++;
                tmp = *ppch;
                *ppch += strlen(*ppch) - 1;
                //  return(*ppch);
                return( tmp );
                }
        else
                {
                (*pargv)++;
                if (--*pargc)
                        return((*pargv)[0]);
                else
                        return(NULL);
                }
        }




int WGetArg(ppch, pargc, pargv, nDefault, szXpl)
//  return the number following the current switch; no whitespace required
char **ppch;
int *pargc;
char **pargv[];
int nDefault;
char * szXpl;
        {
        int nRet;
        char chSwitch;

        chSwitch = **ppch;
        if (*(*ppch+1))
                {
                nRet = atoi(++*ppch);
                *ppch += strlen(*ppch) - 1;
                }
        else
                {
                if ((*pargc>1) &&
                    strlen((*pargv)[1]) == strspn((*pargv)[1], "0123456789") )
                        {
                        (*pargc)--;
                        nRet = atoi((++*pargv)[0]);
                        }
                else
                        nRet = nDefault;
                }

        if (nRet<0)
                Fatal("negative %s (switch %c)", szXpl, chSwitch);
        else
                return(nRet);
        }


void DoIniOptions() //  Get any options from the TOOLS.INI file (OPTS=...)
        {
#define cargsMax 25
    FILE *pfile;
    char *szT;
    char rgbSW[cchArgMax];
    int argc;
    char *pchSp;
    char *argvT[cargsMax];          //  structure to build to be like argv
    char **pargvT = argvT;

//    if ((pfile = swopen()) != NULL) {
    if ((pfile = swopen("$INIT:Tools.INI", "ppr")) != NULL) {
        /* 'PPR' tag was found in 'TOOLS.INI' */
        if (fVerify || fList) {
            fprintf (stdout, "TOOLS.INI contains the following entries:\n");
            fprintf (stdout, "[ppr]\n");
        }
        while (swread(rgbSW, cchArgMax, pfile) != 0) {
            /* a 'switch line' was found in the file */
            szT = rgbSW + strspn(rgbSW, " \t"); // skip spaces and tabs
            if (fVerify || fList) {
                fprintf (stdout, "    %s \n", szT);
            }
            //  an entry "opts=<options>" will cause the options
            //  to be set from the parameter file.
            if (_strnicmp(szT, OPTS, strlen(OPTS)) == 0) {

                if ((szT = strchr(szT, '=')) != NULL) {

                    szT++;  //  advance past '='
                    while (szT[0] == ' ') szT++; //  advance past beginning spaces
                    if(*szT) {
                        argvT[0] = 0;
                        for (argc = 1; argc < cargsMax && szT[0] != '\0'; argc++)
                                {
                            argvT[argc] = szT;
                            pchSp = strchr(szT, ' ');
                            if (pchSp == '\0')
                                    break;
                            *pchSp = 0;
                            szT = pchSp + 1;
                            while (szT[0] == ' ') {
                                    szT++;
                            }
                        }
                        argc++;
                        argvT[argc] = '\0';
                        DoArgs(&argc, &pargvT);
                    }
                }
            }
        }
        swclose(pfile);
    }
}


static void DoArgs(pargc, pargv) //  Parse the argument string.
int * pargc;
char **pargv[];
    {
    int argc, vArgc; //  vArgc - for verify mode
    char **argv, **vArgv;
    char *p;

    argc = vArgc = *pargc;
    argv = vArgv = *pargv;

    argc--;
    argv++;
    p = argv[0];

    while (argc && (*p == '/' || (*p=='-' && *(p+1)!='\0')))
        {
        while (*++p)
            {
            switch (tolower(*p))
                {

                case 'a':
                    chBanner = *++p;
                    break;

                case 'b':
                    cBanner = WGetArg(&p, &argc, &argv, 1, "number of banners");
                    break;

                case 'c':
                    cCopies= WGetArg(&p, &argc, &argv, 1, "number of copies");
                    break;

                case 'd':
                case 'D':
                    if (*p=='D')  // <-- since we did a 'tolower'
                        fDelete = TRUE;
                    break;

                case 'e':
                    colTabCom = WGetArg(&p, &argc, &argv, 8, "tabs");
                    break;

                case 'f':
                    fForceFF = FALSE;
                    break;

                case 'g':
                case 'o':
                    colGutter = WGetArg(&p, &argc, &argv, colGutDef, "offset");
                    break;

                case 'h':
                    szBanner = SzGetArg(&p, &argc, &argv);
                    break;

                case 'l':
                    fList = TRUE;
                    break;

                case 'm':
                case 'M':
                    fBorder = TRUE;
                    fLabel = TRUE;
                    if (*p=='M') // <-- since we did a 'tolower'
                        fConfidential = TRUE;
                    else
                        szStamp = SzGetArg(&p, &argc, &argv);
                    break;

                case 'n':
                    fNumber = TRUE;
                    break;

                case 'p':
                    szPDesc = SzGetArg(&p, &argc, &argv);
                    break;

                case 'q':     //  Enable print of queue
                    fQueue = TRUE;
                    break;
                case 'r':

                    fRaw = TRUE;
                    break;

                case 's':
                    fSilent = TRUE;
                    break;

                case 't':
                    if (!fConfidential && szStamp==NULL)
                        {
                        fBorder = FALSE;
                        fLabel  = FALSE;
                        }
                    break;

                case 'v':
                    fVerify = TRUE;
                    break;

                case 'w':
                    defWidth = WGetArg(&p, &argc, &argv, 80, "Width of column");
                    break;

                case 'x':
                    usCodePage = 850;
                    break;

                case '1': case '2':
                case '3': case '4':
                case '5': case '6':
                case '7': case '8':
                case '9':
                    cColCom = *p - '0';
                    break;

                default :
                    Error("invalid switch: %s\n", p);
                case '?':
                case 'z':
                    Usage();
                    break;
                }
            }
        argc--;
        argv++;
        p = argv[0];
        }

    if (fVerify) {
        vArgv++; //  skip over program name, or null entry
        while (--vArgc) fprintf (stdout, "%s ", *(vArgv++));
        fprintf (stdout, "\n\n");
    }

    *pargv = argv;
    *pargc = argc;
    }



void DoOptSz(szOpt)
/*   scan and handle printer options
 *
 *   Entry:     szOpt - string containing printer options
 *
 *   Exit:      global flags set according to printer options
 *
 *   An option string has the format:
 *     [, [(LJ [P] [L] [CB|CZ] [D|DV|DH]) | (LP [# lines]) | (PS [P] [L])] [F] [S] [, [tabstop] [, [# columns]]]]
 *
 *   Note: Although this is called by the lpprint module,
 *         It is here because it deals with command line arguments
 *         and setting the global print control flags.
 */
register char * szOpt;
    {
    char szBuf[cchArgMax];
    BOOL fLJ = FALSE;
    BOOL fLP = FALSE;
    BOOL fPS = FALSE;

    if (*szOpt++ == ',')
        {
        while (*szOpt != ',' && *szOpt)
            {
            szOpt = SzGetSzSz(szOpt, szBuf);

/* First the different printer types*/

            // Laser Jet
            if (_strcmpi(szBuf, "lj") == 0 && !fLP && !fPS)
                {
                fLJ       = TRUE;
                fLaser    = TRUE;
                fPostScript = FALSE;
                //  don't set border here so -t works
                fPortrait = FALSE;
                colMac    = colLJMax;
                rowMac    = rowLJMax;
                }

            // Line Printer
            else if (_strcmpi(szBuf, "lp") == 0 && !fLJ && !fPS)
                {
                fLP       = TRUE;
                fLaser    = FALSE;
                fPostScript = FALSE;
                fBorder   = FALSE;
                fPortrait = TRUE;
                colMac    = colLPMax;
                rowMac    = rowLPMax;
                }

            // PostScript with custom header
            else if (_strcmpi(szBuf, "psf") == 0 && !fLP && !fLJ)
                {
                fPS       = TRUE;
                fLaser    = FALSE;
                fPostScript = TRUE;
                fPortrait = FALSE;
                fPCondensed = FALSE;
                colMac    = colPSMax;
                rowMac    = rowPSMax;
                fPSF  = TRUE;
                szOpt = SzGetSzSz(szOpt, szPSF);
                }

            // PostScript
            else if (_strcmpi(szBuf, "ps") == 0 && !fLP && !fLJ)
                {
                fPS       = TRUE;
                fLaser    = FALSE;
                fPostScript = TRUE;
                //  don't set border here so -t works
                fPortrait = FALSE;
                fPCondensed = FALSE;
                colMac    = colPSMax;
                rowMac    = rowPSMax;
                }

/* Now the modifiers */

            // Column width to print in
            else if (_strcmpi(szBuf, "c") == 0) {
                szOpt = SzGetSzSz(szOpt, szBuf);
                if (atoi(szBuf) != 0) {
                    defWidth = atoi(szBuf);
                } else {
                        Fatal ("Non-Numeric Columns specified.");
                }
            }

            // LaserJet with the 'B' cartridge
            else if (_strcmpi(szBuf, "cb") == 0 && fLJ)
                usSymSet = BEGINLANDROMAN8;

            // LaserJet emulation of 'IBM' text
            else if (_strcmpi(szBuf, "ci") == 0 && fLJ) {
                usSymSet = BEGINLANDIBMPC; // for the LaserJet
                usCodePage = 850;
            }

            // Code Page specification
            else if (_strcmpi(szBuf, "cp") == 0) {
                szOpt = SzGetSzSz(szOpt, szBuf);
                if (atoi(szBuf) != 0) {
                    usCodePage = (USHORT)atoi(szBuf);
                } else {
                        Fatal ("Non-Numeric CodePage specified.");
                }

            }

            // LaserJet with the 'Z' cartridge
            else if (_strcmpi(szBuf, "cz") == 0 && fLJ)
                usSymSet = BEGINLANDUSASCII;

            // Prep for double sided printing, binding on long edge
            else if ((_strcmpi(szBuf, "d") == 0 || _strcmpi(szBuf, "dv") == 0))
                fVDuplex  = TRUE;

            // Prep for double sided printing, binding on short edge
            else if (_strcmpi(szBuf, "dh") == 0)
                fHDuplex  = TRUE;

            // Extended Ascii printing - shortcut to CP 850
            else if (_strcmpi(szBuf, "ea") == 0) {
                usCodePage = 850;
            }

            // Turn off forced form feed
            else if (_strcmpi(szBuf, "f") == 0)
                fForceFF  = FALSE;

            // Landscape
            else if (_strcmpi(szBuf, "l") == 0 && (fLJ || fPS))
                {
                fPortrait = FALSE;
                colMac    = fLJ ? colLJMax : colPSMax;
                }

            // Portrait
            else if (_strcmpi(szBuf, "p") == 0 && (fLJ || fPS))
                {
                fPortrait = TRUE;
                fBorder   = FALSE;
                colMac    = fLJ ? colLJPortMax : colPSPortMax;
                }

            // Portrait Condensed
            else if (_strcmpi(szBuf, "pc") == 0 && (fLJ || fPS))
                {
                fPortrait = TRUE;
                fPCondensed = TRUE;
                fBorder   = TRUE;
                colMac    = fLJ ? colLJPortMax : colPSPortMax;
                if (cColCom == 0) cColCom   = 2;
                }

            // Number of rows (same as just # by itself, but more descriptive)
            else if (_strcmpi(szBuf, "r") == 0) {
                szOpt = SzGetSzSz(szOpt, szBuf);
                if (atoi(szBuf) != 0) {
                    rowMac = atoi(szBuf);
                    if (rowMac > rowMax)
                        Fatal ("Too many rows (%d) specified.", (char*)rowMac);
                } else {
                        Fatal ("Non-Numeric Rows specified.");
                }
            }

            // Force Form Feed
            else if (_strcmpi(szBuf, "s") == 0)
                fForceFF  = TRUE;

            // Number of rows
            else if (isdigit(szBuf[0]) && fLP) {
                rowMac    = atoi(szBuf);
                if (rowMac > rowMax)
                        Fatal("page size %d to long", (char *)rowMac);
            }

            else if (_strcmpi(szBuf, "") == 0)
                //  empty string
                ;
            else
                Fatal("unrecognized printer type option %s", szBuf);
            }

/* After the first comma - Tab stop specification */

        if (*szOpt++ == ',')
            {                   //  tabstop
            szOpt = SzGetSzSz(szOpt, szBuf);

            if (isdigit(szBuf[0]))
                colTab = atoi(szBuf);
            else if (szBuf[0] != '\0')
                Fatal("tabstop %s is not a number", szBuf);

/* After the second comma - Column specification (1-9) */

            if (*szOpt++ == ',')
                {               //  # columns (1 - 9)
                szOpt = SzGetSzSz(szOpt, szBuf);

                if (isdigit(szBuf[0]))          //  0 means default # col
                    cCol = szBuf[0] - '0';
                else if (szBuf[0] != '\0')
                    Fatal("number columns (%s) must be digit 1-9",szBuf);
                }
            }
        }
    }