/* com_unix.c
 * Unix  specific communication routines
 * Tested on NeXT and Sony
 */

#ifdef NeXT
#include <libc.h>
#include <ctype.h>
#include <errno.h>
#else
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/errno.h>
#endif

#include "bink.h"
#include "externs.h"
#include "com.h"
#include "keybd.h"

/*#define NEXTDEBUG*/
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif

/* do not lowercase filenames here! */
#ifdef open
#undef open
#endif

unsigned int st_lock_baud = 0;	/* Baud rate above which to force baud rate */ 
int unix_line= -1;		/* fd for open modem port */	
static int last_baud = 0;		/* Current setting */
static int portnum = -1;		/* port number that is currently open */

/* Define the available ttys and their lock files */
#if defined(NeXT)
	/* ttys used to dial out
	 * may or may not respond to SIGHUP
	 * must not block waiting for DCD
	 */
	char *ttynames[] = {
		"/dev/cua",
		"/dev/cub",
		"/dev/cufa",
		"/dev/cufb"
	};
	/* tyys used to spawn login and bbs processes on
	 * must respond to SIGHUP
	 * may block waiting for DCD
	 */
	char *dialupnames[] = {
		"/dev/ttyda",
		"/dev/ttydb",
		"/dev/ttydfa",
		"/dev/ttydfb"
	};
	char *lcknames[] = {
		"/usr/spool/uucp/LCK/LCK..cua",
		"/usr/spool/uucp/LCK/LCK..cub",
		"/usr/spool/uucp/LCK/LCK..cufa",
		"/usr/spool/uucp/LCK/LCK..cufb"
	};
#elif defined(linux)
	/* ttys used to dial out
	 * may or may not respond to SIGHUP
	 * must not block waiting for DCD
	 */
	char *ttynames[] = {
		"/dev/cua0",
		"/dev/cua1",
		"/dev/cua2",
		"/dev/cua3"
	};
	/* tyys used to spawn login and bbs processes on
	 * must respond to SIGHUP
	 * may block waiting for DCD
	 */
	char *dialupnames[] = {
		"/dev/ttyS0",
		"/dev/ttyS1",
		"/dev/ttyS2",
		"/dev/ttyS3"
	};
	char *lcknames[] = {
		"/usr/spool/uucp/LCK..cua0",
		"/usr/spool/uucp/LCK..cua1",
		"/usr/spool/uucp/LCK..cua2",
		"/usr/spool/uucp/LCK..cua3"
	};
#elif defined(Sony)
    char *ttynames[] = {
		"/dev/tty00"
	};
    char *dialupnames[] = {
		"/dev/!!!UNKNOWN!!!"
	};
    char *lcknames[] = {
		"/usr/spool/uucp/LCK/LCK..tty00"
	};
#else
#error Must define ttynames!
#endif

/*
 * I/O buffers
 */
#define TSIZE 8192

typedef struct {
	unsigned char buf[TSIZE];
	int readpos;
	int writepos;
	int inbuf;
} BufferType;

static BufferType txBuf;
static BufferType rxBuf;

void initBuffer(BufferType *buf)
{
	buf->readpos = 0;
	buf->writepos = 0;
	buf->inbuf = 0;
}

int inBuffer(BufferType *buf)
{
	return buf->inbuf;
}

int leftBuffer(BufferType *buf)
{
	return TSIZE-buf->inbuf;
}

unsigned char getBuffer(BufferType *buf)
{
	unsigned char result = 0;
	
	if(buf->inbuf > 0) {
		result = buf->buf[buf->readpos];
		buf->readpos = (buf->readpos+1) % TSIZE;
		buf->inbuf--;
	} else {
		status_line(" getBuffer: empty");
		exit(1);
	}

	return result;
}

