Added 'list_only' option (and modified 'run()' to respect it).
[python/dscho.git] / Mac / GUSI-mods / into-src / GUSIDispatch.cp
blob86941cbbc08676e4aec4bb98d6b0c1cedc2b1ec4
1 /*********************************************************************
2 Project :       GUSI                            -       Grand Unified Socket Interface
3 File    :       GUSIDispatch.cp-        Dispatch calls to their correct recipient
4 Author  :       Matthias Neeracher
5 Language:       MPW C/C++
7 $Log$
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
28 Initial revision
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
40 {pre,post}_select
42 Revision 0.23  1993/06/27  00:00:00  neeri
43 ftruncate
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
49 Suffixes
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
64 GUSIConfiguration
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
73 getdtablesize()
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
88 hasProcessMgr
90 Revision 0.7  1992/06/27  00:00:00  neeri
91 choose(), hasNewSF
93 Revision 0.6  1992/06/06  00:00:00  neeri
94 Feature
96 Revision 0.5  1992/04/19  00:00:00  neeri
97 C++ Rewrite
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
103 Spin routines
105 Revision 0.2  1992/04/16  00:00:00  neeri
106 User interrupt stuff
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"
115 #include <SetJmp.h>
116 #include <Signal.h>
117 #include <CursorCtl.h>
118 #include <Resources.h>
119 #include <Events.h> 
120 #include <Windows.h>
121 #include <Finder.h>
122 #include <Script.h>
123 #include <Events.h>
124 #include <Traps.h>
125 #include <CommResources.h>
126 #include <CTBUtilities.h>
127 #include <Connections.h>
128 #include <FileTransfers.h>
129 #include <Terminals.h>
130 #include <EPPC.h>
131 #include <PLStringFuncs.h>
132 #include <LowMem.h>
133 #include <Processes.h>
135 #if GENERATINGCFM
136 #include <CodeFragments.h>
137 #endif
139 #pragma segment GUSI
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;
148 long                                            gGUSISpeed      = 1;
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(
158                                 gestaltFSAttr,
159                                 (1<<gestaltHasFSSpecCalls),
160                                 (1<<gestaltHasFSSpecCalls));
161 Feature         hasAlias(
162                                 gestaltAliasMgrAttr,
163                                 (1<<gestaltAliasMgrPresent),
164                                 (1<<gestaltAliasMgrPresent));
165 Feature hasNewSF(
166                                 gestaltStandardFileAttr,
167                                 (1<<gestaltStandardFile58),
168                                 (1<<gestaltStandardFile58));
169 Feature         hasProcessMgr(
170                                 gestaltOSAttr,
171                                 (1<<gestaltLaunchControl),
172                                 (1<<gestaltLaunchControl));
173 Feature hasCRM_P(
174                                 gestaltCRMAttr,
175                                 (1<<gestaltCRMPresent),
176                                 (1<<gestaltCRMPresent));
177 Feature hasCRM(hasCRM_P, InitCRM);
178 Feature hasCTB(hasCRM, InitCTBUtilities);
179 Feature hasStdNBP_P(
180                                 gestaltStdNBPAttr,
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,
190                         2L);
192 /*********************** Error propagation ************************/
194 #ifdef GUSI_DISPATCH
195 inline
196 #endif
197 int GUSI_error(int err)
199         if (err)
200                 errno = err;
202         return -1;
205 #ifdef GUSI_DISPATCH
206 inline
207 #endif
208 void * GUSI_error_nil(int err)
210         if (err)
211                 errno = err;
213         return nil;
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;
228         
229         if (confSize < 4 || !(defaultType = (*config)->defaultType))
230                 defaultType     =       'TEXT';
231         if (confSize < 8 || !(defaultCreator = (*config)->defaultCreator))
232                 defaultCreator  =       'MPS ';
233         if (confSize < 9) 
234                 autoSpin        =       1;                      // do automatic spin on read/write
235         else
236                 autoSpin = (*config)->autoSpin;
237                         
238         if (confSize < 14)
239                 version = '0102';
240         else
241                 version = (*config)->version;
243         if (confSize < 10) {
244                 noChdir                 =       false;  // Use chdir()
245                 accurStat               =       false;  // st_nlink = # of entries + 2
246                 hasConsole              =       false;
247                 noAutoInitGraf  =       false;
248                 sharedOpen              =       false;
249                 sigPipe                 =       false;
250                 noAppleEvents   =       false;
251                 delayConsole            =       false;
252         } else {
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;
261         }
262         
263         if (version < '0120' || confSize < 16)
264                 numSuffices = 0;
265         else
266                 numSuffices = (*config)->numSuffices;
267         
268         if (!numSuffices)
269                 suffices = nil;
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;
277         }
280 GUSIConfiguration::GUSIConfiguration()
282         short   oldResFile = CurResFile();
283         
284         if (!firstTime)
285                 we = oldResFile;
286         else
287                 UseResFile(we);
288                 
289         Handle config   =       Get1Resource('GUโ€ฆI', GUSIRsrcID);
290         GUSILoadConfiguration(config);  
291         if (!firstTime) {
292                 firstTime       =       true;
293                 
294                 if (!noChdir)
295                         chdir(":");
296         } else
297                 UseResFile(oldResFile);
298         
299         ReleaseResource((Handle)config);
302 void GUSIConfiguration::SetDefaultFType(const TFileSpec & name) const
304         FInfo   info;   
306         // 
307         // Custom hook if existing
308         //
309         if (GUSIFType && GUSIFType(name))
310                 return;
311         
312         //
313         // Otherwise default behaviour
314         //
315         if (HGetFInfo(name.vRefNum, name.parID, name.name, &info))
316                 return;
318         Ptr dot = PLstrrchr(name.name, '.');
319         
320         if (dot && (name.name[0] - (dot-Ptr(name.name))) <= 4) {
321                 char searchsuffix[5];
322                 
323                 strncpy(searchsuffix, dot+1, name.name[0] - (dot-Ptr(name.name)));
324                 
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;
329                                 
330                                 goto determined;
331                         }
332         }
334         info.fdType     =       defaultType;
335         info.fdCreator  =       defaultCreator;
336         info.fdFlags    &= ~kHasBeenInited;
338 determined:     
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 
353         if (autoSpin)
354                 SAFESPIN(0, SP_AUTO_SPIN, autoSpin);
357 Boolean GUSIConfiguration::DelayConsole() const
359         return delayConsole;
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);
372                         if (sock)
373                                 Sockets.Install(sock);
374                 }
375         } else {
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); 
382         }
385 void SocketTable::InitConsole()
387         if (needsConsole) {
388                 needsConsole = false;
389                 ::InitConsole();
390         }
393 #endif // GUSI_DISPATCH
395 /************************ External routines *************************/
397 int getdtablesize()
399         return GUSI_MAX_FD;
402 int socket(int domain, int type, int protocol)
404         SocketDomain *  dom;
405         Socket *                sock;
406         int                             fd;
408         Sockets.InitConsole();
409         
410         if (dom = SocketDomain::Domain(domain))
411                 if (sock = dom->socket(type, protocol))
412                         if ((fd = Sockets.Install(sock)) != -1)
413                                 return fd;
414                         else
415                                 delete sock;
417         if (!errno)
418                 return GUSI_error(ENOMEM);
419         else
420                 return -1;
423 int socketpair(int domain, int type, int protocol, int * sv)
425         SocketDomain *  dom;
426         Socket *                sock[2];
428         Sockets.InitConsole();
429         
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)
434                                         return 0;
435                                 else {
436                                         Sockets.Remove(sv[0]);
437                                         
438                                         goto failInstall;
439                                 }
440                         else {
441 failInstall:
442                                 delete sock[0];
443                                 delete sock[1];
444                         }
445                 
446         if (!errno)
447                 return GUSI_error(ENOMEM);
448         else
449                 return -1;
452 int pipe(int * fd)
454         GUSIwithUnixSockets();
455         
456         if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd))
457                 return -1;
458         shutdown(fd[0], 1);
459         shutdown(fd[1], 0);
460         
461         return 0;
464 int choose(int domain, int type, char * prompt, void * constraint, int flags, void * name, int * namelen)
466         SocketDomain *  dom;
468         if (dom = SocketDomain::Domain(domain))
469                 return dom->choose(type, prompt, constraint, flags, name, namelen);
471         return -1;
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];
499         if (sock)
500                 if (sock        = sock->accept(addr, addrlen))
501                         if ((s = Sockets.Install(sock)) != -1)
502                                 return s;
503                         else
504                                 delete sock;
506         return -1;
509 int close(int s)
511         errorSock       =       -1;
512         
513         return Sockets.Remove(s);
516 #ifdef __MWERKS__
517 int read(int s, char *buffer, int buflen)
518 #else
519 int read(int s, char *buffer, unsigned buflen)
520 #endif
522         GUSIConfig.DoAutoSpin();
523         
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();
532         
533         Socket *        sock    =       Sockets[s];
535         if (sock)       {
536                 Scatterer       scatt(iov, count);
538                 if (scatt)
539                         return scatt.length(sock->read(scatt.buffer(), scatt.buflen()));
540                 else
541                         return GUSI_error(ENOMEM);
542         } else
543                 return -1;
546 int recv(int s, void *buffer, int buflen, int flags)
548         GUSIConfig.DoAutoSpin();
549         
550         int             fromlen         =       0;
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();
559         
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();
568         
569         Socket *        sock    =       Sockets[s];
571         if (sock)       {
572                 Scatterer       scatt((struct iovec *)msg->msg_iov, msg->msg_iovlen);
574                 if (scatt)
575                         return
576                                 scatt.length(
577                                         sock->recvfrom(
578                                                 scatt.buffer(),
579                                                 scatt.buflen(),
580                                                 flags,
581                                                 msg->msg_name,
582                                                 (int *)&msg->msg_namelen));
583                 else
584                         return GUSI_error(ENOMEM);
585         } else
586                 return -1;
589 #ifdef __MWERKS__
590 int write(int s, const char *buffer, int buflen)
591 #else
592 int write(int s, const char *buffer, unsigned buflen)
593 #endif
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.
598         */
599         
600         int     len;
601         
602         GUSIConfig.DoAutoSpin();
603         
604         Socket *        sock    =       Sockets[s];
606         if (sock && (len = sock->write((char *) buffer, (unsigned) buflen)) != -1)
607                 return len;
608                 
609         switch (errno) {
610         case EINTR:
611         case EWOULDBLOCK:
612         case EINPROGRESS:
613         case EALREADY:
614                 break;
615         default:
616                 if (GUSIConfig.sigPipe)
617                         raise(SIGPIPE);
618                 if (errorSock == s && errorType == errno) {
619                         if (++errorCount == errorMax) {
620                                 errorSock = -1;
621                         
622                                 return buflen;
623                         }
624                 } else {
625                         errorSock = s;
626                         errorType = errno;
627                         errorCount= 1;
628                 }
629         }
630         return -1;
633 static int HandleWriteErrors(int retval)
635         if (retval == -1)
636                 switch (errno) {
637                 case EINTR:
638                 case EWOULDBLOCK:
639                 case EINPROGRESS:
640                 case EALREADY:
641                         break;
642                 default:
643                         if (GUSIConfig.sigPipe)
644                                 raise(SIGPIPE);
645                         break;
646                 }
647         
648         return retval;
651 int writev(int s, const struct iovec *iov, int count)
653         GUSIConfig.DoAutoSpin();
654         
655         Socket *        sock    =       Sockets[s];
657         if (sock)       {
658                 Gatherer        gath(iov, count);
660                 if (gath)
661                         return HandleWriteErrors(gath.length(sock->write(gath.buffer(), gath.buflen())));
662                 else
663                         return GUSI_error(ENOMEM);
664         } else
665                 return -1;
668 int send(int s, const void *buffer, int buflen, int flags)
670         GUSIConfig.DoAutoSpin();
671         
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();
680         
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();
689         
690         Socket *        sock    =       Sockets[s];
692         if (sock)       {
693                 Gatherer        gath((struct iovec *) msg->msg_iov, msg->msg_iovlen);
695                 if (gath)
696                         return
697                                 HandleWriteErrors(gath.length(
698                                         sock->sendto(
699                                                 gath.buffer(),
700                                                 gath.buflen(),
701                                                 flags,
702                                                 msg->msg_name,
703                                                 msg->msg_namelen)));
704                 else
705                         return GUSI_error(ENOMEM);
706         } else
707                 return -1;
710 int select(int width, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
712         Socket  *       sock;
713         long                    count;
714         int                     s;
715         long                    starttime, waittime;
716         fd_set          rd, wd, ed;
717         Boolean         r,w,e;
718         Boolean *       canRead;
719         Boolean *       canWrite;
720         Boolean *       exception;
722         count = 0;
723         FD_ZERO(&rd);
724         FD_ZERO(&wd);
725         FD_ZERO(&ed);
727         if (timeout)
728                 waittime =  timeout->tv_sec*60 + timeout->tv_usec/16666;
729         else
730                 waittime =      2000000000;     // Slightly more than a year; close enough to "no timeout"
731                 
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))
740                 )
741                         if (!Sockets[s])
742                                 return GUSI_error(EBADF);
743         
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);
750                         if (r || w || e)
751                                 sock->pre_select(r, w, e);
752                 }
753                 
754         do {
755                 for (s = 0; s < width ; ++s)  {
756                         if (sock = Sockets[s]) {
757                                 r = false;
758                                 w = false;
759                                 e = false;
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);
768                                         if (r)
769                                                 FD_SET(s,&rd);
770                                         if (w)
771                                                 FD_SET(s,&wd);
772                                         if (e)
773                                                 FD_SET(s,&ed);
774                                 }
775                         }
776                 }
777                 if (count)
778                         break;
780                 SAVE_AND_CLEAR_ERRNO;
781                 SAFESPIN(false, SP_SELECT, waittime);
783                 if (errno) {
784                         count = -1;
785                         
786                         break;
787                 }
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);
796                         if (r || w || e)
797                                 sock->post_select(r, w, e);
798                 }
799                 
800         if (count < 0)
801                 return GUSI_error(EINTR);
802                 
803         if (readfds)
804                 *readfds = rd;
805         if (writefds)
806                 *writefds = wd;
807         if (exceptfds)
808                 *exceptfds = ed;
810         return count;
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];
838         if (sock)
839                 return (cmd == F_DUPFD) ? Sockets.Install(sock, arg) : sock->fcntl(cmd, arg);
840         else
841                 return -1;
844 int dup(int s)
846         Socket *        sock    =       Sockets[s];
848         return sock ? Sockets.Install(sock) : -1;
851 int dup2(int s, int s1)
853         Socket *        sock    =       Sockets[s];
855         if (!sock)
856                 return -1;
858         if (Sockets[s1])
859                 Sockets.Remove(s1);
861         return Sockets.Install(sock, s1);
864 int ioctl(int s, unsigned int request, long *argp)
866         Socket *        sock    =       Sockets[s];
868         if (!sock)
869                 return -1;
870         
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;
909 int isatty(int s)
911         Socket *        sock    =       Sockets[s];
913         return sock ? sock->isatty() : -1;
916 void GUSISetHook(GUSIHookCode code, GUSIHook hook)
918         switch (code) {
919         case GUSI_SpinHook:
920                 GUSISpin = (GUSISpinFn) hook;
921                 break;
922         case GUSI_ExecHook:
923                 GUSIExec = (GUSIExecFn) hook;
924                 break;
925         case GUSI_FTypeHook:
926                 GUSIFType = (GUSIFTypeFn) hook;
927                 break;
928         case GUSI_SpeedHook:
929                 gGUSISpeed = (long) hook;
930                 break;
931         }
934 GUSIHook GUSIGetHook(GUSIHookCode code)
936         switch (code) {
937         case GUSI_SpinHook:
938                 return (GUSIHook) GUSISpin;
939         case GUSI_ExecHook:
940                 return (GUSIHook) GUSIExec;
941         case GUSI_FTypeHook:
942                 return (GUSIHook) GUSIFType;
943         case GUSI_SpeedHook:
944                 return (GUSIHook) gGUSISpeed;
945                 break;
946         default:
947                 return (GUSIHook) nil;
948         }
951 int GUSISetEvents(GUSIEvtTable table)
953         short   evt;
955         evtHandler      =       table;
956         evtMask         =       0;
958         for (evt = 0; evt<16; ++evt)
959                 if (evtHandler[evt])
960                         evtMask |=      1 << evt;
962         return 0;
965 GUSIEvtHandler * GUSIGetEvents(void)
967         return evtHandler;
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])        {
980                 GUSI_error(EINVAL);
982                 return nil;
983         } else
984                 return domains[domain];
987 void SocketDomain::Ready()
989         if (hasProcessMgr)
990                 WakeUpProcess(&process);
993 SocketDomain::SocketDomain(int domain)
995 #ifdef PREVENT_DUPLICATE_DOMAINS
996         if (domains[domain])    {
997                 Str63   msg;
999                 sprintf((char *) msg+1, "Duplicate declaration for domain %d\n", domain);
1000                 msg[0] = (unsigned char)strlen((char *) msg+1);
1002                 DebugStr(msg);
1003         }
1004 #endif
1005         if (domain)                                                                     // Ignore AF_UNSPEC domains
1006                 domains[domain] =       this;
1007         
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);
1022         return nil;
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()
1046         fwalk(fflush);
1049 SocketTable::SocketTable()
1051         atexit(FlushStdio);
1052         
1053         needsConsole = true;
1055         
1056 int SocketTable::Install(Socket * sock, int start)
1058         short   fd;
1060         if (start<0 || start >= GUSI_MAX_FD)
1061                 return GUSI_error(EINVAL);
1063         for (fd=start; fd<GUSI_MAX_FD; ++fd)
1064                 if (!sockets[fd])       {
1065                         sockets[fd] = sock;
1066                 
1067                         ++sock->refCount;
1068                         return fd;
1069                 }
1071         return GUSI_error(EMFILE);
1074 int SocketTable::Remove(int fd)
1076         Socket *        sock;
1078         InitConsole();
1080         if (fd<0 || fd >= GUSI_MAX_FD || !(sock = sockets[fd]))
1081                 return GUSI_error(EBADF);
1083         sockets[fd]     =       nil;
1085         if (!--sock->refCount)
1086                 delete sock;
1088         return 0;
1091 Socket * SocketTable::operator[](int fd)
1093         Socket * sock;
1095         InitConsole();
1096         
1097         if (fd<0 || fd >= GUSI_MAX_FD || !(sock = sockets[fd])) {
1098                 GUSI_error(EBADF);
1100                 return nil;
1101         } else
1102                 return sock;
1105 #ifndef powerc
1106 #pragma far_code
1107 #endif
1109 SocketTable::~SocketTable()
1111         int i;
1113         // Flush stdio files (necessary to flush buffers)
1115         fwalk(fflush);
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
1119         
1120         needsConsole = false;
1122         // Now close stdio files, just to be sure
1124         fwalk(fclose);
1126         // Close all files
1128         for (i = 0; i<GUSI_MAX_FD; ++i)
1129                 if (sockets[i])
1130                         close(i);
1133 #endif // GUSI_DISPATCH
1135 /********************** sleep()/alarm() ***********************/
1137 static long     GUSIAlarm = 0;
1139 int GUSICheckAlarm()
1141         if (GUSIAlarm && LMGetTicks() > GUSIAlarm) {
1142                 GUSIAlarm = 0;
1143                 raise(SIGALRM);
1144                 
1145                 return 1;
1146         } else
1147                 return 0;
1150 u_int    alarm(u_int seconds)
1152         long remaining = GUSIAlarm ? (LMGetTicks() - GUSIAlarm) / 60 : 0;
1153         
1154         GUSIAlarm = seconds ? LMGetTicks() + 60 * seconds : 0;
1155         
1156         return (remaining < 0) ? 0 : (u_int) remaining;
1159 static u_int DoSleep(long ticks)
1161         long wakeup = LMGetTicks() + ticks;
1162         
1163         SAFESPIN(wakeup > LMGetTicks(), SP_SLEEP, wakeup - LMGetTicks());
1164         
1165         long remaining = (LMGetTicks() - wakeup) / 60;
1166         
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
1184 #ifndef powerc
1185 #pragma smart_code
1186 #endif
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
1193                                                 // for KeyTrans
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;
1204         short    keyCode;
1205         long     virtualKey, keyInfo, lowChar, highChar, keyCId;
1206         UInt32  state;
1207         Handle   hKCHR;
1208         Ptr             KCHRPtr;
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);
1222                         state      = 0;
1224                         hKCHR = nil;  /* set this to nil before starting */
1225                         KCHRPtr = (Ptr)GetScriptManagerVariable(smKCHRCache);
1227                         if ( !KCHRPtr ) {
1228                                 keyCId = GetScriptVariable(short(GetScriptManagerVariable(smKeyScript)), smScriptKeys);
1230                                 hKCHR   = GetResource('KCHR',short(keyCId));
1231                                 KCHRPtr = *hKCHR;
1232                         }
1234                         if (KCHRPtr) {
1235                                 keyInfo = KeyTrans(KCHRPtr, keyCode, &state);
1236                                 if (hKCHR)
1237                                         ReleaseResource(hKCHR);
1238                         } else
1239                                 keyInfo = (*theEvent).message;
1241                         lowChar =  keyInfo &  kMaskASCII2;
1242                         highChar = (keyInfo & kMaskASCII1) >> 16;
1243                         if (lowChar == kPeriod || highChar == kPeriod)
1244                                 fTimeToQuit = true;
1246                 }  // end the command key is down
1247         }  // end key down event
1249         return( fTimeToQuit );
1252 Boolean GUSIInterrupt()
1254         EvQElPtr                eventQ;
1256         for (eventQ = (EvQElPtr) LMGetEventQueue()->qHead; eventQ; )
1257                 if (CmdPeriod((EventRecord *) &eventQ->evtQWhat))
1258                         return true;
1259                 else
1260                         eventQ = (EvQElPtr)eventQ->qLink;
1261         
1262         return false;
1265 int StandAlone = 1;
1266 long gGUSISpinControl = 0;
1268 int GUSIDefaultSpin(spin_msg msg, long arg)
1270         static Boolean                  inForeground    =       true;
1271         WindowPtr                               win;
1272         EventRecord                             ev;
1273         long                                    sleepTime       =       6;      // 1/10 of a second by default
1274         short                                   mask            =       osMask|highLevelEventMask|mDownMask|evtMask;
1276         GUSIConfig.AutoInitGraf();
1277         
1278         if (inForeground) {
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);
1283         }
1285         if (GUSIInterrupt())
1286                 goto interrupt;
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;
1291                 else
1292                         return 0;                                                               
1293                 
1294         switch (msg) {
1295         case SP_SLEEP:
1296         case SP_SELECT:
1297                 if (arg >= sleepTime)                           // Only sleep if patience guaranteed
1298                         break;
1299                 // Otherwise, fall through      
1300         case SP_AUTO_SPIN:
1301                 sleepTime = 0;
1302                 break;
1303         default:
1304                 break;
1305         }
1306         
1307         if (WaitNextEvent(mask, &ev, sleepTime, nil))
1308                 switch (ev.what) {
1309                 case mouseDown:
1310                         if (!evtHandler || !evtHandler[mouseDown])
1311                                 if (FindWindow(ev.where, &win) == inSysWindow)
1312                                         SystemClick(&ev, win);
1314                         break;
1315                 case osEvt:
1316                         if (ev.message & 1)
1317                                 inForeground    =       true;
1318                         else
1319                                 inForeground    =       false;
1320                         break;
1321                 case kHighLevelEvent:
1322                         if (!evtHandler || !evtHandler[kHighLevelEvent])
1323                                 if (hasAppleEvents)                             // actually pretty likely, if we get HL Events
1324                                         AEProcessAppleEvent(&ev);       // Ignore errors
1325                         break;
1326                 default:
1327                         break;
1328                 }
1330         if (ev.what >= 0 && ev.what < 24 && evtHandler && evtHandler[ev.what])
1331                 evtHandler[ev.what](&ev);
1333         return 0;
1335 interrupt:
1336         FlushEvents(-1, 0);
1338         return -1;
1341 /************************** Feature members **************************/
1343 Feature::Feature(unsigned short trapNum, TrapType tTyp)
1345         good =
1346                 NGetTrapAddress(trapNum, tTyp) != NGetTrapAddress(_Unimplemented, ToolTrap);
1349 Feature::Feature(OSType type, long value)
1351         long            attr;
1353         good = (!Gestalt(type, &attr) && (attr >= value));
1356 Feature::Feature(OSType type, long mask, long value)
1358         long            attr;
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)
1370         good    =       !init();
1373 Feature::Feature(const Feature & precondition, voidInitializer init)
1375         if (precondition)       {
1376                 good = true;
1377                 init();
1378         } else
1379                 good = false;
1382 Feature::Feature(voidInitializer init)
1384         good = true;
1385         init();
1388 Feature::Feature(const Feature & cond1, const Feature & cond2)
1390         good = cond1 && cond2;
1393 OSErr AppleTalkIdentity(short & net, short & node)
1395         static short    mynet;
1396         static short    mynode;
1397         static OSErr    err = 1;
1399         if (err == 1)
1400                 if (!(err = MPPOpen()))
1401                         err = GetNodeAddress(&mynode, &mynet);
1404         net     =       mynet;
1405         node    =       mynode;
1407         return err;
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)())
1426         proc();
1429 void GUSILoadConfiguration(Handle hdl)
1431         GUSIConfig.GUSILoadConfiguration(hdl);
1434 #endif // GUSI_DISPATCH