mirror of
				https://github.com/subsurface/subsurface.git
				synced 2025-02-19 22:16:15 +00:00 
			
		
		
		
	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:
		
							parent
							
								
									343808271c
								
							
						
					
					
						commit
						138f27f65d
					
				
					 7 changed files with 1022 additions and 957 deletions
				
			
		|  | @ -13,57 +13,57 @@ | |||
| #include "membuffer.h" | ||||
| #include "gettext.h" | ||||
| 
 | ||||
| extern int cobalt_profile_sample(void *handle, int columns, char **data, char **column) | ||||
| static int cobalt_profile_sample(void *param, int columns, char **data, char **column) | ||||
| { | ||||
| 	UNUSED(handle); | ||||
| 	UNUSED(columns); | ||||
| 	UNUSED(column); | ||||
| 	struct parser_state *state = (struct parser_state *)param; | ||||
| 
 | ||||
| 	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 = atoi(data[1]); | ||||
| 		state->cur_sample->depth.mm = atoi(data[1]); | ||||
| 	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)); | ||||
| 	sample_end(); | ||||
| 		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)); | ||||
| 	sample_end(state); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| extern int cobalt_cylinders(void *handle, int columns, char **data, char **column) | ||||
| static int cobalt_cylinders(void *param, int columns, char **data, char **column) | ||||
| { | ||||
| 	UNUSED(handle); | ||||
| 	UNUSED(columns); | ||||
| 	UNUSED(column); | ||||
| 	struct parser_state *state = (struct parser_state *)param; | ||||
| 
 | ||||
| 	cylinder_start(); | ||||
| 	cylinder_start(state); | ||||
| 	if (data[0]) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].gasmix.o2.permille = atoi(data[0]) * 10; | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.o2.permille = atoi(data[0]) * 10; | ||||
| 	if (data[1]) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].gasmix.he.permille = atoi(data[1]) * 10; | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.he.permille = atoi(data[1]) * 10; | ||||
| 	if (data[2]) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].start.mbar = psi_to_mbar(atoi(data[2])); | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].start.mbar = psi_to_mbar(atoi(data[2])); | ||||
| 	if (data[3]) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].end.mbar = psi_to_mbar(atoi(data[3])); | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].end.mbar = psi_to_mbar(atoi(data[3])); | ||||
| 	if (data[4]) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].type.size.mliter = atoi(data[4]) * 100; | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].type.size.mliter = atoi(data[4]) * 100; | ||||
| 	if (data[5]) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].gas_used.mliter = atoi(data[5]) * 1000; | ||||
| 	cylinder_end(); | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].gas_used.mliter = atoi(data[5]) * 1000; | ||||
| 	cylinder_end(state); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| extern int cobalt_buddies(void *handle, int columns, char **data, char **column) | ||||
| static int cobalt_buddies(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]) | ||||
| 		utf8_string(data[0], &cur_dive->buddy); | ||||
| 		utf8_string(data[0], &state->cur_dive->buddy); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | @ -73,20 +73,20 @@ extern int cobalt_buddies(void *handle, int columns, char **data, char **column) | |||
|  * Subsurface star rating. | ||||
|  */ | ||||
| 
 | ||||
| extern int cobalt_visibility(void *handle, int columns, char **data, char **column) | ||||
| static int cobalt_visibility(void *param, int columns, char **data, char **column) | ||||
| { | ||||
| 	UNUSED(handle); | ||||
| 	UNUSED(param); | ||||
| 	UNUSED(columns); | ||||
| 	UNUSED(column); | ||||
| 	UNUSED(data); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| extern int cobalt_location(void *handle, int columns, char **data, char **column) | ||||
| static int cobalt_location(void *param, int columns, char **data, char **column) | ||||
| { | ||||
| 	UNUSED(handle); | ||||
| 	UNUSED(columns); | ||||
| 	UNUSED(column); | ||||
| 	struct parser_state *state = (struct parser_state *)param; | ||||
| 
 | ||||
| 	static char *location = NULL; | ||||
| 	if (data[0]) { | ||||
|  | @ -97,7 +97,7 @@ extern int cobalt_location(void *handle, int columns, char **data, char **column | |||
| 			sprintf(tmp, "%s / %s", location, data[0]); | ||||
| 			free(location); | ||||
| 			location = NULL; | ||||
| 			cur_dive->dive_site_uuid = find_or_create_dive_site_with_name(tmp, cur_dive->when); | ||||
| 			state->cur_dive->dive_site_uuid = find_or_create_dive_site_with_name(tmp, state->cur_dive->when); | ||||
| 			free(tmp); | ||||
| 		} else { | ||||
| 			location = strdup(data[0]); | ||||
|  | @ -107,13 +107,14 @@ extern int cobalt_location(void *handle, int columns, char **data, char **column | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| extern int cobalt_dive(void *param, int columns, char **data, char **column) | ||||
| static int cobalt_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 runtime*60,(DepthPressure*10000/SurfacePressure)-10000,p.Temperature from Dive AS d JOIN TrackPoints AS p ON d.Id=p.DiveId where d.Id=%d"; | ||||
| 	char get_cylinder_template[] = "select FO2,FHe,StartingPressure,EndingPressure,TankSize,TankPressure,TotalConsumption from GasMixes where DiveID=%d and StartingPressure>0 and EndingPressure > 0 group by FO2,FHe"; | ||||
|  | @ -123,13 +124,13 @@ extern int cobalt_dive(void *param, int columns, char **data, char **column) | |||
| 	char get_site_template[] = "select l.Data from Items AS i, List AS l ON i.Value1=l.Id where i.DiveId=%d and l.Type=1"; | ||||
| 	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])); | ||||
| 
 | ||||
| 	if (data[4]) | ||||
| 		utf8_string(data[4], &cur_dive->notes); | ||||
| 		utf8_string(data[4], &state->cur_dive->notes); | ||||
| 
 | ||||
| 	/* data[5] should have information on Units used, but I cannot
 | ||||
| 	 * parse it at all based on the sample log I have received. The | ||||
|  | @ -137,79 +138,79 @@ extern int cobalt_dive(void *param, int columns, char **data, char **column) | |||
| 	 * that. | ||||
| 	 */ | ||||
| 
 | ||||
| 	metric = 0; | ||||
| 	state->metric = 0; | ||||
| 
 | ||||
| 	/* Cobalt stores the pressures, not the depth */ | ||||
| 	if (data[6]) | ||||
| 		cur_dive->dc.maxdepth.mm = atoi(data[6]); | ||||
| 		state->cur_dive->dc.maxdepth.mm = atoi(data[6]); | ||||
| 
 | ||||
| 	if (data[7]) | ||||
| 		cur_dive->dc.duration.seconds = atoi(data[7]); | ||||
| 		state->cur_dive->dc.duration.seconds = atoi(data[7]); | ||||
| 
 | ||||
| 	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); | ||||
| 		cur_settings.dc.deviceid = atoi(data[9]); | ||||
| 		cur_settings.dc.model = strdup("Cobalt import"); | ||||
| 		utf8_string(data[9], &state->cur_settings.dc.serial_nr); | ||||
| 		state->cur_settings.dc.deviceid = atoi(data[9]); | ||||
| 		state->cur_settings.dc.model = strdup("Cobalt import"); | ||||
| 	} | ||||
| 
 | ||||
| 	dc_settings_end(); | ||||
| 	settings_end(); | ||||
| 	dc_settings_end(state); | ||||
| 	settings_end(state); | ||||
| 
 | ||||
| 	if (data[9]) { | ||||
| 		cur_dive->dc.deviceid = atoi(data[9]); | ||||
| 		cur_dive->dc.model = strdup("Cobalt import"); | ||||
| 		state->cur_dive->dc.deviceid = atoi(data[9]); | ||||
| 		state->cur_dive->dc.model = strdup("Cobalt import"); | ||||
| 	} | ||||
| 
 | ||||
| 	snprintf(get_buffer, sizeof(get_buffer) - 1, get_cylinder_template, cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_buffer, &cobalt_cylinders, 0, &err); | ||||
| 	snprintf(get_buffer, sizeof(get_buffer) - 1, get_cylinder_template, state->cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_buffer, &cobalt_cylinders, state, &err); | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "%s", "Database query cobalt_cylinders failed.\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	snprintf(get_buffer, sizeof(get_buffer) - 1, get_buddy_template, cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_buffer, &cobalt_buddies, 0, &err); | ||||
| 	snprintf(get_buffer, sizeof(get_buffer) - 1, get_buddy_template, state->cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_buffer, &cobalt_buddies, state, &err); | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "%s", "Database query cobalt_buddies failed.\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	snprintf(get_buffer, sizeof(get_buffer) - 1, get_visibility_template, cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_buffer, &cobalt_visibility, 0, &err); | ||||
| 	snprintf(get_buffer, sizeof(get_buffer) - 1, get_visibility_template, state->cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_buffer, &cobalt_visibility, state, &err); | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "%s", "Database query cobalt_visibility failed.\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	snprintf(get_buffer, sizeof(get_buffer) - 1, get_location_template, cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_buffer, &cobalt_location, 0, &err); | ||||
| 	snprintf(get_buffer, sizeof(get_buffer) - 1, get_location_template, state->cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_buffer, &cobalt_location, state, &err); | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "%s", "Database query cobalt_location failed.\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	snprintf(get_buffer, sizeof(get_buffer) - 1, get_site_template, cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_buffer, &cobalt_location, 0, &err); | ||||
| 	snprintf(get_buffer, sizeof(get_buffer) - 1, get_site_template, state->cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_buffer, &cobalt_location, state, &err); | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "%s", "Database query cobalt_location (site) failed.\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	snprintf(get_buffer, sizeof(get_buffer) - 1, get_profile_template, cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_buffer, &cobalt_profile_sample, 0, &err); | ||||
| 	snprintf(get_buffer, sizeof(get_buffer) - 1, get_profile_template, state->cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_buffer, &cobalt_profile_sample, state, &err); | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "%s", "Database query cobalt_profile_sample failed.\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	dive_end(); | ||||
| 	dive_end(state); | ||||
| 
 | ||||
| 	return SQLITE_OK; | ||||
| } | ||||
|  | @ -223,11 +224,16 @@ int parse_cobalt_buffer(sqlite3 *handle, const char *url, const char *buffer, in | |||
| 
 | ||||
| 	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 Id,strftime('%s',DiveStartTime),LocationId,'buddy','notes',Units,(MaxDepthPressure*10000/SurfacePressure)-10000,DiveMinutes,SurfacePressure,SerialNumber,'model' from Dive where IsViewDeleted = 0"; | ||||
| 
 | ||||
| 	retval = sqlite3_exec(handle, get_dives, &cobalt_dive, handle, &err); | ||||
| 	retval = sqlite3_exec(handle, get_dives, &cobalt_dive, &state, &err); | ||||
| 	free_parser_state(&state); | ||||
| 
 | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "Database query failed '%s'.\n", url); | ||||
