
/*
	poor sgttyb et al / termio and BSD implementations of POSIX termios and wait calls
	good enough to get job control / history list rc working on SunOS 3
*/


#include <stdlib.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <signal.h>
#include "posix.h"


extern int
tcdrain (int fildes)
{
	#ifdef TERMIO
		ioctl (fildes, TCSBRK, !0);
	#else
/*
		struct sgttyb sgttyb;

		ioctl (fildes, TIOCGETP, &sgttyb);
		ioctl (fildes, TIOCSETP, &sgttyb);
*/
	#endif
	return 0;
}


extern int
tcflush (int fildes, int queue_selector)
{
	#ifdef TERMIO
		ioctl (fildes, TCFLSH, queue_selector);
	#else
		ioctl (fildes, TIOCFLUSH, &queue_selector);
	#endif
	return 0;
}


#define setflag(to,from,check,set) \
	if (from & (check)) { \
		termios_p->to |= (set); \
	} else { \
		termios_p->to &= ~(set); \
	}


#define clearflag(to,from,check,set) \
	if (from & (check)) { \
		termios_p->to &= ~(set); \
	} else { \
		termios_p->to |= (set); \
	}


extern int
tcgetattr (int fildes, struct termios *termios_p)
{
	#ifdef TERMIO
		ioctl (fildes, TCGETA, termios_p);
	#else
		ioctl (fildes, TIOCGETP, &(termios_p->sgttyb));
		ioctl (fildes, TIOCLGET, &(termios_p->lmode));
		ioctl (fildes, TIOCGETC, &(termios_p->tchars));
		ioctl (fildes, TIOCGLTC, &(termios_p->ltchars));

		termios_p->c_cc [VERASE] = termios_p->sgttyb.sg_erase;
		termios_p->c_cc [VKILL] = termios_p->sgttyb.sg_kill;
		clearflag (c_lflag, termios_p->sgttyb.sg_flags, CBREAK, ICANON | ISIG);
	#ifdef ISIG
		setflag (c_lflag, termios_p->sgttyb.sg_flags, ISIG, ISIG);
	#elif defined (NOISIG)
		clearflag (c_lflag, termios_p->sgttyb.sg_flags, NOISIG, ISIG);
	#endif
		setflag (c_lflag, termios_p->sgttyb.sg_flags, ECHO, ECHO);
		setflag (c_lflag, termios_p->lmode, LCRTKIL, ECHOK);
		clearflag (c_lflag, termios_p->lmode, LPASS8, ISTRIP);
		termios_p->c_cc [VINTR] = termios_p->tchars.t_intrc;
		termios_p->c_cc [VQUIT] = termios_p->tchars.t_quitc;
		termios_p->c_cc [VSTART] = termios_p->tchars.t_startc;
		termios_p->c_cc [VSTOP] = termios_p->tchars.t_stopc;
		termios_p->c_cc [VEOF] = termios_p->tchars.t_eofc;
		termios_p->c_cc [VEOL] = termios_p->tchars.t_brkc;

		setflag (c_oflag, termios_p->sgttyb.sg_flags, CRMOD, ONLCR);
		setflag (c_iflag, termios_p->sgttyb.sg_flags, CRMOD, ICRNL);
		clearflag (c_oflag, termios_p->lmode, LLITOUT, OPOST);
		termios_p->c_cc [VSUSP] = termios_p->ltchars.t_suspc;
		termios_p->c_cc [VDSUSP] = termios_p->ltchars.t_dsuspc;
		termios_p->c_cc [VREPRINT] = termios_p->ltchars.t_rprntc;
		termios_p->c_cc [VDISCRD] = termios_p->ltchars.t_flushc;
		termios_p->c_cc [VWERSE] = termios_p->ltchars.t_werasc;
		termios_p->c_cc [VLNEXT] = termios_p->ltchars.t_lnextc;
	#endif
	return 0;
}


