download: replace progress_bar_text by std::string

No fixed buffers. Sadly, the thing is still a global variable.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2024-06-08 22:43:04 +02:00 committed by bstoeger
parent 91968ac579
commit 7452aa22c2
8 changed files with 87 additions and 84 deletions

View file

@ -353,20 +353,27 @@ std::string casprintf_loc(const char *cformat, ...)
return std::string(utf8.constData(), utf8.size());
}
std::string __printf(1, 2) format_string_std(const char *fmt, ...)
std::string format_string_std(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
size_t stringsize = vsnprintf(NULL, 0, fmt, ap);
std::string res = vformat_string_std(fmt, ap);
va_end(ap);
return res;
}
std::string vformat_string_std(const char *fmt, va_list ap)
{
va_list ap2;
va_copy(ap2, ap);
size_t stringsize = vsnprintf(NULL, 0, fmt, ap2);
va_end(ap2);
if (stringsize == 0)
return std::string();
std::string res;
res.resize(stringsize); // Pointless clearing, oh my.
// This overwrites the terminal null-byte of std::string.
// That's probably "undefined behavior". Oh my.
va_start(ap, fmt);
vsnprintf(res.data(), stringsize + 1, fmt, ap);
va_end(ap);
return res;
}

View file

@ -11,6 +11,7 @@
__printf(1, 2) QString qasprintf_loc(const char *cformat, ...);
__printf(1, 0) QString vqasprintf_loc(const char *cformat, va_list ap);
__printf(1, 2) std::string casprintf_loc(const char *cformat, ...);
__printf(1, 0) std::string vformat_string_std(const char *fmt, va_list ap);
__printf(1, 2) std::string format_string_std(const char *fmt, ...);
#endif

View file

