core: directly generate std::strings in git parser

The converted strings were stored in a membuffer and later
converted to std::strings. Generate an std::string directly
to avoid unnecessary copying.

Ultimately, when the core structures are converted to
std::string, there should be no copying of the string data
at all (unless formatting is applied or small string
optimization kicks in, of course).

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2024-03-02 17:30:14 +01:00 committed by Michael Keller
parent 6b054318e0
commit 885ff44c56

View file

@ -24,7 +24,6 @@
#include "subsurface-string.h"
#include "trip.h"
#include "device.h"
#include "membuffer.h"
#include "git-access.h"
#include "picture.h"
#include "qthelper.h"
@ -53,11 +52,12 @@ struct git_parser_state {
std::unique_ptr<filter_preset> active_filter;
struct divelog *log = nullptr;
int o2pressure_sensor = 0;
std::vector<std::string> converted_strings;
};
struct keyword_action {
const char *keyword;
void (*fn)(char *, struct membuffer *, struct git_parser_state *);
void (*fn)(char *, struct git_parser_state *);
};
static git_blob *git_tree_entry_blob(git_repository *repo, const git_tree_entry *entry);
@ -168,7 +168,7 @@ static int get_index(const char *line)
static int get_hex(const char *line)
{ return strtoul(line, NULL, 16); }
static void parse_dive_gps(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dive_gps(char *line, struct git_parser_state *state)
{
location_t location;
struct dive_site *ds = get_dive_site_for_dive(state->active_dive);
@ -183,169 +183,172 @@ static void parse_dive_gps(char *line, struct membuffer *, struct git_parser_sta
if (dive_site_has_gps_location(ds) && !same_location(&ds->location, &location)) {
std::string coords = printGPSCoordsC(&location);
// we have a dive site that already has GPS coordinates
ds->notes = add_to_string(ds->notes, translate("gettextFromC", "multiple GPS locations for this dive site; also %s\n"), coords.c_str());
// note 1: there will be much less copying once the core
// structures are converted to std::string.
// note 2: we could include the first newline in the
// translation string, but that would be weird and cause
// a new string.
std::string new_text = std::string(ds->notes) + '\n' +
format_string_std(translate("gettextFromC", "multiple GPS locations for this dive site; also %s\n"), coords.c_str());
free(ds->notes);
ds->notes = strdup(new_text.c_str());
}
ds->location = location;
}
}
static void parse_dive_location(char *, struct membuffer *str, struct git_parser_state *state)
// Gets the first converted string and consumes it.
// Note: does not remove the string from the vector.
// This is supposed to be used for parsers that expect
// only one string.
static std::string get_first_converted_string(struct git_parser_state *state)
{
char *name = detach_cstring(str);
if (state->converted_strings.empty())
return std::string();
return std::move(state->converted_strings.front());
}
// This is a dummy function that converts the first
// converted string to a newly allocated C-string.
// Will be removed when the core data structures are
// converted to std::string.
static char *get_first_converted_string_c(struct git_parser_state *state)
{
return strdup(get_first_converted_string(state).c_str());
}
static void parse_dive_location(char *, struct git_parser_state *state)
{
std::string name = get_first_converted_string(state);
struct dive_site *ds = get_dive_site_for_dive(state->active_dive);
if (!ds) {
ds = get_dive_site_by_name(name, state->log->sites);
ds = get_dive_site_by_name(name.c_str(), state->log->sites);
if (!ds)
ds = create_dive_site(name, state->log->sites);
ds = create_dive_site(name.c_str(), state->log->sites);
add_dive_to_dive_site(state->active_dive, ds);
} else {
// we already had a dive site linked to the dive
if (empty_string(ds->name)) {
free(ds->name); // empty_string could mean pointer to a 0-byte!
ds->name = strdup(name);
ds->name = strdup(name.c_str());
} else {
// and that dive site had a name. that's weird - if our name is different, add it to the notes
if (!same_string(ds->name, name))
ds->notes = add_to_string(ds->notes, translate("gettextFromC", "additional name for site: %s\n"), name);
if (!same_string(ds->name, name.c_str())) {
std::string new_string = std::string(ds->notes) + '\n' +
format_string_std(translate("gettextFromC", "additional name for site: %s\n"), name.c_str());
ds->notes = strdup(new_string.c_str());
}
}
}
free(name);
}
static void parse_dive_diveguide(char *, struct membuffer *str, struct git_parser_state *state)
{ state->active_dive->diveguide = detach_cstring(str); }
static void parse_dive_diveguide(char *, struct git_parser_state *state)
{ state->active_dive->diveguide = get_first_converted_string_c(state); }
static void parse_dive_buddy(char *, struct membuffer *str, struct git_parser_state *state)
{ state->active_dive->buddy = detach_cstring(str); }
static void parse_dive_buddy(char *, struct git_parser_state *state)
{ state->active_dive->buddy = get_first_converted_string_c(state); }
static void parse_dive_suit(char *, struct membuffer *str, struct git_parser_state *state)
{ state->active_dive->suit = detach_cstring(str); }
static void parse_dive_suit(char *, struct git_parser_state *state)
{ state->active_dive->suit = get_first_converted_string_c(state); }
static void parse_dive_notes(char *, struct membuffer *str, struct git_parser_state *state)
{ state->active_dive->notes = detach_cstring(str); }
static void parse_dive_notes(char *, struct git_parser_state *state)
{ state->active_dive->notes = get_first_converted_string_c(state); }
static void parse_dive_divesiteid(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dive_divesiteid(char *line, struct git_parser_state *state)
{ add_dive_to_dive_site(state->active_dive, get_dive_site_by_uuid(get_hex(line), state->log->sites)); }
/*
* We can have multiple tags in the membuffer. They are separated by
* NUL bytes.
* We can have multiple tags.
*/
static void parse_dive_tags(char *, struct membuffer *str, struct git_parser_state *state)
static void parse_dive_tags(char *, struct git_parser_state *state)
{
const char *tag;
int len = str->len;
if (!len)
return;
/* Make sure there is a NUL at the end too */
tag = mb_cstring(str);
for (;;) {
int taglen = strlen(tag);
if (taglen)
taglist_add_tag(&state->active_dive->tag_list, tag);
len -= taglen;
if (!len)
return;
tag += taglen + 1;
len--;
for (const std::string &tag: state->converted_strings) {
if (!tag.empty())
taglist_add_tag(&state->active_dive->tag_list, tag.c_str());
}
}
static void parse_dive_airtemp(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dive_airtemp(char *line, struct git_parser_state *state)
{ state->active_dive->airtemp = get_temperature(line); }
static void parse_dive_watertemp(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dive_watertemp(char *line, struct git_parser_state *state)
{ state->active_dive->watertemp = get_temperature(line); }
static void parse_dive_airpressure(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dive_airpressure(char *line, struct git_parser_state *state)
{ state->active_dive->surface_pressure = get_airpressure(line); }
static void parse_dive_duration(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dive_duration(char *line, struct git_parser_state *state)
{ state->active_dive->duration = get_duration(line); }
static void parse_dive_rating(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dive_rating(char *line, struct git_parser_state *state)
{ state->active_dive->rating = get_index(line); }
static void parse_dive_visibility(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dive_visibility(char *line, struct git_parser_state *state)
{ state->active_dive->visibility = get_index(line); }
static void parse_dive_wavesize(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dive_wavesize(char *line, struct git_parser_state *state)
{ state->active_dive->wavesize = get_index(line); }
static void parse_dive_current(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dive_current(char *line, struct git_parser_state *state)
{ state->active_dive->current = get_index(line); }
static void parse_dive_surge(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dive_surge(char *line, struct git_parser_state *state)
{ state->active_dive->surge = get_index(line); }
static void parse_dive_chill(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dive_chill(char *line, struct git_parser_state *state)
{ state->active_dive->chill = get_index(line); }
static void parse_dive_watersalinity(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dive_watersalinity(char *line, struct git_parser_state *state)
{ state->active_dive->user_salinity = get_salinity(line); }
static void parse_dive_notrip(char *, struct membuffer *, struct git_parser_state *state)
static void parse_dive_notrip(char *, struct git_parser_state *state)
{
state->active_dive->notrip = true;
}
static void parse_dive_invalid(char *, struct membuffer *, struct git_parser_state *state)
static void parse_dive_invalid(char *, struct git_parser_state *state)
{
state->active_dive->invalid = true;
}
static void parse_site_description(char *, struct membuffer *str, struct git_parser_state *state)
{ state->active_site->description = detach_cstring(str); }
static void parse_site_description(char *, struct git_parser_state *state)
{ state->active_site->description = get_first_converted_string_c(state); }
static void parse_site_name(char *, struct membuffer *str, struct git_parser_state *state)
{ state->active_site->name = detach_cstring(str); }
static void parse_site_name(char *, struct git_parser_state *state)
{ state->active_site->name = get_first_converted_string_c(state); }
static void parse_site_notes(char *, struct membuffer *str, struct git_parser_state *state)
{ state->active_site->notes = detach_cstring(str); }
static void parse_site_notes(char *, struct git_parser_state *state)
{ state->active_site->notes = get_first_converted_string_c(state); }
static void parse_site_gps(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_site_gps(char *line, struct git_parser_state *state)
{
parse_location(line, &state->active_site->location);
}
static void parse_site_geo(char *line, struct membuffer *str, struct git_parser_state *state)
static void parse_site_geo(char *line, struct git_parser_state *state)
{
int origin;
int category;
sscanf(line, "cat %d origin %d \"", &category, &origin);
taxonomy_set_category(&state->active_site->taxonomy, (taxonomy_category)category,
mb_cstring(str), (taxonomy_origin)origin);
get_first_converted_string(state).c_str(), (taxonomy_origin)origin);
}
static std::string remove_from_front(struct membuffer *str, int len)
static std::string pop_cstring(struct git_parser_state *state, const char *err)
{
len = std::min(len, (int)str->len);
std::string prefix(str->buffer, len);
str->len -= len;
memmove(str->buffer, str->buffer+len, str->len);
return prefix;
}
static std::string pop_cstring(struct membuffer *str, const char *err)
{
int len;
if (!str) {
if (state->converted_strings.empty()) {
report_error("git-load: string marker without any strings ('%s')", err);
return std::string();
}
len = strlen(mb_cstring(str)) + 1;
return remove_from_front(str, len);
std::string res = std::move(state->converted_strings.front());
// This copies the whole vector. Keep an index instead!
state->converted_strings.erase(state->converted_strings.begin());
return res;
}
/* Parse key=val parts of samples and cylinders etc */
static char *parse_keyvalue_entry(void (*fn)(void *, const char *, const std::string &), void *fndata, char *line, struct membuffer *str)
static char *parse_keyvalue_entry(void (*fn)(void *, const char *, const std::string &), void *fndata, char *line, struct git_parser_state *state)
{
char *key = line, c;
@ -366,7 +369,7 @@ static char *parse_keyvalue_entry(void (*fn)(void *, const char *, const std::st
}
/* Did we get a string? Take it from the list of strings */
std::string val = start_val[0] == '"' ? pop_cstring(str, key)
std::string val = start_val[0] == '"' ? pop_cstring(state, key)
: std::string(start_val, line - start_val);
if (c)
@ -430,7 +433,7 @@ static void parse_cylinder_keyvalue(void *_cylinder, const char *key, const std:
report_error("Unknown cylinder key/value pair (%s/%s)", key, value.c_str());
}
static void parse_dive_cylinder(char *line, struct membuffer *str, struct git_parser_state *state)
static void parse_dive_cylinder(char *line, struct git_parser_state *state)
{
cylinder_t cylinder = empty_cylinder;
@ -440,7 +443,7 @@ static void parse_dive_cylinder(char *line, struct membuffer *str, struct git_pa
line++;
if (!c)
break;
line = parse_keyvalue_entry(parse_cylinder_keyvalue, &cylinder, line, str);
line = parse_keyvalue_entry(parse_cylinder_keyvalue, &cylinder, line, state);
}
if (cylinder.cylinder_use == OXYGEN)
state->o2pressure_sensor = state->active_dive->cylinders.nr;
@ -462,7 +465,7 @@ static void parse_weightsystem_keyvalue(void *_ws, const char *key, const std::s
report_error("Unknown weightsystem key/value pair (%s/%s)", key, value.c_str());
}
static void parse_dive_weightsystem(char *line, struct membuffer *str, struct git_parser_state *state)
static void parse_dive_weightsystem(char *line, struct git_parser_state *state)
{
weightsystem_t ws = empty_weightsystem;
@ -472,13 +475,13 @@ static void parse_dive_weightsystem(char *line, struct membuffer *str, struct gi
line++;
if (!c)
break;
line = parse_keyvalue_entry(parse_weightsystem_keyvalue, &ws, line, str);
line = parse_keyvalue_entry(parse_weightsystem_keyvalue, &ws, line, state);
}
add_to_weightsystem_table(&state->active_dive->weightsystems, state->active_dive->weightsystems.nr, ws);
}
static int match_action(char *line, struct membuffer *str, void *data,
static int match_action(char *line, void *data,
struct keyword_action *action, unsigned nr_action)
{
char *p = line, c;
@ -506,9 +509,9 @@ static int match_action(char *line, struct membuffer *str, void *data,
struct keyword_action *a = action + mid;
int cmp = strcmp(line, a->keyword);
if (!cmp) { // attribute found:
a->fn(p, str, (git_parser_state *)data); // Execute appropriate function,
return 0; // .. passing 2n word from above
} // (p) as a function argument.
a->fn(p, (git_parser_state *)data); // Execute appropriate function,
return 0; // .. passing 2n word from above
} // (p) as a function argument.
if (cmp < 0)
high = mid;
else
@ -702,7 +705,7 @@ static void sample_parser(char *line, struct git_parser_state *state)
break;
/* Less common sample entries have a name */
if (c >= 'a' && c <= 'z') {
line = parse_keyvalue_entry(parse_sample_keyvalue, sample, line, NULL);
line = parse_keyvalue_entry(parse_sample_keyvalue, sample, line, state);
} else {
const char *end;
double val = ascii_strtod(line, &end);
@ -717,54 +720,54 @@ static void sample_parser(char *line, struct git_parser_state *state)
finish_sample(state->active_dc);
}
static void parse_dc_airtemp(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dc_airtemp(char *line, struct git_parser_state *state)
{ state->active_dc->airtemp = get_temperature(line); }
static void parse_dc_date(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dc_date(char *line, struct git_parser_state *state)
{ update_date(&state->active_dc->when, line); }
static void parse_dc_deviceid(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dc_deviceid(char *line, struct git_parser_state *state)
{
get_hex(line); // legacy
}
static void parse_dc_diveid(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dc_diveid(char *line, struct git_parser_state *state)
{ state->active_dc->diveid = get_hex(line); }
static void parse_dc_duration(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dc_duration(char *line, struct git_parser_state *state)
{ state->active_dc->duration = get_duration(line); }
static void parse_dc_dctype(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dc_dctype(char *line, struct git_parser_state *state)
{ state->active_dc->divemode = get_dctype(line); }
static void parse_dc_lastmanualtime(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dc_lastmanualtime(char *line, struct git_parser_state *state)
{ state->active_dc->last_manual_time = get_duration(line); }
static void parse_dc_maxdepth(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dc_maxdepth(char *line, struct git_parser_state *state)
{ state->active_dc->maxdepth = get_depth(line); }
static void parse_dc_meandepth(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dc_meandepth(char *line, struct git_parser_state *state)
{ state->active_dc->meandepth = get_depth(line); }
static void parse_dc_model(char *, struct membuffer *str, struct git_parser_state *state)
{ state->active_dc->model = detach_cstring(str); }
static void parse_dc_model(char *, struct git_parser_state *state)
{ state->active_dc->model = get_first_converted_string_c(state); }
static void parse_dc_numberofoxygensensors(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dc_numberofoxygensensors(char *line, struct git_parser_state *state)
{ state->active_dc->no_o2sensors = get_index(line); }
static void parse_dc_surfacepressure(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dc_surfacepressure(char *line, struct git_parser_state *state)
{ state->active_dc->surface_pressure = get_pressure(line); }
static void parse_dc_salinity(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dc_salinity(char *line, struct git_parser_state *state)
{ state->active_dc->salinity = get_salinity(line); }
static void parse_dc_surfacetime(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dc_surfacetime(char *line, struct git_parser_state *state)
{ state->active_dc->surfacetime = get_duration(line); }
static void parse_dc_time(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dc_time(char *line, struct git_parser_state *state)
{ update_time(&state->active_dc->when, line); }
static void parse_dc_watertemp(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_dc_watertemp(char *line, struct git_parser_state *state)
{ state->active_dc->watertemp = get_temperature(line); }
@ -818,31 +821,17 @@ static void parse_event_keyvalue(void *_parse, const char *key, const std::strin
}
/* keyvalue "key" "value"
* so we have two strings (possibly empty) in the membuffer, separated by a '\0' */
static void parse_dc_keyvalue(char *line, struct membuffer *str, struct git_parser_state *state)
* so we have two strings (possibly empty) */
static void parse_dc_keyvalue(char *line, struct git_parser_state *state)
{
const char *key, *value;
// Let's make sure we have two strings...
int string_counter = 0;
while(*line) {
if (*line == '"')
string_counter++;
line++;
}
if (string_counter != 2)
if (state->converted_strings.size() != 2)
return;
// stupidly the second string in the membuffer isn't NUL terminated;
// asking for a cstring fixes that; interestingly enough, given that there are two
// strings in the mb, the next command at the same time assigns a pointer to the
// first string to 'key' and NUL terminates the second string (which then goes to 'value')
key = mb_cstring(str);
value = key + strlen(key) + 1;
add_extra_data(state->active_dc, key, value);
add_extra_data(state->active_dc, state->converted_strings[0].c_str(), state->converted_strings[1].c_str());
}
static void parse_dc_event(char *line, struct membuffer *str, struct git_parser_state *state)
static void parse_dc_event(char *line, struct git_parser_state *state)
{
int m, s = 0;
struct parse_event p;
@ -859,7 +848,7 @@ static void parse_dc_event(char *line, struct membuffer *str, struct git_parser_
line++;
if (!c)
break;
line = parse_keyvalue_entry(parse_event_keyvalue, &p, line, str);
line = parse_keyvalue_entry(parse_event_keyvalue, &p, line, state);
}
/* Only modechange events should have a divemode - fix up any corrupted names */
@ -889,38 +878,38 @@ static void parse_dc_event(char *line, struct membuffer *str, struct git_parser_
}
/* Not needed anymore - trip date calculated implicitly from first dive */
static void parse_trip_date(char *, struct membuffer *, struct git_parser_state *)
static void parse_trip_date(char *, struct git_parser_state *)
{ }
/* Not needed anymore - trip date calculated implicitly from first dive */
static void parse_trip_time(char *, struct membuffer *, struct git_parser_state *)
static void parse_trip_time(char *, struct git_parser_state *)
{ }
static void parse_trip_location(char *, struct membuffer *str, struct git_parser_state *state)
{ state->active_trip->location = detach_cstring(str); }
static void parse_trip_location(char *, struct git_parser_state *state)
{ state->active_trip->location = get_first_converted_string_c(state); }
static void parse_trip_notes(char *, struct membuffer *str, struct git_parser_state *state)
{ state->active_trip->notes = detach_cstring(str); }
static void parse_trip_notes(char *, struct git_parser_state *state)
{ state->active_trip->notes = get_first_converted_string_c(state); }
static void parse_settings_autogroup(char *, struct membuffer *, struct git_parser_state *state)
static void parse_settings_autogroup(char *, struct git_parser_state *state)
{
state->log->autogroup = true;
}
static void parse_settings_units(char *line, struct membuffer *, struct git_parser_state *)
static void parse_settings_units(char *line, struct git_parser_state *)
{
if (line)
set_informational_units(line);
}
static void parse_settings_userid(char *, struct membuffer *, struct git_parser_state *)
static void parse_settings_userid(char *, struct git_parser_state *)
/* Keep this despite removal of the webservice as there are legacy logbook around
* that still have this defined.
*/
{
}
static void parse_settings_prefs(char *line, struct membuffer *, struct git_parser_state *)
static void parse_settings_prefs(char *line, struct git_parser_state *)
{
if (line)
set_git_prefs(line);
@ -933,7 +922,7 @@ static void parse_settings_prefs(char *line, struct membuffer *, struct git_pars
* We MUST keep this in sync with the XML version (so we can report a consistent
* minimum datafile version)
*/
static void parse_settings_version(char *line, struct membuffer *, struct git_parser_state *)
static void parse_settings_version(char *line, struct git_parser_state *)
{
int version = atoi(line);
report_datafile_version(version);
@ -941,8 +930,8 @@ static void parse_settings_version(char *line, struct membuffer *, struct git_pa
report_error("Git save file version %d is newer than version %d I know about", version, DATAFORMAT_VERSION);
}
/* The string in the membuffer is the version string of subsurface that saved things, just FYI */
static void parse_settings_subsurface(char *, struct membuffer *, struct git_parser_state *)
/* The argument string is the version string of subsurface that saved things, just FYI */
static void parse_settings_subsurface(char *, struct git_parser_state *)
{
}
@ -981,10 +970,10 @@ static void parse_divecomputerid_keyvalue(void *_cid, const char *key, const std
* it can have multiple strings (but see the tag parsing for another example of
* that) in addition to the non-string entries.
*/
static void parse_settings_divecomputerid(char *line, struct membuffer *str, struct git_parser_state *state)
static void parse_settings_divecomputerid(char *line, struct git_parser_state *state)
{
struct divecomputerid id;
id.model = pop_cstring(str, line);
id.model = pop_cstring(state, line);
/* Skip the '"' that stood for the model string */
line++;
@ -996,7 +985,7 @@ static void parse_settings_divecomputerid(char *line, struct membuffer *str, str
line++;
if (!c)
break;
line = parse_keyvalue_entry(parse_divecomputerid_keyvalue, &id, line, str);
line = parse_keyvalue_entry(parse_divecomputerid_keyvalue, &id, line, state);
}
create_device_node(state->log->devices, id.model.c_str(), id.serial.c_str(), id.nickname.c_str());
}
@ -1037,7 +1026,7 @@ static void parse_fingerprint_keyvalue(void *_fph, const char *key, const std::s
}
static void parse_settings_fingerprint(char *line, struct membuffer *str, struct git_parser_state *state)
static void parse_settings_fingerprint(char *line, struct git_parser_state *state)
{
struct fingerprint_helper fph;
for (;;) {
@ -1046,7 +1035,7 @@ static void parse_settings_fingerprint(char *line, struct membuffer *str, struct
line++;
if (!c)
break;
line = parse_keyvalue_entry(parse_fingerprint_keyvalue, &fph, line, str);
line = parse_keyvalue_entry(parse_fingerprint_keyvalue, &fph, line, state);
}
if (verbose > 1)
SSRF_INFO("fingerprint %08x %08x %08x %08x %s\n", fph.model, fph.serial, fph.fdeviceid, fph.fdiveid, fph.hex_data.c_str());
@ -1054,17 +1043,17 @@ static void parse_settings_fingerprint(char *line, struct membuffer *str, struct
fph.hex_data.c_str(), fph.fdeviceid, fph.fdiveid);
}
static void parse_picture_filename(char *, struct membuffer *str, struct git_parser_state *state)
static void parse_picture_filename(char *, struct git_parser_state *state)
{
state->active_pic.filename = detach_cstring(str);
state->active_pic.filename = get_first_converted_string_c(state);
}
static void parse_picture_gps(char *line, struct membuffer *, struct git_parser_state *state)
static void parse_picture_gps(char *line, struct git_parser_state *state)
{
parse_location(line, &state->active_pic.location);
}
static void parse_picture_hash(char *, struct membuffer *, struct git_parser_state *)
static void parse_picture_hash(char *, struct git_parser_state *)
{
// we no longer use hashes to identify pictures, but we shouldn't
// remove this parser lest users get an ugly red warning when
@ -1081,12 +1070,12 @@ struct keyword_action dc_action[] = {
};
/* Sample lines start with a space or a number */
static void divecomputer_parser(char *line, struct membuffer *str, struct git_parser_state *state)
static void divecomputer_parser(char *line, struct git_parser_state *state)
{
char c = *line;
if (c < 'a' || c > 'z')
sample_parser(line, state);
match_action(line, str, state, dc_action, ARRAY_SIZE(dc_action));
match_action(line, state, dc_action, ARRAY_SIZE(dc_action));
}
/* These need to be sorted! */
@ -1099,9 +1088,9 @@ struct keyword_action dive_action[] = {
D(tags), D(visibility), D(watersalinity), D(watertemp), D(wavesize), D(weightsystem)
};
static void dive_parser(char *line, struct membuffer *str, struct git_parser_state *state)
static void dive_parser(char *line, struct git_parser_state *state)
{
match_action(line, str, state, dive_action, ARRAY_SIZE(dive_action));
match_action(line, state, dive_action, ARRAY_SIZE(dive_action));
}
/* These need to be sorted! */
@ -1111,9 +1100,9 @@ struct keyword_action site_action[] = {
D(description), D(geo), D(gps), D(name), D(notes)
};
static void site_parser(char *line, struct membuffer *str, struct git_parser_state *state)
static void site_parser(char *line, struct git_parser_state *state)
{
match_action(line, str, state, site_action, ARRAY_SIZE(site_action));
match_action(line, state, site_action, ARRAY_SIZE(site_action));
}
/* These need to be sorted! */
@ -1123,9 +1112,9 @@ struct keyword_action trip_action[] = {
D(date), D(location), D(notes), D(time),
};
static void trip_parser(char *line, struct membuffer *str, struct git_parser_state *state)
static void trip_parser(char *line, struct git_parser_state *state)
{
match_action(line, str, state, trip_action, ARRAY_SIZE(trip_action));
match_action(line, state, trip_action, ARRAY_SIZE(trip_action));
}
/* These need to be sorted! */
@ -1135,9 +1124,9 @@ static struct keyword_action settings_action[] = {
D(autogroup), D(divecomputerid), D(fingerprint), D(prefs), D(subsurface), D(units), D(userid), D(version)
};
static void settings_parser(char *line, struct membuffer *str, struct git_parser_state *state)
static void settings_parser(char *line, struct git_parser_state *state)
{
match_action(line, str, state, settings_action, ARRAY_SIZE(settings_action));
match_action(line, state, settings_action, ARRAY_SIZE(settings_action));
}
/* These need to be sorted! */
@ -1147,9 +1136,9 @@ static struct keyword_action picture_action[] = {
D(filename), D(gps), D(hash)
};
static void picture_parser(char *line, struct membuffer *str, struct git_parser_state *state)
static void picture_parser(char *line, struct git_parser_state *state)
{
match_action(line, str, state, picture_action, ARRAY_SIZE(picture_action));
match_action(line, state, picture_action, ARRAY_SIZE(picture_action));
}
static void parse_filter_preset_constraint_keyvalue(void *_state, const char *key, const std::string &value)
@ -1179,7 +1168,7 @@ static void parse_filter_preset_constraint_keyvalue(void *_state, const char *ke
report_error("Unknown filter preset constraint key/value pair (%s/%s)", key, value.c_str());
}
static void parse_filter_preset_constraint(char *line, struct membuffer *str, struct git_parser_state *state)
static void parse_filter_preset_constraint(char *line, struct git_parser_state *state)
{
for (;;) {
char c;
@ -1187,7 +1176,7 @@ static void parse_filter_preset_constraint(char *line, struct membuffer *str, st
line++;
if (!c)
break;
line = parse_keyvalue_entry(parse_filter_preset_constraint_keyvalue, state, line, str);
line = parse_keyvalue_entry(parse_filter_preset_constraint_keyvalue, state, line, state);
}
filter_preset_add_constraint(state->active_filter.get(), state->filter_constraint_type.c_str(),
@ -1216,7 +1205,7 @@ static void parse_filter_preset_fulltext_keyvalue(void *_state, const char *key,
report_error("Unknown filter preset fulltext key/value pair (%s/%s)", key, value.c_str());
}
static void parse_filter_preset_fulltext(char *line, struct membuffer *str, struct git_parser_state *state)
static void parse_filter_preset_fulltext(char *line, struct git_parser_state *state)
{
for (;;) {
char c;
@ -1224,7 +1213,7 @@ static void parse_filter_preset_fulltext(char *line, struct membuffer *str, stru
line++;
if (!c)
break;
line = parse_keyvalue_entry(parse_filter_preset_fulltext_keyvalue, state, line, str);
line = parse_keyvalue_entry(parse_filter_preset_fulltext_keyvalue, state, line, state);
}
filter_preset_set_fulltext(state->active_filter.get(), state->fulltext_query.c_str(), state->fulltext_mode.c_str());
@ -1232,9 +1221,9 @@ static void parse_filter_preset_fulltext(char *line, struct membuffer *str, stru
state->fulltext_query.clear();
}
static void parse_filter_preset_name(char *, struct membuffer *str, struct git_parser_state *state)
static void parse_filter_preset_name(char *, struct git_parser_state *state)
{
filter_preset_set_name(state->active_filter.get(), detach_cstring(str));
filter_preset_set_name(state->active_filter.get(), get_first_converted_string_c(state));
}
/* These need to be sorted! */
@ -1244,9 +1233,9 @@ struct keyword_action filter_preset_action[] = {
D(constraint), D(fulltext), D(name)
};
static void filter_preset_parser(char *line, struct membuffer *str, struct git_parser_state *state)
static void filter_preset_parser(char *line, struct git_parser_state *state)
{
match_action(line, str, state, filter_preset_action, ARRAY_SIZE(filter_preset_action));
match_action(line, state, filter_preset_action, ARRAY_SIZE(filter_preset_action));
}
/*
@ -1279,21 +1268,18 @@ static void filter_preset_parser(char *line, struct membuffer *str, struct git_p
* - each string will be represented as a single '"'
* character in the output.
*
* - all string will exist in the same 'membuffer',
* separated by NUL characters (that cannot exist
* in a string, not even quoted).
* - all string will be stores in converted_strings.
*/
static const char *parse_one_string(const char *buf, const char *end, struct membuffer *b)
static const char *parse_one_string(const char *buf, const char *end, std::vector<std::string> &converted_strings)
{
const char *p = buf;
/*
* We turn multiple strings one one line (think dive tags) into one
* membuffer that has NUL characters in between strings.
* We turn multiple strings one one line (think dive tags) into the
* converted_strings vector.
*/
if (b->len)
put_bytes(b, "", 1);
std::string s;
while (p < end) {
char replace;
@ -1316,18 +1302,19 @@ static const char *parse_one_string(const char *buf, const char *end, struct mem
replace = 0;
break;
}
put_bytes(b, buf, p - buf - 1);
s.append(buf, p - buf - 1);
if (!replace)
break;
put_bytes(b, &replace, 1);
s += replace;
buf = ++p;
}
converted_strings.push_back(std::move(s));
return p;
}
typedef void (line_fn_t)(char *, struct membuffer *, struct git_parser_state *);
typedef void (line_fn_t)(char *, struct git_parser_state *);
#define MAXLINE 500
static unsigned parse_one_line(const char *buf, unsigned size, line_fn_t *fn, struct git_parser_state *state, struct membuffer *b)
static unsigned parse_one_line(const char *buf, unsigned size, line_fn_t *fn, struct git_parser_state *state)
{
const char *end = buf + size;
const char *p = buf;
@ -1359,31 +1346,28 @@ static unsigned parse_one_line(const char *buf, unsigned size, line_fn_t *fn, st
if (off > MAXLINE)
off = MAXLINE;
if (c == '"')
p = parse_one_string(p, end, b);
p = parse_one_string(p, end, state->converted_strings);
}
line[off] = 0;
fn(line, b, state);
fn(line, state);
return p - buf;
}
/*
* We keep on re-using the membuffer that we use for
* strings, but the callback function can "steal" it by
* saving its value and just clear the original.
* We keep on re-using the vector that stores converted
* strings, but the callback function can consume the
* strings.
*/
static void for_each_line(git_blob *blob, line_fn_t *fn, struct git_parser_state *state)
{
const char *content = (const char *)git_blob_rawcontent(blob);
unsigned int size = git_blob_rawsize(blob);
struct membufferpp str;
while (size) {
unsigned int n = parse_one_line(content, size, fn, state, &str);
state->converted_strings.clear();
unsigned int n = parse_one_line(content, size, fn, state);
content += n;
size -= n;
/* Re-use the allocation, but forget the data */
str.len = 0;
}
}
@ -1926,7 +1910,7 @@ std::string get_sha(git_repository *repo, const char *branch)
extern "C" int git_load_dives(struct git_info *info, struct divelog *log)
{
int ret;
struct git_parser_state state ;
struct git_parser_state state;
state.repo = info->repo;
state.log = log;