#include <setjmp.h>
#include <sys/time.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/ioctl.h>
#include <sgtty.h>
#include <signal.h>
#include <strings.h>
#include "resize.h"

jmp_buf errorret;
FILE	*ttyfp;
char	*strindex();

char *resize(tty,terminal)
	int	tty;
	char	*terminal;
/*
   resets termcap string to reflect current screen size
 */
{
	register char *ptr, *env;
	register int emu = VT100;
	int rows, cols;
	struct sgttyb sg;
	char termcap [1024];
	char newtc [1024];
	char buf[BUFSIZ];
#ifdef TIOCSWINSZ
	struct winsize ws;
#endif	/* TIOCSWINSZ */
	char *getenv(), *strdup();
	int onintr();

	if (!list_cmp(terminal,resize_terms))
		return(NULL);

	if (setjmp(errorret)) {
		ioctl (tty, TIOCSETP, &sgorig);
		return(NULL);
	}
	
	if((ttyfp = fdopen(tty, "r+")) == NULL) {
		return(NULL);
	}
	if((env = getenv("TERMCAP")) && *env)
		strcpy(termcap, env);
	else {
		if(!(env = getenv("TERM")) || !*env) {
			env = "xterm";
		}
		if(tgetent (termcap, env) <= 0) {
			return(NULL);
		}
	}

 	ioctl (tty, TIOCGETP, &sgorig);
	sg = sgorig;
	sg.sg_flags |= RAW;
	sg.sg_flags &= ~ECHO;
	signal(SIGINT, onintr);
	signal(SIGQUIT, onintr);
	signal(SIGTERM, onintr);
	ioctl (tty, TIOCSETP, &sg);

	write(tty, getsize[emu], strlen(getsize[emu]));
	readstring(ttyfp, buf, size[emu]);
	if(sscanf (buf, size[emu], &rows, &cols) != 2) {
		fprintf(stderr, "resize: Can't get rows and columns\r\n");
		onintr();
	}
	if (restore[emu])
		write(tty, restore[emu], strlen(restore[emu]));

#ifdef TIOCGWINSZ
	/* finally, set the tty's window size */
	if(getwsize[emu]) {
	    /* get the window size in pixels */
	    write (tty, getwsize[emu], strlen (getwsize[emu]));
	    readstring(ttyfp, buf, wsize[emu]);
	    if(sscanf (buf, wsize[emu], &ws.ws_xpixel, &ws.ws_ypixel) != 2) {
		fprintf(stderr, "resize: Can't get window size\r\n");
		onintr();
	    }
	    ws.ws_row = rows;
	    ws.ws_col = cols;
	    ioctl (tty, TIOCSWINSZ, &ws);
	} else if (ioctl (tty, TIOCGWINSZ, &ws) != -1) {
	    /* we don't have any way of directly finding out
	       the current height & width of the window in pixels.  We try
	       our best by computing the font height and width from the "old"
	       struct winsize values, and multiplying by these ratios...*/
	    if (ws.ws_xpixel != 0)
	        ws.ws_xpixel = cols * (ws.ws_xpixel / ws.ws_col);
	    if (ws.ws_ypixel != 0)
	        ws.ws_ypixel = rows * (ws.ws_ypixel / ws.ws_row);
	    ws.ws_row = rows;
	    ws.ws_col = cols;
	    ioctl (tty, TIOCSWINSZ, &ws);
	}
#endif	/* TIOCGWINSZ */


	ioctl (tty, TIOCSETP, &sgorig);
	signal(SIGINT, SIG_DFL);
	signal(SIGQUIT, SIG_DFL);
	signal(SIGTERM, SIG_DFL);

	/* update termcap string */
	/* first do columns */
	if ((ptr = strindex (termcap, "co#")) == NULL) {
		return(NULL);
	}
	bzero(newtc,sizeof(newtc));
	strncpy (newtc, termcap, ptr - termcap + 3);
	sprintf (newtc + strlen (newtc), "%d", cols);
	ptr = index (ptr, ':');
	strcat (newtc, ptr);

	/* now do lines */
	if ((ptr = strindex (newtc, "li#")) == NULL) {
		return(NULL);
	}
	strcpy(termcap,"TERMCAP=");
	strncpy (8 + termcap, newtc, ptr - newtc + 3);
	sprintf (8 + termcap + ((int) ptr - (int) newtc + 3), "%d", rows);
	ptr = index (ptr, ':');
	strcat (termcap, ptr);
	return(strdup(termcap));
}

char *strindex (s1, s2)
/*
   returns a pointer to the first occurrence of s2 in s1, or NULL if there are
   none.
 */
register char *s1, *s2;
{
	register char *s3;

	while ((s3 = index (s1, *s2)) != NULL)
	{
		if (strncmp (s3, s2, strlen (s2)) == 0) return (s3);
		s1 = ++s3;
	}
	return (NULL);
}

checkdigits(str)
register char *str;
{
	while(*str) {
		if(!isdigit(*str))
			return(0);
		str++;
	}
	return(1);
}

readstring(fp, buf, str)
register FILE *fp;
register char *buf;
char *str;
{
	register int last;
	struct itimerval it;
	int timeout();

	signal(SIGALRM, timeout);
	bzero((char *)&it, sizeof(struct itimerval));
	it.it_value.tv_sec = TIMEOUT;
	setitimer(ITIMER_REAL, &it, (struct itimerval *)NULL);
	if((*buf++ = getc(fp)) != *str) {
		fprintf(stderr, "resize: unknown character, exiting.\r\n");
		onintr();
	}
	last = str[strlen(str) - 1];
	while((*buf++ = getc(fp)) != last);
	bzero((char *)&it, sizeof(struct itimerval));
	setitimer(ITIMER_REAL, &it, (struct itimerval *)NULL);
	*buf = 0;
}

timeout()
{
	fprintf(stderr, "resize: Time out occurred\r\n");
	onintr();
}

onintr()
{
	longjmp(errorret);
}

/*
 * Duplicate a string in malloc'ed memory
 */
char *strdup(s)
	char	*s;
{
	register char	*cp;
	extern char	*malloc();
	
	if (!(cp = malloc(strlen(s)+1))) {
		printf("Out of memory!!!\n");
		abort();
	}
	return(strcpy(cp,s));
}

/*
 * Compare a string against a null-terminated list of strings
 */
int list_cmp(str,list)
	char *str,**list;
{
	register char	**p, *s;

	s = str;
	for (p = list; *p; p++)
		if (!strcmp(s, *p))
			return(1);
	return(0);
}