unsigned char peekBuffer(BufferType *buf)
{
	unsigned char result = 0;
	
	if(buf->inbuf > 0) {
		result = buf->buf[buf->readpos];
	} else {
		status_line(" peekBuffer: empty\n");
		exit(1);
	}

	return result;
}

void putBuffer(BufferType *buf, unsigned char ch)
{
	if(buf->inbuf < TSIZE) {
		buf->buf[buf->writepos] = ch;
		buf->writepos = (buf->writepos+1) % TSIZE;
		buf->inbuf++;
	} else {
		status_line(" putBuffer: full\n");
		exit(1);
	}
}

/* ================== timer functions ================== */

#ifdef Sony

long clock()
{
    static long seed=0;
    struct timeval tv;
    struct timezone tz;

    gettimeofday(&tv, &tz);
    if (seed==0)
        seed=tv.tv_sec;
    return (tv.tv_sec-seed)*1000 + tv.tv_usec/1000;
}
#define CLK_TCK 1000

#endif /* Sony - no clock */


/* Indicate timer is to time out in t/100 second */
long timerset(unsigned long t)
{
	struct timeval tp;
	struct timezone tzp;

	gettimeofday(&tp, &tzp);
	return tp.tv_sec*100+tp.tv_usec/10000 + t;
}

/* Return TRUE if timer as timed out */
BOOLEAN timeup(long t)
{
	struct timeval tp;
	struct timezone tzp;

	gettimeofday(&tp, &tzp);
	return tp.tv_sec*100+tp.tv_usec/10000 >= t;
}


/* ================== modem functions ================== */

/*
 * Initialise comms port
 */
int Cominit(int port)
{
	int tmp, pid, fd;
#ifdef USG
	struct termios tios;
#else
	struct sgttyb sg;
#endif

#ifdef NEXTDEBUG
	fprintf(stderr, "opening port %d = %s\n", port, str[port]);
#endif

	/* sanity check */
	if(portnum == -1) {
		/* try to create lock file */
		while (1) {
			fd = open(lcknames[port], O_CREAT | O_EXCL | O_RDWR, 0444);
			if(fd < 0) {
				/* could not create lock file */
				if (errno == EEXIST) {
					/* there was a lock file,
					 * check to see if its owner still lives
					 */
					fd = open(lcknames[port], O_RDONLY);
					if(fd < 0) {
						bt_perror("Cannot open existing lock file");
						return 0;
					}
					if (read(fd, (char *) &pid, 4) != 4) {
						bt_perror("Cannot read existing lock file");
						close(fd);
						return 0;
					}
					close(fd);

					if(kill(pid, 0) == -1) {
						if(errno == ESRCH) {
							/* that process no longer exists,
							 * remove lock file
							 */
							if (unlink(lcknames[port]) == -1) {
								bt_perror("Cannot remove lockfile");
								return 0;
							}
						} else {
							bt_perror("cannot access locking process");
							return 0;
						}
					} else {
						/* process still lives */
						return 0;
					}
				} else {
					bt_perror("Cannot create lock file");
					return 0;
				}
			} else {
				/* opened lock file succesfully */
				break;
			}
		}

		/* write our pid into lock file */
		pid = getpid();
		if(write(fd, (char *) &pid, sizeof(pid)) != sizeof(pid)) {
			bt_perror("Cannot write lock file");
			return 0;
		}
		close(fd);

		/* succesfully locked port, now open it */
		portnum = port;	/* remember which port we opened */
		unix_line = open(ttynames[port], O_RDWR | O_NDELAY, 0);
		if (unix_line < 0 ) {
			bt_perror("BinkleyTerm - Cominit open");
			MDM_DISABLE();
			return 0;
		}
	}
#ifdef USG
	tios.c_iflag = 0;
	tios.c_oflag = 0;
	tios.c_lflag = 0;
 	tios.c_cflag = B0 | CS8 | CREAD | CLOCAL | CRTSCTS; 

	if (tcsetattr(unix_line, TCSANOW, &tios))
		{
		bt_perror("BinkleyTerm - Cominit tcsetattr");
		MDM_DISABLE;
		return 0;
		}

#else	/* ifdef USG */
	tmp = NTTYDISC; /* set new tty style */
	if (ioctl(unix_line, TIOCSETD, &tmp) < 0) {
		bt_perror("BinkleyTerm - Cominit TIOCSETD");
		MDM_DISABLE();
		return 0;
	}
		
#ifdef Sony
    tmp = LPASS8; /* let 8-bits pass */
#else
	tmp = LPASS8 | LPASS8OUT; /* let 8-bits pass */
#endif
	if (ioctl(unix_line, TIOCLBIS, &tmp) < 0) {
		bt_perror("BinkleyTerm - Cominit TIOCLBIS");
		MDM_DISABLE();
		return 0;
	}

	if (ioctl(unix_line, TIOCGETP, &sg) < 0)
		bt_perror("BinkleyTerm - Cominit TIOCGETP");
	sg.sg_flags |= RAW;
	sg.sg_flags &= ~ECHO;
	sg.sg_flags &= ~TANDEM;
	if (ioctl(unix_line, TIOCSETN, &sg) < 0) {
		bt_perror("BinkleyTerm - Cominit TIOCSETN");
		MDM_DISABLE();
		return 0;
	}
#endif /* ifdef  USG */

	last_baud = 0;
	initBuffer(&txBuf);
	initBuffer(&rxBuf);
	CLEAR_INBOUND();

	return 0x1954;	/* Return magic number */
}

