home *** CD-ROM | disk | FTP | other *** search
- /* Copyright รก 1991 Gustavus Adolphus College. All rights reserved.
- *
- * Schematik was developed by Gustavus Adolphus College (GAC) with
- * support from NeXT Computer, Inc. Permission to copy this software,
- * to redistribute it, and to use it for any purpose is granted,
- * subject to the following restrictions and understandings.
- *
- * 1. Any copy made of this software must include this copyright
- * notice in full.
- *
- * 2. Users of this software agree to make their best efforts (a) to
- * return to the GAC Mathematics and Computer Science Department any
- * improvements or extensions that they make, so that these may be
- * included in future releases; and (b) to inform GAC of noteworthy
- * uses of this software.
- *
- * 3. All materials developed as a consequence of the use of this
- * software shall duly acknowledge such use, in accordance with the
- * usual standards of acknowledging credit in academic research.
- *
- * 4. GAC makes no express or implied warranty or representation of
- * any kind with respect to this software, including any warranty
- * that the operation of this software will be error-free. ANY
- * IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
- * PURPOSE IS HEREBY DISCLAIMED. GAC is under no obligation to
- * provide any services, by way of maintenance, update, or otherwise.
- *
- * 5. In conjunction with products arising from the use of this
- * material, there shall be no use of the name of Gustavus Adolphus
- * College nor of any adaptation thereof in any advertising,
- * promotional, or sales literature without prior written consent
- * from GAC in each case.
- */
-
- #import "SchemeProtocol.h"
- #import "../defines.h"
- #import Main_h
- #import PrefAgent_h
- #import DocText_h
- #import InteractionWin_h
- #import <appkit/Matrix.h>
- #import <appkit/Panel.h>
- #import <appkit/Text.h>
- #import <sys/signal.h>
- #import <sys/socket.h>
- #import <defaults.h>
- #import <fcntl.h>
- #import <libc.h>
- #import <mach.h>
- #import <NXCType.h>
- #import <string.h>
- extern void NXBeep(void);
-
- #define BUFFERSIZE 4096
- #define COMMENTCHAR ';'
- #define COMMENTSTRING ";"
- #define ERRORAFFIRMATIVE "y"
- #define ERRORNEGATIVE "n"
- #define MAXPARAMS 64
- #define PROMPTMESSAGESPLITCHAR ' '
- #define QUERYAFFIRMATIVE "y"
- #define QUERYNEGATIVE "n"
- #define SCHEMEENVIRON1 "USE_SCHEMATIK_STYLE_INTERRUPTS="
- #define SCHEMEENVIRON2 "USE_SCHEMATIK_STYLE_ERRORS="
- #define SCHEMEENVIRON3 "USE_SCHEMATIK_STYLE_GRAPHICS="
- #define SMF1A "(message \"%s\" \""
- #define SMF1B "\")"
- #define SMF2A "(xscheme-write-message-1 xscheme-prompt (format \";Value "
- #define SMF2B ": %s\" xscheme-prompt))"
- #define YORN " (y or n)? "
-
- #define USLEEP(x) {int _usleep_mask=sigsetmask(~0);\
- usleep((x));\
- sigsetmask(_usleep_mask);}
-
- static void fdHandler(int, id);
- static void outputHandler(DPSTimedEntry, double, id);
- static void childHandler(DPSTimedEntry, double, id);
-
- int fromScheme,toScheme,schemePid,graphicsFD;
- int inState=1,j=0,k=0;
- BOOL inInputState=NO,gc=NO,sigintOK=YES;
- char buffer1[BUFFERSIZE],buffer3[BUFFERSIZE];
- DPSTimedEntry TE,childCheck;
- NXZone *outputZone=NULL;
- char *outputBuffer=NULL;
- unsigned outputBufferSize=0;
- char *bogusEscPHack=NULL;
-
- @implementation SchemeProtocol
-
- - init
- {
- int sv[2],sw[2],numFDs,fd,pidChild;
-
- DEBUG_FUNC1(DEBUGLEVEL);
- if ((socketpair(AF_UNIX,SOCK_STREAM,0,sv)<0)||(socketpair(AF_UNIX,SOCK_STREAM,0,sw)<0))
- {
- NXRunAlertPanel(ERRORTITLE,SOCKETERRORMESSAGE,NULL,NULL,NULL);
- return nil;
- }
- switch (pidChild = vfork())
- {
- case -1: NXRunAlertPanel(ERRORTITLE,FORKERRORMESSAGE,NULL,NULL,NULL);
- return nil;
- case 0 : {
- char *argv[MAXPARAMS],**envp;
- char *parms=NXCopyStringBuffer([[PrefAgent new] parameters]);
- int i;
-
- argv[0]=[[PrefAgent new] executable];
- argv[1]=strtok(parms, WHITESPACECHARS);
- for(i=2; i<MAXPARAMS; i++)
- argv[i]=strtok(NULL, WHITESPACECHARS);
- argv[MAXPARAMS-1]=NULL;
- for(i=0; environ[i]; i++);
- envp=(char **)malloc((i+3)*sizeof(char *));
- for(i=0; environ[i]; i++) envp[i]=environ[i];
- envp[i++]=SCHEMEENVIRON1;
- envp[i++]=SCHEMEENVIRON2;
- envp[i++]=SCHEMEENVIRON3;
- envp[i]=NULL;
- dup2(sv[1],0);
- dup2(sv[1],1);
- dup2(sv[1],2);
- dup2(sw[1],3);
- numFDs = getdtablesize();
- for(fd=4; fd<numFDs; fd++)
- close(fd);
- execve(argv[0],argv,envp);
- perror(EXECERRORMESSAGE);
- _exit(1);
- }
- default: schemePid = pidChild;
- fromScheme = toScheme = sv[0];
- graphicsFD = sw[0];
- fcntl(toScheme, F_SETFL, fcntl(toScheme, F_GETFL, 0)|FNDELAY);
- fcntl(graphicsFD, F_SETFL, fcntl(graphicsFD, F_GETFL, 0)|FNDELAY);
- DPSAddFD(fromScheme, (DPSFDProc)fdHandler, (id)self, NX_BASETHRESHOLD+1);
- TE = (DPSTimedEntry)0;
- interactionWin = [NXApp interactionWindow];
- outputZone = NXCreateZone(vm_page_size, vm_page_size, YES);
- outputBuffer = (char *)NXZoneMalloc(outputZone, 1020);
- childCheck = DPSAddTimedEntry(10.0, (DPSTimedEntryProc)childHandler, self, NX_MODALRESPTHRESHOLD+1);
- return self;
- }
- }
-
- - free
- {
- inState=1;
- j=k=0;
- inInputState=NO;
- gc=NO;
- sigintOK=YES;
- if (bogusEscPHack!=NULL) free(bogusEscPHack);
- bogusEscPHack=NULL;
- buffer1[0] = buffer3[0] = 0;
- NXDestroyZone(outputZone);
- outputZone = NULL;
- outputBuffer = NULL;
- outputBufferSize = 0;
- return [super free];
- }
-
- @end
-
- @implementation SchemeProtocol (SchemeProcess)
-
- - (int)schemePid { return schemePid;}
-
- - outputHandler
- {
- DEBUG_FUNC1(DEBUGLEVEL);
- if (outputBufferSize)
- {
- int num = write(toScheme, outputBuffer, outputBufferSize);
- if (num>0)
- {
- outputBufferSize-=num;
- memmove(outputBuffer, (outputBuffer+num), outputBufferSize);
- }
- }
- if (!TE&&(outputBufferSize>0))
- TE = DPSAddTimedEntry(0.01, (DPSTimedEntryProc)outputHandler, self, NX_MODALRESPTHRESHOLD);
- else if (TE&&!outputBufferSize)
- {
- DPSRemoveTimedEntry(TE);
- TE = (DPSTimedEntry)0;
- }
- return self;
- }
-
- - send:(STR)aString
- {
- DEBUG_FUNC1(DEBUGLEVEL);
- outputBuffer = (char *)NXZoneRealloc(outputZone, outputBuffer, outputBufferSize+strlen(aString)+1);
- strcpy((outputBuffer+outputBufferSize), aString);
- outputBufferSize+=strlen(aString);
- [self outputHandler];
- return self;
- }
-
- - sendNul
- {
- DEBUG_FUNC1(DEBUGLEVEL);
- outputBuffer = (char *)NXZoneRealloc(outputZone, outputBuffer, outputBufferSize+1);
- outputBuffer[outputBufferSize++] = '\0';
- [self outputHandler];
- return self;
- }
-
- - sendSignal:(int)aSignal
- {
- DEBUG_FUNC1(DEBUGLEVEL);
- switch (aSignal)
- {
- case SIGNALBREAKPOINT: kill(schemePid,aSignal); return self;
- case SIGNALABORTTOP : if (!sigintOK) return self;
- case SIGNALABORTPREV :
- case SIGNALABORTSAME : kill(schemePid,aSignal);
- }
- USLEEP(10000);
- return [self sendNul];
- }
-
- - sendGraphicsWindow:(int)windowNum
- {
- char buffer[2044];
-
- sprintf(buffer,"%i\n%s\n%s\n",windowNum, (NXGetDefaultValue([NXApp appName],"NXHost")?:"\0"), (NXGetDefaultValue([NXApp appName],"NXPSName")?:"\0"));
- write(graphicsFD, buffer, strlen(buffer));
- return self;
- }
-
- #include <syslog.h>
-
- void kill_alarm(int sig)
- {
- kill(schemePid, SIGKILL);
- syslog(LOG_WARNING|LOG_LOCAL1, "Scheme termination timeout (5 sec). Killing with SIGKILL.");
- }
-
- void kill_scheme()
- {
- void (*oldsigh)(int);
- union wait status;
- int ret,oldsigb;
-
- kill(schemePid, SIGHUP);
- oldsigb=sigblock(0);
- // if (sigmask(SIGALRM)&oldsigb)
- // oldsigb=oldsigb&(~sigmask(SIGALRM));
- sigblock(oldsigb);
- oldsigh = signal(SIGALRM, kill_alarm);
- ualarm(5000000, 0);
- ret = wait4(schemePid, &status, 0, NULL);
- if (WIFSTOPPED(status)||(ret<0))
- kill_alarm(0);
- ualarm(0, 0);
- signal(SIGALRM, oldsigh);
- }
-
- - terminate:sender withPrejudice:(BOOL)aBoolean
- {
- DEBUG_FUNC1(DEBUGLEVEL);
- if (!schemePid)
- return self;
- DPSRemoveTimedEntry(childCheck);
- if (TE) DPSRemoveTimedEntry(TE);
- kill_scheme();
- DPSRemoveFD(fromScheme);
- close(fromScheme);
- close(toScheme);
- close(graphicsFD);
- schemePid=0;
- if (!aBoolean)
- NXRunAlertPanel(ERRORTITLE,TERMINATIONERRORMESSAGE,NULL,NULL,NULL);
- return self;
- }
-
- - fdHandler:(int)anFD
- {
- char aChar,tempBuffer[BUFFERSIZE];
- int ret,i;
-
- DEBUG_FUNC1(DEBUGLEVEL);
- if ((ret=read(anFD, tempBuffer, BUFFERSIZE))<=0)
- return [self terminate:self withPrejudice:NO];
- for(i=0; i<ret; i++)
- {
- aChar = tempBuffer[i];
- switch (inState)
- {
- case 1 : switch (aChar) /* Initial state */
- {
- case 27 : buffer1[j] = '\0'; [self sendOutput:buffer1]; j=0; inState = 2; break;
- case 7 : NXBeep(); break;
- default : buffer1[j++] = aChar;
- }
- break;
- case 2 : switch (aChar) /* ESC sequence state */
- {
- case 'c' :
- case 'o' :
- case 'z' :
- case 'R' : inState = 1; break; /* nop, no string */
- case 'w' :
- case 'D' : k = 0; buffer3[0] = '\0'; inState = 3; break; /* nop, with string */
- case 'b' : [self showRunState:GARBCOLLECT]; gc = YES; inState = 1; break;
- case 'e' : [self showRunState:PREVIOUS]; gc = NO; inState = 1; break;
- case 'f' : [self showRunState:EVALUATING]; inInputState = NO; inState = 1; break;
- case 's' : [self showRunState:INPUTSTATE]; inInputState = YES; [self sendGraphics:"f0"]; inState = 1; break;
- case 'g' : sigintOK = YES; inState = 1; break;
- case 'i' :
- case 'm' : k = 0; buffer3[0] = '\0'; inState = 4; break; /* normal message */
- case 'p' : k = 0; buffer3[0] = '\0'; inState = 5; break; /* prompt message */
- case 'v' : k = 0; buffer3[0] = '\0'; inState = 6; break; /* normal value */
- case 'n' : k = 0; buffer3[0] = '\0'; inState = 7; break; /* yes/no query */
- case 'B' : k = 0; buffer3[0] = '\0'; inState = 8; break; /* error message */
- case 'E' : k = 0; buffer3[0] = '\0'; inState = 9; break; /* special message */
- case 'P' : k = 0; buffer3[0] = '\0'; inState = 10; break; /* special value */
- case 'G' : k = 0; buffer3[0] = '\0'; inState = 11; break; /* graphics */
- default : NXRunAlertPanel(PROTOCOLERROR, NONPROTOCOLERROR, NULL, NULL, NULL, aChar); inState = 1;
- }
- break;
- case 3 : if (aChar==27) // nop string
- {
- buffer3[k] = '\0';
- inState = 1; break;
- }
- buffer3[k++] = aChar; break;
- case 4 : if (aChar==27) // normal message
- {
- buffer3[k] = '\0';
- [self sendMessage:buffer3];
- inState = 1; break;
- }
- buffer3[k++] = aChar; break;
- case 5 : if (aChar==27) // prompt message
- {
- buffer3[k] = '\0';
- [self sendPrompt:buffer3];
- inState = 1; break;
- }
- buffer3[k++] = aChar; break;
- case 6 : if (aChar==27) // value
- {
- buffer3[k] = '\0';
- [self sendValue:buffer3];
- inState = 1; break;
- }
- buffer3[k++] = aChar; break;
- case 7 : if (aChar==27) // yes/no query
- {
- buffer3[k] = '\0';
- if ((strlen(buffer3)>=strlen(YORN))&&
- !NXOrderStrings((unsigned char *)(buffer3+strlen(buffer3)-strlen(YORN)),(unsigned char *)YORN,NO,-1,NULL))
- strcpy(buffer3+strlen(buffer3)-strlen(YORN), "?");
- [self sendQuery:buffer3];
- inState = 1; break;
- }
- buffer3[k++] = aChar; break;
- case 8 : if (aChar==27) // error
- {
- buffer3[k] = '\0';
- [self sendError:buffer3];
- inState = 1; break;
- }
- buffer3[k++] = aChar; break;
- case 9 : if (aChar==27) // special message
- {
- buffer3[k] = '\0';
- if ((strlen(buffer3)>=strlen(SMF1A)+strlen(SMF1B))&&
- !NXOrderStrings((unsigned char *)buffer3,(unsigned char *)SMF1A,NO,strlen(SMF1A),NULL)&&
- !NXOrderStrings((unsigned char *)(buffer3+strlen(buffer3)-strlen(SMF1B)),(unsigned char *)SMF1B,NO,-1,NULL))
- {
- buffer3[k-strlen(SMF1B)] = '\0';
- [self sendMessage:(buffer3+strlen(SMF1A))];
- }
- else if ((bogusEscPHack!=NULL)&&
- (strlen(buffer3)>=strlen(SMF2A)+strlen(SMF2B))&&
- !NXOrderStrings((unsigned char *)buffer3,(unsigned char *)SMF2A,NO,strlen(SMF2A),NULL)&&
- !NXOrderStrings((unsigned char *)(buffer3+strlen(buffer3)-strlen(SMF2B)),(unsigned char *)SMF2B,NO,-1,NULL))
- {
- // if (![[PrefAgent new] includeHashValues])
- [self sendValue:bogusEscPHack];
- // else
- // {
- // buffer3[k-strlen(SMF2B)] = '\0';
- // [self sendSpecialValue:bogusEscPHack withHashCode:(buffer3+strlen(SMF2A))];
- // }
- free(bogusEscPHack);
- bogusEscPHack=NULL;
- }
- inState = 1; break;
- }
- buffer3[k++] = aChar; break;
- case 10 : if (aChar==27) // special value
- {
- buffer3[k] = '\0';
- bogusEscPHack = NXCopyStringBuffer(buffer3);
- inState = 1; break;
- }
- buffer3[k++] = aChar; break;
-
- case 11: if (aChar==27) // graphics
- {
- buffer3[k] = '\0';
- [self sendGraphics:buffer3];
- inState = 1; break;
- }
- buffer3[k++] = aChar; break;
- }
- }
- if (inState==1)
- {
- buffer1[j] = '\0'; [self sendOutput:buffer1]; j = 0;
- }
- return self;
- }
-
- @end
-
- @implementation SchemeProtocol (InteractionWindow)
-
- - sendMessage:(STR)aString
- {
- id text = [interactionWin textView];
- DEBUG_FUNC1(DEBUGLEVEL);
- [text appendNewlineIfNeeded];
- return [text appendText:aString commented:YES withNewline:YES];
- }
-
- - sendQuery:(STR)aString
- {
- DEBUG_FUNC1(DEBUGLEVEL);
- if (NXRunAlertPanel(QUERYTITLE, aString, QUERYDEFAULT, QUERYALTERNATE, NULL)>0)
- [self send:QUERYAFFIRMATIVE];
- else
- [self send:QUERYNEGATIVE];
- return self;
- }
-
- - sendValue:(STR)aString
- {
- id text = [interactionWin textView];
- DEBUG_FUNC1(DEBUGLEVEL);
- [text appendNewlineIfNeeded];
- if (!*aString)
- return [text appendText:NOVALUESTRING commented:YES withNewline:YES];
- [text appendText:VALUESTRING commented:YES withNewline:NO];
- return [text appendText:aString commented:NO withNewline:YES];
- }
-
- - sendSpecialValue:(STR)aString withHashCode:(STR)hashString
- {
- id text = [interactionWin textView];
- DEBUG_FUNC1(DEBUGLEVEL);
- [text appendNewlineIfNeeded];
- [text appendText:"Value " commented:YES withNewline:NO];
- [text appendText:hashString commented:NO withNewline:NO];
- [text appendText:": " commented:NO withNewline:NO];
- return [text appendText:aString commented:NO withNewline:YES];
- }
-
- - sendGraphics:(STR)aString // sent to NXApp (Main)
- {
- char function;
- unsigned int windownum,width,height,mode;
-
- switch (aString[0])
- {
- case 'c' : sscanf(aString, "%c%d", &function, &windownum);
- [NXApp closeGraphicsWindow:windownum];
- break;
- case 'f' : sscanf(aString, "%c%d%d", &function, &windownum, &mode);
- [NXApp setGraphicsWindowFlush:windownum mode:mode];
- break;
- case 'o' : sscanf(aString, "%c%d%u%u", &function, &windownum, &width, &height);
- [NXApp openGraphicsWindow:windownum width:width height:height];
- break;
- case 'p' : sscanf(aString, "%c%d", &function, &windownum);
- [NXApp printGraphicsWindow:windownum];
- break;
- default : NXRunAlertPanel(PROTOCOLERROR, GRAPHICSPROTOCOLERROR, NULL, NULL, NULL, aString[0]);
- }
- return self;
- }
-
- - sendOutput:(STR)aString
- {
- id text = [interactionWin textView];
- DEBUG_FUNC1(DEBUGLEVEL);
- if (*aString)
- return [text appendText:aString commented:[[PrefAgent new] commentOutput] withNewline:NO];
- return self;
- }
-
- - sendPrompt:(STR)aString
- {
- id text = [interactionWin textView];
- DEBUG_FUNC1(DEBUGLEVEL);
- [interactionWin setLevel:atoi(aString)];
- [interactionWin setPrompt:strchr(aString, PROMPTMESSAGESPLITCHAR)];
- return [text appendText:"" commented:NO withNewline:YES];
- }
-
- - sendError:(STR)aString
- {
- DEBUG_FUNC1(DEBUGLEVEL);
- if (NXRunAlertPanel(ERRORTITLE,ERRORMESSAGE,ERRORDEFAULT,ERRORALTERNATE,NULL,aString)>0)
- switch ([[PrefAgent new] errorAbort])
- {
- case 0: [self sendSignal:SIGNALABORTTOP]; break;
- case 1: [self sendSignal:SIGNALABORTSAME]; break;
- }
- else
- [self sendNul];
- [self showRunState:PREVIOUS];
- if ([[NXApp prefAgent] insertErrors])
- {
- [self sendMessage:aString];
- [interactionWin makeKeyAndOrderFront:self];
- }
- return self;
- }
-
-
- - showRunState:(int)aState
- {
- static int prevState;
-
- DEBUG_FUNC1(DEBUGLEVEL);
- switch (aState)
- {
- case INPUTSTATE : [interactionWin setTitle:INTERWINDOWTITLE];
- prevState=INPUTSTATE; break;
- case EVALUATING : [interactionWin setTitle:EVALMESSAGE];
- prevState=EVALUATING; break;
- case GARBCOLLECT: [interactionWin setTitle:GCMESSAGE]; break;
- case PREVIOUS : ((prevState==INPUTSTATE)?[interactionWin setTitle:INTERWINDOWTITLE]:[interactionWin setTitle:EVALMESSAGE]);
- }
- return self;
- }
-
- @end
-
- static void fdHandler(int anFD, id self)
- {
- [self fdHandler:anFD];
- }
-
- static void outputHandler(DPSTimedEntry te, double time, id self)
- {
- [self outputHandler];
- }
-
- static void childHandler(DPSTimedEntry te, double time, id self)
- {
- extern char *sys_siglist[];
- union wait status;
- int ret = wait4(schemePid, &status, WNOHANG|WUNTRACED, NULL);
-
- if (ret>0)
- {
- if (WIFSTOPPED(status))
- NXRunAlertPanel(SCHEMEPROCMESSAGE,PROCESSSTOPPED,NULL,NULL,NULL,status.w_stopsig,sys_siglist[status.w_stopsig]);
- else if (WIFSIGNALED(status))
- {
- if (NXRunAlertPanel(SCHEMEPROCMESSAGE,PROCESSSIGTERM,
- RESTARTDEFAULT,RESTARTALTERNATE,NULL,status.w_termsig,sys_siglist[status.w_termsig]))
- [NXApp restartSubprocess];
- }
- else
- NXRunAlertPanel(SCHEMEPROCMESSAGE,PROCESSEXITTERM,NULL,NULL,NULL,status.w_retcode);
- }
- }
-