scummvm/engines/glk/jacl/interpreter.cpp
D G Turner f13ea97bad GLK: JACL: Fix Missing Default Switch Cases
These are flagged by GCC if -Wswitch-default is enabled.
2019-12-16 02:44:00 +00:00

3462 lines
102 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "glk/jacl/jacl.h"
#include "glk/jacl/language.h"
#include "glk/jacl/types.h"
#include "glk/jacl/prototypes.h"
#include "glk/jacl/csv.h"
#include "common/str.h"
namespace Glk {
namespace JACL {
struct flock {
short l_type;
short l_whence;
long l_start;
long l_len;
long l_pid;
};
#define F_DUPFD 0
#define F_GETFD 1
#define F_SETFD 2
#define F_GETFL 3
#define F_SETFL 4
#define F_GETLK 5
#define F_SETLK 6
#define F_SETLKW 7
#define F_RDLCK 0
#define F_WRLCK 1
#define F_UNLCK 2
int fcntl(int __fd, int __cmd, ...) {
return 0;
}
#ifndef strcasestr
const char *strcasestr(const char *s, const char *find) {
char c, sc;
size_t len;
if ((c = *find++) != 0) {
c = (char)tolower((unsigned char)c);
len = strlen(find);
do {
do {
if ((sc = *s++) == 0)
return (NULL);
} while ((char)tolower((unsigned char)sc) != c);
} while (scumm_strnicmp(s, find, len) != 0);
s--;
}
return s;
}
#endif
#define MAX_TRY 10
flock read_lck;
int read_fd;
flock write_lck;
int write_fd;
char *url_encode(char *str);
char to_hex(char code);
const char *location_attributes[] = {
"VISITED ", "DARK ", "ON_WATER ", "UNDER_WATER ", "WITHOUT_AIR ", "OUTDOORS ",
"MID_AIR ", "TIGHT_ROPE ", "POLLUTED ", "SOLVED ", "MID_WATER ", "DARKNESS ",
"MAPPED ", "KNOWN ",
NULL
};
const char *object_attributes[] = {
"CLOSED ", "LOCKED ", "DEAD ", "IGNITABLE ", "WORN ", "CONCEALING ",
"LUMINOUS ", "WEARABLE ", "CLOSABLE ", "LOCKABLE ", "ANIMATE ", "LIQUID ",
"CONTAINER ", "SURFACE ", "PLURAL ", "FLAMMABLE ", "BURNING ", "LOCATION ",
"ON ", "DAMAGED ", "FEMALE ", "POSSESSIVE ", "OUT_OF_REACH ", "TOUCHED ",
"SCORED ", "SITTING ", "NPC ", "DONE ", "GAS ", "NO_TAB ",
"NOT_IMPORTANT ", NULL
};
const char *object_elements[] = {
"parent", "capacity", "mass", "bearing", "velocity", "next", "previous",
"child", "index", "status", "state", "counter", "points", "class", "x", "y",
NULL
};
const char *location_elements[] = {
"north", "south", "east", "west", "northeast", "northwest", "southeast",
"southwest", "up", "down", "in", "out", "points", "class", "x", "y",
NULL
};
struct csv_parser parser_csv;
char in_name[1024];
char out_name[1024];
Common::SeekableReadStream *infile;
Common::WriteStream *outfile;
int stack = 0;
int proxy_stack = 0;
int field_no = 0;
struct stack_type backup[STACK_SIZE];
struct proxy_type proxy_backup[STACK_SIZE];
struct function_type *resolved_function = NULL;
struct string_type *resolved_string = NULL;
struct string_type *new_string = NULL;
struct string_type *current_cstring = NULL;
struct string_type *previous_cstring = NULL;
struct cinteger_type *new_cinteger = NULL;
struct cinteger_type *current_cinteger = NULL;
struct cinteger_type *previous_cinteger = NULL;
long bit_mask;
extern int encrypted;
extern int after_from;
extern int last_exact;
extern char temp_directory[];
extern char data_directory[];
char csv_buffer[1024];
int resolved_attribute;
/* THE ITERATION VARIABLE USED FOR LOOPS */
int *loop_integer = NULL;
int *select_integer = NULL;
int criterion_value = 0;
int criterion_type = 0;
int criterion_negate = FALSE;
int current_level;
int execution_level;
int *ask_integer;
int new_x;
int new_y;
int interrupted = FALSE;
char string_buffer[2048];
char argument_buffer[1024];
#ifdef GLK
extern schanid_t sound_channel[];
extern strid_t game_stream;
extern winid_t mainwin;
extern winid_t statuswin;
extern winid_t current_window;
extern strid_t mainstr;
extern strid_t statusstr;
extern strid_t quotestr;
extern strid_t inputstr;
int top_of_loop = 0;
int top_of_select = 0;
int top_of_while = 0;
int top_of_iterate = 0;
int top_of_update = 0;
int top_of_do_loop = 0;
#else
extern FILE *file;
char option_buffer[2024];
int style_stack[100];
int style_index = 0;
long top_of_loop = 0;
long top_of_select = 0;
long top_of_while = 0;
long top_of_iterate = 0;
long top_of_update = 0;
long top_of_do_loop = 0;
#endif
#ifdef __NDS__
extern int bold_mode;
extern int pre_mode;
extern int reverse_mode;
extern int input_mode;
extern int subheader_mode;
extern int note_mode;
#endif
extern char user_id[];
extern char prefix[];
extern char text_buffer[];
extern char chunk_buffer[];
extern const char *word[];
extern char bookmark[];
extern char file_prompt[];
/* CONTAINED IN PARSER.C */
extern int object_list[4][MAX_OBJECTS];
extern int list_size[];
extern int max_size[];
/* CONTAINED IN ENCAPSULATE.C */
extern int quoted[];
extern struct object_type *object[];
extern struct integer_type *integer_table;
extern struct integer_type *integer[];
extern struct cinteger_type *cinteger_table;
extern struct attribute_type *attribute_table;
extern struct string_type *string_table;
extern struct string_type *cstring_table;
extern struct function_type *function_table;
extern struct function_type *executing_function;
extern struct command_type *completion_list;
extern struct word_type *grammar_table;
extern struct synonym_type *synonym_table;
extern struct filter_type *filter_table;
extern char function_name[];
extern char temp_buffer[];
extern char error_buffer[];
extern char proxy_buffer[];
extern char default_function[];
extern char override_[];
extern int noun[];
extern int wp;
extern int start_of_this_command;
extern int start_of_last_command;
extern int buffer_index;
extern int objects;
extern int integers;
extern int player;
extern int oec;
extern int *object_element_address;
extern int *object_backup_address;
extern int walkthru_running;
// VALUES FROM LOADER
extern int value_resolved;
extern Common::WriteStream *transcript;
extern char margin_string[];
char integer_buffer[16];
char called_name[1024];
char scope_criterion[24];
const char *output;
void terminate(int code) {
// FREE ANY EXTRA RAM ALLOCATED BY THE CSV PARSER
csv_free(&parser_csv);
#ifdef GLK
int index;
event_t event;
// FLUSH THE GLK WINDOW SO THE ERROR GETS DISPLAYED IMMEDIATELY.
g_vm->glk_select_poll(&event);
/* CLOSE THE SOUND CHANNELS */
for (index = 0; index < 8; index++) {
if (sound_channel[index] != NULL) {
g_vm->glk_schannel_destroy(sound_channel[index]);
}
}
/* CLOSE THE STREAM */
if (game_stream != NULL) {
g_vm->glk_stream_close(game_stream, NULL);
}
g_vm->glk_exit();
#else
if (file != NULL) /* CLOSE THE GAME FILE */
fclose(file);
exit(code);
#endif
}
void build_proxy() {
int index;
proxy_buffer[0] = 0;
/* LOOP THROUGH ALL THE PARAMETERS OF THE PROXY COMMAND
AND BUILD THE MOVE TO BE ISSUED ON THE PLAYER'S BEHALF */
for (index = 1; word[index] != NULL; index++) {
strcat(proxy_buffer, text_of_word(index));
}
for (index = 0; index < (int)strlen(proxy_buffer); index++) {
if (proxy_buffer[index] == '~') {
proxy_buffer[index] = '\"';
}
}
//printf("--- proxy buffer = \"%s\"\n", proxy_buffer);
}
void cb1(void *s, size_t i, void *not_used) {
struct string_type *resolved_cstring;
//sprintf (temp_buffer, "Trying to set field %d to equal %s^", field_no, (const char *) s);
//write_text(temp_buffer);
sprintf(temp_buffer, "field[%d]", field_no);
if ((resolved_cstring = cstring_resolve(temp_buffer)) != NULL) {
//write_text("Resolved ");
//write_text(temp_buffer);
//write_text("^");
strncpy(resolved_cstring->value, (const char *)s, i);
resolved_cstring->value[i] = 0;
//sprintf(temp_buffer, "Setting field %d to ~%s~^", field_no, (const char *) s);
//write_text(temp_buffer);
// INCREMENT THE FIELD NUMBER SO THE NEXT ONE GETS STORED IN THE RIGHT CONSTANT
field_no++;
} else {
write_text("Can't resolve ");
write_text(temp_buffer);
write_text("^");
}
}
void cb2(int c, void *not_used) {
// THE END OF THE RECORD HAS BEEN REACHED, EXPORT THE NUMBER OF FIELDS READ
struct cinteger_type *resolved_cinteger;
if ((resolved_cinteger = cinteger_resolve("field_count")) != NULL) {
resolved_cinteger->value = field_no;
}
}
int execute(const char *funcname) {
int index;
int counter;
int *container;
int object_1,
object_2;
if (g_vm->shouldQuit())
return 0;
/* THESE VARIABLE KEEP TRACK OF if AND endif COMMANDS TO DECIDE WHETHER
*THE CURRENT LINE OF CODE SHOULD BE EXECUTED OR NOT */
int currentLevel = 0;
int executionLevel = 0;
/* THESE ARE USED AS FILE POINTER OFFSETS TO RETURN TO FIXED
* POINTS IN THE GAME FILE */
#ifdef GLK
int before_command = 0;
#else
long before_command = 0;
#endif
strncpy(called_name, funcname, 1023);
/* GET THE FUNCTION OBJECT BY THE FUNCTION NAME */
resolved_function = function_resolve(called_name);
if (resolved_function == NULL) {
//printf("--- failed to find %s\n", called_name);
return (FALSE);
}
#ifdef GLK
push_stack(g_vm->glk_stream_get_position(game_stream));
if (g_vm->shouldQuit())
return FALSE;
#else
push_stack(ftell(file));
#endif
top_of_loop = 0;
top_of_select = 0;
top_of_while = 0;
top_of_iterate = 0;
top_of_update = 0;
top_of_do_loop = 0;
executing_function = resolved_function;
executing_function->call_count++;
// CREATE ALL THE PASSED ARGUMENTS AS JACL INTEGER CONSTANTS
set_arguments(called_name);
// SET function_name TO THE CORE NAME STORED IN THE FUNCTION OBJECT
// LEAVING called_name TO CONTAIN THE FULL ARGUMENT LIST
strncpy(function_name, executing_function->name, 80);
strncpy(cstring_resolve("function_name")->value, executing_function->name, 80);
//sprintf(temp_buffer, "--- starting to execute %s^", function_name);
//write_text(temp_buffer);
// JUMP TO THE POINT IN THE PROCESSED GAME FILE WHERE THIS FUNCTION STARTS
#ifdef GLK
g_vm->glk_stream_set_position(game_stream, executing_function->position, seekmode_Start);
before_command = executing_function->position;
(void)glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
fseek(file, executing_function->position, SEEK_SET);
before_command = executing_function->position;
fgets(text_buffer, 1024, file);
#endif
if (encrypted) jacl_decrypt(text_buffer);
while (text_buffer[0] != 125 && !interrupted) {
encapsulate();
if (word[0] == NULL);
else if (!strcmp(word[0], "endwhile")) {
currentLevel--;
if (currentLevel < executionLevel) {
// THIS ENDWHILE COMMAND WAS BEING EXECUTED,
// NOT JUST COUNTED.
if (top_of_while == FALSE) {
sprintf(error_buffer, NO_WHILE, executing_function->name);
log_error(error_buffer, PLUS_STDOUT);
} else {
#ifdef GLK
g_vm->glk_stream_set_position(game_stream, top_of_while, seekmode_Start);
#else
fseek(file, top_of_while, SEEK_SET);
#endif
executionLevel = currentLevel;
}
}
} else if (!strcmp(word[0], "enditerate")) {
currentLevel--;
if (currentLevel < executionLevel) {
// THIS ENDITERATE COMMAND WAS BEING EXECUTED,
// NOT JUST COUNTED.
if (top_of_iterate == FALSE) {
sprintf(error_buffer, NO_ITERATE, executing_function->name);
log_error(error_buffer, PLUS_STDOUT);
} else {
#ifdef GLK
g_vm->glk_stream_set_position(game_stream, top_of_iterate, seekmode_Start);
#else
fseek(file, top_of_iterate, SEEK_SET);
#endif
executionLevel = currentLevel;
}
}
} else if (!strcmp(word[0], "endupdate")) {
currentLevel--;
if (currentLevel < executionLevel) {
// THIS ENDUPDATE COMMAND WAS BEING EXECUTED,
// NOT JUST COUNTED.
if (top_of_update == FALSE) {
sprintf(error_buffer, NO_UPDATE, executing_function->name);
log_error(error_buffer, PLUS_STDOUT);
} else {
#ifdef GLK
g_vm->glk_stream_set_position(game_stream, top_of_update, seekmode_Start);
#else
fseek(file, top_of_update, SEEK_SET);
#endif
executionLevel = currentLevel;
}
}
} else if (!strcmp(word[0], "print") && currentLevel != executionLevel) {
// SKIP THIS BLOCK OF PLAIN TEXT UNTIL IT FINDS A
// LINE THAT STARTS WITH A '.' OR A '}'
#ifdef GLK
(void)glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
fgets(text_buffer, 1024, file);
#endif
if (encrypted) jacl_decrypt(text_buffer);
while (text_buffer[0] != '.') {
if (text_buffer[0] == '}') {
// HIT THE END OF THE FUNCTION, JUST BAIL OUT
return (exit_function(TRUE));
}
// GET THE NEXT LINE
#ifdef GLK
(void)glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
fgets(text_buffer, 1024, file);
#endif
if (encrypted) jacl_decrypt(text_buffer);
}
} else if (!strcmp(word[0], "endif")) {
currentLevel--;
if (currentLevel < executionLevel) {
/* THIS SHOULD NEVER HAPPEN */
executionLevel = currentLevel;
}
} else if (!strcmp(word[0], "endall")) {
currentLevel = 0;
executionLevel = 0;
} else if (!strcmp(word[0], "else")) {
if (currentLevel == executionLevel) {
executionLevel--;
} else if (currentLevel == executionLevel + 1) {
executionLevel++;
}
} else if (currentLevel == executionLevel) {
if (!strcmp(word[0], "look")) {
// THIS IS JUST HERE FOR BACKWARDS COMPATIBILITY
object[HERE]->attributes &= ~1L;
look_around();
} else if (!strcmp(word[0], "repeat")) {
#ifdef GLK
top_of_do_loop = g_vm->glk_stream_get_position(game_stream);
#else
top_of_do_loop = ftell(file);
#endif
} else if (!strcmp(word[0], "until")) {
if (word[3] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
if (top_of_do_loop == FALSE) {
sprintf(error_buffer, NO_REPEAT, executing_function->name);
log_error(error_buffer, PLUS_STDOUT);
} else if (!condition()) {
#ifdef GLK
g_vm->glk_stream_set_position(game_stream, top_of_do_loop, seekmode_Start);
#else
fseek(file, top_of_do_loop, SEEK_SET);
#endif
}
}
} else if (!strcmp(word[0], "untilall")) {
if (word[3] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
if (top_of_do_loop == FALSE) {
sprintf(error_buffer, NO_REPEAT, executing_function->name);
log_error(error_buffer, PLUS_STDOUT);
} else if (!and_condition()) {
#ifdef GLK
g_vm->glk_stream_set_position(game_stream, top_of_do_loop, seekmode_Start);
#else
fseek(file, top_of_do_loop, SEEK_SET);
#endif
}
}
} else if (!strcmp(word[0], "iterate")) {
int i;
// A NEW iterate LOOP MEANS STARTING BACK AT THE FIRST FIELD
field_no = 0;
currentLevel++;
/* THIS LOOP COMES BACK TO THE START OF THE LINE CURRENTLY
EXECUTING, NOT THE LINE AFTER */
top_of_iterate = before_command;
// infile REMAINS OPEN DURING THE ITERATION, ONLY NEEDS
// OPENING THE FIRST TIME
if (infile == NULL) {
strcpy(temp_buffer, data_directory);
strcat(temp_buffer, prefix);
strcat(temp_buffer, "-");
strcat(temp_buffer, text_of_word(1));
strcat(temp_buffer, ".csv");
infile = File::openForReading(temp_buffer);
if (word[2] != NULL && !strcmp(word[2], "skip_header")) {
assert(infile);
infile->read(csv_buffer, 1024);
}
}
if (infile == NULL) {
sprintf(error_buffer, "Failed to open file %s\n", temp_buffer);
log_error(error_buffer, LOG_ONLY);
infile = NULL;
} else {
if (word[1] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
// IF THERE IS ANOTHER RECORD TO READ FROM THE CSV FILE THEN
// SET THE field[] CONSTANTS AND INCREMENT THE executionLevel
infile->read(csv_buffer, 1024);
if (infile->pos() < infile->size()) {
i = strlen(csv_buffer);
//sprintf (temp_buffer, "Read ~%s~ with %d bytes.^", csv_buffer, i);
//write_text(temp_buffer);
if (csv_parse(&parser_csv, csv_buffer, i, cb1, cb2, (void *) NULL) != (uint)i) {
sprintf(error_buffer, "Error parsing file: %s\n", csv_strerror(csv_error(&parser_csv)));
log_error(error_buffer, PLUS_STDOUT);
delete infile;
infile = NULL;
} else {
// A LINE HAS BEEN SUCCESSFULLY READ, EXECUTE THE CONTENTS OF THE LOOP
executionLevel++;
}
} else {
delete infile;
infile = NULL;
}
}
}
} else if (!strcmp(word[0], "update")) {
int i;
// SET UP THE RECORD LOCKING STRUCTURE, THE ADDRESS OF WHICH
// IS PASSED TO THE fcntl() SYSTEM CALL
write_lck.l_type = F_WRLCK; // SETTING A WRITE LOCK
write_lck.l_whence = 0; // OFFSET l_start FROM BEGINNING OF FILE
write_lck.l_start = 0LL;
write_lck.l_len = 0LL; // UNTIL THE END OF THE FILE ADDRESS SPACE
read_lck.l_type = F_RDLCK; // SETTING A READ LOCK
read_lck.l_whence = 0; // OFFSET l_start FROM BEGINNING OF FILE
read_lck.l_start = 0LL;
read_lck.l_len = 0LL; // UNTIL THE END OF THE FILE ADDRESS SPACE
// A NEW iterate LOOP MEANS STARTING BACK AT THE FIRST FIELD
field_no = 0;
currentLevel++;
// THIS LOOP COMES BACK TO THE START OF THE LINE CURRENTLY
// EXECUTING, NOT THE LINE AFTER
top_of_update = before_command;
// infile REMAINS OPEN DURING THE ITERATION, ONLY NEEDS
// OPENING THE FIRST TIME
if (infile == NULL) {
strcpy(in_name, data_directory);
strcat(in_name, prefix);
strcat(in_name, "-");
strcat(in_name, text_of_word(1));
strcat(in_name, ".csv");
infile = File::openForReading(in_name);
}
if (outfile == NULL) {
// OPEN A TEMPORARY OUTPUT FILE TO WRITE THE MODIFICATIONS TO
strcpy(out_name, data_directory);
strcat(out_name, prefix);
strcat(out_name, "-");
strcat(out_name, text_of_word(1));
strcat(out_name, "-");
strcat(out_name, user_id);
strcat(out_name, ".csv");
outfile = File::openForWriting(out_name);
}
if (infile == NULL) {
sprintf(error_buffer, "Failed to open input CSV file ~%s\n", in_name);
log_error(error_buffer, LOG_ONLY);
if (outfile != NULL) {
delete outfile;
outfile = NULL;
}
return (exit_function(TRUE));
} else {
if (outfile == NULL) {
sprintf(error_buffer, "Failed to open output CSV file ~%s~\n", out_name);
log_error(error_buffer, LOG_ONLY);
if (infile != NULL) {
delete infile;
infile = NULL;
}
return (exit_function(TRUE));
} else {
#ifdef FILE_CTL
int tryCtr = 0;
write_fd = fileno(outfile);
// ATTEMPT LOCKING OUTPUT FILE MAX_TRY TIMES BEFORE GIVING UP.
while (fcntl(write_fd, F_SETLK, &write_lck) < 0) {
if (errno == EAGAIN || errno == EACCES) {
// THERE MIGHT BE OTHER ERROR CASES IN WHICH
// USERS MIGHT TRY AGAIN
if (++tryCtr < MAX_TRY) {
jacl_sleep(1000);
continue;
}
sprintf(error_buffer, "File busy unable to get lock on output file.\n");
log_error(error_buffer, PLUS_STDOUT);
return (exit_function(TRUE));
}
}
tryCtr = 0;
read_fd = fileno(infile);
// ATTEMPT LOCKING OUTPUT FILE MAX_TRY TIMES BEFORE GIVING UP.
while (fcntl(read_fd, F_SETLK, &read_lck) < 0) {
if (errno == EAGAIN || errno == EACCES) {
// THERE MIGHT BE OTHER ERROR CASES IN WHICH
// USERS MIGHT TRY AGAIN
if (++tryCtr < MAX_TRY) {
jacl_sleep(1000);
continue;
}
sprintf(error_buffer, "File busy unable to get lock on input file.\n");
log_error(error_buffer, PLUS_STDOUT);
return (exit_function(TRUE));
}
}
#endif
if (word[1] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
// IF THERE IS ANOTHER RECORD TO READ FROM THE CSV FILE THEN
// SET THE field[] CONSTANTS AND INCREMENT THE executionLevel
infile->read(csv_buffer, 1024);
if (infile->pos() < infile->size()) {
i = strlen(csv_buffer);
if (csv_parse(&parser_csv, csv_buffer, i, cb1, cb2, (int *) &field_no) != (uint)i) {
sprintf(error_buffer, "Error parsing file: %s\n", csv_strerror(csv_error(&parser_csv)));
log_error(error_buffer, PLUS_STDOUT);
read_lck.l_type = F_UNLCK; // SETTING A READ LOCK
fcntl(read_fd, F_SETLK, &read_lck);
delete infile;
infile = NULL;
} else {
// A LINE HAS BEEN SUCCESSFULLY READ, EXECUTE THE CONTENTS OF THE LOOP
executionLevel++;
}
} else {
write_lck.l_type = F_UNLCK; // REMOVE THE WRITE LOCK
fcntl(write_fd, F_SETLK, &write_lck);
delete outfile;
read_lck.l_type = F_UNLCK; // REMOVE THE READ LOCK
fcntl(read_fd, F_SETLK, &read_lck);
delete infile;
rename(out_name, in_name);
outfile = NULL;
infile = NULL;
}
}
}
}
} else if (!strcmp(word[0], "while")) {
currentLevel++;
/* THIS LOOP COMES BACK TO THE START OF THE LINE CURRENTLY
EXECUTING, NOT THE LINE AFTER */
top_of_while = before_command;
if (word[3] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else if (condition()) {
executionLevel++;
}
} else if (!strcmp(word[0], "whileall")) {
currentLevel++;
/* THIS LOOP COMES BACK TO THE START OF THE LINE CURRENTLY
EXECUTING, NOT THE LINE AFTER */
top_of_while = before_command;
if (word[3] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else if (and_condition()) {
executionLevel++;
}
} else if (!strcmp(word[0], "loop")) {
/* THE LOOP COMMAND LOOPS ONCE FOR EACH DEFINED
* OBJECT (FOREACH) */
#ifdef GLK
top_of_loop = g_vm->glk_stream_get_position(game_stream);
#else
top_of_loop = ftell(file);
#endif
if (word[1] == NULL) {
// IF NONE IS SUPPLIED DEFAULT TO noun3
loop_integer = &noun[2];
} else {
// STORE THE CONTAINER TO PUT THE CURRENT OBJECT IN
loop_integer = container_resolve(word[1]);
// IF THE SUPPLIED CONTAINER CAN'T BE RESOLVED
// DEFAULT TO noun3
if (loop_integer == NULL)
loop_integer = &noun[2];
}
// SET THE VALUE OF THE LOOP INDEX TO POINT TO THE FIRST OBJECT
*loop_integer = 1;
} else if (!strcmp(word[0], "endloop")) {
if (top_of_loop == FALSE) {
sprintf(error_buffer, NO_LOOP, executing_function->name);
log_error(error_buffer, PLUS_STDOUT);
} else {
*loop_integer += 1;
if (*loop_integer > objects) {
top_of_loop = FALSE;
*loop_integer = 0;
} else {
#ifdef GLK
g_vm->glk_stream_set_position(game_stream, top_of_loop, seekmode_Start);
#else
fseek(file, top_of_loop, SEEK_SET);
#endif
}
}
} else if (!strcmp(word[0], "select")) {
/* THE SELECT COMMAND LOOPS ONCE FOR EACH DEFINED
* OBJECT THAT MATCHES THE SUPPLIED CRITERION */
#ifdef GLK
top_of_select = g_vm->glk_stream_get_position(game_stream);
#else
top_of_select = ftell(file);
#endif
if (word[1] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else if (word[2] == NULL) {
// IF NONE IS SUPPLIED DEFAULT TO noun3
select_integer = &noun[2];
} else {
// STORE THE CONTAINER TO PUT THE CURRENT OBJECT IN
select_integer = container_resolve(word[2]);
// IF THE SUPPLIED CONTAINER CAN'T BE RESOLVED
// DEFAULT TO noun3
if (select_integer == NULL) {
select_integer = &noun[2];
}
}
// SET THE VALUE OF THE SELECT INDEX TO ONE BEFORE THE
// FIRST OBJECT. THE NEXT FUNCTION AUTOMATICALLY INCREMENTS
// THE INDEX BY ONE AT THE START OF THE WHILE LOOP.
*select_integer = 0;
if (word[1][0] == '!') {
criterion_negate = TRUE;
strcpy(argument_buffer, &word[1][1]);
} else {
criterion_negate = FALSE;
strcpy(argument_buffer, word[1]);
}
// DETERMINE THE CRITERION FOR SELETION
if (!strcmp(argument_buffer, "*held")
|| !strcmp(argument_buffer, "*here")
|| !strcmp(argument_buffer, "*anywhere")
|| !strcmp(argument_buffer, "*present")) {
criterion_type = CRI_SCOPE;
strncpy(scope_criterion, argument_buffer, 20);
} else if ((criterion_value = attribute_resolve(argument_buffer))) {
criterion_type = CRI_ATTRIBUTE;
} else if ((criterion_value = user_attribute_resolve(argument_buffer))) {
criterion_type = CRI_USER_ATTRIBUTE;
} else {
// USE VALUE OF AS A CATCH ALL IF IT IS NOT AN ATTRIBUTE OR SCOPE
criterion_value = value_of(argument_buffer);
if (value_resolved) {
criterion_type = CRI_PARENT;
} else {
// CAN'T RESOLVE CRITERION
criterion_type = CRI_NONE;
}
}
if (criterion_type != CRI_NONE) {
if (select_next() == FALSE) {
*select_integer = 0;
top_of_select = 0;
}
} else {
*select_integer = 0;
}
if (*select_integer == 0) {
// THERE ARE NO MATCHING OBJECTS SO JUMP TO THE endselect
#ifdef GLK
(void)glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
fgets(text_buffer, 1024, file);
#endif
if (encrypted) jacl_decrypt(text_buffer);
while (text_buffer[0] != '}') {
encapsulate();
if (word[0] != NULL && !strcmp(word[0], "endselect")) {
break;
}
#ifdef GLK
(void)glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
fgets(text_buffer, 1024, file);
#endif
}
}
} else if (!strcmp(word[0], "endselect")) {
if (top_of_select == FALSE) {
sprintf(error_buffer, NO_LOOP, executing_function->name);
log_error(error_buffer, PLUS_STDOUT);
} else {
if (select_next(/* select_integer, criterion_type, criterion_value, scope_criterion */)) {
#ifdef GLK
g_vm->glk_stream_set_position(game_stream, top_of_select, seekmode_Start);
#else
fseek(file, top_of_select, SEEK_SET);
#endif
} else {
*select_integer = 0;
top_of_select = 0;
}
}
} else if (!strcmp(word[0], "break")) {
currentLevel++;
executionLevel--;
#ifdef GLK
} else if (!strcmp(word[0], "cursor")) {
if (word[2] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun(0);
return (exit_function(TRUE));
} else {
if (current_window == statuswin) {
g_vm->glk_window_move_cursor(statuswin, value_of(word[1], TRUE), value_of(word[2], TRUE));
} else {
log_error(BAD_CURSOR, PLUS_STDOUT);
}
}
} else if (!strcmp(word[0], "stop")) {
int channel;
if (SOUND_SUPPORTED->value) {
/* SET THE CHANNEL TO STOP, IF SUPPLIED */
if (word[1] == NULL) {
channel = 0;
} else {
channel = value_of(word[1], TRUE);
/* SANITY CHECK THE CHANNEL SELECTED */
if (channel < 0 || channel > 7) {
channel = 0;
}
}
g_vm->glk_schannel_stop(sound_channel[channel]);
}
} else if (!strcmp(word[0], "volume")) {
int channel, volume;
if (SOUND_SUPPORTED->value) {
/* SET THE CHANNEL TO STOP, IF SUPPLIED */
if (word[2] == NULL) {
channel = 0;
} else {
channel = value_of(word[2], TRUE);
/* SANITY CHECK THE CHANNEL SELECTED */
if (channel < 0 || channel > 7) {
channel = 0;
}
}
if (word[1] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
volume = value_of(word[1], TRUE);
/* SANITY CHECK THE CHANNEL SELECTED */
if (volume < 0) {
volume = 0;
}
if (volume > 100) {
volume = 100;
}
/* STORE A COPY OF THE CURRENT VOLUME FOR ACCESS
* FROM JACL CODE */
sprintf(temp_buffer, "volume[%d]", channel);
cinteger_resolve(temp_buffer)->value = volume;
/* NOW SCALE THE 0-100 VOLUME TO THE 0-65536 EXPECTED
* BY Glk */
volume = volume * 655;
/* SET THE VOLUME */
g_vm->glk_schannel_set_volume(sound_channel[channel], (glui32) volume);
}
}
} else if (!strcmp(word[0], "timer")) {
if (TIMER_SUPPORTED->value && TIMER_ENABLED->value) {
if (word[1] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
index = value_of(word[1], TRUE);
/* DON'T ALLOW NEGATIVE VALUES, BUT NO UPPER LIMIT */
if (index < 0) index = 0;
/* SET THE GLK TIMER */
g_vm->glk_request_timer_events((glui32) index);
/* EXPOSE THE CURRENT VALUE THROUGH A JACL CONSTANT
SO THAT GAME CODE CAN READ THE IT */
cinteger_resolve("timer")->value = index;
}
}
} else if (!strcmp(word[0], "sound")) {
int channel;
glui32 repeats;
if (SOUND_SUPPORTED->value && SOUND_ENABLED->value) {
/* SET THE CHANNEL TO USE, IF SUPPLIED */
if (word[2] == NULL) {
channel = 0;
} else {
channel = value_of(word[2], TRUE);
/* SANITY CHECK THE CHANNEL SELECTED */
if (channel < 0 || channel > 7) {
channel = 0;
}
}
/* SET THE NUMBER OF REPEATS, IF SUPPLIED */
if (word[3] == NULL) {
repeats = 1;
} else {
repeats = value_of(word[3], TRUE);
}
if (word[1] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
if (g_vm->glk_schannel_play_ext(sound_channel[channel], (glui32) value_of(word[1], TRUE), repeats, channel + 1) == 0) {
/* THE CHANNEL NUMBER IS PASSED SO THAT THE SOUND
* NOTIFICATION EVENT CAN USE THE INFORMATION
* IT HAS 1 ADDED TO IT SO THAT IT IS A NON-ZERO
* NUMBER AND THE EVENT IS ACTIVATED */
sprintf(error_buffer, "Unable to play sound: %ld", value_of(word[1], FALSE));
log_error(error_buffer, PLUS_STDERR);
}
}
}
} else if (!strcmp(word[0], "image")) {
if (GRAPHICS_SUPPORTED->value && GRAPHICS_ENABLED->value) {
if (word[1] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
if (!g_vm->loadingSavegame() && g_vm->glk_image_draw(mainwin, (glui32) value_of(word[1], TRUE), imagealign_InlineDown, 0) == 0) {
sprintf(error_buffer, "Unable to draw image: %ld", value_of(word[1], FALSE));
log_error(error_buffer, PLUS_STDERR);
}
}
}
} else if (!strcmp(word[0], "askstring") || !strcmp(word[0], "getstring")) {
if (word[1] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun(0);
return (exit_function(TRUE));
} else {
/* GET A POINTER TO THE STRING BEING MODIFIED */
if ((resolved_string = string_resolve(word[1])) == NULL) {
unkstrrun(word[1]);
return (exit_function(TRUE));
}
// PROMPT THE USER TO INPUT A STRING AND STORE IT IN THE
// RESOLVED VARIABLE
get_string(resolved_string->value);
}
} else if (!strcmp(word[0], "asknumber") || !strcmp(word[0], "getnumber")) {
int low, high;
int insist = FALSE;
/* THE ONLY DIFFERENCE WITH THE getnumber COMMAND IS THAT
* IT INSISTS THE PLAYER GIVES A LEGAL RESPONSE */
if (!strcmp(word[0], "getnumber")) {
insist = TRUE;
}
if (word[3] != NULL) {
ask_integer = container_resolve(word[1]);
if (ask_integer == NULL) {
unkvarrun(word[1]);
return (exit_function(TRUE));
}
low = value_of(word[2], TRUE);
high = value_of(word[3], TRUE);
if (high == -1 || low == -1) {
return (exit_function(TRUE));
}
*ask_integer = get_number(insist, low, high);
} else {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
}
} else if (!strcmp(word[0], "getyesorno")) {
if (word[1] != NULL) {
ask_integer = container_resolve(word[1]);
if (ask_integer == NULL) {
unkvarrun(word[1]);
return (exit_function(TRUE));
}
*ask_integer = get_yes_or_no();
} else {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
}
} else if (!strcmp(word[0], "clear")) {
if (!walkthru_running) {
g_vm->glk_window_clear(current_window);
}
} else if (!strcmp(word[0], "terminate")) {
terminate(0);
return 0;
} else if (!strcmp(word[0], "more")) {
if (word[1] == NULL) {
more("[MORE]");
} else {
more(word[1]);
}
} else if (!strcmp(word[0], "style")) {
/* THIS COMMAND IS USED TO OUTPUT ANSI CODES OR SET GLK
* STREAM STYLES */
if (word[1] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
if (!strcmp(word[1], "bold")
|| !strcmp(word[1], "emphasised")) {
g_vm->glk_set_style(style_Emphasized);
} else if (!strcmp(word[1], "note")) {
g_vm->glk_set_style(style_Note);
} else if (!strcmp(word[1], "input")) {
g_vm->glk_set_style(style_Input);
} else if (!strcmp(word[1], "header")) {
g_vm->glk_set_style(style_Header);
} else if (!strcmp(word[1], "subheader")) {
g_vm->glk_set_style(style_Subheader);
} else if (!strcmp(word[1], "reverse")
|| !strcmp(word[1], "inverse")) {
if (current_window == mainwin) {
g_vm->glk_set_style(style_User2);
} else {
g_vm->glk_set_style(style_User1);
}
} else if (!strcmp(word[1], "pre")
|| !strcmp(word[1], "preformatted")) {
g_vm->glk_set_style(style_Preformatted);
} else if (!strcmp(word[1], "normal")) {
g_vm->glk_set_style(style_Normal);
}
}
} else if (!strcmp(word[0], "flush")) {
} else if (!strcmp(word[0], "hyperlink")) {
/* OUTPUT LINK TEXT AS PLAIN TEXT UNDER Glk */
if (word[2] == NULL) {
noproprun();
pop_stack();
return (TRUE);
} else {
write_text(text_of_word(1));
}
#else
#ifdef __NDS__
} else if (!strcmp(word[0], "flush")) {
jflush();
} else if (!strcmp(word[0], "cursor")) {
if (word[2] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun(0);
return (exit_function(TRUE));
} else {
printf("\x1b[%d;%dH", (int) value_of(word[1], TRUE), (int) value_of(word[2], TRUE));
}
} else if (!strcmp(word[0], "stop")) {
} else if (!strcmp(word[0], "volume")) {
} else if (!strcmp(word[0], "timer")) {
} else if (!strcmp(word[0], "sound")) {
} else if (!strcmp(word[0], "image")) {
} else if (!strcmp(word[0], "askstring") || !strcmp(word[0], "getstring")) {
if (word[1] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun(0);
return (exit_function(TRUE));
} else {
/* GET A POINTER TO THE STRING BEING MODIFIED */
if ((resolved_string = string_resolve(word[1])) == NULL) {
unkstrrun(word[1]);
return (exit_function(TRUE));
}
// PROMPT THE USER TO INPUT A STRING AND STORE IT IN THE
// RESOLVED VARIABLE
get_string(resolved_string->value);
}
} else if (!strcmp(word[0], "asknumber") || !strcmp(word[0], "getnumber")) {
int low, high;
int insist = FALSE;
/* THE ONLY DIFFERENCE WITH THE getnumber COMMAND IS THAT
* IT INSISTS THE PLAYER GIVES A LEGAL RESPONSE */
if (!strcmp(word[0], "getnumber")) {
insist = TRUE;
}
if (word[3] != NULL) {
ask_integer = container_resolve(word[1]);
if (ask_integer == NULL) {
unkvarrun(word[1]);
return (exit_function(TRUE));
}
low = value_of(word[2], TRUE);
high = value_of(word[3], TRUE);
if (high == -1 || low == -1) {
return (exit_function(TRUE));
}
*ask_integer = get_number(insist, low, high);
} else {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
}
} else if (!strcmp(word[0], "getyesorno")) {
if (word[1] != NULL) {
ask_integer = container_resolve(word[1]);
if (ask_integer == NULL) {
unkvarrun(word[1]);
return (exit_function(TRUE));
}
*ask_integer = get_yes_or_no();
} else {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
}
} else if (!strcmp(word[0], "clear")) {
clrscrn();
} else if (!strcmp(word[0], "terminate")) {
terminate(0);
return;
} else if (!strcmp(word[0], "more")) {
if (word[1] == NULL) {
more("[MORE]");
} else {
more(word[1]);
}
} else if (!strcmp(word[0], "style")) {
/* THIS COMMAND IS USED TO OUTPUT ANSI CODES OR SET GLK
* STREAM STYLES */
if (word[1] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
if (!strcmp(word[1], "bold")
|| !strcmp(word[1], "emphasised")) {
printf("\x1b[37;1m"); // SET TO BRIGHT WHITE
bold_mode = TRUE;
} else if (!strcmp(word[1], "note")) {
printf("\x1b[34;1m"); // SET TO BRIGHT BLUE
note_mode = TRUE;
} else if (!strcmp(word[1], "input")) {
printf("\x1b[32;0m"); // SET TO DIM GREEN
input_mode = TRUE;
} else if (!strcmp(word[1], "header")) {
printf("\x1b[37;0m"); // SET TO DIM WHITE
} else if (!strcmp(word[1], "subheader")) {
printf("\x1b[33;1m"); // SET TO BRIGHT YELLOW
subheader_mode = TRUE;
} else if (!strcmp(word[1], "reverse")
|| !strcmp(word[1], "inverse")) {
printf("\x1b[7m"); // SET TO DIM WHITE
reverse_mode = TRUE;
} else if (!strcmp(word[1], "pre")
|| !strcmp(word[1], "preformatted")) {
printf("\x1b[37;0m"); // SET TO DIM WHITE
pre_mode = TRUE;
} else if (!strcmp(word[1], "normal")) {
printf("\x1b[37;0m"); // SET TO DIM WHITE
bold_mode = FALSE;
pre_mode = FALSE;
reverse_mode = FALSE;
input_mode = FALSE;
subheader_mode = FALSE;
note_mode = FALSE;
}
}
} else if (!strcmp(word[0], "hyperlink")) {
/* OUTPUT LINK TEXT AS PLAIN TEXT UNDER Glk */
if (word[2] == NULL) {
noproprun();
pop_stack();
return (TRUE);
} else {
write_text(text_of_word(1));
}
#else
/* HERE STARTS THE CGIJACL-ONLY FUNCTIONS */
} else if (!strcmp(word[0], "option")) {
/* USED TO ADD AN OPTION TO AN HTML LIST */
if (word[1] == NULL) {
noproprun();
pop_stack();
return (TRUE);
} else {
index = value_of(word[1]);
if (word[2] != NULL) {
sprintf(option_buffer, "<option value=\"%d\">",
index);
} else {
object_names(index, temp_buffer);
sprintf(option_buffer, "<option value=\"%s\">", temp_buffer);
}
write_text(option_buffer);
list_output(index, TRUE);
write_text(temp_buffer);
}
} else if (!strcmp(word[0], "getenv")) {
struct string_type *resolved_setstring = NULL;
if (word[2] == NULL) {
noproprun();
pop_stack();
return (TRUE);
} else {
// GET A POINTER TO THE STRING BEING MODIFIED
if ((resolved_setstring = string_resolve(word[1])) == NULL) {
unkstrrun(word[1]);
return (exit_function(TRUE));
}
// COPY THE VARIABLE OF THE CGI VARIABLE INTO THE SPECIFIED STRING VARIABLE
if (getenv(text_of_word(2)) != NULL) {
strncpy(resolved_setstring->value, getenv(text_of_word(2)), 255);
} else {
strncpy(resolved_setstring->value, "", 255);
}
}
} else if (!strcmp(word[0], "button")) {
/* USED TO CREATE AN HTML BUTTON */
if (word[1] == NULL) {
noproprun();
pop_stack();
return (TRUE);
}
if (word[2] != NULL) {
sprintf(option_buffer, "<input class=~button~ type=~image~ src=~%s~ name=~verb~ value=~", text_of_word(2));
strcat(option_buffer, text_of_word(1));
strcat(option_buffer, "~>");
write_text(option_buffer);
} else {
sprintf(option_buffer, "<input class=~button~ type=~submit~ style=~width: 90px; margin: 5px;~ name=~verb~ value=~%s~>", text_of_word(1));
write_text(option_buffer);
}
} else if (!strcmp(word[0], "hidden")) {
sprintf(temp_buffer, "<INPUT TYPE=\"hidden\" NAME=\"user_id\" VALUE=\"%s\">", user_id);
write_text(temp_buffer);
} else if (!strcmp(word[0], "control")) {
/* USED TO CREATE A HYPERLINK THAT IS AN IMAGE */
if (word[2] == NULL) {
noproprun();
pop_stack();
return (TRUE);
} else {
sprintf(option_buffer, "<a href=\"?command=%s&amp;user_id=%s\"><img border=0 SRC=\"", text_of_word(2), user_id);
strcat(option_buffer, text_of_word(1));
strcat(option_buffer, "\"></a>");
write_text(option_buffer);
}
} else if (!strcmp(word[0], "hyperlink") || !strcmp(word[0], "hyperlinkNE")) {
string_buffer[0] = 0;
/* USED TO CREATE A HYPERLINK WITH SESSION INFORMATION INCLUDED */
if (word[2] == NULL) {
noproprun();
pop_stack();
return (TRUE);
} else {
char *encoded;
if (!strcmp(word[0], "hyperlink")) {
encoded = url_encode(text_of_word(2));
} else {
encoded = text_of_word(2);
}
if (word[3] == NULL) {
sprintf(string_buffer, "<a href=\"?command=%s&amp;user_id=%s\">", encoded, user_id);
strcat(string_buffer, text_of_word(1));
strcat(string_buffer, "</a>");
} else {
sprintf(string_buffer, "<a class=\"%s\" href=\"?command=", text_of_word(3));
strcat(string_buffer, encoded);
sprintf(option_buffer, "&amp;user_id=%s\">%s</a>", user_id, text_of_word(1));
strcat(string_buffer, option_buffer);
}
if (!strcmp(word[0], "hyperlink")) {
free(encoded);
}
write_text(string_buffer);
}
} else if (!strcmp(word[0], "prompt")) {
/* USED TO OUTPUT A HTML INPUT CONTROL THAT CONTAINS SESSION INFORMATION */
if (word[1] != NULL) {
sprintf(temp_buffer, "<input id=\"JACLCommandPrompt\" type=text name=~command~ onKeyPress=~%s~>\n", word[1]);
write_text(temp_buffer);
} else {
sprintf(temp_buffer, "<input id=\"JACLCommandPrompt\" type=text name=~command~>\n");
write_text(temp_buffer);
}
sprintf(temp_buffer, "<input type=hidden name=\"user_id\" value=\"%s\">", user_id);
write_text(temp_buffer);
} else if (!strcmp(word[0], "style")) {
/* THIS COMMAND IS USED TO OUTPUT ANSI CODES OR SET GLK
* STREAM STYLES */
if (word[1] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
if (!strcmp(word[1], "bold")
|| !strcmp(word[1], "emphasised")) {
write_text("<b>");
style_stack[style_index++] = BOLD;
} else if (!strcmp(word[1], "note")) {
write_text("<i>");
style_stack[style_index++] = NOTE;
} else if (!strcmp(word[1], "input")) {
write_text("<i>");
style_stack[style_index++] = INPUT;
} else if (!strcmp(word[1], "header")) {
write_text("<h1>");
style_stack[style_index++] = HEADER;
} else if (!strcmp(word[1], "subheader")) {
write_text("<h2>");
style_stack[style_index++] = SUBHEADER;
} else if (!strcmp(word[1], "reverse")
|| !strcmp(word[1], "inverse")) {
write_text("<b>");
style_stack[style_index++] = REVERSE;
} else if (!strcmp(word[1], "pre")
|| !strcmp(word[1], "preformatted")) {
write_text("<pre>");
style_stack[style_index++] = PRE;
} else if (!strcmp(word[1], "normal")) {
style_index--;
for (; style_index > -1; style_index--) {
switch (style_stack[style_index]) {
case BOLD:
write_text("</b>");
break;
case NOTE:
write_text("</i>");
break;
case INPUT:
write_text("</i>");
break;
case HEADER:
write_text("</h1>");
break;
case SUBHEADER:
write_text("</h2>");
break;
case REVERSE:
write_text("</b>");
break;
case PRE:
write_text("</pre>");
break;
}
}
style_index = 0;
}
}
/* THESE FINAL COMMANDS HAVE NO EFFECT UNDER CGIJACL
AND THERE IS NO HARM IN IGNORING THEM */
} else if (!strcmp(word[0], "flush")) {
} else if (!strcmp(word[0], "image")) {
if (word[1] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun(0);
return (exit_function(TRUE));
} else {
if (word[2] == NULL) {
sprintf(option_buffer, "<img src=~%s~>", text_of_word(1));
} else {
sprintf(option_buffer, "<img class=~%s~ src=~%s~>", text_of_word(2), text_of_word(1));
}
write_text(option_buffer);
}
} else if (!strcmp(word[0], "sound")) {
if (word[2] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun(0);
return (exit_function(TRUE));
} else {
write_text("<audio autoplay=~autoplay~>");
if (word[3] == NULL) {
sprintf(option_buffer, "<source src=~%s~ type=~%s~>", text_of_word(1), text_of_word(2));
write_text(option_buffer);
}
write_text("</audio>");
}
} else if (!strcmp(word[0], "cursor")) {
} else if (!strcmp(word[0], "timer")) {
} else if (!strcmp(word[0], "volume")) {
} else if (!strcmp(word[0], "askstring") || !strcmp(word[0], "getstring")) {
} else if (!strcmp(word[0], "asknumber") || !strcmp(word[0], "getnumber")) {
} else if (!strcmp(word[0], "getyesorno")) {
} else if (!strcmp(word[0], "clear")) {
} else if (!strcmp(word[0], "more")) {
} else if (!strcmp(word[0], "terminate")) {
#endif
#endif
} else if (!strcmp(word[0], "proxy")) {
/* THE PROXY COMMAND ISSUES A MOVE ON THE PLAYER'S BEHALF
* ALL STATE MUST BE SAVED SO THE CURRENT MOVE CAN CONTINUE
* ONCE THE PROXIED MOVE IS COMPLETE */
#ifdef GLK
push_stack(g_vm->glk_stream_get_position(game_stream));
#else
push_stack(ftell(file));
#endif
push_proxy();
build_proxy();
// TEXT BUFFER IS THE NORMAL ARRAY FOR HOLDING THE PLAYERS
// MOVE FOR PROCESSING
strncpy(text_buffer, proxy_buffer, 1024);
command_encapsulate();
jacl_truncate();
preparse();
pop_proxy();
pop_stack();
} else if (!strcmp(word[0], "override")) {
/* TELLS THE INTERPRETER TO LOOK FOR AN _override FUNCTION
* TO EXECUTE IN PLACE OF ANY CODE THAT FOLLOWS THIS LINE.
* THIS COMMAND IS USED EXCLUSIVELY IN GLOBAL FUNCTIONS
* ASSOCIATED WITH GRAMMAR LINES */
if (execute(override_) == TRUE) {
return (exit_function(TRUE));
} else {
if (execute(default_function) == TRUE) {
return (exit_function(TRUE));
}
}
} else if (!strcmp(word[0], "execute") || !strcmp(word[0], "call")) {
/* CALLS ANOTHER JACL FUNCTION */
if (word[1] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
/* RESOLVE ALL THE TEXT AND STORE IT IN A TEMPORARY BUFFER*/
string_buffer[0] = 0;
for (counter = 1; word[counter] != NULL && counter < MAX_WORDS; counter++) {
strcat(string_buffer, arg_text_of_word(counter));
}
if (function_resolve(string_buffer) == NULL && !strcmp(word[0], "execute")) {
char *argstart;
/* REMOVE ANY PARAMETERS FROM FUNCTION NAME
BEFORE DISPLAYING ERROR MESSAGE */
argstart = strchr(string_buffer, '<');
if (argstart != NULL)
*argstart = 0;
sprintf(error_buffer, UNDEFINED_FUNCTION, executing_function->name, string_buffer);
log_error(error_buffer, PLUS_STDOUT);
} else {
execute(string_buffer);
}
}
} else if (!strcmp(word[0], "points")) {
/* INCREASE THE PLAYER'S SCORE AND POTENTIALLY INFORM THEM OF THE INCREASE */
if (word[1] != NULL) {
SCORE->value += value_of(word[1], TRUE);
if (NOTIFY->value) {
#ifdef GLK
g_vm->glk_set_style(style_Note);
#else
#ifdef __NDS__
printf("\x1b[34;1m"); // SET TO BRIGHT BLUE
note_mode = TRUE;
#else
write_text("<b><i>");
#endif
#endif
write_text(cstring_resolve("SCORE_UP")->value);
sprintf(temp_buffer, "%ld", value_of(word[1], TRUE));
write_text(temp_buffer);
if (value_of(word[1], TRUE) == 1) {
write_text(cstring_resolve("POINT")->value);
} else {
write_text(cstring_resolve("POINTS")->value);
}
#ifdef GLK
g_vm->glk_set_style(style_Normal);
#else
#ifdef __NDS__
printf("\x1b[37;0m"); // SET TO DIM WHITE
note_mode = FALSE;
#else
write_text("</i></b>");
#endif
#endif
}
} else {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
}
} else if (!strcmp(word[0], "print")) {
int non_space = FALSE;
// DISPLAYS A BLOCK OF PLAIN TEXT UNTIL IT FINDS A
// LINE THAT STARTS WITH A '.' OR A '}'
#ifdef GLK
(void)glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
fgets(text_buffer, 1024, file);
#endif
if (encrypted) jacl_decrypt(text_buffer);
while (text_buffer[0] != '.' && text_buffer[0] != '}') {
index = 0;
non_space = FALSE;
/* REMOVE ANY NEWLINE CHARACTERS */
while (text_buffer[index] != 0) {
if (text_buffer[index] == '|' && non_space == FALSE) {
/* THE BAR CHARACTER IS CHANGED TO A SPACE TO
* ALLOW INDENTING OF NEW PARAGRAPHS ETC */
text_buffer[index] = ' ';
} else if (text_buffer[index] == '\r') {
text_buffer[index] = 0;
break;
} else if (text_buffer[index] == '\n') {
text_buffer[index] = 0;
break;
} else if (text_buffer[index] != ' ' && text_buffer[index] != '\t') {
non_space = TRUE;
}
index++;
}
if (text_buffer[0] != 0) {
// CHECK IF THERE IS THE NEED TO ADD AN
// IMPLICIT SPACE
index = strlen(text_buffer);
if (text_buffer[index - 1] == '\\') {
// A BACKSLASH IS USED TO INDICATE AN IMPLICIT
// SPACE SHOULD NOT BE PRINTED
text_buffer[index - 1] = 0;
} else if (text_buffer[index - 1] != '^') {
// ADD AN IMPLICIT SPACE IF THE PREVIOUS LINE
// DIDN'T END WITH A CARRIAGE RETURN
strcat(text_buffer, " ");
}
// OUTPUT THE LINE READ AS PLAIN TEXT
write_text(text_buffer);
}
// GET THE NEXT LINE
#ifdef GLK
(void)glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
fgets(text_buffer, 1024, file);
#endif
if (encrypted) jacl_decrypt(text_buffer);
}
} else if (!strcmp(word[0], "mesg")) {
for (counter = 1; word[counter] != NULL && counter < MAX_WORDS; counter++) {
warning("%s", text_of_word(counter));
}
} else if (!strcmp(word[0], "error")) {
write_text("ERROR: In function ~");
write_text(executing_function->name);
write_text("~, ");
for (counter = 1; word[counter] != NULL && counter < MAX_WORDS; counter++) {
write_text(text_of_word(counter));
}
} else if (!strcmp(word[0], "debug") && DEBUG->value) {
write_text("DEBUG: ");
for (counter = 1; word[counter] != NULL && counter < MAX_WORDS; counter++) {
write_text(text_of_word(counter));
}
} else if (!strcmp(word[0], "write")) {
for (counter = 1; word[counter] != NULL && counter < MAX_WORDS; counter++) {
output = text_of_word(counter);
if (*output != 0) {
// IF THE OUTPUT ISN'T AN EMPTY STRING, DISPLAY IT
write_text(output);
}
}
} else if (!strcmp(word[0], "length")) {
if (word[2] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun(0);
return (exit_function(TRUE));
} else {
if ((container = container_resolve(word[1])) == NULL) {
unkvarrun(word[1]);
return (exit_function(TRUE));
}
*container = strlen(text_of(word[2]));
}
} else if (!strcmp(word[0], "savegame")) {
if (word[1] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
if ((container = container_resolve(word[1])) == NULL) {
unkvarrun(word[1]);
return (exit_function(TRUE));
} else {
*container = save_interaction();
}
}
} else if (!strcmp(word[0], "restoregame")) {
if (word[1] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
if ((container = container_resolve(word[1])) == NULL) {
unkvarrun(word[1]);
return (exit_function(TRUE));
} else {
*container = restore_interaction();
}
}
} else if (!strcmp(word[0], "restartgame")) {
restart_game();
execute("+intro");
eachturn();
#ifdef GLK
} else if (!strcmp(word[0], "undomove")) {
undoing();
} else if (!strcmp(word[0], "updatestatus")) {
status_line();
#else
} else if (!strcmp(word[0], "undomove")) {
} else if (!strcmp(word[0], "updatestatus")) {
#endif
} else if (!strcmp(word[0], "split")) {
// 0 1 2 3 4
// split counter source delimiter destination
int *split_container;
char split_buffer[256] = "";
char container_buffer[256] = "";
char delimiter[256] = "";
char *match = NULL;
struct string_type *resolved_splitstring = NULL;
strcpy(split_buffer, text_of_word(2));
strcpy(delimiter, text_of_word(3));
char *source = split_buffer;
if (word[4] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun(0);
return (exit_function(TRUE));
} else {
split_container = container_resolve(var_text_of_word(1));
if (split_container == NULL) {
unkvarrun(var_text_of_word(1));
return (exit_function(TRUE));
} else {
*split_container = 0;
match = source; // THERE IS ALWAYS ONE MATCH, EVEN IF
// NO DELIMETERS ARE FOUND
while ((match = strstr(source, delimiter))) {
*match = 0;
strcpy(container_buffer, var_text_of_word(4));
strcat(container_buffer, "[");
sprintf(integer_buffer, "%d", *split_container);
strcat(container_buffer, integer_buffer);
strcat(container_buffer, "]");
if ((resolved_splitstring = string_resolve(container_buffer)) == NULL) {
unkstrrun(var_text_of_word(4));
return (exit_function(TRUE));
} else {
strcpy(resolved_splitstring->value, source);
source = match + strlen(delimiter);
(*split_container)++;
}
}
strcpy(container_buffer, var_text_of_word(4));
strcat(container_buffer, "[");
sprintf(integer_buffer, "%d", *split_container);
strcat(container_buffer, integer_buffer);
strcat(container_buffer, "]");
if ((resolved_splitstring = string_resolve(container_buffer)) == NULL) {
unkstrrun(word[1]);
return (exit_function(TRUE));
} else {
strcpy(resolved_splitstring->value, source);
(*split_container)++;
}
}
}
} else if (!strcmp(word[0], "setstring") ||
!strcmp(word[0], "addstring")) {
char setstring_buffer[2048] = "";
struct string_type *resolved_setstring = NULL;
if (word[2] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun(0);
return (exit_function(TRUE));
} else {
/* GET A POINTER TO THE STRING BEING MODIFIED */
if ((resolved_setstring = string_resolve(var_text_of_word(1))) == NULL) {
unkstrrun(word[1]);
return (exit_function(TRUE));
}
/* RESOLVE ALL THE TEXT AND STORE IT IN A TEMPORARY BUFFER*/
for (counter = 2; word[counter] != NULL && counter < MAX_WORDS; counter++) {
strcat(setstring_buffer, text_of_word(counter));
}
/* setstring_buffer IS NOW FILLED, COPY THE UP TO 256 BYTES OF
* IT INTO THE STRING */
if (!strcmp(word[0], "setstring")) {
strncpy(resolved_setstring->value, setstring_buffer, 255);
} else {
/* CALCULATE HOW MUCH SPACE IS LEFT IN THE STRING */
counter = 255 - strlen(resolved_setstring->value);
/* THIS IS A addstring COMMAND, SO USE STRNCAT INSTEAD */
strncat(resolved_setstring->value, setstring_buffer, counter);
}
}
} else if (!strcmp(word[0], "padstring")) {
char setstring_buffer[2048] = "";
struct string_type *resolved_setstring = NULL;
string_buffer[0] = 0;
if (word[3] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun(0);
return (exit_function(TRUE));
} else {
/* GET A POINTER TO THE STRING BEING MODIFIED */
if ((resolved_setstring = string_resolve(word[1])) == NULL) {
unkstrrun(word[1]);
return (exit_function(TRUE));
}
index = value_of(word[3], TRUE);
for (counter = 0; counter < index; counter++) {
strcat(setstring_buffer, text_of_word(2));
}
/* setstring_buffer IS NOW FILLED, COPY THE UP TO 256 BYTES OF
* IT INTO THE STRING */
strncpy(resolved_setstring->value, setstring_buffer, 255);
}
} else if (!strcmp(word[0], "return")) {
/* RETURN FROM THIS FUNCTION, POSSIBLY RETURNING AN INTEGER VALUE */
if (word[1] == NULL) {
return (exit_function(TRUE));
} else {
index = value_of(word[1], TRUE);
return (exit_function(index));
}
} else if (!strcmp(word[0], "position")) {
/* MOVE AN OBJECT TO ITS NEW X,Y COORDINATES BASED ON ITS CURRENT VALUES
* FOR x, y, bearing, velocity */
if (word[1] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
object_1 = value_of(word[1], TRUE);
if (object_1 < 1 || object_1 > objects) {
badptrrun(word[1], object_1);
return (exit_function(TRUE));
} else {
new_position((double) object[object_1]->X,
(double) object[object_1]->Y,
(double) object[object_1]->BEARING,
(double) object[object_1]->VELOCITY);
object[object_1]->X = new_x;
object[object_1]->Y = new_y;
}
}
} else if (!strcmp(word[0], "bearing")) {
/* CALCULATE THE BEARING BETWEEN TWO OBJECTS */
if (word[3] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
if ((container = container_resolve(word[1])) == NULL) {
unkvarrun(word[1]);
return (exit_function(TRUE));
}
object_1 = value_of(word[2], TRUE);
if (object_1 < 1 || object_1 > objects) {
badptrrun(word[2], object_1);
return (exit_function(TRUE));
} else {
object_2 = value_of(word[3], TRUE);
if (object_2 < 1 || object_2 > objects) {
badptrrun(word[3], object_2);
return (exit_function(TRUE));
} else {
if (container != NULL
&& object_1 != FALSE
&& object_2 != FALSE) {
*container = bearing((double) object[object_1]->X,
(double) object[object_1]->Y,
(double) object[object_2]->X,
(double) object[object_2]->Y);
}
}
}
}
} else if (!strcmp(word[0], "distance")) {
/* CALCULATE THE DISTANCE BETWEEN TWO OBJECTS */
if (word[3] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
container = container_resolve(word[1]);
object_1 = value_of(word[2], TRUE);
if (object_1 < 1 || object_1 > objects) {
badptrrun(word[2], object_1);
return (exit_function(TRUE));
} else {
object_2 = value_of(word[3], TRUE);
if (object_2 < 1 || object_2 > objects) {
badptrrun(word[3], object_2);
return (exit_function(TRUE));
} else {
if (container != NULL
&& object_1 != FALSE
&& object_2 != FALSE) {
*container = distance((double)
object[object_1]->X,
(double)
object[object_1]->Y,
(double)
object[object_2]->X,
(double)
object[object_2]->Y);
}
}
}
}
} else if (!strcmp(word[0], "dir_to") ||
!strcmp(word[0], "npc_to")) {
/* CALCULATE THE FIRST DIRECTION TO TRAVEL IN GET TO
* A SPECIFIED LOCATION */
if (word[3] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
container = container_resolve(word[1]);
object_1 = value_of(word[2], TRUE);
if (object_1 < 1 || object_1 > objects) {
badptrrun(word[2], object_1);
return (exit_function(TRUE));
} else {
object_2 = value_of(word[3], TRUE);
if (object_2 < 1 || object_2 > objects) {
badptrrun(word[3], object_2);
return (exit_function(TRUE));
} else {
if (container != NULL
&& object_1 != FALSE
&& object_2 != FALSE) {
if (!strcmp(word[0], "dir_to")) {
*container = find_route(object_1, object_2, TRUE);
} else {
*container = find_route(object_1, object_2, FALSE);
}
}
}
}
}
} else if (!strcmp(word[0], "set")) {
/* SET THE VALUE OF AN ELEMENT TO A SUPPLIED INTEGER */
if (word[3] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
container = container_resolve(var_text_of_word(1));
if (container == NULL) {
unkvarrun(word[1]);
return (exit_function(TRUE));
} else {
int mark = 2; // SET mark TO POINT TO THE FIRST OPERATOR
while (word[mark + 1] != NULL) {
counter = value_of(word[mark + 1], TRUE);
if (word[mark][0] == '+')
*container += counter;
else if (word[mark][0] == '-')
*container -= counter;
else if (word[mark][0] == '*')
*container = *container * counter;
else if (word[mark][0] == '%')
*container = *container % counter;
else if (word[mark][0] == '/') {
if (counter == 0) {
sprintf(error_buffer, DIVIDE_BY_ZERO,
executing_function->name);
log_error(error_buffer, PLUS_STDOUT);
} else
*container = *container / counter;
} else if (!strcmp(word[mark], "locationof")) {
*container = grand_of(counter, FALSE);
} else if (!strcmp(word[mark], "grandof")) {
*container = grand_of(counter, TRUE);
} else if (word[mark][0] == '=') {
*container = counter;
} else {
sprintf(error_buffer, ILLEGAL_OPERATOR,
executing_function->name,
word[2]);
log_error(error_buffer, PLUS_STDOUT);
}
mark += 2;
}
}
}
} else if (!strcmp(word[0], "ensure")) {
/* USED TO GIVE OR TAKE AN ATTRIBUTE TO OR FROM AND OBJECT */
if (word[3] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
} else {
if ((bit_mask = attribute_resolve(arg_text_of(word[3])))) {
index = value_of(word[1], TRUE);
if (index < 1 || index > objects) {
badptrrun(word[1], index);
return (exit_function(TRUE));
} else {
if (!strcmp(word[2], "has")) {
object[index]->attributes =
object[index]->attributes | bit_mask;
} else if (!strcmp(word[2], "hasnt")) {
bit_mask = ~bit_mask;
object[index]->attributes =
object[index]->attributes & bit_mask;
}
}
} else if ((bit_mask = user_attribute_resolve(arg_text_of(word[3])))) {
index = value_of(word[1], TRUE);
if (index < 1 || index > objects) {
badptrrun(word[1], index);
return (exit_function(TRUE));
} else {
if (!strcmp(word[2], "has")) {
object[index]->user_attributes =
object[index]->user_attributes | bit_mask;
} else if (!strcmp(word[2], "hasnt")) {
bit_mask = ~bit_mask;
object[index]->user_attributes =
object[index]->user_attributes & bit_mask;
}
}
} else {
unkattrun(3);
return (exit_function(TRUE));
}
}
} else if (!strcmp(word[0], "append")) {
int first = TRUE;
if (word[2] == NULL) {
// NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND
noproprun();
return (exit_function(TRUE));
} else {
strcpy(temp_buffer, data_directory);
strcat(temp_buffer, prefix);
strcat(temp_buffer, "-");
strcat(temp_buffer, text_of_word(1));
strcat(temp_buffer, ".csv");
outfile = File::openForWriting(temp_buffer);
if (outfile == NULL) {
sprintf(error_buffer, "Failed to open file %s\n", temp_buffer);
log_error(error_buffer, PLUS_STDOUT);
} else {
for (counter = 2; word[counter] != NULL && counter < MAX_WORDS; counter++) {
output = text_of_word(counter);
if (*output != 0) {
if (first == FALSE) {
outfile->writeByte(',');
}
csv_fwrite(outfile, output, (size_t) strlen(output));
first = FALSE;
}
}
// TERMINATE THE LINE
outfile->writeByte('\n');
// FLUSH AND CLOSE THE FILE
outfile->flush();
}
delete outfile;
outfile = NULL;
}
} else if (!strcmp(word[0], "insert")) {
int first = TRUE;
if (word[1] == NULL) {
// NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND
noproprun();
return (exit_function(TRUE));
} else {
if (outfile == NULL) {
log_error("Insert statement not inside an 'update' loop.", PLUS_STDOUT);
} else {
for (counter = 1; word[counter] != NULL && counter < MAX_WORDS; counter++) {
output = text_of_word(counter);
if (*output != 0) {
if (first == FALSE) {
outfile->writeByte(',');
}
csv_fwrite(outfile, output, (size_t) strlen(output));
first = FALSE;
}
}
// TERMINATE THE LINE
outfile->writeByte('\n');
}
}
} else if (!strcmp(word[0], "inspect")) {
if (word[1] == NULL) {
// NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND
noproprun();
return (exit_function(TRUE));
} else {
inspect(value_of(word[1], TRUE));
}
} else if (!strcmp(word[0], "move")) {
/* THIS COMMAND IS USED TO MOVE AN OBJECT TO HAVE ANOTHER PARENT
* INCLUDING MODIFYING ALL QUANTITY VALUES BASED ON THE OBJECTS MASS */
if (word[3] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun();
return (exit_function(TRUE));
}
index = value_of(word[1], TRUE);
if (index < 1 || index > objects) {
badptrrun(word[1], index);
return (exit_function(TRUE));
} else {
object_2 = object[index]->PARENT;
if (object_2 && !(object[object_2]->attributes & LOCATION)) {
object[object_2]->QUANTITY += object[index]->MASS;
}
object_1 = value_of(word[3], TRUE);
if (object_1 < 1 || object_1 > objects) {
badptrrun(word[1], object_1);
return (exit_function(TRUE));
} else {
object[index]->PARENT = object_1;
if (!(object[object_1]->attributes & LOCATION))
object[object_1]->QUANTITY -= object[index]->MASS;
}
}
} else if (!strcmp(word[0], "ifstringall")) {
/* CHECK IF A STRING EQUALS OR CONTAINS ANOTHER STRING */
currentLevel++;
if (word[3] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun(0);
return (exit_function(TRUE));
} else if (and_strcondition()) {
executionLevel++;
}
} else if (!strcmp(word[0], "ifstring")) {
/* CHECK IF A STRING EQUALS OR CONTAINS ANOTHER STRING */
currentLevel++;
if (word[3] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun(0);
return (exit_function(TRUE));
} else if (strcondition()) {
executionLevel++;
}
} else if (!strcmp(word[0], "ifexecute")) {
currentLevel++;
if (word[1] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun(0);
return (exit_function(TRUE));
} else {
/* RESOLVE ALL THE TEXT AND STORE IT IN A TEMPORARY BUFFER*/
string_buffer[0] = 0;
for (counter = 1; word[counter] != NULL && counter < MAX_WORDS; counter++) {
strcat(string_buffer, arg_text_of_word(counter));
}
if (execute(string_buffer)) {
executionLevel++;
}
}
} else if (!strcmp(word[0], "if")) {
currentLevel++;
if (word[3] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun(0);
return (exit_function(TRUE));
} else if (condition()) {
executionLevel++;
}
} else if (!strcmp(word[0], "ifall")) {
currentLevel++;
if (word[3] == NULL) {
/* NOT ENOUGH PARAMETERS SUPPLIED FOR THIS COMMAND */
noproprun(0);
return (exit_function(TRUE));
} else if (and_condition()) {
executionLevel++;
}
} else {
sprintf(error_buffer, UNKNOWN_COMMAND,
executing_function->name, word[0]);
log_error(error_buffer, PLUS_STDOUT);
}
} else if (!strcmp(word[wp], "if")
|| !strcmp(word[wp], "ifall")
|| !strcmp(word[wp], "ifstring")
|| !strcmp(word[wp], "ifstringall")
|| !strcmp(word[wp], "ifexecute")
|| !strcmp(word[wp], "iterate")
|| !strcmp(word[wp], "update")
|| !strcmp(word[wp], "while")
|| !strcmp(word[wp], "whileall")) {
currentLevel++;
}
#ifdef GLK
if (g_vm->shouldQuit())
return 0;
before_command = g_vm->glk_stream_get_position(game_stream);
(void)glk_get_bin_line_stream(game_stream, text_buffer, (glui32) 1024);
#else
before_command = ftell(file);
fgets(text_buffer, 1024, file);
#endif
if (encrypted) jacl_decrypt(text_buffer);
};
return (exit_function(TRUE));
}
int exit_function(int return_code) {
if (infile != NULL) {
read_lck.l_type = F_UNLCK; // SETTING A READ LOCK
fcntl(read_fd, F_SETLK, &read_lck);
delete infile;
infile = NULL;
}
if (outfile != NULL) {
write_lck.l_type = F_UNLCK; // SETTING A WRITE LOCK
fcntl(write_fd, F_SETLK, &write_lck);
delete outfile;
outfile = NULL;
}
/* POP THE STACK REGARDLESS OF THE RETURN CODE */
pop_stack();
return (return_code);
}
char *object_names(int object_index, char *names_buffer) {
/* THIS FUNCTION CREATES A LIST OF ALL AN OBJECT'S NAMES.
THE escape ARGUMENT INDICATES WHETHER A + SIGN SHOULD BE
USED IN PLACE OF A SPACE BETWEEN EACH OF THE NAMES */
struct name_type *current_name = object[object_index]->first_name;
names_buffer[0] = 0;
while (current_name != NULL) {
strcat(names_buffer, " ");
strcat(names_buffer, current_name->name);
current_name = current_name->next_name;
}
return names_buffer;
}
int distance(double x1, double y1, double x2, double y2) {
/* THIS FUNCTION CALCULATES THE DISTANCE BETWEEN TWO POINTS IN A
TWO-DIMENSIONAL PLANE */
double delta_x,
delta_y;
double distance,
total;
/*
* Object two in which quadrant compared to object one? 0 x = opp, y =
* ajd + 0 degrees 1 x = adj, y = opp + 90 degrees 2 x = opp, y = ajd
* + 180 degrees 3 x = adj, y = opp + 270 degrees
*/
/*
* DETERMINE WHICH QUADRANT OBJECT TWO IS IN
*/
if (x2 > x1) {
/*
* OBJECT TWO IS IN 1 OR 2
*/
delta_x = x2 - x1;
if (y2 > y1) {
delta_y = y2 - y1;
} else {
delta_y = y1 - y2;
}
} else {
/*
* OBJECT TWO IS IN 3 OR 4
*/
delta_x = x1 - x2;
if (y2 > y1) {
delta_y = y2 - y1;
} else {
delta_y = y1 - y2;
}
}
delta_y = delta_y * delta_y;
delta_x = delta_x * delta_x;
total = delta_y + delta_x;
distance = sqrt(total);
return ((int) distance);
}
void new_position(double x1, double y1, double bearing, double velocity) {
double delta_x,
delta_y;
double radians;
/*
* Object two in which quadrant compared to object one? 0 x = opp, y =
* ajd + 0 degrees 1 x = adj, y = opp + 90 degrees 2 x = opp, y = ajd
* + 180 degrees 3 x = adj, y = opp + 270 degrees
*/
/*
* sin finds opp, cos finds adj
*/
if (bearing < 91) {
radians = bearing * 2.0 * M_PI / 360.;
delta_x = velocity * sin(radians);
delta_y = velocity * cos(radians);
new_x = x1 + delta_x;
new_y = y1 + delta_y;
} else if (bearing < 181) {
bearing -= 90;
radians = bearing * 2.0 * M_PI / 360.;
delta_y = velocity * sin(radians);
delta_x = velocity * cos(radians);
new_x = x1 + delta_x;
new_y = y1 - delta_y;
} else if (bearing < 271) {
bearing -= 180;
radians = bearing * 2.0 * M_PI / 360.;
delta_x = velocity * sin(radians);
delta_y = velocity * cos(radians);
new_x = x1 - delta_x;
new_y = y1 - delta_y;
} else {
bearing -= 270;
radians = bearing * 2.0 * M_PI / 360.;
delta_y = velocity * sin(radians);
delta_x = velocity * cos(radians);
new_x = x1 - delta_x;
new_y = y1 + delta_y;
}
}
int bearing(double x1, double y1, double x2, double y2) {
int quadrant;
double delta_x,
delta_y;
double oppoadj;
double bearing;
/*
* Object two in which quadrant compared to object one? 0 x = opp, y =
* ajd + 0 degrees 1 x = adj, y = opp + 90 degrees 2 x = opp, y = ajd
* + 180 degrees 3 x = adj, y = opp + 270 degrees
*/
if (x2 > x1) {
delta_x = x2 - x1;
if (y2 > y1) {
quadrant = 0;
delta_y = y2 - y1;
oppoadj = delta_x / delta_y;
} else {
quadrant = 1;
delta_y = y1 - y2;
oppoadj = delta_y / delta_x;
}
} else {
delta_x = x1 - x2;
if (y2 > y1) {
quadrant = 3;
delta_y = y2 - y1;
oppoadj = delta_y / delta_x;
} else {
quadrant = 2;
delta_y = y1 - y2;
oppoadj = delta_x / delta_y;
}
}
bearing = atan(oppoadj);
bearing = bearing / (2.0 * M_PI) * 360.;
bearing = bearing + (90 * quadrant);
return ((int) bearing);
}
void set_arguments(const char *function_call) {
/* THIS FUNCTION CREATES AN ARRAY OF JACL INTEGER CONSTANTS TO
REPRESENT THE ARGUMENTS PASSED TO A JACL FUNCTION */
int index,
counter,
length;
int position = 0; /* STORE THE INDEX OF THE WORD */
/* SETTING new_word TO FALSE SKIPS THE FIRST */
/* WORD WHICH IS THE FUNCTION NAME */
int new_word = FALSE;
char *arg_ptr[MAX_WORDS];
int arg_value[MAX_WORDS];
struct integer_type *resolved_integer;
struct cinteger_type *resolved_cinteger;
/* SPLIT UP THE FUNCTION CALL STRING AND EXTRACT THE ARGUMENTS */
length = strlen(function_call);
for (index = 0; index < length; index++) {
if (function_call[index] == '<') {
argument_buffer[index] = 0;
new_word = TRUE;
} else {
// COPY THE CHARACTER FROM THE CALLED NAME INTO THE CURRENT
// ARGUMENT BUFFER
argument_buffer[index] = function_call[index];
if (new_word) {
// THIS IS THE FIRST CHARACTER OF A NEW ARGUMENT SO STORE
// THE ADDRESS OF THIS CHARACTER IN THE ARGUMENT BUFFER
arg_ptr[position] = &argument_buffer[index];
new_word = FALSE;
if (position < MAX_WORDS)
position++;
}
}
}
argument_buffer[index] = 0;
/* CLEAR THE NEXT ARGUMENT POINTER */
arg_ptr[position] = NULL;
/* STORE THE INTEGER VALUE OF EACH ARGUMENT PASSED*/
index = 0;
while (arg_ptr[index] != NULL) {
//arg_value[index] = value_of(arg_ptr[index], TRUE);
if ((resolved_integer = integer_resolve(arg_ptr[index])) != NULL) {
arg_value[index] = resolved_integer->value;
} else if ((resolved_cinteger = cinteger_resolve(arg_ptr[index])) != NULL) {
arg_value[index] = resolved_cinteger->value;
} else if (object_element_resolve(arg_ptr[index])) {
arg_value[index] = oec;
} else if ((counter = object_resolve(arg_ptr[index])) != -1) {
if (counter < 1 || counter > objects) {
badptrrun(arg_ptr[index], counter);
pop_stack();
return;
} else {
arg_value[index] = counter;
}
} else if (validate(arg_ptr[index])) {
arg_value[index] = atoi(arg_ptr[index]);
} else {
arg_value[index] = -1;
}
index++;
}
/* THE CURRENT ARGUMENTS HAVE ALREADY BEEN PUSHED ONTO THE STACK
* AND STORED IF PASSED AS AN ARGUMENT TO THIS FUNCTION SO IT IS
* OKAY TO CLEAR THEM AND SET THE NEW VALUES */
clear_cinteger("arg");
clear_cstring("string_arg");
/* CREATE A CONSTANT FOR EACH ARGUMENT AFTER THE CORE FUNCTION NAME */
index = 0;
while (arg_ptr[index] != NULL) {
if (index == 0) noun[3] = arg_value[index];
add_cinteger("arg", arg_value[index]);
//printf("--- %s = %s\n", arg_ptr[index], arg_text_of(arg_ptr[index]));
add_cstring("string_arg", arg_text_of(arg_ptr[index]));
index++;
}
}
void pop_stack() {
int index, counter;
stack--;
clear_cinteger("arg");
clear_cstring("string_arg");
/* RECREATE THE arg ARRAY FOR THIS STACK FRAME */
for (index = 0; index < backup[stack].argcount; index++) {
if (index == 0) noun[3] = backup[stack].arguments[0];
add_cinteger("arg", backup[stack].arguments[index]);
}
/* RECREATE THE string_arg ARRAY FOR THIS STACK FRAME */
for (index = 0; index < backup[stack].argcount; index++) {
add_cstring("string_arg", backup[stack].str_arguments[index]);
}
/* RESTORE THE CONTENTS OF text_buffer */
for (counter = 0; counter < 1024; counter++)
text_buffer[counter] = backup[stack].text_buffer[counter];
/* RESTORE THE CONTENTS OF called_name */
//for (counter = 0; counter < 256; counter++)
//called_name[counter] = backup[stack].called_name[counter];
strncpy(called_name, backup[stack].called_name, 1024);
/* RESTORE THE CONTENTS OF scope_criterion */
//for (counter = 0; counter < 21; counter++)
// scope_criterion[counter] = backup[stack].scope_criterion[counter];
strncpy(scope_criterion, backup[stack].scope_criterion, 20);
/* RESTORE THE STORED FUNCTION NAMES THAT ARE USED WHEN AN
* 'override' COMMAND IS ENCOUNTERED IN THE CURRENT FUNCTION */
strncpy(override_, backup[stack]._override, 80);
strncpy(default_function, backup[stack].default_function, 80);
/* RESTORE ALL THE WORD POINTERS */
for (counter = 0; counter < MAX_WORDS; counter++) {
word[counter] = backup[stack].word[counter];
quoted[counter] = backup[stack].quoted[counter];
}
executing_function = backup[stack].function;
if (executing_function != NULL) {
strncpy(function_name, executing_function->name, 80);
strncpy(cstring_resolve("function_name")->value, executing_function->name, 80);
}
wp = backup[stack].wp;
top_of_loop = backup[stack].top_of_loop;
outfile = backup[stack].outfile;
infile = backup[stack].infile;
top_of_select = backup[stack].top_of_select;
top_of_while = backup[stack].top_of_while;
top_of_iterate = backup[stack].top_of_iterate;
top_of_update = backup[stack].top_of_update;
top_of_do_loop = backup[stack].top_of_do_loop;
criterion_value = backup[stack].criterion_value;
criterion_type = backup[stack].criterion_type;
criterion_negate = backup[stack].criterion_negate;
current_level = backup[stack].current_level;
execution_level = backup[stack].execution_level;
loop_integer = backup[stack].loop_integer;
select_integer = backup[stack].select_integer;
#ifdef GLK
g_vm->glk_stream_set_position(game_stream, backup[stack].address, seekmode_Start);
#else
fseek(file, backup[stack].address, SEEK_SET);
#endif
}
void push_stack(int32 file_pointer) {
/* COPY ALL THE CURRENT SYSTEM DATA ONTO THE STACK */
int index;
int counter = 0;
if (stack == STACK_SIZE) {
log_error("Stack overflow.", PLUS_STDERR);
terminate(45);
return;
} else {
backup[stack].infile = infile;
infile = NULL;
backup[stack].outfile = outfile;
outfile = NULL;
backup[stack].function = executing_function;
backup[stack].address = file_pointer;
backup[stack].wp = wp;
backup[stack].top_of_loop = top_of_loop;
backup[stack].top_of_select = top_of_select;
backup[stack].top_of_while = top_of_while;
backup[stack].top_of_iterate = top_of_iterate;
backup[stack].top_of_update = top_of_update;
backup[stack].top_of_do_loop = top_of_do_loop;
backup[stack].criterion_value = criterion_value;
backup[stack].criterion_type = criterion_type;
backup[stack].criterion_negate = criterion_negate;
backup[stack].current_level = current_level;
backup[stack].execution_level = execution_level;
backup[stack].loop_integer = loop_integer;
backup[stack].select_integer = select_integer;
/* MAKE A COPY OF THE CURRENT CONTENTS OF text_buffer */
for (counter = 0; counter < 1024; counter++)
backup[stack].text_buffer[counter] = text_buffer[counter];
/* MAKE A COPY OF THE CURRENT CONTENTS OF called_name */
strncpy(backup[stack].called_name, called_name, 1024);
// MAKE A COPY OF THE CURRENT CONTENTS OF scope_criterion
strncpy(backup[stack].scope_criterion, scope_criterion, 20);
/* COPY THE STORED FUNCTION NAMES THAT ARE USED WHEN AN
* 'override' COMMAND IS ENCOUNTERED IN THE CURRENT FUNCTION */
strncpy(backup[stack]._override, override_, 80);
strncpy(backup[stack].default_function, default_function, 80);
/* PUSH ALL THE WORD POINTERS ONTO THE STACK */
for (counter = 0; counter < MAX_WORDS; counter++) {
backup[stack].word[counter] = word[counter];
backup[stack].quoted[counter] = quoted[counter];
}
// PUSH ALL THE ARGUMENTS AS INTEGERS ONTO THE STACK
index = 0;
current_cinteger = cinteger_table;
if (current_cinteger != NULL) {
do {
if (!strcmp(current_cinteger->name, "arg")) {
backup[stack].arguments[index++] = current_cinteger->value;
}
current_cinteger = current_cinteger->next_cinteger;
} while (current_cinteger != NULL);
}
// STORE THE NUMBER OF ARGUMENTS PASSED TO THIS FUNCTION
// THIS IS THE SAME NUMBER FOR STRINGS AND INTEGERS
backup[stack].argcount = index;
// PUSH ALL THE ARGUMENTS AS STRINGS STRING ONTO THE STACK
index = 0;
current_cstring = cstring_table;
if (current_cstring != NULL) {
do {
if (!strcmp(current_cstring->name, "string_arg")) {
strncpy(backup[stack].str_arguments[index++], current_cstring->value, 255);
}
current_cstring = current_cstring->next_string;
} while (current_cstring != NULL);
}
}
// PUSH ON TO THE NEXT STACK FRAME
stack++;
}
void pop_proxy() {
int index, counter;
proxy_stack--;
clear_cinteger("$integer");
clear_cstring("$string");
clear_cstring("$word");
/* RECREATE THE integer ARRAY FOR THIS STACK FRAME */
for (index = 0; index < proxy_backup[proxy_stack].integercount; index++) {
add_cinteger("$integer", proxy_backup[proxy_stack].integer[index]);
}
/* RECREATE THE text ARRAY FOR THIS STACK FRAME */
for (index = 0; index < proxy_backup[proxy_stack].textcount; index++) {
add_cstring("$string", proxy_backup[proxy_stack].text[index]);
}
/* RECREATE THE $word ARRAY FOR THIS STACK FRAME */
for (index = 0; index < proxy_backup[proxy_stack].commandcount; index++) {
add_cstring("$word", proxy_backup[proxy_stack].command[index]);
}
/* RESTORE ALL THE NOUN POINTERS */
for (counter = 0; counter < 4; counter++)
noun[counter] = proxy_backup[proxy_stack].object_pointers[counter];
/* PUSH ALL THE RESOLVED OBJECTS ONTO THE STACK */
for (index = 0; index < 4; index++) {
list_size[index] = proxy_backup[proxy_stack].list_size[index];
max_size[index] = proxy_backup[proxy_stack].max_size[index];
for (counter = 0; counter < max_size[index]; counter++) {
object_list[index][counter] = proxy_backup[proxy_stack].object_list[index][counter];
}
}
start_of_this_command = proxy_backup[proxy_stack].start_of_this_command;
start_of_last_command = proxy_backup[proxy_stack].start_of_last_command;
after_from = proxy_backup[proxy_stack].after_from;
last_exact = proxy_backup[proxy_stack].last_exact;
}
void push_proxy() {
/* COPY ALL THE CURRENT SYSTEM DATA ONTO THE STACK */
int index;
int counter = 0;
int command = 0;
int text = 0;
current_cinteger = cinteger_table;
current_cstring = cstring_table;
if (proxy_stack == STACK_SIZE) {
log_error("Stack overflow.", PLUS_STDERR);
terminate(45);
return;
} else {
proxy_backup[proxy_stack].start_of_this_command = start_of_this_command;
proxy_backup[proxy_stack].start_of_last_command = start_of_last_command;
/* PUSH ALL THE OBJECT POINTERS ONTO THE STACK */
for (counter = 0; counter < 4; counter++)
proxy_backup[proxy_stack].object_pointers[counter] = noun[counter];
/* PUSH ALL THE RESOLVED OBJECTS ONTO THE STACK */
for (index = 0; index < 4; index++) {
for (counter = 0; counter < max_size[index]; counter++) {
proxy_backup[proxy_stack].object_list[index][counter]
= object_list[index][counter];
}
proxy_backup[proxy_stack].list_size[index] = list_size[index];
proxy_backup[proxy_stack].max_size[index] = max_size[index];
}
/* PUSH ALL THE CURRENT COMMAND INTEGERS ONTO THE STACK */
counter = 0;
if (current_cinteger != NULL) {
do {
if (!strcmp(current_cinteger->name, "$integer")) {
proxy_backup[proxy_stack].integer[counter++] = current_cinteger->value;
}
current_cinteger = current_cinteger->next_cinteger;
} while (current_cinteger != NULL);
}
proxy_backup[proxy_stack].integercount = counter;
// PUSH ALL THE TEXT STRING SUPPLIED BY THE CURRENT COMMAND ONTO THE STACK
text = 0;
command = 0;
if (current_cstring != NULL) {
do {
if (!strcmp(current_cstring->name, "$string")) {
strncpy(proxy_backup[proxy_stack].text[text++], current_cstring->value, 255);
proxy_backup[proxy_stack].text[counter++][255] = 0;
} else if (!strcmp(current_cstring->name, "$word")) {
strncpy(proxy_backup[proxy_stack].command[command++], current_cstring->value, 255);
}
current_cstring = current_cstring->next_string;
} while (current_cstring != NULL);
}
proxy_backup[proxy_stack].textcount = counter;
proxy_backup[proxy_stack].commandcount = command;
proxy_backup[proxy_stack].after_from = after_from;
proxy_backup[proxy_stack].last_exact = last_exact;
}
// PUSH ON TO THE NEXT STACK FRAME
proxy_stack++;
}
int condition() {
/* COMPARE GROUPS OF TWO ELEMENTS. RETURN TRUE IF ANY ONE GROUP OF
* ELEMENTS COMPARE 'TRUE' */
int first;
first = 1;
while (word[first + 2] != NULL && ((first + 2) < MAX_WORDS)) {
if (logic_test(first))
return (TRUE);
else
first = first + 3;
}
return (FALSE);
}
int and_condition() {
/* COMPARE GROUPS OF TWO ELEMENTS. RETURN FALSE IF ANY ONE GROUP OF
* ELEMENTS COMPARE 'FALSE' */
int first;
first = 1;
while (word[first + 2] != NULL && ((first + 2) < MAX_WORDS)) {
if (logic_test(first) == FALSE)
return (FALSE);
else
first = first + 3;
}
return (TRUE);
}
int logic_test(int first) {
long index,
compare;
resolved_attribute = FALSE;
index = value_of(word[first], TRUE);
compare = value_of(word[first + 2], TRUE);
if (!strcmp(word[first + 1], "=") || !strcmp(word[first + 1], "==")) {
if (index == compare)
return (TRUE);
else
return (FALSE);
} else if (!strcmp(word[first + 1], ">")) {
if (index > compare)
return (TRUE);
else
return (FALSE);
} else if (!strcmp(word[first + 1], "<")) {
if (index < compare)
return (TRUE);
else
return (FALSE);
} else if (!strcmp(word[first + 1], "is")) {
if (index < 1 || index > objects) {
unkobjrun(first);
return (FALSE);
} else
return (scope(index, word[first + 2]));
} else if (!strcmp(word[first + 1], "isnt")) {
if (index < 1 || index > objects) {
unkobjrun(first);
return (FALSE);
} else
return (!scope(index, word[first + 2]));
} else if (!strcmp(word[first + 1], "has"))
if (index < 1 || index > objects) {
unkobjrun(first);
return (FALSE);
} else {
if (resolved_attribute == SYSTEM_ATTRIBUTE) {
return (object[index]->attributes & compare);
} else {
return (object[index]->user_attributes & compare);
}
}
else if (!strcmp(word[first + 1], "hasnt"))
if (index < 1 || index > objects) {
unkobjrun(first);
return (FALSE);
} else {
if (resolved_attribute == SYSTEM_ATTRIBUTE) {
return (!(object[index]->attributes & compare));
} else {
return (!(object[index]->user_attributes & compare));
}
}
else if (!strcmp(word[first + 1], "!=")
|| !strcmp(word[first + 1], "<>")) {
if (index != compare)
return (TRUE);
else
return (FALSE);
} else if (!strcmp(word[first + 1], ">=")
|| !strcmp(word[first + 1], "=>")) {
if (index >= compare)
return (TRUE);
else
return (FALSE);
} else if (!strcmp(word[first + 1], "<=")
|| !strcmp(word[first + 1], "=<")) {
if (index <= compare)
return (TRUE);
else
return (FALSE);
} else if (!strcmp(word[first + 1], "grandof")) {
/* GRANDOF SAYS THAT AN OBJECT IS THE EVENTUAL PARENT OF ANOTHER OBJECT, NOT
* NECESSARILY IMMEDIATE */
if (index < 1 || index > objects) {
unkobjrun(first);
return (FALSE);
} else {
if (compare < 1 || compare > objects) {
unkobjrun(first + 2);
return (FALSE);
} else {
if (parent_of(index, compare, UNRESTRICT))
return (TRUE);
else
return (FALSE);
}
}
} else if (!strcmp(word[first + 1], "!grandof")) {
if (index < 1 || index > objects) {
unkobjrun(first);
return (FALSE);
} else {
if (compare < 1 || compare > objects) {
unkobjrun(first + 2);
return (FALSE);
} else {
if (parent_of(index, compare, UNRESTRICT))
return (FALSE);
else
return (TRUE);
}
}
} else {
sprintf(error_buffer,
"ERROR: In function \"%s\", illegal operator \"%s\".^",
executing_function->name, word[2]);
write_text(error_buffer);
return (FALSE);
}
}
int strcondition() {
int first;
first = 1;
while (word[first + 2] != NULL && ((first + 2) < MAX_WORDS)) {
if (str_test(first))
return (TRUE);
else
first = first + 3;
}
return (FALSE);
}
int and_strcondition() {
int first;
first = 1;
while (word[first + 2] != NULL && ((first + 2) < MAX_WORDS)) {
if (str_test(first) == FALSE)
return (FALSE);
else
first = first + 3;
}
return (TRUE);
}
int str_test(int first) {
const char *index;
const char *compare;
// GET THE TWO STRING VALUES TO COMPARE
index = arg_text_of_word(first);
compare = arg_text_of_word(first + 2);
if (!strcmp(word[first + 1], "==") || !strcmp(word[first + 1], "=")) {
if (!scumm_stricmp(index, compare)) {
return (TRUE);
} else {
return (FALSE);
}
} else if (!strcmp(word[first + 1], "!contains")) {
if (strcasestr(index, compare))
return (FALSE);
else
return (TRUE);
} else if (!strcmp(word[first + 1], "contains")) {
if (strcasestr(index, compare))
return (TRUE);
else
return (FALSE);
} else if (!strcmp(word[first + 1], "<>") || !strcmp(word[first + 1], "!=")) {
if (scumm_stricmp(index, compare))
return (TRUE);
else
return (FALSE);
} else if (!strcmp(word[first + 1], "==C") || !strcmp(word[first + 1], "=C")) {
if (!strcmp(index, compare)) {
return (TRUE);
} else {
return (FALSE);
}
} else if (!strcmp(word[first + 1], "!containsC")) {
if (strstr(index, compare))
return (FALSE);
else
return (TRUE);
} else if (!strcmp(word[first + 1], "containsC")) {
if (strstr(index, compare))
return (TRUE);
else
return (FALSE);
} else if (!strcmp(word[first + 1], "<>C") || !strcmp(word[first + 1], "!=C")) {
if (strcmp(index, compare))
return (TRUE);
else
return (FALSE);
} else {
sprintf(error_buffer,
"ERROR: In function \"%s\", illegal operator \"%s\".^",
executing_function->name, word[2]);
write_text(error_buffer);
return (FALSE);
}
}
void add_cinteger(const char *name, int value) {
/* THIS FUNCTION ADDS A NEW JACL CONSTANT TO THE LIST */
if ((new_cinteger = (struct cinteger_type *)
malloc(sizeof(struct cinteger_type))) == NULL)
outofmem();
else {
if (cinteger_table == NULL) {
cinteger_table = new_cinteger;
} else {
/* FIND LAST CONSTANT IN LIST */
current_cinteger = cinteger_table;
while (current_cinteger->next_cinteger != NULL) {
current_cinteger = current_cinteger->next_cinteger;
}
current_cinteger->next_cinteger = new_cinteger;
}
strncpy(new_cinteger->name, name, 40);
new_cinteger->name[40] = 0;
new_cinteger->value = value;
new_cinteger->next_cinteger = NULL;
}
}
void clear_cinteger(const char *name) {
/* FREE CONSTANTS THAT HAVE SUPPLIED NAME*/
//printf("--- clear integer %s\n", name);
if (cinteger_table != NULL) {
current_cinteger = cinteger_table;
previous_cinteger = cinteger_table;
while (current_cinteger != NULL) {
//sprintf(temp_buffer, "--- checking integer %s^", current_cinteger->name);
//write_text(temp_buffer);
if (!strcmp(current_cinteger->name, name)) {
//sprintf(temp_buffer, "--- found integer %s^", name);
//write_text(temp_buffer);
/* FREE THIS CONSTANT */
if (previous_cinteger == current_cinteger) {
// THE INTEGER BEING CLEARED IS THE FIRST INTEGER IN THE LIST
cinteger_table = current_cinteger->next_cinteger;
previous_cinteger = current_cinteger->next_cinteger;
free(current_cinteger);
current_cinteger = previous_cinteger;
} else {
previous_cinteger->next_cinteger = current_cinteger->next_cinteger;
free(current_cinteger);
current_cinteger = previous_cinteger->next_cinteger;
}
} else {
previous_cinteger = current_cinteger;
current_cinteger = current_cinteger->next_cinteger;
}
}
}
//printf("--- leaving clear integer\n");
}
void add_cstring(const char *name, const char *value) {
/* ADD A STRING CONSTANT WITH THE SUPPLIED NAME AND VALUE */
if ((new_string = (struct string_type *)
malloc(sizeof(struct string_type))) == NULL)
outofmem();
else {
if (cstring_table == NULL) {
cstring_table = new_string;
} else {
/* FIND LAST STRING IN LIST */
current_cstring = cstring_table;
while (current_cstring->next_string != NULL) {
current_cstring = current_cstring->next_string;
}
current_cstring->next_string = new_string;
}
strncpy(new_string->name, name, 40);
new_string->name[40] = 0;
strncpy(new_string->value, value, 255);
new_string->value[255] = 0;
new_string->next_string = NULL;
}
}
void clear_cstring(const char *name) {
/* FREE CONSTANTS THAT HAVE SUPPLIED NAME*/
if (cstring_table != NULL) {
current_cstring = cstring_table;
previous_cstring = cstring_table;
while (current_cstring != NULL) {
if (!strcmp(current_cstring->name, name)) {
/* FREE THIS STRING */
if (previous_cstring == current_cstring) {
cstring_table = current_cstring->next_string;
previous_cstring = current_cstring->next_string;
free(current_cstring);
current_cstring = previous_cstring;
} else {
previous_cstring->next_string = current_cstring->next_string;
free(current_cstring);
current_cstring = previous_cstring->next_string;
}
} else {
previous_cstring = current_cstring;
current_cstring = current_cstring->next_string;
}
}
}
}
void inspect(int object_num) {
// THIS FUNCTION DISPLAYS THE STATE OF A JACL OBJECT FOR DEBUGGING
int index, attribute_value;
struct attribute_type *pointer = attribute_table;
if (object_num < 1 || object_num > objects) {
badptrrun(word[1], object_num);
return;
}
write_text("label: ");
write_text(object[object_num]->label);
if (object[object_num]->attributes & LOCATION) {
// OUTPUT ALL THE ATTRIBUTES WITH LOCATION ATTRIBUTE TEXT
write_text("^has location attributes: ");
index = 0;
attribute_value = 1;
while (location_attributes[index] != NULL) {
if (object[object_num]->attributes & attribute_value) {
write_text(location_attributes[index]);
}
index++;
attribute_value *= 2;
}
} else {
// OUTPUT ALL THE ATTRIBUTES WITH OBJECT ATTRIBUTE TEXT
write_text("^has object attributes: ");
index = 0;
attribute_value = 1;
while (object_attributes[index] != NULL) {
if (object[object_num]->attributes & attribute_value) {
write_text(object_attributes[index]);
}
index++;
attribute_value *= 2;
}
write_text("^has user attributes: ");
attribute_value = 1;
}
if (pointer != NULL) {
// THERE ARE USER ATTRIBUTES, SO CHECK IF THIS OBJECT OR LOCATION
// HAS ANY OF THEM
do {
if (object[object_num]->user_attributes & pointer->value) {
write_text(pointer->name);
write_text(" ");
}
pointer = pointer->next_attribute;
} while (pointer != NULL);
}
write_text("^");
index = 0;
if (object[object_num]->attributes & LOCATION) {
while (location_elements[index] != NULL) {
if (index < 12) {
if (object[object_num]->integer[index] < 1 || object[object_num]->integer[index] > objects) {
sprintf(temp_buffer, "%s: nowhere (%d)^", location_elements[index], object[object_num]->integer[index]);
} else {
sprintf(temp_buffer, "%s: %s (%d)^", location_elements[index], object[object[object_num]->integer[index]]->label, object[object_num]->integer[index]);
}
} else {
sprintf(temp_buffer, "%s: %d^", location_elements[index], object[object_num]->integer[index]);
}
write_text(temp_buffer);
index++;
}
} else {
while (object_elements[index] != NULL) {
if (index == 0) {
sprintf(temp_buffer, "%s: %s (%d)^", object_elements[index], object[object[object_num]->integer[index]]->label, object[object_num]->integer[index]);
} else {
sprintf(temp_buffer, "%s: %d^", object_elements[index], object[object_num]->integer[index]);
}
write_text(temp_buffer);
index++;
}
}
}
int grand_of(int child, int objs_only) {
/* THIS FUNCTION WILL CLIMB THE OBJECT TREE STARTING AT 'CHILD' UNTIL
* A 'PARENT' IS REACHED */
/* objs_only ARGUMENT TELLS FUNCTION TO IGNORE OBJECT IF IT IS IN A
* LOCATION */
int parent;
if (object[child]->PARENT != NOWHERE) {
/* STORE THE CHILDS PARENT OBJECT */
parent = object[child]->PARENT;
if (object[parent]->attributes & LOCATION) {
if (objs_only) {
/* THE CHILDS PARENT IS LOCATION AND SEARCH IS RESTRICTED TO
* OBJECTS */
return (child);
} else {
return (parent);
}
} else {
/* KEEP LOOKING UP THE TREE UNTIL THE CHILD HAS NO
* PARENT */
return (grand_of(parent, objs_only));
}
} else {
/* THE SPECIFIED OBJECT HAS NO PARENT */
return (child);
}
}
int select_next() {
while (++*select_integer <= objects) {
switch (criterion_type) {
case CRI_ATTRIBUTE:
if (object[*select_integer]->attributes & criterion_value) {
if (!criterion_negate) {
return TRUE;
}
} else {
if (criterion_negate) {
return TRUE;
}
}
break;
case CRI_USER_ATTRIBUTE:
if (object[*select_integer]->user_attributes & criterion_value) {
if (!criterion_negate) {
return TRUE;
}
} else {
if (criterion_negate) {
return TRUE;
}
}
break;
case CRI_PARENT:
if (object[*select_integer]->PARENT == criterion_value) {
if (!criterion_negate) {
return TRUE;
}
} else {
if (criterion_negate) {
return TRUE;
}
}
break;
case CRI_SCOPE:
if (scope(*select_integer, scope_criterion)) {
if (!criterion_negate) {
return TRUE;
}
} else {
if (criterion_negate) {
return TRUE;
}
}
break;
default:
break;
}
}
return (FALSE);
}
/* Converts an integer value to its hex character*/
char to_hex(char code) {
static char hex[] = "0123456789abcdef";
return hex[code & 15];
}
/* Returns a url-encoded version of str */
/* IMPORTANT: be sure to free() the returned string after use */
char *url_encode(char *str) {
char *pstr = str, *buf = (char *)malloc(strlen(str) * 3 + 1), *pbuf = buf;
while (*pstr) {
if (Common::isAlnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~')
*pbuf++ = *pstr;
else if (*pstr == ' ')
*pbuf++ = '+';
else
*pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
pstr++;
}
*pbuf = '\0';
return buf;
}
} // End of namespace JACL
} // End of namespace Glk