/*
 * Close up the comms port and restore everything to normal
 */
 
void MDM_DISABLE(void)
{
#ifdef NEXTDEBUG
	fprintf(stderr, "closing port %d\n", unix_line);
#endif

	initBuffer(&txBuf);
	initBuffer(&rxBuf);

	/* sanity check */
	if(portnum != -1) {
		if(close(unix_line) == -1)
			bt_perror("BinkleyTerm - MDM_DISABLE close");
		unix_line = -1;
	
		/* remove lock file */
		if (unlink(lcknames[portnum]) == -1) {
			bt_perror("Cannot remove lockfile");
		}
		portnum = -1;
	}
}

/*
 * Initialise modem to give baud rate
 * The baud will be the bits defined as BAUD_??? in com_unix.h
 */

void MDM_ENABLE(unsigned baud)
{
#ifdef USG
	struct termios tios;
#else
	struct sgttyb sg;
#endif
	
	if(st_lock_baud && (baud >= st_lock_baud))
		baud = max_baud.rate_mask;

/*	if(baud != last_baud) { */
#ifdef NEXTDEBUG
		fprintf(stderr, "MDM_ENABLE baud = %d\n", baud);
#endif
		last_baud = baud;
#ifdef USG
		if (tcgetattr(unix_line, &tios))
			bt_perror("BinkleyTerm - MDM_ENABLE tcgetattr");
		if (cfsetospeed(&tios, baud))
			bt_perror("BinkleyTerm - MDM_ENABLE cfsetospeed");
		if (tcsetattr(unix_line, TCSANOW, &tios))
			bt_perror("BinkleyTerm - MDM_ENABLE tcsetattr");
#else	/* not USG */
		if (ioctl(unix_line, TIOCGETP, &sg) < 0)
			bt_perror("BinkleyTerm - MDM_ENABLE TIOCGETP");
		sg.sg_ispeed = sg.sg_ospeed = baud;
		sg.sg_flags |= RAW; /* todo: this is redundant? See Cominit */
		sg.sg_flags &= ~ECHO;
		if (ioctl(unix_line, TIOCSETN, &sg) < 0)
			bt_perror("BinkleyTerm - MDM_ENABLE TIOCSETN");
#endif	/* USG */
/*	}*/
}

