diff options
Diffstat (limited to 'source/state.h')
| -rw-r--r-- | source/state.h | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/source/state.h b/source/state.h new file mode 100644 index 0000000..2f70527 --- /dev/null +++ b/source/state.h @@ -0,0 +1,57 @@ +#ifndef EXITEST_STATE_H_INCLUDED +#define EXITEST_STATE_H_INCLUDED + +#include <stdint.h> +#include <stddef.h> + +struct et_state; + +typedef union { + uintptr_t i; + void *p; +} et_state_init_data; + +extern const et_state_init_data et_init_data_null; + +struct et_next_state { + const struct et_state *state; + et_state_init_data init_data; +}; + +/* Sets up the state. The second argument (void *) should point to at least state->private_size bytes + * of data. The state assumes responsibility for clearing/initializing this buffer before use. + * + * Returns < 0 for error, >= 0 for success. + * This function conceptually takes ownership of init_data. The implications of this depend + * on what init_data actually contains -- sometimes it's globally shared data. + * + * State authors: Free any data filled into init_data regardless of error states. + * The caller will not touch init_data again. */ +typedef int (et_state_init_f)(const struct et_state *, void *, et_state_init_data); + +/* Ticks the state. + * + * Returns < 0 for error (still call cleanup or exit(...)), 0 for "continue", >0 for "advance state". + * If a state requests to advance to the next state, the info will be in *next_state (which should be non-NULL). + * Note that next_state->init_data may have malloc()'d data which must be handed off by passing to the init function + * of the appropriate state. */ +typedef int (et_state_tick_f)(const struct et_state *, void *, struct et_next_state *); +typedef void (et_state_cleanup_f)(const struct et_state *, void *); + +struct et_state { + et_state_init_f *init_f; + et_state_tick_f *tick_f; + et_state_cleanup_f *cleanup_f; + size_t private_size; +}; + +/* convenience macros because these existed as functions at one point + * (note: state expression is evaluated twice. make sure it doesn't have side effects) */ + +#define et_state_init(_st, _data, _init_data) ((_st)->init_f(_st, _data, _init_data)) +#define et_state_tick(_st, _data, _next) ((_st)->tick_f(_st, _data, _next)) +#define et_state_cleanup(_st, _data) ((_st)->cleanup_f(_st, _data)) + +extern const struct et_state *et_state_setup; + +#endif /* include guard */ |
