This is MathConnector.m in view mode; [Download] [Up]
// MathConnector.m
// By Charles G. Fleming, Educational Computing Services, Allegheny College.
// Copyright 1993, Allegheny College.
// You may freely copy, distribute and reuse this code.
// Allegheny College and the author disclaim any warranty of any kind,
// expressed or implied, as to its fitness for any particular use.
#import "MathConnector.h"
#import <objc/NXBundle.h>
#import <strings.h>
#import <stdlib.h>
#include <stdio.h>
@implementation MathConnector
int readPacket(MLINK);
void readAndPrintExpression(MLINK);
void error(MLINK);
// Make sure linkPointer is initialized and then start up Mathematica.
- init
{
id returnVal;
self = [super init];
linkPointer = NULL;
// If we can't form a MathLink connection to Mathematica, we return
// nil.
if([self initMathConnection])
returnVal = self;
else
{
NXRunAlertPanel("Error", "Unable to form a MathLink connection "
"with Mathematica.", NULL, NULL, NULL);
returnVal = nil;
}
return returnVal;
}
// Open a MathLink connection to Mathematica.
- (MLINK)initMathConnection
{
int numArgs = 2;
char *args[] = {"-linkname", "math -mathlink", NULL};
// Open a MathLink connection.
linkPointer = MLOpen(numArgs, args);
// Take care of the initial messages sent by Mathematica.
if(linkPointer != NULL)
{
// Mathematica sends a text packet containing the string
// " -- NeXT graphics initialized -- ".
MLNextPacket(linkPointer);
MLNewPacket(linkPointer);
// Mathematica then sends a text packet containing
// the string "\n"
MLNextPacket(linkPointer);
MLNewPacket(linkPointer);
// Mathematica then sends an input name packet containing the
// string
// " In[1]:= "
MLNextPacket(linkPointer);
MLNewPacket(linkPointer);
}
if(MLError(linkPointer))
linkPointer = NULL;
return linkPointer;
}
// Return the linkPointer if a connection was formed or NULL.
- (MLINK)link
{
return linkPointer;
}
// Send "non-matrix" commands to Mathematica.
- (BOOL)evaluateExpression:(char *)string resultType:(int)type
result:(void**)result
{
char *commandString, *resultString, *returnedString;
BOOL success = YES;
int returnedInt, *nonVolatileInt, packetTag, packetType;
double returnedDouble, *nonVolatileDouble;
commandString = malloc(strlen(string) + 50);
switch(type)
{
case STRING:
sprintf(commandString, "ToString[%s, PageWidth->70]", string);
break;
case DEFINITION:
sprintf(commandString, "ToString[%s, PageWidth->70]", string);
break;
case GRAPHICS:
sprintf(commandString, "ToString[%s]", string);
break;
case INTEGER:
strcpy(commandString, string);
break;
case REAL:
strcpy(commandString, string);
break;
default:
success = NO;
break;
}
// If an illegal type was specified, we'll return NO.
if(!success)
{
free(commandString);
return NO;
}
// Ship the command off to Mathematica.
MLReturnValue = MLPutFunction(linkPointer, "ToExpression", 1);
MLPutString(linkPointer, commandString);
MLEndPacket(linkPointer);
free(commandString);
//readPacket(linkPointer);
//return NO;
// Get the result of the execution of the command.
packetType = MLNextPacket(linkPointer);
switch(packetType)
{
case RETURNPKT:
if(type == DEFINITION)
{
// Throw away anything returned.
MLNewPacket(linkPointer);
resultString = (char *)malloc(2);
strcpy(resultString, "");
*result = resultString;
return YES;
}
packetTag = MLGetNext(linkPointer);
switch(packetTag)
{
case MLTKSTR:
if(MLGetString(linkPointer, &returnedString))
{
resultString = (char *)malloc(strlen(returnedString)
+1);
strcpy(resultString, returnedString);
*result = resultString;
MLDisownString(linkPointer, returnedString);
}
else
success = NO;
break;
case MLTKINT:
if(MLGetInteger(linkPointer, &returnedInt))
{
nonVolatileInt = (int *)malloc(sizeof(int));
memcpy(nonVolatileInt, &returnedInt, sizeof(int));
*result = nonVolatileInt;
}
else
success = NO;
break;
case MLTKREAL:
if(MLGetDouble(linkPointer, &returnedDouble))
{
nonVolatileDouble = (double *)malloc(sizeof(double));
memcpy(nonVolatileDouble, &returnedDouble,
sizeof(double));
*result = nonVolatileDouble;
}
else
success = NO;
break;
case MLTKSYM:
case MLTKFUNC:
// Discard the packet.
MLNewPacket(linkPointer);
success = NO;
break;
case MLTKERROR:
default:
MLNewPacket(linkPointer);
if(MLError(linkPointer))
MLClearError(linkPointer);
success = NO;
break;
}
break;
case MESSAGEPKT:
// Discard the MLTKSYM and MLTSTR that will be returned.
MLNewPacket(linkPointer);
// Discard all packets until we get a RETURNPKT.
while(MLNextPacket(linkPointer) != RETURNPKT)
MLNewPacket(linkPointer);
// Discard the return packet.
MLNewPacket(linkPointer);
success = NO;
break;
case DISPLAYPKT:
// We shouldn't ever get one of these.
MLNewPacket(linkPointer);
success = NO;
break;
default:
// Discard any mysterious packet.
MLNewPacket(linkPointer);
success = NO;
break;
}
return success;
}
// Send "matrix" commands to Mathematica.
- (BOOL)evaluateMatrixExpression:(char *)string resultType:(int)type
result:(void**)result rows:(int *)numRows cols:(int *)numCols
{
char *commandString, *resultString, *symbol, *returnedString;
BOOL success = YES;
int packetType, packetTag, *returnedIntList, *nonVolatileIntList, row;
long listCount;
double *returnedRealList, *nonVolatileRealList, *returnedRow;
double *returnedMatrix;
commandString = malloc(strlen(string) + 50);
switch(type)
{
case STRING:
sprintf(commandString, "ToString[%s, PageWidth->70]", string);
break;
case DEFINITION:
sprintf(commandString, "ToString[%s, PageWidth->70]", string);
break;
case INTEGERLIST:
strcpy(commandString, string);
break;
case REALLIST:
strcpy(commandString, string);
break;
case REALMATRIX:
strcpy(commandString, string);
break;
default:
success = NO;
break;
}
// If an illegal type was specified, we'll return NO.
if(!success)
{
free(commandString);
return NO;
}
// Ship the command off to Mathematica.
MLReturnValue = MLPutFunction(linkPointer, "ToExpression", 1);
MLPutString(linkPointer, commandString);
MLEndPacket(linkPointer);
free(commandString);
// Get the result of the execution of the command.
packetType = MLNextPacket(linkPointer);
switch(packetType)
{
case RETURNPKT:
if(type == DEFINITION)
{
// Throw away anything returned.
MLNewPacket(linkPointer);
return NO;
}
packetTag = MLGetNext(linkPointer);
switch(packetTag)
{
case MLTKSTR:
if(MLGetString(linkPointer, &returnedString))
{
resultString = (char *) malloc (strlen(returnedString)
+1);
strcpy(resultString, returnedString);
*result = resultString;
MLDisownString(linkPointer, returnedString);
}
else
success = NO;
break;
case MLTKFUNC:
switch(type)
{
case INTEGERLIST:
if(MLGetIntegerList(linkPointer, &returnedIntList,
&listCount))
{
nonVolatileIntList = (int *)malloc(sizeof(int)
* listCount);
memcpy(nonVolatileIntList, returnedIntList,
sizeof(int) * listCount);
*result = nonVolatileIntList;
*numCols = listCount;
*numRows = 1;
MLDisownIntegerList(linkPointer,
returnedIntList, listCount);
}
break;
case REALLIST:
if(MLGetRealList(linkPointer, &returnedRealList,
&listCount))
{
nonVolatileRealList = (double*)
malloc(sizeof(double) * listCount);
memcpy(nonVolatileRealList, returnedRealList,
sizeof(double) * listCount);
*result = nonVolatileRealList;
*numCols = listCount;
*numRows = 1;
MLDisownRealList(linkPointer, returnedRealList,
listCount);
}
break;
case REALMATRIX:
returnedMatrix = (double *)malloc(*numRows *
*numCols * sizeof(double));
MLGetNext(linkPointer);
MLGetSymbol(linkPointer, &symbol);
MLDisownSymbol(linkPointer, symbol);
for(row = 0; row < *numRows; row++)
{
MLGetNext(linkPointer);
MLGetRealList(linkPointer, &returnedRow,
&listCount);
memcpy(returnedMatrix+(row * *numCols),
returnedRow, *numCols *
sizeof(double));
MLDisownRealList(linkPointer, returnedRow,
listCount);
}
*result = returnedMatrix;
break;
default:
success = NO;
break;
}
break;
default:
success = NO;
break;
}
break;
case MESSAGEPKT:
// Discard the MLTKSYM and MLTSTR that will be returned.
MLNewPacket(linkPointer);
// Discard all packets until we get a RETURNPKT.
while(MLNextPacket(linkPointer) != RETURNPKT)
MLNewPacket(linkPointer);
// Discard the return packet.
MLNewPacket(linkPointer);
success = NO;
break;
case DISPLAYPKT:
// We shouldn't ever get one of these.
MLNewPacket(linkPointer);
success = NO;
break;
default:
// Discard any mysterious packet.
MLNewPacket(linkPointer);
success = NO;
break;
}
return success;
}
void error(MLINK linkPointer)
{
printf("\nerror: %s\n", MLErrorMessage(linkPointer));
MLClose(linkPointer);
}
void readAndPrintExpression(MLINK linkPointer)
{
char *s;
long len;
int n, i;
double r;
static int indent;
switch (MLGetNext(linkPointer))
{
case MLTKSYM:
printf("MLTSYM\n");
MLGetSymbol(linkPointer, &s);
printf("%s\n", s);
break;
case MLTKSTR:
printf("MLTKSTR\n");
MLGetString( linkPointer, &s);
printf("%s\n", s);
break;
case MLTKINT:
printf("MLTKINT\n");
MLGetInteger(linkPointer, &n);
printf("%d\n", n);
break;
case MLTKREAL:
printf("MLTKREAL\n");
MLGetReal(linkPointer, &r);
printf("%f\n", r);
break;
case MLTKFUNC:
printf("MLTKFUNC\n");
indent += 3;
printf("\n %*.*s", indent, indent, "");
if (MLGetArgCount( linkPointer, &len) == 0)
error( linkPointer);
else
{
readAndPrintExpression(linkPointer);
printf("[");
for (i = 1; i <= len; ++i)
{
readAndPrintExpression(linkPointer);
if (i != len) printf(", ");
}
printf("]");
}
indent -= 3;
break;
case MLTKERROR:
default:
printf("MLTKERROR\n");
error(linkPointer);
}
}
int readPacket(MLINK linkPointer)
{
int packetTag;
int length = 1;
switch (packetTag = MLNextPacket(linkPointer))
{
case INPUTPKT:
printf("<INPUTPKT>\n");
break;
case TEXTPKT:
printf("<TEXTPKT>\n");
break;
case RETURNPKT:
printf("<RETURNPKT>\n");
break;
case RETURNTEXTPKT:
printf("<RETURNTEXTPKT>\n");
break;
case MESSAGEPKT:
length = 2;
printf("<MESSAGEPKT>\n");
break;
case CALLPKT:
printf("<CALLPKT>\n");
break;
case INPUTNAMEPKT:
printf("<INPUTNAMEPKT>\n");
break;
case OUTPUTNAMEPKT:
printf("<OUTPUTNAMEPKT>\n");
break;
case SYNTAXPKT:
printf("<SYNTAXERROR>\n");
break;
case MENUPKT:
printf("<MENUPKT>\n");
break;
case DISPLAYPKT:
printf("<DISPLAYPKT>\n");
break;
case DISPLAYENDPKT:
printf("<DISPLAYENDPKT>\n");
break;
default:
printf("unknown packet \"%d\"\n", packetTag);
return 0;
}
while (length --)
readAndPrintExpression(linkPointer);
if ((packetTag != INPUTNAMEPKT) && (packetTag != OUTPUTNAMEPKT))
printf("\n");
return packetTag;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.