|  | @ -236,4 +242,3 @@ int parse_cobalt_buffer(sqlite3 *handle, const char *url, const char *buffer, in | |||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -13,11 +13,11 @@ | |||
| #include "membuffer.h" | ||||
| #include "gettext.h" | ||||
| 
 | ||||
| extern int divinglog_cylinder(void *handle, int columns, char **data, char **column) | ||||
| static int divinglog_cylinder(void *param, int columns, char **data, char **column) | ||||
| { | ||||
| 	UNUSED(handle); | ||||
| 	UNUSED(columns); | ||||
| 	UNUSED(column); | ||||
| 	struct parser_state *state = (struct parser_state *)param; | ||||
| 
 | ||||
| 	short dbl = 1; | ||||
| 	//char get_cylinder_template[] = "select TankID,TankSize,PresS,PresE,PresW,O2,He,DblTank from Tank where LogID = %d";
 | ||||
|  | @ -27,13 +27,13 @@ extern int divinglog_cylinder(void *handle, int columns, char **data, char **col | |||
| 	 * better to ignore those. | ||||
| 	 */ | ||||
| 
 | ||||
| 	if (cur_cylinder_index >= MAX_CYLINDERS) | ||||
| 	if (state->cur_cylinder_index >= MAX_CYLINDERS) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (data[7] && atoi(data[7]) > 0) | ||||
| 		dbl = 2; | ||||
| 
 | ||||
| 	cylinder_start(); | ||||
| 	cylinder_start(state); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Assuming that we have to double the cylinder size, if double | ||||
|  | @ -41,29 +41,29 @@ extern int divinglog_cylinder(void *handle, int columns, char **data, char **col | |||
| 	 */ | ||||
| 
 | ||||
| 	if (data[1] && atoi(data[1]) > 0) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].type.size.mliter = atol(data[1]) * 1000 * dbl; | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].type.size.mliter = atol(data[1]) * 1000 * dbl; | ||||
| 
 | ||||
| 	if (data[2] && atoi(data[2]) > 0) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].start.mbar = atol(data[2]) * 1000; | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].start.mbar = atol(data[2]) * 1000; | ||||
| 	if (data[3] && atoi(data[3]) > 0) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].end.mbar = atol(data[3]) * 1000; | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].end.mbar = atol(data[3]) * 1000; | ||||
| 	if (data[4] && atoi(data[4]) > 0) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].type.workingpressure.mbar = atol(data[4]) * 1000; | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].type.workingpressure.mbar = atol(data[4]) * 1000; | ||||
| 	if (data[5] && atoi(data[5]) > 0) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].gasmix.o2.permille = atol(data[5]) * 10; | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.o2.permille = atol(data[5]) * 10; | ||||
| 	if (data[6] && atoi(data[6]) > 0) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].gasmix.he.permille = atol(data[6]) * 10; | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.he.permille = atol(data[6]) * 10; | ||||
| 
 | ||||
