This is SchemeProtocol.m in view mode; [Download] [Up]
/* 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); } }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.