From 44bf5d77f21dd99f2404f0e7f1a9e41cb0c1a18f Mon Sep 17 00:00:00 2001 From: AliceLR Date: Wed, 29 Nov 2023 19:29:56 -0700 Subject: [PATCH] Save the current output file mode in saved games. --- docs/changelog.txt | 4 ++ docs/fileform.html | 16 +++++++ src/counter.c | 103 ++++++++++++++++---------------------------- src/utils/downver.c | 4 ++ src/world.c | 23 +++++++++- src/world_format.h | 5 ++- src/world_struct.h | 10 +++++ 7 files changed, 95 insertions(+), 70 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 2d329e636..856b8ed65 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -247,6 +247,10 @@ USERS + Robotic debugger watchpoints can now watch for particular counter or string values. Leaving the value field blank will still check for any value. ++ The output file mode (FWRITE_OPEN, FWRITE_MODIFY, or + FWRITE_APPEND) is now stored in save files. This fixes a bug + where the output file would be reopened in the wrong mode (ab) + when reloading a saved game. + editor_show_thing_toggles is now enabled by default. - board_editor_hide_help and robot_editor_hide_help are no longer enabled by default for accessibility. diff --git a/docs/fileform.html b/docs/fileform.html index 4827aeacb..d6a076b43 100644 --- a/docs/fileform.html +++ b/docs/fileform.html @@ -2504,6 +2504,7 @@

World Properties

| `0x8078` | Output filename | string | Save-only | `0x807C` | Output file position | int(d) | Save-only | `0x807D` | Output file delimiter | int(ds) | Save-only +| `0x807E` | Output file mode | int(b) | Save-only, 2.93+ (2) | `0x8080` | Multiplier | int(ds) | Save-only | `0x8081` | Divider | int(ds) | Save-only | `0x8082` | Circle divisions | int(ds) | Save-only @@ -2518,6 +2519,21 @@

World Properties

