Parser: make parser (mostly) reentrant

Introduce a parser_state structure, which describes (most) of the
global parser state. Create such a structure in the entry routines
to the parser and pass it down to the individual functions. The
parser state is initialized and freed with the init_parser_state()
and free_parser_state() functions.

The main benefits are:
1) Isolation of parser state.
2) Keeping the global name space tidy.
3) Prevent memory leaks which could happen in truncated files by
   freeing all the parser state after parse.

A somewhat controversial point might be that the individual
parsing functions are split in those that need parser-state and
those that don't. This means that there are now two versions of
the MATCH macro, viz. one for the former and one for the latter.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2018-10-17 18:45:22 +02:00 committed by Dirk Hohndel
parent 343808271c
commit 138f27f65d
7 changed files with 1022 additions and 957 deletions

View file

@ -9,20 +9,9 @@ typedef union {
char allocation[sizeof(struct event) + MAX_EVENT_NAME];
} event_allocation_t;
extern event_allocation_t event_allocation;
#define cur_event event_allocation.event
/*
* Dive info as it is being built up..
*/
extern struct divecomputer *cur_dc;
extern struct dive *cur_dive;
extern struct dive_site *cur_dive_site;
extern location_t cur_location;
extern dive_trip_t *cur_trip;
extern struct sample *cur_sample;
extern struct picture *cur_picture;
struct parser_settings {
struct {
@ -31,66 +20,94 @@ struct parser_settings {
const char *nickname, *serial_nr, *firmware;
} dc;
};
extern struct parser_settings cur_settings;
extern bool in_settings;
extern bool in_userid;
extern struct tm cur_tm;
extern int cur_cylinder_index, cur_ws_index;
extern int lastcylinderindex, next_o2_sensor;
extern int o2pressure_sensor;
extern struct extra_data cur_extra_data;
enum import_source {
UNKNOWN,
LIBDIVECOMPUTER,
DIVINGLOG,
UDDF,
} import_source;
};
/*
* parser_state is the state needed by the parser(s). It is initialized
* with init_parser_state() and resources are freed with free_parser_state().
* "owning" marks pointers to objects that are freed in free_parser_state().
* In contrast, "non-owning" marks pointers to objects that are owned
* by other data-structures.
*/
struct parser_state {
bool metric;
struct parser_settings cur_settings;
enum import_source import_source;
struct divecomputer *cur_dc; /* non-owning */
struct dive *cur_dive; /* owning */
struct dive_site *cur_dive_site; /* owning */
location_t cur_location;
dive_trip_t *cur_trip; /* owning */
struct sample *cur_sample; /* non-owning */
struct picture *cur_picture; /* owning */
char *country, *city; /* owning */
bool in_settings;
bool in_userid;
struct tm cur_tm;
int cur_cylinder_index, cur_ws_index;
int lastcylinderindex, next_o2_sensor;
int o2pressure_sensor;
struct extra_data cur_extra_data;
struct units xml_parsing_units;
struct dive_table *target_table; /* non-owning */
sqlite3 *sql_handle; /* for SQL based parsers */
event_allocation_t event_allocation;
};
#define cur_event event_allocation.event
void init_parser_state(struct parser_state *state);
void free_parser_state(struct parser_state *state);
/* the dive table holds the overall dive list; target table points at
* the table we are currently filling */
extern struct dive_table dive_table;
extern struct dive_table *target_table;
extern int metric;
int trimspace(char *buffer);
void start_match(const char *type, const char *name, char *buffer);
void nonmatch(const char *type, const char *name, char *buffer);
void event_start(void);
void event_end(void);
struct divecomputer *get_dc(void);
void event_start(struct parser_state *state);
void event_end(struct parser_state *state);
struct divecomputer *get_dc(struct parser_state *state);
bool is_dive(void);
void reset_dc_info(struct divecomputer *dc);
void reset_dc_settings(void);
void settings_start(void);
void settings_end(void);
void dc_settings_start(void);
void dc_settings_end(void);
void dive_site_start(void);
void dive_site_end(void);
void dive_start(void);
void dive_end(void);
void trip_start(void);
void trip_end(void);
void picture_start(void);
void picture_end(void);
void cylinder_start(void);
void cylinder_end(void);
void ws_start(void);
void ws_end(void);
bool is_dive(struct parser_state *state);
void reset_dc_info(struct divecomputer *dc, struct parser_state *state);
void reset_dc_settings(struct parser_state *state);
void settings_start(struct parser_state *state);
void settings_end(struct parser_state *state);
void dc_settings_start(struct parser_state *state);
void dc_settings_end(struct parser_state *state);
void dive_site_start(struct parser_state *state);
void dive_site_end(struct parser_state *state);
void dive_start(struct parser_state *state);
void dive_end(struct parser_state *state);
void trip_start(struct parser_state *state);
void trip_end(struct parser_state *state);
void picture_start(struct parser_state *state);
void picture_end(struct parser_state *state);
void cylinder_start(struct parser_state *state);
void cylinder_end(struct parser_state *state);
void ws_start(struct parser_state *state);
void ws_end(struct parser_state *state);
void sample_start(void);
void sample_end(void);
void divecomputer_start(void);
void divecomputer_end(void);
void userid_start(void);
void userid_stop(void);
void sample_start(struct parser_state *state);
void sample_end(struct parser_state *state);
void divecomputer_start(struct parser_state *state);
void divecomputer_end(struct parser_state *state);
void userid_start(struct parser_state *state);
void userid_stop(struct parser_state *state);
void utf8_string(char *buffer, void *_res);
void add_dive_site(char *ds_name, struct dive *dive);
void add_dive_site(char *ds_name, struct dive *dive, struct parser_state *state);
int atoi_n(char *ptr, unsigned int len);
#endif