X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/48d4740c8305b8a59a9fc067916582b4e44b465e..4c692867911ca67863d00f8538ce4b7d6928779e:/midend.c diff --git a/midend.c b/midend.c index 15d11bb..df661b5 100644 --- a/midend.c +++ b/midend.c @@ -149,6 +149,7 @@ void midend_free(midend_data *me) random_free(me->random); sfree(me->states); sfree(me->desc); + sfree(me->privdesc); sfree(me->seedstr); sfree(me->aux_info); me->ourgame->free_params(me->params); @@ -386,37 +387,38 @@ static int midend_really_process_key(midend_data *me, int x, int y, int button) me->ourgame->dup_game(me->states[me->statepos - 1].state); int special = FALSE, gotspecial = FALSE, ret = 1; float anim_time; + game_state *s; + char *movestr; + + movestr = + me->ourgame->interpret_move(me->states[me->statepos-1].state, + me->ui, me->drawstate, x, y, button); - if (button == 'n' || button == 'N' || button == '\x0E') { - midend_stop_anim(me); - midend_new_game(me); - midend_redraw(me); - goto done; /* never animate */ - } else if (button == 'u' || button == 'u' || - button == '\x1A' || button == '\x1F') { - midend_stop_anim(me); - special = special(me->states[me->statepos-1].movetype); - gotspecial = TRUE; - if (!midend_undo(me)) + if (!movestr) { + if (button == 'n' || button == 'N' || button == '\x0E') { + midend_stop_anim(me); + midend_new_game(me); + midend_redraw(me); + goto done; /* never animate */ + } else if (button == 'u' || button == 'u' || + button == '\x1A' || button == '\x1F') { + midend_stop_anim(me); + special = special(me->states[me->statepos-1].movetype); + gotspecial = TRUE; + if (!midend_undo(me)) + goto done; + } else if (button == 'r' || button == 'R' || + button == '\x12' || button == '\x19') { + midend_stop_anim(me); + if (!midend_redo(me)) + goto done; + } else if (button == 'q' || button == 'Q' || button == '\x11') { + ret = 0; + goto done; + } else goto done; - } else if (button == 'r' || button == 'R' || - button == '\x12' || button == '\x19') { - midend_stop_anim(me); - if (!midend_redo(me)) - goto done; - } else if (button == 'q' || button == 'Q' || button == '\x11') { - ret = 0; - goto done; } else { - game_state *s; - char *movestr; - - movestr = - me->ourgame->interpret_move(me->states[me->statepos-1].state, - me->ui, me->drawstate, x, y, button); - if (!movestr) - s = NULL; - else if (!*movestr) + if (!*movestr) s = me->states[me->statepos-1].state; else { s = me->ourgame->execute_move(me->states[me->statepos-1].state, @@ -756,7 +758,7 @@ int midend_num_presets(midend_data *me) } me->presets[me->npresets] = preset; - me->preset_names[me->npresets] = name; + me->preset_names[me->npresets] = dupstr(name); me->npresets++; } } @@ -854,6 +856,8 @@ config_item *midend_get_config(midend_data *me, int which, char **wintitle) static char *midend_game_id_int(midend_data *me, char *id, int defmode) { char *error, *par, *desc, *seed; + game_params *newcurparams, *newparams, *oldparams1, *oldparams2; + int free_params; seed = strchr(id, '#'); desc = strchr(id, ':'); @@ -893,18 +897,24 @@ static char *midend_game_id_int(midend_data *me, char *id, int defmode) } } + /* + * We must be reasonably careful here not to modify anything in + * `me' until we have finished validating things. This function + * must either return an error and do nothing to the midend, or + * return success and do everything; nothing in between is + * acceptable. + */ + newcurparams = newparams = oldparams1 = oldparams2 = NULL; + if (par) { - game_params *tmpparams; - tmpparams = me->ourgame->dup_params(me->params); - me->ourgame->decode_params(tmpparams, par); - error = me->ourgame->validate_params(tmpparams); + newcurparams = me->ourgame->dup_params(me->params); + me->ourgame->decode_params(newcurparams, par); + error = me->ourgame->validate_params(newcurparams); if (error) { - me->ourgame->free_params(tmpparams); + me->ourgame->free_params(newcurparams); return error; } - if (me->curparams) - me->ourgame->free_params(me->curparams); - me->curparams = tmpparams; + oldparams1 = me->curparams; /* * Now filter only the persistent parts of this state into @@ -912,16 +922,50 @@ static char *midend_game_id_int(midend_data *me, char *id, int defmode) * received a params string in which case the whole lot is * persistent. */ + oldparams2 = me->params; if (seed || desc) { - char *tmpstr = me->ourgame->encode_params(tmpparams, FALSE); - me->ourgame->decode_params(me->params, tmpstr); + char *tmpstr; + + newparams = me->ourgame->dup_params(me->params); + + tmpstr = me->ourgame->encode_params(newcurparams, FALSE); + me->ourgame->decode_params(newparams, tmpstr); + sfree(tmpstr); } else { - me->ourgame->free_params(me->params); - me->params = me->ourgame->dup_params(tmpparams); + newparams = me->ourgame->dup_params(newcurparams); } + free_params = TRUE; + } else { + newcurparams = me->curparams; + newparams = me->params; + free_params = FALSE; } + if (desc) { + error = me->ourgame->validate_desc(newparams, desc); + if (error) { + if (free_params) { + if (newcurparams) + me->ourgame->free_params(newcurparams); + if (newparams) + me->ourgame->free_params(newparams); + } + return error; + } + } + + /* + * Now we've got past all possible error points. Update the + * midend itself. + */ + me->params = newparams; + me->curparams = newcurparams; + if (oldparams1) + me->ourgame->free_params(oldparams1); + if (oldparams2) + me->ourgame->free_params(oldparams2); + sfree(me->desc); sfree(me->privdesc); me->desc = me->privdesc = NULL; @@ -929,10 +973,6 @@ static char *midend_game_id_int(midend_data *me, char *id, int defmode) me->seedstr = NULL; if (desc) { - error = me->ourgame->validate_desc(me->params, desc); - if (error) - return error; - me->desc = dupstr(desc); me->genmode = GOT_DESC; sfree(me->aux_info); @@ -1351,7 +1391,7 @@ char *midend_deserialise(midend_data *me, uistr = val; val = NULL; } else if (!strcmp(key, "TIME")) { - elapsed = strtod(val, NULL); + elapsed = atof(val); } else if (!strcmp(key, "NSTATES")) { nstates = atoi(val); if (nstates <= 0) { @@ -1516,6 +1556,12 @@ char *midend_deserialise(midend_data *me, midend_set_timer(me); + if (me->drawstate) + me->ourgame->free_drawstate(me->drawstate); + me->drawstate = + me->ourgame->new_drawstate(me->states[me->statepos-1].state); + midend_size_new_drawstate(me); + ret = NULL; /* success! */ cleanup: