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

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

/*
 *	uw_opt - window option handling for UW
 *
 * 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 "uw_param.h"
#include "uw_opt.h"

/*
 * The following variable is a kludge for efficiency.  It is set to
 * a nonzero value when a bitmask is changed, indicating that opt_scan()
 * should be called.
 */
int calloptscan;			/* pending,do,dont awaits opt_scan */

/* option input state variables */
static caddr_t optwin;			/* window */
static struct woptdefn *optwod;		/* window option definition */
static woptcmd_t optcmd;		/* option command */
static woption_t optnum;		/* current option number */
static woptarg_t *optarg;		/* current encoding */
static int optcnt;			/* count in current encoding */
static char *optout;			/* decoded option */
static char optbuf[512];		/* buffer for decoded option */

opt_new(wod, generic, unique)
register struct woptdefn *wod, *generic, *unique;
{
	register int n, mask;

	/*
	 * Set up the option definition structure pointed to by "wod" to
	 * correspond with the option definitions in "generic" (common to
	 * all window types) and "unique" (per-window).
	 */
	mask = (1<<(WONUM_GENERIC+1))-1;
	if (unique) {
		wod->wod_askrpt = unique->wod_askrpt & ~mask;
		wod->wod_pending = unique->wod_pending & ~mask;
		for (n=WONUM_GENERIC+1; n <= WONUM_MAX; n++)
			wod->wod_optlst[n] = unique->wod_optlst[n];
	} else {
		wod->wod_askrpt = 0;
		wod->wod_pending = 0;
		for (n=WONUM_GENERIC+1; n <= WONUM_MAX; n++)
			wod->wod_optlst[n].wol_argdefn = (woptarg_t *)0;
	}
	if (generic) {
		wod->wod_askrpt |= generic->wod_askrpt & mask;
		wod->wod_pending |= generic->wod_pending & mask;
		for (n=1; n <= WONUM_GENERIC; n++)
			wod->wod_optlst[n] = generic->wod_optlst[n];
	} else {
		for (n=1; n <= WONUM_GENERIC; n++)
			wod->wod_optlst[n].wol_argdefn = (woptarg_t *)0;
	}
	wod->wod_do = wod->wod_askrpt;
	wod->wod_dont = 0;
	wod->wod_inquire = 0;
	calloptscan = 1;
}

opt_renew(wod, report)
register struct woptdefn *wod;
int report;
{
	/*
	 * Reset "wod_do" for all window options that we want the Macintosh
	 * to report to us.  If "report" is nonzero, send the Mac the
	 * current values of these options.
	 */
	wod->wod_do = wod->wod_askrpt;
	wod->wod_dont = 0;
	if (report)
		wod->wod_pending = wod->wod_askrpt;
	calloptscan = 1;
}

opt_newtype(wod, generic, unique)
register struct woptdefn *wod, *generic, *unique;
{
	register int n, bit;
	register woptbmask_t oldask;

	/*
	 * Change the window options to reflect a new window emulation type.
	 * The new emulation may not support all of the events that the old
	 * one did, and in any event they may not mean the same thing.
	 */
	oldask = wod->wod_askrpt;
	opt_new(wod, generic, unique);
	for (n=1, bit=2; n <= WONUM_GENERIC; n++,bit<<=1) {
		if ((oldask&bit) && !(wod->wod_askrpt&bit))
			wod->wod_dont |= bit;
		if (!(oldask&bit) && (wod->wod_askrpt&bit))
			wod->wod_do |= bit;
	}
	for ( ; n <= WONUM_MAX; n++, bit<<=1)
		if (wod->wod_askrpt&bit)
			wod->wod_do |= bit;
	calloptscan = 1;
}

opt_setext(wod, fn)
register struct woptdefn *wod;
register void (*fn)();
{
	register int n;

	/*
	 * Set "wol_ext" to "fn" for each option that has a defined "wol_set".
	 */
	for (n=1; n <= WONUM_MAX; n++)
		if (wod->wod_optlst[n].wol_set)
			wod->wod_optlst[n].wol_ext = fn;
}

