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.