summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2022-11-29 20:12:46 +0000
committerAidan MacDonald <amachronic@protonmail.com>2022-12-01 13:07:24 -0500
commit5b1dd64f5090ebf7c3f05ce630efbc7066acdc33 (patch)
tree1cf31e13f184f69146578378caf1f294b794d141
parentafa58ef2775dea3f3f16e3d74e01ed7cf869d3c4 (diff)
downloadrockbox-5b1dd64f50.tar.gz
rockbox-5b1dd64f50.zip
settings: Add helper function for handling filename settings
The old inline implementation was buggy -- it didn't check the suffix was actually at the end of the string before stripping it, and didn't check for truncation. This version also avoids using an extra buffer. Change-Id: I33abfefc508675d3079cc64a9ad2b11d646baa0d
-rw-r--r--apps/settings.c72
-rw-r--r--apps/settings.h3
2 files changed, 52 insertions, 23 deletions
diff --git a/apps/settings.c b/apps/settings.c
index 3d2c463cdd..cd93dcfb4b 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -262,6 +262,52 @@ bool cfg_string_to_int(int setting_id, int* out, const char* str)
return false;
}
+/**
+ * Copy an input string to an output buffer, stripping the prefix and
+ * suffix listed in the filename setting. Returns false if the output
+ * string does not fit in the buffer or is longer than the setting's
+ * max_len, and the output buffer will not be modified.
+ *
+ * Returns true if the setting was copied successfully. The input and
+ * output buffers are allowed to alias.
+ */
+bool copy_filename_setting(char *buf, size_t buflen, const char *input,
+ const struct filename_setting *fs)
+{
+ size_t input_len = strlen(input);
+ size_t len;
+
+ if (fs->prefix)
+ {
+ len = strlen(fs->prefix);
+ if (len <= input_len && !strncasecmp(input, fs->prefix, len))
+ {
+ input += len;
+ input_len -= len;
+ }
+ }
+
+ if (fs->suffix)
+ {
+ len = strlen(fs->suffix);
+ if (len <= input_len &&
+ !strcasecmp(input + input_len - len, fs->suffix))
+ {
+ input_len -= len;
+ }
+ }
+
+ /* Make sure it fits the output buffer and repsects the setting's max_len.
+ * Note that max_len is a buffer size and thus includes a null terminator */
+ if (input_len >= (size_t)fs->max_len || input_len >= buflen)
+ return false;
+
+ /* Copy what remains into buf - use memmove in case of aliasing */
+ memmove(buf, input, input_len);
+ buf[input_len] = '\0';
+ return true;
+}
+
bool settings_load_config(const char* file, bool apply)
{
int fd;
@@ -335,29 +381,9 @@ bool settings_load_config(const char* file, bool apply)
case F_T_CHARPTR:
case F_T_UCHARPTR:
{
- char storage[MAX_PATH];
- if (settings[i].filename_setting->prefix)
- {
- const char *dir = settings[i].filename_setting->prefix;
- size_t len = strlen(dir);
- if (!strncasecmp(value, dir, len))
- {
- strmemccpy(storage, &value[len], MAX_PATH);
- }
- else
- strmemccpy(storage, value, MAX_PATH);
-
- }
- else
- strmemccpy(storage, value, MAX_PATH);
-
- if (settings[i].filename_setting->suffix)
- {
- char *s = strcasestr(storage,settings[i].filename_setting->suffix);
- if (s) *s = '\0';
- }
- strmemccpy((char*)settings[i].setting, storage,
- settings[i].filename_setting->max_len);
+ const struct filename_setting *fs = settings[i].filename_setting;
+ copy_filename_setting((char*)settings[i].setting,
+ fs->max_len, value, fs);
break;
}
}
diff --git a/apps/settings.h b/apps/settings.h
index 37e546f6fc..9c5bf0470f 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -247,6 +247,7 @@ enum {
bool settings_save_config(int options);
struct settings_list;
+struct filename_setting;
void reset_setting(const struct settings_list *setting, void *var);
void settings_reset(void);
void sound_settings_apply(void);
@@ -267,6 +268,8 @@ const struct settings_list* find_setting_by_cfgname(const char* name, int *id);
bool cfg_int_to_string(int setting_id, int val, char* buf, int buf_len);
bool cfg_string_to_int(int setting_id, int* out, const char* str);
bool cfg_to_string(int setting_id, char* buf, int buf_len);
+bool copy_filename_setting(char *buf, size_t buflen, const char *input,
+ const struct filename_setting *fs);
bool set_bool_options(const char* string, const bool* variable,
const char* yes_str, int yes_voice,
const char* no_str, int no_voice,