Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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