diff -c zip/object.c zip_zs/object.c *** zip/object.c Fri Jan 2 13:49:22 1998 --- zip_zs/object.c Fri Jan 2 15:10:22 1998 *************** *** 66,71 **** --- 66,84 ---- { zword_t obj1p, obj2p, child2; + #ifdef STRICTZ + if (obj1 == 0) { + report_strictz_error(STRZERR_MOVE_OBJECT, + "@move_object called moving object 0"); + return; + } + if (obj2 == 0) { + report_strictz_error(STRZERR_MOVE_OBJECT_2, + "@move_object called moving into object 0"); + return; + } + #endif + /* Get addresses of both objects */ obj1p = get_object_address (obj1); *************** *** 111,116 **** --- 124,137 ---- { zword_t objp, parentp, childp, parent, child; + #ifdef STRICTZ + if (obj == 0) { + report_strictz_error(STRZERR_REMOVE_OBJECT, + "@remove_object called with object 0"); + return; + } + #endif + /* Get address of object to be removed */ objp = get_object_address (obj); *************** *** 169,174 **** --- 190,204 ---- zword_t obj; #endif { + + #ifdef STRICTZ + if (obj == 0) { + report_strictz_error(STRZERR_GET_PARENT, + "@get_parent called with object 0"); + store_operand(0); + return; + } + #endif store_operand (read_object (get_object_address (obj), PARENT)); *************** *** 191,196 **** --- 221,236 ---- { zword_t child; + #ifdef STRICTZ + if (obj == 0) { + report_strictz_error(STRZERR_GET_CHILD, + "@get_child called with object 0"); + store_operand(0); + conditional_jump(FALSE); + return; + } + #endif + child = read_object (get_object_address (obj), CHILD); store_operand (child); *************** *** 216,221 **** --- 256,271 ---- { zword_t next; + #ifdef STRICTZ + if (obj == 0) { + report_strictz_error(STRZERR_GET_SIBLING, + "@get_sibling called with object 0"); + store_operand(0); + conditional_jump(FALSE); + return; + } + #endif + next = read_object (get_object_address (obj), NEXT); store_operand (next); *************** *** 240,245 **** --- 290,304 ---- #endif { + #ifdef STRICTZ + if (obj1 == 0) { + report_strictz_error(STRZERR_JIN, + "@jin called with object 0"); + conditional_jump(0 == obj2); + return; + } + #endif + conditional_jump (read_object (get_object_address (obj1), PARENT) == obj2); }/* compare_parent_object */ *************** *** 264,269 **** --- 323,337 ---- assert (O3_ATTRIBUTES == O4_ATTRIBUTES); + #ifdef STRICTZ + if (obj == 0) { + report_strictz_error(STRZERR_TEST_ATTR, + "@test_attr called with object 0"); + conditional_jump(FALSE); + return; + } + #endif + /* Get attribute address */ objp = get_object_address (obj) + (bit >> 3); *************** *** 298,303 **** --- 366,379 ---- assert (O3_ATTRIBUTES == O4_ATTRIBUTES); + #ifdef STRICTZ + if (obj == 0) { + report_strictz_error(STRZERR_SET_ATTR, + "@set_attr called with object 0"); + return; + } + #endif + /* Get attribute address */ objp = get_object_address (obj) + (bit >> 3); *************** *** 335,340 **** --- 411,424 ---- zbyte_t value; assert (O3_ATTRIBUTES == O4_ATTRIBUTES); + + #ifdef STRICTZ + if (obj == 0) { + report_strictz_error(STRZERR_CLEAR_ATTR, + "@clear_attr called with object 0"); + return; + } + #endif /* Get attribute address */ diff -c zip/osdepend.c zip_zs/osdepend.c *** zip/osdepend.c Fri Jan 2 13:49:22 1998 --- zip_zs/osdepend.c Fri Jan 2 15:40:43 1998 *************** *** 21,26 **** --- 21,56 ---- #define RECORD_NAME "record.lis" /* Default record name */ #endif /* defined(AMIGA) */ + #ifdef STRICTZ + + /* Define stuff for stricter Z-code error checking, for the generic + Unix/DOS/etc terminal-window interface. Feel free to change the way + player prefs are specified, or replace report_zstrict_error() + completely if you want to change the way errors are reported. */ + + /* There are four error reporting modes: never report errors; + report only the first time a given error type occurs; report + every time an error occurs; or treat all errors as fatal + errors, killing the interpreter. I strongly recommend + "report once" as the default. But you can compile in a + different default by changing the definition of + STRICTZ_DEFAULT_REPORT_MODE. In any case, the player can + specify a report mode on the command line by typing "-s 0" + through "-s 3". */ + + #define STRICTZ_REPORT_NEVER (0) + #define STRICTZ_REPORT_ONCE (1) + #define STRICTZ_REPORT_ALWAYS (2) + #define STRICTZ_REPORT_FATAL (3) + + #define STRICTZ_DEFAULT_REPORT_MODE STRICTZ_REPORT_ONCE + + static int strictz_report_mode; + static int strictz_error_count[STRICTZ_NUM_ERRORS]; + + #endif /* STRICTZ */ + + #if !defined(AMIGA) /* getopt linkages */ *************** *** 50,59 **** #endif { int c, errflg = 0; /* Parse the options */ ! while ((c = getopt (argc, argv, "hl:c:r:t:")) != EOF) { switch (c) { case 'l': /* lines */ screen_rows = atoi (optarg); --- 80,100 ---- #endif { int c, errflg = 0; + int num; + #ifdef STRICTZ + /* Initialize the STRICTZ variables. */ + + strictz_report_mode = STRICTZ_DEFAULT_REPORT_MODE; + + for (num=0; num STRICTZ_REPORT_FATAL) { + errflg++; + } + break; + #endif /* STRICTZ */ case 'h': case '?': default: *************** *** 84,89 **** --- 134,143 ---- fprintf (stderr, "\t-c n columns in display\n"); fprintf (stderr, "\t-r n text right margin (default = %d)\n", DEFAULT_RIGHT_MARGIN); fprintf (stderr, "\t-t n text top margin (default = %d)\n", DEFAULT_TOP_MARGIN); + #ifdef STRICTZ + fprintf (stderr, "\t-s n stricter error checking (default = %d)\n", STRICTZ_DEFAULT_REPORT_MODE); + fprintf (stderr, "\t\t(0: none; 1: report first error; 2: report all errors; 3: exit after any error)\n"); + #endif /* STRICTZ */ exit (EXIT_FAILURE); } *************** *** 314,319 **** --- 368,436 ---- exit (1); }/* fatal */ + + #endif /* !defined(AMIGA) */ + + #if !defined(AMIGA) + + /* + * report_strictz_error + * + * This handles Z-code error conditions which ought to be fatal errors, + * but which players might want to ignore for the sake of finishing the + * game. + * + * The error is provided as both a numeric code and a string. This allows + * us to print a warning the first time a particular error occurs, and + * ignore it thereafter. + * + * errnum : Numeric code for error (0 to STRICTZ_NUM_ERRORS-1) + * errstr : Text description of error + * + */ + + #ifdef STRICTZ + + #ifdef __STDC__ + void report_strictz_error (int errnum, const char *errstr) + #else /* __STDC__ */ + void report_strictz_error (errnum, errstr) + int errnum; + const char *errstr; + #endif /* __STDC__ */ + { + int wasfirst; + + if (errnum <= 0 || errnum >= STRICTZ_NUM_ERRORS) + return; + + if (strictz_report_mode == STRICTZ_REPORT_FATAL) { + fatal(errstr); + return; + } + + wasfirst = (strictz_error_count[errnum] == 0); + strictz_error_count[errnum]++; + + if ((strictz_report_mode == STRICTZ_REPORT_ALWAYS) + || (strictz_report_mode == STRICTZ_REPORT_ONCE && wasfirst)) { + char buf[256]; + sprintf(buf, "Warning: %s (PC = %lx)", errstr, pc); + write_string(buf); + + if (strictz_report_mode == STRICTZ_REPORT_ONCE) { + write_string(" (will ignore further occurrences)"); + } + else { + sprintf(buf, " (occurrence %d)", strictz_error_count[errnum]); + write_string(buf); + } + new_line(); + } + + } /* report_strictz_error */ + + #endif /* STRICTZ */ #endif /* !defined(AMIGA) */ diff -c zip/property.c zip_zs/property.c *** zip/property.c Fri Jan 2 13:49:22 1998 --- zip_zs/property.c Fri Jan 2 15:10:22 1998 *************** *** 98,103 **** --- 98,112 ---- { zword_t propp; + #ifdef STRICTZ + if (obj == 0) { + report_strictz_error(STRZERR_GET_PROP, + "@get_prop called with object 0"); + store_operand (0); + return; + } + #endif + /* Load address of first property */ propp = get_property_addr (obj); *************** *** 149,154 **** --- 158,171 ---- { zword_t propp; + #ifdef STRICTZ + if (obj == 0) { + report_strictz_error(STRZERR_PUT_PROP, + "@put_prop called with object 0"); + return; + } + #endif + /* Load address of first property */ propp = get_property_addr (obj); *************** *** 192,197 **** --- 209,223 ---- { zword_t propp; + #ifdef STRICTZ + if (obj == 0) { + report_strictz_error(STRZERR_GET_NEXT_PROP, + "@get_next_prop called with object 0"); + store_operand (0); + return; + } + #endif + /* Load address of first property */ propp = get_property_addr (obj); *************** *** 236,241 **** --- 262,276 ---- #endif { zword_t propp; + + #ifdef STRICTZ + if (obj == 0) { + report_strictz_error(STRZERR_GET_PROP_ADDR, + "@get_prop_addr called with object 0"); + store_operand (0); + return; + } + #endif /* Load address of first property */ diff -c zip/ztypes.h zip_zs/ztypes.h *** zip/ztypes.h Fri Jan 2 13:49:24 1998 --- zip_zs/ztypes.h Fri Jan 2 15:48:11 1998 *************** *** 27,32 **** --- 27,48 ---- #define DEFAULT_RIGHT_MARGIN 0 /* # of characters in right margin */ #define DEFAULT_TOP_MARGIN 0 /* # of lines left on screen before [MORE] message */ + /* Perform stricter z-code error checking. If STRICTZ is #defined, + the interpreter will check for common opcode errors, such as reading + or writing properties of the "nothing" (0) object. When such an + error occurs, the opcode will call report_zstrict_error() and + then continue in some safe manner. This may mean doing nothing, + returning 0, or something like that. + See osdepend.c for the definition of report_zstrict_error(). Note that + this function may call fatal() to shut down the interpreter. + If STRICTZ is not #defined, the STRICTZ patch has no effect at all. + It does not even check to continue safely when an error occurs; + it just behaves the way ZIP has always behaved. This typically + means calling get_property_addr(0) or get_object_address(0), + which will return a meaningless value, and continuing on with + that. */ + #define STRICTZ + /* Global defines */ #ifndef TRUE *************** *** 353,358 **** --- 369,404 ---- extern char *status_line; extern char lookup_table[3][26]; + + #ifdef STRICTZ + + /* Definitions for STRICTZ functions and error codes. */ + + #ifdef __STDC__ + void report_strictz_error (int, const char *); + #else /* __STDC__ */ + void report_strictz_error (); + #endif /* __STDC__ */ + + /* Error codes */ + #define STRZERR_NO_ERROR (0) + #define STRZERR_JIN (1) + #define STRZERR_GET_CHILD (2) + #define STRZERR_GET_PARENT (3) + #define STRZERR_GET_SIBLING (4) + #define STRZERR_GET_PROP_ADDR (5) + #define STRZERR_GET_PROP (6) + #define STRZERR_PUT_PROP (7) + #define STRZERR_CLEAR_ATTR (8) + #define STRZERR_SET_ATTR (9) + #define STRZERR_TEST_ATTR (10) + #define STRZERR_MOVE_OBJECT (11) + #define STRZERR_MOVE_OBJECT_2 (12) + #define STRZERR_REMOVE_OBJECT (13) + #define STRZERR_GET_NEXT_PROP (14) + #define STRICTZ_NUM_ERRORS (15) + + #endif /* STRICTZ */ /* Global routines */