extern int
tcsetattr (int fildes, int opt_actions, struct termios *termios_p)
{
	#ifdef TERMIO
		ioctl (fildes, opt_actions, termios_p);
	#else
		int ldisc = NTTYDISC;

		if (opt_actions == TCSANOW) ioctl (fildes, TIOCSETD, &ldisc);

		termios_p->sgttyb.sg_erase = termios_p->c_cc [VERASE];
		termios_p->sgttyb.sg_kill = termios_p->c_cc [VKILL];
		clearflag (sgttyb.sg_flags, termios_p->c_lflag, ICANON | ISIG, CBREAK);
	#ifdef ISIG
		setflag (sgttyb.sg_flags, termios_p->c_lflag, ISIG, ISIG);
	#elif defined (NOISIG)
		clearflag (sgttyb.sg_flags, termios_p->c_lflag, ISIG, NOISIG);
	#endif
		setflag (sgttyb.sg_flags, termios_p->c_lflag, ECHO, ECHO);
		setflag (lmode, termios_p->c_lflag, ECHOK, LCRTKIL);
		clearflag (lmode, termios_p->c_lflag, ISTRIP, LPASS8);
		termios_p->tchars.t_intrc = termios_p->c_cc [VINTR];
		termios_p->tchars.t_quitc = termios_p->c_cc [VQUIT];
		termios_p->tchars.t_startc = termios_p->c_cc [VSTART];
		termios_p->tchars.t_stopc = termios_p->c_cc [VSTOP];
		termios_p->tchars.t_eofc = termios_p->c_cc [VEOF];
		termios_p->tchars.t_brkc = termios_p->c_cc [VEOL];

		/* these two are grouped in BSD */
		setflag (sgttyb.sg_flags, termios_p->c_oflag, ONLCR, CRMOD);
		setflag (sgttyb.sg_flags, termios_p->c_iflag, ICRNL, CRMOD);

		clearflag (lmode, termios_p->c_oflag, OPOST, LLITOUT);
		termios_p->ltchars.t_suspc = termios_p->c_cc [VSUSP];
		termios_p->ltchars.t_dsuspc = termios_p->c_cc [VDSUSP];
		termios_p->ltchars.t_rprntc = termios_p->c_cc [VREPRINT];
		termios_p->ltchars.t_flushc = termios_p->c_cc [VDISCRD];
		termios_p->ltchars.t_werasc = termios_p->c_cc [VWERSE];
		termios_p->ltchars.t_lnextc = termios_p->c_cc [VLNEXT];

		/* this is equally (in)valid either way round, but I don't want input to be flushed on TCSADRAIN */
		if (opt_actions != TCSANOW) {
			ioctl (fildes, TIOCSETN, &(termios_p->sgttyb));
		} else {
			ioctl (fildes, TIOCSETP, &(termios_p->sgttyb));
		}
		ioctl (fildes, TIOCLSET, &(termios_p->lmode));
		ioctl (fildes, TIOCSETC, &(termios_p->tchars));
		ioctl (fildes, TIOCSLTC, &(termios_p->ltchars));
	#endif
	return 0;
}


extern pid_t
tcgetpgrp (int fildes)
{
	int pid;

	/* old BSD systems *need* int in the ioctl(), even the ones with 16 bit pid_t */
	ioctl (fildes, TIOCGPGRP, &pid);

	return (pid_t) pid;
}


extern int
tcsetpgrp (int fildes, pid_t pgrp_id)
{
	/* old BSD systems *need* int in the ioctl(), even the ones with 16 bit pid_t */
	int pid = pgrp_id;

	return ioctl (fildes, TIOCSPGRP, &pid);
}


/* only the case where pid == -1 is catered for */

extern pid_t
waitpid (pid_t pid, int *statptr, int options)
{
	return wait3 ((union wait *) statptr, options, NULL);
}



extern int
sigaction (int sig, struct sigaction *act, struct sigaction *oact)
{
	return sigvec (sig, (struct sigvec *) act, (struct sigvec *) oact);
}

extern int
sigprocmask (int operation, sigset_t *set, sigset_t *oset)
{
	int sv_mask;
	extern int sigblock (int mask);
	if (set && operation == SIG_SETMASK) {
		sv_mask = *set;
	} else {
		sv_mask = sigblock (0);
		if (set && operation == SIG_BLOCK) sv_mask |= *set;
		if (set && operation == SIG_UNBLOCK) sv_mask &= ~*set;
	}
	sv_mask = sigsetmask (sv_mask);
	if (oset) *oset = sv_mask;
	return 0;
}

extern int
sigemptyset (sigset_t *set)
{
	*set = 0;
	return 0;
}

extern int
sigaddset (sigset_t *set, int signo)
{
	*set |= 1 << (signo - 1);
	return 0;
}

