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