@ -43,8 +43,8 @@
std::string dumpfile_name;
std::string logfile_name;
const char *progress_bar_text = "";
void (*progress_callback)(const char *text) = NULL;
std::string progress_bar_text;
void (*progress_callback)(const std::string &text) = NULL;
double progress_bar_fraction = 0.0;
static int stoptime, stopdepth, ndl, po2, cns, heartbeat, bearing;
@ -491,33 +491,30 @@ sample_cb(dc_sample_type_t type, const dc_sample_value_t *pvalue, void *userdata
}
}
static void dev_info(device_data_t *, const char *fmt, ...)
static void dev_info(const char *fmt, ...)
{
static char buffer[1024];
va_list ap;
va_start(ap, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, ap);
progress_bar_text = vformat_string_std(fmt, ap);
va_end(ap);
progress_bar_text = buffer;
if (verbose)
INFO("dev_info: %s", buffer);
INFO("dev_info: %s", progress_bar_text.c_str());
if (progress_callback)
(*progress_callback)(buffer);
(*progress_callback)(progress_bar_text);
}
static int import_dive_number = 0;
static void download_error(const char *fmt, ...)
{
static char buffer[1024];
va_list ap;
va_start(ap, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, ap);
std::string buffer = vformat_string_std(fmt, ap);
va_end(ap);
report_error("Dive %d: %s", import_dive_number, buffer);
report_error("Dive %d: %s", import_dive_number, buffer.c_str());
}
static dc_status_t parse_samples(device_data_t *, struct divecomputer *dc, dc_parser_t *parser)
@ -649,7 +646,7 @@ static dc_status_t libdc_header_parser(dc_parser_t *parser, device_data_t *devda
// Parse the divetime.
std::string date_string = get_dive_date_c_string(dive->when);
dev_info(devdata, translate("gettextFromC", "Dive %d: %s"), import_dive_number, date_string.c_str());
dev_info(translate("gettextFromC", "Dive %d: %s"), import_dive_number, date_string.c_str());
unsigned int divetime = 0;
rc = dc_parser_get_field(parser, DC_FIELD_DIVETIME, 0, &divetime);
@ -846,7 +843,7 @@ static int dive_cb(const unsigned char *data, unsigned int size,
/* If we already saw this dive, abort. */
if (!devdata->force_download && find_dive(dive->dcs[0])) {
std::string date_string = get_dive_date_c_string(dive->when);
dev_info(devdata, translate("gettextFromC", "Already downloaded dive at %s"), date_string.c_str());
dev_info(translate("gettextFromC", "Already downloaded dive at %s"), date_string.c_str());
return false;
}
@ -884,7 +881,7 @@ static void do_save_fingerprint(device_data_t *devdata, const char *tmp, const c
return;
if (verbose)
dev_info(devdata, "Saving fingerprint for %08x:%08x to '%s'",
dev_info("Saving fingerprint for %08x:%08x to '%s'",
devdata->fdeviceid, devdata->fdiveid, final);
/* The fingerprint itself.. */
@ -984,16 +981,16 @@ static void verify_fingerprint(dc_device_t *device, device_data_t *devdata, cons
memcpy(&diveid, buffer + size + 4, 4);
if (verbose)
dev_info(devdata, " ... fingerprinted dive %08x:%08x", deviceid, diveid);
dev_info(" ... fingerprinted dive %08x:%08x", deviceid, diveid);
/* Only use it if we *have* that dive! */
if (!has_dive(deviceid, diveid)) {
if (verbose)
dev_info(devdata, " ... dive not found");
dev_info(" ... dive not found");
return;
}
dc_device_set_fingerprint(device, buffer, size);
if (verbose)
dev_info(devdata, " ... fingerprint of size %zu", size);
dev_info(" ... fingerprint of size %zu", size);
}
/*
@ -1010,18 +1007,18 @@ static void lookup_fingerprint(dc_device_t *device, device_data_t *devdata)
auto [fsize, raw_data] = get_fingerprint_data(fingerprints, calculate_string_hash(devdata->model.c_str()), devdata->devinfo.serial);
if (fsize) {
if (verbose)
dev_info(devdata, "... found fingerprint in dive table");
dev_info("... found fingerprint in dive table");
dc_device_set_fingerprint(device, raw_data, fsize);
return;
}
/* now check if we have a fingerprint on disk */
std::string cachename = fingerprint_file(devdata);
if (verbose)
dev_info(devdata, "Looking for fingerprint in '%s'", cachename.c_str());
dev_info("Looking for fingerprint in '%s'", cachename.c_str());
auto [mem, err] = readfile(cachename.c_str());
if (err > 0) {
if (verbose)
dev_info(devdata, " ... got %zu bytes", mem.size());
dev_info(" ... got %zu bytes", mem.size());
verify_fingerprint(device, devdata, (unsigned char *)mem.data(), mem.size());
}
}
@ -1037,7 +1034,7 @@ static void event_cb(dc_device_t *device, dc_event_type_t event, const void *dat
switch (event) {
case DC_EVENT_WAITING:
dev_info(devdata, translate("gettextFromC", "Event: waiting for user action"));
dev_info(translate("gettextFromC", "Event: waiting for user action"));
break;
case DC_EVENT_PROGRESS:
/* this seems really dumb... but having no idea what is happening on long
@ -1049,7 +1046,7 @@ static void event_cb(dc_device_t *device, dc_event_type_t event, const void *dat
last = progress->current;
if (progress->current > last + 10240) {
last = progress->current;
dev_info(NULL, translate("gettextFromC", "read %dkb"), progress->current / 1024);
dev_info(translate("gettextFromC", "read %dkb"), progress->current / 1024);
}
if (progress->maximum)
progress_bar_fraction = (double)progress->current / (double)progress->maximum;
@ -1069,7 +1066,7 @@ static void event_cb(dc_device_t *device, dc_event_type_t event, const void *dat
devinfo->model, dc_descriptor_get_model(devdata->descriptor));
}
}
dev_info(devdata, translate("gettextFromC", "model=%s firmware=%u serial=%u"),
dev_info(translate("gettextFromC", "model=%s firmware=%u serial=%u"),
devdata->product.c_str(), devinfo->firmware, devinfo->serial);
if (devdata->libdc_logfile) {
fprintf(devdata->libdc_logfile, "Event: model=%u (0x%08x), firmware=%u (0x%08x), serial=%u (0x%08x)\n",
@ -1083,7 +1080,7 @@ static void event_cb(dc_device_t *device, dc_event_type_t event, const void *dat
break;
case DC_EVENT_CLOCK:
dev_info(devdata, translate("gettextFromC", "Event: systime=%" PRId64 ", devtime=%u\n"),
dev_info(translate("gettextFromC", "Event: systime=%" PRId64 ", devtime=%u\n"),
(uint64_t)clock->systime, clock->devtime);
if (devdata->libdc_logfile) {
fprintf(devdata->libdc_logfile, "Event: systime=%" PRId64 ", devtime=%u\n",
@ -1121,7 +1118,7 @@ static std::string do_device_import(device_data_t *data)
int events = DC_EVENT_WAITING | DC_EVENT_PROGRESS | DC_EVENT_DEVINFO | DC_EVENT_CLOCK | DC_EVENT_VENDOR;
rc = dc_device_set_events(device, events, event_cb, data);
if (rc != DC_STATUS_SUCCESS) {
dev_info(data, "Import error: %s", errmsg(rc));
dev_info("Import error: %s", errmsg(rc));
return translate("gettextFromC", "Error registering the event handler.");
}
@ -1129,7 +1126,7 @@ static std::string do_device_import(device_data_t *data)
// Register the cancellation handler.
rc = dc_device_set_cancel(device, cancel_cb, data);
if (rc != DC_STATUS_SUCCESS) {
dev_info(data, "Import error: %s", errmsg(rc));
dev_info("Import error: %s", errmsg(rc));
return translate("gettextFromC", "Error registering the cancellation handler.");
}
@ -1154,7 +1151,7 @@ static std::string do_device_import(device_data_t *data)
if (rc == DC_STATUS_UNSUPPORTED)
return translate("gettextFromC", "Dumping not supported on this device");
dev_info(data, "Import error: %s", errmsg(rc));
dev_info("Import error: %s", errmsg(rc));
return translate("gettextFromC", "Dive data dumping error");
}
@ -1164,7 +1161,7 @@ static std::string do_device_import(device_data_t *data)
if (rc != DC_STATUS_SUCCESS) {
progress_bar_fraction = 0.0;
dev_info(data, "Import error: %s", errmsg(rc));
dev_info("Import error: %s", errmsg(rc));
return translate("gettextFromC", "Dive data import error");
}
@ -1254,7 +1251,7 @@ static dc_status_t usbhid_device_open(dc_iostream_t **iostream, dc_context_t *co
ERROR("didn't find HID device");
return DC_STATUS_NODEVICE;
}
dev_info(data, "Opening USB HID device for %04x:%04x",
dev_info("Opening USB HID device for %04x:%04x",
dc_usbhid_device_get_vid(device),
dc_usbhid_device_get_pid(device));
rc = dc_usbhid_open(iostream, context, device);
@ -1277,7 +1274,7 @@ static dc_status_t usb_device_open(dc_iostream_t **iostream, dc_context_t *conte
if (!device)
return DC_STATUS_NODEVICE;
dev_info(data, "Opening USB device for %04x:%04x",
dev_info("Opening USB device for %04x:%04x",
dc_usb_device_get_vid(device),
dc_usb_device_get_pid(device));
rc = dc_usb_open(iostream, context, device);
@ -1305,7 +1302,7 @@ static dc_status_t irda_device_open(dc_iostream_t **iostream, dc_context_t *cont
if (!address)
std::from_chars(data->devname.c_str(), data->devname.c_str() + data->devname.size(), address);
dev_info(data, "Opening IRDA address %u", address);
dev_info("Opening IRDA address %u", address);
return dc_irda_open(&data->iostream, context, address, 1);
}
@ -1326,11 +1323,11 @@ static dc_status_t bluetooth_device_open(dc_context_t *context, device_data_t *d
dc_iterator_free (iterator);
if (!address) {
dev_info(data, "No rfcomm device found");
dev_info("No rfcomm device found");
return DC_STATUS_NODEVICE;
}
dev_info(data, "Opening rfcomm address %llu", address);
dev_info("Opening rfcomm address %llu", address);
return dc_bluetooth_open(&data->iostream, context, address, 0);
}
#endif
@ -1346,13 +1343,13 @@ dc_status_t divecomputer_device_open(device_data_t *data)
transports &= supported;
if (!transports) {
dev_info(data, "Dive computer transport not supported");
dev_info("Dive computer transport not supported");
return DC_STATUS_UNSUPPORTED;
}
#ifdef BT_SUPPORT
if (transports & DC_TRANSPORT_BLUETOOTH) {
dev_info(data, "Opening rfcomm stream %s", data->devname.c_str());
dev_info("Opening rfcomm stream %s", data->devname.c_str());
#if defined(__ANDROID__) || defined(__APPLE__)
// we don't have BT on iOS in the first place, so this is for Android and macOS
rc = rfcomm_stream_open(&data->iostream, context, data->devname.c_str());
@ -1366,7 +1363,7 @@ dc_status_t divecomputer_device_open(device_data_t *data)
#ifdef BLE_SUPPORT
if (transports & DC_TRANSPORT_BLE) {
dev_info(data, "Connecting to BLE device %s", data->devname.c_str());
dev_info("Connecting to BLE device %s", data->devname.c_str());
rc = ble_packet_open(&data->iostream, context, data->devname.c_str(), data);
if (rc == DC_STATUS_SUCCESS)
return rc;
@ -1374,21 +1371,21 @@ dc_status_t divecomputer_device_open(device_data_t *data)
#endif
if (transports & DC_TRANSPORT_USBHID) {
dev_info(data, "Connecting to USB HID device");
dev_info("Connecting to USB HID device");
rc = usbhid_device_open(&data->iostream, context, data);
if (rc == DC_STATUS_SUCCESS)
return rc;
}
if (transports & DC_TRANSPORT_USB) {
dev_info(data, "Connecting to native USB device");
dev_info("Connecting to native USB device");
rc = usb_device_open(&data->iostream, context, data);
if (rc == DC_STATUS_SUCCESS)
return rc;
}
if (transports & DC_TRANSPORT_SERIAL) {
dev_info(data, "Opening serial device %s", data->devname.c_str());
dev_info("Opening serial device %s", data->devname.c_str());
#ifdef SERIAL_FTDI
if (!strcasecmp(data->devname.c_str(), "ftdi"))
return ftdi_open(&data->iostream, context);
@ -1404,14 +1401,14 @@ dc_status_t divecomputer_device_open(device_data_t *data)
}
if (transports & DC_TRANSPORT_IRDA) {
dev_info(data, "Connecting to IRDA device");
dev_info("Connecting to IRDA device");
rc = irda_device_open(&data->iostream, context, data);
if (rc == DC_STATUS_SUCCESS)
return rc;
}
if (transports & DC_TRANSPORT_USBSTORAGE) {
dev_info(data, "Opening USB storage at %s", data->devname.c_str());
dev_info("Opening USB storage at %s", data->devname.c_str());
rc = dc_usb_storage_open(&data->iostream, context, data->devname.c_str());
if (rc == DC_STATUS_SUCCESS)
return rc;
@ -1462,9 +1459,9 @@ std::string do_libdivecomputer_import(device_data_t *data)
rc = divecomputer_device_open(data);
if (rc != DC_STATUS_SUCCESS) {
dev_info(data, "Import error: %s", errmsg(rc));
dev_info("Import error: %s", errmsg(rc));
} else {
dev_info(data, "Connecting ...");
dev_info("Connecting ...");
rc = dc_device_open(&data->device, data->context, data->descriptor, data->iostream);
if (rc != DC_STATUS_SUCCESS) {
INFO("dc_device_open error value of %d", rc);
@ -1475,26 +1472,26 @@ std::string do_libdivecomputer_import(device_data_t *data)
err = translate("gettextFromC", "Error opening the device %s %s (%s).\nIn most cases, in order to debug this issue, a libdivecomputer logfile will be useful.\nYou can create this logfile by selecting the corresponding checkbox in the download dialog.");
#endif
} else {
dev_info(data, "Starting import ...");
dev_info("Starting import ...");
err = do_device_import(data);
/* TODO: Show the logfile to the user on error. */
dev_info(data, "Import complete");
dev_info("Import complete");
if (err.empty() && data->sync_time) {
dev_info(data, "Syncing dive computer time ...");
dev_info("Syncing dive computer time ...");
rc = sync_divecomputer_time(data->device);
switch (rc) {
case DC_STATUS_SUCCESS:
dev_info(data, "Time sync complete");
dev_info("Time sync complete");
break;
case DC_STATUS_UNSUPPORTED:
dev_info(data, "Time sync not supported by dive computer");
dev_info("Time sync not supported by dive computer");
break;
default:
dev_info(data, "Time sync failed");
dev_info("Time sync failed");
break;
}
@ -1503,7 +1500,7 @@ std::string do_libdivecomputer_import(device_data_t *data)
dc_device_close(data->device);
data->device = NULL;
if (data->log->dives.empty())
dev_info(data, translate("gettextFromC", "No new dives downloaded from dive computer"));
dev_info(translate("gettextFromC", "No new dives downloaded from dive computer"));
}
dc_iostream_close(data->iostream);
data->iostream = NULL;

View file

@ -55,8 +55,8 @@ void logfunc(dc_context_t *context, dc_loglevel_t loglevel, const char *file, un
dc_descriptor_t *get_descriptor(dc_family_t type, unsigned int model);
extern int import_thread_cancelled;
extern const char *progress_bar_text;
extern void (*progress_callback)(const char *text);
extern std::string progress_bar_text;
extern void (*progress_callback)(const std::string &text);
extern double progress_bar_fraction;
dc_status_t ble_packet_open(dc_iostream_t **iostream, dc_context_t *context, const char* devaddr, void *userdata);

View file

@ -200,15 +200,13 @@ static struct dive *get_dive_by_uemis_diveid(device_data_t *devdata, uint32_t ob
/* send text to the importer progress bar */
static void uemis_info(const char *fmt, ...)
{
static char buffer[256];
va_list ap;
va_start(ap, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, ap);
progress_bar_text = vformat_string_std(fmt, ap);
va_end(ap);
progress_bar_text = buffer;
if (verbose)
report_info("Uemis downloader: %s", buffer);
report_info("Uemis downloader: %s", progress_bar_text.c_str());
}
static long bytes_available(int file)

View file

@ -63,7 +63,7 @@ DownloadFromDCWidget::DownloadFromDCWidget(const QString &filename, QWidget *par
ui.product->setModel(&productModel);
ui.syncDiveComputerTime->setChecked(prefs.sync_dc_time);
progress_bar_text = "";
progress_bar_text.clear();
timer->setInterval(200);
@ -212,21 +212,19 @@ DELETEDCBUTTON(4)
void DownloadFromDCWidget::updateProgressBar()
{
static char *last_text = NULL;
if (empty_string(last_text)) {
if (last_text.empty()) {
// if we get the first actual text after the download is finished
// (which happens for example on the OSTC), then don't bother
if (!empty_string(progress_bar_text) && nearly_equal(progress_bar_fraction, 1.0))
progress_bar_text = "";
if (!progress_bar_text.empty() && nearly_equal(progress_bar_fraction, 1.0))
progress_bar_text.clear();
}
if (!empty_string(progress_bar_text)) {
if (!progress_bar_text.empty()) {
// once the progress bar text is set, setup the maximum so the user sees actual progress
ui.progressBar->setFormat(progress_bar_text);
ui.progressBar->setFormat(QString::fromStdString(progress_bar_text));
ui.progressBar->setMaximum(100);
#if defined(Q_OS_MAC)
// on mac the progress bar doesn't show its text
ui.progressText->setText(progress_bar_text);
ui.progressText->setText(QString::fromStdString(progress_bar_text));
#endif
} else {
if (nearly_0(progress_bar_fraction)) {
@ -248,8 +246,7 @@ void DownloadFromDCWidget::updateProgressBar()
}
}
ui.progressBar->setValue(lrint(progress_bar_fraction * 100));
free(last_text);
last_text = strdup(progress_bar_text);
last_text = progress_bar_text;
}
void DownloadFromDCWidget::updateState(states state)
@ -262,10 +259,10 @@ void DownloadFromDCWidget::updateState(states state)
ui.progressBar->hide();
markChildrenAsEnabled();
timer->stop();
progress_bar_text = "";
progress_bar_text.clear();
#if defined(Q_OS_MAC)
// on mac we show the text in a label
ui.progressText->setText(progress_bar_text);
ui.progressText->setText(QString::fromStdString(progress_bar_text));
#endif
}
@ -288,10 +285,10 @@ void DownloadFromDCWidget::updateState(states state)
ui.progressBar->setValue(0);
ui.progressBar->hide();
markChildrenAsEnabled();
progress_bar_text = "";
progress_bar_text.clear();
#if defined(Q_OS_MAC)
// on mac we show the text in a label
ui.progressText->setText(progress_bar_text);
ui.progressText->setText(QString::fromStdString(progress_bar_text));
#endif
}
@ -300,19 +297,19 @@ void DownloadFromDCWidget::updateState(states state)
// If we find an error, offer to retry, otherwise continue the interaction to pick the dives the user wants
else if (currentState == DOWNLOADING && state == DONE) {
timer->stop();
if (QString(progress_bar_text).contains("error", Qt::CaseInsensitive)) {
if (QString::fromStdString(progress_bar_text).contains("error", Qt::CaseInsensitive)) {
updateProgressBar();
markChildrenAsEnabled();
progress_bar_text = "";
progress_bar_text.clear();
} else {
if (diveImportedModel->numDives() != 0)
progress_bar_text = "";
progress_bar_text.clear();
ui.progressBar->setValue(100);
markChildrenAsEnabled();
}
#if defined(Q_OS_MAC)
// on mac we show the text in a label
ui.progressText->setText(progress_bar_text);
ui.progressText->setText(QString::fromStdString(progress_bar_text));
#endif
}
@ -333,11 +330,11 @@ void DownloadFromDCWidget::updateState(states state)
QMessageBox::critical(this, TITLE_OR_TEXT(tr("Error"),
QString::fromStdString(diveImportedModel->thread.error)), QMessageBox::Ok);
markChildrenAsEnabled();
progress_bar_text = "";
progress_bar_text.clear();
ui.progressBar->hide();
#if defined(Q_OS_MAC)
// on mac we show the text in a label
ui.progressText->setText(progress_bar_text);
ui.progressText->setText(QString::fromStdString(progress_bar_text));
#endif
}

View file

@ -8,6 +8,7 @@
#include <QMap>
#include <QAbstractTableModel>
#include <memory>
#include <string>
#include "core/libdivecomputer.h"
#include "desktop-widgets/configuredivecomputerdialog.h"
@ -77,6 +78,7 @@ private:
QStringListModel productModel;
Ui::DownloadFromDiveComputer ui;
QString filename;
std::string last_text;
bool downloading;
int previousLast;

View file

@ -76,12 +76,13 @@ void showErrorFromC(char *buf)
}
// this gets called from libdivecomputer
static void progressCallback(const char *text)
static void progressCallback(const std::string &text)
{
QMLManager *self = QMLManager::instance();
if (self) {
self->appendTextToLog(QString(text));
self->setProgressMessage(QString(text));
QString s = QString::fromStdString(text);
self->appendTextToLog(s);
self->setProgressMessage(s);
}
}