void DTR_ON(void)
{
#ifdef USG
	int set_status_line = TIOCM_DTR;
#endif

#ifdef NEXTDEBUG
	fprintf(stderr, "Setting DTR on, line = %d\n", unix_line);
#endif

#ifdef USG
	if(ioctl(unix_line, TIOCMBIS, set_status_line) < 0)
		bt_perror("BinkleyTerm - DTR_ON");
#else
	if(ioctl(unix_line, TIOCSDTR, NULL) < 0)
		bt_perror("BinkleyTerm - DTR_ON");
#endif
}

void DTR_OFF(void)
{
#ifdef USG
	int reset_status_line = TIOCM_DTR;
#endif

#ifdef NEXTDEBUG
	fprintf(stderr, "Setting DTR off, line = %d\n", unix_line);
#endif
#ifdef USG
	if(ioctl(unix_line, TIOCMBIC, reset_status_line) < 0)
		bt_perror("BinkleyTerm - DTR_OFF");
#else

	if(ioctl(unix_line, TIOCCDTR, NULL) < 0)
		bt_perror("BinkleyTerm - DTR_OFF");
#endif
}

void XON_ENABLE(void)
{
#ifdef NeXT
	struct sgttyb sg;

#ifdef NEXTDEBUG
	fprintf(stderr, "setting XON_ENABLE\n");
#endif
	if (ioctl(unix_line, TIOCGETP, &sg) < 0)
		bt_perror("BinkleyTerm - XON_ENABLE TIOCGETP");
	sg.sg_flags |= TANDEM;
	if (ioctl(unix_line, TIOCSETN, &sg) < 0)
		bt_perror("BinkleyTerm - XON_ENABLE TIOCSETN");
#endif
}

void XON_DISABLE(void)
{
#ifdef NeXT
	struct sgttyb sg;

#ifdef NEXTDEBUG
	fprintf(stderr, "setting XON_DISABLE\n");
#endif
	if (ioctl(unix_line, TIOCGETP, &sg) < 0)
		bt_perror("BinkleyTerm - XON_DISABLE TIOCGETP");
	sg.sg_flags &= ~TANDEM;
	if (ioctl(unix_line, TIOCSETN, &sg) < 0)
		bt_perror("BinkleyTerm - XON_DISABLE TIOCSETN");
#endif
}

void IN_XON_ENABLE(void)
{
#ifdef NEXTDEBUG
	fprintf(stderr, "setting IN_XON_ENABLE\n");
#endif
	XON_ENABLE();
}

/* get carrier status */
long get_dcd(void)
{
	int tmp = 0;

	if(ioctl(unix_line, TIOCMGET, &tmp) < 0)
			bt_perror("get_dcd");

	return (tmp & TIOCM_CD) != 0;
}

/* ================== console input functions ================== */

BOOLEAN KEYPRESS(void)
{
	int numchar;

	if(ioctl(0, FIONREAD, &numchar) < 0) /* use stdin */
		bt_perror("BinkleyTerm - KEYPRESS");

	return numchar > 0;
}

/*
 * BSD specific key input, to return similar sort of codes as the PC
 *
 * i.e. if it is an ascii character then that is in low 8 bits
 * otherwise a keyscan is in bits 8..15
 * todo: not really implemented yet...
 *
 * todo: On the NeXT, Alt-key returns Esc followed by key.
 * upper/lowercase dep on shift key.
 */

