1 /*
2 * $Id: main.c,v 1.3 1992/10/07 22:06:08 craigs Exp $
3 *
4 * This code was written by Craig Southeren whilst under contract
5 * to Computer Sciences of Australia, Systems Engineering Division.
6 * It has been kindly released by CSA into the public domain.
7 *
8 * Neither CSA or me guarantee that this source code is fit for anything,
9 * so use it at your peril. I don't even work for CSA any more, so
10 * don't bother them about it. If you have any suggestions or comments
11 * (or money, cheques, free trips =8^) !!!!! ) please contact me
12 * care of geoffw@extro.ucc.oz.au
13 *
14 * handling for different classification banners for 1st page added by
15 * Daniel Risacher (magnus@alum.mit.edu)
16 *
17 */
18
19 #include "machdep.h"
20 #include "defs.h"
21
22 #include "version.h"
23 #include "print.h"
24 #include "main.h"
25 #include "paper.h"
26 #include "postscri.h"
27
28 /********************************
29 defines
30 ********************************/
31
32 /* environment variables */
33 #define PRINTER "PRINTER" /* sets name of printer */
34 #define NENSCRIPT "NENSCRIPT" /* contains options */
35
36 /********************************
37 exports
38 ********************************/
39 char *progname;
40
41 /********************************
42 usage
43 ********************************/
44
usage()45 void usage ()
46
47 {
48 printf ("usage: %s -?12BGghlNnRrSsVWwZ -f font -F titlefont -b header -i filetitle -L lines -p filename -P printer -S classification -U classification_1st_page -T papertype -t tabstop -# copies file...\n", progname);
49 exit (0);
50 }
51
52 /*********************************
53
54 variables set by options
55
56 *********************************/
57
58 static int landscape = False; /* True if in ladnscape mode, i.e. -r specified */
59 static int columns = 1; /* number of columns to print with */
60 static char *outputfilename = NULL; /* name of output file, if still NULL after parsing args then use lpr */
61 static char *bodyfont = NULL; /* font to use for text */
62 static char *titlefont = NULL; /* font to use for titles */
63 static int wrap = True; /* True if to wrap long lines */
64 static int titlesenabled = True; /* True if page titles enables */
65 static char *title = NULL; /* set to title if specified */
66 static int copies = 1; /* number of copies of each page */
67 static int gaudy = False; /* enables gaudy mode */
68 static int force_lines = 0; /* force number of lines per page */
69 static char *classification_1st = NULL; /* security classification for 1st page */
70 static char *classification = NULL; /* security classification for body of document */
71 static int line_numbers = False; /* true if to display line numbers */
72 static char *printername = DEF_PRINTER; /* name of printer to use when output goes to lpr */
73 static int tabstop = 8; /* tab stops */
74 static int passthroughflag = False; /* if True, then check for %! to allow passthrough of raw postscript */
75 static char *filetitle = NULL; /* set file title */
76
77 #ifdef US_VERSION
78 static char *papertype = "US";
79 #else
80 static char *papertype = "A4";
81 #endif
82
83
84 /*
85 * forward declarations if in ANSI mode
86 */
87
88 #ifdef __STDC__
89 char * get_string (char **);
90 void parse_options (int *, char ***);
91 void parse_env (char *);
92
93
94 #endif
95
96
97 /********************************
98 parse_options
99 ********************************/
100
101 #define ARGC (*argc)
102 #define ARGV (*argv)
103
parse_options(argc,argv)104 void parse_options (argc, argv)
105
106 int *argc;
107 char ***argv;
108
109 {
110 char c;
111 char *s;
112 int i;
113
114 /* parse the options */
115
116 next_argv:
117 while (--ARGC > 0 && (*++ARGV)[0] == '-')
118 while (c = *++ARGV[0])
119 switch (c) {
120
121 /* -? : print help message */
122 case '?' :
123 case 'h' :
124 usage ();
125 break;
126
127 /* -1 : single column mode */
128 case '1' :
129 columns = 1;
130 break;
131
132 /* -2 : double column mode */
133 case '2' :
134 columns = 2;
135 break;
136
137 /* -#: set number of copies */
138 case '#' :
139 if (*++ARGV[0])
140 copies = atoi (ARGV[0]);
141 else {
142 if (ARGC < 1)
143 fprintf (stderr, "%s: -# option requires argument\n", progname);
144 else {
145 --ARGC;
146 copies = atoi (*++ARGV);
147 }
148 }
149 if (copies < 1) {
150 fprintf (stderr, "%s: illegal number of copies specified - defaulting to one\n", progname);
151 copies = 1;
152 }
153 goto next_argv;
154 break;
155
156 /* -b: set page title */
157 case 'b' :
158 if (*++ARGV[0])
159 title = ARGV[0];
160 else {
161 if (ARGC < 1)
162 fprintf (stderr, "%s: -b option requires argument\n", progname);
163 else {
164 --ARGC;
165 title = *++ARGV;
166 }
167 }
168 goto next_argv;
169 break;
170
171 /* -f : set font to use for printing body */
172 case 'f' :
173 if (*++ARGV[0])
174 bodyfont = ARGV[0];
175 else {
176 if (ARGC < 1)
177 fprintf (stderr, "%s: -f option requires argument\n", progname);
178 else {
179 --ARGC;
180 bodyfont = *++ARGV;
181 }
182 }
183 goto next_argv;
184 break;
185
186 /* -N : display line numbers */
187 case 'N' :
188 line_numbers = True;
189 break;
190
191 /* -n : disable line numbers */
192 case 'n' :
193 line_numbers = False;
194 break;
195
196 /* -p: send to file rather than lpr */
197 case 'p' :
198 if (*++ARGV[0])
199 outputfilename = ARGV[0];
200 else {
201 if (ARGC < 1)
202 fprintf (stderr, "%s: -p option requires argument\n", progname);
203 else {
204 --ARGC;
205 outputfilename = *++ARGV;
206 }
207 }
208 goto next_argv;
209 break;
210
211 /* -r : landscape mode */
212 case 'r' :
213 landscape = True;
214 break;
215
216 /* -w : wrap mode */
217 case 'w' :
218 wrap = True;
219 break;
220
221 /* -Z : check for postscript passthrough mode */
222 case 'Z' :
223 passthroughflag = True;
224 break;
225
226 /* -B : disable page headings and disable gaudy mode */
227 case 'B' :
228 titlesenabled = False;
229 break;
230
231 /* -F : set font to use for printing titles */
232 case 'F' :
233 if (*++ARGV[0])
234 titlefont = ARGV[0];
235 else {
236 if (ARGC < 1)
237 fprintf (stderr, "%s: -F option requires argument\n", progname);
238 else {
239 --ARGC;
240 titlefont = *++ARGV;
241 }
242 }
243 goto next_argv;
244 break;
245
246 /* -g : disable gaudy mode */
247 case 'g' :
248 gaudy = False;
249 break;
250
251 /* -G : enable gaudy mode */
252 case 'G' :
253 gaudy = True;
254 break;
255
256 /* -i: set file title when inputting from stdin */
257 case 'i' :
258 if (*++ARGV[0])
259 filetitle = ARGV[0];
260 else {
261 if (ARGC < 1)
262 fprintf (stderr, "%s: -i option requires argument\n", progname);
263 else {
264 --ARGC;
265 filetitle = *++ARGV;
266 }
267 }
268 goto next_argv;
269 break;
270
271 /* -l : don't set number of lines of page, i.e. use maximum */
272 case 'l' :
273 force_lines = 0;
274 break;
275
276 /* -L : force number of lines per page */
277 case 'L' :
278 if (*++ARGV[0])
279 force_lines = atoi(ARGV[0]);
280 else {
281 if (ARGC < 1)
282 fprintf (stderr, "%s: -x option requires argument\n", progname);
283 else {
284 --ARGC;
285 force_lines = atoi (*++ARGV);
286 }
287 }
288 if (force_lines <= 0) {
289 fprintf (stderr, "%s: ignoring illegal arguement to -L option\n", progname);
290 force_lines = 0;
291 }
292 goto next_argv;
293 break;
294
295 /* -P: set printer name - overrides PRINTER environment variables */
296 case 'P' :
297 if (*++ARGV[0])
298 printername = ARGV[0];
299 else {
300 if (ARGC < 1)
301 fprintf (stderr, "%s: -P option requires argument\n", progname);
302 else {
303 --ARGC;
304 printername = *++ARGV;
305 }
306 }
307 goto next_argv;
308 break;
309
310 /* -R : portrait mode */
311 case 'R' :
312 landscape = False;
313 break;
314
315 /* -U: set security classification for first page only*/
316 case 'U' :
317 if (*++ARGV[0])
318 classification_1st = ARGV[0];
319 else {
320 if (ARGC < 1)
321 fprintf (stderr, "%s: -U option requires argument\n", progname);
322 else {
323 --ARGC;
324 classification_1st = *++ARGV;
325 }
326 }
327 goto next_argv;
328 break;
329
330 /* -S: set security classification */
331 case 'S' :
332 if (*++ARGV[0])
333 classification = ARGV[0];
334 else {
335 if (ARGC < 1)
336 fprintf (stderr, "%s: -S option requires argument\n", progname);
337 else {
338 --ARGC;
339 classification = *++ARGV;
340 }
341 }
342 goto next_argv;
343 break;
344
345 /* -s : disable security classification printing */
346 case 's' :
347 classification_1st = NULL;
348 classification = NULL;
349 break;
350
351
352 /* -T: set paper size to either US or A4 */
353 case 'T' :
354 if (*++ARGV[0])
355 papertype = ARGV[0];
356 else {
357 if (ARGC < 1)
358 fprintf (stderr, "%s: -T option requires argument\n", progname);
359 else {
360 --ARGC;
361 papertype = *++ARGV;
362 }
363 }
364 goto next_argv;
365 break;
366
367 /* -t: set tab stop size */
368 case 't' :
369 if (*++ARGV[0])
370 s = ARGV[0];
371 else {
372 if (ARGC < 1) {
373 fprintf (stderr, "%s: -t option requires argument\n", progname);
374 s = 0; /* We should flag the error in some way */
375 } else {
376 --ARGC;
377 s = *++ARGV;
378 }
379 }
380 if ((i = atoi (s)) <= 0)
381 fprintf (stderr, "%s: illegal tab setting %s ignored\n", progname, s);
382 else
383 tabstop = i;
384 goto next_argv;
385 break;
386
387 /* -V : print version number */
388 case 'V' :
389 fputs (version_string, stderr);
390 fputs ("\n", stderr);
391 /* fputs (copyright_string, stderr); */
392 exit (0);
393 break;
394
395 /* -W : turn off wrap mode */
396 case 'W' :
397 wrap = False;
398 break;
399
400 /* single char option */
401 /* case 'x' :
402 allow_checkouts = True;
403 break;
404 */
405
406 /* option with string */
407 /* case 'x' :
408 if (*++ARGV[0])
409 optionstring = ARGV[0];
410 else {
411 if (ARGC < 1)
412 fprintf (stderr, "%s: -x option requires argument\n", progname);
413 else {
414 --ARGC;
415 optionstring = *++ARGV;
416 }
417 }
418 goto next_argv;
419 break;
420 */
421 default :
422 fprintf (stderr, "%s: unknown option %c\n", progname, c);
423 usage();
424 break;
425 }
426 }
427
428 /********************************
429 get_string
430 return the next string from the argument
431 ********************************/
432
get_string(str)433 char * get_string (str)
434
435 char **str;
436
437 #define STR (*str)
438
439 {
440 char *ret = NULL;
441 int in_dquote, in_squote, in_bquote;
442 int quote_count;
443
444 /* skip leading whitespace */
445 while (*STR == ' ' ||
446 *STR == '\t')
447 STR++;
448
449 /* return if end of string */
450 if (*STR == '\0')
451 return NULL;
452
453 /* collect characters until end of string or whitespace */
454 in_dquote = -1;
455 in_squote = -1;
456 in_bquote = -1;
457 quote_count = 0;
458 ret = STR;
459 while (*STR != '\0' &&
460 (quote_count > 0 || (*STR != ' ' && *STR != '\t'))
461 ) {
462 switch (*STR) {
463 case '"':
464 in_dquote = -in_dquote;
465 quote_count += in_dquote;
466 break;
467
468 case '\'':
469 in_squote = -in_squote;
470 quote_count += in_squote;
471 break;
472
473 case '`':
474 in_bquote = -in_bquote;
475 quote_count += in_bquote;
476 break;
477
478 case '\\':
479 if (STR[1] != '\0')
480 STR++;
481 break;
482 }
483 STR++;
484 }
485 if (*STR != '\0') {
486 *STR = '\0';
487 STR++;
488 }
489
490 if (quote_count > 0)
491 fprintf (stderr, "unmatched quote in %s environment variable\n", NENSCRIPT);
492
493 return ret;
494 }
495
496
497 /********************************
498 parse_env
499 process the options specified in the supplied string
500 ********************************/
501
parse_env(env)502 void parse_env (env)
503
504 char *env;
505
506 {
507 int argc;
508 char *s;
509 char **argv;
510
511 if (env == NULL)
512 return;
513
514 /* insert a "fake" argv[0] which corresponds to the real
515 argv[0] passed to main. The allows us to use same routine
516 for handling the real arguments */
517 argv = (char **)malloc (sizeof (char *));
518 argc = 1;
519 argv[0] = progname;
520
521 /* split the single environment string into separate strings so we can pass
522 them to parse_options */
523 while ((s = get_string (&env)) != NULL) {
524 argv = (char **)realloc ((void *)argv, (argc+1) * sizeof (char *));
525 argv[argc] = s;
526 argc++;
527 }
528
529 /* parse the options */
530 parse_options (&argc, &argv);
531 }
532
533 /********************************
534 passthrough
535 ********************************/
536
passthrough(input,output)537 static void passthrough (input, output)
538
539 FILE * input;
540 FILE * output;
541
542 {
543 char buff [512];
544 int len;
545
546 while ((len = fread (buff, 1, 512, input)) > 0)
547 fwrite (buff, 1, len, output);
548 }
549
550
551 /********************************
552 main
553 ********************************/
554
main(argc,argv)555 int main (argc, argv)
556
557 int argc;
558 char *argv[];
559
560 {
561 char *env;
562 char cmd[1024];
563 struct PaperMetrics * papermetrics;
564 int i;
565 int ch1;
566 int ch2;
567
568
569 FILE *outputstream; /* opened output stream - either file or lpr */
570 FILE *inputstream; /* opened input stream, 0 if max */
571
572 /* extract the program name */
573 if ((progname = strrchr (argv[0], '/')) == NULL)
574 progname = argv[0];
575 else
576 progname++;
577
578 /* get the printer environment variable */
579 if ((env = getenv (PRINTER)) != NULL)
580 printername = env;
581
582 /* handle the NENSCRIPT environment variable */
583 if ((env = getenv (NENSCRIPT)) != NULL)
584 parse_env (STRDUP(env));
585
586 /* parse arguments */
587 parse_options (&argc, &argv);
588
589 /* open either the output file or a pipe to lpr */
590 if (outputfilename != NULL) {
591 if (strcmp (outputfilename, "-") == 0)
592 outputstream = stdout;
593 else if ((outputstream = fopen (outputfilename, "w")) == NULL) {
594 perror (outputfilename);
595 exit (1);
596 }
597 } else {
598 #ifdef MSDOS
599 if ((outputstream = fopen (printername, "w")) == NULL) {
600 perror (printername);
601 exit (1);
602 }
603 #else
604 snprintf (cmd, sizeof(cmd), "%s %s", LPR, printername);
605 if ((outputstream = popen (cmd, "w")) == NULL) {
606 perror (LPR);
607 exit (1);
608 }
609 #endif
610 }
611
612 /* can't be in passthrough mode with more than one argument */
613 if (argc > 1 && passthroughflag) {
614 fprintf (stderr, "%s: ignoring -Z flag as there is more than one argument", progname);
615 passthroughflag = False;
616 }
617
618 /* if in passthrough mode, open the input stream and check for %! */
619 if (passthroughflag) {
620 if (argc < 1)
621 inputstream = stdin;
622 else if ((inputstream = fopen (*argv, "r")) == NULL) {
623 perror (*argv);
624 exit (1);
625 }
626 ch1 = fgetc (inputstream);
627 ch2 = fgetc (inputstream);
628 ungetc (ch2, inputstream);
629 ungetc (ch1, inputstream);
630 if (ch1 == '%' && ch2 == '!') {
631 passthrough (inputstream, outputstream);
632 exit (0);
633 }
634 } else
635 inputstream = NULL;
636
637 /* check the paper type and get ptr to record */
638 papermetrics = NULL;
639 for (i = 0; PaperTypes[i].Name != NULL; i++)
640 if (STRICMP ((papermetrics = &PaperTypes[i])->Name, papertype) == 0)
641 break;
642
643 /* if the papermetric was not set, give error */
644 if (PaperTypes[i].Name == NULL) {
645 fprintf (stderr, "%s: paper type %s not known\n", progname, papertype);
646 exit (1);
647 }
648
649 /* set up the fonts */
650 if (bodyfont == NULL)
651 bodyfont = (columns == 2 && landscape) ? papermetrics->LandscapeFont : papermetrics->PortraitFont;
652
653 if (titlefont == NULL)
654 titlefont = papermetrics->TitleFont;
655
656 /* display the header */
657 StartJob (outputstream,
658 *argv,
659 landscape,
660 columns,
661 bodyfont,
662 titlefont,
663 wrap,
664 titlesenabled,
665 title,
666 copies,
667 gaudy,
668 force_lines,
669 classification_1st,
670 classification,
671 papermetrics,
672 tabstop);
673
674 /* if no arguments, then accept stdin */
675 if (argc < 1)
676 print_file (stdin, outputstream, (filetitle ? filetitle : "stdin"), line_numbers);
677 else for (;argc > 0;argc--) {
678 if (inputstream == NULL && (inputstream = fopen (*argv, "r")) == NULL)
679 perror (*argv);
680 else {
681 print_file (inputstream, outputstream, (filetitle ? filetitle : *argv), line_numbers);
682 fclose(inputstream);
683 inputstream = NULL;
684 }
685 argv++;
686 }
687
688 /* output trailer */
689 EndJob (outputstream);
690
691 /* finished */
692 return (0);
693 }
694