1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "glk/jacl/jacl.h"
24 #include "glk/jacl/language.h"
25 #include "glk/jacl/types.h"
26 #include "glk/jacl/prototypes.h"
27 
28 namespace Glk {
29 namespace JACL {
30 
31 #ifdef GLK
32 extern uint                     status_width, status_height;
33 extern winid_t                  statuswin;
34 #endif
35 
36 #ifdef __NDS__
37 extern int                      screen_width;
38 extern int                      screen_depth;
39 #endif
40 
41 extern struct object_type       *object[];
42 extern struct integer_type      *integer_table;
43 extern struct integer_type      *integer[];
44 extern struct cinteger_type     *cinteger_table;
45 extern struct attribute_type    *attribute_table;
46 extern struct string_type       *string_table;
47 extern struct string_type       *cstring_table;
48 extern struct function_type     *function_table;
49 extern struct function_type     *executing_function;
50 extern struct command_type      *completion_list;
51 extern struct word_type         *grammar_table;
52 extern struct synonym_type      *synonym_table;
53 extern struct filter_type       *filter_table;
54 
55 extern char                     function_name[];
56 extern char                     temp_buffer[];
57 extern char                     error_buffer[];
58 extern char                     integer_buffer[16];
59 
60 #ifndef GLK
61 #ifndef __NDS__
62 extern char                     game_url[];
63 extern char                     user_id[];
64 #endif
65 #endif
66 
67 extern int                      noun[];
68 extern int                      quoted[];
69 extern int                      percented[];
70 extern const char               *word[];
71 
72 extern int                      resolved_attribute;
73 
74 extern int                      objects;
75 extern int                      integers;
76 extern int                      player;
77 extern int                      oec;
78 extern int                      *object_element_address;
79 extern int                      *object_backup_address;
80 
81 extern int                      value_resolved;
82 
83 char                            macro_function[84];
84 int                             value_has_been_resolved;
85 
container_resolve(const char * container_name)86 int *container_resolve(const char *container_name) {
87 	container_name = arg_text_of(container_name);
88 
89 	/* IN JACL, A 'CONTAINER' IS ANYTHING THAT CAN STORE AN INTEGER */
90 	struct integer_type *resolved_integer;
91 
92 	if ((resolved_integer = integer_resolve(container_name)) != NULL)
93 		return (&resolved_integer->value);
94 	else if (object_element_resolve(container_name))
95 		return (object_element_address);
96 	else if (!strcmp(container_name, "noun1"))
97 		return (&noun[0]);
98 	else if (!strcmp(container_name, "noun2"))
99 		return (&noun[1]);
100 	else if (!strcmp(container_name, "noun3"))
101 		return (&noun[2]);
102 	else if (!strcmp(container_name, "noun4"))
103 		return (&noun[3]);
104 	else if (!strcmp(container_name, "player"))
105 		return (&player);
106 	else if (!strcmp(container_name, "here"))
107 		return (&object[player]->PARENT);
108 	else
109 		return ((int *) NULL);
110 }
111 
var_text_of_word(int wordnumber)112 const char *var_text_of_word(int wordnumber) {
113 	const char *value;
114 
115 	if (percented[wordnumber] == FALSE) {
116 		return (word[wordnumber]);
117 	} else {
118 		value_has_been_resolved = TRUE;
119 		value = arg_text_of(word[wordnumber]);
120 		while (value_has_been_resolved && percented[wordnumber]) {
121 			value = arg_text_of(value);
122 			percented[wordnumber]--;
123 		}
124 
125 		return (value);
126 	}
127 }
128 
arg_text_of_word(int wordnumber)129 const char *arg_text_of_word(int wordnumber) {
130 	const char *value;
131 
132 	if (quoted[wordnumber] == 1) {
133 		return (word[wordnumber]);
134 	} else {
135 		value_has_been_resolved = TRUE;
136 		value = arg_text_of(word[wordnumber]);
137 		while (value_has_been_resolved && percented[wordnumber]) {
138 			value = arg_text_of(value);
139 			percented[wordnumber]--;
140 		}
141 
142 		return (value);
143 	}
144 }
145 
text_of_word(int wordnumber)146 const char *text_of_word(int wordnumber) {
147 	const char *value;
148 
149 	if (quoted[wordnumber] == 1) {
150 		return (word[wordnumber]);
151 	} else {
152 		value_has_been_resolved = TRUE;
153 		value = text_of(word[wordnumber]);
154 		while (value_has_been_resolved && percented[wordnumber]) {
155 			value = text_of(value);
156 			percented[wordnumber]--;
157 		}
158 
159 		return (value);
160 	}
161 }
162 
text_of(const char * string)163 const char *text_of(const char *string) {
164 	struct integer_type *resolved_integer;
165 	struct cinteger_type *resolved_cinteger;
166 	struct string_type *resolved_string;
167 	struct string_type *resolved_cstring;
168 	char            *return_string;
169 
170 	int             index;
171 
172 	/* CHECK IF THE SUPPLIED STRING IS THE NAME OF A STRING CONSTANT,
173 	 * IF NOT, RETURN THE STRING LITERAL */
174 	if ((return_string = macro_resolve(string)) != NULL) {
175 		value_has_been_resolved = FALSE;
176 		return (return_string);
177 	} else if ((resolved_integer = integer_resolve(string)) != NULL) {
178 		value_has_been_resolved = FALSE;
179 		integer_buffer[0] = 0;
180 		sprintf(integer_buffer, "%d", resolved_integer->value);
181 		return (integer_buffer);
182 	} else if ((resolved_cinteger = cinteger_resolve(string)) != NULL) {
183 		value_has_been_resolved = FALSE;
184 		integer_buffer[0] = 0;
185 		sprintf(integer_buffer, "%d", resolved_cinteger->value);
186 		return (integer_buffer);
187 	} else if (object_element_resolve(string)) {
188 		value_has_been_resolved = FALSE;
189 		integer_buffer[0] = 0;
190 		sprintf(integer_buffer, "%d", oec);
191 		return (integer_buffer);
192 	} else if ((index = object_resolve(string)) != -1) {
193 		value_has_been_resolved = FALSE;
194 		if (index < 1 || index > objects) {
195 			badptrrun(string, index);
196 			return ("");
197 		} else {
198 			return (object[index]->label);
199 		}
200 	} else if ((resolved_string = string_resolve(string)) != NULL) {
201 		return (resolved_string->value);
202 	} else if ((resolved_cstring = cstring_resolve(string)) != NULL) {
203 		return (resolved_cstring->value);
204 	} else if (function_resolve(string) != NULL) {
205 		value_has_been_resolved = FALSE;
206 		sprintf(integer_buffer, "%d", execute(string));
207 		return (integer_buffer);
208 #ifndef GLK
209 #ifndef __NDS__
210 	} else if (!strcmp(string, "$url")) {
211 		value_has_been_resolved = FALSE;
212 		return (game_url);
213 	} else if (!strcmp(string, "$user_id")) {
214 		value_has_been_resolved = FALSE;
215 		return (user_id);
216 #endif
217 #endif
218 	} else {
219 		value_has_been_resolved = FALSE;
220 		return (string);
221 	}
222 }
223 
arg_text_of(const char * string)224 const char *arg_text_of(const char *string) {
225 	struct string_type *resolved_string;
226 	struct string_type *resolved_cstring;
227 	char               *macro_text;
228 
229 	/* CHECK IF THE SUPPLIED STRING IS THE NAME OF A STRING CONSTANT,
230 	 * IF NOT, RETURN THE STRING LITERAL */
231 	if ((macro_text = macro_resolve(string)) != NULL) {
232 		value_has_been_resolved = FALSE;
233 		return (macro_text);
234 	} else if ((resolved_string = string_resolve(string)) != NULL) {
235 		return (resolved_string->value);
236 	} else if ((resolved_cstring = cstring_resolve(string)) != NULL) {
237 		value_has_been_resolved = FALSE;
238 		return (resolved_cstring->value);
239 	} else {
240 		value_has_been_resolved = FALSE;
241 		return (string);
242 	}
243 }
244 
validate(const char * string)245 int validate(const char *string) {
246 	int             index,
247 	                count;
248 
249 	if (string == NULL) {
250 		return (FALSE);
251 	}
252 
253 	/* CHECK IF THE SUPPLIED STRING IS A VALID INTEGER */
254 	count = strlen(string);
255 
256 	/* LOOP OVER THE WHOLE STRING MAKING SURE THAT EACH CHARACTER IS EITHER
257 	 * A DIGIT OR A MINUS SIGN */
258 	for (index = 0; index < count; index++) {
259 		if (!Common::isDigit((int) * (string + index)) && string[index] != '-') {
260 			//printf ("'%c' is not a digit\n", *(string + index));
261 			return (FALSE);
262 		}
263 	}
264 
265 	return (TRUE);
266 }
267 
value_of(const char * value,int run_time)268 long value_of(const char *value, int run_time) {
269 	long            compare;
270 
271 	value_resolved = TRUE;
272 
273 	value = arg_text_of(value);
274 
275 	/* RETURN THE INTEGER VALUE OF A STRING */
276 	struct integer_type *resolved_integer;
277 	struct cinteger_type *resolved_cinteger;
278 
279 	if (!strcmp(value, "**held")) {
280 		return (FALSE);
281 	} else if (!strcmp(value, "**here")) {
282 		return (FALSE);
283 	} else if (!strcmp(value, "**anywhere")) {
284 		return (FALSE);
285 	} else if (!strcmp(value, "**present")) {
286 		return (FALSE);
287 	} else if (!strcmp(value, "*held")) {
288 		return (FALSE);
289 	} else if (!strcmp(value, "*here")) {
290 		return (FALSE);
291 	} else if (!strcmp(value, "*anywhere")) {
292 		return (FALSE);
293 	} else if (!strcmp(value, "*present")) {
294 		return (FALSE);
295 	} else if (!strcmp(value, "random")) {
296 		return random_number();
297 #ifdef GLK
298 	} else if (!strcmp(value, "status_height")) {
299 		g_vm->glk_window_get_size(statuswin, &status_width, &status_height);
300 		return status_height;
301 	} else if (!strcmp(value, "status_width")) {
302 		g_vm->glk_window_get_size(statuswin, &status_width, &status_height);
303 		return status_width;
304 #else
305 #ifdef __NDS__
306 	} else if (!strcmp(value, "status_height")) {
307 		return screen_depth;
308 	} else if (!strcmp(value, "status_width")) {
309 		return screen_width;
310 #else
311 	} else if (!strcmp(value, "status_height")) {
312 		value_resolved = FALSE;
313 		return -1;
314 	} else if (!strcmp(value, "status_width")) {
315 		value_resolved = FALSE;
316 		return -1;
317 #endif
318 #endif
319 	} else if (!strcmp(value, "unixtime")) {
320 		return g_system->getMillis() / 1000;
321 	} else if (validate(value)) {
322 		return (atoi(value));
323 	} else if ((resolved_cinteger = cinteger_resolve(value)) != NULL) {
324 		return (resolved_cinteger->value);
325 	} else if ((resolved_integer = integer_resolve(value)) != NULL) {
326 		return (resolved_integer->value);
327 	} else if (function_resolve(value) != NULL) {
328 		return (execute(value));
329 	} else if (object_element_resolve(value)) {
330 		return (oec);
331 	} else if ((compare = attribute_resolve(value))) {
332 		resolved_attribute = SYSTEM_ATTRIBUTE;
333 		return (compare);
334 	} else if ((compare = user_attribute_resolve(value))) {
335 		resolved_attribute = USER_ATTRIBUTE;
336 		return (compare);
337 	} else if ((compare = object_resolve(value)) != -1) {
338 		return (compare);
339 	} else if (*value == '@') {
340 		return (count_resolve(value));
341 	} else {
342 		if (run_time) {
343 			unkvarrun(value);
344 		}
345 		value_resolved = FALSE;
346 		return (-1);
347 	}
348 }
349 
integer_resolve(const char * name)350 struct integer_type *integer_resolve(const char *name) {
351 	int             index,
352 	                iterator,
353 	                counter;
354 	int             delimiter = 0;
355 	char            expression[84];
356 
357 	strncpy(expression, name, 80);
358 
359 	counter = strlen(expression);
360 
361 	for (index = 0; index < counter; index++) {
362 		if (expression[index] == '[') {
363 			/* THIS MAY STILL BE AN OBJECT ELEMENT IF A CLOSING ] */
364 			/* IS FOUND BEFORE AN OPENING ( */
365 			expression[index] = 0;
366 			delimiter = index + 1;
367 			/* LOOK FOR THE CLOSING ], BUT IF YOU FIND A ( FIRST */
368 			/* THEN THIS EXPRESSION IS NOT AN ARRAY */
369 			for (iterator = counter; iterator > 0; iterator--) {
370 				if (expression[iterator] == ']') {
371 					expression[iterator] = 0;
372 					break;
373 				} else if (expression[iterator] == '(') {
374 					/* NOT A VARIABLE ARRAY */
375 					return (FALSE);
376 				}
377 			}
378 			break;
379 		} else if (expression[index] == '<') {
380 			/* HIT A < BEFORE A [ THEREFORE */
381 			/* IS A FUNCTION CALL, NOT AN ARRAY */
382 			return (NULL);
383 		} else if (expression[index] == '(') {
384 			/* HIT A ( BEFORE A [ THEREFORE */
385 			/* IS AN OBJECT ELEMENT, NOT AN ARRAY */
386 			return (NULL);
387 		} else if (expression[index] == ' ')
388 			return (NULL);
389 	}
390 
391 	// NO DELIMITER FOUND, TRY AS UNINDEXED VARIABLE
392 	if (delimiter == 0) {
393 		return (integer_resolve_indexed(name, 0));
394 	}
395 
396 	// NO STRING BEFORE DELIMITER
397 	if (delimiter == 1) {
398 		return (NULL);
399 	}
400 
401 	counter = value_of(&expression[delimiter], TRUE);
402 
403 	if (counter > -1) {
404 		return (integer_resolve_indexed(expression, counter));
405 	} else {
406 		/* INDEX OUT OF RANGE */
407 		return (NULL);
408 	}
409 }
410 
integer_resolve_indexed(const char * name,int index)411 struct integer_type *integer_resolve_indexed(const char *name, int index) {
412 	struct integer_type *pointer = integer_table;
413 
414 	if (pointer == NULL)
415 		return (NULL);
416 
417 	do {
418 		if (!strcmp(name, pointer->name)) {
419 			if (index == 0) {
420 				return (pointer);
421 			} else {
422 				/* THIS VARIABLE DOES MATCH, BUT WERE NOT AT THE
423 				 * RIGHT INDEX YET SO MOVE ON */
424 				pointer = pointer->next_integer;
425 				index--;
426 			}
427 		} else
428 			pointer = pointer->next_integer;
429 	} while (pointer != NULL);
430 
431 	/* IF index != 0, INDEX OUT OF RANGE, OTHERWISE NOT VARIABLE */
432 	return (NULL);
433 }
434 
cinteger_resolve(const char * name)435 struct cinteger_type *cinteger_resolve(const char *name) {
436 	int             index,
437 	                iterator,
438 	                counter;
439 	int             delimiter = 0;
440 	char            expression[84];
441 
442 	strncpy(expression, name, 80);
443 
444 	counter = strlen(expression);
445 
446 	for (index = 0; index < counter; index++) {
447 		if (expression[index] == '[') {
448 			/* THIS MAY STILL BE AN OBJECT ELEMENT IF A CLOSING ] */
449 			/* IS FOUND BEFORE AN OPENING ( */
450 			expression[index] = 0;
451 			delimiter = index + 1;
452 			/* LOOK FOR THE CLOSING ], BUT IF YOU FIND A ( FIRST */
453 			/* THEN THIS EXPRESSION IS NOT AN ARRAY */
454 			for (iterator = counter; iterator > 0; iterator--) {
455 				if (expression[iterator] == ']') {
456 					expression[iterator] = 0;
457 					break;
458 				} else if (expression[iterator] == '(') {
459 					/* NOT A CONSTANT ARRAY */
460 					return (FALSE);
461 				}
462 			}
463 			break;
464 		} else if (expression[index] == '<') {
465 			/* HIT A < BEFORE A [ THEREFORE */
466 			/* IS A FUNCTION CALL, NOT AN ARRAY */
467 			return (NULL);
468 		} else if (expression[index] == '(') {
469 			/* HIT A ( BEFORE A [ THEREFORE */
470 			/* IS AN OBJECT ELEMENT, NOT AN ARRAY */
471 			return (NULL);
472 		} else if (expression[index] == ' ')
473 			return (NULL);
474 	}
475 
476 	// NO DELIMITER FOUND, TRY AS UNINDEXED CONSTANT
477 	if (delimiter == 0) {
478 		return (cinteger_resolve_indexed(name, 0));
479 	}
480 
481 	// NO STRING BEFORE DELIMITER
482 	if (delimiter == 1) {
483 		return (NULL);
484 	}
485 
486 	counter = value_of(&expression[delimiter], TRUE);
487 
488 	if (counter > -1) {
489 		return (cinteger_resolve_indexed(expression, counter));
490 	} else {
491 		/* INDEX OUT OF RANGE */
492 		return (NULL);
493 	}
494 }
495 
cinteger_resolve_indexed(const char * name,int index)496 struct cinteger_type *cinteger_resolve_indexed(const char *name, int index) {
497 	struct cinteger_type *pointer = cinteger_table;
498 
499 	if (pointer == NULL)
500 		return (NULL);
501 
502 	do {
503 		if (!strcmp(name, pointer->name)) {
504 			if (index == 0) {
505 				return (pointer);
506 			} else {
507 				/* THIS VARIABLE DOES MATCH, BUT WERE NOT AT THE
508 				 * RIGHT INDEX YET SO MOVE ON */
509 				pointer = pointer->next_cinteger;
510 				index--;
511 			}
512 		} else
513 			pointer = pointer->next_cinteger;
514 	} while (pointer != NULL);
515 
516 	/* IF index != 0, INDEX OUT OF RANGE, OTHERWISE NOT VARIABLE */
517 	return (NULL);
518 }
519 
string_resolve(const char * name)520 struct string_type *string_resolve(const char *name) {
521 	int             index,
522 	                iterator,
523 	                counter;
524 	int             delimiter = 0;
525 	char            expression[84];
526 
527 	strncpy(expression, name, 80);
528 
529 	counter = strlen(expression);
530 
531 	for (index = 0; index < counter; index++) {
532 		if (expression[index] == '[') {
533 			expression[index] = 0;
534 			delimiter = index + 1;
535 			for (iterator = counter; iterator > 0; iterator--) {
536 				if (expression[iterator] == ']') {
537 					expression[iterator] = 0;
538 					break;
539 				}
540 			}
541 			break;
542 		} else if (expression[index] == '<') {
543 			/* HIT A < BEFORE A [ THEREFORE */
544 			/* IS A FUNCTION CALL, NOT AN ARRAY */
545 			return (NULL);
546 		} else if (expression[index] == '(') {
547 			/* HIT A ( BEFORE A [ THEREFORE */
548 			/* IS AN OBJECT ELEMENT, NOT AN ARRAY */
549 			return (NULL);
550 		} else if (expression[index] == ' ')
551 			return (NULL);
552 	}
553 
554 	if (delimiter == 0) {
555 		/* NO DELIMITER FOUND, TRY AS UNINDEXED VARIABLE */
556 		return (string_resolve_indexed(name, 0));
557 	}
558 
559 	if (delimiter == 1) {
560 		/* NO STRING BEFORE DELIMITER */
561 		return (NULL);
562 	}
563 
564 	counter = value_of(&expression[delimiter], TRUE);
565 
566 	if (counter > -1) {
567 		return (string_resolve_indexed(expression, counter));
568 	} else
569 		return (NULL);
570 }
571 
string_resolve_indexed(const char * name,int index)572 struct string_type *string_resolve_indexed(const char *name, int index) {
573 	struct string_type *pointer = string_table;
574 
575 	if (pointer == NULL)
576 		return (NULL);
577 
578 	do {
579 		if (!strcmp(name, pointer->name)) {
580 			if (index == 0) {
581 				return (pointer);
582 			} else {
583 				/* THIS STRING DOES MATCH, BUT WERE NOT AT THE
584 				 * RIGHT INDEX YET SO MOVE ON */
585 				pointer = pointer->next_string;
586 				index--;
587 			}
588 		} else {
589 			pointer = pointer->next_string;
590 		}
591 	} while (pointer != NULL);
592 
593 	return (NULL);
594 }
595 
cstring_resolve(const char * name)596 struct string_type *cstring_resolve(const char *name) {
597 	int             index,
598 	                iterator,
599 	                counter;
600 	int             delimiter = 0;
601 	char            expression[84];
602 
603 	strncpy(expression, name, 80);
604 
605 	counter = strlen(expression);
606 
607 	for (index = 0; index < counter; index++) {
608 		if (expression[index] == '[') {
609 			expression[index] = 0;
610 			delimiter = index + 1;
611 			for (iterator = counter; iterator > 0; iterator--) {
612 				if (expression[iterator] == ']') {
613 					expression[iterator] = 0;
614 					break;
615 				}
616 			}
617 			break;
618 		} else if (expression[index] == '<') {
619 			/* HIT A < BEFORE A [ THEREFORE */
620 			/* IS A FUNCTION CALL, NOT AN ARRAY */
621 			return (NULL);
622 		} else if (expression[index] == '(') {
623 			/* HIT A ( BEFORE A [ THEREFORE */
624 			/* IS AN OBJECT ELEMENT, NOT AN ARRAY */
625 			return (NULL);
626 		} else if (expression[index] == ' ')
627 			return (NULL);
628 	}
629 
630 	if (delimiter == 0) {
631 		/* NO DELIMITER FOUND, TRY AS UNINDEXED VARIABLE */
632 		return (cstring_resolve_indexed(name, 0));
633 	}
634 
635 	if (delimiter == 1) {
636 		/* NO STRING BEFORE DELIMITER */
637 		return (NULL);
638 	}
639 
640 	counter = value_of(&expression[delimiter], TRUE);
641 
642 	if (counter > -1) {
643 		return (cstring_resolve_indexed(expression, counter));
644 	} else
645 		return (NULL);
646 }
647 
cstring_resolve_indexed(const char * name,int index)648 struct string_type *cstring_resolve_indexed(const char *name, int index) {
649 	struct string_type *pointer = cstring_table;
650 
651 	if (pointer == NULL)
652 		return (NULL);
653 
654 	do {
655 		if (!strcmp(name, pointer->name)) {
656 			if (index == 0) {
657 				return (pointer);
658 			} else {
659 				/* THIS STRING DOES MATCH, BUT WERE NOT AT THE
660 				 * RIGHT INDEX YET SO MOVE ON */
661 				pointer = pointer->next_string;
662 				index--;
663 			}
664 		} else {
665 			pointer = pointer->next_string;
666 		}
667 	} while (pointer != NULL);
668 
669 	return (NULL);
670 }
671 
function_resolve(const char * name)672 struct function_type *function_resolve(const char *name) {
673 	const char      *full_name;
674 	char            core_name[84];
675 	int             index;
676 
677 	struct function_type *pointer = function_table;
678 
679 	if (function_table == NULL)
680 		return (NULL);
681 
682 	/* STRIP ARGUMENTS OFF FIRST, THEN EXPAND RESOLVE NAME */
683 	index = 0;
684 
685 	while (*name && index < 80) {
686 		if (*name == '<') {
687 			break;
688 		} else {
689 			core_name[index++] = *name++;
690 		}
691 	}
692 	core_name[index] = 0;
693 
694 	/* GET A POINTER TO A STRING THAT REPRESENTS THE EXPANDED NAME OF THE FUNCTION */
695 	full_name = (const char *)expand_function(core_name);
696 
697 	/* LOOP THROUGH ALL THE FUNCTIONS LOOKING FOR A FUNCTION THAT
698 	 * HAS THIS EXPANDED FULL NAME */
699 	do {
700 		if (!strcmp(full_name, pointer->name))
701 			return (pointer);
702 		else
703 			pointer = pointer->next_function;
704 	} while (pointer != NULL);
705 
706 	/* RETURN A POINTER TO THE STRUCTURE THAT ENCAPSULATES THE FUNCTION */
707 	return (NULL);
708 }
709 
expand_function(const char * name)710 const char *expand_function(const char *name) {
711 	/* THIS FUNCTION TAKES A SCOPE FUNCTION CALL SUCH AS noun1.function
712 	 * AND REOLVE THE ACTUAL FUNCTION NAME SUCH AS function_key */
713 	int             index,
714 	                counter;
715 	int             delimiter = 0;
716 	char            expression[84];
717 
718 	strncpy(expression, name, 80);
719 
720 	counter = strlen(expression);
721 
722 	for (index = 0; index < counter; index++) {
723 		if (expression[index] == '.') {
724 			expression[index] = 0;
725 			delimiter = index + 1;
726 			break;
727 		}
728 	}
729 
730 	if (delimiter == FALSE) {
731 		/* THIS FUNCTION DOESN'T CONTAIN A '.', SO RETURN IT AS IS */
732 		return (arg_text_of(name));
733 	}
734 
735 	/* THE ORIGINAL STRING IS NOW CUT INTO TWO STRINGS:
736 	 * expression.delimiter */
737 
738 	index = value_of(expression, TRUE);
739 
740 	if (index < 1 || index > objects) {
741 		return ((const char *) name);
742 	}
743 
744 	if (cinteger_resolve(&expression[delimiter]) != NULL ||
745 	        integer_resolve(&expression[delimiter]) != NULL ||
746 	        object_element_resolve(&expression[delimiter])) {
747 		/* THE DELIMETER RESOLVES TO A CONSTANT, VARIABLE OR OBJECT
748 		 * ELEMENT, SO TAKE NOTE OF THAT */
749 		sprintf(function_name, "%ld", value_of(&expression[delimiter], TRUE));
750 	} else {
751 		strcpy(function_name, &expression[delimiter]);
752 	}
753 	strcat(function_name, "_");
754 	strcat(function_name, object[index]->label);
755 
756 	return ((const char *) function_name);
757 }
758 
macro_resolve(const char * testString)759 char *macro_resolve(const char *testString) {
760 	int             index,
761 	                counter;
762 	int             delimiter = 0;
763 	char            expression[84];
764 
765 	strncpy(expression, testString, 80);
766 
767 	counter = strlen(expression);
768 
769 	for (index = 0; index < counter; index++) {
770 		if (expression[index] == '{' || expression[index] == '}') {
771 			expression[index] = 0;
772 			if (!delimiter)
773 				delimiter = index + 1;
774 		}
775 	}
776 
777 	if (delimiter == FALSE)
778 		return (NULL);
779 
780 	if (*expression != 0) {
781 		index = value_of(expression, TRUE);
782 	} else {
783 		index = 0;
784 	}
785 
786 	if (!strcmp(&expression[delimiter], "list")) {
787 		if (index < 1 || index > objects) {
788 			badptrrun(expression, index);
789 			return (NULL);
790 		} else {
791 			return (list_output(index, FALSE));
792 		}
793 	} else if (!strcmp(&expression[delimiter], "plain")) {
794 		if (index < 1 || index > objects) {
795 			badptrrun(expression, index);
796 			return (NULL);
797 		} else {
798 			return (plain_output(index, FALSE));
799 		}
800 	} else if (!strcmp(&expression[delimiter], "long")) {
801 		if (index < 1 || index > objects) {
802 			badptrrun(expression, index);
803 			return (NULL);
804 		} else {
805 			return (long_output(index));
806 		}
807 	} else if (!strcmp(&expression[delimiter], "sub")) {
808 		if (index < 1 || index > objects) {
809 			badptrrun(expression, index);
810 			return (NULL);
811 		} else {
812 			return (sub_output(index, FALSE));
813 		}
814 	} else if (!strcmp(&expression[delimiter], "obj")) {
815 		if (index < 1 || index > objects) {
816 			badptrrun(expression, index);
817 			return (NULL);
818 		} else {
819 			return (obj_output(index, FALSE));
820 		}
821 	} else if (!strcmp(&expression[delimiter], "that")) {
822 		if (index < 1 || index > objects) {
823 			badptrrun(expression, index);
824 			return (NULL);
825 		} else {
826 			return (that_output(index, FALSE));
827 		}
828 	} else if (!strcmp(&expression[delimiter], "it")) {
829 		if (index < 1 || index > objects) {
830 			badptrrun(expression, index);
831 			return (NULL);
832 		} else {
833 			return (it_output(index, FALSE));
834 		}
835 	} else if (!strcmp(&expression[delimiter], "doesnt")) {
836 		if (index < 1 || index > objects) {
837 			badptrrun(expression, index);
838 			return (NULL);
839 		} else {
840 			return (doesnt_output(index, FALSE));
841 		}
842 	} else if (!strcmp(&expression[delimiter], "does")) {
843 		if (index < 1 || index > objects) {
844 			badptrrun(expression, index);
845 			return (NULL);
846 		} else {
847 			return (does_output(index, FALSE));
848 		}
849 	} else if (!strcmp(&expression[delimiter], "isnt")) {
850 		if (index < 1 || index > objects) {
851 			badptrrun(expression, index);
852 			return (NULL);
853 		} else {
854 			return (isnt_output(index, FALSE));
855 		}
856 	} else if (!strcmp(&expression[delimiter], "is")) {
857 		if (index < 1 || index > objects) {
858 			badptrrun(expression, index);
859 			return (NULL);
860 		} else {
861 			return (is_output(index, FALSE));
862 		}
863 	} else if (!strcmp(&expression[delimiter], "the")) {
864 		if (index < 1 || index > objects) {
865 			badptrrun(expression, index);
866 			return (NULL);
867 		} else {
868 			return (sentence_output(index, FALSE));
869 		}
870 	} else if (!strcmp(&expression[delimiter], "s")) {
871 		if (index < 1 || index > objects) {
872 			badptrrun(expression, index);
873 			return (NULL);
874 		} else {
875 			if (object[index]->attributes & PLURAL) {
876 				strcpy(temp_buffer, "");
877 			} else {
878 				strcpy(temp_buffer, "s");
879 			}
880 			return (temp_buffer);
881 		}
882 	} else if (!strcmp(&expression[delimiter], "names")) {
883 		if (index < 1 || index > objects) {
884 			badptrrun(expression, index);
885 			return (NULL);
886 		} else {
887 			return (object_names(index, temp_buffer));
888 		}
889 	} else if (!strcmp(&expression[delimiter], "label")) {
890 		if (index < 1 || index > objects) {
891 			badptrrun(expression, index);
892 			return (NULL);
893 		} else {
894 			return (object[index]->label);
895 		}
896 	} else if (!strcmp(&expression[delimiter], "List")) {
897 		if (index < 1 || index > objects) {
898 			badptrrun(expression, index);
899 			return (NULL);
900 		} else {
901 			return (list_output(index, TRUE));
902 		}
903 	} else if (!strcmp(&expression[delimiter], "Plain")) {
904 		if (index < 1 || index > objects) {
905 			badptrrun(expression, index);
906 			return (NULL);
907 		} else {
908 			return (plain_output(index, TRUE));
909 		}
910 	} else if (!strcmp(&expression[delimiter], "Sub")) {
911 		if (index < 1 || index > objects) {
912 			badptrrun(expression, index);
913 			return (NULL);
914 		} else {
915 			return (sub_output(index, TRUE));
916 		}
917 	} else if (!strcmp(&expression[delimiter], "Obj")) {
918 		if (index < 1 || index > objects) {
919 			badptrrun(expression, index);
920 			return (NULL);
921 		} else {
922 			return (obj_output(index, TRUE));
923 		}
924 	} else if (!strcmp(&expression[delimiter], "That")) {
925 		if (index < 1 || index > objects) {
926 			badptrrun(expression, index);
927 			return (NULL);
928 		} else {
929 			return (that_output(index, TRUE));
930 		}
931 	} else if (!strcmp(&expression[delimiter], "It")) {
932 		if (index < 1 || index > objects) {
933 			badptrrun(expression, index);
934 			return (NULL);
935 		} else {
936 			return (it_output(index, TRUE));
937 		}
938 	} else if (!strcmp(&expression[delimiter], "Doesnt")) {
939 		if (index < 1 || index > objects) {
940 			badptrrun(expression, index);
941 			return (NULL);
942 		} else {
943 			return (doesnt_output(index, TRUE));
944 		}
945 	} else if (!strcmp(&expression[delimiter], "Does")) {
946 		if (index < 1 || index > objects) {
947 			badptrrun(expression, index);
948 			return (NULL);
949 		} else {
950 			return (does_output(index, TRUE));
951 		}
952 	} else if (!strcmp(&expression[delimiter], "Isnt")) {
953 		if (index < 1 || index > objects) {
954 			badptrrun(expression, index);
955 			return (NULL);
956 		} else {
957 			return (isnt_output(index, TRUE));
958 		}
959 	} else if (!strcmp(&expression[delimiter], "Is")) {
960 		if (index < 1 || index > objects) {
961 			badptrrun(expression, index);
962 			return (NULL);
963 		} else {
964 			return (is_output(index, TRUE));
965 		}
966 	} else if (!strcmp(&expression[delimiter], "The")) {
967 		if (index < 1 || index > objects) {
968 			badptrrun(expression, index);
969 			return (NULL);
970 		} else {
971 			return (sentence_output(index, TRUE));
972 		}
973 	} else {
974 		strcpy(macro_function, "+macro_");
975 		strcat(macro_function, &expression[delimiter]);
976 		strcat(macro_function, "<");
977 		sprintf(temp_buffer, "%d", index);
978 		strcat(macro_function, temp_buffer);
979 
980 		// BUILD THE FUNCTION NAME AND PASS THE OBJECT AS
981 		// THE ONLY ARGUMENT
982 		if (execute(macro_function)) {
983 			return (string_resolve("return_value")->value);
984 		}
985 	}
986 
987 	return (NULL);
988 }
989 
count_resolve(const char * testString)990 int count_resolve(const char *testString) {
991 	struct function_type    *resolved_function = NULL;
992 
993 	if (*(testString + 1) == 0) {
994 		// @ ON ITS OWN, SO RETURN THE CALL COUNT OF THE CURRENTLY EXECUTING
995 		// FUNCTION
996 		return (executing_function->call_count);
997 	} else if ((resolved_function = function_resolve(testString + 1)) != NULL) {
998 		return (resolved_function->call_count);
999 	} else {
1000 		return array_length_resolve(testString);
1001 	}
1002 }
1003 
array_length_resolve(const char * testString)1004 int array_length_resolve(const char *testString) {
1005 	int             counter = 0;
1006 	const char      *array_name = &testString[1];
1007 
1008 	struct integer_type *integer_pointer = integer_table;
1009 	struct cinteger_type *cinteger_pointer = cinteger_table;
1010 	struct string_type *string_pointer = string_table;
1011 	struct string_type *cstring_pointer = cstring_table;
1012 
1013 	if (integer_pointer != NULL) {
1014 		do {
1015 			if (!strcmp(array_name, integer_pointer->name)) {
1016 				counter++;
1017 			}
1018 			integer_pointer = integer_pointer->next_integer;
1019 		} while (integer_pointer != NULL);
1020 	}
1021 
1022 	/* IF ONE OR MORE INTEGERS WITH THIS NAME WERE FOUND
1023 	   RETURN THE COUNT */
1024 	if (counter)
1025 		return (counter);
1026 
1027 	if (string_pointer != NULL) {
1028 		do {
1029 			if (!strcmp(array_name, string_pointer->name)) {
1030 				counter++;
1031 			}
1032 			string_pointer = string_pointer->next_string;
1033 		} while (string_pointer != NULL);
1034 	}
1035 
1036 	/* IF ONE OR MORE STRINGS WITH THIS NAME WERE FOUND
1037 	   RETURN THE COUNT */
1038 	if (counter)
1039 		return (counter);
1040 
1041 	if (cinteger_pointer != NULL) {
1042 		do {
1043 			if (!strcmp(array_name, cinteger_pointer->name)) {
1044 				counter++;
1045 			}
1046 			cinteger_pointer = cinteger_pointer->next_cinteger;
1047 		} while (cinteger_pointer != NULL);
1048 	}
1049 
1050 	/* IF ONE OR MORE INTEGER CONSTANTS WITH THIS NAME WERE FOUND
1051 	   RETURN THE COUNT */
1052 	if (counter)
1053 		return (counter);
1054 
1055 	if (cstring_pointer != NULL) {
1056 		do {
1057 			if (!strcmp(array_name, cstring_pointer->name)) {
1058 				counter++;
1059 			}
1060 			cstring_pointer = cstring_pointer->next_string;
1061 		} while (cstring_pointer != NULL);
1062 	}
1063 
1064 	/* IF ONE OR MORE STRING CONSTANTS WITH THIS NAME WERE FOUND
1065 	   RETURN THE COUNT */
1066 	if (counter)
1067 		return (counter);
1068 
1069 	/* NO VARIABLES OR STRINGS FOUND */
1070 	return (0);
1071 }
1072 
object_element_resolve(const char * testString)1073 int object_element_resolve(const char *testString) {
1074 	int             index,
1075 	                iterator,
1076 	                counter;
1077 	int             delimiter = 0;
1078 	char            expression[84];
1079 
1080 	struct integer_type *resolved_integer;
1081 	struct cinteger_type *resolved_cinteger;
1082 
1083 	strncpy(expression, testString, 80);
1084 
1085 	//sprintf(temp_buffer, "incoming = %s^", testString);
1086 	//write_text (temp_buffer);
1087 
1088 	counter = strlen(expression);
1089 
1090 	for (index = 0; index < counter; index++) {
1091 		if (expression[index] == '(') {
1092 			expression[index] = 0;
1093 			delimiter = index + 1;
1094 			for (iterator = counter; iterator > 0; iterator--) {
1095 				if (expression[iterator] == ')') {
1096 					expression[iterator] = 0;
1097 					break;
1098 				}
1099 			}
1100 			break;
1101 		} else if (expression[index] == '<') {
1102 			/* HIT A < BEFORE A [ THEREFORE */
1103 			/* IS A FUNCTION CALL, NOT AN ARRAY */
1104 			return (FALSE);
1105 		} else if (expression[index] == '[') {
1106 			/* HIT A [ BEFORE A ( THEREFORE */
1107 			/* THIS EXPRESSION IS AN ARRAY, NOT AN OBJECT ELEMENT */
1108 			/* UNLESS A CLOSING ] IS FOUND BEFORE THE OPENING ( */
1109 			/* ie. COULD BE AN array[index](element) FORMAT */
1110 			/* SEARCH FORWARD... */
1111 			for (; index < counter; index++) {
1112 				if (expression[index] == ']') {
1113 					/* BREAK OUT AND KEEP LOOKING FOR A ( */
1114 					break;
1115 				} else if (expression[index] == '(') {
1116 					/* THIS EXPRESSION IS DEFINITELY AN ARRAY WITH AN */
1117 					/* OBJECT ELEMENT AS THE INDEX */
1118 					return (FALSE);
1119 				}
1120 			}
1121 		} else if (expression[index] == ' ')
1122 			return (FALSE);
1123 	}
1124 
1125 	// NO DELIMITER FOUND OR NO STRING BEFORE DELIMITER
1126 	if (delimiter == FALSE || delimiter == 1)
1127 		return (FALSE);
1128 
1129 	index = object_resolve(expression);
1130 
1131 	if (index == -1) {
1132 		//sprintf(temp_buffer, "expression %s is not an object^", expression);
1133 		//write_text(temp_buffer);
1134 
1135 		// COULDN'T BE RESOLVED AS AN OBJECT, TRY AS A VARIABLE
1136 		if ((resolved_integer = integer_resolve(expression)) != NULL) {
1137 			index = resolved_integer->value;
1138 		} else if ((resolved_cinteger = cinteger_resolve(expression)) != NULL) {
1139 			index = resolved_cinteger->value;
1140 		}
1141 	}
1142 
1143 	if (index < 1 || index > objects) {
1144 		badptrrun(expression, index);
1145 		return (FALSE);
1146 	}
1147 
1148 	counter = value_of(&expression[delimiter], TRUE);
1149 
1150 	if (counter < 0 || counter > 15) {
1151 		sprintf(error_buffer,
1152 		        "ERROR: In function \"%s\", element \"%s\" out of range (%d).^",
1153 		        executing_function->name, &expression[delimiter], counter);
1154 		write_text(error_buffer);
1155 		return (FALSE);
1156 	} else {
1157 		oec = object[index]->integer[counter];
1158 		object_element_address = &object[index]->integer[counter];
1159 		return (TRUE);
1160 	}
1161 }
1162 
object_resolve(const char * object_string)1163 int object_resolve(const char *object_string) {
1164 	int             index;
1165 
1166 	if (!strcmp(object_string, "noun1"))
1167 		return (noun[0]);
1168 	else if (!strcmp(object_string, "noun2"))
1169 		return (noun[1]);
1170 	else if (!strcmp(object_string, "noun3"))
1171 		return (noun[2]);
1172 	else if (!strcmp(object_string, "noun4"))
1173 		return (noun[3]);
1174 	else if (!strcmp(object_string, "player"))
1175 		return (player);
1176 	else if (!strcmp(object_string, "here"))
1177 		return (HERE);
1178 	else if (!strcmp(object_string, "self") ||
1179 	         !strcmp(object_string, "this")) {
1180 		if (executing_function != NULL && executing_function->self == 0) {
1181 			sprintf(error_buffer,
1182 			        "ERROR: Reference to 'self' from global function \"%s\".^",
1183 			        executing_function->name);
1184 			write_text(error_buffer);
1185 		} else
1186 			return (executing_function->self);
1187 	} else {
1188 		for (index = 1; index <= objects; index++) {
1189 			if (!strcmp(object_string, object[index]->label))
1190 				return (index);
1191 		}
1192 	}
1193 
1194 	return (-1);
1195 }
1196 
attribute_resolve(const char * attribute)1197 long attribute_resolve(const char *attribute) {
1198 	long            bit_mask;
1199 
1200 	if (!strcmp(attribute, "VISITED"))
1201 		return (VISITED);
1202 	else if (!strcmp(attribute, "DARK"))
1203 		return (DARK);
1204 	else if (!strcmp(attribute, "ON_WATER"))
1205 		return (ON_WATER);
1206 	else if (!strcmp(attribute, "UNDER_WATER"))
1207 		return (UNDER_WATER);
1208 	else if (!strcmp(attribute, "WITHOUT_AIR"))
1209 		return (WITHOUT_AIR);
1210 	else if (!strcmp(attribute, "OUTDOORS"))
1211 		return (OUTDOORS);
1212 	else if (!strcmp(attribute, "MID_AIR"))
1213 		return (MID_AIR);
1214 	else if (!strcmp(attribute, "TIGHT_ROPE"))
1215 		return (TIGHT_ROPE);
1216 	else if (!strcmp(attribute, "POLLUTED"))
1217 		return (POLLUTED);
1218 	else if (!strcmp(attribute, "SOLVED"))
1219 		return (SOLVED);
1220 	else if (!strcmp(attribute, "MID_WATER"))
1221 		return (MID_WATER);
1222 	else if (!strcmp(attribute, "DARKNESS")) {
1223 		bit_mask = DARKNESS;
1224 		if (check_light(HERE)) {
1225 			bit_mask = ~bit_mask;
1226 			object[HERE]->attributes = object[HERE]->attributes & bit_mask;
1227 		} else {
1228 			object[HERE]->attributes = object[HERE]->attributes | bit_mask;
1229 		}
1230 		return (DARKNESS);
1231 	} else if (!strcmp(attribute, "MAPPED"))
1232 		return (MAPPED);
1233 	else if (!strcmp(attribute, "KNOWN"))
1234 		return (KNOWN);
1235 	else if (!strcmp(attribute, "CLOSED"))
1236 		return (CLOSED);
1237 	else if (!strcmp(attribute, "LOCKED"))
1238 		return (LOCKED);
1239 	else if (!strcmp(attribute, "DEAD"))
1240 		return (DEAD);
1241 	else if (!strcmp(attribute, "IGNITABLE"))
1242 		return (IGNITABLE);
1243 	else if (!strcmp(attribute, "WORN"))
1244 		return (WORN);
1245 	else if (!strcmp(attribute, "CONCEALING"))
1246 		return (CONCEALING);
1247 	else if (!strcmp(attribute, "LUMINOUS"))
1248 		return (LUMINOUS);
1249 	else if (!strcmp(attribute, "WEARABLE"))
1250 		return (WEARABLE);
1251 	else if (!strcmp(attribute, "CLOSABLE"))
1252 		return (CLOSABLE);
1253 	else if (!strcmp(attribute, "LOCKABLE"))
1254 		return (LOCKABLE);
1255 	else if (!strcmp(attribute, "ANIMATE"))
1256 		return (ANIMATE);
1257 	else if (!strcmp(attribute, "LIQUID"))
1258 		return (LIQUID);
1259 	else if (!strcmp(attribute, "CONTAINER"))
1260 		return (CONTAINER);
1261 	else if (!strcmp(attribute, "SURFACE"))
1262 		return (SURFACE);
1263 	else if (!strcmp(attribute, "PLURAL"))
1264 		return (PLURAL);
1265 	else if (!strcmp(attribute, "FLAMMABLE"))
1266 		return (FLAMMABLE);
1267 	else if (!strcmp(attribute, "BURNING"))
1268 		return (BURNING);
1269 	else if (!strcmp(attribute, "LOCATION"))
1270 		return (LOCATION);
1271 	else if (!strcmp(attribute, "ON"))
1272 		return (ON);
1273 	else if (!strcmp(attribute, "DAMAGED"))
1274 		return (DAMAGED);
1275 	else if (!strcmp(attribute, "FEMALE"))
1276 		return (FEMALE);
1277 	else if (!strcmp(attribute, "POSSESSIVE"))
1278 		return (POSSESSIVE);
1279 	else if (!strcmp(attribute, "OUT_OF_REACH"))
1280 		return (OUT_OF_REACH);
1281 	else if (!strcmp(attribute, "TOUCHED"))
1282 		return (TOUCHED);
1283 	else if (!strcmp(attribute, "SCORED"))
1284 		return (SCORED);
1285 	else if (!strcmp(attribute, "SITTING"))
1286 		return (SITTING);
1287 	else if (!strcmp(attribute, "NPC"))
1288 		return (NPC);
1289 	else if (!strcmp(attribute, "DONE"))
1290 		return (DONE);
1291 	else if (!strcmp(attribute, "GAS"))
1292 		return (MAPPED);
1293 	else if (!strcmp(attribute, "NO_TAB"))
1294 		return (NO_TAB);
1295 	else if (!strcmp(attribute, "NOT_IMPORTANT"))
1296 		return (NOT_IMPORTANT);
1297 	else
1298 		return (0);
1299 }
1300 
user_attribute_resolve(const char * name)1301 long user_attribute_resolve(const char *name) {
1302 	struct attribute_type *pointer = attribute_table;
1303 
1304 	if (pointer == NULL)
1305 		return (0);
1306 
1307 	do {
1308 		if (!strcmp(name, pointer->name)) {
1309 			return (pointer->value);
1310 		} else
1311 			pointer = pointer->next_attribute;
1312 	} while (pointer != NULL);
1313 
1314 	/* ATTRIBUTE NOT FOUND */
1315 	return (0);
1316 }
1317 
1318 } // End of namespace JACL
1319 } // End of namespace Glk
1320