terminated, and may leave parts of previous world names in the loaded name if it is not. +
  • + This field may be omitted. Valid output file mode values: +
    +| Value | Mode | +|-------|--------------| +| 0 | none/unknown +| 1 | `w+b` +| 2 | `r+b` +| 3 | `a+b` +
    + Files opened in mode w+b should be reopened in mode + r+b. The output file is currently write-only, so + wb and ab are used in Robotic instead + of w+b and a+b for now. +
  • Status Counter Properties

    As of 2.93, the status counters are a nested properties file. Status diff --git a/src/counter.c b/src/counter.c index 8d1fdd770..794fc3462 100644 --- a/src/counter.c +++ b/src/counter.c @@ -2887,6 +2887,30 @@ static struct robot *get_robot_by_id(struct world *mzx_world, int id) return NULL; } +static void fread_close(struct world *mzx_world) +{ + if(!mzx_world->input_is_dir && mzx_world->input_file) + vfclose(mzx_world->input_file); + + if(mzx_world->input_is_dir && mzx_world->input_directory) + vdir_close(mzx_world->input_directory); + + mzx_world->input_file_name[0] = '\0'; + mzx_world->input_file = NULL; + mzx_world->input_directory = NULL; + mzx_world->input_is_dir = false; +} + +static void fwrite_close(struct world *mzx_world) +{ + if(mzx_world->output_file) + vfclose(mzx_world->output_file); + + mzx_world->output_file_name[0] = '\0'; + mzx_world->output_file = NULL; + mzx_world->output_mode = FWRITE_MODE_UNKNOWN; +} + int set_counter_special(struct world *mzx_world, char *char_value, int value, int id) { @@ -2899,25 +2923,15 @@ int set_counter_special(struct world *mzx_world, char *char_value, { case FOPEN_FREAD: { - mzx_world->input_file_name[0] = 0; + fread_close(mzx_world); if(char_value[0]) { - char *translated_path = cmalloc(MAX_PATH); + char *translated_path = (char *)cmalloc(MAX_PATH); int err; - if(!mzx_world->input_is_dir && mzx_world->input_file) - { - vfclose(mzx_world->input_file); - mzx_world->input_file = NULL; - } - - if(mzx_world->input_is_dir) - { - vdir_close(mzx_world->input_directory); - mzx_world->input_directory = NULL; - mzx_world->input_is_dir = false; - } + if(!translated_path) + return 0; err = fsafetranslate(char_value, translated_path, MAX_PATH); @@ -2937,97 +2951,54 @@ int set_counter_special(struct world *mzx_world, char *char_value, free(translated_path); } - else - { - if(!mzx_world->input_is_dir && mzx_world->input_file) - { - vfclose(mzx_world->input_file); - mzx_world->input_file = NULL; - } - - if(mzx_world->input_is_dir) - { - vdir_close(mzx_world->input_directory); - mzx_world->input_directory = NULL; - mzx_world->input_is_dir = false; - } - } - break; } case FOPEN_FWRITE: { - mzx_world->output_file_name[0] = 0; + fwrite_close(mzx_world); if(char_value[0]) { - if(mzx_world->output_file) - vfclose(mzx_world->output_file); - mzx_world->output_file = fsafeopen(char_value, "wb"); - if(mzx_world->output_file) - strcpy(mzx_world->output_file_name, char_value); - } - else - { if(mzx_world->output_file) { - vfclose(mzx_world->output_file); - mzx_world->output_file = NULL; + strcpy(mzx_world->output_file_name, char_value); + mzx_world->output_mode = FWRITE_MODE_TRUNCATE; } } - break; } case FOPEN_FAPPEND: { - mzx_world->output_file_name[0] = 0; + fwrite_close(mzx_world); if(char_value[0]) { - if(mzx_world->output_file) - vfclose(mzx_world->output_file); - mzx_world->output_file = fsafeopen(char_value, "ab"); - if(mzx_world->output_file) - strcpy(mzx_world->output_file_name, char_value); - } - else - { if(mzx_world->output_file) { - vfclose(mzx_world->output_file); - mzx_world->output_file = NULL; + strcpy(mzx_world->output_file_name, char_value); + mzx_world->output_mode = FWRITE_MODE_APPEND; } } - break; } case FOPEN_FMODIFY: { - mzx_world->output_file_name[0] = 0; + fwrite_close(mzx_world); if(char_value[0]) { - if(mzx_world->output_file) - vfclose(mzx_world->output_file); - mzx_world->output_file = fsafeopen(char_value, "r+b"); - if(mzx_world->output_file) - strcpy(mzx_world->output_file_name, char_value); - } - else - { if(mzx_world->output_file) { - vfclose(mzx_world->output_file); - mzx_world->output_file = NULL; + strcpy(mzx_world->output_file_name, char_value); + mzx_world->output_mode = FWRITE_MODE_MODIFY; } } - break; } diff --git a/src/utils/downver.c b/src/utils/downver.c index 8f2d4b4b1..a213556f3 100644 --- a/src/utils/downver.c +++ b/src/utils/downver.c @@ -235,6 +235,10 @@ static void convert_293_to_292_world_info(struct downver_state *dv, save_prop_c(ident, dv->screen_mode, dest); break; + case WPROP_OUTPUT_MODE: + /* Added in 2.93 */ + break; + default: save_prop_p(ident, &prop, dest); break; diff --git a/src/world.c b/src/world.c index a19084d5e..410095850 100644 --- a/src/world.c +++ b/src/world.c @@ -401,6 +401,9 @@ static inline int save_world_info(struct world *mzx_world, save_prop_s(WPROP_OUTPUT_FILE_NAME, mzx_world->output_file_name, mf); save_prop_d(WPROP_OUTPUT_POS, mzx_world->temp_output_pos, mf); save_prop_d(WPROP_FWRITE_DELIMITER, mzx_world->fwrite_delimiter, mf); + if(file_version >= V293) + save_prop_c(WPROP_OUTPUT_MODE, mzx_world->output_mode, mf); + save_prop_d(WPROP_MULTIPLIER, mzx_world->multiplier, mf); save_prop_d(WPROP_DIVIDER, mzx_world->divider, mf); save_prop_d(WPROP_C_DIVISIONS, mzx_world->c_divisions, mf); @@ -567,6 +570,7 @@ static inline enum val_result validate_world_info(struct world *mzx_world, check(WPROP_OUTPUT_FILE_NAME); check(WPROP_OUTPUT_POS); check(WPROP_FWRITE_DELIMITER); + // ignore optional WPROP_OUTPUT_MODE (2.93) check(WPROP_MULTIPLIER); check(WPROP_DIVIDER); check(WPROP_C_DIVISIONS); @@ -1038,6 +1042,16 @@ static inline void load_world_info(struct world *mzx_world, mzx_world->fwrite_delimiter = load_prop_int(prop) & 255; break; + case WPROP_OUTPUT_MODE: + if_savegame + if(*file_version >= V293) + { + int tmp = load_prop_int_u(prop, FWRITE_MODE_UNKNOWN, FWRITE_MODE_MAX); + mzx_world->output_mode = + tmp < FWRITE_MODE_MAX ? (enum fwrite_mode)tmp : FWRITE_MODE_UNKNOWN; + } + break; + case WPROP_MULTIPLIER: if_savegame mzx_world->multiplier = load_prop_int(prop); @@ -2890,8 +2904,12 @@ static void load_world(struct world *mzx_world, struct zip_archive *zp, // Open output file if(mzx_world->output_file_name[0]) { - mzx_world->output_file = - fsafeopen(mzx_world->output_file_name, "ab"); + // Truncation occurred during the initial FWRITE_APPEND, + // so wb and r+b should both be reopened as r+b. + if(mzx_world->output_mode == FWRITE_MODE_APPEND) + mzx_world->output_file = fsafeopen(mzx_world->output_file_name, "ab"); + else + mzx_world->output_file = fsafeopen(mzx_world->output_file_name, "r+b"); if(mzx_world->output_file) { @@ -3531,6 +3549,7 @@ void clear_world(struct world *mzx_world) vfclose(mzx_world->output_file); mzx_world->output_file = NULL; } + mzx_world->output_mode = FWRITE_MODE_UNKNOWN; mzx_world->current_cycle_odd = false; mzx_world->current_cycle_frozen = false; diff --git a/src/world_format.h b/src/world_format.h index bd8ad20e2..0ea5cf08f 100644 --- a/src/world_format.h +++ b/src/world_format.h @@ -98,8 +98,8 @@ enum status_counters_prop #define COUNT_WORLD_PROPS ( 1 + 3 + 4 + 16 + 4 + 1) #define BOUND_WORLD_PROPS (BOARD_NAME_SIZE + 5 + 455 + 24 + 9 + STATCTR_PROP_SIZE) -#define COUNT_SAVE_PROPS ( 2 + 32 + 3 + 1) -#define BOUND_SAVE_PROPS ( 2 + 120 + 3*MAX_PATH + NUM_KEYS) +#define COUNT_SAVE_PROPS ( 2 + 33 + 3 + 1) +#define BOUND_SAVE_PROPS ( 2 + 121 + 3*MAX_PATH + NUM_KEYS) // For world files, use WORLD_PROP_SIZE // For save files, use WORLD_PROP_SIZE + SAVE_PROP_SIZE @@ -194,6 +194,7 @@ enum world_prop WPROP_OUTPUT_FILE_NAME = 0x8078, // MAX_PATH WPROP_OUTPUT_POS = 0x807C, // 4 WPROP_FWRITE_DELIMITER = 0x807D, // 4 + WPROP_OUTPUT_MODE = 0x807E, // 1 WPROP_MULTIPLIER = 0x8080, // 4 WPROP_DIVIDER = 0x8081, // 4 WPROP_C_DIVISIONS = 0x8082, // 4 diff --git a/src/world_struct.h b/src/world_struct.h index 3fec3f4bd..ecc8df093 100644 --- a/src/world_struct.h +++ b/src/world_struct.h @@ -48,6 +48,15 @@ enum change_game_state_value CHANGE_STATE_REQUEST_EXIT }; +enum fwrite_mode +{ + FWRITE_MODE_UNKNOWN, + FWRITE_MODE_TRUNCATE, + FWRITE_MODE_MODIFY, + FWRITE_MODE_APPEND, + FWRITE_MODE_MAX +}; + struct world { // 0 if a world has been loaded, 1 if it hasn't @@ -129,6 +138,7 @@ struct world vfile *input_file; vdir *input_directory; boolean input_is_dir; + enum fwrite_mode output_mode; int temp_input_pos; int temp_output_pos; int commands;