| 	cylinder_end(); | ||||
| 	cylinder_end(state); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| extern int divinglog_profile(void *handle, int columns, char **data, char **column) | ||||
| static int divinglog_profile(void *param, int columns, char **data, char **column) | ||||
| { | ||||
| 	UNUSED(handle); | ||||
| 	UNUSED(columns); | ||||
| 	UNUSED(column); | ||||
| 	struct parser_state *state = (struct parser_state *)param; | ||||
| 
 | ||||
| 	int sinterval = 0; | ||||
| 	unsigned long time; | ||||
|  | @ -121,11 +121,11 @@ extern int divinglog_profile(void *handle, int columns, char **data, char **colu | |||
| 
 | ||||
| 	time = 0; | ||||
| 	while (len1 >= 12) { | ||||
| 		sample_start(); | ||||
| 		sample_start(state); | ||||
| 
 | ||||
| 		cur_sample->time.seconds = time; | ||||
| 		cur_sample->in_deco = ptr1[5] - '0' ? true : false; | ||||
| 		cur_sample->depth.mm = atoi_n(ptr1, 5) * 10; | ||||
| 		state->cur_sample->time.seconds = time; | ||||
| 		state->cur_sample->in_deco = ptr1[5] - '0' ? true : false; | ||||
| 		state->cur_sample->depth.mm = atoi_n(ptr1, 5) * 10; | ||||
| 
 | ||||
| 		if (len2 >= 11) { | ||||
| 			int temp = atoi_n(ptr2, 3); | ||||
|  | @ -133,23 +133,23 @@ extern int divinglog_profile(void *handle, int columns, char **data, char **colu | |||
| 			int tank = atoi_n(ptr2+7, 1); | ||||
| 			int rbt = atoi_n(ptr2+8, 3) * 60; | ||||
| 
 | ||||
| 			cur_sample->temperature.mkelvin = C_to_mkelvin(temp / 10.0f); | ||||
| 			cur_sample->pressure[0].mbar = pressure * 100; | ||||
| 			cur_sample->rbt.seconds = rbt; | ||||
| 			state->cur_sample->temperature.mkelvin = C_to_mkelvin(temp / 10.0f); | ||||
| 			state->cur_sample->pressure[0].mbar = pressure * 100; | ||||
| 			state->cur_sample->rbt.seconds = rbt; | ||||
| 			if (oldcyl != tank) { | ||||
| 				struct gasmix mix = cur_dive->cylinder[tank].gasmix; | ||||
| 				struct gasmix mix = state->cur_dive->cylinder[tank].gasmix; | ||||
| 				int o2 = get_o2(mix); | ||||
| 				int he = get_he(mix); | ||||
| 
 | ||||
| 				event_start(); | ||||
| 				cur_event.time.seconds = time; | ||||
| 				strcpy(cur_event.name, "gaschange"); | ||||
| 				event_start(state); | ||||
| 				state->cur_event.time.seconds = time; | ||||
| 				strcpy(state->cur_event.name, "gaschange"); | ||||
| 
 | ||||
| 				o2 = (o2 + 5) / 10; | ||||
| 				he = (he + 5) / 10; | ||||
| 				cur_event.value = o2 + (he << 16); | ||||
| 				state->cur_event.value = o2 + (he << 16); | ||||
| 
 | ||||
| 				event_end(); | ||||
| 				event_end(state); | ||||
| 				oldcyl = tank; | ||||
| 			} | ||||
| 
 | ||||
|  | @ -157,7 +157,7 @@ extern int divinglog_profile(void *handle, int columns, char **data, char **colu | |||
| 		} | ||||
| 
 | ||||
| 		if (len3 >= 14) { | ||||
| 			cur_sample->heartbeat = atoi_n(ptr3+8, 3); | ||||
| 			state->cur_sample->heartbeat = atoi_n(ptr3+8, 3); | ||||
| 			ptr3 += 14; len3 -= 14; | ||||
| 		} | ||||
| 
 | ||||
|  | @ -167,15 +167,15 @@ extern int divinglog_profile(void *handle, int columns, char **data, char **colu | |||
| 			 * either 0 or TTS when in deco. | ||||
| 			 */ | ||||
| 			int val = atoi_n(ptr4, 3); | ||||
| 			if (cur_sample->in_deco) { | ||||
| 				cur_sample->ndl.seconds = 0; | ||||
| 			if (state->cur_sample->in_deco) { | ||||
| 				state->cur_sample->ndl.seconds = 0; | ||||
| 				if (val) | ||||
| 					cur_sample->tts.seconds = val * 60; | ||||
| 					state->cur_sample->tts.seconds = val * 60; | ||||
| 			} else { | ||||
| 				cur_sample->ndl.seconds = val * 60; | ||||
| 				state->cur_sample->ndl.seconds = val * 60; | ||||
| 			} | ||||
| 			cur_sample->stoptime.seconds = atoi_n(ptr4+3, 3) * 60; | ||||
| 			cur_sample->stopdepth.mm = atoi_n(ptr4+6, 3) * 1000; | ||||
| 			state->cur_sample->stoptime.seconds = atoi_n(ptr4+3, 3) * 60; | ||||
| 			state->cur_sample->stopdepth.mm = atoi_n(ptr4+6, 3) * 1000; | ||||
| 			ptr4 += 9; len4 -= 9; | ||||
| 		} | ||||
| 
 | ||||
|  | @ -203,15 +203,15 @@ extern int divinglog_profile(void *handle, int columns, char **data, char **colu | |||
| 			int setpoint = atoi_n(ptr5 + 17, 2); | ||||
| 
 | ||||
| 			if (ppo2_1 > 0) | ||||
| 				cur_sample->o2sensor[0].mbar = ppo2_1 * 100; | ||||
| 				state->cur_sample->o2sensor[0].mbar = ppo2_1 * 100; | ||||
| 			if (ppo2_2 > 0) | ||||
| 				cur_sample->o2sensor[1].mbar = ppo2_2 * 100; | ||||
| 				state->cur_sample->o2sensor[1].mbar = ppo2_2 * 100; | ||||
| 			if (ppo2_3 > 0) | ||||
| 				cur_sample->o2sensor[2].mbar = ppo2_3 * 100; | ||||
| 				state->cur_sample->o2sensor[2].mbar = ppo2_3 * 100; | ||||
| 			if (cns > 0) | ||||
| 				cur_sample->cns = lrintf(cns / 10.0f); | ||||
| 				state->cur_sample->cns = lrintf(cns / 10.0f); | ||||
| 			if (setpoint > 0) | ||||
| 				cur_sample->setpoint.mbar = setpoint * 100; | ||||
| 				state->cur_sample->setpoint.mbar = setpoint * 100; | ||||
| 			ptr5 += 19; len5 -= 19; | ||||
| 		} | ||||
| 
 | ||||
|  | @ -219,44 +219,44 @@ extern int divinglog_profile(void *handle, int columns, char **data, char **colu | |||
| 		 * Count the number of o2 sensors | ||||
| 		 */ | ||||
| 
 | ||||
| 		if (!cur_dive->dc.no_o2sensors && (cur_sample->o2sensor[0].mbar || cur_sample->o2sensor[1].mbar || cur_sample->o2sensor[2].mbar)) { | ||||
| 			cur_dive->dc.no_o2sensors = cur_sample->o2sensor[0].mbar ? 1 : 0 + | ||||
| 				 cur_sample->o2sensor[1].mbar ? 1 : 0 + | ||||
| 				 cur_sample->o2sensor[2].mbar ? 1 : 0; | ||||
| 		if (!state->cur_dive->dc.no_o2sensors && (state->cur_sample->o2sensor[0].mbar || state->cur_sample->o2sensor[1].mbar || state->cur_sample->o2sensor[2].mbar)) { | ||||
| 			state->cur_dive->dc.no_o2sensors = state->cur_sample->o2sensor[0].mbar ? 1 : 0 + | ||||
| 				 state->cur_sample->o2sensor[1].mbar ? 1 : 0 + | ||||
| 				 state->cur_sample->o2sensor[2].mbar ? 1 : 0; | ||||
| 		} | ||||
| 
 | ||||
| 		sample_end(); | ||||
| 		sample_end(state); | ||||
| 
 | ||||
| 		/* Remaining bottom time warning */ | ||||
| 		if (ptr1[6] - '0') { | ||||
| 			event_start(); | ||||
| 			cur_event.time.seconds = time; | ||||
| 			strcpy(cur_event.name, "rbt"); | ||||
| 			event_end(); | ||||
| 			event_start(state); | ||||
| 			state->cur_event.time.seconds = time; | ||||
| 			strcpy(state->cur_event.name, "rbt"); | ||||
| 			event_end(state); | ||||
| 		} | ||||
| 
 | ||||
| 		/* Ascent warning */ | ||||
| 		if (ptr1[7] - '0') { | ||||
| 			event_start(); | ||||
| 			cur_event.time.seconds = time; | ||||
| 			strcpy(cur_event.name, "ascent"); | ||||
| 			event_end(); | ||||
| 			event_start(state); | ||||
| 			state->cur_event.time.seconds = time; | ||||
| 			strcpy(state->cur_event.name, "ascent"); | ||||
| 			event_end(state); | ||||
| 		} | ||||
| 
 | ||||
| 		/* Deco stop ignored */ | ||||
| 		if (ptr1[8] - '0') { | ||||
| 			event_start(); | ||||
| 			cur_event.time.seconds = time; | ||||
| 			strcpy(cur_event.name, "violation"); | ||||
| 			event_end(); | ||||
| 			event_start(state); | ||||
| 			state->cur_event.time.seconds = time; | ||||
| 			strcpy(state->cur_event.name, "violation"); | ||||
| 			event_end(state); | ||||
| 		} | ||||
| 
 | ||||
| 		/* Workload warning */ | ||||
| 		if (ptr1[9] - '0') { | ||||
| 			event_start(); | ||||
| 			cur_event.time.seconds = time; | ||||
| 			strcpy(cur_event.name, "workload"); | ||||
| 			event_end(); | ||||
| 			event_start(state); | ||||
| 			state->cur_event.time.seconds = time; | ||||
| 			strcpy(state->cur_event.name, "workload"); | ||||
| 			event_end(state); | ||||
| 		} | ||||
| 
 | ||||
| 		ptr1 += 12; len1 -= 12; | ||||
|  | @ -266,56 +266,57 @@ extern int divinglog_profile(void *handle, int columns, char **data, char **colu | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| extern int divinglog_dive(void *param, int columns, char **data, char **column) | ||||
| static int divinglog_dive(void *param, int columns, char **data, char **column) | ||||
| { | ||||
| 	UNUSED(columns); | ||||
| 	UNUSED(column); | ||||
| 
 | ||||
| 	int retval = 0, diveid; | ||||
| 	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 ProfileInt,Profile,Profile2,Profile3,Profile4,Profile5 from Logbook where ID = %d"; | ||||
| 	char get_cylinder0_template[] = "select 0,TankSize,PresS,PresE,PresW,O2,He,DblTank from Logbook where ID = %d"; | ||||
| 	char get_cylinder_template[] = "select TankID,TankSize,PresS,PresE,PresW,O2,He,DblTank from Tank where LogID = %d order by TankID"; | ||||
| 	char get_buffer[1024]; | ||||
| 
 | ||||
| 	dive_start(); | ||||
| 	dive_start(state); | ||||
| 	diveid = atoi(data[13]); | ||||
| 	cur_dive->number = atoi(data[0]); | ||||
| 	state->cur_dive->number = atoi(data[0]); | ||||
| 
 | ||||
| 	cur_dive->when = (time_t)(atol(data[1])); | ||||
| 	state->cur_dive->when = (time_t)(atol(data[1])); | ||||
| 
 | ||||
| 	if (data[2]) | ||||
| 		cur_dive->dive_site_uuid = find_or_create_dive_site_with_name(data[2], cur_dive->when); | ||||
| 		state->cur_dive->dive_site_uuid = find_or_create_dive_site_with_name(data[2], state->cur_dive->when); | ||||
| 
 | ||||
| 	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); | ||||
| 
 | ||||
| 	if (data[5]) | ||||
| 		cur_dive->dc.maxdepth.mm = lrint(strtod_flags(data[5], NULL, 0) * 1000); | ||||
| 		state->cur_dive->dc.maxdepth.mm = lrint(strtod_flags(data[5], NULL, 0) * 1000); | ||||
| 
 | ||||
| 	if (data[6]) | ||||
| 		cur_dive->dc.duration.seconds = atoi(data[6]) * 60; | ||||
| 		state->cur_dive->dc.duration.seconds = atoi(data[6]) * 60; | ||||
| 
 | ||||
| 	if (data[7]) | ||||
| 		utf8_string(data[7], &cur_dive->divemaster); | ||||
| 		utf8_string(data[7], &state->cur_dive->divemaster); | ||||
| 
 | ||||
| 	if (data[8]) | ||||
| 		cur_dive->airtemp.mkelvin = C_to_mkelvin(atol(data[8])); | ||||
| 		state->cur_dive->airtemp.mkelvin = C_to_mkelvin(atol(data[8])); | ||||
| 
 | ||||
| 	if (data[9]) | ||||
| 		cur_dive->watertemp.mkelvin = C_to_mkelvin(atol(data[9])); | ||||
| 		state->cur_dive->watertemp.mkelvin = C_to_mkelvin(atol(data[9])); | ||||
| 
 | ||||
| 	if (data[10]) { | ||||
| 		cur_dive->weightsystem[0].weight.grams = atol(data[10]) * 1000; | ||||
| 		cur_dive->weightsystem[0].description = strdup(translate("gettextFromC", "unknown")); | ||||
| 		state->cur_dive->weightsystem[0].weight.grams = atol(data[10]) * 1000; | ||||
| 		state->cur_dive->weightsystem[0].description = strdup(translate("gettextFromC", "unknown")); | ||||
| 	} | ||||
| 
 | ||||
| 	if (data[11]) | ||||
| 		cur_dive->suit = strdup(data[11]); | ||||
| 		state->cur_dive->suit = strdup(data[11]); | ||||
| 
 | ||||
| 	/* Divinglog has following visibility options: good, medium, bad */ | ||||
| 	if (data[14]) { | ||||
|  | @ -323,37 +324,37 @@ extern int divinglog_dive(void *param, int columns, char **data, char **column) | |||
| 		case '0': | ||||
| 			break; | ||||
| 		case '1': | ||||
| 			cur_dive->visibility = 5; | ||||
| 			state->cur_dive->visibility = 5; | ||||
| 			break; | ||||
| 		case '2': | ||||
| 			cur_dive->visibility = 3; | ||||
| 			state->cur_dive->visibility = 3; | ||||
| 			break; | ||||
| 		case '3': | ||||
| 			cur_dive->visibility = 1; | ||||
| 			state->cur_dive->visibility = 1; | ||||
| 			break; | ||||
| 		default: | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	settings_start(); | ||||
| 	dc_settings_start(); | ||||
| 	settings_start(state); | ||||
| 	dc_settings_start(state); | ||||
| 
 | ||||
| 	if (data[12]) { | ||||
| 		cur_dive->dc.model = strdup(data[12]); | ||||
| 		state->cur_dive->dc.model = strdup(data[12]); | ||||
| 	} else { | ||||
| 		cur_settings.dc.model = strdup("Divinglog import"); | ||||
| 		state->cur_settings.dc.model = strdup("Divinglog import"); | ||||
| 	} | ||||
| 
 | ||||
| 	snprintf(get_buffer, sizeof(get_buffer) - 1, get_cylinder0_template, diveid); | ||||
| 	retval = sqlite3_exec(handle, get_buffer, &divinglog_cylinder, 0, &err); | ||||
| 	retval = sqlite3_exec(handle, get_buffer, &divinglog_cylinder, state, &err); | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "%s", "Database query divinglog_cylinder0 failed.\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	snprintf(get_buffer, sizeof(get_buffer) - 1, get_cylinder_template, diveid); | ||||
| 	retval = sqlite3_exec(handle, get_buffer, &divinglog_cylinder, 0, &err); | ||||
| 	retval = sqlite3_exec(handle, get_buffer, &divinglog_cylinder, state, &err); | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "%s", "Database query divinglog_cylinder failed.\n"); | ||||
| 		return 1; | ||||
|  | @ -365,31 +366,31 @@ extern int divinglog_dive(void *param, int columns, char **data, char **column) | |||
| 		case '0': | ||||
| 			break; | ||||
| 		case '1': | ||||
| 			cur_dive->dc.divemode = PSCR; | ||||
| 			state->cur_dive->dc.divemode = PSCR; | ||||
| 			break; | ||||
| 		case '2': | ||||
| 			cur_dive->dc.divemode = CCR; | ||||
| 			state->cur_dive->dc.divemode = CCR; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	dc_settings_end(); | ||||
| 	settings_end(); | ||||
| 	dc_settings_end(state); | ||||
| 	settings_end(state); | ||||
| 
 | ||||
| 	if (data[12]) { | ||||
| 		cur_dive->dc.model = strdup(data[12]); | ||||
| 		state->cur_dive->dc.model = strdup(data[12]); | ||||
| 	} else { | ||||
| 		cur_dive->dc.model = strdup("Divinglog import"); | ||||
| 		state->cur_dive->dc.model = strdup("Divinglog import"); | ||||
| 	} | ||||
| 
 | ||||
| 	snprintf(get_buffer, sizeof(get_buffer) - 1, get_profile_template, diveid); | ||||
| 	retval = sqlite3_exec(handle, get_buffer, &divinglog_profile, 0, &err); | ||||
| 	retval = sqlite3_exec(handle, get_buffer, &divinglog_profile, state, &err); | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "%s", "Database query divinglog_profile failed.\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	dive_end(); | ||||
| 	dive_end(state); | ||||
| 
 | ||||
| 	return SQLITE_OK; | ||||
| } | ||||
|  | @ -403,11 +404,16 @@ int parse_divinglog_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 Number,strftime('%s',Divedate || ' ' || ifnull(Entrytime,'00:00')),Country || ' - ' || City || ' - ' || Place,Buddy,Comments,Depth,Divetime,Divemaster,Airtemp,Watertemp,Weight,Divesuit,Computer,ID,Visibility,SupplyType from Logbook where UUID not in (select UUID from DeletedRecords)"; | ||||
| 
 | ||||
| 	retval = sqlite3_exec(handle, get_dives, &divinglog_dive, handle, &err); | ||||
| 	retval = sqlite3_exec(handle, get_dives, &divinglog_dive, &state, &err); | ||||
| 	free_parser_state(&state); | ||||
| 
 | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "Database query failed '%s'.\n", url); | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -13,122 +13,122 @@ | |||
| #include "membuffer.h" | ||||
| #include "gettext.h" | ||||
| 
 | ||||
| extern int dm4_events(void *handle, int columns, char **data, char **column) | ||||
| static int dm4_events(void *param, int columns, char **data, char **column) | ||||
| { | ||||
| 	UNUSED(handle); | ||||
| 	UNUSED(columns); | ||||
| 	UNUSED(column); | ||||
| 	struct parser_state *state = (struct parser_state *)param; | ||||
| 
 | ||||
| 	event_start(); | ||||
| 	event_start(state); | ||||
| 	if (data[1]) | ||||
| 		cur_event.time.seconds = atoi(data[1]); | ||||
| 		state->cur_event.time.seconds = atoi(data[1]); | ||||
| 
 | ||||
| 	if (data[2]) { | ||||
| 		switch (atoi(data[2])) { | ||||
| 		case 1: | ||||
| 			/* 1 Mandatory Safety Stop */ | ||||
| 			strcpy(cur_event.name, "safety stop (mandatory)"); | ||||
| 			strcpy(state->cur_event.name, "safety stop (mandatory)"); | ||||
| 			break; | ||||
| 		case 3: | ||||
| 			/* 3 Deco */ | ||||
| 			/* What is Subsurface's term for going to
 | ||||
| 				 * deco? */ | ||||
| 			strcpy(cur_event.name, "deco"); | ||||
| 			strcpy(state->cur_event.name, "deco"); | ||||
| 			break; | ||||
| 		case 4: | ||||
| 			/* 4 Ascent warning */ | ||||
| 			strcpy(cur_event.name, "ascent"); | ||||
| 			strcpy(state->cur_event.name, "ascent"); | ||||
| 			break; | ||||
| 		case 5: | ||||
| 			/* 5 Ceiling broken */ | ||||
| 			strcpy(cur_event.name, "violation"); | ||||
| 			strcpy(state->cur_event.name, "violation"); | ||||
| 			break; | ||||
| 		case 6: | ||||
| 			/* 6 Mandatory safety stop ceiling error */ | ||||
| 			strcpy(cur_event.name, "violation"); | ||||
| 			strcpy(state->cur_event.name, "violation"); | ||||
| 			break; | ||||
| 		case 7: | ||||
| 			/* 7 Below deco floor */ | ||||
| 			strcpy(cur_event.name, "below floor"); | ||||
| 			strcpy(state->cur_event.name, "below floor"); | ||||
| 			break; | ||||
| 		case 8: | ||||
| 			/* 8 Dive time alarm */ | ||||
| 			strcpy(cur_event.name, "divetime"); | ||||
| 			strcpy(state->cur_event.name, "divetime"); | ||||
| 			break; | ||||
| 		case 9: | ||||
| 			/* 9 Depth alarm */ | ||||
| 			strcpy(cur_event.name, "maxdepth"); | ||||
| 			strcpy(state->cur_event.name, "maxdepth"); | ||||
| 			break; | ||||
| 		case 10: | ||||
| 		/* 10 OLF 80% */ | ||||
| 		case 11: | ||||
| 			/* 11 OLF 100% */ | ||||
| 			strcpy(cur_event.name, "OLF"); | ||||
| 			strcpy(state->cur_event.name, "OLF"); | ||||
| 			break; | ||||
| 		case 12: | ||||
| 			/* 12 High pO₂ */ | ||||
| 			strcpy(cur_event.name, "PO2"); | ||||
| 			strcpy(state->cur_event.name, "PO2"); | ||||
| 			break; | ||||
| 		case 13: | ||||
| 			/* 13 Air time */ | ||||
| 			strcpy(cur_event.name, "airtime"); | ||||
| 			strcpy(state->cur_event.name, "airtime"); | ||||
| 			break; | ||||
| 		case 17: | ||||
| 			/* 17 Ascent warning */ | ||||
| 			strcpy(cur_event.name, "ascent"); | ||||
| 			strcpy(state->cur_event.name, "ascent"); | ||||
| 			break; | ||||
| 		case 18: | ||||
| 			/* 18 Ceiling error */ | ||||
| 			strcpy(cur_event.name, "ceiling"); | ||||
| 			strcpy(state->cur_event.name, "ceiling"); | ||||
| 			break; | ||||
| 		case 19: | ||||
| 			/* 19 Surfaced */ | ||||
| 			strcpy(cur_event.name, "surface"); | ||||
| 			strcpy(state->cur_event.name, "surface"); | ||||
| 			break; | ||||
| 		case 20: | ||||
| 			/* 20 Deco */ | ||||
| 			strcpy(cur_event.name, "deco"); | ||||
| 			strcpy(state->cur_event.name, "deco"); | ||||
| 			break; | ||||
| 		case 22: | ||||
| 		case 32: | ||||
| 			/* 22 Mandatory safety stop violation */ | ||||
| 			/* 32 Deep stop violation */ | ||||
| 			strcpy(cur_event.name, "violation"); | ||||
| 			strcpy(state->cur_event.name, "violation"); | ||||
| 			break; | ||||
| 		case 30: | ||||
| 			/* Tissue level warning */ | ||||
| 			strcpy(cur_event.name, "tissue warning"); | ||||
| 			strcpy(state->cur_event.name, "tissue warning"); | ||||
| 			break; | ||||
| 		case 37: | ||||
| 			/* Tank pressure alarm */ | ||||
| 			strcpy(cur_event.name, "tank pressure"); | ||||
| 			strcpy(state->cur_event.name, "tank pressure"); | ||||
| 			break; | ||||
| 		case 257: | ||||
| 			/* 257 Dive active */ | ||||
| 			/* This seems to be given after surface when
 | ||||
| 			 * descending again. */ | ||||
| 			strcpy(cur_event.name, "surface"); | ||||
| 			strcpy(state->cur_event.name, "surface"); | ||||
| 			break; | ||||
| 		case 258: | ||||
| 			/* 258 Bookmark */ | ||||
| 			if (data[3]) { | ||||
| 				strcpy(cur_event.name, "heading"); | ||||
| 				cur_event.value = atoi(data[3]); | ||||
| 				strcpy(state->cur_event.name, "heading"); | ||||
| 				state->cur_event.value = atoi(data[3]); | ||||
| 			} else { | ||||
| 				strcpy(cur_event.name, "bookmark"); | ||||
| 				strcpy(state->cur_event.name, "bookmark"); | ||||
| 			} | ||||
| 			break; | ||||
| 		case 259: | ||||
| 			/* Deep stop */ | ||||
| 			strcpy(cur_event.name, "Deep stop"); | ||||
| 			strcpy(state->cur_event.name, "Deep stop"); | ||||
| 			break; | ||||
| 		case 260: | ||||
| 			/* Deep stop */ | ||||
| 			strcpy(cur_event.name, "Deep stop cleared"); | ||||
| 			strcpy(state->cur_event.name, "Deep stop cleared"); | ||||
| 			break; | ||||
| 		case 266: | ||||
| 			/* Mandatory safety stop activated */ | ||||
| 			strcpy(cur_event.name, "safety stop (mandatory)"); | ||||
| 			strcpy(state->cur_event.name, "safety stop (mandatory)"); | ||||
| 			break; | ||||
| 		case 267: | ||||
| 			/* Mandatory safety stop deactivated */ | ||||
|  | @ -136,35 +136,36 @@ extern int dm4_events(void *handle, int columns, char **data, char **column) | |||
| 			 * profile so skipping as well for now */ | ||||
| 			break; | ||||
| 		default: | ||||
| 			strcpy(cur_event.name, "unknown"); | ||||
| 			cur_event.value = atoi(data[2]); | ||||
| 			strcpy(state->cur_event.name, "unknown"); | ||||
| 			state->cur_event.value = atoi(data[2]); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	event_end(); | ||||
| 	event_end(state); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| extern int dm4_tags(void *handle, int columns, char **data, char **column) | ||||
| static int dm4_tags(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]) | ||||
| 		taglist_add_tag(&cur_dive->tag_list, data[0]); | ||||
| 		taglist_add_tag(&state->cur_dive->tag_list, data[0]); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| extern int dm4_dive(void *param, int columns, char **data, char **column) | ||||
| static int dm4_dive(void *param, int columns, char **data, char **column) | ||||
| { | ||||
| 	UNUSED(columns); | ||||
| 	UNUSED(column); | ||||
| 	int i; | ||||
| 	int interval, retval = 0; | ||||
| 	sqlite3 *handle = (sqlite3 *)param; | ||||
| 	struct parser_state *state = (struct parser_state *)param; | ||||
| 	sqlite3 *handle = state->sql_handle; | ||||
| 	float *profileBlob; | ||||
| 	unsigned char *tempBlob; | ||||
| 	int *pressureBlob; | ||||
|  | @ -173,12 +174,12 @@ extern int dm4_dive(void *param, int columns, char **data, char **column) | |||
| 	char get_tags_template[] = "select Text from DiveTag where DiveId = %d"; | ||||
| 	char get_events[64]; | ||||
| 
 | ||||
| 	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])); | ||||
| 	if (data[2]) | ||||
| 		utf8_string(data[2], &cur_dive->notes); | ||||
| 		utf8_string(data[2], &state->cur_dive->notes); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * DM4 stores Duration and DiveTime. It looks like DiveTime is | ||||
|  | @ -188,90 +189,90 @@ extern int dm4_dive(void *param, int columns, char **data, char **column) | |||
| 	 * DiveTime = data[15] | ||||
| 	 */ | ||||
| 	if (data[3]) | ||||
| 		cur_dive->duration.seconds = atoi(data[3]); | ||||
| 		state->cur_dive->duration.seconds = atoi(data[3]); | ||||
| 	if (data[15]) | ||||
| 		cur_dive->dc.duration.seconds = atoi(data[15]); | ||||
| 		state->cur_dive->dc.duration.seconds = atoi(data[15]); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * TODO: the deviceid hash should be calculated here. | ||||
| 	 */ | ||||
| 	settings_start(); | ||||
| 	dc_settings_start(); | ||||
| 	settings_start(state); | ||||
| 	dc_settings_start(state); | ||||
| 	if (data[4]) | ||||
| 		utf8_string(data[4], &cur_settings.dc.serial_nr); | ||||
| 		utf8_string(data[4], &state->cur_settings.dc.serial_nr); | ||||
| 	if (data[5]) | ||||
| 		utf8_string(data[5], &cur_settings.dc.model); | ||||
| 		utf8_string(data[5], &state->cur_settings.dc.model); | ||||
| 
 | ||||
| 	cur_settings.dc.deviceid = 0xffffffff; | ||||
| 	dc_settings_end(); | ||||
| 	settings_end(); | ||||
| 	state->cur_settings.dc.deviceid = 0xffffffff; | ||||
| 	dc_settings_end(state); | ||||
| 	settings_end(state); | ||||
| 
 | ||||
| 	if (data[6]) | ||||
| 		cur_dive->dc.maxdepth.mm = lrint(strtod_flags(data[6], NULL, 0) * 1000); | ||||
| 		state->cur_dive->dc.maxdepth.mm = lrint(strtod_flags(data[6], NULL, 0) * 1000); | ||||
| 	if (data[8]) | ||||
| 		cur_dive->dc.airtemp.mkelvin = C_to_mkelvin(atoi(data[8])); | ||||
| 		state->cur_dive->dc.airtemp.mkelvin = C_to_mkelvin(atoi(data[8])); | ||||
| 	if (data[9]) | ||||
| 		cur_dive->dc.watertemp.mkelvin = C_to_mkelvin(atoi(data[9])); | ||||
| 		state->cur_dive->dc.watertemp.mkelvin = C_to_mkelvin(atoi(data[9])); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * TODO: handle multiple cylinders | ||||
| 	 */ | ||||
| 	cylinder_start(); | ||||
| 	cylinder_start(state); | ||||
| 	if (data[22] && atoi(data[22]) > 0) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].start.mbar = atoi(data[22]); | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].start.mbar = atoi(data[22]); | ||||
| 	else if (data[10] && atoi(data[10]) > 0) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].start.mbar = atoi(data[10]); | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].start.mbar = atoi(data[10]); | ||||
| 	if (data[23] && atoi(data[23]) > 0) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].end.mbar = (atoi(data[23])); | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].end.mbar = (atoi(data[23])); | ||||
| 	if (data[11] && atoi(data[11]) > 0) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].end.mbar = (atoi(data[11])); | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].end.mbar = (atoi(data[11])); | ||||
| 	if (data[12]) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].type.size.mliter = lrint((strtod_flags(data[12], NULL, 0)) * 1000); | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].type.size.mliter = lrint((strtod_flags(data[12], NULL, 0)) * 1000); | ||||
| 	if (data[13]) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].type.workingpressure.mbar = (atoi(data[13])); | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].type.workingpressure.mbar = (atoi(data[13])); | ||||
| 	if (data[20]) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].gasmix.o2.permille = atoi(data[20]) * 10; | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.o2.permille = atoi(data[20]) * 10; | ||||
| 	if (data[21]) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].gasmix.he.permille = atoi(data[21]) * 10; | ||||
| 	cylinder_end(); | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.he.permille = atoi(data[21]) * 10; | ||||
| 	cylinder_end(state); | ||||
| 
 | ||||
