This is COWSIPCLibrary.m in view mode; [Download] [Up]
/* Copyright (C) 1994 Sean Luke COWSIPCLibrary.m Version 10 Sean Luke */ #import "COWSIPCLibrary.h" #import <stdio.h> #import <remote/NXProxy.h> // Timed Entry DPSTimedEntryProc _ipc_timer (DPSTimedEntry teNum, double now, void* ipc_library) { COWSIPCLibrary* the_library=(COWSIPCLibrary*) ipc_library; [the_library _checkup]; return (void*) NULL; } @implementation COWSIPCLibrary - init { char nm[COWSLARGESTPATHLENGTH]; id returnval=[super init]; sprintf (nm,"%s(COWS)",[NXApp appName]); //printf ("%s(COWS)\n",[NXApp appName]); connection = [NXConnection registerRoot: self withName:nm]; [connection runFromAppKit]; arguments=[[COWSArgumentList alloc] init]; arguments_state=COWSIPCLIBRARY_ARGSTATE_READY; result=[[COWSStringNode alloc] init]; inited=YES; return returnval; } - awake { if (!inited) return [self init]; return self; } - free { if (connection!=NULL) [connection free]; [arguments free]; [result free]; [NXConnection removeObject:self]; return [super free]; } - loadLibrary:sender { id returnval=[super loadLibrary:sender]; if (![sender conformsTo:@protocol(LibraryControl)]) { printf ("StandardLibrary error: Interpreter cannot accept Library Control protocol!\n"); return NULL; } [sender addLibraryFunction:"send-out" selector:@selector(ipc_sendout:) target:self]; [sender addLibraryFunction:"send-out-remote" selector:@selector(ipc_sendout_machine:) target:self]; [sender addLibraryFunction:"send" selector:@selector(ipc_send:) target:self]; [sender addLibraryFunction:"send-remote" selector:@selector(ipc_send_machine:) target:self]; [sender addLibraryFunction:"launch" selector:@selector(ipc_launch:) target:self]; [sender addLibraryFunction:"launched?" selector:@selector(ipc_launched:) target:self]; [sender makeMeALibraryDelegate:self]; interpreter=sender; return returnval; } - _checkup // pings the recieving library to see if it's done { int answer; // this option is for background sending interpreters [connection setOutTimeout:250]; // library will wait for 1/4 second before // giving up on message NX_DURING answer=[server state]; NX_HANDLER if (NXLocalHandler.code >= NX_REMOTE_EXCEPTION_BASE && NXLocalHandler.code < NX_REMOTE_EXCEPTION_BASE +1000) { //printf ("waiting on error\n"); return NULL; // try again next time... } else NX_RERAISE(); NX_ENDHANDLER if (answer==COWSIPCLIBRARY_ARGSTATE_READY) { id return_val=[[COWSStringNode alloc] init]; if (teNum) DPSRemoveTimedEntry(teNum); teNum=0; [return_val setString:[server result]]; [return_val setError:[server resultIsError]]; [interpreter resumeInterpretingWithValue:return_val]; return self; } //printf ("waiting...\n"); return NULL; } - _send:arg_list:(BOOL) remote { char nm[COWSLARGESTPATHLENGTH]; id current; id name=[[COWSStringNode alloc] init]; id function=[[COWSStringNode alloc] init]; id machine=[[COWSStringNode alloc] init]; int answer; if (remote) { if ([arg_list top]==NULL) // no args { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-remote error: no machine to connect to"]; else [return_val setString:"send error: no machine to connect to"]; [return_val setError:YES]; [name free]; [machine free]; [function free]; return return_val; } else { current=[arg_list pop]; [machine setString:[current string]]; [current free]; } } if ([arg_list top]==NULL) // no args { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-remote error: nothing to connect to"]; else [return_val setString:"send error: nothing to connect to"]; [return_val setError:YES]; [name free]; [machine free]; [function free]; return return_val; } else { current=[arg_list pop]; [name setString:[current string]]; [current free]; } if ([arg_list top]==NULL) // only one arg { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-remote error: no function to call"]; else [return_val setString:"send error: no function to call"]; [return_val setError:YES]; [name free]; [machine free]; [function free]; return return_val; } else { current=[arg_list pop]; [function setString:[current string]]; [current free]; } sprintf (nm,"%s(COWS)",[name string]); if (!remote) server = [NXConnection connectToName:nm]; else server = [NXConnection connectToName:nm onHost:[machine string]]; [name free]; [machine free]; [connection setOutTimeout:5000];// library will wait for 5 seconds before // giving up on message if (server==nil) { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-remote error: cannot establish connection"]; else [return_val setString:"send error: cannot establish connection"]; [return_val setError:YES]; [function free]; return return_val; } NX_DURING answer=[server conformsTo:@protocol(InterpreterIPC)]; NX_HANDLER // server is unavailable! if (NXLocalHandler.code >= NX_REMOTE_EXCEPTION_BASE && NXLocalHandler.code < NX_REMOTE_EXCEPTION_BASE +1000) { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-remote error: send timeout"]; else [return_val setString:"send error: send timeout"]; [return_val setError:YES]; [function free]; return return_val; } else NX_RERAISE(); NX_ENDHANDLER if (!answer) // doesn't conform to protocol { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-remote error: remote object is not an interpreter"]; else [return_val setString:"send error: remote object is not an interpreter"]; [return_val setError:YES]; [function free]; return return_val; } NX_DURING answer=[server state]; NX_HANDLER // server is unavailable! if (NXLocalHandler.code >= NX_REMOTE_EXCEPTION_BASE && NXLocalHandler.code < NX_REMOTE_EXCEPTION_BASE +1000) { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-remote error: send timeout"]; else [return_val setString:"send error: send timeout"]; [return_val setError:YES]; [function free]; return return_val; } else NX_RERAISE(); NX_ENDHANDLER if (answer!=COWSIPCLIBRARY_ARGSTATE_READY) // interpreter is in a busy state { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-remote error: interpreter is busy"]; else [return_val setString:"send error: interpreter is busy"]; [return_val setError:YES]; [function free]; return return_val; } while ([arg_list top]!=NULL) { id current=[arg_list pop]; NX_DURING [server addArgument:(const char*)[current string]]; // if server is working and background, this does nothing but print // a warning message to standard out on the server NX_HANDLER // if server is working and foreground, or app is actively engaged // in something important, this times out! if (NXLocalHandler.code >= NX_REMOTE_EXCEPTION_BASE && NXLocalHandler.code < NX_REMOTE_EXCEPTION_BASE +1000) { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-remote error: send timeout"]; else [return_val setString: "send error: send timeout"]; [return_val setError:YES]; [current free]; [function free]; return return_val; } else NX_RERAISE(); NX_ENDHANDLER [current free]; } NX_DURING [server sendFunction:(const char*) [function string]]; [function free]; NX_HANDLER if (NXLocalHandler.code >= NX_REMOTE_EXCEPTION_BASE && NXLocalHandler.code < NX_REMOTE_EXCEPTION_BASE +1000) { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-remote error: send timeout"]; else [return_val setString:"send error: send timeout"]; [return_val setError:YES]; return return_val; } else NX_RERAISE(); NX_ENDHANDLER // this option is good for foreground sending interpreters // but not background sending ones: if ([interpreter foreground]) { id return_val=[[COWSStringNode alloc] init]; while (1) { NX_DURING answer=[server state]; NX_HANDLER if (NXLocalHandler.code >= NX_REMOTE_EXCEPTION_BASE && NXLocalHandler.code < NX_REMOTE_EXCEPTION_BASE +1000) { //printf ("waiting on error\n"); usleep (500); // pester twice a second continue; } else NX_RERAISE(); NX_ENDHANDLER if (NXUserAborted()) { [interpreter stopInterpreting]; return return_val; } if (answer==COWSIPCLIBRARY_ARGSTATE_READY) break; //printf ("waiting\n"); usleep (500); // pester twice a second } //printf ("Got an answer\n"); [return_val setString:[server result]]; [return_val setError:[server resultIsError]]; return return_val; } else // interpreter is background mode... set up timed entry // to do same thing { [interpreter pauseInterpreting]; if (teNum) DPSRemoveTimedEntry(teNum); teNum=DPSAddTimedEntry(.5, // pester twice a second (DPSTimedEntryProc) _ipc_timer, (void*) self, (int) NX_RUNMODALTHRESHOLD); return NULL; } } - ipc_send:arg_list { return [self _send:arg_list:NO]; } - ipc_send_machine:arg_list { return [self _send:arg_list:YES]; } - _sendout:arg_list:(BOOL) remote // calls a remote function in another // interpreter and ignores answer. { char nm[COWSLARGESTPATHLENGTH]; id current; id name=[[COWSStringNode alloc] init]; id function=[[COWSStringNode alloc] init]; id machine=[[COWSStringNode alloc] init]; int answer; if (remote) { if ([arg_list top]==NULL) // no args { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-out-remote error: no machine to connect to"]; else [return_val setString:"send-out error: no machine to connect to"]; [return_val setError:YES]; [name free]; [machine free]; [function free]; return return_val; } else { current=[arg_list pop]; [machine setString:[current string]]; [current free]; } } if ([arg_list top]==NULL) // no args { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-out-remote error: nothing to connect to"]; else [return_val setString:"send-out error: nothing to connect to"]; [return_val setError:YES]; [name free]; [machine free]; [function free]; return return_val; } else { current=[arg_list pop]; [name setString:[current string]]; [current free]; } if ([arg_list top]==NULL) // only one arg { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-out-remote error: no function to call"]; else [return_val setString:"send-out error: no function to call"]; [return_val setError:YES]; [name free]; [machine free]; [function free]; return return_val; } else { current=[arg_list pop]; [function setString:[current string]]; [current free]; } sprintf (nm,"%s(COWS)",[name string]); if (!remote) server = [NXConnection connectToName:nm]; else server = [NXConnection connectToName:nm onHost:[machine string]]; [name free]; [machine free]; [connection setOutTimeout:5000];// library will wait for 5 seconds before // giving up on message if (server==nil) { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-out-remote error: cannot establish connection"]; else [return_val setString:"send-out error: cannot establish connection"]; [return_val setError:YES]; [function free]; return return_val; } NX_DURING answer=[server conformsTo:@protocol(InterpreterIPC)]; NX_HANDLER // server is unavailable! if (NXLocalHandler.code >= NX_REMOTE_EXCEPTION_BASE && NXLocalHandler.code < NX_REMOTE_EXCEPTION_BASE +1000) { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-out-remote error: send timeout"]; else [return_val setString:"send-out error: send timeout"]; [return_val setError:YES]; [function free]; return return_val; } else NX_RERAISE(); NX_ENDHANDLER if (!answer) // doesn't conform to protocol { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-out-remote error: remote object is not an interpreter"]; else [return_val setString:"send-out error: remote object is not an interpreter"]; [return_val setError:YES]; [function free]; return return_val; } NX_DURING answer=[server state]; NX_HANDLER // server is unavailable! if (NXLocalHandler.code >= NX_REMOTE_EXCEPTION_BASE && NXLocalHandler.code < NX_REMOTE_EXCEPTION_BASE +1000) { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-out-remote error: send timeout"]; else [return_val setString:"send-out error: send timeout"]; [return_val setError:YES]; [function free]; return return_val; } else NX_RERAISE(); NX_ENDHANDLER if (answer!=COWSIPCLIBRARY_ARGSTATE_READY) // interpreter is in a busy state { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-out-remote error: interpreter is busy"]; else [return_val setString:"send-out error: interpreter is busy"]; [return_val setError:YES]; [function free]; return return_val; } while ([arg_list top]!=NULL) { id current=[arg_list pop]; NX_DURING [server addArgument:(const char*)[current string]]; // if server is working and background, this does nothing but print // a warning message to standard out on the server NX_HANDLER // if server is working and foreground, or app is actively engaged // in something important, this times out! if (NXLocalHandler.code >= NX_REMOTE_EXCEPTION_BASE && NXLocalHandler.code < NX_REMOTE_EXCEPTION_BASE +1000) { id return_val=[[COWSStringNode alloc] init]; if (remote) [return_val setString:"send-out-remote error: send timeout"]; else [return_val setString: "send-out error: send timeout"]; [return_val setError:YES]; [current free]; [function free]; return return_val; } else NX_RERAISE(); NX_ENDHANDLER [current free]; } if (1) // otherwise... { id return_val=[[COWSStringNode alloc] init]; [return_val setBooleanVal:YES]; NX_DURING [server sendOutFunction:(const char*) [function string]]; NX_HANDLER if (NXLocalHandler.code >= NX_REMOTE_EXCEPTION_BASE && NXLocalHandler.code < NX_REMOTE_EXCEPTION_BASE +1000) { if (remote) [return_val setString:"send-out-remote error: send timeout"]; else [return_val setString:"send-out error: send timeout"]; [return_val setError:YES]; } else NX_RERAISE(); NX_ENDHANDLER [function free]; return return_val; } } - ipc_sendout:arg_list { return [self _sendout:arg_list:NO]; } - ipc_sendout_machine:arg_list { return [self _sendout:arg_list:YES]; } - ipc_launch:arg_list { id current; id name=[[COWSStringNode alloc] init]; id machine=[[COWSStringNode alloc] init]; id return_val=[[COWSStringNode alloc] init]; port_t response; if ([arg_list top]==NULL) // no args { [return_val setString:"launch error: nothing to launch"]; [return_val setError:YES]; [name free]; [machine free]; return return_val; } else { current=[arg_list pop]; [name setString:[current string]]; [current free]; } if ([arg_list top]==NULL) // only one arg { char host[MAXHOSTNAMELEN]; gethostname(host,MAXHOSTNAMELEN); [machine setString:(const char*) host]; } else { current=[arg_list pop]; [machine setString:[current string]]; [current free]; } response=NXPortFromName([name string],[machine string]); [name free]; [machine free]; if (response==PORT_NULL) { [return_val setBooleanVal:NO]; return return_val; } [return_val setBooleanVal:YES]; return return_val; } - ipc_launched:arg_list { id current; id name=[[COWSStringNode alloc] init]; id machine=[[COWSStringNode alloc] init]; id return_val=[[COWSStringNode alloc] init]; port_t response; if ([arg_list top]==NULL) // no args { [return_val setString:"launched? error: nothing to check for"]; [return_val setError:YES]; [name free]; [machine free]; return return_val; } else { current=[arg_list pop]; [name setString:[current string]]; [current free]; } if ([arg_list top]==NULL) // only one arg { char host[MAXHOSTNAMELEN]; gethostname(host,MAXHOSTNAMELEN); [machine setString:(const char*) host]; } else { current=[arg_list pop]; [machine setString:[current string]]; [current free]; } response=NXPortNameLookup([name string],[machine string]); [name free]; [machine free]; if (response==PORT_NULL) { [return_val setBooleanVal:NO]; return return_val; } [return_val setBooleanVal:YES]; return return_val; } // Delegate Messages - finishedInterpreting:(const char*)returnValue:(int)thisMessage:sender // this message is sent to the delegate, if it can receive it, after // the interpreter has finished interpreting a function request. // it is defined here for IPC purposes (an interpreter can be its // own delegate in an IPC process. { [result setString:returnValue]; [result setError:NO]; started=NO; return self; } - errorInterpreting:(int) thisError:(const char*)thisFunction: (int)thisPosition:(const char*)thisString:sender // this message is sent to the delegate, if it can receive it, after // the interpreter has encountered an error while interpreting. { char anerror[COWSIPCLIBRARY_MAXERRSTRINGLENGTH]; char msg[COWSIPCLIBRARY_MAXERRSTRINGLENGTH]; switch (thisError) { case COWSLIBRARYFUNCTIONERROR : strcpy(msg,thisString); break; case COWSERRORNOSUCHFUNCTION : strcpy(msg,"No Such Function"); break; case COWSERRORNOTENOUGHARGUMENTS : strcpy(msg,"Not Enough Arguments"); break; case COWSERRORTOOMANYARGUMENTS : strcpy(msg,"Too Many Arguments"); break; case COWSERRORNOSUCHVARIABLE : strcpy(msg,"No Such Variable"); break; case COWSERRORNOMORETOKENS : strcpy(msg,"No More Tokens"); break; case COWSERRORNOFUNCTIONNAME : strcpy(msg,"No Function Name"); break; case COWSERRORSETNOTVARIABLE : strcpy(msg,"Set: Not a Variable"); break; case COWSERRORSETTOOMANYVALUES : strcpy(msg,"Set: Too Many Values"); break; case COWSERRORSETNOVALUE : strcpy(msg,"Set: No Value to Set"); break; case COWSERRORSETNOSUCHVARIABLE : strcpy(msg,"Set: No Such Variable"); break; case COWSERRORIFNOTHENCLAUSE : strcpy(msg,"If: No Then Clause"); break; case COWSERRORIFTOOMANYVALUES : strcpy(msg,"If: Too Many Values"); break; case COWSERRORIFNOTENOUGHVALUES : strcpy(msg,"If: Not Enough Values"); break; case COWSERRORWHILETOOMANYVALUES : strcpy(msg,"While: Too Many Values"); break; case COWSERRORWHILENOTENOUGHVALUES : strcpy(msg,"While: Not Enough Values"); break; case COWSERRORFORNOTAVARIABLE : strcpy(msg,"For: Not a Variable"); break; case COWSERRORFORSTARTNOTNUMBER : strcpy(msg,"For: Start Value Not a Number"); break; case COWSERRORFORSTOPNOTNUMBER : strcpy(msg,"For: Stop Value Not a Number"); break; case COWSERRORFORSTEPNOTNUMBER : strcpy(msg,"For: Step Value Not a Number"); break; case COWSERRORFORNOSUCHVARIABLE : strcpy(msg,"For: No Such Variable"); break; case COWSERRORFORTOOMANYVALUES : strcpy(msg,"For: Too Many Values"); break; case COWSERRORFORNOTENOUGHVALUES : strcpy(msg,"For: Not Enough Values"); break; case COWSINTERNALERROR : strcpy(msg,"Interpreter Internal Error"); break; default : strcpy(msg,"Unknown Error"); break; } if (thisError==COWSLIBRARYFUNCTIONERROR) { sprintf (anerror,"Error from %s... %s",[NXApp appName], msg); } else { sprintf(anerror,"Error from %s... %s (%s, %d)",[NXApp appName], msg,thisString,thisPosition); } [result setString:anerror]; [result setError:YES]; started=NO; return self; } - interpreterStopped:sender { char anerror[COWSIPCLIBRARY_MAXERRSTRINGLENGTH]; if (sender==interpreter) { if (![result error]&&started) // interpreter prematurely stopped { sprintf (anerror,"Error from %s... User prematurely stopped interpreter",[NXApp appName]); [result setString:anerror]; [result setError:YES]; } started=NO; arguments_state=COWSIPCLIBRARY_ARGSTATE_READY; // to remove problems receiving } return self; } - interpreterDidStop:sender { if (teNum) DPSRemoveTimedEntry(teNum); // to remove problems sending teNum=0; return self; } - interpreterStarted:sender { started=YES; return self; } - interpreterDidStart:sender { return self; } // IPC Messages - (void) addArgument:(const char*)this_argument { id new_string; //printf ("Adding Argument: %s\n",this_argument); if (arguments_state==COWSIPCLIBRARY_ARGSTATE_WORKING) { printf ("COWS IPC Error: trying to begin new function before old one has finished\n"); } new_string=[[COWSStringNode alloc] init]; [new_string setString:this_argument]; [arguments push:new_string]; //printf ("Added Argument: %s\n",[new_string string]); } - (oneway void) sendOutFunction:(const char*) this_name { id arg_list=[[COWSArgumentList alloc] init]; if (arguments_state==COWSIPCLIBRARY_ARGSTATE_WORKING) { printf ("COWS IPC Error: calling new function before old one has finished\n"); } else { arguments_state=COWSIPCLIBRARY_ARGSTATE_WORKING; // reverse the argument list while([arguments top]!=NULL) { [arg_list push:[arguments pop]]; } if (![interpreter locked]&&![interpreter working]) // i.e., interpreter is able to respond to messages { // note no delegate is assigned. [interpreter setTempDelegate:NULL]; [interpreter interpretFunction:this_name arguments:arg_list]; } [arguments clear]; arguments_state=COWSIPCLIBRARY_ARGSTATE_READY; } [arg_list free]; } - (oneway void) sendFunction:(const char*) this_name { id arg_list=[[COWSArgumentList alloc] init]; if (arguments_state==COWSIPCLIBRARY_ARGSTATE_WORKING) { char junk[COWSLARGESTPATHLENGTH+40]; sprintf (junk,"remote send error (%s): calling new function before old one has finished.", [NXApp appName]); [result setString:junk]; [result setError:YES]; } else { arguments_state=COWSIPCLIBRARY_ARGSTATE_WORKING; // clean out result in preparation for delegate messages [result setString:""]; [result setError:NO]; // reverse the argument list while([arguments top]!=NULL) { [arg_list push:[arguments pop]]; } if (![interpreter locked]&&![interpreter working]) { [interpreter setTempDelegate:self]; [interpreter interpretFunction:this_name arguments:arg_list]; } else { char junk[COWSLARGESTPATHLENGTH+40]; sprintf (junk,"error from (%s): application is busy.", [NXApp appName]); [result setString: junk]; [result setError:YES]; arguments_state=COWSIPCLIBRARY_ARGSTATE_READY; } } [arg_list free]; } - (BOOL) isForeground { if (interpreter==NULL) { printf ("Yikes! No Interpreter\n"); return NO; } return (const) [interpreter foreground]; } - (const char*) result { return (const char*) [result string]; } - (BOOL) resultIsError { return (const) [result error]; } - (int) state { return (const) arguments_state; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.