Next improvement of the nickname code

Now it is able to replace nicknames for existing entries (which will be
needed by the yet to be written UI).

This commit fixes a couple issues with the previous code:
- a potential SIGSEGV with malformed config entries
- missing closing parenthesis in the dialog box text

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
Dirk Hohndel 2012-12-22 21:37:13 -08:00
parent 267476e3fe
commit 06cd494a2f

View file

@ -1226,7 +1226,7 @@ void init_ui(int *argcp, char ***argvp)
len = strlen(namestart + 1); len = strlen(namestart + 1);
nameend = g_utf8_strchr(namestart + 1, len, ','); nameend = g_utf8_strchr(namestart + 1, len, ',');
tupleend = g_utf8_strchr(namestart + 1, len, '}'); tupleend = g_utf8_strchr(namestart + 1, len, '}');
if (!nameend && !tupleend) if (!tupleend)
/* the config entry is messed up - bail */ /* the config entry is messed up - bail */
break; break;
if (!nameend || tupleend < nameend) if (!nameend || tupleend < nameend)
@ -2063,16 +2063,16 @@ const char *get_dc_nickname(uint32_t deviceid)
} }
/* do we have a DIFFERENT divecomputer of the same model? */ /* do we have a DIFFERENT divecomputer of the same model? */
static gboolean dc_model_exists(struct divecomputer *dc) static struct dcnicknamelist *get_dc_nicknameentry(const char *model, int deviceid)
{ {
struct dcnicknamelist *known = nicknamelist; struct dcnicknamelist *known = nicknamelist;
while (known) { while (known) {
if (known->model && dc->model && !strcmp(known->model, dc->model) && if (known->model && model && !strcmp(known->model, model) &&
known->deviceid != dc->deviceid) known->deviceid != deviceid)
return TRUE; return known;
known = known->next; known = known->next;
} }
return FALSE; return NULL;
} }
/* no curly braces or commas, please */ /* no curly braces or commas, please */
@ -2102,6 +2102,50 @@ static char *cleanedup_nickname(const char *nickname, int len)
return clean; return clean;
} }
void replace_nickname_nicknamestring(int deviceid, const char *nickname)
{
char buf[11];
char *entry, *comma1, *comma2, *brace, *new_nn;
int len;
snprintf(buf, sizeof(buf), "{%08x,", deviceid);
entry = strstr(nicknamestring, buf);
if (!entry)
/* this cannot happen as we know have an entry for this deviceid */
goto bail;
len = strlen(entry);
comma1 = g_utf8_strchr(entry, len, ',');
if (!comma1)
goto bail;
len = strlen(comma1);
comma2 = g_utf8_strchr(comma1, len, ',');
brace = g_utf8_strchr(comma1, len, '}');
if (!brace)
goto bail;
if (!comma2 || brace < comma2) {
/* didn't have a nickname, so add one */
len = strlen(nicknamestring) + strlen(nickname) + 2;
*brace = '\0';
} else {
/* replace the nickname */
len = strlen(nicknamestring) + strlen(nickname) - (brace - comma2) + 1;
*comma2 = '\0';
}
new_nn = malloc(len);
if (strlen(nickname))
snprintf(new_nn, len, "%s,%s}%s", entry, nickname, brace + 1);
else
snprintf(new_nn, len, "%s}%s", entry, brace + 1);
free(nicknamestring);
nicknamestring = new_nn;
return;
bail:
printf("invalid nicknamestring %s (while looking at deviceid %08x\n", nicknamestring, deviceid);
return;
}
void remember_dc(uint32_t deviceid, const char *model, const char *nickname, gboolean change_conf) void remember_dc(uint32_t deviceid, const char *model, const char *nickname, gboolean change_conf)
{ {
if (!get_dc_nickname(deviceid)) { if (!get_dc_nickname(deviceid)) {
@ -2122,6 +2166,13 @@ void remember_dc(uint32_t deviceid, const char *model, const char *nickname, gbo
strcat(nicknamestring, buffer); strcat(nicknamestring, buffer);
if (change_conf) if (change_conf)
subsurface_set_conf("dc_nicknames", PREF_STRING, nicknamestring); subsurface_set_conf("dc_nicknames", PREF_STRING, nicknamestring);
} else {
/* modify existing entry */
struct dcnicknamelist *nn_entry = get_dc_nicknameentry(model, deviceid);
if (!nn_entry->model || !*nn_entry->model)
nn_entry->model = model;
nn_entry->nickname = nickname;
replace_nickname_nicknamestring(deviceid, nickname);
} }
#if defined(NICKNAME_DEBUG) #if defined(NICKNAME_DEBUG)
struct dcnicknamelist *nn_entry = nicknamelist; struct dcnicknamelist *nn_entry = nicknamelist;
@ -2150,7 +2201,8 @@ void set_dc_nickname(struct dive *dive)
fprintf(debugfile, "set_dc_nickname for model %s deviceid %8x\n", dc->model ? : "", dc->deviceid); fprintf(debugfile, "set_dc_nickname for model %s deviceid %8x\n", dc->model ? : "", dc->deviceid);
#endif #endif
if (get_dc_nickname(dc->deviceid) == NULL) { if (get_dc_nickname(dc->deviceid) == NULL) {
if (!dc_model_exists(dc)) { struct dcnicknamelist *nn_entry = get_dc_nicknameentry(dc->model, dc->deviceid);
if (!nn_entry) {
/* just remember the dive computer without setting a nickname */ /* just remember the dive computer without setting a nickname */
if (dc->model) if (dc->model)
remember_dc(dc->deviceid, dc->model, "", TRUE); remember_dc(dc->deviceid, dc->model, "", TRUE);
@ -2164,15 +2216,17 @@ void set_dc_nickname(struct dive *dive)
NULL); NULL);
vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
snprintf(dialogtext, sizeof(dialogtext), snprintf(dialogtext, sizeof(dialogtext),
_("You already have a dive computer of model %s\n" _("You already have a dive computer of this model\n"
"named %s\n"
"Subsurface can maintain a nickname for this device to " "Subsurface can maintain a nickname for this device to "
"distinguish it from the existing one. " "distinguish it from the existing one. "
"The default is the model and device ID as shown below.\n" "The default is the model and device ID as shown below.\n"
"If you don't want to name this dive computer click " "If you don't want to name this dive computer click "
"'Cancel' and Subsurface will simply display its model " "'Cancel' and Subsurface will simply display its model "
"as its name (which may mean that you cannot tell the two " "as its name (which may mean that you cannot tell the two "
"dive computers apart in the logs."), "dive computers apart in the logs)."),
dc->model ? dc->model : "(unset)"); nn_entry->nickname && *nn_entry->nickname ? nn_entry->nickname :
(nn_entry->model && *nn_entry->model ? nn_entry->model : _("(nothing)")));
label = gtk_label_new(dialogtext); label = gtk_label_new(dialogtext);
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 3); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 3);