int getkey(void)
{
	unsigned char c=0;
	int numchar;
	
	if(read(0, &c, 1) != 1)
		bt_perror("BinkleyTerm - getkey read 1");
#ifdef NEXTDEBUG
	fprintf(stderr, "NORM-'%c' ", (int)c);
#endif

	if(c == 0x1b) {
		/* got escape, might be ALT code.
		 * check if there are any more characters waiting:
		 */
		if(ioctl(0, FIONREAD, &numchar) < 0)
			bt_perror("BinkleyTerm - getkey ioctl 1");
#ifdef Sony
        numchar=1;  /* simulate function keys with esc prefix */
#endif
		if( numchar > 0 ) {
			/* assume alternate key */
			if(read(0, &c, 1) != 1)
				bt_perror("BinkleyTerm - getkey read 2");
#ifdef NEXTDEBUG
	fprintf(stderr, "ALT-'%c' ", (int)c);
#endif
			if(c == '[') {
				/* might be vt escape code */
				if(ioctl(0, FIONREAD, &numchar) < 0)
					bt_perror("BinkleyTerm - getkey ioctl 2");
				if( numchar > 0 ) {
					/* assume vt key */
					if(read(0, &c, 1) != 1)
						bt_perror("BinkleyTerm - getkey read 3");
#ifdef NEXTDEBUG
	fprintf(stderr, "VT-'%c' ", (int)c);
#endif
					switch(c) {
					case 'A':
						return UPAR;
						break;
					case 'B':
						return DNAR;
						break;
					case 'C':
						return RTAR;
						break;
					case 'D':
						return LFAR;
						break;
					}
				}
			}
			return ((int)c) << 8;
		}
	}

	return (int)c;
}

/* ================== modem input functions ================== */

/* get data from modem port into zRxBuf,
 * return TRUE if data is available.
 */

int fill_rbuf(void)
{
	int i,
	    numchar = 0;
	static char tmpbuf[TSIZE];

	if (inBuffer(&rxBuf) > 0)
		return TRUE;

	/* if inrbuf == TSIZE return... */

	if(ioctl(unix_line, FIONREAD, &numchar) < 0)
		bt_perror("BinkleyTerm - fill_rbuf ioctl");

	if(numchar > 0) {
		numchar = read(unix_line, tmpbuf, leftBuffer(&rxBuf));
		if (numchar == 0)
			bt_perror("BinkleyTerm - fill_rbuf read");
		for(i=0; i<numchar; i++) {
			putBuffer(&rxBuf, tmpbuf[i]);
		}
#ifdef NEXTDEBUG
		fprintf(stderr, "\r#ch=%d ", numchar);
#endif
	}

	return inBuffer(&rxBuf) > 0;
}

BOOLEAN CHAR_AVAIL(void)
{
	return fill_rbuf();
}

void CLEAR_INBOUND(void)
{
#ifndef USG
	int what;
#endif

#ifdef NEXTDEBUG
	fprintf(stderr, "CLEAR_INBOUND\n");
#endif

#ifdef USG
	if(tcflush(unix_line, TCIFLUSH) < 0)
		bt_perror("BinkleyTerm - CLEAR_INBOUND");
#else	
	what = FREAD;
	if(ioctl(unix_line, TIOCFLUSH, &what) < 0)
		bt_perror("BinkleyTerm - CLEAR_INBOUND");
#endif
	initBuffer(&rxBuf);
}

int MODEM_IN(void)
{
	unsigned char c=0;

	while(!fill_rbuf())
		;
	
	c = getBuffer(&rxBuf);
#ifdef NEXTDEBUG
	fprintf(stderr, "<%c'%02x'", c, c);
#endif
	return c;
}

/*
 * Return the next character in the RS232 input buffer
 * but dont actually take it.
 *
 * Return -1 if buffer was empty
 */

int PEEKBYTE(void)
{
	if(fill_rbuf())
		return (int) peekBuffer(&rxBuf);
	else
		return -1;
}

/* ================== modem output functions ================== */


BOOLEAN OUT_FULL(void)
{
	int out;

	if(ioctl(unix_line, TIOCOUTQ, &out) < 0)
		bt_perror("BinkleyTerm - OUT_FULL");

#ifdef NEXTDEBUG
	if(out >= BUFSIZ)
		fprintf(stderr, "OUT_FULL numout = %d\n", out);
#endif
	return out >= 1 /*BUFSIZ*/; /* todo: will this actually work? */
}

