/*
 *				T 5
 *
 * Read and reposition the file being printed.  Much magic for RSX modes.
 */

#include <stdio.h>
#ifdef	vms
#include	<ctype.h>
#define FALSE	0
#define	TRUE	1
#endif
#include	"t.h"

int
getbyte()
/*
 * Read a byte from the physical record, return EOS at end of file.
 */
{
	register int	c;

	do {
		if (rec_bor >= rec_eor) {
			if (getrecord())
				return (EOS);
		}
	} while ((c = *rec_bor++ & 0177) == EOS);
	return (c);
}

int
getrecord()		
/*
 * Need a new record.  Return TRUE at end of file.
 */
{
	register char		*rp;		/* Start of record ptr.	*/
	register char		*ep;		/* End of record ptr.	*/
	register int		count;		/* For vms printfile	*/
	int			recsiz;		/* Input rec. size	*/

	if (eofseen) {
		return (TRUE);			/* Don't change record	*/
	}
#ifdef	vms
	if (rms_get(buff, max_size, infd) == NULL) {
		rec_bor = rec_eor = buff;
		eofseen = TRUE;
		return (TRUE);
	}
	rms_tell(infd, &rec_rfa);
	recsiz = rms_lrecl(infd);
#ifdef	DEBUG
	if (debug) {
	    _tracef("getrecord: rfa %d %d %d, record size %d",
		rec_rfa.word[0], rec_rfa.word[1], rec_rfa.word[2], recsiz);
	}
#endif
#else
	rec_rfa = ftell(infd);
#ifdef	rsx
	/*
	 * RSX emulated modes
	 */
	recsiz = fget(buff, max_size, infd);
	if (feof(infd)) {
		rec_bor = rec_eor = buff;
		eofseen = TRUE;
		return (TRUE);
	}
#else
	/*
	 * RT11 modes and Unix
	 */
	if (fgets(buff, max_size, infd) == NULL) {
		rec_bor = rec_eor = buff;
		eofseen = TRUE;
		return (TRUE);
	}
	recsiz = strlen(buff);
#endif
#endif
	/*
	 * rp ->  start of the record as read by fget[s]().
	 * ep -> just past the last byte of the record.
	 */
	rp = buff;
	ep = rp + recsiz;
#ifdef	rsx
	if (vms_printfile) {
		if (((count = *fdb_seqn & 0377) & 0200) != 0) {
			*--rp = count & 017;
			if ((count & 0100) != 0)
				*rp |= 0200;
		}
		else while (--count >= 0) {
			*--rp = '\n';
		}
		if (((count = (*fdb_seqn >> 8) & 0377) & 0200) != 0) {
			*ep++ = count & 017;
			if ((count & 0100) != 0)
				ep[-1] |= 0200;
		}
		else while (--count >= 0) {
			*ep++ = '\n';
		}
	}
	else if (implied_cr) {
		*--rp = '\n';
		*ep++ = '\r';
	}
	else if (fortran_cr) {
		/*
		 * The first byte (may be) funny.  Note:
		 * This code is untested.
		 */
		switch (*rp) {
		case '1':			/* Fortran top of page	*/
			*rp = '\f';

		case '\f':			/* Top of page as seen	*/
			/*
			 * Make sure the previous record
			 * has been nicely terminated.  If
			 * this record is longer than one byte,
			 * terminate it, too.
			 */
			*--rp = '\n';
			if (recsiz > 1)
				*ep++ = '\r';
			break;

		case ' ':			/* Normal newline	*/
			*rp = '\n';		/* Linefeed before, and	*/
			*ep++ = '\r';		/* Carriage-return ends	*/
			break;

		case '$':
			*rp = '\n';		/* Newline before,	*/
						/* Nothing follows	*/
			break;

		case '+':
			rp++;			/* Nothing before,	*/
			*ep++ = '\r';		/* Return after		*/
			break;

		case '0':			/* Blank line before	*/
			*rp = '\n';
			*--rp = '\n';		/* Wow, What a hack!	*/
			*ep++ = '\r';		/* Carriage-return ends	*/
			break;

		default:
			*--rp = '\n';		/* Assume it's vanilla	*/
			*ep++ = '\r';		/* 'cause we don't know	*/
		}
	}					
#endif
	rec_bor = rp;				/* Start of record	*/
	rec_eor = ep;				/* End of record	*/
	return (FALSE);
}

