ftp.nice.ch/pub/next/unix/macintosh/uw.4.2.N.bs.tar.gz#/uw/lib/uw_options.c

This is uw_options.c in view mode; [Download] [Up]

/*
 *	uw library - uw_options
 *
 * Copyright 1986 by John D. Bruner.  All rights reserved.  Permission to
 * copy this program is given provided that the copy is not sold and that
 * this copyright notice is included.
 */
#include <sys/types.h>
#include <sys/file.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <strings.h>
#include <signal.h>
#include <errno.h>

#include "uwlib.h"

#ifndef FD_SET
#define	FD_SET(n,p)	((p)->fds_bits[0] |= (1 << (n)))
#define	FD_CLR(n,p)	((p)->fds_bits[0] &= ~(1 << (n)))
#define	FD_ISSET(n,p)	((p)->fds_bits[0] & (1 << (n)))
#define	FD_ZERO(p)	((p)->fds_bits[0] = 0)
#define	FD_SETSIZE	(NBBY*sizeof(long))
#endif

#ifndef sigmask
#define sigmask(m)	(1 << ((m)-1))
#endif

#ifndef htons
/* These should have been defined in <netinet/in.h>, but weren't (in 4.2BSD) */
extern unsigned short htons(), ntohs();
extern unsigned long htonl(), ntohl();
#endif

static UWIN *fdmap;
static int (*oldsigio)();
static struct fd_set fdmask;
static int nfds;

extern char *malloc();

uw_optinit(fd, uwin)
int fd;
UWIN uwin;
{
	register int i, flags;
	static int first = 1;
	extern uw_optinput();

	/*
	 * The first time through, allocate the file descriptor map and
	 * bitmask, and cause SIGIO traps to be handled by uw_optinput.
	 */
	if (first) {
		first = 0;
		nfds = getdtablesize();
		fdmap = (UWIN *)malloc((unsigned)(sizeof(UWIN)*nfds));
		if (fdmap != (UWIN *)0)
			for (i = 0; i < nfds; i++)
				fdmap[i] = (UWIN)0;
		oldsigio = signal(SIGIO, uw_optinput);
		FD_ZERO(&fdmask);
	}

	/*
	 * Add the new control fd to the map and mask.  Set the owner
	 * to this process
	 */
	if (fd >= 0 && fd < nfds && uwin != (UWIN)0 && fdmap != (UWIN *)0) {
		fdmap[fd] = uwin;
		FD_SET(fd, &fdmask);
#ifdef SETOWN_BUG
		(void)fcntl(fd, F_SETOWN, -getpid());
#else
		(void)fcntl(fd, F_SETOWN, getpid());
#endif
		if ((flags = fcntl(fd, F_GETFL, 0)) >= 0)
			(void)fcntl(fd, F_SETFL, flags|FASYNC|FNDELAY);
		uwin->uwi_ipclen = 0;
	}
}

uw_optdone(fd)
{
	register int flags;

	/*
	 * Turn off asynchronous I/O notification and remove the
	 * map and mask information for "fd".  We do not close the
	 * file descriptor, however -- the caller is expected to
	 * take care of that.
	 */
	if (fd >= 0 && fd < nfds && fdmap != (UWIN *)0) {
		if ((flags = fcntl(fd, F_GETFL, 0)) >= 0)
			(void)fcntl(fd, F_SETFL, flags&~FASYNC);
		else
			(void)fcntl(fd, F_SETFL, 0);
		(void)fcntl(fd, F_SETFL, 0);
		fdmap[fd] = (UWIN)0;
		FD_CLR(fd, &fdmask);
	}
}

static
uw_optinput(sig, code, scp)
int sig, code;
struct sigcontext *scp;
{
	register int k, n, fd;
	register UWIN uwin;
	register struct uwoption *uwop;
	register union uwoptval *uwov;
	uwopt_t optnum;
	uwoptcmd_t optcmd;
	uwfnptr_t userfn;
	int oldmask;
	struct timeval timeo;
	struct fd_set ready;
	extern int errno;

	/*
	 * This routine is called when input is waiting on a control
	 * file descriptor.
	 */
	oldmask = sigblock(sigmask(SIGALRM));
	do {
		ready = fdmask;
		timeo.tv_sec = 0;
		timeo.tv_usec = 0;
		n = select(nfds, &ready, (struct fd_set *)0,
			   (struct fd_set *)0, &timeo);
		if (n < 0 && errno == EBADF) {
			/*
			 * One of the file descriptors that we asked for
			 * is no longer valid.  This isn't supposed to
			 * happen; however, we try to handle it by testing
			 * each bit individually and eliminating the bad
			 * ones.
			 */
			for (fd=0; fd < nfds; fd++) {
				if (FD_ISSET(fd, &fdmask)) {
					do {
						ready = fdmask;
						timeo.tv_sec = 0;
						timeo.tv_usec = 0;
						k = select(nfds, &ready,
						    (struct fd_set *)0,
						    (struct fd_set *)0, &timeo);
						if (k < 0 && errno == EBADF) {
							fdmap[fd] = (UWIN)0;
							FD_CLR(fd, &fdmask);
						}
					} while (n < 0 && errno == EINTR);
				}
			}
		}
	} while (n < 0 && errno == EINTR);

	for (fd=0; n > 0 && fd < nfds; fd++) {
		if (FD_ISSET(fd, &ready)) {
			n--;
			uwin = fdmap[fd];
			while ((k = getmesg(fd, uwin)) > 0) {
				uwin->uwi_ipclen = 0;	/* for next time */
				if (uwin->uwi_ipcbuf.uwip_cmd == UWC_OPTION) {
					uwop = &uwin->uwi_ipcbuf.uwip_option;
					uwov = &uwop->uwop_val;
					optnum = ntohs(uwop->uwop_opt);
					optcmd = ntohs(uwop->uwop_cmd);
					if (optcmd == UWOC_SET)
						uw_ntoh(uwin->uwi_type, optnum,
						    (char *)uwov);
					if (optcmd == UWOC_SET) switch(optnum) {
					case UWOP_VIS:
						uwin->uwi_vis = !!uwov->uwov_6bit;
						break;
					case UWOP_TYPE:
						if (uwov->uwov_6bit<UW_NWTYPES)
							uwin->uwi_type=uwov->uwov_6bit;
						break;
					case UWOP_POS:
						uwin->uwi_pos.uwp_v = uwov->uwov_point.v;
						uwin->uwi_pos.uwp_h = uwov->uwov_point.h;
						break;
					case UWOP_TITLE:
						(void)strncpy(uwin->uwi_title,
						    uwov->uwov_string,
						    sizeof uwin->uwi_title);
						break;
					case UWOP_WSIZE:
						uwin->uwi_wsize.uwp_v = uwov->uwov_point.v;
						uwin->uwi_wsize.uwp_h = uwov->uwov_point.h;
						break;
					}
					if (optnum == UWOP_TYPE &&
					    optcmd == UWOC_SET &&
					    uwov->uwov_6bit < UW_NWTYPES)
						uwin->uwi_type=uwov->uwov_6bit;
					userfn = uwin->uwi_options[optnum].uwi_optfn;
					if (userfn != (uwfnptr_t)0)
						(*userfn)(uwin, optnum,
							  optcmd, uwov);
				}
			}
			if (k < 0)
				(void)uw_detach(uwin);	/* I/O error or EOF */
		}
	}
	(void)sigsetmask(oldmask);

	/*
	 * Finally, if "oldsigio" is not SIG_DFL, call it.
	 */
	if (oldsigio != SIG_DFL)
		(*oldsigio)(sig, code, scp);
}

static
getmesg(fd, uwin)
register int fd;
register UWIN uwin;
{
	register int len;
	register char *cp;

	/*
	 * Read some more bytes from control socket "fd" into the input
	 * buffer.  Return 1 if the message is now complete, -1 if an
	 * EOF was reached, or 0 otherwise.  Before returning 1, the byte
	 * order of the common parameters (command, length) is changed
	 * from network to host order.
	 */
	cp = (char *)&uwin->uwi_ipcbuf + uwin->uwi_ipclen;
	if (uwin->uwi_ipclen < sizeof(uwin->uwi_ipcbuf.uwip_len)) {
		len = read(fd, cp, sizeof uwin->uwi_ipcbuf.uwip_len - uwin->uwi_ipclen);
		if (len == 0 || (len < 0 && errno != EWOULDBLOCK))
			return(-1);
		if (len < 0)
			return(0);
		if ((uwin->uwi_ipclen +=len) < sizeof uwin->uwi_ipcbuf.uwip_len)
			return(0);
		uwin->uwi_ipcbuf.uwip_len = ntohs(uwin->uwi_ipcbuf.uwip_len);
		if (uwin->uwi_ipcbuf.uwip_len==sizeof uwin->uwi_ipcbuf.uwip_len)
			return(1);
		cp += len;
	}
	if (uwin->uwi_ipcbuf.uwip_len > sizeof(struct uwipc))
		uwin->uwi_ipcbuf.uwip_len = sizeof(struct uwipc);
	len = read(fd, cp, uwin->uwi_ipcbuf.uwip_len - uwin->uwi_ipclen);
	if (len == 0 || (len < 0 && errno != EWOULDBLOCK))
		return(-1);
	if ((uwin->uwi_ipclen += len) == uwin->uwi_ipcbuf.uwip_len) {
		uwin->uwi_ipcbuf.uwip_cmd = ntohs(uwin->uwi_ipcbuf.uwip_cmd);
		return(1);
	} else
		return(0);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.