#
/*
 *				T 1 . C
 *
 * File typeout utility
 */

/*)BUILD	$(PROGRAM)	=	T
		$(INCLUDE)	= 	t.h
		$(FILES)	=	{ t1.c t2.c t3.c t4.c t5.c t6.c t7.c }
		$(TKBOPTIONS)	= {
			TASK	= ...TXX
		}
*/

#ifdef	DOCUMENTATION

title	t	Type File on Video Screen
index		Type File on Video Screen

synopsis
	t [+cols_per_line] [-lines_per_screen] [file_list]

description

	T writes a file, one screen at a time, on the user's terminal.  The
	argument list may contain wildcard file specifiers.  The optional
	lines_per_screen may be given to shorten the screen from its default
	of 24 lines. The optional cols_per_line parameter may be given to
	change the screen from its default width of 80 columns.  Setting
	cols__per__line to zero supresses line wrap-around.
	.s
	After each screen has been
	printed, T waits for the user to type a single-letter command:
	.lm +24
	.s.i-24;_<Space> or
	.i  -24;_<Carriage-Return>	To get the next screen.
	.s.i-24;_<Backspace> or
	.i  -24;_<Line-feed> or
	.i  -24;'_^' <Circumflex>	To back up one screen.
	.s.i-24;'P'			To get the next page.
	.s.i-24;'F'			To return to the first screen.
	.s.i-24;'B'			To skip to the last screen.
	.s.i-24;'S'			To search for a regular expression.
	.s.i-24;'E' or CTRL/Z		To exit the program.
	.s.i-24;'X'			To exit the current file.
	.s.lm -24
	If the "next screen," "next page," or "backup" commands
	are preceeded by a number,
	T will skip the requested number of screens or pages.  Negative
	skips are allowed:  "-P" moves back one page.
	Note that <Space>, 0<Space>,
	and 1<Space> are equivalent. All other characters will be ignored.
	.s
	The 'P' command skips to the next page (as delimited by form-feeds).
	.s
	The 'B' command is equivalent to 32767<Space>.  As T must
	scan the file byte-by-byte, the 'B' command may seem slow.
	.s
	Search arguments are regular expressions (as defined in the grep
	program).  If you enter '?' when prompted for a search argument,
	a help screen will be printed.  Backward searching is not possible.
	.s
	Note that T works only on video terminals.  If no file_list is
	specified, T prompts for each file.  If a file_list argument lacks
	an explicit extension, ".*" will be used; thus "T#X" is equivalent
	to
	.s
		"T X.*".
	.s
	The program will only backup to the built-in maximum of 100 screens.
	.s
	T will erase underline and boldface information
	from the text if it occurs in the
	following format (where 'X' is any character and '\b' is backspace):
	.s.nf
		X\b_    for underline and
	.br
		X\bX... for boldface
	.s.f
	If an embedded carriage return (for line-overprint) is encountered,
	all text following the return will be ignored.
	.s
	T converts <escape> characters in the text file to "<ESC>". 
	This was done to defend against escape sequences triggering user
	terminal identification sequences (which could, for example, cause
	the program to backup one screen).

diagnostics

	.lm +8
	.s.i -8;Sorry, t works only on video terminals.
	.s.i -8;Can't open file "name".
	.lm -8

author

	Martin Minow

bugs


	Neither input nor output may
	be redirected.  T cannot be used as a filter.
	.s
	If a skip or backup command fails (for example, if the input file is
	not on a disk), the program will exit with an error message.
	.s
	When running T from a remote (DECnet) terminal, you should use
	<return> to request the next page and <rubout> or <linefeed>
	to request the previous page.

#endif

#include <stdio.h>
#ifdef	vms
#include <ctype.h>
#define	FALSE		0
#define	TRUE		1
#endif
#include	"t.h"
#ifdef	decus
int	$$narg = 1;			/* Don't argv prompt		*/
#endif

long		magic_cookie;		/* fseek() value to rewind file	*/
long		rec_rfa;		/* Current record being read	*/
char		*rec_bor;		/* Record start in buff[]	*/
char		*rec_eor;		/* Record end   in buff[]	*/
char		*rec_txt;		/* Line start in textline[]	*/
char		rec_savec;		/* Saved byte for line wrap	*/

#ifdef rsx
int	max_size;			/* Maximum file record size	*/
extern	char		*F_SEQN;	/* FDB offset to F.SEQN		*/
int			*fdb_seqn;	/* infdb @ F.SEQN		*/
int	implied_cr	= FALSE;	/* TRUE if vanilla file		*/
int	fortran_cr	= FALSE;	/* TRUE if we hack Fortran VFC	*/
int	vms_printfile	= FALSE;	/* TRUE if VMS VFC file		*/
extern	int		$$vms;		/* VMS compatibility signal	*/

/*
 * buff -> the current record read by getrecord().  Note that it is
 * allocated with guard areas before and after for printfile formats.
 */

char			*allobuff;	/* from calloc()		*/
char			*buff;		/* -> logical record for fget()	*/

#endif

#ifdef	rt11

int	max_size	= 512;		/* Maximum record size		*/
struct	rt11record	rt11record = { EOS, "" };
#endif

#ifdef	vms
/*
 * VMS native
 */
int	max_size	= 512;		/* Maximum record size		*/
struct	vmsrecord vmsrecord = { EOS, "" };
#endif

/*
 * Things for screen handling
 */

