1 /*********************************************************************
2 Project : GUSI - Grand Unified Socket Interface
3 File : GUSIDispatch.cp- Dispatch calls to their correct recipient
4 Author : Matthias Neeracher
8 Revision 1.1 1998/08/18 14:52:37 jack
9 Putting Python-specific GUSI modifications under CVS.
11 Revision 1.4 1994/12/30 19:48:09 neeri
12 Remove (theoretical) support for pre-System 6 systems.
13 Remove built-in support for INETd.
14 Fix problems in connection with ROM PowerPC library.
15 Move open() to GUSIFileDispatch.cp.
16 Support AF_UNSPEC domains.
17 More work on spinning performance.
19 Revision 1.3 1994/08/10 00:30:30 neeri
20 Sanitized for universal headers.
21 Prevent overly fast spinning.
23 Revision 1.2 1994/05/01 23:47:34 neeri
24 Extend fflush() kludge.
25 Define _lastbuf for MPW 3.2 compatibility.
27 Revision 1.1 1994/02/25 02:28:36 neeri
30 Revision 0.27 1993/11/24 00:00:00 neeri
31 Flush stdio before closing
33 Revision 0.26 1993/11/22 00:00:00 neeri
34 Extend two time loser for EBADF
36 Revision 0.25 1993/11/12 00:00:00 neeri
37 Two time loser workaround for flush bug
39 Revision 0.24 1993/06/27 00:00:00 neeri
42 Revision 0.23 1993/06/27 00:00:00 neeri
45 Revision 0.22 1993/06/20 00:00:00 neeri
46 Further subtleties in console handling
48 Revision 0.21 1993/05/21 00:00:00 neeri
51 Revision 0.20 1993/05/15 00:00:00 neeri
52 Try to keep errno always set on error returns
54 Revision 0.19 1993/05/13 00:00:00 neeri
55 Limit Search for configuration resource to application
57 Revision 0.18 1993/01/31 00:00:00 neeri
58 Introducing daemons (pleased to meet you, hope you guess my name)
60 Revision 0.17 1993/01/17 00:00:00 neeri
61 Be more careful about user aborts.
63 Revision 0.16 1993/01/03 00:00:00 neeri
66 Revision 0.15 1992/11/25 00:00:00 neeri
67 Still trying to get standard descriptors for standalone programs right. sigh.
69 Revision 0.14 1992/10/05 00:00:00 neeri
70 Small fix in event dispatching
72 Revision 0.13 1992/09/12 00:00:00 neeri
75 Revision 0.12 1992/08/30 00:00:00 neeri
76 Move hasPPC to GUSIPPC.cp, AppleTalkIdentity
78 Revision 0.11 1992/08/05 00:00:00 neeri
79 Change the way standard I/O channels are opened
81 Revision 0.10 1992/08/03 00:00:00 neeri
82 Move Scatter/Gather to GUSIBuffer.cp
84 Revision 0.9 1992/07/30 00:00:00 neeri
85 Features with initializers
87 Revision 0.8 1992/07/13 00:00:00 neeri
90 Revision 0.7 1992/06/27 00:00:00 neeri
93 Revision 0.6 1992/06/06 00:00:00 neeri
96 Revision 0.5 1992/04/19 00:00:00 neeri
99 Revision 0.4 1992/04/18 00:00:00 neeri
100 Changed read/write/send/recv dispatchers
102 Revision 0.3 1992/04/17 00:00:00 neeri
105 Revision 0.2 1992/04/16 00:00:00 neeri
108 Revision 0.1 1992/03/31 00:00:00 neeri
109 unix domain socket calls
111 *********************************************************************/
113 #include "GUSIFile_P.h"
114 #include "GUSIMPW_P.h"
117 #include <CursorCtl.h>
118 #include <Resources.h>
125 #include <CommResources.h>
126 #include <CTBUtilities.h>
127 #include <Connections.h>
128 #include <FileTransfers.h>
129 #include <Terminals.h>
131 #include <PLStringFuncs.h>
133 #include <Processes.h>
136 #include <CodeFragments.h>
141 /***************************** Globals ******************************/
143 GUSIConfiguration GUSIConfig; // Change the order of these declarations
144 SocketTable Sockets; // and you'll regret it (ARM ยง12.6.1)
145 GUSISpinFn GUSISpin = GUSIDefaultSpin;
146 GUSIExecFn GUSIExec = GUSIDefaultExec;
147 GUSIFTypeFn GUSIFType = (GUSIFTypeFn)0;
149 static GUSIEvtHandler * evtHandler = nil;
150 static short evtMask = 0;
151 static int errorSock = -1;
152 static int errorType = 0;
153 static int errorCount = 0;
154 const int errorMax = 3;
155 Boolean CatchStdIO = false;
157 Feature hasMakeFSSpec(
159 (1<<gestaltHasFSSpecCalls),
160 (1<<gestaltHasFSSpecCalls));
163 (1<<gestaltAliasMgrPresent),
164 (1<<gestaltAliasMgrPresent));
166 gestaltStandardFileAttr,
167 (1<<gestaltStandardFile58),
168 (1<<gestaltStandardFile58));
169 Feature hasProcessMgr(
171 (1<<gestaltLaunchControl),
172 (1<<gestaltLaunchControl));
175 (1<<gestaltCRMPresent),
176 (1<<gestaltCRMPresent));
177 Feature hasCRM(hasCRM_P, InitCRM);
178 Feature hasCTB(hasCRM, InitCTBUtilities);
181 (1<<gestaltStdNBPPresent),
182 (1<<gestaltStdNBPPresent));
183 Feature hasStdNBP(hasCTB, hasStdNBP_P);
184 Feature hasAppleEvents(
185 gestaltAppleEventsAttr,
186 (1<<gestaltAppleEventsPresent),
187 (1<<gestaltAppleEventsPresent));
188 Feature hasRevisedTimeMgr(
189 gestaltTimeMgrVersion,
192 /*********************** Error propagation ************************/
197 int GUSI_error(int err)
208 void * GUSI_error_nil(int err)
216 /*********************** GUSIConfiguration members ************************/
218 #ifndef GUSI_DISPATCH
220 Boolean GUSIConfiguration::firstTime = false;
221 short GUSIConfiguration::we;
223 void GUSIConfiguration::GUSILoadConfiguration(Handle h)
225 typedef GUSIConfigRsrc ** GUSIConfHdl;
226 GUSIConfHdl config = GUSIConfHdl(h);
227 long confSize = config ? GetHandleSize(Handle(config)) : 0;
229 if (confSize < 4 || !(defaultType = (*config)->defaultType))
230 defaultType = 'TEXT';
231 if (confSize < 8 || !(defaultCreator = (*config)->defaultCreator))
232 defaultCreator = 'MPS ';
234 autoSpin = 1; // do automatic spin on read/write
236 autoSpin = (*config)->autoSpin;
241 version = (*config)->version;
244 noChdir = false; // Use chdir()
245 accurStat = false; // st_nlink = # of entries + 2
247 noAutoInitGraf = false;
250 noAppleEvents = false;
251 delayConsole = false;
253 noChdir = ((*config)->flags & 0x80) != 0;
254 accurStat = ((*config)->flags & 0x40) != 0;
255 hasConsole = version >= '0150' && version <= '0180' && ((*config)->flags & 0x08) != 0;
256 delayConsole = version >= '0181' && ((*config)->flags & 0x20) != 0;
257 noAppleEvents = version >= '0181' && ((*config)->flags & 0x08) != 0;
258 noAutoInitGraf = version >= '0174' && ((*config)->flags & 0x04) != 0;
259 sharedOpen = version >= '0174' && ((*config)->flags & 0x02) != 0;
260 sigPipe = version >= '0174' && ((*config)->flags & 0x01) != 0;
263 if (version < '0120' || confSize < 16)
266 numSuffices = (*config)->numSuffices;
270 else if (suffices = new GUSISuffix[numSuffices]) {
271 HLock((Handle)config);
272 memcpy(suffices, (*config)->suffices, numSuffices*sizeof(GUSISuffix));
273 for (int i=0; i<numSuffices; i++)
274 for (int j=0; j<4; j++)
275 if (((char *) (suffices+i))[j] == ' ')
276 ((char *) (suffices+i))[j] = 0;
280 GUSIConfiguration::GUSIConfiguration()
282 short oldResFile = CurResFile();
289 Handle config = Get1Resource('GUโฆI', GUSIRsrcID);
290 GUSILoadConfiguration(config);
297 UseResFile(oldResFile);
299 ReleaseResource((Handle)config);
302 void GUSIConfiguration::SetDefaultFType(const TFileSpec & name) const
307 // Custom hook if existing
309 if (GUSIFType && GUSIFType(name))
313 // Otherwise default behaviour
315 if (HGetFInfo(name.vRefNum, name.parID, name.name, &info))
318 Ptr dot = PLstrrchr(name.name, '.');
320 if (dot && (name.name[0] - (dot-Ptr(name.name))) <= 4) {
321 char searchsuffix[5];
323 strncpy(searchsuffix, dot+1, name.name[0] - (dot-Ptr(name.name)));
325 for (int i = 0; i<numSuffices; i++)
326 if (!strncmp(suffices[i].suffix, searchsuffix, 4)) {
327 info.fdType = suffices[i].suffType;
328 info.fdCreator = suffices[i].suffCreator;
334 info.fdType = defaultType;
335 info.fdCreator = defaultCreator;
336 info.fdFlags &= ~kHasBeenInited;
339 HSetFInfo(name.vRefNum, name.parID, name.name, &info);
342 void GUSIConfiguration::DoAutoInitGraf() const
344 if (*(GrafPtr **) LMGetCurrentA5() != &qd.thePort)
345 InitGraf(&qd.thePort);
346 const_cast<GUSIConfiguration *>(this)->noAutoInitGraf = true;
349 #endif // GUSI_DISPATCH
351 inline void GUSIConfiguration::DoAutoSpin() const
354 SAFESPIN(0, SP_AUTO_SPIN, autoSpin);
357 Boolean GUSIConfiguration::DelayConsole() const
362 /************************ Handle nonstandard consoles *************************/
364 #ifndef GUSI_DISPATCH
366 static void InitConsole()
368 if (MPWDomain::stdopen) {
369 for (int i = 0; i < 3; i++) {
370 Socket * sock = MPWDomain::stdopen(i);
373 Sockets.Install(sock);
376 if (open("dev:console", O_RDONLY) < 0)
377 open("dev:null", O_RDONLY);
378 if (open("dev:console", O_WRONLY) < 0)
379 open("dev:null", O_WRONLY);
380 if (open("dev:console", O_WRONLY) < 0)
381 open("dev:null", O_WRONLY);
385 void SocketTable::InitConsole()
388 needsConsole = false;
393 #endif // GUSI_DISPATCH
395 /************************ External routines *************************/
402 int socket(int domain, int type, int protocol)
408 Sockets.InitConsole();
410 if (dom = SocketDomain::Domain(domain))
411 if (sock = dom->socket(type, protocol))
412 if ((fd = Sockets.Install(sock)) != -1)
418 return GUSI_error(ENOMEM);
423 int socketpair(int domain, int type, int protocol, int * sv)
428 Sockets.InitConsole();
430 if (dom = SocketDomain::Domain(domain))
431 if (!dom->socketpair(type, protocol, sock))
432 if ((sv[0] = Sockets.Install(sock[0])) != -1)
433 if ((sv[1] = Sockets.Install(sock[1])) != -1)
436 Sockets.Remove(sv[0]);
447 return GUSI_error(ENOMEM);
454 GUSIwithUnixSockets();
456 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd))
464 int choose(int domain, int type, char * prompt, void * constraint, int flags, void * name, int * namelen)
468 if (dom = SocketDomain::Domain(domain))
469 return dom->choose(type, prompt, constraint, flags, name, namelen);
474 int bind(int s, const struct sockaddr *name, int namelen)
476 Socket * sock = Sockets[s];
478 return sock ? sock->bind((void *) name, namelen) : -1;
481 int connect(int s, const struct sockaddr *addr, int addrlen)
483 Socket * sock = Sockets[s];
485 return sock ? sock->connect((void *) addr, addrlen) : -1;
488 int listen(int s, int qlen)
490 Socket * sock = Sockets[s];
492 return sock ? sock->listen(qlen) : -1;
495 int accept(int s, struct sockaddr *addr, int *addrlen)
497 Socket * sock = Sockets[s];
500 if (sock = sock->accept(addr, addrlen))
501 if ((s = Sockets.Install(sock)) != -1)
513 return Sockets.Remove(s);
517 int read(int s, char *buffer, int buflen)
519 int read(int s, char *buffer, unsigned buflen)
522 GUSIConfig.DoAutoSpin();
524 Socket * sock = Sockets[s];
526 return sock ? sock->read(buffer, (unsigned) buflen) : -1;
529 int readv(int s, const struct iovec *iov, int count)
531 GUSIConfig.DoAutoSpin();
533 Socket * sock = Sockets[s];
536 Scatterer scatt(iov, count);
539 return scatt.length(sock->read(scatt.buffer(), scatt.buflen()));
541 return GUSI_error(ENOMEM);
546 int recv(int s, void *buffer, int buflen, int flags)
548 GUSIConfig.DoAutoSpin();
551 Socket * sock = Sockets[s];
553 return sock ? sock->recvfrom(buffer, buflen, flags, nil, &fromlen) : -1;
556 int recvfrom(int s, void *buffer, int buflen, int flags, struct sockaddr *from, int *fromlen)
558 GUSIConfig.DoAutoSpin();
560 Socket * sock = Sockets[s];
562 return sock ? sock->recvfrom(buffer, buflen, flags, from, fromlen) : -1;
565 int recvmsg(int s, struct msghdr *msg, int flags)
567 GUSIConfig.DoAutoSpin();
569 Socket * sock = Sockets[s];
572 Scatterer scatt((struct iovec *)msg->msg_iov, msg->msg_iovlen);
582 (int *)&msg->msg_namelen));
584 return GUSI_error(ENOMEM);
590 int write(int s, const char *buffer, int buflen)
592 int write(int s, const char *buffer, unsigned buflen)
595 /* fflush() in the MPW stdio library doesn't take no for an answer.
596 Our workaround is to treat a second subsequent ESHUTDOWN or EBADF as
597 an invitation to lie by pretending the write worked.
602 GUSIConfig.DoAutoSpin();
604 Socket * sock = Sockets[s];
606 if (sock && (len = sock->write((char *) buffer, (unsigned) buflen)) != -1)
616 if (GUSIConfig.sigPipe)
618 if (errorSock == s && errorType == errno) {
619 if (++errorCount == errorMax) {
633 static int HandleWriteErrors(int retval)
643 if (GUSIConfig.sigPipe)
651 int writev(int s, const struct iovec *iov, int count)
653 GUSIConfig.DoAutoSpin();
655 Socket * sock = Sockets[s];
658 Gatherer gath(iov, count);
661 return HandleWriteErrors(gath.length(sock->write(gath.buffer(), gath.buflen())));
663 return GUSI_error(ENOMEM);
668 int send(int s, const void *buffer, int buflen, int flags)
670 GUSIConfig.DoAutoSpin();
672 Socket * sock = Sockets[s];
674 return sock ? HandleWriteErrors(sock->sendto((void *)buffer, buflen, flags, nil, 0)) : -1;
677 int sendto(int s, const void *buffer, int buflen, int flags, const struct sockaddr *to, int tolen)
679 GUSIConfig.DoAutoSpin();
681 Socket * sock = Sockets[s];
683 return sock ? HandleWriteErrors(sock->sendto((void *)buffer, buflen, flags, (void *) to, tolen)) : -1;
686 int sendmsg(int s, const struct msghdr *msg, int flags)
688 GUSIConfig.DoAutoSpin();
690 Socket * sock = Sockets[s];
693 Gatherer gath((struct iovec *) msg->msg_iov, msg->msg_iovlen);
697 HandleWriteErrors(gath.length(
705 return GUSI_error(ENOMEM);
710 int select(int width, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
715 long starttime, waittime;
728 waittime = timeout->tv_sec*60 + timeout->tv_usec/16666;
730 waittime = 2000000000; // Slightly more than a year; close enough to "no timeout"
732 starttime = LMGetTicks();
734 // Check files for kosherness
736 for (s = 0; s < width ; ++s)
737 if ( (readfds && FD_ISSET(s,readfds))
738 || (writefds && FD_ISSET(s,writefds))
739 || (exceptfds && FD_ISSET(s,exceptfds))
742 return GUSI_error(EBADF);
744 for (s = 0; s < width ; ++s)
745 if (sock = Sockets[s]) {
746 r = readfds && FD_ISSET(s,readfds);
747 w = writefds && FD_ISSET(s,writefds);
748 e = exceptfds && FD_ISSET(s,exceptfds);
751 sock->pre_select(r, w, e);
755 for (s = 0; s < width ; ++s) {
756 if (sock = Sockets[s]) {
761 canRead = (readfds && FD_ISSET(s,readfds)) ? &r : nil;
762 canWrite = (writefds && FD_ISSET(s,writefds)) ? &w : nil;
763 exception = (exceptfds && FD_ISSET(s,exceptfds)) ? &e : nil;
765 if (canRead || canWrite || exception) {
766 count += sock->select(canRead, canWrite, exception);
780 SAVE_AND_CLEAR_ERRNO;
781 SAFESPIN(false, SP_SELECT, waittime);
788 } while (LMGetTicks() - starttime < waittime);
790 for (s = 0; s < width ; ++s)
791 if (sock = Sockets[s]) {
792 r = readfds && FD_ISSET(s,readfds);
793 w = writefds && FD_ISSET(s,writefds);
794 e = exceptfds && FD_ISSET(s,exceptfds);
797 sock->post_select(r, w, e);
801 return GUSI_error(EINTR);
813 int getsockname(int s, struct sockaddr *name, int *namelen)
815 Socket * sock = Sockets[s];
817 return sock ? sock->getsockname(name, namelen) : -1;
820 int getpeername(int s, struct sockaddr *name, int *namelen)
822 Socket * sock = Sockets[s];
824 return sock ? sock->getpeername(name, namelen) : -1;
827 int shutdown(int s, int how)
829 Socket * sock = Sockets[s];
831 return sock ? sock->shutdown(how) : -1;
834 int fcntl(int s, unsigned int cmd, int arg)
836 Socket * sock = Sockets[s];
839 return (cmd == F_DUPFD) ? Sockets.Install(sock, arg) : sock->fcntl(cmd, arg);
846 Socket * sock = Sockets[s];
848 return sock ? Sockets.Install(sock) : -1;
851 int dup2(int s, int s1)
853 Socket * sock = Sockets[s];
861 return Sockets.Install(sock, s1);
864 int ioctl(int s, unsigned int request, long *argp)
866 Socket * sock = Sockets[s];
871 return sock->ioctl(request, argp);
874 int getsockopt(int s, int level, int optname, void *optval, int * optlen)
876 Socket * sock = Sockets[s];
878 return sock ? sock->getsockopt(level, optname, optval, optlen) : -1;
881 int setsockopt(int s, int level, int optname, const void *optval, int optlen)
883 Socket * sock = Sockets[s];
885 return sock ? sock->setsockopt(level, optname, (void *) optval, optlen) : -1;
888 int fstat(int s, struct stat * buf)
890 Socket * sock = Sockets[s];
892 return sock ? sock->fstat(buf) : -1;
895 long lseek(int s, long offset, int whence)
897 Socket * sock = Sockets[s];
899 return sock ? sock->lseek(offset, whence) : -1;
902 int ftruncate(int s, long offset)
904 Socket * sock = Sockets[s];
906 return sock ? sock->ftruncate(offset) : -1;
911 Socket * sock = Sockets[s];
913 return sock ? sock->isatty() : -1;
916 void GUSISetHook(GUSIHookCode code, GUSIHook hook)
920 GUSISpin = (GUSISpinFn) hook;
923 GUSIExec = (GUSIExecFn) hook;
926 GUSIFType = (GUSIFTypeFn) hook;
929 gGUSISpeed = (long) hook;
934 GUSIHook GUSIGetHook(GUSIHookCode code)
938 return (GUSIHook) GUSISpin;
940 return (GUSIHook) GUSIExec;
942 return (GUSIHook) GUSIFType;
944 return (GUSIHook) gGUSISpeed;
947 return (GUSIHook) nil;
951 int GUSISetEvents(GUSIEvtTable table)
958 for (evt = 0; evt<16; ++evt)
965 GUSIEvtHandler * GUSIGetEvents(void)
970 /*********************** SocketDomain members ***********************/
972 #ifndef GUSI_DISPATCH
974 SocketDomain * SocketDomain::domains[GUSI_MAX_DOMAIN];
975 ProcessSerialNumber SocketDomain::process;
977 SocketDomain * SocketDomain::Domain(int domain)
979 if (domain < 0 || domain >= GUSI_MAX_DOMAIN || !domains[domain]) {
984 return domains[domain];
987 void SocketDomain::Ready()
990 WakeUpProcess(&process);
993 SocketDomain::SocketDomain(int domain)
995 #ifdef PREVENT_DUPLICATE_DOMAINS
996 if (domains[domain]) {
999 sprintf((char *) msg+1, "Duplicate declaration for domain %d\n", domain);
1000 msg[0] = (unsigned char)strlen((char *) msg+1);
1005 if (domain) // Ignore AF_UNSPEC domains
1006 domains[domain] = this;
1008 if (hasProcessMgr && !process.highLongOfPSN && !process.lowLongOfPSN)
1009 GetCurrentProcess(&process);
1012 SocketDomain::~SocketDomain()
1016 // Default implementations of socket() just returns an error
1018 Socket * SocketDomain::socket(int, short)
1020 GUSI_error(EOPNOTSUPP);
1025 // Same with socketpair
1027 int SocketDomain::socketpair(int, short, Socket **)
1029 return GUSI_error(EOPNOTSUPP);
1033 int SocketDomain::choose(int, char *, void *, int, void *, int *)
1035 return GUSI_error(EOPNOTSUPP);
1038 void SocketDomain::DontStrip()
1042 /*********************** SocketTable members ************************/
1044 static void FlushStdio()
1049 SocketTable::SocketTable()
1053 needsConsole = true;
1056 int SocketTable::Install(Socket * sock, int start)
1060 if (start<0 || start >= GUSI_MAX_FD)
1061 return GUSI_error(EINVAL);
1063 for (fd=start; fd<GUSI_MAX_FD; ++fd)
1071 return GUSI_error(EMFILE);
1074 int SocketTable::Remove(int fd)
1080 if (fd<0 || fd >= GUSI_MAX_FD || !(sock = sockets[fd]))
1081 return GUSI_error(EBADF);
1085 if (!--sock->refCount)
1091 Socket * SocketTable::operator[](int fd)
1097 if (fd<0 || fd >= GUSI_MAX_FD || !(sock = sockets[fd])) {
1109 SocketTable::~SocketTable()
1113 // Flush stdio files (necessary to flush buffers)
1117 // If we didn't need a console so far, we certainly don't need one now!
1118 // Doing this further up would be dangerous for small write only apps
1120 needsConsole = false;
1122 // Now close stdio files, just to be sure
1128 for (i = 0; i<GUSI_MAX_FD; ++i)
1133 #endif // GUSI_DISPATCH
1135 /********************** sleep()/alarm() ***********************/
1137 static long GUSIAlarm = 0;
1139 int GUSICheckAlarm()
1141 if (GUSIAlarm && LMGetTicks() > GUSIAlarm) {
1150 u_int alarm(u_int seconds)
1152 long remaining = GUSIAlarm ? (LMGetTicks() - GUSIAlarm) / 60 : 0;
1154 GUSIAlarm = seconds ? LMGetTicks() + 60 * seconds : 0;
1156 return (remaining < 0) ? 0 : (u_int) remaining;
1159 static u_int DoSleep(long ticks)
1161 long wakeup = LMGetTicks() + ticks;
1163 SAFESPIN(wakeup > LMGetTicks(), SP_SLEEP, wakeup - LMGetTicks());
1165 long remaining = (LMGetTicks() - wakeup) / 60;
1167 return (remaining < 0) ? 0 : (u_int) remaining;
1170 u_int sleep(u_int seconds)
1172 return DoSleep(seconds * 60);
1175 void usleep(u_int useconds)
1177 DoSleep((useconds * 3) / 50000);
1180 /********************** Default spin function ***********************/
1182 #ifndef GUSI_DISPATCH
1188 /* Borrowed from tech note 263 */
1190 #define kMaskModifiers 0xFE00 // we need the modifiers without the
1191 // command key for KeyTrans
1192 #define kMaskVirtualKey 0x0000FF00 // get virtual key from event message
1194 #define kUpKeyMask 0x0080
1195 #define kShiftWord 8 // we shift the virtual key to mask it
1196 // into the keyCode for KeyTrans
1197 #define kMaskASCII1 0x00FF0000 // get the key out of the ASCII1 byte
1198 #define kMaskASCII2 0x000000FF // get the key out of the ASCII2 byte
1199 #define kPeriod 0x2E // ascii for a period
1201 static Boolean CmdPeriod(EventRecord *theEvent)
1203 Boolean fTimeToQuit;
1205 long virtualKey, keyInfo, lowChar, highChar, keyCId;
1210 fTimeToQuit = false;
1212 if (((*theEvent).what == keyDown) || ((*theEvent).what == autoKey)) {
1214 // see if the command key is down. If it is, find out the ASCII
1215 // equivalent for the accompanying key.
1217 if ((*theEvent).modifiers & cmdKey ) {
1219 virtualKey = ((*theEvent).message & kMaskVirtualKey) >> kShiftWord;
1220 // And out the command key and Or in the virtualKey
1221 keyCode = short(((*theEvent).modifiers & kMaskModifiers) | virtualKey);
1224 hKCHR = nil; /* set this to nil before starting */
1225 KCHRPtr = (Ptr)GetScriptManagerVariable(smKCHRCache);
1228 keyCId = GetScriptVariable(short(GetScriptManagerVariable(smKeyScript)), smScriptKeys);
1230 hKCHR = GetResource('KCHR',short(keyCId));
1235 keyInfo = KeyTrans(KCHRPtr, keyCode, &state);
1237 ReleaseResource(hKCHR);
1239 keyInfo = (*theEvent).message;
1241 lowChar = keyInfo & kMaskASCII2;
1242 highChar = (keyInfo & kMaskASCII1) >> 16;
1243 if (lowChar == kPeriod || highChar == kPeriod)
1246 } // end the command key is down
1247 } // end key down event
1249 return( fTimeToQuit );
1252 Boolean GUSIInterrupt()
1256 for (eventQ = (EvQElPtr) LMGetEventQueue()->qHead; eventQ; )
1257 if (CmdPeriod((EventRecord *) &eventQ->evtQWhat))
1260 eventQ = (EvQElPtr)eventQ->qLink;
1266 long gGUSISpinControl = 0;
1268 int GUSIDefaultSpin(spin_msg msg, long arg)
1270 static Boolean inForeground = true;
1273 long sleepTime = 6; // 1/10 of a second by default
1274 short mask = osMask|highLevelEventMask|mDownMask|evtMask;
1276 GUSIConfig.AutoInitGraf();
1279 register long contrib = (msg == SP_AUTO_SPIN) ? arg : gGUSISpeed;
1280 gGUSISpinControl += contrib;
1281 // Tweak when a spin point has been overshot
1282 RotateCursor((gGUSISpinControl & 31) < contrib ? 32 : gGUSISpinControl);
1285 if (GUSIInterrupt())
1288 if (!StandAlone && inForeground) // For MPW tools, SpinCursor already calls WNE
1289 if (!GUSIConfig.noAppleEvents) // but it no longer reports AppleEvents
1290 mask = highLevelEventMask|evtMask;
1297 if (arg >= sleepTime) // Only sleep if patience guaranteed
1299 // Otherwise, fall through
1307 if (WaitNextEvent(mask, &ev, sleepTime, nil))
1310 if (!evtHandler || !evtHandler[mouseDown])
1311 if (FindWindow(ev.where, &win) == inSysWindow)
1312 SystemClick(&ev, win);
1317 inForeground = true;
1319 inForeground = false;
1321 case kHighLevelEvent:
1322 if (!evtHandler || !evtHandler[kHighLevelEvent])
1323 if (hasAppleEvents) // actually pretty likely, if we get HL Events
1324 AEProcessAppleEvent(&ev); // Ignore errors
1330 if (ev.what >= 0 && ev.what < 24 && evtHandler && evtHandler[ev.what])
1331 evtHandler[ev.what](&ev);
1341 /************************** Feature members **************************/
1343 Feature::Feature(unsigned short trapNum, TrapType tTyp)
1346 NGetTrapAddress(trapNum, tTyp) != NGetTrapAddress(_Unimplemented, ToolTrap);
1349 Feature::Feature(OSType type, long value)
1353 good = (!Gestalt(type, &attr) && (attr >= value));
1356 Feature::Feature(OSType type, long mask, long value)
1360 good = (!Gestalt(type, &attr) && ((attr & mask) == value));
1363 Feature::Feature(const Feature & precondition, OSErrInitializer init)
1365 good = precondition && !init();
1368 Feature::Feature(OSErrInitializer init)
1373 Feature::Feature(const Feature & precondition, voidInitializer init)
1382 Feature::Feature(voidInitializer init)
1388 Feature::Feature(const Feature & cond1, const Feature & cond2)
1390 good = cond1 && cond2;
1393 OSErr AppleTalkIdentity(short & net, short & node)
1396 static short mynode;
1397 static OSErr err = 1;
1400 if (!(err = MPPOpen()))
1401 err = GetNodeAddress(&mynode, &mynet);
1410 /************************** Setup suppport **************************/
1412 /* Pray that the following function never inlines GUSISetup */
1414 void GUSIDefaultSetup()
1416 GUSISetup(GUSIwithAppleTalkSockets);
1417 GUSISetup(GUSIwithInternetSockets);
1418 GUSISetup(GUSIwithPAPSockets);
1419 GUSISetup(GUSIwithPPCSockets);
1420 GUSISetup(GUSIwithUnixSockets);
1421 GUSISetup(GUSIwithSIOUXSockets);
1424 void GUSISetup(void (*proc)())
1429 void GUSILoadConfiguration(Handle hdl)
1431 GUSIConfig.GUSILoadConfiguration(hdl);
1434 #endif // GUSI_DISPATCH