BOOLEAN OUT_EMPTY(void)
{
	int out;
	
	if(ioctl(unix_line, TIOCOUTQ, &out) < 0)
		bt_perror("BinkleyTerm - OUT_EMPTY");

#ifdef NEXTDEBUG
	if(out > 0)
		fprintf(stderr, "OUT_EMPTY numout = %d\n", poutmt);
#endif

	return out == 0;
}

void CLEAR_OUTBOUND(void)
{
#ifndef USG
	int what;
#endif

#ifdef NEXTDEBUG
	fprintf(stderr, "CLEAR_OUTBOUND\n");
#endif

#ifdef USG
	if(tcflush(unix_line, TCOFLUSH) < 0)
		bt_perror("BinkleyTerm - CLEAR_OUTBOUND");
#else
	what = FWRITE;
	if(ioctl(unix_line, TIOCFLUSH, &what) < 0)
		bt_perror("BinkleyTerm - CLEAR_OUTBOUND");
#endif
	initBuffer(&txBuf);
}

void SENDBYTE(unsigned char c)
{
#ifdef NEXTDEBUG
	fprintf(stderr, ">%c'%02x'", (unsigned int)c, (unsigned int)c);
#endif

	if(write(unix_line, &c, 1) == -1)
		bt_perror("BinkleyTerm - SENDBYTE");
}

/*
 * Send a block of data to modem
 * if carcheck is non zero then abort if no carrier
 *
 * Will NOT wait for buffer space.
 */

void SENDCHARS(unsigned char *buf, size_t size, BOOLEAN carcheck)
{
	int numsent = 0;

	while( (!carcheck || CARRIER) && (size > 0)) {
		numsent = write(unix_line, buf, size);
		if(numsent == -1) {
			bt_perror("BinkleyTerm - SENDCHARS");
		} else {
			size -= numsent;
			buf += numsent;
		}
	}
}

/* todo: this should never block! */
BOOLEAN Com_Tx_NW(unsigned char ch)
{
#ifdef NEXTDEBUG
	fprintf(stderr, ">%c'%02x'", (unsigned int)ch, (unsigned int)ch);
#endif

	if(write(unix_line, &ch, 1) == -1) {
		bt_perror("BinkleyTerm - Com_Tx_NW");
		return FALSE;
	} else
		return TRUE;
}

/*
 * Send character, but buffer it up
 * and force a send with UNBUFFER_BYTES
 * used by zsend and janus
 */

void BUFFER_BYTE(unsigned char ch)
{
	if(leftBuffer(&txBuf) == 0)		/* If buffer full, then empty it */
		 UNBUFFER_BYTES();
	putBuffer(&txBuf, ch);			/* Add character to buffer */
}

void UNBUFFER_BYTES(void)
{
	static unsigned char tmpbuf[TSIZE];
	int numch, i;

	numch = inBuffer(&txBuf);
	if(numch && CARRIER) {
		if(numch == 1)
			SENDBYTE(getBuffer(&txBuf));
		else {
			for(i=0; i < numch; i++)
				tmpbuf[i] = getBuffer(&txBuf);
			SENDCHARS(tmpbuf,numch,1);
		}
	}
}

void do_break(int b)		/* Send break signal */
{
#ifdef USG
	if (tcsendbreak(unix_line, 0))
		bt_perror("BinkleyTerm - do_break");
#else
	if(ioctl(unix_line, TIOCSBRK, NULL) < 0)
		bt_perror("BinkleyTerm - TIOCSBRK");
	usleep(500000L);
	if(ioctl(unix_line, TIOCCBRK, NULL) < 0)
		bt_perror("BinkleyTerm - TIOCCBRK");
#endif
}

/* ================== utility functions ================== */

