
/*
 * Screen I/O interface library -- allows DECUSC programs to
 * call the scr$... routines.
 */

#include <stdio.h>

globalvalue int	SS$_NORMAL;
globalvalue int	RMS$_EOF;

static	int	_err;			/* Directive error code		*/
static	int	paranoid = 0;		/* When to force buffer flush	*/
static	int	stored = 0;		/* How much in scr$ buffers	*/

typedef struct _descriptor {
		int	size;
		char	*loc;
} _DESCRIPTOR;

static _DESCRIPTOR	_newbuf_;	/* From scset()			*/

static char	*_oldbuf_;		/* From lib$set_buffer		*/

char **
scset(_buffer, _buffer_size, _old_buffer)
char		*_buffer;		/* New buffer			*/
int		_buffer_size;		/* New buffer size		*/
char		**_old_buffer;		/* Old buffer			*/
{
	extern	lib$set_buffer();

	_newbuf_.loc = _buffer;
	_newbuf_.size = _buffer_size;
	paranoid = (_buffer_size * 3) / 4;	/* Buffer flush forcer	*/
	stored = 0;
	if ((_err = lib$set_buffer(&_newbuf_, &_oldbuf_)) != SS$_NORMAL)
		_trouble("scset -> lib$set_buffer");
	*_old_buffer = _oldbuf_;
}

scput(_old)
char	*_old;
{
	extern	lib$put_buffer();

	if ((_err = lib$put_buffer(&_old)) != SS$_NORMAL)
		_trouble("scput -> lib$put_buffer");
	paranoid = 0;
}

int
sctype()
/*
 * Return screen type
 */
{
	long int	flags;
	char		dev_type;
	short int	line_width;
	short int	lines_per_page;
	extern	lib$screen_info();

	if ((_err = lib$screen_info(&flags, &dev_type,
			&line_width, &lines_per_page)) != SS$_NORMAL)
		_trouble("sctype -> lib$screen_info");
	if ((flags & 02) != 0) {
		dev_type = 96;		/* VT100 compatible terminal	*/
	}
	flags &= 01;			/* Other bits meaningless	*/
	return (dev_type + flags);
}

int
scerln(_row, _col)
int		_row;
int		_col;
/*
 * Erase line
 */
{
	extern scr$erase_line();

	if (_row == 0 || _col == 0)
		_err = scr$erase_line();
	else
		_err = scr$erase_line(_row, _col);
	if (_err != SS$_NORMAL)
		_trouble("scerln -> scr$erase_line()");
}

int
scerpg(_row, _col)
int		_row;
int		_col;
/*
 * Erase page
 */
{
	extern scr$erase_page();

	if (_row == 0 || _col == 0)
		_err = scr$erase_page();
	else
		_err = scr$erase_page(_row, _col);
	if (_err != SS$_NORMAL)
		_trouble("scerpg -> scr$erase_page()");
}

int
scout(_row, _col, _text)
int		_row;
int		_col;
char		*_text;
/*
 * Output text
 */
{
	extern scr$put_screen();
	extern scr$set_cursor();
	extern lib$set_buffer();
	extern lib$put_buffer();
	int		errcode;
	_DESCRIPTOR	textp;

	if (_row != 0 && _col != 0) {
		if ((_err = scr$set_cursor(_row, _col)) != SS$_NORMAL)
			_trouble("scout -> scr$set_cursor");
	}
	if (_text != NULL) {
		textp.loc = _text;
		textp.size = strlen(_text);
		if (stored + textp.size >= paranoid)
			flush_buffer();
		if ((_err = scr$put_screen(&textp)) != SS$_NORMAL)
			_trouble("scout -> scr$put_screen");
		stored += textp.size;
	}
	else {
		/*
		 * Flush current buffer
		 */
		flush_buffer();
	}
}

static
flush_buffer()
/*
 * Flush current buffer
 */
{
	if ((_err = lib$put_buffer(&NULL)) != SS$_NORMAL)
		_trouble("flush_buffer -> lib$putbuffer()");
	if ((_err = lib$set_buffer(&_newbuf_)) != SS$_NORMAL)
		_trouble("flush_buffer -> lib$set_buffer(&_newbuf_)");
	stored = 0;
}

scget(_text, _textsize, _prompt)
char		*_text;
int		_textsize;
char		*_prompt;
/*
 * Get from the screen
 */
{
	_DESCRIPTOR	_textp;
	_DESCRIPTOR	_promptp;
	short int	_bytes_gotten;
	extern int	lib$get_screen();

	_textp.loc = _text;
	_textp.size = _textsize;
	if (_prompt == NULL) {
		_promptp.loc = "";
		_promptp.size = 0;
	}
	else {
		_promptp.loc = _prompt;
		_promptp.size = strlen(_prompt);
	}
	flush_buffer();				/* Why is this needed?	*/
	if ((_err = lib$get_screen(&_textp, &_promptp, &_bytes_gotten))
			!= SS$_NORMAL) {
		if (_err != RMS$_EOF) {
			fprintf(stderr,
				"scget -> lib$get_screen code %08x\n", _err);
			sleep(3);
		}
		_text[0] = '\0';
		return(NULL);
	}
	else {
		_text[_bytes_gotten] = '\0';	/* Terminate string	*/
		return (_text);
	}
}	

static
_trouble(where)
char		*where;
{
	fprintf(stderr, "\nscreen error %x %d. from %s\n", _err, _err, where);
/*
 *	exit(_err);
 */
	lib$stop(_err);
}