| 	if (data[14]) | ||||
| 		cur_dive->dc.surface_pressure.mbar = (atoi(data[14]) * 1000); | ||||
| 		state->cur_dive->dc.surface_pressure.mbar = (atoi(data[14]) * 1000); | ||||
| 
 | ||||
| 	interval = data[16] ? atoi(data[16]) : 0; | ||||
| 	profileBlob = (float *)data[17]; | ||||
| 	tempBlob = (unsigned char *)data[18]; | ||||
| 	pressureBlob = (int *)data[19]; | ||||
| 	for (i = 0; interval && i * interval < cur_dive->duration.seconds; i++) { | ||||
| 		sample_start(); | ||||
| 		cur_sample->time.seconds = i * interval; | ||||
| 	for (i = 0; interval && i * interval < state->cur_dive->duration.seconds; i++) { | ||||
| 		sample_start(state); | ||||
| 		state->cur_sample->time.seconds = i * interval; | ||||
| 		if (profileBlob) | ||||
| 			cur_sample->depth.mm = lrintf(profileBlob[i] * 1000.0f); | ||||
| 			state->cur_sample->depth.mm = lrintf(profileBlob[i] * 1000.0f); | ||||
| 		else | ||||
| 			cur_sample->depth.mm = cur_dive->dc.maxdepth.mm; | ||||
| 			state->cur_sample->depth.mm = state->cur_dive->dc.maxdepth.mm; | ||||
| 
 | ||||
| 		if (data[18] && data[18][0]) | ||||
| 			cur_sample->temperature.mkelvin = C_to_mkelvin(tempBlob[i]); | ||||
| 			state->cur_sample->temperature.mkelvin = C_to_mkelvin(tempBlob[i]); | ||||
| 		if (data[19] && data[19][0]) | ||||
| 			cur_sample->pressure[0].mbar = pressureBlob[i]; | ||||
| 		sample_end(); | ||||
| 			state->cur_sample->pressure[0].mbar = pressureBlob[i]; | ||||
| 		sample_end(state); | ||||
| 	} | ||||
| 
 | ||||
| 	snprintf(get_events, sizeof(get_events) - 1, get_events_template, cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_events, &dm4_events, 0, &err); | ||||
| 	snprintf(get_events, sizeof(get_events) - 1, get_events_template, state->cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_events, &dm4_events, state, &err); | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "%s", "Database query dm4_events failed.\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	snprintf(get_events, sizeof(get_events) - 1, get_tags_template, cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_events, &dm4_tags, 0, &err); | ||||
| 	snprintf(get_events, sizeof(get_events) - 1, get_tags_template, state->cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_events, &dm4_tags, state, &err); | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "%s", "Database query dm4_tags failed.\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	dive_end(); | ||||
| 	dive_end(state); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	for (i=0; i<columns;++i) { | ||||
|  | @ -295,13 +296,18 @@ int parse_dm4_buffer(sqlite3 *handle, const char *url, const char *buffer, int s | |||
| 
 | ||||
| 	int retval; | ||||
| 	char *err = NULL; | ||||
| 	target_table = table; | ||||
| 	struct parser_state state; | ||||
| 
 | ||||
| 	init_parser_state(&state); | ||||
| 	state.target_table = table; | ||||
| 	state.sql_handle = handle; | ||||
| 
 | ||||
| 	/* StartTime is converted from Suunto's nano seconds to standard
 | ||||
| 	 * time. We also need epoch, not seconds since year 1. */ | ||||
| 	char get_dives[] = "select D.DiveId,StartTime/10000000-62135596800,Note,Duration,SourceSerialNumber,Source,MaxDepth,SampleInterval,StartTemperature,BottomTemperature,D.StartPressure,D.EndPressure,Size,CylinderWorkPressure,SurfacePressure,DiveTime,SampleInterval,ProfileBlob,TemperatureBlob,PressureBlob,Oxygen,Helium,MIX.StartPressure,MIX.EndPressure FROM Dive AS D JOIN DiveMixture AS MIX ON D.DiveId=MIX.DiveId"; | ||||
| 
 | ||||
| 	retval = sqlite3_exec(handle, get_dives, &dm4_dive, handle, &err); | ||||
| 	retval = sqlite3_exec(handle, get_dives, &dm4_dive, &state, &err); | ||||
| 	free_parser_state(&state); | ||||
| 
 | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "Database query failed '%s'.\n", url); | ||||
|  | @ -311,64 +317,65 @@ int parse_dm4_buffer(sqlite3 *handle, const char *url, const char *buffer, int s | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| extern int dm5_cylinders(void *handle, int columns, char **data, char **column) | ||||
| static int dm5_cylinders(void *param, int columns, char **data, char **column) | ||||
| { | ||||
| 	UNUSED(handle); | ||||
| 	UNUSED(columns); | ||||
| 	UNUSED(column); | ||||
| 	struct parser_state *state = (struct parser_state *)param; | ||||
| 
 | ||||
| 	cylinder_start(); | ||||
| 	cylinder_start(state); | ||||
| 	if (data[7] && atoi(data[7]) > 0 && atoi(data[7]) < 350000) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].start.mbar = atoi(data[7]); | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].start.mbar = atoi(data[7]); | ||||
| 	if (data[8] && atoi(data[8]) > 0 && atoi(data[8]) < 350000) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].end.mbar = (atoi(data[8])); | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].end.mbar = (atoi(data[8])); | ||||
| 	if (data[6]) { | ||||
| 		/* DM5 shows tank size of 12 liters when the actual
 | ||||
| 		 * value is 0 (and using metric units). So we just use | ||||
| 		 * the same 12 liters when size is not available */ | ||||
| 		if (strtod_flags(data[6], NULL, 0) == 0.0 && cur_dive->cylinder[cur_cylinder_index].start.mbar) | ||||
| 			cur_dive->cylinder[cur_cylinder_index].type.size.mliter = 12000; | ||||
| 		if (strtod_flags(data[6], NULL, 0) == 0.0 && state->cur_dive->cylinder[state->cur_cylinder_index].start.mbar) | ||||
| 			state->cur_dive->cylinder[state->cur_cylinder_index].type.size.mliter = 12000; | ||||
| 		else | ||||
| 			cur_dive->cylinder[cur_cylinder_index].type.size.mliter = lrint((strtod_flags(data[6], NULL, 0)) * 1000); | ||||
| 			state->cur_dive->cylinder[state->cur_cylinder_index].type.size.mliter = lrint((strtod_flags(data[6], NULL, 0)) * 1000); | ||||
| 	} | ||||
| 	if (data[2]) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].gasmix.o2.permille = atoi(data[2]) * 10; | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.o2.permille = atoi(data[2]) * 10; | ||||
| 	if (data[3]) | ||||
| 		cur_dive->cylinder[cur_cylinder_index].gasmix.he.permille = atoi(data[3]) * 10; | ||||
| 	cylinder_end(); | ||||
| 		state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.he.permille = atoi(data[3]) * 10; | ||||
| 	cylinder_end(state); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| extern int dm5_gaschange(void *handle, int columns, char **data, char **column) | ||||
| static int dm5_gaschange(void *param, int columns, char **data, char **column) | ||||
| { | ||||
| 	UNUSED(handle); | ||||
| 	UNUSED(columns); | ||||
| 	UNUSED(column); | ||||
| 	struct parser_state *state = (struct parser_state *)param; | ||||
| 
 | ||||
| 	event_start(); | ||||
| 	event_start(state); | ||||
| 	if (data[0]) | ||||
| 		cur_event.time.seconds = atoi(data[0]); | ||||
| 		state->cur_event.time.seconds = atoi(data[0]); | ||||
| 	if (data[1]) { | ||||
| 		strcpy(cur_event.name, "gaschange"); | ||||
| 		cur_event.value = lrint(strtod_flags(data[1], NULL, 0)); | ||||
| 		strcpy(state->cur_event.name, "gaschange"); | ||||
| 		state->cur_event.value = lrint(strtod_flags(data[1], NULL, 0)); | ||||
| 	} | ||||
| 
 | ||||
| 	/* He part of the mix */ | ||||
| 	if (data[2]) | ||||
| 		cur_event.value += lrint(strtod_flags(data[2], NULL, 0)) << 16; | ||||
| 	event_end(); | ||||
| 		state->cur_event.value += lrint(strtod_flags(data[2], NULL, 0)) << 16; | ||||
| 	event_end(state); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| extern int dm5_dive(void *param, int columns, char **data, char **column) | ||||
| static int dm5_dive(void *param, int columns, char **data, char **column) | ||||
| { | ||||
| 	UNUSED(columns); | ||||
| 	UNUSED(column); | ||||
| 	int i; | ||||
| 	int tempformat = 0; | ||||
| 	int interval, retval = 0, block_size; | ||||
| 	sqlite3 *handle = (sqlite3 *)param; | ||||
| 	struct parser_state *state = (struct parser_state *)param; | ||||
| 	sqlite3 *handle = state->sql_handle; | ||||
| 	unsigned const char *sampleBlob; | ||||
| 	char *err = NULL; | ||||
| 	char get_events_template[] = "select * from Mark where DiveId = %d"; | ||||
|  | @ -377,55 +384,55 @@ extern int dm5_dive(void *param, int columns, char **data, char **column) | |||
| 	char get_gaschange_template[] = "select GasChangeTime,Oxygen,Helium from DiveGasChange join DiveMixture on DiveGasChange.DiveMixtureId=DiveMixture.DiveMixtureId where DiveId = %d"; | ||||
| 	char get_events[512]; | ||||
| 
 | ||||
| 	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])); | ||||
| 	if (data[2]) | ||||
| 		utf8_string(data[2], &cur_dive->notes); | ||||
| 		utf8_string(data[2], &state->cur_dive->notes); | ||||
| 
 | ||||
