/* this file is intentionally ugly */
#ifndef __sio_h
#define __sio_h

#include "config.h"

/* synchronized I/O */
#ifdef HAVE_POLL
#include <sys/types.h>
#include <sys/poll.h>
#else
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#endif

#include "bin.h"

#define sio_read	1
#define sio_write	2
#define sio_infinite	-1
#define sio_infinity sio_infinite

int inline sio_test(bin_t b, int fd)
{
	register int op;
#ifdef HAVE_POLL
	struct pollfd *pf;
	register int i;
	int pfnum;

	pf = (struct pollfd *)caddr(b);
	if (!pf)
		return 0;

	pfnum = (bin_len(b)) / sizeof(struct pollfd);
	for (i = 0; i < pfnum; i++) {
		if (pf[i].fd == fd) {
			op = 0;
			if (pf[i].revents & (POLLIN|POLLPRI|POLLHUP))
				op |= sio_read;
			if (pf[i].revents & POLLOUT)
				op |= sio_write;
			return op;
		}
	}
	return 0;
#else
	fd_set *r, *w;

	if (caddr(b) == 0)
		return 0;

	bin_need(b, sizeof(fd_set) * 2);
	r = (fd_set *)(caddr(b));
	w = (fd_set *)(((char *)caddr(b)) + sizeof(fd_set));

	op = 0;
	if (FD_ISSET(fd, r))
		op |= sio_read;
	if (FD_ISSET(fd, w))
		op |= sio_write;

	return op;
#endif
}

int inline sio_block(bin_t b, int timeout)
{
#ifdef HAVE_POLL
	struct pollfd *pf;
	int pfnum;

	pf = (struct pollfd *)caddr(b);
	if (!pf)
		return 0;

	pfnum = (bin_len(b)) / sizeof(struct pollfd);

	return poll(pf, pfnum, timeout);
#else
	fd_set *r, *w;
	struct timeval tv;
	int high;

	if (caddr(b) == 0)
		return 0;

	bin_need(b, sizeof(fd_set) * 2);
	r = (fd_set *)(caddr(b));
	w = (fd_set *)(((char *)caddr(b)) + sizeof(fd_set));
	high = *(int *)(((char *)caddr(b)) + (sizeof(fd_set)+sizeof(fd_set)));

	if (timeout < 0) {
		return select(high+1, r, w, 0, 0);
	} else {
		tv.tv_sec = 0;
		tv.tv_usec = timeout;
		return select(high+1, r, w, 0, &tv);
	}
#endif
}
void inline sio_remove(bin_t b, int fd)
{
#ifdef HAVE_POLL
	struct pollfd *pf;
	register int i;
	int pfnum;

	pf = (struct pollfd *)caddr(b);
	if (pf) {
		pfnum = (bin_len(b)) / sizeof(struct pollfd);

		for (i = 0; i < pfnum; i++) {
			if (fd == -1 || pf[i].fd == fd) {
				pf[i].fd = -1;
				pf[i].events = 0;
				pf[i].revents = 0;
				if (fd != -1)
					break;
			}
		}
	}
#else
	fd_set *r, *w;
	register int i;
	int *high;

	i = (caddr(b) == 0) ? 1 : 0;
	bin_need(b, (sizeof(fd_set) * 2) + sizeof(int));
	r = (fd_set *)(caddr(b));
	w = (fd_set *)(((char *)caddr(b)) + sizeof(fd_set));
	high = (int *)(((char *)caddr(b)) + (sizeof(fd_set)+sizeof(fd_set)));

	if (i || fd == -1) {
		FD_ZERO(r); FD_ZERO(w);
		*high = 0;
	} else {
		FD_CLR(fd, r);
		FD_CLR(fd, w);
	}
#endif
}
void inline sio_flush(bin_t b)
{
	sio_remove(b, -1);
}
void inline sio_add(bin_t b, int fd, int ops)
{
#ifdef HAVE_POLL
	struct pollfd *pf;
	register int i;
	int pfnum;

	if (fd == -1)
		return;

	/* search for a -1 */
	pf = (struct pollfd *)caddr(b);
	if (!pf) {
		i = pfnum = 0;
	} else {
		pfnum = (bin_len(b)) / sizeof(struct pollfd);

		for (i = 0; i < pfnum; i++) {
			if (pf[i].fd == -1)
				break;
		}
	}
	if (i == pfnum) {
		bin_needplus(b, sizeof(struct pollfd));
		clen(b) = bin_len(b); /* update length */
		pf = (struct pollfd *)caddr(b);
	}
	pf[i].fd = fd;
	pf[i].events = 0;
	pf[i].revents = 0;
	if (ops & sio_read)
		pf[i].events |= (POLLIN|POLLPRI);
	if (ops & sio_write)
		pf[i].events |= POLLOUT;
#else
	fd_set *r, *w;
	register int i;
	int *high;

	if (fd == -1)
		return;

	i = (caddr(b) == 0) ? 1 : 0;
	bin_need(b, (sizeof(fd_set) * 2) + sizeof(int));
	r = (fd_set *)(caddr(b));
	w = (fd_set *)(((char *)caddr(b)) + sizeof(fd_set));
	high = (int *)(((char *)caddr(b)) + (sizeof(fd_set)+sizeof(fd_set)));

	if (i) {
		FD_ZERO(r); FD_ZERO(w);
		*high = fd;
	} else if (fd > *high)
		*high = fd;

	if (ops & sio_read)
		FD_SET(fd, r);
	if (ops & sio_write)
		FD_SET(fd, w);
#endif
}

#endif


syntax highlighted by Code2HTML, v. 0.9.1