saveplace()
/*
 * Save the location of the start of the current page.
 */
{
	if (++memptr > LASTMEM)			/* Wrap around		*/
		memptr = memory;		/* Memory if necessary	*/
	memptr->record_rfa = rec_rfa;		/* *memptr identifies	*/
	memptr->buff_offset = rec_bor - buff;	/* top of this page	*/
	memptr->line_offset = rec_txt - textline;
	/*
	 * Remember whether the line wrapped around.
	 */
	if (ff_flag)
		memptr->buff_offset |= MASK;
	if (rec_savec != EOS)
		memptr->line_offset |= MASK;	/* Set top bit if saved	*/
#ifdef	DEBUG
#ifdef	vms
	if (debug) {
	    _tracef("saveplace mem[%d], rfa %d %d %d, buff %d line %d",
		memptr - memory,
		rec_rfa.word[0], rec_rfa.word[1], rec_rfa.word[2],
		memptr->buff_offset, memptr->line_offset);
	}
#endif
#endif
}

backup(page_flag)
int		page_flag;
/*
 * Backup the memory pointer (wrapping it around
 * to the end of the memory as needed).  Note:
 *	memptr[-1]	top of previous page
 *	memptr[0]	top of current  page
 * If page_flag, the backup continues until a form-feed.
 */
{
#ifdef	DEBUG
	if (debug) {
	    _tracef("backup from mem[%d]", memptr - memory);
	}
#endif
	do {
	    memptr--;			/* To previous page	*/
	    if (memptr < memory) {
		memptr = LASTMEM;
		if (rewound(&memptr->record_rfa)) {
		    memptr = memory;
		    break;
		}
	    }
	} while (page_flag && (memptr->buff_offset >= 0));
#ifdef	DEBUG
#ifdef	vms
	if (debug) {
	    _tracef("backup to mem[%d], rfa %d %d %d, buff %d line %d",
		memptr - memory,
		rec_rfa.word[0], rec_rfa.word[1], rec_rfa.word[2],
		memptr->buff_offset, memptr->line_offset);
	}
#endif
#endif
}

locate(flag)
int		flag;		/* True if error is non-fatal		*/
/*
 * Locate the proper physical record.
 * Note that breakout is cleared so we can still
 * backup after seeing the last record.
 *
 * The flag is needed on rsx/vms when reading an empty file.
 */
{
	RFAVALUE	this_rfa;
	register short	loffset;

	this_rfa = memptr->record_rfa;
	breakout = FALSE;
	iseof = 0;
	eofseen = FALSE;
#ifdef	vms
	if (rms_seek(infd, &this_rfa) != 0 || getrecord()) {
		/*
		 * Could not seek.  Maybe rewind
		 */
		if (rewound(&this_rfa) || flag) {
			rec_eor = rec_bor = buff;
			rec_savec = EOS;
		}
		else {
			scerpg(0, 0);  scout(0, 0, NULL);
			fprintf(stderr, "can't seek to %X %X %X\n",
				this_rfa.word[0], this_rfa.word[1],
				this_rfa.word[2]);
			rms_message(infd, "");
			error("Program bug; can't continue");
		}
	}
#else
	if (fseek(infd, this_rfa, 0) != 0 || getrecord()) {
		/*
		 * Could not seek.  Allow rewind in some cases
		 */
		if (this_rfa == 0 || flag) {
			rec_eor = rec_bor = buff;
			rec_savec = EOS;
		}
		else {
			scout(0, 0, NULL);  scerpg(0, 0, NULL);
			fprintf(stderr, "\nCan't seek to %ld\n", rec_rfa);
			perror("");
			error("Program bug; can't continue");
		}
	}
#endif
	else {
		/*
		 * Step on next record start
		 */
		rec_bor = &buff[memptr->buff_offset & ~MASK];
		if ((memptr->line_offset & MASK) != 0) {
			loffset = memptr->line_offset & ~MASK;
			bigline(1);
			/*
			 * Note, there is a very strange program bug
			 * that has been seen while wandering around
			 * files containing teco macros.  This error
			 * printout should be removed when the bug
			 * is found and fixed.
			 */
			if (loffset < 0
			 || loffset >= sizeof textline) {
				fprintf(stderr,
				    "\nmemptr (%d) bug, line offset = %d,",
				    memptr - memory, loffset);
				fprintf(stderr,
				    " range is 0..%d \n", sizeof textline);
				sleep(4);
			}
			rec_txt = &textline[loffset];
			rec_savec = *rec_txt;
		}
		else {
			rec_savec = EOS;
		}
	}
}

#ifdef	rt11
ctrlc()
/*
 * Control C trap routine -- for RSTS/RT11 only
 */
{
	scerpg(0, 0);
	scout(0, 0, NULL);			/* Flush last buffer	*/
	scput(oldbuf);
	exit(IO_SUCCESS);
}
#endif

static int
rewound(rp)
RFAVALUE	*rp;
/*
 * TRUE if at the magic cookie
 */
{
#ifdef	vms
	return (rp->word[0] == 0 && rp->word[1] == 0 && rp->word[2] == 0);
#else
	return (*rp == magic_cookie);
#endif
}

