#include <stdio.h>
#include <ctype.h>
#include "xtek.h"

#ifdef VMS
#include <errno.h>
#endif

extern char	*optarg;
extern int	optind;
extern double	atof();

int tv_mode = 0;
int mbx_mode = 0;


/* output filter for tektronics 4010-graphics files to generate postscript
 * files.  This does a simple-minded byte by byte translation to predefined
 * PS routines, contained in a prolog file.
 * Defaults:
 * input:	stdin
 * output:	stdout
 * prolog:	~msf/tek2ps/pstek.pro

 modified for VMS, added -o option. George Carrette 8-30-88
 modified for X-windows. (or other graphics driver) if -o filename is x
  then sets tv_mode to true, ignores prolog file, and calls xtek_init instead.
  xtek_* routines dispatch on tv_mode. George Carrette 15-SEP-89
 */


main(argc, argv)
	int	argc;
	char	*argv[];
{
#ifndef lint
	static char	sccsid[]=" @(#)t2p.c	1.10 tek2ps (Copyright) M. Fischbein  Commercial reproduction prohibited; non-profit reproduction and distribution encouraged.";
#endif
	static char	def_pro[]="TEK2PS_PRO";
	char		*pro_fn = def_pro;
	FILE		*pro_fp, *infile = stdin;
	int		c, mode=ALPHA, tsizex=CHUGEX, tsizey=CHUGEY, oldmode;
	int		cx=0, cy=YDIM-CHUGEY, leftmargin=0;
	int		used_large=FALSE, used_med=FALSE, used_small=FALSE;
	int		dark_vector, HiX=0, HiY=0, LoY=0, LoX=0, BX=0, BY=0;
	int		gotLoY=FALSE, debug=FALSE, beamon, pr_on_er=FALSE;
	double		scale_factor=1.0;


	/* first, parse command line */
	while ((c = getopt (argc, argv, "s:p:deo:")) != EOF) {
		switch (c) {
		case 'p' :	/* use custom prolog */
			pro_fn = optarg;
			break;

		case 'd' :	/* toggle debugging */
			if (debug) {
				debug = FALSE;
			} else {
				debug = TRUE;
			}
			break;

		case 'e':	/* turn on print-before-erase */
				/* and erase-after-print */
			pr_on_er = TRUE;
			break;

		case 's':	/* set scale option */
			scale_factor = atof(optarg)/100.;
			break;
		case 'o' :	/* open output file */
		        if(strcmp(optarg,"x") == 0)
			  tv_mode = 1;
			else if(!(stdout = fopen(optarg,"w")))
			  {perror(optarg);exit(1);}
			break;
		default:
			fprintf(stderr, "Usage: %s [-p prologfile] [-de] [input]\n", argv[0]);
			
		}
	}

	if(!tv_mode)
	  {/* next, copy the prolog file */
	    if( (pro_fp = fopen(pro_fn, "r")) == NULL) {
	      fprintf(stderr, "Can't open prolog file %s\n", pro_fn);
	      exit(1);
	    }
	    while ((c = getc(pro_fp)) != EOF) {
	      putc((char) c, stdout);
	    }
	    fclose(pro_fp);}
	else
	  xtek_init();

	if ((optind < argc)
	    &&
	    (strncmp(argv[optind],"xtek_mail_box",13) == 0))
	  {mbx_mode = 1;
	   infile = open_xtek_mail_box(argv[optind]);}

	/* check for named file (loop if more than one) */
	do {	/* should indent here */
	if ((optind < argc) && !mbx_mode) {
		if ((infile = fopen( argv[optind], "r")) == NULL) {
			fprintf(stderr, "Can't open input file %s\n", argv[optind]);
			exit(1);
		}
	}
	/* check for scale factor */
	if (scale_factor != 1.0) {	/* I know floating pt equality is
					 * a bad idea, but if the option is not
					 * present I explicity initialize to
					 * 1.0, so the bit pattern should be
					 * identical portably
					 */
	        xtek_scale(scale_factor);
	}

	/* Now,  read a byte and figure out what to do about it */
	while ((c = getc(infile)) != EOF) { /* should indent below */
	switch (mode) {
	case ALPHA:
		if ( isgraph((char) c) ) {	/* normal printing char */
			/* put char at current position */
		        xtek_char(c,cx,cy);

			/* increment current postion, wrt type size */
			if ((cx += tsizex) > XDIM) {
				/* new line or margin */
				if((cy -= tsizey) < 0) {
					cy = YDIM - tsizey;
					leftmargin = leftmargin ? 0 : XDIM/2;
				}
				cx = leftmargin;
			}
		} else { /* isn't normal printing character */
		switch (c) {
		case ( HT ):
		case ( SPACE ):
			if ((cx += tsizex) > XDIM) {
				/* new line or margin */
				if((cy -= tsizey) < 0) {
					cy = YDIM - tsizey;
					leftmargin = leftmargin ? 0 : XDIM/2;
				}
				cx = leftmargin;
			}
			break;

		case ( CR ):
		case ( LF ):
			if ((cy -= tsizey) < 0) {
				cy = YDIM - tsizey;
				leftmargin = leftmargin ? 0 : XDIM/2;
			}
			cx = leftmargin;
			break;

		case ( BS ):
			if ((cx -= tsizex) < 0) {
				cx = XDIM;
			}
			break;

		case ( VT ):
			if ((cy += tsizey) > YDIM) {
				cy = 0;
			}
			break;

		case ( GS ):
			mode = GRAPH;
			dark_vector = TRUE;
			break;

		case ( RS ):
			mode = INCRE;
			break;
		
		case ( FS ):
			mode = PTPLT;
			break;

		case ( US ):	/* put in ALPHA mode, already there */
		case ( BEL ):
		case ( SYN ):	/* padding character, ignore*/
		case ( NUL ):	/* padding character, ignore*/
			break;

		case ( ESC ):
			oldmode = ALPHA;
			mode = LCEMD;
			break;

		default :
			if (debug) fprintf(stderr, "Unknown ALPHA mode character 0x%02x\n", c);
			break;
		}	/* end of switch on non-printing char in ALPHA mode */
		}	/* end of printing vs non-printing char in ALPHA mode */
	break;	/* end of ALPHA mode */

	case PTPLT:
	case GRAPH:
		if ( (char) c > US ) {	/* first, handle vector case */
			if( (char) c < '@') { /* High byte */
				if (gotLoY) {	/* must be HiX */
					HiX = ((char) c & 0x1f) << 7;
				} else {	/* must be HiY */
					HiY = ((char) c & 0x1f) << 7;
				}
			} else if ( (char) c < '`') {	/* Lo X: plot */
				gotLoY = FALSE;
				LoX = (c & 0x1f) << 2;
				/* now actually do a plot */
				if (dark_vector) {
					dark_vector = FALSE;
					cx = HiX + LoX + BX;
					cy = HiY + LoY + BY;
					xtek_moveto(cx,cy);
				} else { /* draw the line */
					cx = HiX + LoX + BX;
					cy = HiY + LoY + BY;
					if (mode == GRAPH)  {
					  xtek_ltsm(cx,cy);

					} else {	/* mode == PTPLT */
					  xtek_mtarc(cx,cy);
					}
				}
			} else {	/* Lo Y or extra byte */
				if (gotLoY) {	/* previous LoY => extra byte */
					BX = (LoY & 0x0c) >> 2;
					BY = (LoY & 0x30) >> 4;
					LoY = (c & 0x1f) << 2;
					/* gotLoY stays TRUE */
				} else {	/* assume is LoY */
					LoY = (c & 0x1f) << 2;
					gotLoY = TRUE;
				}
			}
		} else /* end of GRAPH mode vector address parsing*/
		/* so, it isn't a vector address */
		switch ( c ) {
		case ( NUL ): /* padding */
		case ( SYN ): /* padding */
		case ( BEL ): /* ignore */
			break;

		case ( LF ):
			cy -= tsizey;
			xtek_moveto(cx,cy);
			break;

		case ( CR ):
			mode = ALPHA;
			leftmargin = 0;
			break;

		case ( RS ):
			mode = INCRE;
			break;

		case ( FS ):
			fprintf(stderr,"special point plot not implemented\n");
			break;

		case ( GS ):
			dark_vector = TRUE;
			break;

		case ( US ):
			mode = ALPHA;
			break;

		case ( ESC ):
			oldmode = GRAPH;
			mode = LCEMD;
			break;

		default :
			if (debug) fprintf(stderr, "Unknown GRAPH mode character 0x%02x\n", c);
			break;
		}	/* end of switch on non-vector char in GRAPH mode */
	break;	/* end of GRAPH mode */

	case INCRE:
		/* could do with bit masking and check for control, */
		/* but this is is simpler. (Let the compiler work). */
		switch ( c ) {
		case ( 32 ):
		        xtek_smt(cx,cy);
			beamon = FALSE;
			break;

		case ( 80 ):
		        xtek_moveto(cx,cy);
			beamon = TRUE;
			break;

		case ( 68 ):	/* N */
			if (++cy > YDIM) cy = YDIM;
			if (beamon) xtek_lineto(cx,cy);
			break;
			
		case ( 69 ):	/* NE */
			if (++cy > YDIM) cy = YDIM;
			if (++cx > XDIM) cx = XDIM;
			if (beamon) xtek_lineto(cx,cy);
			break;

		case ( 65 ):	/* E */
			if (++cx > XDIM) cx = XDIM;
			if (beamon) xtek_lineto(cx,cy);
			break;

		case ( 73 ):	/* SE */
			if (--cy < 0) cy = 0;
			if (++cx > XDIM) cx = XDIM;
			if (beamon) xtek_lineto(cx,cy);
			break;

		case ( 72 ):	/* S */
			if (--cy < 0) cy = 0;
			if (beamon) xtek_lineto(cx,cy);
			break;

		case ( 74 ):	/* SW */
			if (--cy < 0) cy = 0;
			if (--cx < 0) cx = 0;
			if (beamon) xtek_lineto(cx,cy);
			break;

		case ( 66 ):	/* W */
			if (--cx < 0) cx = 0;
			if (beamon) xtek_lineto(cx,cy);
			break;

		case ( 70 ):	/* NW */
			if (++cy > YDIM) cy = YDIM;
			if (--cx < 0) cx = 0;
			if (beamon) xtek_lineto(cx,cy);
			break;

		case ( ESC ):
			if (beamon) xtek_smt(cx,cy);
			oldmode = INCRE;
			mode = LCEMD;
			break;

		case ( FS ):
			if (beamon) xtek_smt(cx,cy);
			mode = PTPLT;
			break;

		case ( GS ):
			if (beamon) xtek_smt(cx,cy);
			mode = GRAPH;
			dark_vector = TRUE;
			break;

		case ( RS ):
			break;

		case ( US ):
			if (beamon) xtek_smt(cx,cy);
			mode = ALPHA;
			break;

		default:
			if (debug) fprintf(stderr,"Unknown incremental mode character 0x%02x\n", c);
			break;
		}	/* end of INCR switch on c */
	break;	/* end of INCREmental mode */

	case LCEMD:
		if ((c > 95) && (c < 117)) {
			/* set Z axis */
			if ((char) c & 0x08) {
				xtek_DZ();
			} else {
				xtek_FZ();
			}
			/* set vector type */
			switch ((char) c & 0x07) {
			case 0:	/* normal vectors */

				xtek_NV();
				break;

			case 1:	/* dotted vectors */
				xtek_DV();
				break;

			case 2:	/* dot-dash vectors */
				xtek_DDV();
				break;

			case 3:	/* short-dash vectors */
				xtek_SDV();
				break;

			case 4:	/* long-dash vectors */
				xtek_LDV();
				break;

			default:	/* error */
				if (debug) fprintf(stderr,"Unknown beam selector 0x%02x\n", (char) c);
				break;
			}
		} else {
			switch ( c ) {
			case ( FF ):	/* erase */
				if (pr_on_er) {
					xtek_showpage_NP();
					if (scale_factor != 1.0) {
					        xtek_scale(scale_factor);
					}
				}
				xtek_DP(tsizey);
				cx = 0; cy = YDIM - tsizey;
				break;

			case ( '8' ):
				/* default size */
				xtek_FntH_setfont();
				tsizex = CHUGEX; tsizey = CHUGEY;
				break;

			case ( '9' ):
				if (! used_large ) {
					used_large = TRUE;
					xtek_DFntL();
				}
				xtek_FntL_setfont();
				tsizex = CLARGEX; tsizey = CLARGEY;
				break;

			case ( ':' ):
				tsizex = CMEDX; tsizey = CMEDY;
				if (! used_med ) {
					used_med = TRUE;
					xtek_DFntM();
				}
				xtek_FntM_setfont();
				break;

			case ( ';' ):
				tsizex = CSMALLX; tsizey = CSMALLY;
				if (! used_small ) {
					used_small = TRUE;
					xtek_DFntS();
				}
				xtek_FntS_setfont();
				break;

			case ( BS ):
				if ((cx -= tsizex) < 0) {
					cx = XDIM;
				}
				break;

			case ( HT ):
			case ( SPACE ):
				if ((cx += tsizex) > XDIM) {
					/* new line or margin */
					if((cy -= tsizey) < 0) {
						cy = YDIM - tsizey;
						leftmargin = leftmargin ? 0 : XDIM/2;
					}
					cx = leftmargin;
				}
				break;

			case ( VT ):
				if ((cy += tsizey) > YDIM) {
					cy = 0;
				}
				break;

			case ( GS ):
				mode = GRAPH;
				dark_vector = TRUE;
				break;

			case ( LF ):
			case ( CR ):
			case ( DEL ):
			case ( NUL ):
			case ( ESC ):
			case ( BEL ):
			case ( SYN ):
				ungetc( (char) ESC, infile);
				break;

			case ( ETB ):	/* make copy: print & start new page */
				if (pr_on_er) {
					xtek_showpage_NP();
					if (scale_factor != 1.0) {
					        xtek_scale(scale_factor);
					}
					cx = 0; cy = YDIM - tsizey;
				} else {
					xtek_copypage();
				}
				break;

			case ( SO ):
			case ( SI ):
				if (debug) fprintf(stderr, "No alternate character set implemented\n");
				break;

			case ( CAN ):
			case ( SUB ):
			case ( ENQ ):
				if (debug) fprintf(stderr, "GIN and BYPASS  modes not implemented\n");
				break;

			case ( '?' ):
				ungetc( (char) DEL, infile);
				break;

			default :
				if (debug) fprintf(stderr, "Unknown LCE mode character 0x%02x ignored\n", c);
				break;
			}	/* end of LCE mode switch */
		}
	mode = oldmode;
	break;

	default:
		if (debug) fprintf(stderr, "Unknown major mode %d\n", mode);
		break;
	} /* end of mode switch */
	} /* end of main input loop */
	xtek_showpage();
	if (!mbx_mode) fclose(infile);
	} while ((mbx_mode == 1) || (++optind < argc) );
}

