diff options
author | Berthold Stoeger <bstoeger@mail.tuwien.ac.at> | 2018-10-17 18:45:22 +0200 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2018-10-23 08:06:17 +0100 |
commit | 138f27f65d7f92e313be212cdcaee05aa09a7586 (patch) | |
tree | 65d608f9cbae7487cd30f4ac6a3b8c5bfa32cce1 /core/import-shearwater.c | |
parent | 343808271c22942992f4470c05e138d8597a630b (diff) | |
download | subsurface-138f27f65d7f92e313be212cdcaee05aa09a7586.tar.gz |
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>
Diffstat (limited to 'core/import-shearwater.c')
-rw-r--r-- | core/import-shearwater.c | 182 |
1 files changed, 94 insertions, 88 deletions
diff --git a/core/import-shearwater.c b/core/import-shearwater.c index 2105055a0..629f4721f 100644 --- a/core/import-shearwater.c +++ b/core/import-shearwater.c @@ -13,11 +13,11 @@ #include "membuffer.h" #include "gettext.h" -extern int shearwater_cylinders(void *handle, int columns, char **data, char **column) +static int shearwater_cylinders(void *param, int columns, char **data, char **column) { - UNUSED(handle); UNUSED(columns); UNUSED(column); + struct parser_state *state = (struct parser_state *)param; int o2 = lrint(strtod_flags(data[0], NULL, 0) * 1000); int he = lrint(strtod_flags(data[1], NULL, 0) * 1000); @@ -27,19 +27,19 @@ extern int shearwater_cylinders(void *handle, int columns, char **data, char **c if (o2 == 990 && he == 0) o2 = 1000; - cylinder_start(); - cur_dive->cylinder[cur_cylinder_index].gasmix.o2.permille = o2; - cur_dive->cylinder[cur_cylinder_index].gasmix.he.permille = he; - cylinder_end(); + cylinder_start(state); + state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.o2.permille = o2; + state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.he.permille = he; + cylinder_end(state); return 0; } -extern int shearwater_changes(void *handle, int columns, char **data, char **column) +static int shearwater_changes(void *param, int columns, char **data, char **column) { - UNUSED(handle); UNUSED(columns); UNUSED(column); + struct parser_state *state = (struct parser_state *)param; if (columns != 3) { return 1; @@ -58,148 +58,149 @@ extern int shearwater_changes(void *handle, int columns, char **data, char **col // Find the cylinder index int i; bool found = false; - for (i = 0; i < cur_cylinder_index; ++i) { - if (cur_dive->cylinder[i].gasmix.o2.permille == o2 && cur_dive->cylinder[i].gasmix.he.permille == he) { + for (i = 0; i < state->cur_cylinder_index; ++i) { + if (state->cur_dive->cylinder[i].gasmix.o2.permille == o2 && state->cur_dive->cylinder[i].gasmix.he.permille == he) { found = true; break; } } if (!found) { // Cylinder not found, creating a new one - cylinder_start(); - cur_dive->cylinder[cur_cylinder_index].gasmix.o2.permille = o2; - cur_dive->cylinder[cur_cylinder_index].gasmix.he.permille = he; - cylinder_end(); - i = cur_cylinder_index; + cylinder_start(state); + state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.o2.permille = o2; + state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.he.permille = he; + cylinder_end(state); + i = state->cur_cylinder_index; } - add_gas_switch_event(cur_dive, get_dc(), atoi(data[0]), i); + add_gas_switch_event(state->cur_dive, get_dc(state), atoi(data[0]), i); return 0; } -extern int shearwater_profile_sample(void *handle, int columns, char **data, char **column) +static int shearwater_profile_sample(void *param, int columns, char **data, char **column) { - UNUSED(handle); UNUSED(columns); UNUSED(column); + struct parser_state *state = (struct parser_state *)param; int d6, d7; - sample_start(); + sample_start(state); if (data[0]) - cur_sample->time.seconds = atoi(data[0]); + state->cur_sample->time.seconds = atoi(data[0]); if (data[1]) - cur_sample->depth.mm = metric ? lrint(strtod_flags(data[1], NULL, 0) * 1000) : feet_to_mm(strtod_flags(data[1], NULL, 0)); + state->cur_sample->depth.mm = state->metric ? lrint(strtod_flags(data[1], NULL, 0) * 1000) : feet_to_mm(strtod_flags(data[1], NULL, 0)); if (data[2]) - cur_sample->temperature.mkelvin = metric ? C_to_mkelvin(strtod_flags(data[2], NULL, 0)) : F_to_mkelvin(strtod_flags(data[2], NULL, 0)); + state->cur_sample->temperature.mkelvin = state->metric ? C_to_mkelvin(strtod_flags(data[2], NULL, 0)) : F_to_mkelvin(strtod_flags(data[2], NULL, 0)); if (data[3]) { - cur_sample->setpoint.mbar = lrint(strtod_flags(data[3], NULL, 0) * 1000); + state->cur_sample->setpoint.mbar = lrint(strtod_flags(data[3], NULL, 0) * 1000); } if (data[4]) - cur_sample->ndl.seconds = atoi(data[4]) * 60; + state->cur_sample->ndl.seconds = atoi(data[4]) * 60; if (data[5]) - cur_sample->cns = atoi(data[5]); + state->cur_sample->cns = atoi(data[5]); if (data[6]) { d6 = atoi(data[6]); if (d6 > 0) { - cur_sample->stopdepth.mm = metric ? d6 * 1000 : feet_to_mm(d6); - cur_sample->in_deco = 1; + state->cur_sample->stopdepth.mm = state->metric ? d6 * 1000 : feet_to_mm(d6); + state->cur_sample->in_deco = 1; } else if (data[7]) { d7 = atoi(data[7]); if (d7 > 0) { - cur_sample->stopdepth.mm = metric ? d7 * 1000 : feet_to_mm(d7); + state->cur_sample->stopdepth.mm = state->metric ? d7 * 1000 : feet_to_mm(d7); if (data[8]) - cur_sample->stoptime.seconds = atoi(data[8]) * 60; - cur_sample->in_deco = 1; + state->cur_sample->stoptime.seconds = atoi(data[8]) * 60; + state->cur_sample->in_deco = 1; } else { - cur_sample->in_deco = 0; + state->cur_sample->in_deco = 0; } } else { - cur_sample->in_deco = 0; + state->cur_sample->in_deco = 0; } } /* We don't actually have data[3], but it should appear in the * SQL query at some point. if (data[3]) - cur_sample->pressure[0].mbar = metric ? atoi(data[3]) * 1000 : psi_to_mbar(atoi(data[3])); + state->cur_sample->pressure[0].mbar = state->metric ? atoi(data[3]) * 1000 : psi_to_mbar(atoi(data[3])); */ - sample_end(); + sample_end(state); return 0; } -extern int shearwater_ai_profile_sample(void *handle, int columns, char **data, char **column) +static int shearwater_ai_profile_sample(void *param, int columns, char **data, char **column) { - UNUSED(handle); UNUSED(columns); UNUSED(column); + struct parser_state *state = (struct parser_state *)param; int d6, d9; - sample_start(); + sample_start(state); if (data[0]) - cur_sample->time.seconds = atoi(data[0]); + state->cur_sample->time.seconds = atoi(data[0]); if (data[1]) - cur_sample->depth.mm = metric ? lrint(strtod_flags(data[1], NULL, 0) * 1000) : feet_to_mm(strtod_flags(data[1], NULL, 0)); + state->cur_sample->depth.mm = state->metric ? lrint(strtod_flags(data[1], NULL, 0) * 1000) : feet_to_mm(strtod_flags(data[1], NULL, 0)); if (data[2]) - cur_sample->temperature.mkelvin = metric ? C_to_mkelvin(strtod_flags(data[2], NULL, 0)) : F_to_mkelvin(strtod_flags(data[2], NULL, 0)); + state->cur_sample->temperature.mkelvin = state->metric ? C_to_mkelvin(strtod_flags(data[2], NULL, 0)) : F_to_mkelvin(strtod_flags(data[2], NULL, 0)); if (data[3]) { - cur_sample->setpoint.mbar = lrint(strtod_flags(data[3], NULL, 0) * 1000); + state->cur_sample->setpoint.mbar = lrint(strtod_flags(data[3], NULL, 0) * 1000); } if (data[4]) - cur_sample->ndl.seconds = atoi(data[4]) * 60; + state->cur_sample->ndl.seconds = atoi(data[4]) * 60; if (data[5]) - cur_sample->cns = atoi(data[5]); + state->cur_sample->cns = atoi(data[5]); if (data[6]) { d6 = atoi(data[6]); if (d6 > 0) { - cur_sample->stopdepth.mm = metric ? d6 * 1000 : feet_to_mm(d6); - cur_sample->in_deco = 1; + state->cur_sample->stopdepth.mm = state->metric ? d6 * 1000 : feet_to_mm(d6); + state->cur_sample->in_deco = 1; } else if (data[9]) { d9 = atoi(data[9]); if (d9 > 0) { - cur_sample->stopdepth.mm = metric ? d9 * 1000 : feet_to_mm(d9); + state->cur_sample->stopdepth.mm = state->metric ? d9 * 1000 : feet_to_mm(d9); if (data[10]) - cur_sample->stoptime.seconds = atoi(data[10]) * 60; - cur_sample->in_deco = 1; + state->cur_sample->stoptime.seconds = atoi(data[10]) * 60; + state->cur_sample->in_deco = 1; } else { - cur_sample->in_deco = 0; + state->cur_sample->in_deco = 0; } } else { - cur_sample->in_deco = 0; + state->cur_sample->in_deco = 0; } } /* Weird unit conversion but seems to produce correct results. * Also missing values seems to be reported as a 4092 (564 bar) */ if (data[7] && atoi(data[7]) != 4092) { - cur_sample->pressure[0].mbar = psi_to_mbar(atoi(data[7])) * 2; + state->cur_sample->pressure[0].mbar = psi_to_mbar(atoi(data[7])) * 2; } if (data[8] && atoi(data[8]) != 4092) - cur_sample->pressure[1].mbar = psi_to_mbar(atoi(data[8])) * 2; - sample_end(); + state->cur_sample->pressure[1].mbar = psi_to_mbar(atoi(data[8])) * 2; + sample_end(state); return 0; } -extern int shearwater_mode(void *handle, int columns, char **data, char **column) +static int shearwater_mode(void *param, int columns, char **data, char **column) { - UNUSED(handle); UNUSED(columns); UNUSED(column); + struct parser_state *state = (struct parser_state *)param; if (data[0]) - cur_dive->dc.divemode = atoi(data[0]) == 0 ? CCR : OC; + state->cur_dive->dc.divemode = atoi(data[0]) == 0 ? CCR : OC; return 0; } -extern int shearwater_dive(void *param, int columns, char **data, char **column) +static int shearwater_dive(void *param, int columns, char **data, char **column) { UNUSED(columns); UNUSED(column); int retval = 0; - sqlite3 *handle = (sqlite3 *)param; + struct parser_state *state = (struct parser_state *)param; + sqlite3 *handle = state->sql_handle; char *err = NULL; char get_profile_template[] = "select currentTime,currentDepth,waterTemp,averagePPO2,currentNdl,CNSPercent,decoCeiling,firstStopDepth,firstStopTime from dive_log_records where diveLogId=%d"; char get_profile_template_ai[] = "select currentTime,currentDepth,waterTemp,averagePPO2,currentNdl,CNSPercent,decoCeiling,aiSensor0_PressurePSI,aiSensor1_PressurePSI,firstStopDepth,firstStopTime from dive_log_records where diveLogId = %d"; @@ -208,74 +209,74 @@ extern int shearwater_dive(void *param, int columns, char **data, char **column) char get_mode_template[] = "select distinct currentCircuitSetting from dive_log_records where diveLogId = %d"; char get_buffer[1024]; - dive_start(); - cur_dive->number = atoi(data[0]); + dive_start(state); + state->cur_dive->number = atoi(data[0]); - cur_dive->when = (time_t)(atol(data[1])); + state->cur_dive->when = (time_t)(atol(data[1])); int dive_id = atoi(data[11]); if (data[2]) - add_dive_site(data[2], cur_dive); + add_dive_site(data[2], state->cur_dive, state); if (data[3]) - utf8_string(data[3], &cur_dive->buddy); + utf8_string(data[3], &state->cur_dive->buddy); if (data[4]) - utf8_string(data[4], &cur_dive->notes); + utf8_string(data[4], &state->cur_dive->notes); - metric = atoi(data[5]) == 1 ? 0 : 1; + state->metric = atoi(data[5]) == 1 ? 0 : 1; /* TODO: verify that metric calculation is correct */ if (data[6]) - cur_dive->dc.maxdepth.mm = metric ? lrint(strtod_flags(data[6], NULL, 0) * 1000) : feet_to_mm(strtod_flags(data[6], NULL, 0)); + state->cur_dive->dc.maxdepth.mm = state->metric ? lrint(strtod_flags(data[6], NULL, 0) * 1000) : feet_to_mm(strtod_flags(data[6], NULL, 0)); if (data[7]) - cur_dive->dc.duration.seconds = atoi(data[7]) * 60; + state->cur_dive->dc.duration.seconds = atoi(data[7]) * 60; if (data[8]) - cur_dive->dc.surface_pressure.mbar = atoi(data[8]); + state->cur_dive->dc.surface_pressure.mbar = atoi(data[8]); /* * TODO: the deviceid hash should be calculated here. */ - settings_start(); - dc_settings_start(); + settings_start(state); + dc_settings_start(state); if (data[9]) - utf8_string(data[9], &cur_settings.dc.serial_nr); + utf8_string(data[9], &state->cur_settings.dc.serial_nr); if (data[10]) { switch (atoi(data[10])) { case 2: - cur_settings.dc.model = strdup("Shearwater Petrel/Perdix"); + state->cur_settings.dc.model = strdup("Shearwater Petrel/Perdix"); break; case 4: - cur_settings.dc.model = strdup("Shearwater Predator"); + state->cur_settings.dc.model = strdup("Shearwater Predator"); break; default: - cur_settings.dc.model = strdup("Shearwater import"); + state->cur_settings.dc.model = strdup("Shearwater import"); break; } } - cur_settings.dc.deviceid = atoi(data[9]); + state->cur_settings.dc.deviceid = atoi(data[9]); - dc_settings_end(); - settings_end(); + dc_settings_end(state); + settings_end(state); if (data[10]) { switch (atoi(data[10])) { case 2: - cur_dive->dc.model = strdup("Shearwater Petrel/Perdix"); + state->cur_dive->dc.model = strdup("Shearwater Petrel/Perdix"); break; case 4: - cur_dive->dc.model = strdup("Shearwater Predator"); + state->cur_dive->dc.model = strdup("Shearwater Predator"); break; default: - cur_dive->dc.model = strdup("Shearwater import"); + state->cur_dive->dc.model = strdup("Shearwater import"); break; } } if (data[11]) { snprintf(get_buffer, sizeof(get_buffer) - 1, get_mode_template, dive_id); - retval = sqlite3_exec(handle, get_buffer, &shearwater_mode, 0, &err); + retval = sqlite3_exec(handle, get_buffer, &shearwater_mode, state, &err); if (retval != SQLITE_OK) { fprintf(stderr, "%s", "Database query shearwater_mode failed.\n"); return 1; @@ -283,31 +284,31 @@ extern int shearwater_dive(void *param, int columns, char **data, char **column) } snprintf(get_buffer, sizeof(get_buffer) - 1, get_cylinder_template, dive_id); - retval = sqlite3_exec(handle, get_buffer, &shearwater_cylinders, 0, &err); + retval = sqlite3_exec(handle, get_buffer, &shearwater_cylinders, state, &err); if (retval != SQLITE_OK) { fprintf(stderr, "%s", "Database query shearwater_cylinders failed.\n"); return 1; } snprintf(get_buffer, sizeof(get_buffer) - 1, get_changes_template, dive_id); - retval = sqlite3_exec(handle, get_buffer, &shearwater_changes, 0, &err); + retval = sqlite3_exec(handle, get_buffer, &shearwater_changes, state, &err); if (retval != SQLITE_OK) { fprintf(stderr, "%s", "Database query shearwater_changes failed.\n"); return 1; } snprintf(get_buffer, sizeof(get_buffer) - 1, get_profile_template_ai, dive_id); - retval = sqlite3_exec(handle, get_buffer, &shearwater_ai_profile_sample, 0, &err); + retval = sqlite3_exec(handle, get_buffer, &shearwater_ai_profile_sample, state, &err); if (retval != SQLITE_OK) { snprintf(get_buffer, sizeof(get_buffer) - 1, get_profile_template, dive_id); - retval = sqlite3_exec(handle, get_buffer, &shearwater_profile_sample, 0, &err); + retval = sqlite3_exec(handle, get_buffer, &shearwater_profile_sample, state, &err); if (retval != SQLITE_OK) { fprintf(stderr, "%s", "Database query shearwater_profile_sample failed.\n"); return 1; } } - dive_end(); + dive_end(state); return SQLITE_OK; } @@ -320,11 +321,16 @@ int parse_shearwater_buffer(sqlite3 *handle, const char *url, const char *buffer int retval; char *err = NULL; - target_table = table; + struct parser_state state; + + init_parser_state(&state); + state.target_table = table; + state.sql_handle = handle; char get_dives[] = "select l.number,timestamp,location||' / '||site,buddy,notes,imperialUnits,maxDepth,maxTime,startSurfacePressure,computerSerial,computerModel,i.diveId FROM dive_info AS i JOIN dive_logs AS l ON i.diveId=l.diveId"; - retval = sqlite3_exec(handle, get_dives, &shearwater_dive, handle, &err); + retval = sqlite3_exec(handle, get_dives, &shearwater_dive, &state, &err); + free_parser_state(&state); if (retval != SQLITE_OK) { fprintf(stderr, "Database query failed '%s'.\n", url); |