| 	if (data[3]) | ||||
| 		cur_dive->duration.seconds = atoi(data[3]); | ||||
| 		state->cur_dive->duration.seconds = atoi(data[3]); | ||||
| 	if (data[15]) | ||||
| 		cur_dive->dc.duration.seconds = atoi(data[15]); | ||||
| 		state->cur_dive->dc.duration.seconds = atoi(data[15]); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * TODO: the deviceid hash should be calculated here. | ||||
| 	 */ | ||||
| 	settings_start(); | ||||
| 	dc_settings_start(); | ||||
| 	settings_start(state); | ||||
| 	dc_settings_start(state); | ||||
| 	if (data[4]) { | ||||
| 		utf8_string(data[4], &cur_settings.dc.serial_nr); | ||||
| 		cur_settings.dc.deviceid = atoi(data[4]); | ||||
| 		utf8_string(data[4], &state->cur_settings.dc.serial_nr); | ||||
| 		state->cur_settings.dc.deviceid = atoi(data[4]); | ||||
| 	} | ||||
| 	if (data[5]) | ||||
| 		utf8_string(data[5], &cur_settings.dc.model); | ||||
| 		utf8_string(data[5], &state->cur_settings.dc.model); | ||||
| 
 | ||||
| 	dc_settings_end(); | ||||
| 	settings_end(); | ||||
| 	dc_settings_end(state); | ||||
| 	settings_end(state); | ||||
| 
 | ||||
