1 /*
2 *
3 * posttek - PostScript translator for tektronix 4014 files
4 *
5 * A program that can be used to translate tektronix 4014 files into PostScript.
6 * Most of the code was borrowed from the tektronix 4014 emulator that was written
7 * for DMDs. Things have been cleaned up some, but there's still plently that
8 * could be done.
9 *
10 * The PostScript prologue is copied from *prologue before any of the input files
11 * are translated. The program expects that the following PostScript procedures
12 * are defined in that file:
13 *
14 * setup
15 *
16 * mark ... setup -
17 *
18 * Handles special initialization stuff that depends on how the program
19 * was called. Expects to find a mark followed by key/value pairs on the
20 * stack. The def operator is applied to each pair up to the mark, then
21 * the default state is set up.
22 *
23 * pagesetup
24 *
25 * page pagesetup -
26 *
27 * Does whatever is needed to set things up for the next page. Expects
28 * to find the current page number on the stack.
29 *
30 * v
31 *
32 * mark dx1 dy1 ... dxn dyn x y v mark
33 *
34 * Draws the vector described by the numbers on the stack. The top two
35 * numbers are the starting point. The rest are relative displacements
36 * from the preceeding point. Must make sure we don't put too much on
37 * the stack!
38 *
39 * t
40 *
41 * x y string t -
42 *
43 * Prints the string that's on the top of the stack starting at point
44 * (x, y).
45 *
46 * p
47 *
48 * x y p -
49 *
50 * Marks the point (x, y) with a circle whose radius varies with the
51 * current intensity setting.
52 *
53 * i
54 *
55 * percent focus i -
56 *
57 * Changes the size of the circle used to mark individual points to
58 * percent of maximum for focused mode (focus=1) or defocused mode
59 * (focus=0). The implementation leaves much to be desired!
60 *
61 * l
62 *
63 * mark array l mark
64 *
65 * Set the line drawing mode according to the description given in array.
66 * The arrays that describe the different line styles are declared in
67 * STYLES (file posttek.h). The array really belongs in the prologue!
68 *
69 * w
70 *
71 * n w -
72 *
73 * Adjusts the line width for vector drawing. Used to select normal (n=0)
74 * or defocused (n=1) mode.
75 *
76 * f
77 *
78 * size f -
79 *
80 * Changes the size of the font that's used to print characters in alpha
81 * mode. size is the tektronix character width and is used to choose an
82 * appropriate point size in the current font.
83 *
84 * done
85 *
86 * done
87 *
88 * Makes sure the last page is printed. Only needed when we're printing
89 * more than one page on each sheet of paper.
90 *
91 * The default line width is zero, which forces lines to be one pixel wide. That
92 * works well on 'write to black' engines but won't be right for 'write to white'
93 * engines. The line width can be changed using the -w option, or you can change
94 * the initialization of linewidth in the prologue.
95 *
96 * Many default values, like the magnification and orientation, are defined in
97 * the prologue, which is where they belong. If they're changed (by options), an
98 * appropriate definition is made after the prologue is added to the output file.
99 * The -P option passes arbitrary PostScript through to the output file. Among
100 * other things it can be used to set (or change) values that can't be accessed by
101 * other options.
102 *
103 */
104
105 #include <stdio.h>
106 #include <signal.h>
107 #include <sys/types.h>
108 #include <fcntl.h>
109
110 #include "comments.h" /* PostScript file structuring comments */
111 #include "gen.h" /* general purpose definitions */
112 #include "path.h" /* for the prologue */
113 #include "ext.h" /* external variable definitions */
114 #include "posttek.h" /* control codes and other definitions */
115
116 char *optnames = "a:c:f:m:n:o:p:w:x:y:A:C:E:J:L:P:R:DI";
117
118 char *prologue = POSTTEK; /* default PostScript prologue */
119 char *formfile = FORMFILE; /* stuff for multiple pages per sheet */
120
121 int formsperpage = 1; /* page images on each piece of paper */
122 int copies = 1; /* and this many copies of each sheet */
123
124 int charheight[] = CHARHEIGHT; /* height */
125 int charwidth[] = CHARWIDTH; /* and width arrays for tek characters */
126 int tekfont = TEKFONT; /* index into charheight[] and charwidth[] */
127
128 char intensity[] = INTENSITY; /* special point intensity array */
129 char *styles[] = STYLES; /* description of line styles */
130 int linestyle = 0; /* index into styles[] */
131 int linetype = 0; /* 0 for normal, 1 for defocused */
132
133 int dispmode = ALPHA; /* current tektronix state */
134 int points = 0; /* points making up the current vector */
135 int characters = 0; /* characters waiting to be printed */
136 int pen = UP; /* just for point plotting */
137 int margin = 0; /* left edge - ALPHA state */
138
139 Point cursor; /* should be current cursor position */
140
141 Fontmap fontmap[] = FONTMAP; /* for translating font names */
142 char *fontname = "Courier"; /* use this PostScript font */
143
144 int page = 0; /* page we're working on */
145 int printed = 0; /* printed this many pages */
146
147 FILE *fp_in; /* read from this file */
148 FILE *fp_out = stdout; /* and write stuff here */
149 FILE *fp_acct = NULL; /* for accounting data */
150
151 /*****************************************************************************/
152
main(agc,agv)153 main(agc, agv)
154
155 int agc;
156 char *agv[];
157
158 {
159
160 /*
161 *
162 * A simple program that can be used to translate tektronix 4014 files into
163 * PostScript. Most of the code was taken from the DMD tektronix 4014 emulator,
164 * although things have been cleaned up some.
165 *
166 */
167
168 argv = agv; /* so everyone can use them */
169 argc = agc;
170
171 prog_name = argv[0]; /* just for error messages */
172
173 init_signals(); /* sets up interrupt handling */
174 header(); /* PostScript header comments */
175 options(); /* handle the command line options */
176 setup(); /* for PostScript */
177 arguments(); /* followed by each input file */
178 done(); /* print the last page etc. */
179 account(); /* job accounting data */
180
181 exit(x_stat); /* nothing could be wrong */
182
183 } /* End of main */
184
185 /*****************************************************************************/
186
init_signals()187 init_signals()
188
189 {
190
191 /*
192 *
193 * Make sure we handle interrupts.
194 *
195 */
196
197 if ( signal(SIGINT, interrupt) == SIG_IGN ) {
198 signal(SIGINT, SIG_IGN);
199 signal(SIGQUIT, SIG_IGN);
200 signal(SIGHUP, SIG_IGN);
201 } else {
202 signal(SIGHUP, interrupt);
203 signal(SIGQUIT, interrupt);
204 } /* End else */
205
206 signal(SIGTERM, interrupt);
207
208 } /* End of init_signals */
209
210 /*****************************************************************************/
211
header()212 header()
213
214 {
215
216 int ch; /* return value from getopt() */
217 int old_optind = optind; /* for restoring optind - should be 1 */
218
219 /*
220 *
221 * Scans the option list looking for things, like the prologue file, that we need
222 * right away but could be changed from the default. Doing things this way is an
223 * attempt to conform to Adobe's latest file structuring conventions. In particular
224 * they now say there should be nothing executed in the prologue, and they have
225 * added two new comments that delimit global initialization calls. Once we know
226 * where things really are we write out the job header, follow it by the prologue,
227 * and then add the ENDPROLOG and BEGINSETUP comments.
228 *
229 */
230
231 while ( (ch = getopt(argc, argv, optnames)) != EOF )
232 if ( ch == 'L' )
233 prologue = optarg;
234 else if ( ch == '?' )
235 error(FATAL, "");
236
237 optind = old_optind; /* get ready for option scanning */
238
239 fprintf(stdout, "%s", CONFORMING);
240 fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION);
241 fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND);
242 fprintf(stdout, "%s %s\n", PAGES, ATEND);
243 fprintf(stdout, "%s", ENDCOMMENTS);
244
245 if ( cat(prologue) == FALSE )
246 error(FATAL, "can't read %s", prologue);
247
248 fprintf(stdout, "%s", ENDPROLOG);
249 fprintf(stdout, "%s", BEGINSETUP);
250 fprintf(stdout, "mark\n");
251
252 } /* End of header */
253
254 /*****************************************************************************/
255
options()256 options()
257
258 {
259
260 int ch; /* value returned by getopt() */
261
262 /*
263 *
264 * Reads and processes the command line options. Added the -P option so arbitrary
265 * PostScript code can be passed through. Expect it could be useful for changing
266 * definitions in the prologue for which options have not been defined.
267 *
268 */
269
270 while ( (ch = getopt(argc, argv, optnames)) != EOF ) {
271 switch ( ch ) {
272 case 'a': /* aspect ratio */
273 fprintf(stdout, "/aspectratio %s def\n", optarg);
274 break;
275
276 case 'c': /* copies */
277 copies = atoi(optarg);
278 fprintf(stdout, "/#copies %s store\n", optarg);
279 break;
280
281 case 'f': /* use this PostScript font */
282 fontname = get_font(optarg);
283 fprintf(stdout, "/font /%s def\n", fontname);
284 break;
285
286 case 'm': /* magnification */
287 fprintf(stdout, "/magnification %s def\n", optarg);
288 break;
289
290 case 'n': /* forms per page */
291 formsperpage = atoi(optarg);
292 fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg);
293 fprintf(stdout, "/formsperpage %s def\n", optarg);
294 break;
295
296 case 'o': /* output page list */
297 out_list(optarg);
298 break;
299
300 case 'p': /* landscape or portrait mode */
301 if ( *optarg == 'l' )
302 fprintf(stdout, "/landscape true def\n");
303 else fprintf(stdout, "/landscape false def\n");
304 break;
305
306 case 'w': /* line width */
307 fprintf(stdout, "/linewidth %s def\n", optarg);
308 break;
309
310 case 'x': /* shift horizontally */
311 fprintf(stdout, "/xoffset %s def\n", optarg);
312 break;
313
314 case 'y': /* and vertically on the page */
315 fprintf(stdout, "/yoffset %s def\n", optarg);
316 break;
317
318 case 'A': /* force job accounting */
319 case 'J':
320 if ( (fp_acct = fopen(optarg, "a")) == NULL )
321 error(FATAL, "can't open accounting file %s", optarg);
322 break;
323
324 case 'C': /* copy file straight to output */
325 if ( cat(optarg) == FALSE )
326 error(FATAL, "can't read %s", optarg);
327 break;
328
329 case 'E': /* text font encoding */
330 fontencoding = optarg;
331 break;
332
333 case 'L': /* PostScript prologue file */
334 prologue = optarg;
335 break;
336
337 case 'P': /* PostScript pass through */
338 fprintf(stdout, "%s\n", optarg);
339 break;
340
341 case 'R': /* special global or page level request */
342 saverequest(optarg);
343 break;
344
345 case 'D': /* debug flag */
346 debug = ON;
347 break;
348
349 case 'I': /* ignore FATAL errors */
350 ignore = ON;
351 break;
352
353 case '?': /* don't know the option */
354 error(FATAL, "");
355 break;
356
357 default: /* don't know what to do for ch */
358 error(FATAL, "missing case for option %c", ch);
359 break;
360 } /* End switch */
361 } /* End while */
362
363 argc -= optind;
364 argv += optind;
365
366 } /* End of options */
367
368 /*****************************************************************************/
369
get_font(name)370 char *get_font(name)
371
372 char *name; /* name the user asked for */
373
374 {
375
376 int i; /* for looking through fontmap[] */
377
378 /*
379 *
380 * Called from options() to map a user's font name into a legal PostScript name.
381 * If the lookup fails *name is returned to the caller. That should let you choose
382 * any PostScript font.
383 *
384 */
385
386 for ( i = 0; fontmap[i].name != NULL; i++ )
387 if ( strcmp(name, fontmap[i].name) == 0 )
388 return(fontmap[i].val);
389
390 return(name);
391
392 } /* End of get_font */
393
394 /*****************************************************************************/
395
setup()396 setup()
397
398 {
399
400 /*
401 *
402 * Handles things that must be done after the options are read but before the
403 * input files are processed.
404 *
405 */
406
407 writerequest(0, stdout); /* global requests eg. manual feed */
408 setencoding(fontencoding);
409 fprintf(stdout, "setup\n");
410
411 if ( formsperpage > 1 ) {
412 if ( cat(formfile) == FALSE )
413 error(FATAL, "can't read %s", formfile);
414 fprintf(stdout, "%d setupforms\n", formsperpage);
415 } /* End if */
416
417 fprintf(stdout, "%s", ENDSETUP);
418
419 } /* End of setup */
420
421 /*****************************************************************************/
422
arguments()423 arguments()
424
425 {
426
427 /*
428 *
429 * Makes sure all the non-option command line arguments are processed. If we get
430 * here and there aren't any arguments left, or if '-' is one of the input files
431 * we'll process stdin.
432 *
433 */
434
435 if ( argc < 1 )
436 statemachine(fp_in = stdin);
437 else { /* at least one argument is left */
438 while ( argc > 0 ) {
439 if ( strcmp(*argv, "-") == 0 )
440 fp_in = stdin;
441 else if ( (fp_in = fopen(*argv, "r")) == NULL )
442 error(FATAL, "can't open %s", *argv);
443 statemachine(fp_in);
444 if ( fp_in != stdin )
445 fclose(fp_in);
446 argc--;
447 argv++;
448 } /* End while */
449 } /* End else */
450
451 } /* End of arguments */
452
453 /*****************************************************************************/
454
done()455 done()
456
457 {
458
459 /*
460 *
461 * Finished with all the input files, so mark the end of the pages with a TRAILER
462 * comment, make sure the last page prints, and add things like the PAGES comment
463 * that can only be determined after all the input files have been read.
464 *
465 */
466
467 fprintf(stdout, "%s", TRAILER);
468 fprintf(stdout, "done\n");
469 fprintf(stdout, "%s %s\n", DOCUMENTFONTS, fontname);
470 fprintf(stdout, "%s %d\n", PAGES, printed);
471
472 } /* End of done */
473
474 /*****************************************************************************/
475
account()476 account()
477
478 {
479
480 /*
481 *
482 * Writes an accounting record to *fp_acct provided it's not NULL. Accounting
483 * is requested using the -A or -J options.
484 *
485 */
486
487 if ( fp_acct != NULL )
488 fprintf(fp_acct, " print %d\n copies %d\n", printed, copies);
489
490 } /* End of account */
491
492 /*****************************************************************************/
493
statemachine(fp)494 statemachine(fp)
495
496 FILE *fp; /* used to set fp_in */
497
498 {
499
500 /*
501 *
502 * Controls the translation of the next input file. Tektronix states (dispmode)
503 * are typically changed in control() and esc().
504 *
505 */
506
507 redirect(-1); /* get ready for the first page */
508 formfeed();
509 dispmode = RESET;
510
511 while ( 1 )
512 switch ( dispmode ) {
513 case RESET:
514 reset();
515 break;
516
517 case ALPHA:
518 alpha();
519 break;
520
521 case GIN:
522 gin();
523 break;
524
525 case GRAPH:
526 graph();
527 break;
528
529 case POINT:
530 case SPECIALPOINT:
531 point();
532 break;
533
534 case INCREMENTAL:
535 incremental();
536 break;
537
538 case EXIT:
539 formfeed();
540 return;
541 } /* End switch */
542
543 } /* End of statemachine */
544
545 /*****************************************************************************/
546
reset()547 reset()
548
549 {
550
551 /*
552 *
553 * Called to reset things, typically only at the beginning of each input file.
554 *
555 */
556
557 tekfont = -1;
558 home();
559 setfont(TEKFONT);
560 setmode(ALPHA);
561
562 } /* End of reset */
563
564 /*****************************************************************************/
565
alpha()566 alpha()
567
568 {
569
570 int c; /* next character */
571 int x, y; /* cursor will be here when we're done */
572
573 /*
574 *
575 * Takes care of printing characters in the current font.
576 *
577 */
578
579 if ( (c = nextchar()) == OUTMODED )
580 return;
581
582 if ( (c < 040) && ((c = control(c)) <= 0) )
583 return;
584
585 x = cursor.x; /* where the cursor is right now */
586 y = cursor.y;
587
588 switch ( c ) {
589 case DEL:
590 return;
591
592 case BS:
593 if ((x -= charwidth[tekfont]) < margin)
594 x = TEKXMAX - charwidth[tekfont];
595 break;
596
597 case NL:
598 y -= charheight[tekfont];
599 break;
600
601 case CR:
602 x = margin;
603 break;
604
605 case VT:
606 if ((y += charheight[tekfont]) >= TEKYMAX)
607 y = 0;
608 break;
609
610 case HT:
611 case ' ':
612 default:
613 if ( characters++ == 0 )
614 fprintf(fp_out, "%d %d (", cursor.x, cursor.y);
615 switch ( c ) {
616 case '(':
617 case ')':
618 case '\\':
619 putc('\\', fp_out);
620
621 default:
622 putc(c, fp_out);
623 } /* End switch */
624 x += charwidth[tekfont];
625 move(x, y);
626 break;
627 } /* End switch */
628
629 if (x >= TEKXMAX) {
630 x = margin;
631 y -= charheight[tekfont];
632 } /* End if */
633
634 if (y < 0) {
635 y = TEKYMAX - charheight[tekfont];
636 x -= margin;
637 margin = (TEKXMAX/2) - margin;
638 if ((x += margin) > TEKXMAX)
639 x -= margin;
640 } /* End if */
641
642 if ( y != cursor.y || x != cursor.x )
643 text();
644
645 move(x, y);
646
647 } /* End of alpha */
648
649 /*****************************************************************************/
650
graph()651 graph()
652
653 {
654
655 int c; /* next character */
656 int b; /* for figuring out loy */
657 int x, y; /* next point in the vector */
658 static int hix, hiy; /* upper */
659 static int lox, loy; /* and lower part of the address */
660 static int extra; /* for extended addressing */
661
662 /*
663 *
664 * Handles things when we're in GRAPH, POINT, or SPECIALPOINT mode.
665 *
666 */
667
668 if ((c = nextchar()) < 040) {
669 control(c);
670 return;
671 } /* End if */
672
673 if ((c & 0140) == 040) { /* new hiy */
674 hiy = c & 037;
675 do
676 if (((c = nextchar()) < 040) && ((c = control(c)) == OUTMODED))
677 return;
678 while (c == 0);
679 } /* End if */
680
681 if ((c & 0140) == 0140) { /* new loy */
682 b = c & 037;
683 do
684 if (((c = nextchar()) < 040) && ((c = control(c)) == OUTMODED))
685 return;
686 while (c == 0);
687 if ((c & 0140) == 0140) { /* no, it was extra */
688 extra = b;
689 loy = c & 037;
690 do
691 if (((c = nextchar()) < 040) && ((c = control(c)) == OUTMODED))
692 return;
693 while (c == 0);
694 } else loy = b;
695 } /* End if */
696
697 if ((c & 0140) == 040) { /* new hix */
698 hix = c & 037;
699 do
700 if (((c = nextchar()) < 040) && ((c = control(c)) == OUTMODED))
701 return;
702 while (c == 0);
703 } /* End if */
704
705 lox = c & 037; /* this should be lox */
706 if (extra & 020)
707 margin = TEKXMAX/2;
708
709 x = (hix<<7) | (lox<<2) | (extra & 03);
710 y = (hiy<<7) | (loy<<2) | ((extra & 014)>>2);
711
712 if ( points > 100 ) { /* don't put too much on the stack */
713 draw();
714 points = 1;
715 } /* End if */
716
717 if ( points++ )
718 fprintf(fp_out, "%d %d\n", cursor.x - x, cursor.y - y);
719
720 move(x, y); /* adjust the cursor */
721
722 } /* End of graph */
723
724 /*****************************************************************************/
725
point()726 point()
727
728 {
729
730 int c; /* next input character */
731
732 /*
733 *
734 * Special point mode permits gray scaling by varying the size of the stored
735 * point, which is controlled by an intensity character that preceeds each point
736 * address.
737 *
738 */
739
740 if ( dispmode == SPECIALPOINT ) {
741 if ( (c = nextchar()) < 040 || c > 0175 )
742 return(control(c));
743
744 fprintf(fp_out, "%d %d i\n", intensity[c - ' '], c & 0100);
745 } /* End if */
746
747 graph();
748 draw();
749
750 } /* End of point */
751
752 /*****************************************************************************/
753
incremental()754 incremental()
755
756 {
757
758 int c; /* for the next few characters */
759 int x, y; /* cursor position when we're done */
760
761 /*
762 *
763 * Handles incremental plot mode. It's entered after the RS control code and is
764 * used to mark points relative to our current position. It's typically followed
765 * by one or two bytes that set the pen state and are used to increment the
766 * current position.
767 *
768 */
769
770 if ( (c = nextchar()) == OUTMODED )
771 return;
772
773 if ( (c < 040) && ((c = control(c)) <= 0) )
774 return;
775
776 x = cursor.x; /* where we are right now */
777 y = cursor.y;
778
779 if ( c & 060 )
780 pen = ( c & 040 ) ? UP : DOWN;
781
782 if ( c & 04 ) y++;
783 if ( c & 010 ) y--;
784 if ( c & 01 ) x++;
785 if ( c & 02 ) x--;
786
787 move(x, y);
788
789 if ( pen == DOWN ) {
790 points = 1;
791 draw();
792 } /* End if */
793
794 } /* End of incremental */
795
796 /*****************************************************************************/
797
gin()798 gin()
799
800 {
801
802 /*
803 *
804 * All we really have to do for GIN mode is make sure it's properly ended.
805 *
806 */
807
808 control(nextchar());
809
810 } /* End of gin */
811
812 /*****************************************************************************/
813
control(c)814 control(c)
815
816 int c; /* check this control character */
817
818 {
819
820 /*
821 *
822 * Checks character c and does special things, like mode changes, that depend
823 * not only on the character, but also on the current state. If the mode changed
824 * becuase of c, OUTMODED is returned to the caller. In all other cases the
825 * return value is c or 0, if c doesn't make sense in the current mode.
826 *
827 */
828
829 switch ( c ) {
830 case BEL:
831 return(0);
832
833 case BS:
834 case HT:
835 case VT:
836 return(dispmode == ALPHA ? c : 0);
837
838 case CR:
839 if ( dispmode != ALPHA ) {
840 setmode(ALPHA);
841 ungetc(c, fp_in);
842 return(OUTMODED);
843 } else return(c);
844
845 case FS:
846 if ( (dispmode == ALPHA) || (dispmode == GRAPH) ) {
847 setmode(POINT);
848 return(OUTMODED);
849 } /* End if */
850 return(0);
851
852 case GS:
853 if ( (dispmode == ALPHA) || (dispmode == GRAPH) ) {
854 setmode(GRAPH);
855 return(OUTMODED);
856 } /* End if */
857 return(0);
858
859 case NL:
860 ungetc(CR, fp_in);
861 return(dispmode == ALPHA ? c : 0);
862
863 case RS:
864 if ( dispmode != GIN ) {
865 setmode(INCREMENTAL);
866 return(OUTMODED);
867 } /* End if */
868 return(0);
869
870 case US:
871 if ( dispmode == ALPHA )
872 return(0);
873 setmode(ALPHA);
874 return(OUTMODED);
875
876 case ESC:
877 return(esc());
878
879 case OUTMODED:
880 return(c);
881
882 default:
883 return(c < 040 ? 0 : c);
884 } /* End switch */
885
886 } /* End of control */
887
888 /*****************************************************************************/
889
esc()890 esc()
891
892 {
893
894 int c; /* next input character */
895 int ignore; /* skip it if nonzero */
896
897 /*
898 *
899 * Handles tektronix escape code. Called from control() whenever an ESC character
900 * is found in the input file.
901 *
902 */
903
904 do {
905 c = nextchar();
906 ignore = 0;
907 switch ( c ) {
908 case CAN:
909 return(0);
910
911 case CR:
912 ignore = 1;
913 break;
914
915 case ENQ:
916 setmode(ALPHA);
917 return(OUTMODED);
918
919 case ETB:
920 return(0);
921
922 case FF:
923 formfeed();
924 setmode(ALPHA);
925 return(OUTMODED);
926
927 case FS:
928 if ( (dispmode == INCREMENTAL) || ( dispmode == GIN) )
929 return(0);
930 setmode(SPECIALPOINT);
931 return(OUTMODED);
932
933 case SI:
934 case SO:
935 return(0);
936
937 case SUB:
938 setmode(GIN);
939 return(OUTMODED);
940
941 case OUTMODED:
942 return(OUTMODED);
943
944 case '8':
945 case '9':
946 case ':':
947 case ';':
948 setfont(c - '8');
949 return(0);
950
951 default:
952 if ( c == '?' && dispmode == GRAPH )
953 return(DEL);
954 if ( (c<'`') || (c>'w') )
955 break;
956 c -= '`';
957 if ( (c & 010) != linetype )
958 fprintf(fp_out, "%d w\n", (linetype = (c & 010))/010);
959 if ( ((c + 1) & 7) >= 6 )
960 break;
961 if ( (c + 1) & 7 )
962 if ( (c & 7) != linestyle ) {
963 linestyle = c & 7;
964 setmode(dispmode);
965 fprintf(fp_out, "%s l\n", styles[linestyle]);
966 } /* End if */
967 return(0);
968 } /* End switch */
969
970 } while (ignore);
971
972 return(0);
973
974 } /* End of esc */
975
976 /*****************************************************************************/
977
move(x,y)978 move(x, y)
979
980 int x, y; /* move the cursor here */
981
982 {
983
984 /*
985 *
986 * Moves the cursor to the point (x, y).
987 *
988 */
989
990 cursor.x = x;
991 cursor.y = y;
992
993 } /* End of move */
994
995 /*****************************************************************************/
996
setmode(mode)997 setmode(mode)
998
999 int mode; /* this should be the new mode */
1000
1001 {
1002
1003 /*
1004 *
1005 * Makes sure the current mode is properly ended and then sets dispmode to mode.
1006 *
1007 */
1008
1009 switch ( dispmode ) {
1010 case ALPHA:
1011 text();
1012 break;
1013
1014 case GRAPH:
1015 draw();
1016 break;
1017
1018 case INCREMENTAL:
1019 pen = UP;
1020 break;
1021 } /* End switch */
1022
1023 dispmode = mode;
1024
1025 } /* End of setmode */
1026
1027 /*****************************************************************************/
1028
home()1029 home()
1030
1031 {
1032
1033 /*
1034 *
1035 * Makes sure the cursor is positioned at the upper left corner of the page.
1036 *
1037 */
1038
1039 margin = 0;
1040 move(0, TEKYMAX);
1041
1042 } /* End of home */
1043
1044 /*****************************************************************************/
1045
setfont(newfont)1046 setfont(newfont)
1047
1048 int newfont; /* use this font next */
1049
1050 {
1051
1052 /*
1053 *
1054 * Generates the call to the procedure that's responsible for changing the
1055 * tektronix font (really just the size).
1056 *
1057 */
1058
1059 if ( newfont != tekfont ) {
1060 setmode(dispmode);
1061 fprintf(fp_out, "%d f\n", charwidth[newfont]);
1062 } /* End if */
1063
1064 tekfont = newfont;
1065
1066 } /* End of setfont */
1067
1068 /*****************************************************************************/
1069
text()1070 text()
1071
1072 {
1073
1074 /*
1075 *
1076 * Makes sure any text we've put on the stack is printed.
1077 *
1078 */
1079
1080 if ( dispmode == ALPHA && characters > 0 )
1081 fprintf(fp_out, ") t\n");
1082
1083 characters = 0;
1084
1085 } /* End of text */
1086
1087 /*****************************************************************************/
1088
draw()1089 draw()
1090
1091 {
1092
1093 /*
1094 *
1095 * Called whenever we need to draw a vector or plot a point. Nothing will be
1096 * done if points is 0 or if it's 1 and we're in GRAPH mode.
1097 *
1098 */
1099
1100 if ( points > 1 ) /* it's a vector */
1101 fprintf(fp_out, "%d %d v\n", cursor.x, cursor.y);
1102 else if ( points == 1 && dispmode != GRAPH )
1103 fprintf(fp_out, "%d %d p\n", cursor.x, cursor.y);
1104
1105 points = 0;
1106
1107 } /* End of draw */
1108
1109 /*****************************************************************************/
1110
formfeed()1111 formfeed()
1112
1113 {
1114
1115 /*
1116 *
1117 * Usually called when we've finished the last page and want to get ready for the
1118 * next one. Also used at the beginning and end of each input file, so we have to
1119 * be careful about exactly what's done.
1120 *
1121 */
1122
1123 setmode(dispmode); /* end any outstanding text or graphics */
1124
1125 if ( fp_out == stdout ) /* count the last page */
1126 printed++;
1127
1128 fprintf(fp_out, "cleartomark\n");
1129 fprintf(fp_out, "showpage\n");
1130 fprintf(fp_out, "saveobj restore\n");
1131 fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed);
1132
1133 if ( ungetc(getc(fp_in), fp_in) == EOF )
1134 redirect(-1);
1135 else redirect(++page);
1136
1137 fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1);
1138 fprintf(fp_out, "/saveobj save def\n");
1139 fprintf(fp_out, "mark\n");
1140 writerequest(printed+1, fp_out);
1141 fprintf(fp_out, "%d pagesetup\n", printed+1);
1142 fprintf(fp_out, "%d f\n", charwidth[tekfont]);
1143 fprintf(fp_out, "%s l\n", styles[linestyle]);
1144
1145 home();
1146
1147 } /* End of formfeed */
1148
1149 /*****************************************************************************/
1150
nextchar()1151 nextchar()
1152
1153 {
1154
1155 int ch; /* next input character */
1156
1157 /*
1158 *
1159 * Reads the next character from the current input file and returns it to the
1160 * caller. When we're finished with the file dispmode is set to EXIT and OUTMODED
1161 * is returned to the caller.
1162 *
1163 */
1164
1165 if ( (ch = getc(fp_in)) == EOF ) {
1166 setmode(EXIT);
1167 ch = OUTMODED;
1168 } /* End if */
1169
1170 return(ch);
1171
1172 } /* End of nextchar */
1173
1174 /*****************************************************************************/
1175
redirect(pg)1176 redirect(pg)
1177
1178 int pg; /* next page we're printing */
1179
1180 {
1181
1182 static FILE *fp_null = NULL; /* if output is turned off */
1183
1184 /*
1185 *
1186 * If we're not supposed to print page pg, fp_out will be directed to /dev/null,
1187 * otherwise output goes to stdout.
1188 *
1189 */
1190
1191 if ( pg >= 0 && in_olist(pg) == ON )
1192 fp_out = stdout;
1193 else if ( (fp_out = fp_null) == NULL )
1194 fp_out = fp_null = fopen("/dev/null", "w");
1195
1196 } /* End of redirect */
1197
1198 /*****************************************************************************/
1199
1200