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.