| 	if (data[6]) | ||||
| 		cur_dive->dc.maxdepth.mm = lrint(strtod_flags(data[6], NULL, 0) * 1000); | ||||
| 		state->cur_dive->dc.maxdepth.mm = lrint(strtod_flags(data[6], NULL, 0) * 1000); | ||||
| 	if (data[8]) | ||||
| 		cur_dive->dc.airtemp.mkelvin = C_to_mkelvin(atoi(data[8])); | ||||
| 		state->cur_dive->dc.airtemp.mkelvin = C_to_mkelvin(atoi(data[8])); | ||||
| 	if (data[9]) | ||||
| 		cur_dive->dc.watertemp.mkelvin = C_to_mkelvin(atoi(data[9])); | ||||
| 		state->cur_dive->dc.watertemp.mkelvin = C_to_mkelvin(atoi(data[9])); | ||||
| 
 | ||||
| 	if (data[4]) { | ||||
| 		cur_dive->dc.deviceid = atoi(data[4]); | ||||
| 		state->cur_dive->dc.deviceid = atoi(data[4]); | ||||
| 	} | ||||
| 	if (data[5]) | ||||
| 		utf8_string(data[5], &cur_dive->dc.model); | ||||
| 		utf8_string(data[5], &state->cur_dive->dc.model); | ||||
| 
 | ||||
| 	snprintf(get_events, sizeof(get_events) - 1, get_cylinders_template, cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_events, &dm5_cylinders, 0, &err); | ||||
| 	snprintf(get_events, sizeof(get_events) - 1, get_cylinders_template, state->cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_events, &dm5_cylinders, state, &err); | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "%s", "Database query dm5_cylinders failed.\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	if (data[14]) | ||||
| 		cur_dive->dc.surface_pressure.mbar = (atoi(data[14]) / 100); | ||||
| 		state->cur_dive->dc.surface_pressure.mbar = (atoi(data[14]) / 100); | ||||
| 
 | ||||
| 	interval = data[16] ? atoi(data[16]) : 0; | ||||
| 
 | ||||
