mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
There was a global variable last_pi_entry_new, which stored the recently allocated plot data. This was freed when new plot data was generated. A very scary proposition: You can never have two plot datas at the same time! But exactly that happens when you export for example subtitles. The only reason why this didn't lead to very crazy behavior is that at least on my Linux machine, the calloc() call would just return the previously freed memory. Fix this mess by removing the global variable and freeing the data in the callers. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
265 lines
7.4 KiB
C
265 lines
7.4 KiB
C
#include "core/profile.h"
|
|
#include "core/profile.h"
|
|
#include "core/dive.h"
|
|
#include "core/display.h"
|
|
#include "core/membuffer.h"
|
|
#include "core/subsurface-string.h"
|
|
#include "core/save-profiledata.h"
|
|
#include "core/version.h"
|
|
|
|
static void put_int(struct membuffer *b, int val)
|
|
{
|
|
put_format(b, "\"%d\", ", val);
|
|
}
|
|
|
|
static void put_csv_string(struct membuffer *b, const char *val)
|
|
{
|
|
put_format(b, "\"%s\", ", val);
|
|
}
|
|
|
|
static void put_double(struct membuffer *b, double val)
|
|
{
|
|
put_format(b, "\"%f\" ", val);
|
|
}
|
|
|
|
static void put_video_time(struct membuffer *b, int secs)
|
|
{
|
|
int hours = secs / 3600;
|
|
secs -= hours * 3600;
|
|
int mins = secs / 60;
|
|
secs -= mins * 60;
|
|
put_format(b, "%d:%02d:%02d.000,", hours, mins, secs);
|
|
}
|
|
|
|
static void put_pd(struct membuffer *b, struct plot_data *entry)
|
|
{
|
|
if (!entry)
|
|
return;
|
|
|
|
put_int(b, entry->in_deco);
|
|
put_int(b, entry->sec);
|
|
for (int c = 0; c < MAX_CYLINDERS; c++) {
|
|
put_int(b, entry->pressure[c][0]);
|
|
put_int(b, entry->pressure[c][1]);
|
|
}
|
|
put_int(b, entry->temperature);
|
|
put_int(b, entry->depth);
|
|
put_int(b, entry->ceiling);
|
|
for (int i = 0; i < 16; i++)
|
|
put_int(b, entry->ceilings[i]);
|
|
for (int i = 0; i < 16; i++)
|
|
put_int(b, entry->percentages[i]);
|
|
put_int(b, entry->ndl);
|
|
put_int(b, entry->tts);
|
|
put_int(b, entry->rbt);
|
|
put_int(b, entry->stoptime);
|
|
put_int(b, entry->stopdepth);
|
|
put_int(b, entry->cns);
|
|
put_int(b, entry->smoothed);
|
|
put_int(b, entry->sac);
|
|
put_int(b, entry->running_sum);
|
|
put_double(b, entry->pressures.o2);
|
|
put_double(b, entry->pressures.n2);
|
|
put_double(b, entry->pressures.he);
|
|
put_int(b, entry->o2pressure.mbar);
|
|
put_int(b, entry->o2sensor[0].mbar);
|
|
put_int(b, entry->o2sensor[1].mbar);
|
|
put_int(b, entry->o2sensor[2].mbar);
|
|
put_int(b, entry->o2setpoint.mbar);
|
|
put_int(b, entry->scr_OC_pO2.mbar);
|
|
put_double(b, entry->mod);
|
|
put_double(b, entry->ead);
|
|
put_double(b, entry->end);
|
|
put_double(b, entry->eadd);
|
|
switch (entry->velocity) {
|
|
case STABLE:
|
|
put_csv_string(b, "STABLE");
|
|
break;
|
|
case SLOW:
|
|
put_csv_string(b, "SLOW");
|
|
break;
|
|
case MODERATE:
|
|
put_csv_string(b, "MODERATE");
|
|
break;
|
|
case FAST:
|
|
put_csv_string(b, "FAST");
|
|
break;
|
|
case CRAZY:
|
|
put_csv_string(b, "CRAZY");
|
|
break;
|
|
}
|
|
put_int(b, entry->speed);
|
|
put_int(b, entry->in_deco_calc);
|
|
put_int(b, entry->ndl_calc);
|
|
put_int(b, entry->tts_calc);
|
|
put_int(b, entry->stoptime_calc);
|
|
put_int(b, entry->stopdepth_calc);
|
|
put_int(b, entry->pressure_time);
|
|
put_int(b, entry->heartbeat);
|
|
put_int(b, entry->bearing);
|
|
put_double(b, entry->ambpressure);
|
|
put_double(b, entry->gfline);
|
|
put_double(b, entry->surface_gf);
|
|
put_double(b, entry->density);
|
|
put_int(b, entry->icd_warning ? 1 : 0);
|
|
}
|
|
|
|
static void put_headers(struct membuffer *b)
|
|
{
|
|
put_csv_string(b, "in_deco");
|
|
put_csv_string(b, "sec");
|
|
for (int c = 0; c < MAX_CYLINDERS; c++) {
|
|
put_format(b, "\"pressure_%d_cylinder\", ", c);
|
|
put_format(b, "\"pressure_%d_interpolated\", ", c);
|
|
}
|
|
put_csv_string(b, "temperature");
|
|
put_csv_string(b, "depth");
|
|
put_csv_string(b, "ceiling");
|
|
for (int i = 0; i < 16; i++)
|
|
put_format(b, "\"ceiling_%d\", ", i);
|
|
for (int i = 0; i < 16; i++)
|
|
put_format(b, "\"percentage_%d\", ", i);
|
|
put_csv_string(b, "ndl");
|
|
put_csv_string(b, "tts");
|
|
put_csv_string(b, "rbt");
|
|
put_csv_string(b, "stoptime");
|
|
put_csv_string(b, "stopdepth");
|
|
put_csv_string(b, "cns");
|
|
put_csv_string(b, "smoothed");
|
|
put_csv_string(b, "sac");
|
|
put_csv_string(b, "running_sum");
|
|
put_csv_string(b, "pressureo2");
|
|
put_csv_string(b, "pressuren2");
|
|
put_csv_string(b, "pressurehe");
|
|
put_csv_string(b, "o2pressure");
|
|
put_csv_string(b, "o2sensor0");
|
|
put_csv_string(b, "o2sensor1");
|
|
put_csv_string(b, "o2sensor2");
|
|
put_csv_string(b, "o2setpoint");
|
|
put_csv_string(b, "scr_oc_po2");
|
|
put_csv_string(b, "mod");
|
|
put_csv_string(b, "ead");
|
|
put_csv_string(b, "end");
|
|
put_csv_string(b, "eadd");
|
|
put_csv_string(b, "velocity");
|
|
put_csv_string(b, "speed");
|
|
put_csv_string(b, "in_deco_calc");
|
|
put_csv_string(b, "ndl_calc");
|
|
put_csv_string(b, "tts_calc");
|
|
put_csv_string(b, "stoptime_calc");
|
|
put_csv_string(b, "stopdepth_calc");
|
|
put_csv_string(b, "pressure_time");
|
|
put_csv_string(b, "heartbeat");
|
|
put_csv_string(b, "bearing");
|
|
put_csv_string(b, "ambpressure");
|
|
put_csv_string(b, "gfline");
|
|
put_csv_string(b, "surface_gf");
|
|
put_csv_string(b, "density");
|
|
put_csv_string(b, "icd_warning");
|
|
}
|
|
|
|
static void put_st_event(struct membuffer *b, struct plot_data *entry, int offset, int length)
|
|
{
|
|
double value;
|
|
int decimals;
|
|
const char *unit;
|
|
|
|
if (entry->sec < offset || entry->sec > offset + length)
|
|
return;
|
|
|
|
put_format(b, "Dialogue: 0,");
|
|
put_video_time(b, entry->sec - offset);
|
|
put_video_time(b, (entry+1)->sec - offset < length ? (entry+1)->sec - offset : length);
|
|
put_format(b, "Default,,0,0,0,,");
|
|
put_format(b, "%d:%02d ", FRACTION(entry->sec, 60));
|
|
value = get_depth_units(entry->depth, &decimals, &unit);
|
|
put_format(b, "D=%02.2f %s ", value, unit);
|
|
if (entry->temperature) {
|
|
value = get_temp_units(entry->temperature, &unit);
|
|
put_format(b, "T=%.1f%s ", value, unit);
|
|
}
|
|
// Only show NDL if it is not essentially infinite, show TTS for mandatory stops.
|
|
if (entry->ndl_calc < 3600) {
|
|
if (entry->ndl_calc > 0)
|
|
put_format(b, "NDL=%d:%02d ", FRACTION(entry->ndl_calc, 60));
|
|
else
|
|
if (entry->tts_calc > 0)
|
|
put_format(b, "TTS=%d:%02d ", FRACTION(entry->tts_calc, 60));
|
|
}
|
|
if (entry->surface_gf > 0.0) {
|
|
put_format(b, "sGF=%.1f%% ", entry->surface_gf);
|
|
}
|
|
put_format(b, "\n");
|
|
}
|
|
|
|
static void save_profiles_buffer(struct membuffer *b, bool select_only)
|
|
{
|
|
int i;
|
|
struct dive *dive;
|
|
struct plot_info pi;
|
|
struct deco_state *planner_deco_state = NULL;
|
|
|
|
for_each_dive(i, dive) {
|
|
if (select_only && !dive->selected)
|
|
continue;
|
|
pi = calculate_max_limits_new(dive, &dive->dc);
|
|
create_plot_info_new(dive, &dive->dc, &pi, false, planner_deco_state);
|
|
put_headers(b);
|
|
put_format(b, "\n");
|
|
|
|
for (int i = 0; i < pi.nr; i++) {
|
|
put_pd(b, &pi.entry[i]);
|
|
put_format(b, "\n");
|
|
}
|
|
put_format(b, "\n");
|
|
free_plot_info_data(&pi);
|
|
}
|
|
}
|
|
|
|
void save_subtitles_buffer(struct membuffer *b, struct dive *dive, int offset, int length)
|
|
{
|
|
struct plot_info pi;
|
|
struct deco_state *planner_deco_state = NULL;
|
|
|
|
pi = calculate_max_limits_new(dive, &dive->dc);
|
|
create_plot_info_new(dive, &dive->dc, &pi, false, planner_deco_state);
|
|
|
|
put_format(b, "[Script Info]\n");
|
|
put_format(b, "; Script generated by Subsurface %s\n", subsurface_canonical_version());
|
|
put_format(b, "ScriptType: v4.00+\nPlayResX: 384\nPlayResY: 288\n\n");
|
|
put_format(b, "[V4+ Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n");
|
|
put_format(b, "Style: Default,Arial,12,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,7,10,10,10,0\n\n");
|
|
put_format(b, "[Events]\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n");
|
|
|
|
for (int i = 0; i < pi.nr; i++) {
|
|
put_st_event(b, &pi.entry[i], offset, length);
|
|
}
|
|
put_format(b, "\n");
|
|
|
|
free_plot_info_data(&pi);
|
|
}
|
|
|
|
int save_profiledata(const char *filename, const bool select_only)
|
|
{
|
|
struct membuffer buf = { 0 };
|
|
FILE *f;
|
|
int error = 0;
|
|
|
|
save_profiles_buffer(&buf, select_only);
|
|
|
|
if (same_string(filename, "-")) {
|
|
f = stdout;
|
|
} else {
|
|
error = -1;
|
|
f = subsurface_fopen(filename, "w");
|
|
}
|
|
if (f) {
|
|
flush_buffer(&buf, f);
|
|
error = fclose(f);
|
|
}
|
|
if (error)
|
|
report_error("Save failed (%s)", strerror(error));
|
|
|
|
free_buffer(&buf);
|
|
return error;
|
|
}
|