opt_scan(w, wod, fn, mfd, cmd)
caddr_t w;
register struct woptdefn *wod;
void (*fn)();
fildes_t mfd;
int cmd;
{
	register struct woptlst *wol;
	register char *cp;
	register int n, bit, maxsize;
	char buf[512];

	/*
	 * Scan the entire list of options for pending ones.  For each
	 * one, call "fn".  "cmd" is the command that we are to pass as the
	 * first argument to "fn".
	 *
	 * Note that we must send data (wod_pending) before processing
	 * DO commands (wod_do); otherwise, the host and Mac may not
	 * agree upon the value of a window option.  (The Mac might
	 * respond to the "do" command before it sees the new value.)
	 */
	cp = buf;
#ifdef notdef
	for (n=1,bit=2,wol=wod->wod_optlst+1; n<=WONUM_MAX; n++,bit<<=1,wol++) {
#else
	for (n=WONUM_MAX, bit=(1<<WONUM_MAX), wol=wod->wod_optlst+WONUM_MAX;
	     n > 0;
	     n--, bit >>= 1, wol--) {
#endif
		if (wod->wod_pending&bit) {
			wod->wod_pending &= ~bit;
			if (wol->wol_argdefn) {
				maxsize = 2 +
				    opt_size(wol->wol_argdefn);
				if (cp > buf + sizeof buf - maxsize - 1) {
					*cp++ = 0;
					(*fn)(mfd, cmd, buf, cp-buf);
					cp = buf;
				}
				if (WONUM_USELONG(n)) {
					*cp++ = WOC_SET|WONUM_LPREFIX;
					*cp++ = WONUM_LENCODE(n);
				} else
					*cp++ = WOC_SET|WONUM_SENCODE(n);
				cp += opt_encode(cp, wol->wol_argdefn,
				    (*wol->wol_get)(w, n));
			}
		}
		if (wod->wod_inquire&bit) {
			wod->wod_inquire &= ~bit;
			if (cp > buf + sizeof buf - 3) {
				*cp++ = 0;
				(*fn)(mfd, cmd, buf, cp-buf);
				cp = buf;
			}
			if (wol->wol_argdefn) {
				if (WONUM_USELONG(n)) {
					*cp++ = WOC_INQUIRE|WONUM_LPREFIX;
					*cp++ = WONUM_LENCODE(n);
				} else
					*cp++ = WOC_INQUIRE|WONUM_SENCODE(n);
			}
		}
		if ((wod->wod_do|wod->wod_dont)&bit) {
			if (cp > buf + sizeof buf - 3) {
				*cp++ = 0;
				(*fn)(mfd, cmd, buf, cp-buf);
				cp = buf;
			}
			if (wod->wod_do&bit) {
				wod->wod_do &= ~bit;
				wod->wod_dont &= ~bit;
				if (wol->wol_argdefn) {
					if (WONUM_USELONG(n)) {
						*cp++ = WOC_DO|WONUM_LPREFIX;
						*cp++ = WONUM_LENCODE(n);
					} else
						*cp++ = WOC_DO|WONUM_SENCODE(n);
				}
			} else if (wod->wod_dont&bit) {
				wod->wod_do &= ~bit;
				wod->wod_dont &= ~bit;
				if (wol->wol_argdefn) {
					if (WONUM_USELONG(n)) {
						*cp++ = WOC_DONT|WONUM_LPREFIX;
						*cp++ = WONUM_LENCODE(n);
					} else
						*cp++=WOC_DONT|WONUM_SENCODE(n);
				}
			}
		}
		if (cp > buf) {
			*cp++ = 0;
			(*fn)(mfd, cmd, buf, cp-buf);
			cp = buf;
		}
	}
}

opt_size(woa)
register woptarg_t *woa;
{
	register int size, cnt;

	/*
	 * Determine the maximum size of an option whose argument encoding
	 * is specified by "woa".  This does NOT include additional encoding
	 * (e.g. for meta characters) at the protocol level.
	 */
	if (woa) {
		for (size=0; *woa != WOA_END; woa++) {
			cnt = *woa & ~WOA_CMDMASK;
			switch (*woa & WOA_CMDMASK) {
			case WOA_CHARS(0):
			case WOA_STRING(0):
				size += cnt;
				break;
			case WOA_UDATA(0):
				size += (cnt + 5) / 6;
				break;
			}
		}
	} else
		size = 0;
	return(size);
}

opt_encode(buf, woa, data)
char *buf;
register woptarg_t *woa;
char *data;
{
	register char *cp, *cq;
	register int n, cnt;
	register unsigned long ival;
	union {
		struct {
			char	c1;
			short	s;
		}	cs;
		struct {
			char	c2;
			long	l;
		}	cl;
	} u;

	/*
	 * Encode "data" according to the option argument specifier "woa"
	 * into the buffer "buf".  Return the number of bytes of "buf"
	 * actually used.  The caller has already verified that "buf" is
	 * large enough.
	 */
	if (!data)
		return(0);
	for (cp=buf,cq=data; *woa != WOA_END; woa++) {
		cnt = *woa & ~WOA_CMDMASK;
		switch (*woa & WOA_CMDMASK) {
		case WOA_CHARS(0):
			for (n=0; n < cnt; n++)
				*cp++ = *cq++;
			break;
		case WOA_STRING(0):
			for (n=0; n < cnt-1 && *cq; n++)
				*cp++ = *cq++;
			if (n < cnt)
				cq += cnt-n;
			*cp++ = '\0';
			break;
		case WOA_UDATA(0):
			if (cnt <= NBBY) {
				ival = (unsigned char)*cq++;
			} else if (cnt <= sizeof(short)*NBBY) {
				while ((int)cq & ((char *)&u.cs.s-&u.cs.c1-1))
					cq++;
				ival = *(unsigned short *)cq;
				cq += sizeof(short);
			} else {
				while ((int)cq & ((char *)&u.cl.l-&u.cl.c2-1))
					cq++;
				ival = *(unsigned long *)cq;
				cq += sizeof(long);
			}
			if (cnt != sizeof(long)*NBBY)
				ival &= (1<<cnt) - 1;
			for (n=0; n < cnt; n += 6, ival >>= 6)
				*cp++ = (ival & 077) | 0100;
			break;
		}
	}
	return(cp-buf);
}
			
opt_istart(w, wod)
caddr_t w;
struct woptdefn *wod;
{
	/*
	 * Start collecting input for a window option specification.
	 */
	optwin = w;
	optwod = wod;
	optnum = 0;
}

opt_input(c)
char c;
{
	register int cnt, bit;
	register struct woptdefn *wod;
	register struct woptlst *wol;
	register unsigned long ival;
	union {
		struct {
			char	c1;
			short	s;
		}	cs;
		struct {
			char	c2;
			long	l;
		}	cl;
	} u;

	/*
	 * Add the received character "c" to the current option specification.
	 * If it is complete, take the appropriate action.  If option 0
	 * (the endmarker) is received, return 0 (to notify the caller that
	 * we are done).  Otherwise, return 1 -- more option data remains
	 * to be processed.
	 *
	 * This code isn't as readable as it should be; there are far too
	 * many return statements floating around.  Sorry about that.
	 */
	if (optwin) {
		wod = optwod;
		if (optnum == 0 || optnum == WONUM_MAX+1) {
			/* start (or continue) decoding a new option */
			if (optnum == 0) {
				/* start new option (or decode endmarker) */
				if (c & WONUM_MASK) {
					/* new option */
					optcmd = c & WOC_MASK;
					if (WOC_BADCMD(optcmd)) {
						opt_iflush();
						return(0);
					}
					if (c == WONUM_LPREFIX) {
						optnum = WONUM_MAX+1;
						return(1);
					} else
						optnum = WONUM_SDECODE(c);
				} else {
					/* end of options */
					opt_iflush();
					return(0);
				}
			} else {
				/* read second byte of long option number */
				optnum = WONUM_LDECODE(c);
				if (optnum > WONUM_MAX) {
					opt_iflush();
					return(0);
				}
			}
			/*
			 * This point is reached when the option number has
			 * been completely decoded.  If the command is not
			 * WOC_SET, then it has no arguments and we can
			 * process it immediately.
			 */
			wol = &wod->wod_optlst[optnum];
			bit = 1<<optnum;
			if (optcmd == WOC_SET) {
				optout = optbuf;
				optcnt = 0;
				optarg = wol->wol_argdefn;
				if (!optarg) {
					opt_iflush();
					return(0);
				}
			} else {
				if (wol->wol_ext &&
				    (optcmd == WOC_WILL || optcmd == WOC_WONT))
					(*wol->wol_ext)(optwin, optcmd,
					    optnum, (char *)0, 0);
				switch (optcmd) {
				case WOC_INQUIRE:
					wod->wod_pending |= bit;
					calloptscan = 1;
					break;
				case WOC_DO:
				case WOC_DONT:
					break;
				case WOC_WILL:
					wod->wod_askrpt |= bit;
					wod->wod_do &= ~bit;
					break;
				case WOC_WONT:
					wod->wod_askrpt &= ~bit;
					wod->wod_dont &= ~bit;
					break;
				}
				optnum = 0;
			}
			return(1);
		} else {
			/* continue processing argument to option */
			wol = &wod->wod_optlst[optnum];
			bit = 1<<optnum;
			cnt = *optarg & ~WOA_CMDMASK;
			switch (*optarg & WOA_CMDMASK) {
			case WOA_CHARS(0):
				*optout++ = c;
				optcnt++;
				break;
			case WOA_STRING(0):
				*optout++ = c;
				optcnt++;
				if (!c) {
					optout += cnt - optcnt;
					optcnt = cnt;
				} else if (optcnt == cnt-1) {
					*optout++ = '\0';
					optcnt = cnt;
				}
				break;
			case WOA_UDATA(0):
				if (optcnt == 0) {
					if (cnt <= NBBY) {
						*optout = 0;
					} else if (cnt <= sizeof(short)*NBBY) {
						while ((int)optout & ((char *)&u.cs.s-&u.cs.c1-1))
							optout++;
						*(short *)optout = 0;
					} else {
						while ((int)optout & ((char *)&u.cl.l-&u.cl.c2-1))
							optout++;
						*(long *)optout = 0;
					}
				}
				ival = (c & 077) << optcnt;
				if (cnt != NBBY*sizeof(long))
					ival &= (1<<cnt) - 1;
				optcnt += 6;
				if (cnt <= NBBY) {
					*(unsigned char *)optout |= (unsigned char)ival;
					if (optcnt >= cnt)
						optout++;
				} else if (cnt <= sizeof(short)*NBBY) {
					*(unsigned short *)optout |= (unsigned short)ival;
					if (optcnt >= cnt)
						optout += sizeof(short);
				} else {
					*(unsigned long *)optout |= ival;
					if (optcnt >= cnt)
						optout += sizeof(long);
				}
				break;
			}
			if (optcnt >= cnt) {
				optcnt = 0;
				if (*++optarg == WOA_END) {
					wod->wod_pending &= ~bit;
					(*wol->wol_set)(optwin, optnum, optbuf);
					if (wol->wol_ext) {
						(*wol->wol_ext)(optwin, WOC_SET,
						    optnum, optbuf,
						    optout-optbuf);
					}
					optnum = 0;
				}
			}
			return(1);
		}
		/*NOTREACHED*/
	}
	return(0);
}

opt_iflush()
{
	optwin = (caddr_t)0;
}

opt_extopt(w, wod, cmd, num, data, na)
caddr_t w;
register struct woptdefn *wod;
woptcmd_t cmd;
woption_t num;
char *data;
struct netadj *na;
{
	register struct woptlst *wol;

	if (w != NULL && wod != NULL && num <= WONUM_MAX) {
		wol = wod->wod_optlst + num;
		if (wol->wol_argdefn) {
			switch (cmd) {
			case WOC_SET:
				if (data && wol->wol_set) {
					if (na) {
						opt_netadj(wol->wol_argdefn,
						    data, na);
					}
					/*
					 * Set the new value and notify the Mac.
					 * Because of a race condition (the Mac
					 * might concurrently be sending us its
					 * value for this option), we ask the
					 * Mac to send back the value after it
					 * is set.
					 */
					(*wol->wol_set)(w, num, data);
					WOPT_SET(wod->wod_pending, num);
					WOPT_SET(wod->wod_inquire, num);
					calloptscan = 1;
				}
				break;
			case WOC_INQUIRE:
				WOPT_SET(wod->wod_inquire, num);
				calloptscan = 1;
				break;
			case WOC_DO:
				WOPT_SET(wod->wod_do, num);
				WOPT_SET(wod->wod_askrpt, num);
				calloptscan = 1;
				break;
			case WOC_DONT:
				WOPT_SET(wod->wod_dont, num);
				WOPT_CLR(wod->wod_askrpt, num);
				calloptscan = 1;
				break;
			}
		}
	}
}

opt_netadj(woa, data, na)
register woptarg_t *woa;
char *data;
register struct netadj *na;
{
	register char *cp;
	register int cnt;
	union {
		struct {
			char	c1;
			short	s;
		}	cs;
		struct {
			char	c2;
			long	l;
		}	cl;
	} u;

	/*
	 * Convert an option (in internal format) from host byte order
	 * to network byte order.  If the two are the same then this is
	 * a NOP.
	 */
	if (data && na) {
		for (cp=data; *woa != WOA_END; woa++) {
			cnt = *woa & ~WOA_CMDMASK;
			switch (*woa & WOA_CMDMASK) {
			case WOA_CHARS(0):
			case WOA_STRING(0):
				cp += cnt;
				break;
			case WOA_UDATA(0):
				if (cnt <= NBBY) {
					cp++;
				} else if (cnt <= sizeof(short)*NBBY) {
					while ((int)cp & ((char *)&u.cs.s-&u.cs.c1-1))
						cp++;
					*(u_short *)cp =
					    (*na->na_ushort)(*(u_short *)cp);
					cp += sizeof(short);
				} else {
					while ((int)cp & ((char *)&u.cl.l-&u.cl.c2-1))
						cp++;
					*(u_short *)cp =
					    (*na->na_ushort)(*(u_short *)cp);
					cp += sizeof(long);
				}
			}
		}
	}
}

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