|  | @ -469,20 +476,20 @@ extern int dm5_dive(void *param, int columns, char **data, char **column) | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; interval && sampleBlob && i * interval < cur_dive->duration.seconds; i++) { | ||||
| 	for (i = 0; interval && sampleBlob && i * interval < state->cur_dive->duration.seconds; i++) { | ||||
| 		float *depth = (float *)&sampleBlob[i * block_size + 3]; | ||||
| 		int32_t pressure = (sampleBlob[i * block_size + 9] << 16) + (sampleBlob[i * block_size + 8] << 8) + sampleBlob[i * block_size + 7]; | ||||
| 
 | ||||
| 		sample_start(); | ||||
| 		cur_sample->time.seconds = i * interval; | ||||
| 		cur_sample->depth.mm = lrintf(depth[0] * 1000.0f); | ||||
| 		sample_start(state); | ||||
| 		state->cur_sample->time.seconds = i * interval; | ||||
| 		state->cur_sample->depth.mm = lrintf(depth[0] * 1000.0f); | ||||
| 
 | ||||
| 		if (tempformat == 1) { | ||||
| 			float *temp = (float *)&(sampleBlob[i * block_size + 11]); | ||||
| 			cur_sample->temperature.mkelvin = C_to_mkelvin(*temp); | ||||
| 			state->cur_sample->temperature.mkelvin = C_to_mkelvin(*temp); | ||||
| 		} else { | ||||
| 			if ((sampleBlob[i * block_size + 11]) != 0x7F) { | ||||
| 				cur_sample->temperature.mkelvin = C_to_mkelvin(sampleBlob[i * block_size + 11]); | ||||
| 				state->cur_sample->temperature.mkelvin = C_to_mkelvin(sampleBlob[i * block_size + 11]); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
|  | @ -490,8 +497,8 @@ extern int dm5_dive(void *param, int columns, char **data, char **column) | |||
| 		 * Limit cylinder pressures to somewhat sensible values | ||||
| 		 */ | ||||
| 		if (pressure >= 0 && pressure < 350000) | ||||
| 			cur_sample->pressure[0].mbar = pressure; | ||||
| 		sample_end(); | ||||
| 			state->cur_sample->pressure[0].mbar = pressure; | ||||
| 		sample_end(state); | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
|  | @ -507,44 +514,44 @@ extern int dm5_dive(void *param, int columns, char **data, char **column) | |||
| 		profileBlob = (float *)data[17]; | ||||
| 		tempBlob = (unsigned char *)data[18]; | ||||
| 		pressureBlob = (int *)data[19]; | ||||
| 		for (i = 0; interval && i * interval < cur_dive->duration.seconds; i++) { | ||||
| 			sample_start(); | ||||
| 			cur_sample->time.seconds = i * interval; | ||||
| 		for (i = 0; interval && i * interval < state->cur_dive->duration.seconds; i++) { | ||||
| 			sample_start(state); | ||||
| 			state->cur_sample->time.seconds = i * interval; | ||||
| 			if (profileBlob) | ||||
| 				cur_sample->depth.mm = lrintf(profileBlob[i] * 1000.0f); | ||||
| 				state->cur_sample->depth.mm = lrintf(profileBlob[i] * 1000.0f); | ||||
| 			else | ||||
| 				cur_sample->depth.mm = cur_dive->dc.maxdepth.mm; | ||||
| 				state->cur_sample->depth.mm = state->cur_dive->dc.maxdepth.mm; | ||||
| 
 | ||||
| 			if (data[18] && data[18][0]) | ||||
| 				cur_sample->temperature.mkelvin = C_to_mkelvin(tempBlob[i]); | ||||
| 				state->cur_sample->temperature.mkelvin = C_to_mkelvin(tempBlob[i]); | ||||
| 			if (data[19] && data[19][0]) | ||||
| 				cur_sample->pressure[0].mbar = pressureBlob[i]; | ||||
| 			sample_end(); | ||||
| 				state->cur_sample->pressure[0].mbar = pressureBlob[i]; | ||||
| 			sample_end(state); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	snprintf(get_events, sizeof(get_events) - 1, get_gaschange_template, cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_events, &dm5_gaschange, 0, &err); | ||||
| 	snprintf(get_events, sizeof(get_events) - 1, get_gaschange_template, state->cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_events, &dm5_gaschange, state, &err); | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "%s", "Database query dm5_gaschange failed.\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	snprintf(get_events, sizeof(get_events) - 1, get_events_template, cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_events, &dm4_events, 0, &err); | ||||
| 	snprintf(get_events, sizeof(get_events) - 1, get_events_template, state->cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_events, &dm4_events, state, &err); | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "%s", "Database query dm4_events failed.\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	snprintf(get_events, sizeof(get_events) - 1, get_tags_template, cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_events, &dm4_tags, 0, &err); | ||||
| 	snprintf(get_events, sizeof(get_events) - 1, get_tags_template, state->cur_dive->number); | ||||
| 	retval = sqlite3_exec(handle, get_events, &dm4_tags, state, &err); | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "%s", "Database query dm4_tags failed.\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	dive_end(); | ||||
| 	dive_end(state); | ||||
| 
 | ||||
| 	return SQLITE_OK; | ||||
| } | ||||
|  | @ -557,13 +564,18 @@ int parse_dm5_buffer(sqlite3 *handle, const char *url, const char *buffer, int s | |||
| 
 | ||||
| 	int retval; | ||||
| 	char *err = NULL; | ||||
| 	target_table = table; | ||||
| 	struct parser_state state; | ||||
| 
 | ||||
| 	init_parser_state(&state); | ||||
| 	state.target_table = table; | ||||
| 	state.sql_handle = handle; | ||||
| 
 | ||||
| 	/* StartTime is converted from Suunto's nano seconds to standard
 | ||||
| 	 * time. We also need epoch, not seconds since year 1. */ | ||||
| 	char get_dives[] = "select DiveId,StartTime/10000000-62135596800,Note,Duration,coalesce(SourceSerialNumber,SerialNumber),Source,MaxDepth,SampleInterval,StartTemperature,BottomTemperature,StartPressure,EndPressure,'','',SurfacePressure,DiveTime,SampleInterval,ProfileBlob,TemperatureBlob,PressureBlob,'','','','',SampleBlob FROM Dive where Deleted is null"; | ||||
| 
 | ||||
| 	retval = sqlite3_exec(handle, get_dives, &dm5_dive, handle, &err); | ||||
| 	retval = sqlite3_exec(handle, get_dives, &dm5_dive, &state, &err); | ||||
| 	free_parser_state(&state); | ||||
| 
 | ||||
| 	if (retval != SQLITE_OK) { | ||||
| 		fprintf(stderr, "Database query failed '%s'.\n", url); | ||||
|  |  | |||
							
								
								
									
										757
									
								
								core/parse-xml.c
									
										
									
									
									
								
							
							
						
						
									
										757
									
								
								core/parse-xml.c
									
										
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										294
									
								
								core/parse.c
									
										
									
									
									
								
							
							
						
						
									
										294
									
								
								core/parse.c
									
										
									
									
									
								
							|  | @ -14,37 +14,39 @@ | |||
| #include "device.h" | ||||
| #include "gettext.h" | ||||
| 
 | ||||
| int metric = 1; | ||||
| 
 | ||||
| event_allocation_t event_allocation = { .event.deleted = 1 }; | ||||
| struct parser_settings cur_settings; | ||||
| 
 | ||||
| struct divecomputer *cur_dc = NULL; | ||||
| struct dive *cur_dive = NULL; | ||||
| struct dive_site *cur_dive_site = NULL; | ||||
| location_t cur_location; | ||||
| dive_trip_t *cur_trip = NULL; | ||||
| struct sample *cur_sample = NULL; | ||||
| struct picture *cur_picture = NULL; | ||||
| 
 | ||||
| bool in_settings = false; | ||||
| bool in_userid = false; | ||||
| 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 dive_table dive_table; | ||||
| struct dive_table *target_table = NULL; | ||||
| 
 | ||||
| void init_parser_state(struct parser_state *state) | ||||
| { | ||||
| 	memset(state, 0, sizeof(*state)); | ||||
| 	state->metric = true; | ||||
| 	state->cur_event.deleted = 1; | ||||
| } | ||||
| 
 | ||||
| void free_parser_state(struct parser_state *state) | ||||
| { | ||||
| 	free_dive(state->cur_dive); | ||||
| 	free_trip(state->cur_trip); | ||||
| 	free_dive_site(state->cur_dive_site); | ||||
| 	free_picture(state->cur_picture); | ||||
| 	free((void *)state->cur_extra_data.key); | ||||
| 	free((void *)state->cur_extra_data.value); | ||||
| 	free((void *)state->cur_settings.dc.nickname); | ||||
| 	free((void *)state->cur_settings.dc.model); | ||||
| 	free((void *)state->cur_settings.dc.nickname); | ||||
| 	free((void *)state->cur_settings.dc.serial_nr); | ||||
| 	free((void *)state->cur_settings.dc.firmware); | ||||
| 	free(state->country); | ||||
| 	free(state->city); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * If we don't have an explicit dive computer, | ||||
|  * we use the implicit one that every dive has.. | ||||
|  */ | ||||
| struct divecomputer *get_dc(void) | ||||
| struct divecomputer *get_dc(struct parser_state *state) | ||||
| { | ||||
| 	return cur_dc ?: &cur_dive->dc; | ||||
| 	return state->cur_dc ?: &state->cur_dive->dc; | ||||
| } | ||||
| 
 | ||||
| /* Trim a character string by removing leading and trailing white space characters.
 | ||||
|  | @ -102,48 +104,48 @@ void nonmatch(const char *type, const char *name, char *buffer) | |||
| 		       type, name, buffer); | ||||
| } | ||||
| 
 | ||||
| void event_start(void) | ||||
| void event_start(struct parser_state *state) | ||||
| { | ||||
| 	memset(&cur_event, 0, sizeof(cur_event)); | ||||
| 	cur_event.deleted = 0;	/* Active */ | ||||
| 	memset(&state->cur_event, 0, sizeof(state->cur_event)); | ||||
| 	state->cur_event.deleted = 0;	/* Active */ | ||||
| } | ||||
| 
 | ||||
| void event_end(void) | ||||
| void event_end(struct parser_state *state) | ||||
| { | ||||
| 	struct divecomputer *dc = get_dc(); | ||||
| 	if (cur_event.type == 123) { | ||||
| 	struct divecomputer *dc = get_dc(state); | ||||
| 	if (state->cur_event.type == 123) { | ||||
| 		struct picture *pic = alloc_picture(); | ||||
| 		pic->filename = strdup(cur_event.name); | ||||
| 		pic->filename = strdup(state->cur_event.name); | ||||
| 		/* theoretically this could fail - but we didn't support multi year offsets */ | ||||
| 		pic->offset.seconds = cur_event.time.seconds; | ||||
| 		dive_add_picture(cur_dive, pic); | ||||
| 		pic->offset.seconds = state->cur_event.time.seconds; | ||||
| 		dive_add_picture(state->cur_dive, pic); | ||||
| 	} else { | ||||
| 		struct event *ev; | ||||
| 		/* At some point gas change events did not have any type. Thus we need to add
 | ||||
| 		 * one on import, if we encounter the type one missing. | ||||
| 		 */ | ||||
| 		if (cur_event.type == 0 && strcmp(cur_event.name, "gaschange") == 0) | ||||
| 			cur_event.type = cur_event.value >> 16 > 0 ? SAMPLE_EVENT_GASCHANGE2 : SAMPLE_EVENT_GASCHANGE; | ||||
| 		ev = add_event(dc, cur_event.time.seconds, | ||||
| 			       cur_event.type, cur_event.flags, | ||||
| 			       cur_event.value, cur_event.name); | ||||
| 		if (state->cur_event.type == 0 && strcmp(state->cur_event.name, "gaschange") == 0) | ||||
| 			state->cur_event.type = state->cur_event.value >> 16 > 0 ? SAMPLE_EVENT_GASCHANGE2 : SAMPLE_EVENT_GASCHANGE; | ||||
| 		ev = add_event(dc, state->cur_event.time.seconds, | ||||
| 			       state->cur_event.type, state->cur_event.flags, | ||||
| 			       state->cur_event.value, state->cur_event.name); | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Older logs might mark the dive to be CCR by having an "SP change" event at time 0:00. Better | ||||
| 		 * to mark them being CCR on import so no need for special treatments elsewhere on the code. | ||||
| 		 */ | ||||
| 		if (ev && cur_event.time.seconds == 0 && cur_event.type == SAMPLE_EVENT_PO2 && cur_event.value && dc->divemode==OC) { | ||||
| 		if (ev && state->cur_event.time.seconds == 0 && state->cur_event.type == SAMPLE_EVENT_PO2 && state->cur_event.value && dc->divemode==OC) { | ||||
| 			dc->divemode = CCR; | ||||
| 		} | ||||
| 
 | ||||
| 		if (ev && event_is_gaschange(ev)) { | ||||
| 			/* See try_to_fill_event() on why the filled-in index is one too big */ | ||||
| 			ev->gas.index = cur_event.gas.index-1; | ||||
| 			if (cur_event.gas.mix.o2.permille || cur_event.gas.mix.he.permille) | ||||
| 				ev->gas.mix = cur_event.gas.mix; | ||||
| 			ev->gas.index = state->cur_event.gas.index-1; | ||||
| 			if (state->cur_event.gas.mix.o2.permille || state->cur_event.gas.mix.he.permille) | ||||
| 				ev->gas.mix = state->cur_event.gas.mix; | ||||
| 		} | ||||
| 	} | ||||
| 	cur_event.deleted = 1;	/* No longer active */ | ||||
| 	state->cur_event.deleted = 1;	/* No longer active */ | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  | @ -158,156 +160,156 @@ void event_end(void) | |||
|  * to make a dive valid, but if it has no location, no date and no | ||||
|  * samples I'm pretty sure it's useless. | ||||
|  */ | ||||
| bool is_dive(void) | ||||
| bool is_dive(struct parser_state *state) | ||||
| { | ||||
| 	return cur_dive && | ||||
| 		(cur_dive->dive_site_uuid || cur_dive->when || cur_dive->dc.samples); | ||||
| 	return state->cur_dive && | ||||
| 		(state->cur_dive->dive_site_uuid || state->cur_dive->when || state->cur_dive->dc.samples); | ||||
| } | ||||
| 
 | ||||
| void reset_dc_info(struct divecomputer *dc) | ||||
| void reset_dc_info(struct divecomputer *dc, struct parser_state *state) | ||||
| { | ||||
| 	/* WARN: reset dc info does't touch the dc? */ | ||||
| 	UNUSED(dc); | ||||
| 	lastcylinderindex = 0; | ||||
| 	state->lastcylinderindex = 0; | ||||
| } | ||||
| 
 | ||||
| void reset_dc_settings(void) | ||||
| void reset_dc_settings(struct parser_state *state) | ||||
| { | ||||
| 	free((void *)cur_settings.dc.model); | ||||
| 	free((void *)cur_settings.dc.nickname); | ||||
| 	free((void *)cur_settings.dc.serial_nr); | ||||
| 	free((void *)cur_settings.dc.firmware); | ||||
| 	cur_settings.dc.model = NULL; | ||||
| 	cur_settings.dc.nickname = NULL; | ||||
| 	cur_settings.dc.serial_nr = NULL; | ||||
| 	cur_settings.dc.firmware = NULL; | ||||
| 	cur_settings.dc.deviceid = 0; | ||||
| 	free((void *)state->cur_settings.dc.model); | ||||
| 	free((void *)state->cur_settings.dc.nickname); | ||||
| 	free((void *)state->cur_settings.dc.serial_nr); | ||||
| 	free((void *)state->cur_settings.dc.firmware); | ||||
| 	state->cur_settings.dc.model = NULL; | ||||
| 	state->cur_settings.dc.nickname = NULL; | ||||
| 	state->cur_settings.dc.serial_nr = NULL; | ||||
| 	state->cur_settings.dc.firmware = NULL; | ||||
| 	state->cur_settings.dc.deviceid = 0; | ||||
| } | ||||
| 
 | ||||
| void settings_start(void) | ||||
| void settings_start(struct parser_state *state) | ||||
| { | ||||
| 	in_settings = true; | ||||
| 	state->in_settings = true; | ||||
| } | ||||
| 
 | ||||
| void settings_end(void) | ||||
| void settings_end(struct parser_state *state) | ||||
| { | ||||
| 	in_settings = false; | ||||
| 	state->in_settings = false; | ||||
| } | ||||
| 
 | ||||
| void dc_settings_start(void) | ||||
| void dc_settings_start(struct parser_state *state) | ||||
| { | ||||
| 	reset_dc_settings(); | ||||
| 	reset_dc_settings(state); | ||||
| } | ||||
| 
 | ||||
| void dc_settings_end(void) | ||||
| void dc_settings_end(struct parser_state *state) | ||||
| { | ||||
| 	create_device_node(cur_settings.dc.model, cur_settings.dc.deviceid, cur_settings.dc.serial_nr, | ||||
| 			   cur_settings.dc.firmware, cur_settings.dc.nickname); | ||||
| 	reset_dc_settings(); | ||||
| 	create_device_node(state->cur_settings.dc.model, state->cur_settings.dc.deviceid, state->cur_settings.dc.serial_nr, | ||||
| 			   state->cur_settings.dc.firmware, state->cur_settings.dc.nickname); | ||||
| 	reset_dc_settings(state); | ||||
| } | ||||
| 
 | ||||
| void dive_site_start(void) | ||||
| void dive_site_start(struct parser_state *state) | ||||
| { | ||||
| 	if (cur_dive_site) | ||||
| 	if (state->cur_dive_site) | ||||
| 		return; | ||||
| 	cur_dive_site = calloc(1, sizeof(struct dive_site)); | ||||
| 	state->cur_dive_site = calloc(1, sizeof(struct dive_site)); | ||||
| } | ||||
| 
 | ||||
| void dive_site_end(void) | ||||
| void dive_site_end(struct parser_state *state) | ||||
| { | ||||
| 	if (!cur_dive_site) | ||||
| 	if (!state->cur_dive_site) | ||||
| 		return; | ||||
| 	if (cur_dive_site->taxonomy.nr == 0) { | ||||
| 		free(cur_dive_site->taxonomy.category); | ||||
| 		cur_dive_site->taxonomy.category = NULL; | ||||
| 	if (state->cur_dive_site->taxonomy.nr == 0) { | ||||
| 		free(state->cur_dive_site->taxonomy.category); | ||||
| 		state->cur_dive_site->taxonomy.category = NULL; | ||||
| 	} | ||||
| 	if (cur_dive_site->uuid) { | ||||
| 		struct dive_site *ds = alloc_or_get_dive_site(cur_dive_site->uuid); | ||||
| 		merge_dive_site(ds, cur_dive_site); | ||||
| 	if (state->cur_dive_site->uuid) { | ||||
| 		struct dive_site *ds = alloc_or_get_dive_site(state->cur_dive_site->uuid); | ||||
| 		merge_dive_site(ds, state->cur_dive_site); | ||||
| 
 | ||||
| 		if (verbose > 3) | ||||
| 			printf("completed dive site uuid %x8 name {%s}\n", ds->uuid, ds->name); | ||||
| 	} | ||||
| 	free_dive_site(cur_dive_site); | ||||
| 	cur_dive_site = NULL; | ||||
| 	free_dive_site(state->cur_dive_site); | ||||
| 	state->cur_dive_site = NULL; | ||||
| } | ||||
| 
 | ||||
| // now we need to add the code to parse the parts of the divesite enry
 | ||||
| 
 | ||||
| void dive_start(void) | ||||
| void dive_start(struct parser_state *state) | ||||
| { | ||||
| 	if (cur_dive) | ||||
| 	if (state->cur_dive) | ||||
| 		return; | ||||
| 	cur_dive = alloc_dive(); | ||||
| 	reset_dc_info(&cur_dive->dc); | ||||
| 	memset(&cur_tm, 0, sizeof(cur_tm)); | ||||
| 	if (cur_trip) { | ||||
| 		add_dive_to_trip(cur_dive, cur_trip); | ||||
| 		cur_dive->tripflag = IN_TRIP; | ||||
| 	state->cur_dive = alloc_dive(); | ||||
| 	reset_dc_info(&state->cur_dive->dc, state); | ||||
| 	memset(&state->cur_tm, 0, sizeof(state->cur_tm)); | ||||
| 	if (state->cur_trip) { | ||||
| 		add_dive_to_trip(state->cur_dive, state->cur_trip); | ||||
| 		state->cur_dive->tripflag = IN_TRIP; | ||||
| 	} | ||||
| 	o2pressure_sensor = 1; | ||||
| 	state->o2pressure_sensor = 1; | ||||
| } | ||||
| 
 | ||||
| void dive_end(void) | ||||
| void dive_end(struct parser_state *state) | ||||
| { | ||||
| 	if (!cur_dive) | ||||
| 	if (!state->cur_dive) | ||||
| 		return; | ||||
| 	if (!is_dive()) | ||||
| 		free_dive(cur_dive); | ||||
| 	if (!is_dive(state)) | ||||
| 		free_dive(state->cur_dive); | ||||
| 	else | ||||
| 		record_dive_to_table(cur_dive, target_table); | ||||
| 	cur_dive = NULL; | ||||
| 	cur_dc = NULL; | ||||
| 	cur_location.lat.udeg = 0; | ||||
| 	cur_location.lon.udeg = 0; | ||||
| 	cur_cylinder_index = 0; | ||||
| 	cur_ws_index = 0; | ||||
| 		record_dive_to_table(state->cur_dive, state->target_table); | ||||
| 	state->cur_dive = NULL; | ||||
| 	state->cur_dc = NULL; | ||||
| 	state->cur_location.lat.udeg = 0; | ||||
| 	state->cur_location.lon.udeg = 0; | ||||
| 	state->cur_cylinder_index = 0; | ||||
| 	state->cur_ws_index = 0; | ||||
| } | ||||
| 
 | ||||
| void trip_start(void) | ||||
| void trip_start(struct parser_state *state) | ||||
| { | ||||
| 	if (cur_trip) | ||||
| 	if (state->cur_trip) | ||||
| 		return; | ||||
| 	dive_end(); | ||||
| 	cur_trip = alloc_trip(); | ||||
| 	memset(&cur_tm, 0, sizeof(cur_tm)); | ||||
| 	dive_end(state); | ||||
| 	state->cur_trip = alloc_trip(); | ||||
| 	memset(&state->cur_tm, 0, sizeof(state->cur_tm)); | ||||
| } | ||||
| 
 | ||||
| void trip_end(void) | ||||
| void trip_end(struct parser_state *state) | ||||
| { | ||||
| 	if (!cur_trip) | ||||
| 	if (!state->cur_trip) | ||||
| 		return; | ||||
| 	insert_trip(&cur_trip); | ||||
| 	cur_trip = NULL; | ||||
| 	insert_trip(&state->cur_trip); | ||||
| 	state->cur_trip = NULL; | ||||
| } | ||||
| 
 | ||||
| void picture_start(void) | ||||
| void picture_start(struct parser_state *state) | ||||
| { | ||||
| 	cur_picture = alloc_picture(); | ||||
| 	state->cur_picture = alloc_picture(); | ||||
| } | ||||
| 
 | ||||
| void picture_end(void) | ||||
| void picture_end(struct parser_state *state) | ||||
| { | ||||
| 	dive_add_picture(cur_dive, cur_picture); | ||||
| 	cur_picture = NULL; | ||||
| 	dive_add_picture(state->cur_dive, state->cur_picture); | ||||
| 	state->cur_picture = NULL; | ||||
| } | ||||
| 
 | ||||
| void cylinder_start(void) | ||||
| void cylinder_start(struct parser_state *state) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| void cylinder_end(void) | ||||
| void cylinder_end(struct parser_state *state) | ||||
| { | ||||
| 	cur_cylinder_index++; | ||||
| 	state->cur_cylinder_index++; | ||||
| } | ||||
| 
 | ||||
| void ws_start(void) | ||||
| void ws_start(struct parser_state *state) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| void ws_end(void) | ||||
| void ws_end(struct parser_state *state) | ||||
| { | ||||
| 	cur_ws_index++; | ||||
| 	state->cur_ws_index++; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  | @ -328,9 +330,9 @@ void ws_end(void) | |||
|  * or the second cylinder depending on what isn't an | ||||
|  * oxygen cylinder. | ||||
|  */ | ||||
| void sample_start(void) | ||||
| void sample_start(struct parser_state *state) | ||||
| { | ||||
| 	struct divecomputer *dc = get_dc(); | ||||
| 	struct divecomputer *dc = get_dc(state); | ||||
| 	struct sample *sample = prepare_sample(dc); | ||||
| 
 | ||||
| 	if (sample != dc->sample) { | ||||
|  | @ -338,28 +340,28 @@ void sample_start(void) | |||
| 		sample->pressure[0].mbar = 0; | ||||
| 		sample->pressure[1].mbar = 0; | ||||
| 	} else { | ||||
| 		sample->sensor[0] = !o2pressure_sensor; | ||||
| 		sample->sensor[1] = o2pressure_sensor; | ||||
| 		sample->sensor[0] = !state->o2pressure_sensor; | ||||
| 		sample->sensor[1] = state->o2pressure_sensor; | ||||
| 	} | ||||
| 	cur_sample = sample; | ||||
| 	next_o2_sensor = 0; | ||||
| 	state->cur_sample = sample; | ||||
| 	state->next_o2_sensor = 0; | ||||
| } | ||||
| 
 | ||||
| void sample_end(void) | ||||
| void sample_end(struct parser_state *state) | ||||
| { | ||||
| 	if (!cur_dive) | ||||
| 	if (!state->cur_dive) | ||||
| 		return; | ||||
| 
 | ||||
| 	finish_sample(get_dc()); | ||||
| 	cur_sample = NULL; | ||||
| 	finish_sample(get_dc(state)); | ||||
| 	state->cur_sample = NULL; | ||||
| } | ||||
| 
 | ||||
| void divecomputer_start(void) | ||||
| void divecomputer_start(struct parser_state *state) | ||||
| { | ||||
| 	struct divecomputer *dc; | ||||
| 
 | ||||
| 	/* Start from the previous dive computer */ | ||||
| 	dc = &cur_dive->dc; | ||||
| 	dc = &state->cur_dive->dc; | ||||
| 	while (dc->next) | ||||
| 		dc = dc->next; | ||||
| 
 | ||||
|  | @ -373,25 +375,25 @@ void divecomputer_start(void) | |||
| 	} | ||||
| 
 | ||||
| 	/* .. this is the one we'll use */ | ||||
| 	cur_dc = dc; | ||||
| 	reset_dc_info(dc); | ||||
| 	state->cur_dc = dc; | ||||
| 	reset_dc_info(dc, state); | ||||
| } | ||||
| 
 | ||||
| void divecomputer_end(void) | ||||
| void divecomputer_end(struct parser_state *state) | ||||
| { | ||||
| 	if (!cur_dc->when) | ||||
| 		cur_dc->when = cur_dive->when; | ||||
| 	cur_dc = NULL; | ||||
| 	if (!state->cur_dc->when) | ||||
| 		state->cur_dc->when = state->cur_dive->when; | ||||
| 	state->cur_dc = NULL; | ||||
| } | ||||
| 
 | ||||
| void userid_start(void) | ||||
| void userid_start(struct parser_state *state) | ||||
| { | ||||
| 	in_userid = true; | ||||
| 	state->in_userid = true; | ||||
| } | ||||
| 
 | ||||
| void userid_stop(void) | ||||
| void userid_stop(struct parser_state *state) | ||||
| { | ||||
| 	in_userid = false; | ||||
| 	state->in_userid = false; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  | @ -409,7 +411,7 @@ void utf8_string(char *buffer, void *_res) | |||
| 		*res = strdup(buffer); | ||||
| } | ||||
| 
 | ||||
| void add_dive_site(char *ds_name, struct dive *dive) | ||||
| void add_dive_site(char *ds_name, struct dive *dive, struct parser_state *state) | ||||
| { | ||||
| 	char *buffer = ds_name; | ||||
| 	char *to_free = NULL; | ||||
|  | @ -441,9 +443,9 @@ void add_dive_site(char *ds_name, struct dive *dive) | |||
| 				} else { | ||||
| 					dive->dive_site_uuid = create_dive_site(buffer, dive->when); | ||||
| 					struct dive_site *newds = get_dive_site_by_uuid(dive->dive_site_uuid); | ||||
| 					if (has_location(&cur_location)) { | ||||
| 					if (has_location(&state->cur_location)) { | ||||
| 						// we started this uuid with GPS data, so lets use those
 | ||||
| 						newds->location = cur_location; | ||||
| 						newds->location = state->cur_location; | ||||
| 					} else { | ||||
| 						newds->location = ds->location; | ||||
| 					} | ||||
|  |  | |||
							
								
								
									
										123
									
								
								core/parse.h
									
										
									
									
									
								
							
							
						
						
									
										123
									
								
								core/parse.h
									
										
									
									
									
								
							|  | @ -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 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue