This is Controller.m in view mode; [Download] [Up]
#import "Controller.h"
@implementation Controller
+ initialize
{
static char buffer [1025];
static NXDefaultsVector MyDefaults = {
{"SayAvailable", "false"},
{"SayPath", "/usr/local/bin/say"},
{"SndplayPath", "/usr/bin/sndplay"},
{"SoundPath", buffer},
{NULL}
};
sprintf (buffer, "%s/Library/Sounds", NXHomeDirectory ());
NXRegisterDefaults ("FIX", MyDefaults);
return self;
}
- init
{
commands = NULL;
variables = [[NXStringTable alloc] init];
constants = [[NXStringTable alloc] init];
directory = NULL;
filename = NULL;
return [super init];
}
- awakeFromNib
{
[self revertDefaults:self];
return self;
}
- defaultsOK:sender
{
NXWriteDefault ("FIX", "SayAvailable", [sayAvailableButton state] ? "true": "false");
NXWriteDefault ("FIX", "SayPath", [sayPathField stringValue] ?
[sayPathField stringValue] : "");
NXWriteDefault ("FIX", "SoundPath", [soundPathField stringValue] ?
[soundPathField stringValue] : "");
NXWriteDefault ("FIX", "SndplayPath", [sndplayPathField stringValue] ?
[sndplayPathField stringValue] : "");
return self;
}
- revertDefaults:sender
{
const char * sayAvailable;
const char * sayPath;
const char * soundPath;
const char * sndplayPath;
sayAvailable = NXGetDefaultValue ("FIX", "SayAvailable");
if (sayAvailable == NULL || !*sayAvailable ||
strcmp (sayAvailable, "true") != 0)
[sayAvailableButton setState:NO];
else
[sayAvailableButton setState:YES];
sayPath = NXGetDefaultValue ("FIX", "SayPath");
if (sayPath == NULL || !*sayPath)
[sayPathField setStringValue:""];
else
[sayPathField setStringValue:sayPath];
soundPath = NXGetDefaultValue ("FIX", "SoundPath");
if (soundPath == NULL || !*soundPath)
[soundPathField setStringValue:""];
else
[soundPathField setStringValue:soundPath];
sndplayPath = NXGetDefaultValue ("FIX", "SndplayPath");
if (sndplayPath == NULL || !*sndplayPath)
[sndplayPathField setStringValue:""];
else
[sndplayPathField setStringValue:sndplayPath];
return self;
}
- setKey:(const char *)key toValue:(const char *)value inStringTable:table
{
[table insertKey:NXUniqueString(key) value:(char *)NXUniqueString(value)];
return self;
}
- setNextCommand:(command *)command
{
nextCommand = command;
if (nextCommand != NULL)
[programText setSel:nextCommand->startPosition :nextCommand->endPosition];
else
[programText setSel:0 :0];
return self;
}
- analyseConstantLine:(const char *)line
{
char name [80];
char * blankPtr;
blankPtr = index (line, ' ');
if (blankPtr == NULL) {
[self setMessage:[translation valueForStringKey:
"Feste Daten mössen im Format <name> <wert> sein!"]];
return NULL;
}
strncpy (name, line, blankPtr - line);
name[blankPtr - line] = '\0';
[self setKey:name toValue:blankPtr + 1 inStringTable:constants];
return self;
}
- addCommand:(commandCode)code label:(char *)label argument:(char *)arg
start:(int)start end:(int)end
{
command * c, * n;
c = malloc (sizeof (command));
c->succ = NULL;
c->startPosition = start;
c->endPosition = end;
strcpy (c->label, label);
c->code = code;
strcpy (c->argument, arg);
if (commands == NULL)
commands = c;
else {
n = commands;
while (n->succ != NULL)
n = n->succ;
n->succ = c;
}
return self;
}
- missingArgument:(char *)arg inCommand:(char *)command
{
char buffer[256];
sprintf (buffer, [translation valueForStringKey:
"Der Befehl %s braucht %s als Argument."], command,
[translation valueForStringKey:arg]);
[self setMessage:buffer];
return self;
}
- analyseProgramLine:(const char *)line start:(int)start end:(int)end
{
char label [80];
char name [80];
char argument [256];
char * firstBlankPtr;
char * secondBlankPtr;
BOOL hasArgument;
if (line[0] == ' ')
while (line[1] == ' ')
line++;
firstBlankPtr = index (line, ' ');
if (firstBlankPtr == NULL) {
[self setMessage:[translation valueForStringKey:
"Programmzeilen mössen im Format <nummer> <befehl> <argument> sein!"]];
return NULL;
}
strncpy (label, line, firstBlankPtr - line);
label[firstBlankPtr - line] = '\0';
secondBlankPtr = index (firstBlankPtr + 1, ' ');
if (secondBlankPtr == NULL) {
hasArgument = NO;
strcpy (name, firstBlankPtr + 1);
strcpy (argument, "");
}
else {
hasArgument = YES;
strncpy (name, firstBlankPtr + 1, secondBlankPtr - firstBlankPtr - 1);
name[secondBlankPtr - firstBlankPtr - 1] = '\0';
strcpy (argument, secondBlankPtr + 1);
}
if (strcasecmp (name, "L") == 0) {
if (!hasArgument) {
[self missingArgument:"eine Datenadresse" inCommand:"L"];
return NULL;
}
[self addCommand:C_L label:label argument:argument start:start end:end];
[self addVariableOrConstOrDirectValue:argument];
}
if (strcasecmp (name, "S") == 0) {
if (!hasArgument) {
[self missingArgument:"eine Datenadresse" inCommand:"B"];
return NULL;
}
[self addCommand:C_S label:label argument:argument start:start end:end];
if (![self addVariable:argument]) {
[self setMessage:[translation valueForStringKey:
"Du kannst keinen festen Wert in einem S-Befehl verwenden"]];
return NULL;
}
}
if (strcasecmp (name, "D") == 0) {
if (!hasArgument) {
[self missingArgument:"einen Wert" inCommand:"D"];
return NULL;
}
[self addCommand:C_D label:label argument:argument start:start end:end];
}
if (strcasecmp (name, "GO") == 0) {
if (!hasArgument) {
[self missingArgument:"eine Befehlsadresse" inCommand:"GO"];
return NULL;
}
[self addCommand:C_GO label:label argument:argument start:start end:end];
}
if (strcasecmp (name, "IF") == 0) {
if (!hasArgument) {
[self missingArgument:"eine Datenadresse" inCommand:"IF"];
return NULL;
}
[self addCommand:C_IF label:label argument:argument start:start end:end];
[self addVariableOrConstOrDirectValue:argument];
}
if (strcasecmp (name, "TH") == 0) {
if (!hasArgument) {
[self missingArgument:"eine Befehlsadresse" inCommand:"TH"];
return NULL;
}
[self addCommand:C_TH label:label argument:argument start:start end:end];
}
if (strcasecmp (name, "EL") == 0) {
if (!hasArgument) {
[self missingArgument:"eine Befehlsadresse" inCommand:"EL"];
return NULL;
}
[self addCommand:C_EL label:label argument:argument start:start end:end];
}
if (strcasecmp (name, "E") == 0) {
if (!hasArgument)
[self addCommand:C_E label:label argument:"" start:start end:end];
else {
[self addCommand:C_E label:label argument:argument start:start end:end];
if (![self addVariable:argument]) {
[self setMessage:[translation valueForStringKey:
"Du kannst keinen festen Wert in einem E-Befehl verwenden"]];
return NULL;
}
}
}
if (strcasecmp (name, "A") == 0) {
if (!hasArgument)
[self addCommand:C_A label:label argument:"" start:start end:end];
else {
[self addCommand:C_A label:label argument:argument start:start end:end];
[self addVariableOrConstOrDirectValue:argument];
}
}
if (strcmp (name, "+") == 0) {
if (!hasArgument) {
[self missingArgument:"eine Datenadresse" inCommand:"+"];
return NULL;
}
[self addCommand:C_PLUS label:label argument:argument
start:start end:end];
[self addVariableOrConstOrDirectValue:argument];
}
if (strcmp (name, "-") == 0) {
if (!hasArgument) {
[self missingArgument:"eine Datenadresse" inCommand:"-"];
return NULL;
}
[self addCommand:C_MINUS label:label argument:argument
start:start end:end];
[self addVariableOrConstOrDirectValue:argument];
}
if (strcmp (name, "*") == 0) {
if (!hasArgument) {
[self missingArgument:"eine Datenadresse" inCommand:"*"];
return NULL;
}
[self addCommand:C_MUL label:label argument:argument
start:start end:end];
[self addVariableOrConstOrDirectValue:argument];
}
if (strcmp (name, "/") == 0) {
if (!hasArgument) {
[self missingArgument:"eine Datenadresse" inCommand:"/"];
return NULL;
}
[self addCommand:C_DIV label:label argument:argument
start:start end:end];
[self addVariableOrConstOrDirectValue:argument];
}
if (strcmp (name, "|") == 0) {
if (!hasArgument) {
[self missingArgument:"eine Datenadresse" inCommand:"|"];
return NULL;
}
[self addCommand:C_APP label:label argument:argument
start:start end:end];
[self addVariableOrConstOrDirectValue:argument];
}
if (strcasecmp (name, "P") == 0) {
if (!hasArgument) {
[self missingArgument:"einen Wert" inCommand:"P"];
return NULL;
}
[self addCommand:C_P label:label argument:argument start:start end:end];
}
if (strcasecmp (name, "F") == 0) {
if (!hasArgument) {
[self missingArgument:"eine Frage" inCommand:"F"];
return NULL;
}
[self addCommand:C_F label:label argument:argument start:start end:end];
}
if (strcasecmp (name, "I") == 0) {
if (!hasArgument) {
[self missingArgument:"eine Frage" inCommand:"I"];
return NULL;
}
[self addCommand:C_I label:label argument:argument start:start end:end];
}
if (strcasecmp (name, "END") == 0) {
[self addCommand:C_END label:label argument:"" start:start end:end];
}
if (strcasecmp (name, "SAY") == 0) {
if (!hasArgument)
[self addCommand:C_SAY label:label argument:"" start:start end:end];
else {
[self addCommand:C_SAY label:label argument:argument start:start end:end];
[self addVariableOrConstOrDirectValue:argument];
}
}
if (strcasecmp (name, "PLAY") == 0) {
if (!hasArgument)
[self addCommand:C_PLAY label:label argument:"" start:start end:end];
else {
[self addCommand:C_PLAY label:label argument:argument start:start end:end];
[self addVariableOrConstOrDirectValue:argument];
}
}
if (strcasecmp (name, "ALERT") == 0) {
if (!hasArgument)
[self addCommand:C_ALERT label:label argument:"" start:start end:end];
else {
[self addCommand:C_ALERT label:label argument:argument start:start end:end];
[self addVariableOrConstOrDirectValue:argument];
}
}
if (strcasecmp (name, "") == 0 || strcasecmp (name, "NOP") == 0) {
[self addCommand:C_NOP label:label argument:"" start:start end:end];
}
return self;
}
- showVariables
{
NXHashState state;
char * key;
char * value;
char buffer [1024];
[variablesText setText:""];
[variablesText selectText:self];
state = [variables initState];
while ([variables nextState:&state key:(const void **)&key
value:(void **)&value]) {
sprintf (buffer, "%s %s\n", key, value);
[variablesText replaceSel:buffer];
}
return self;
}
- (command *)searchCommandWithLabel:(char *)label
{
command * n;
for (n = commands; n != NULL; n = n->succ)
if (strcasecmp (n->label, label) == 0)
return n;
return NULL;
}
- (const char *)getDirectValue:(const char *)name
{
static char buffer[256];
int len;
if (name != NULL && (len = strlen (name)) > 1 && *name == '"') {
// lets first copy the string without opening quote
len--;
strncpy (buffer, name+1, len);
// now lets remove spaces from the end
while (len > 0 && buffer[len - 1] == ' ')
len--;
// if len == 0, it was only one quote
// if buffer[len - 1] != '"', it is not terminated with a quote
if (len > 0 && buffer[len - 1] == '"') {
buffer[len - 1] = '\0';
return buffer;
}
}
return NULL;
}
- (const char *)getVarOrConstOrDirectValue:(const char *)name
{
const char * value;
if ((value = [self getDirectValue:name]) != NULL)
return value;
value = [constants valueForStringKey:name];
if (value == NULL)
value = [variables valueForStringKey:name];
return value;
}
- setVar:(const char *)name toValue:(const char *)value
{
char buffer[256];
if ([constants valueForStringKey:name] != NULL) {
sprintf (buffer, [translation valueForStringKey:
"Der feste Datenwert %s kann nicht öberschrieben werden"],
name);
[self setMessage:buffer];
return nil;
}
[self setKey:name toValue:value inStringTable:variables];
return self;
}
- addVariable:(const char *)name
{
if ([constants valueForStringKey:name] != NULL)
return nil;
[self setKey:name toValue:"0" inStringTable:variables];
return self;
}
- addVariableOrConstOrDirectValue:(const char *)name
{
if ([self getDirectValue:name] == NULL &&
[constants valueForStringKey:name] == NULL)
[self setKey:name toValue:"0" inStringTable:variables]; // its a variable
return self;
}
- findInputLine:(int)line start:(int *)start end:(int *)end
{
char buffer[2];
*start = [inputText positionFromLine:line];
if (*start == -1)
return nil;
*end = [inputText positionFromLine:line + 1];
if (*end == -1)
*end = [inputText textLength];
if (*start == *end)
return self;
if ([inputText getSubstring:buffer start:(*end) - 1 length:1] != 1)
return self;
if (buffer[0] == '\n')
(*end)--;
return self;
}
- unselectNextInputLine
{
int start, end;
char buffer [3];
[self findInputLine:nextInputLine start:&start end:&end];
if (start == -1)
return self;
if (end - start > 1 &&
[inputText getSubstring:buffer start:start length:2] == 2 &&
strncmp (buffer, "> ", 2) == 0) {
[inputText setSel:start :start + 2];
[inputText replaceSel:""];
}
return self;
}
- selectNextInputLine
{
int start, end;
[self findInputLine:nextInputLine start:&start end:&end];
if (start == -1)
return self;
[inputText setSel:start :start];
[inputText replaceSel:"> "];
return self;
}
- (const char *) input
{
int start, end;
static char buffer[256];
[self unselectNextInputLine];
[self findInputLine:nextInputLine start:&start end:&end];
if (start < end)
[inputText getSubstring:buffer start:start length:end - start];
buffer[end - start] = '\0';
nextInputLine++;
[self selectNextInputLine];
return buffer;
}
- output:(const char *)line
{
int end;
end = [outputText textLength];
[outputText setSel:end :end];
[outputText replaceSel:line];
[outputText replaceSel:"\n"];
[outputText setSel:end :[outputText textLength] - 1];
[outputText scrollSelToVisible];
return self;
}
- (const char *)askForValue:(const char *)question
{
[questionField setStringValue:question? question : ""];
[answerField setStringValue:""];
[answerField selectText:self];
cancelRequested = NO;
[questionPanel makeKeyAndOrderFront:self];
[NXApp runModalFor:questionPanel]; // returns with OK
[questionPanel orderOut:self];
if (cancelRequested)
return NULL;
return [answerField stringValue];
}
- answerOK:sender
{
cancelRequested = NO;
[NXApp stopModal];
return self;
}
- answerCancel:sender
{
cancelRequested = YES;
[NXApp stopModal];
return self;
}
- say:(const char *)value
{
char buffer [1000];
const char * sayAvailable;
const char * sayPath;
sayAvailable = NXGetDefaultValue ("FIX", "SayAvailable");
if (sayAvailable == NULL || !*sayAvailable || strcmp (sayAvailable, "true") != 0) {
NXBeep ();
return self;
}
sayPath = NXGetDefaultValue ("FIX", "SayPath");
if (sayPath == NULL || !*sayPath) {
NXBeep ();
return self;
}
if (value != NULL) {
sprintf (buffer, "%s %s", sayPath, value);
system (buffer);
}
return self;
}
- (BOOL)fileExists:(const char *)name
{
FILE * fp;
if ((fp = fopen (name, "r")) != NULL) {
fclose (fp);
return YES;
}
return NO;
}
- (const char *)findSoundFile:(const char *)name
{
static char buffer [1000];
const char * soundPath;
sprintf (buffer, "%s", name);
if ([self fileExists:buffer])
return buffer;
strcat (buffer, ".snd");
if ([self fileExists:buffer])
return buffer;
if (directory != NULL) {
sprintf (buffer, "%s/%s", directory, name);
if ([self fileExists:buffer])
return buffer;
strcat (buffer, ".snd");
if ([self fileExists:buffer])
return buffer;
}
soundPath = NXGetDefaultValue ("FIX", "SoundPath");
if (soundPath != NULL && *soundPath) {
sprintf (buffer, "%s/%s", soundPath, name);
if ([self fileExists:buffer])
return buffer;
}
strcat (buffer, ".snd");
if ([self fileExists:buffer])
return buffer;
return NULL;
}
- play:(const char *)name
{
char msgbuffer [1000];
char buffer [1000];
const char * file = NULL;
int code;
const char * sndplayPath;
const char * soundPath;
sndplayPath = NXGetDefaultValue ("FIX", "SndplayPath");
if (sndplayPath == NULL || !*sndplayPath) {
NXBeep ();
return self;
}
soundPath = NXGetDefaultValue ("FIX", "SoundPath");
if (soundPath != NULL && !*soundPath)
soundPath = NULL;
if ((file = [self findSoundFile:name]) == NULL) {
if (soundPath || directory) {
strcpy (msgbuffer, [translation valueForStringKey:"Habe auch in "]);
if (soundPath) {
strcat (msgbuffer, soundPath);
if (directory)
strcat (msgbuffer, [translation valueForStringKey:" und "]);
}
if (directory)
strcat (msgbuffer, directory);
strcat (msgbuffer, [translation valueForStringKey:" gesucht."]);
}
else
strcpy (msgbuffer, [translation valueForStringKey:"Es ist weder ein Sounddirectory in den Einstellungen angegeben noch ist die aktuelle Datei abgespeichert."]);
code = NXRunAlertPanel ("Play",
[translation valueForStringKey:
"Kann die Sounddatei %s nicht finden! %s"],
"OK", [translation valueForStringKey:"Abbrechen"],
NULL, name, msgbuffer);
if (code == NX_ALERTDEFAULT)
return self;
else
return nil;
}
if (file != NULL) {
sprintf (buffer, "%s %s", sndplayPath, file);
system (buffer);
}
return self;
}
- alert:(const char *)value
{
int code;
if (value == NULL)
value = "nix los!";
code = NXRunAlertPanel ([translation valueForStringKey:"FIX teilt mit:"],
value, "OK",
[translation valueForStringKey:"Abbrechen"], NULL);
if (code == NX_ALERTDEFAULT)
return self;
else
return nil;
}
- performNextCommand
{
command * next;
int ival;
char buffer [1024];
const char * answer;
int code;
id result;
if (nextCommand == NULL)
return self;
switch (nextCommand->code) {
case C_L: [accumulator setStringValue:
[self getVarOrConstOrDirectValue:nextCommand->argument]];
[self setNextCommand:nextCommand->succ];
break;
case C_S: [self setVar:nextCommand->argument
toValue:[accumulator stringValue]];
[self showVariables];
[self setNextCommand:nextCommand->succ];
break;
case C_D: [accumulator setStringValue:nextCommand->argument];
[self setNextCommand:nextCommand->succ];
break;
case C_GO: next = [self searchCommandWithLabel:nextCommand->argument];
if (next == NULL) {
[self setMessage:
[translation valueForStringKey:"Unbekanntes Sprungziel"]];
return nil;
}
[self setNextCommand:next];
break;
case C_IF: if (strcasecmp ([accumulator stringValue],
[self getVarOrConstOrDirectValue:nextCommand->argument]) == 0)
[testResult setState:1];
else
[testResult setState:0];
[self setNextCommand:nextCommand->succ];
break;
case C_TH: next = [self searchCommandWithLabel:nextCommand->argument];
if (next == NULL) {
[self setMessage:
[translation valueForStringKey:"Unbekanntes Sprungziel"]];
return nil;
}
if ([testResult state] != 0)
[self setNextCommand:next];
else
[self setNextCommand:nextCommand->succ];
break;
case C_EL: next = [self searchCommandWithLabel:nextCommand->argument];
if (next == NULL) {
[self setMessage:
[translation valueForStringKey:"Unbekanntes Sprungziel"]];
return nil;
}
if ([testResult state] != 0)
[self setNextCommand:nextCommand->succ];
else
[self setNextCommand:next];
break;
case C_E: if (nextCommand->argument[0] == '\0')
[accumulator setStringValue:[self input]];
else {
[self setVar:nextCommand->argument toValue:[self input]];
[self showVariables];
}
[self setNextCommand:nextCommand->succ];
break;
case C_A: if (nextCommand->argument[0] == '\0')
[self output:[accumulator stringValue]];
else
[self output:[self getVarOrConstOrDirectValue:nextCommand->argument]];
[self setNextCommand:nextCommand->succ];
break;
case C_P: [self output:nextCommand->argument];
[self setNextCommand:nextCommand->succ];
break;
case C_F: code = NXRunAlertPanel ([translation valueForStringKey:"FIX fragt:"],
nextCommand->argument,
[translation valueForStringKey:"Nein"],
[translation valueForStringKey:"Ja"],
[translation valueForStringKey:"Abbrechen"]);
switch (code) {
case NX_ALERTDEFAULT: [testResult setState:0];
[self setNextCommand:nextCommand->succ];
break;
case NX_ALERTALTERNATE: [testResult setState:1];
[self setNextCommand:nextCommand->succ];
break;
case NX_ALERTOTHER: [self setNextCommand:NULL];
break;
}
break;
case C_I: if ((answer = [self askForValue:nextCommand->argument]) == NULL) {
[self setNextCommand:NULL];
break;
}
[accumulator setStringValue:answer];
[self setNextCommand:nextCommand->succ];
break;
case C_PLUS:ival = atoi ([self getVarOrConstOrDirectValue:nextCommand->argument]);
[accumulator setIntValue:[accumulator intValue] + ival];
[self setNextCommand:nextCommand->succ];
break;
case C_MINUS:ival = atoi ([self getVarOrConstOrDirectValue:nextCommand->argument]);
[accumulator setIntValue:[accumulator intValue] - ival];
[self setNextCommand:nextCommand->succ];
break;
case C_MUL: ival = atoi ([self getVarOrConstOrDirectValue:nextCommand->argument]);
[accumulator setIntValue:[accumulator intValue] * ival];
[self setNextCommand:nextCommand->succ];
break;
case C_DIV: ival = atoi ([self getVarOrConstOrDirectValue:nextCommand->argument]);
if (ival == 0) {
[self setMessage:
[translation valueForStringKey:"Division durch Null"]];
return nil;
}
[accumulator setIntValue:[accumulator intValue] / ival];
[self setNextCommand:nextCommand->succ];
break;
case C_APP: sprintf (buffer, "%s%s", [accumulator stringValue],
[self getVarOrConstOrDirectValue:nextCommand->argument]);
[accumulator setStringValue:buffer];
[self setNextCommand:nextCommand->succ];
break;
case C_NOP: [self setNextCommand:nextCommand->succ];
break;
case C_END: [self setNextCommand:NULL];
break;
case C_SAY: if (nextCommand->argument[0] == '\0')
[self say:[accumulator stringValue]];
else
[self say:[self getVarOrConstOrDirectValue:nextCommand->argument]];
[self setNextCommand:nextCommand->succ];
break;
case C_PLAY:
if (nextCommand->argument[0] == '\0')
result = [self play:[accumulator stringValue]];
else
result = [self play:[self getVarOrConstOrDirectValue:nextCommand->argument]];
if (result)
[self setNextCommand:nextCommand->succ];
else
[self setNextCommand:NULL];
break;
case C_ALERT:
if (nextCommand->argument[0] == '\0')
result = [self alert:[accumulator stringValue]];
else
result = [self alert:[self getVarOrConstOrDirectValue:nextCommand->argument]];
if (result)
[self setNextCommand:nextCommand->succ];
else
[self setNextCommand:NULL];
break;
default: [self setMessage:
[translation valueForStringKey:"Unbekannter Kommandocode"]];
return nil;
}
return self;
}
- reset:sender
{
NXStream * stream;
char buffer[1024];
char * p;
int c;
int position, start;
command * comm, * next;
[constants empty];
[variables empty];
[self unselectNextInputLine];
// read and analyse constant lines
stream = [constantsText stream];
NXSeek (stream, 0L, NX_FROMSTART);
position = 0;
while (1) {
start = position;
p = buffer;
while ((c = NXGetc (stream)) != '\n' && c != EOF) {
position++;
*p++ = c;
}
*p = '\0';
if (p - buffer > 0)
if (![self analyseConstantLine:buffer]) {
[constantsText setSel:start :position];
return self;
}
position++;
if (c == EOF)
break;
}
// free commands
comm = commands;
while (comm != NULL) {
next = comm->succ;
free (comm);
comm = next;
}
commands = NULL;
// read and analyse program lines
stream = [programText stream];
NXSeek (stream, 0L, NX_FROMSTART);
position = 0;
while (1) {
start = position;
p = buffer;
while ((c = NXGetc (stream)) != '\n' && c != EOF) {
position++;
*p++ = c;
}
*p = '\0';
if (p - buffer > 0)
if (![self analyseProgramLine:buffer start:start end:position]) {
[programText setSel:start :position];
return self;
}
position++;
if (c == EOF)
break;
}
[self showVariables];
nextInputLine = 1;
[self selectNextInputLine];
[self setNextCommand:commands];
[outputText setText:""];
[accumulator setStringValue:"0"];
[self setMessage:""];
return self;
}
- step:sender
{
if (![self performNextCommand])
return nil;
if (nextCommand == NULL)
[self setMessage:[translation valueForStringKey:"Fertig!"]];
return self;
}
/*
- run:sender
{
int count;
count = 0;
while (nextCommand != NULL) {
if (++count > 1000) // cycling control
break;
if ([self step:sender] == nil)
break;
}
return self;
}
*/
- run:sender
{
id result;
if (nextCommand == NULL)
return self;
result = [self step:sender];
if (result == nil)
return self;
[self perform:@selector(run:) with:sender afterDelay:50 cancelPrevious:YES];
return self;
}
- stop:sender
{
[self perform:@selector(run:) with:sender afterDelay:-1 cancelPrevious:YES];
return self;
}
- toggleProgramVisibility:sender
{
if ([sender state]) { // on is invisible
[programText setBackgroundGray:NX_DKGRAY];
[programText setTextGray:NX_DKGRAY];
[constantsText setBackgroundGray:NX_DKGRAY];
[constantsText setTextGray:NX_DKGRAY];
[variablesText setBackgroundGray:NX_DKGRAY];
[variablesText setTextGray:NX_DKGRAY];
}
else {
[programText setBackgroundGray:NX_WHITE];
[programText setTextGray:NX_BLACK];
[constantsText setBackgroundGray:NX_WHITE];
[constantsText setTextGray:NX_BLACK];
[variablesText setBackgroundGray:NX_LTGRAY];
[variablesText setTextGray:NX_BLACK];
}
[programText update];
[constantsText update];
[variablesText update];
return self;
}
- setMessage:(const char *)msg
{
[programText scrollSelToVisible];
[messageText setStringValue:msg];
return self;
}
- save:sender
{
id savePanel;
int tag;
NXStream * stream;
if (directory == NULL)
directory = NXCopyStringBuffer ("~/Library/FIX");
if (filename == NULL)
filename = NXCopyStringBuffer ([translation valueForStringKey:"OHNE_NAMEN.fix"]);
savePanel = [SavePanel new];
[savePanel setTitle:[translation valueForStringKey:"FIX Abspeichern"]];
[savePanel setRequiredFileType:"fix"];
tag = [savePanel runModalForDirectory:directory file:filename];
[savePanel setTitle:[translation valueForStringKey:"Save"]];
if (tag == NX_OKTAG) {
free (directory);
directory = NXCopyStringBuffer ([savePanel directory]);
free (filename);
filename = NXCopyStringBuffer (rindex ([savePanel filename], '/') + 1);
stream = NXOpenMemory (NULL, 0, NX_WRITEONLY);
NXPrintf (stream, "Programm: %d\n", [programText byteLength]);
[programText writeText:stream];
NXPrintf (stream, "\nFeste Daten: %d\n", [constantsText byteLength]);
[constantsText writeText:stream];
[self unselectNextInputLine];
NXPrintf (stream, "\nEingaben: %d\n", [inputText byteLength]);
[inputText writeText:stream];
[self selectNextInputLine];
if (NXSaveToFile (stream, [savePanel filename]) == -1)
NXRunAlertPanel ([translation valueForStringKey:"Error"],
[translation valueForStringKey:"Kann die Datei %s leider nicht schreiben."],
NULL, NULL, NULL, [savePanel filename]);
NXCloseMemory (stream, NX_FREEBUFFER);
[[programText window] setTitleAsFilename:[savePanel filename]];
}
return self;
}
- restore:sender
{
id openPanel;
int tag;
NXStream * stream;
static const char * fileType[2] = {"fix", NULL};
char * buffer;
int count;
openPanel = [[OpenPanel new] allowMultipleFiles:NO];
if (directory == NULL)
directory = NXCopyStringBuffer ("~/Library/FIX");
if (filename == NULL)
filename = NXCopyStringBuffer ("");
tag = [openPanel runModalForDirectory:directory
file:filename types:fileType];
if (tag == NX_OKTAG) {
free (directory);
directory = NXCopyStringBuffer ([openPanel directory]);
free (filename);
filename = NXCopyStringBuffer (rindex ([openPanel filename], '/') + 1);
stream = NXMapFile ([openPanel filename], NX_READONLY);
if (stream == NULL)
return self;
count = 0;
NXScanf (stream, "Programm: %d", &count);
if (count == 0)
[programText setText:""];
else {
buffer = malloc (count + 2);
if (NXRead (stream, buffer, count + 1) != count + 1)
return self;
buffer[count + 1] = '\0';
[programText setText:buffer + 1];
free (buffer);
}
count = 0;
NXScanf (stream, "\nFeste Daten: %d", &count);
if (count == 0)
[constantsText setText:""];
else {
buffer = malloc (count + 2);
if (NXRead (stream, buffer, count + 1) != count + 1)
return self;
buffer[count + 1] = '\0';
[constantsText setText:buffer + 1];
free (buffer);
}
count = 0;
NXScanf (stream, "\nEingaben: %d", &count);
if (count == 0)
[inputText setText:""];
else {
buffer = malloc (count + 2);
if (NXRead (stream, buffer, count + 1) != count + 1)
return self;
buffer[count + 1] = '\0';
[inputText setText:buffer + 1];
free (buffer);
}
NXCloseMemory (stream, NX_FREEBUFFER);
[[programText window] setTitleAsFilename:[openPanel filename]];
}
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.