char	**oldbuf;			/* For screen package		*/
#ifdef	vms
char	buffer[1000];			/* For screen package		*/
#else
char	buffer[800];			/* For screen package		*/
#endif
int	linesperscreen	= ROWS;		/* Maximum lines per screen	*/
int	columnsperline	= COLS;		/* Maximum columns per line	*/
int	vt100;				/* True if vt100		*/
int	cursrow = 1;			/* Home for cursor		*/
int	curscol = 1;			/* Home for cursor		*/

/*
 * Finis is set when the user types CTRL/C or CTRL/Z in response to
 * a "next screen" prompt.  It forces an exit from the program.
 *
 * Breakout is set on end of file or when the user types 'X' in
 * response to a "next screen" prompt.  It exits the current file,
 * going on to the next (wildcard) file.  Note that the <backup> and
 * <rewind> commands clear breakout.
 */

char	inline[81];			/* Argument line		*/
FILE	*infd;				/* Input file descriptor	*/
char	textline[513];			/* Current output text line	*/
char	file_name[81];			/* Input file name		*/
char	pfilename[81];			/* Process file name		*/
char	temptext[81];			/* Text work space		*/
int	iseof 		= 0;		/* <End-of-file> switch		*/
int	ff_flag		= FALSE;	/* Magic form-feed signal	*/
int	finis		= FALSE;	/* TRUE on CTRL/C or CTRL/Z	*/
int	breakout	= FALSE;	/* TRUE on eXit			*/
RFA	memory[MAXMEM];			/* Top of page memory		*/
RFA	*memptr		= memory;	/* Pointer within memory[]	*/
#define	LASTMEM		(&memory[MAXMEM - 1])
extern	long		ftell();	/* Returns file position	*/


#define	HELPROW	3

char	*help1 =
"T prints files on your terminal, one screenful at a time.\r\n\
When each screen is printed, you may type:\r\n\
  <space> or <return>              to see the next screen.\r\n\
  <backspace>, <linefeed>, or '^'  to see the previous screen.\r\n\
  P                                to go to the next page (form-feed).\r\n\
The above commands may be preceeded by a signed number to skip multiple\r\n\
screens or pages.  They stop at the start or end of the file.\r\n\
  F                                to go to the front of the file.\r\n\
  B                                to go to the back end of the file.\r\n\
  S                                to search for a pattern ('?' for help).\r\n\
  N or X                           to exit this file and start the next.\r\n\
  E (or CTRL/Z)                    to terminate processing.\r\n\
  ? or H                           to view this help message.\r\n\
\r\n";
char *help2 =
"File names may contain \"wild-card\" arguments.  If no \".ext\" is supplied,\r\n\
\".*\" will be used.  If run as a command, T accepts two optional arguments:\r\n\
  +<number> sets the number of columns per line (+0 supresses line wraparound).\r\n\
  -<number> sets the number of lines per screen.\r\n\r\n";

char	*help3 = "(Only compatibility-mode wild-cards are allowed.)\r\n";
char	*help4 =
"Define T as \"T :== $DISK:[ACCOUNT]T\"\r\n\
Execute as \"$ T (options) file1 file2 ...\"";


main(argc, argv)
register int	argc;
register char	**argv;
{
	if (((vt100 = sctype()) & 64) == 0)
		error("Sorry, t works only on video terminals");
	vt100 = (vt100 == IS_VT100);	/* Make it a flag		*/
	scset(buffer, sizeof buffer, &oldbuf);
#ifdef	rt11
	if ($$rsts)
		setcc(ctrlc);		/* Enable CTRL/Z trapping	*/
#endif
	while (argc > 1) {
		switch (argv[1][0]) {
		case '-':
			if ((linesperscreen = atoi(&argv[1][1])) < 3)
				linesperscreen = 3;
			break;
		case '+':
			/*
			 * The "10" in the following line must be
			 * larger than the length of the "blob string"
			 * used by getline.
			 */
			if ((columnsperline = atoi(&argv[1][1])) < 10)
				columnsperline = 0;
			break;

		default:
			goto exit_while;
		}
		argc--;
		argv++;
	}
exit_while:
	if (argc <= 1) {
		/*
		 * T was called without file arguments, or just run.
		 * Print a help message, then prompt and command lines.
		 */
		helpmessage();
		getall(1);
	}
	else {
		while (argc > 1 && !finis) {
			if (process(argv[1], 1) == 0 && argc == 2) {
				/*
				 * If "can't" on only or last file,
				 * go forever.  Start on line 3 since
				 * process() uses 1+2 for error messages.
				 */
				getall(3);
			}
			argc--;			/* Count the argument	*/
			argv++;			/* and step arg. ptr.	*/
		}
	}
	scout(0, 0, NULL);			/* Flush last buffer	*/
	scput(oldbuf);				/* Cleanup screen i/o	*/
}

getall(row)
int		row;
/*
 * Prompt and read files forever.  Row is for the first prompt
 */
{
	while (!finis) {
		scerln(row, 1);
		if (scget(inline, sizeof inline, "File to print? ") == NULL) {
			scerpg(1, 1);
			break;
		}
		else if (inline[0] == '?' && inline[1] == EOS) {
			helpmessage();
		}
		else {
			process(inline, row + 1);
			row = 1;
		}
	}
}

helpmessage()
/*
 * Print a help message
 */
{
	scerpg(1, 1);
	scout(HELPROW, 1, help1);
	scout(0, 0, help2);
#ifdef	rsx
	if ($$vms) {
		scout(0, 0, help3);
		scout(0, 0, help4);
	}
#endif
#ifdef	vms
	scout(0, 0, help4);
#endif
	scout(0, 0, NULL);		/* Needed for inquire() call	*/
}