void dostime(int *hour, int *min, int *sec, int *hdths)
{
	time_t t;
	struct tm *dt;

	time(&t);
	dt = localtime(&t);

	*hour	   = dt->tm_hour;	/* current hour */
	*min	   = dt->tm_min;	/* current minute */
	*sec	   = dt->tm_sec;	/* current second */
	*hdths	   = 0;			/* hundredths of seconds */
}

void dosdate(int *month, int *mday, int *year, int *weekday)
{
	time_t t;
	struct tm *dt;

	time(&t);
	dt = localtime(&t);

	*mday	   = dt->tm_mday;	/* current day */
	*month	   = dt->tm_mon;	/* current month */
	*year	   = dt->tm_year;	/* current year */
	*weekday   = dt->tm_wday;	/* current day of week */
}

int real_flush(int f)		/* Flush the file */
{
	/* nothing needed as a fflush has already been done */
	return 0;
}

size_t filelength(int handle)
{
	struct stat buf;
	if (fstat(handle, &buf) == 0)
		return buf.st_size;
	else
		return -1;
}

#if 0
int strnicmp(const char *s1, const char *s2, size_t count)
{
    return strncasecmp(s1, s2, count);
}

int stricmp(const char *s1, const char *s2)
{
    return strcasecmp(s1, s2);
}
#endif

char *strupr(char *s)
{
	char *org = s;

	while(*s) {
		if(islower(*s))
			*s = toupper(*s);
		s++;
	}
	return org;
}

char *strlwr(char *s)
{
	char *org = s;

	while(*s) {
		if(isupper(*s))
			*s = tolower(*s);
		s++;
	}
	return org;
}

void putenv(char *str)
{
        /* Nothing */
}

#ifndef Sony /* already here */
#ifndef linux /* already here */
void tzset()
{
        /* Nothing */
}
#endif
#endif

char *strdup(const char *str)
{
	char *res;
	if(str == NULL)
		return NULL;
	res = (char *)malloc(strlen(str)+1);
	if(res == NULL)
		return NULL;
	strcpy(res, str);
    return res;
}

char *ultoa (unsigned long value, char * string, int radix)
{
	switch(radix) {
		case 8:
			sprintf(string, "%lo", value);
			break;
		case 10:
			sprintf(string, "%lu", value);
			break;
		case 16:
			sprintf(string, "%lx", value);
			break;
		default:
			status_line(" ultoa error, unsupported radix %d.\n", radix);
			break;
	}
	return string;
}

int wait_event(int event, int time)
{
	struct timeval timeout;
	fd_set readfds;
	int nfound, nfds, result;

	if((event & SEL_MODEM) && (inBuffer(&rxBuf) > 0)) {
		result =  SEL_MODEM;
	} else {
		FD_ZERO(&readfds);
		FD_SET(unix_line, &readfds);
		FD_SET(0, &readfds);
		nfds = unix_line+1;

		if((event & SEL_TIME) && (time >= 0)) {
			timeout.tv_sec = time / 100;
			timeout.tv_usec = (time % 100) * 10000;
			nfound = select(nfds, &readfds, NULL, NULL, &timeout);
		} else {
			nfound = select(nfds, &readfds, NULL, NULL, NULL);
		}

		if(nfound == -1) {
			bt_perror("BinkleyTerm - wait_event select");
			status_line(" Event = %d, time = %d\n", event, time);
		}

		result = 0;
		if(FD_ISSET(unix_line, &readfds))
			result |= SEL_MODEM;
		if(FD_ISSET(0, &readfds))
			result |= SEL_CONSOLE;
		if(nfound == 0)
			result |= SEL_TIME;
	}

#ifdef NEXTDEBUG
	fprintf(stderr, "\rwait_event = %d, %d, %d, %d ",
		result, nfound, timeout.tv_sec, timeout.tv_usec);
#endif

	return result;
}

void bt_perror(char *s)
{
	if(s)
		status_line (" %s: %s\n", s, strerror(errno));
	else
		status_line (" %s\n", strerror(errno));
}

