diff options
Diffstat (limited to 'engines/glk/adrift/sxscript.cpp')
-rw-r--r-- | engines/glk/adrift/sxscript.cpp | 714 |
1 files changed, 330 insertions, 384 deletions
diff --git a/engines/glk/adrift/sxscript.cpp b/engines/glk/adrift/sxscript.cpp index 41be4c2b77..33c0501a3c 100644 --- a/engines/glk/adrift/sxscript.cpp +++ b/engines/glk/adrift/sxscript.cpp @@ -76,9 +76,8 @@ static sc_char *scr_game_output = NULL; * Set error reporting for expectation errors detected in the script. */ void -scr_set_verbose (sc_bool flag) -{ - scr_is_verbose = flag; +scr_set_verbose(sc_bool flag) { + scr_is_verbose = flag; } @@ -90,31 +89,27 @@ scr_set_verbose (sc_bool flag) * is used by the serialization helper, so is not static. */ static void -scr_test_message (const sc_char *format, const sc_char *string) -{ - if (scr_is_verbose) - { - sx_trace ("--- "); - sx_trace (format, string); - sx_trace ("\n"); - } +scr_test_message(const sc_char *format, const sc_char *string) { + if (scr_is_verbose) { + sx_trace("--- "); + sx_trace(format, string); + sx_trace("\n"); + } } void -scr_test_failed (const sc_char *format, const sc_char *string) -{ - assert (format && string); - - if (scr_is_verbose) - { - if (scr_line_number > 0) - sx_trace ("--- Near line %ld: ", scr_line_number); - else - sx_trace ("--- "); - sx_trace (format, string); - sx_trace ("\n"); - } - scr_errors++; +scr_test_failed(const sc_char *format, const sc_char *string) { + assert(format && string); + + if (scr_is_verbose) { + if (scr_line_number > 0) + sx_trace("--- Near line %ld: ", scr_line_number); + else + sx_trace("--- "); + sx_trace(format, string); + sx_trace("\n"); + } + scr_errors++; } @@ -129,47 +124,41 @@ scr_test_failed (const sc_char *format, const sc_char *string) * Line classifiers, return TRUE if line has the given type. */ static sc_bool -scr_is_line_type (const sc_char *line, sc_char type) -{ - return line[0] == type; +scr_is_line_type(const sc_char *line, sc_char type) { + return line[0] == type; } static sc_bool -scr_is_line_comment_or_empty (const sc_char *line) -{ - return scr_is_line_type (line, SCRIPT_COMMENT) - || strspn (line, "\t\n\v\f\r ") == strlen (line); +scr_is_line_comment_or_empty(const sc_char *line) { + return scr_is_line_type(line, SCRIPT_COMMENT) + || strspn(line, "\t\n\v\f\r ") == strlen(line); } static sc_bool -scr_is_line_game_command (const sc_char *line) -{ - return scr_is_line_type (line, GAME_COMMAND); +scr_is_line_game_command(const sc_char *line) { + return scr_is_line_type(line, GAME_COMMAND); } static sc_bool -scr_is_line_debug_command (const sc_char *line) -{ - return scr_is_line_type (line, DEBUG_COMMAND); +scr_is_line_debug_command(const sc_char *line) { + return scr_is_line_type(line, DEBUG_COMMAND); } static sc_bool -scr_is_line_command (const sc_char *line) -{ - return scr_is_line_game_command (line) || scr_is_line_debug_command (line); +scr_is_line_command(const sc_char *line) { + return scr_is_line_game_command(line) || scr_is_line_debug_command(line); } static sc_bool -scr_is_line_empty_debug_command (const sc_char *line) -{ - return scr_is_line_type (line, DEBUG_COMMAND) && line[1] == NUL; +scr_is_line_empty_debug_command(const sc_char *line) { + return scr_is_line_type(line, DEBUG_COMMAND) && line[1] == NUL; } /* Script location, a pair holding the file location and the line number. */ struct sx_scr_location_t { - size_t position; - sc_int line_number; + size_t position; + sc_int line_number; }; typedef sx_scr_location_t *sx_scr_locationref_t; @@ -180,12 +169,12 @@ typedef sx_scr_location_t *sx_scr_locationref_t; * Save and restore the script location in the given structure. */ static void -scr_save_location (sx_script script, sx_scr_locationref_t location) { +scr_save_location(sx_script script, sx_scr_locationref_t location) { location->position = script->pos(); location->line_number = scr_line_number; } -static void scr_restore_location (sx_script script, sx_scr_locationref_t location) { +static void scr_restore_location(sx_script script, sx_scr_locationref_t location) { script->seek(location->position); scr_line_number = location->line_number; } @@ -198,28 +187,26 @@ static void scr_restore_location (sx_script script, sx_scr_locationref_t locatio * line from the script. Returns NULL if no more lines, or on file error. The * return string is allocated, and it's the caller's responsibility to free it. */ -static sc_char *scr_get_next_line (sx_script script) { - sc_char *buffer, *line = NULL; - - /* Allocate a buffer for line reads. */ - buffer = (sc_char *)sx_malloc(LINE_BUFFER_SIZE); - - /* Read until a significant line is found, or end of file or error. */ - while (adrift_fgets(buffer, LINE_BUFFER_SIZE, script)) - { - scr_line_number++; - if (!scr_is_line_comment_or_empty (buffer)) - { - line = buffer; - break; - } - } - - /* If no significant line read, free the read buffer. */ - if (!line) - sx_free (buffer); - - return line; +static sc_char *scr_get_next_line(sx_script script) { + sc_char *buffer, *line = NULL; + + /* Allocate a buffer for line reads. */ + buffer = (sc_char *)sx_malloc(LINE_BUFFER_SIZE); + + /* Read until a significant line is found, or end of file or error. */ + while (adrift_fgets(buffer, LINE_BUFFER_SIZE, script)) { + scr_line_number++; + if (!scr_is_line_comment_or_empty(buffer)) { + line = buffer; + break; + } + } + + /* If no significant line read, free the read buffer. */ + if (!line) + sx_free(buffer); + + return line; } @@ -231,23 +218,19 @@ static sc_char *scr_get_next_line (sx_script script) { * instead. */ static sc_char * -scr_concatenate (sc_char *string, const sc_char *buffer) -{ - /* If string is not null, concatenate buffer, otherwise duplicate. */ - if (string) - { - string = (sc_char *)sx_realloc(string, - strlen (string) + 1 + strlen (buffer) + 1); - strcat (string, " "); - strcat (string, buffer); - } - else - { - string = (sc_char *)sx_malloc(strlen (buffer) + 1); - strcpy (string, buffer); - } - - return string; +scr_concatenate(sc_char *string, const sc_char *buffer) { + /* If string is not null, concatenate buffer, otherwise duplicate. */ + if (string) { + string = (sc_char *)sx_realloc(string, + strlen(string) + 1 + strlen(buffer) + 1); + strcat(string, " "); + strcat(string, buffer); + } else { + string = (sc_char *)sx_malloc(strlen(buffer) + 1); + strcpy(string, buffer); + } + + return string; } @@ -261,65 +244,57 @@ scr_concatenate (sc_char *string, const sc_char *buffer) * free them. */ static sc_bool -scr_get_next_section (sx_script script, - sc_char **command, sc_char **expectation) -{ - sc_char *line, *first_line, *other_lines; - sx_scr_location_t location; - - /* Clear initial line accumulation. */ - first_line = other_lines = NULL; - - /* Read the next significant line from the script. */ - scr_save_location (script, &location); - line = scr_get_next_line (script); - while (line) - { - /* If already a first line, this is other lines or section end. */ - if (first_line) - { - /* - * If we found the start of the next section, reset the script - * location that saved on the line read, and we're done. - */ - if (scr_is_line_command (line)) - { - scr_restore_location (script, &location); - sx_free (line); - break; - } - else - other_lines = scr_concatenate (other_lines, line); - } - else - first_line = scr_concatenate (first_line, line); - - sx_free (line); - - /* Read the next significant line from the script. */ - scr_save_location (script, &location); - line = scr_get_next_line (script); - } - - /* Clean up and return nothing on file error. */ - if (script->err()) - { - scr_test_failed ("Script error: Failed reading script input file", ""); - sx_free (first_line); - sx_free (other_lines); - return FALSE; - } - - /* Return the command and the matching expectation string, if any. */ - if (first_line) - { - *command = sx_normalize_string (first_line); - *expectation = other_lines ? sx_normalize_string (other_lines) : NULL; - return TRUE; - } - - /* End of file, no command section read. */ - return FALSE; +scr_get_next_section(sx_script script, + sc_char **command, sc_char **expectation) { + sc_char *line, *first_line, *other_lines; + sx_scr_location_t location; + + /* Clear initial line accumulation. */ + first_line = other_lines = NULL; + + /* Read the next significant line from the script. */ + scr_save_location(script, &location); + line = scr_get_next_line(script); + while (line) { + /* If already a first line, this is other lines or section end. */ + if (first_line) { + /* + * If we found the start of the next section, reset the script + * location that saved on the line read, and we're done. + */ + if (scr_is_line_command(line)) { + scr_restore_location(script, &location); + sx_free(line); + break; + } else + other_lines = scr_concatenate(other_lines, line); + } else + first_line = scr_concatenate(first_line, line); + + sx_free(line); + + /* Read the next significant line from the script. */ + scr_save_location(script, &location); + line = scr_get_next_line(script); + } + + /* Clean up and return nothing on file error. */ + if (script->err()) { + scr_test_failed("Script error: Failed reading script input file", ""); + sx_free(first_line); + sx_free(other_lines); + return FALSE; + } + + /* Return the command and the matching expectation string, if any. */ + if (first_line) { + *command = sx_normalize_string(first_line); + *expectation = other_lines ? sx_normalize_string(other_lines) : NULL; + return TRUE; + } + + /* End of file, no command section read. */ + return FALSE; } @@ -334,48 +309,41 @@ scr_get_next_section (sx_script script, * input. */ static void -scr_expect (sc_char *expectation) -{ - /* - * Save the expectation, and set up collection of game output if needed. - * And if not needed, ensure expectation and game output are cleared. - */ - if (expectation) - { - scr_expectation = (sc_char *)sx_malloc(strlen (expectation) + 1); - strcpy (scr_expectation, expectation); - scr_game_output = (sc_char *)sx_malloc (1); - strcpy (scr_game_output, ""); - } - else - { - sx_free(scr_expectation); - scr_expectation = NULL; - sx_free(scr_game_output); - scr_game_output = NULL; - } +scr_expect(sc_char *expectation) { + /* + * Save the expectation, and set up collection of game output if needed. + * And if not needed, ensure expectation and game output are cleared. + */ + if (expectation) { + scr_expectation = (sc_char *)sx_malloc(strlen(expectation) + 1); + strcpy(scr_expectation, expectation); + scr_game_output = (sc_char *)sx_malloc(1); + strcpy(scr_game_output, ""); + } else { + sx_free(scr_expectation); + scr_expectation = NULL; + sx_free(scr_game_output); + scr_game_output = NULL; + } } static void -scr_verify_expectation (void) -{ - /* Compare expected with actual, and handle any error detected. */ - if (scr_expectation && scr_game_output) - { - scr_game_output = sx_normalize_string (scr_game_output); - if (!glob_match (scr_expectation, scr_game_output)) - { - scr_test_failed ("Expectation error:", ""); - scr_test_message (" Expected: \"%s\"", scr_expectation); - scr_test_message (" Received: \"%s\"", scr_game_output); - } - } - - /* Dispose of the expectation and accumulated game output. */ - sx_free (scr_expectation); - scr_expectation = NULL; - sx_free (scr_game_output); - scr_game_output = NULL; +scr_verify_expectation(void) { + /* Compare expected with actual, and handle any error detected. */ + if (scr_expectation && scr_game_output) { + scr_game_output = sx_normalize_string(scr_game_output); + if (!glob_match(scr_expectation, scr_game_output)) { + scr_test_failed("Expectation error:", ""); + scr_test_message(" Expected: \"%s\"", scr_expectation); + scr_test_message(" Received: \"%s\"", scr_game_output); + } + } + + /* Dispose of the expectation and accumulated game output. */ + sx_free(scr_expectation); + scr_expectation = NULL; + sx_free(scr_game_output); + scr_game_output = NULL; } @@ -390,28 +358,26 @@ scr_verify_expectation (void) * to turn it off when it's no longer needed. */ static void -scr_execute_debugger_command (const sc_char *command, sc_char *expectation) -{ - sc_bool status; - - /* Set up the expectation. */ - scr_expect (expectation); - - /* - * Execute the command via the debugger interface. The "+1" on command - * skips the leading '~' read in from the game script. - */ - sc_set_game_debugger_enabled (scr_game, TRUE); - status = sc_run_game_debugger_command (scr_game, command + 1); - - if (!status) - { - scr_test_failed ("Script error:" - " Debug command \"%s\" is not valid", command); - } - - /* Check expectations immediately. */ - scr_verify_expectation (); +scr_execute_debugger_command(const sc_char *command, sc_char *expectation) { + sc_bool status; + + /* Set up the expectation. */ + scr_expect(expectation); + + /* + * Execute the command via the debugger interface. The "+1" on command + * skips the leading '~' read in from the game script. + */ + sc_set_game_debugger_enabled(scr_game, TRUE); + status = sc_run_game_debugger_command(scr_game, command + 1); + + if (!status) { + scr_test_failed("Script error:" + " Debug command \"%s\" is not valid", command); + } + + /* Check expectations immediately. */ + scr_verify_expectation(); } @@ -425,65 +391,60 @@ scr_execute_debugger_command (const sc_char *command, sc_char *expectation) * to the game. */ static sc_bool -scr_read_line_callback (sc_char *buffer, sc_int length) -{ - sc_char *command, *expectation; - assert (buffer && length > 0); - - /* Check pending expectation, and clear settings for the next line. */ - scr_verify_expectation (); - - /* Get the next line-expectation pair from the script stream. */ - if (scr_get_next_section (scr_script, &command, &expectation)) - { - if (scr_is_line_debug_command (command)) - { - /* The debugger persists where debug commands are adjacent. */ - scr_execute_debugger_command (command, expectation); - sx_free (command); - sx_free (expectation); - - /* - * Returning FALSE here causes the game to re-prompt. We could - * loop (or tail recurse) ourselves, but returning is simpler. - */ - return FALSE; - } - else - sc_set_game_debugger_enabled (scr_game, FALSE); - - if (scr_is_line_game_command (command)) - { - /* Set up the expectation. */ - scr_expect (expectation); - - /* Copy out the line to the return buffer, and free the line. */ - strncpy (buffer, command + 1, length); - buffer[length - 1] = NUL; - sx_free (command); - sx_free (expectation); - return TRUE; - } - - /* Neither a '~' nor a '>' command. */ - scr_test_failed ("Script error:" - " Command \"%s\" is not valid, ignored", command); - sx_free (command); - sx_free (expectation); - return FALSE; - } - - /* Ensure the game debugger is off after this section. */ - sc_set_game_debugger_enabled (scr_game, FALSE); - - /* - * We reached the end of the script without finding a "quit" command. - * Supply one here, then. In the unlikely even that this does not quit - * the game, we'll iterate on this. - */ - assert (length > 4); - strcpy (buffer, "quit"); - return TRUE; +scr_read_line_callback(sc_char *buffer, sc_int length) { + sc_char *command, *expectation; + assert(buffer && length > 0); + + /* Check pending expectation, and clear settings for the next line. */ + scr_verify_expectation(); + + /* Get the next line-expectation pair from the script stream. */ + if (scr_get_next_section(scr_script, &command, &expectation)) { + if (scr_is_line_debug_command(command)) { + /* The debugger persists where debug commands are adjacent. */ + scr_execute_debugger_command(command, expectation); + sx_free(command); + sx_free(expectation); + + /* + * Returning FALSE here causes the game to re-prompt. We could + * loop (or tail recurse) ourselves, but returning is simpler. + */ + return FALSE; + } else + sc_set_game_debugger_enabled(scr_game, FALSE); + + if (scr_is_line_game_command(command)) { + /* Set up the expectation. */ + scr_expect(expectation); + + /* Copy out the line to the return buffer, and free the line. */ + strncpy(buffer, command + 1, length); + buffer[length - 1] = NUL; + sx_free(command); + sx_free(expectation); + return TRUE; + } + + /* Neither a '~' nor a '>' command. */ + scr_test_failed("Script error:" + " Command \"%s\" is not valid, ignored", command); + sx_free(command); + sx_free(expectation); + return FALSE; + } + + /* Ensure the game debugger is off after this section. */ + sc_set_game_debugger_enabled(scr_game, FALSE); + + /* + * We reached the end of the script without finding a "quit" command. + * Supply one here, then. In the unlikely even that this does not quit + * the game, we'll iterate on this. + */ + assert(length > 4); + strcpy(buffer, "quit"); + return TRUE; } @@ -495,17 +456,15 @@ scr_read_line_callback (sc_char *buffer, sc_int length) * the current game output will be NULL, and we can simply save the effort. */ static void -scr_print_string_callback (const sc_char *string) -{ - assert (string); - - if (scr_game_output) - { - scr_game_output = (sc_char *)sx_realloc (scr_game_output, - strlen (scr_game_output) - + strlen (string) + 1); - strcat (scr_game_output, string); - } +scr_print_string_callback(const sc_char *string) { + assert(string); + + if (scr_game_output) { + scr_game_output = (sc_char *)sx_realloc(scr_game_output, + strlen(scr_game_output) + + strlen(string) + 1); + strcat(scr_game_output, string); + } } @@ -518,68 +477,60 @@ scr_print_string_callback (const sc_char *string) * and match against the expectations on next request or on finalization. */ void -scr_start_script (sc_game game, sx_script script) -{ - sc_char *command, *expectation; - sx_scr_location_t location; - assert (game && script); - - /* Save the game and stream, and clear the line number and errors count. */ - assert (!scr_game && !scr_script); - scr_game = game; - scr_script = script; - scr_line_number = 0; - scr_errors = 0; - - /* Set up our callback functions to catch game i/o. */ - stub_attach_handlers (scr_read_line_callback, scr_print_string_callback, - file_open_file_callback, file_read_file_callback, - file_write_file_callback, file_close_file_callback); - - /* - * Handle any initial debugging commands, terminating on either a non- - * debugging one or an expectation for the game intro. - */ - scr_script->seek(0); - scr_save_location (scr_script, &location); - while (scr_get_next_section (scr_script, &command, &expectation)) - { - if (scr_is_line_debug_command (command)) - { - if (scr_is_line_empty_debug_command (command)) - { - /* It's an intro expectation - set and break loop. */ - scr_expect (expectation); - sx_free (command); - sx_free (expectation); - break; - } - else - { - /* It's a full debug command - execute it as one. */ - scr_execute_debugger_command (command, expectation); - sx_free (command); - sx_free (expectation); - } - } - else - { - /* - * It's an ordinary section - rewind so that it's the first one - * handled in the callback, and break loop. - */ - scr_restore_location (scr_script, &location); - sx_free (command); - sx_free (expectation); - break; - } - - /* Note script position before reading the next section. */ - scr_save_location (scr_script, &location); - } - - /* Ensure the game debugger is off after this section. */ - sc_set_game_debugger_enabled (scr_game, FALSE); +scr_start_script(sc_game game, sx_script script) { + sc_char *command, *expectation; + sx_scr_location_t location; + assert(game && script); + + /* Save the game and stream, and clear the line number and errors count. */ + assert(!scr_game && !scr_script); + scr_game = game; + scr_script = script; + scr_line_number = 0; + scr_errors = 0; + + /* Set up our callback functions to catch game i/o. */ + stub_attach_handlers(scr_read_line_callback, scr_print_string_callback, + file_open_file_callback, file_read_file_callback, + file_write_file_callback, file_close_file_callback); + + /* + * Handle any initial debugging commands, terminating on either a non- + * debugging one or an expectation for the game intro. + */ + scr_script->seek(0); + scr_save_location(scr_script, &location); + while (scr_get_next_section(scr_script, &command, &expectation)) { + if (scr_is_line_debug_command(command)) { + if (scr_is_line_empty_debug_command(command)) { + /* It's an intro expectation - set and break loop. */ + scr_expect(expectation); + sx_free(command); + sx_free(expectation); + break; + } else { + /* It's a full debug command - execute it as one. */ + scr_execute_debugger_command(command, expectation); + sx_free(command); + sx_free(expectation); + } + } else { + /* + * It's an ordinary section - rewind so that it's the first one + * handled in the callback, and break loop. + */ + scr_restore_location(scr_script, &location); + sx_free(command); + sx_free(expectation); + break; + } + + /* Note script position before reading the next section. */ + scr_save_location(scr_script, &location); + } + + /* Ensure the game debugger is off after this section. */ + sc_set_game_debugger_enabled(scr_game, FALSE); } @@ -591,51 +542,46 @@ scr_start_script (sc_game game, sx_script script) * count of errors detected during the script. */ sc_int -scr_finalize_script (void) -{ - sc_char *command, *expectation; - sc_int errors; - - /* Check pending expectation, and clear settings. */ - scr_verify_expectation (); - - /* Drain the remainder of the script, ignoring non-debugging commands. */ - while (scr_get_next_section (scr_script, &command, &expectation)) - { - if (scr_is_line_debug_command (command)) - { - scr_execute_debugger_command (command, expectation); - sx_free (command); - sx_free (expectation); - } - else - { - /* Complain about script entries ignored because the game ended. */ - scr_test_failed ("Script error:" - " Game completed, command \"%s\" ignored", command); - sx_free (command); - sx_free (expectation); - } - } - - /* Ensure the game debugger is off after this section. */ - sc_set_game_debugger_enabled (scr_game, FALSE); - - /* - * Remove our callback functions from the stubs, and "close" any retained - * stream data from game save/load tests. - */ - stub_detach_handlers (); - file_cleanup (); - - /* Clear local records of game stream, line number, and errors count. */ - errors = scr_errors; - scr_game = NULL; - scr_script = NULL; - scr_line_number = 0; - scr_errors = 0; - - return errors; +scr_finalize_script(void) { + sc_char *command, *expectation; + sc_int errors; + + /* Check pending expectation, and clear settings. */ + scr_verify_expectation(); + + /* Drain the remainder of the script, ignoring non-debugging commands. */ + while (scr_get_next_section(scr_script, &command, &expectation)) { + if (scr_is_line_debug_command(command)) { + scr_execute_debugger_command(command, expectation); + sx_free(command); + sx_free(expectation); + } else { + /* Complain about script entries ignored because the game ended. */ + scr_test_failed("Script error:" + " Game completed, command \"%s\" ignored", command); + sx_free(command); + sx_free(expectation); + } + } + + /* Ensure the game debugger is off after this section. */ + sc_set_game_debugger_enabled(scr_game, FALSE); + + /* + * Remove our callback functions from the stubs, and "close" any retained + * stream data from game save/load tests. + */ + stub_detach_handlers(); + file_cleanup(); + + /* Clear local records of game stream, line number, and errors count. */ + errors = scr_errors; + scr_game = NULL; + scr_script = NULL; + scr_line_number = 0; + scr_errors = 0; + + return errors; } } // End of namespace Adrift |