|
|
@@ -18,6 +18,7 @@
|
|
|
#include <stdio.h>
|
|
|
#include <wchar.h>
|
|
|
#include "config-file.h"
|
|
|
+#include "threading.h"
|
|
|
#include "platform.h"
|
|
|
#include "base.h"
|
|
|
#include "bmem.h"
|
|
|
@@ -57,8 +58,19 @@ struct config_data {
|
|
|
char *file;
|
|
|
struct darray sections; /* struct config_section */
|
|
|
struct darray defaults; /* struct config_section */
|
|
|
+ pthread_mutex_t mutex;
|
|
|
};
|
|
|
|
|
|
+static inline bool init_mutex(config_t *config)
|
|
|
+{
|
|
|
+ pthread_mutexattr_t attr;
|
|
|
+ if (pthread_mutexattr_init(&attr) != 0)
|
|
|
+ return false;
|
|
|
+ if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0)
|
|
|
+ return false;
|
|
|
+ return pthread_mutex_init(&config->mutex, &attr) == 0;
|
|
|
+}
|
|
|
+
|
|
|
config_t *config_create(const char *file)
|
|
|
{
|
|
|
struct config_data *config;
|
|
|
@@ -70,6 +82,12 @@ config_t *config_create(const char *file)
|
|
|
fclose(f);
|
|
|
|
|
|
config = bzalloc(sizeof(struct config_data));
|
|
|
+
|
|
|
+ if (!init_mutex(config)) {
|
|
|
+ bfree(config);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
config->file = bstrdup(file);
|
|
|
return config;
|
|
|
}
|
|
|
@@ -278,6 +296,11 @@ int config_open(config_t **config, const char *file,
|
|
|
if (!*config)
|
|
|
return CONFIG_ERROR;
|
|
|
|
|
|
+ if (!init_mutex(*config)) {
|
|
|
+ bfree(*config);
|
|
|
+ return CONFIG_ERROR;
|
|
|
+ }
|
|
|
+
|
|
|
(*config)->file = bstrdup(file);
|
|
|
|
|
|
errorcode = config_parse_file(&(*config)->sections, file, always_open);
|
|
|
@@ -301,6 +324,11 @@ int config_open_string(config_t **config, const char *str)
|
|
|
if (!*config)
|
|
|
return CONFIG_ERROR;
|
|
|
|
|
|
+ if (!init_mutex(*config)) {
|
|
|
+ bfree(*config);
|
|
|
+ return CONFIG_ERROR;
|
|
|
+ }
|
|
|
+
|
|
|
(*config)->file = NULL;
|
|
|
|
|
|
lexer_init(&lex);
|
|
|
@@ -333,9 +361,13 @@ int config_save(config_t *config)
|
|
|
dstr_init(&str);
|
|
|
dstr_init(&tmp);
|
|
|
|
|
|
+ pthread_mutex_lock(&config->mutex);
|
|
|
+
|
|
|
f = os_fopen(config->file, "wb");
|
|
|
- if (!f)
|
|
|
+ if (!f) {
|
|
|
+ pthread_mutex_unlock(&config->mutex);
|
|
|
return CONFIG_FILENOTFOUND;
|
|
|
+ }
|
|
|
|
|
|
for (i = 0; i < config->sections.num; i++) {
|
|
|
struct config_section *section = darray_item(
|
|
|
@@ -371,6 +403,8 @@ int config_save(config_t *config)
|
|
|
fwrite(str.array, 1, str.len, f);
|
|
|
fclose(f);
|
|
|
|
|
|
+ pthread_mutex_unlock(&config->mutex);
|
|
|
+
|
|
|
dstr_free(&tmp);
|
|
|
dstr_free(&str);
|
|
|
|
|
|
@@ -391,6 +425,8 @@ int config_save_safe(config_t *config, const char *temp_ext,
|
|
|
return CONFIG_ERROR;
|
|
|
}
|
|
|
|
|
|
+ pthread_mutex_lock(&config->mutex);
|
|
|
+
|
|
|
dstr_copy(&temp_file, config->file);
|
|
|
if (*temp_ext != '.')
|
|
|
dstr_cat(&temp_file, ".");
|
|
|
@@ -419,6 +455,7 @@ int config_save_safe(config_t *config, const char *temp_ext,
|
|
|
os_rename(temp_file.array, file);
|
|
|
|
|
|
cleanup:
|
|
|
+ pthread_mutex_unlock(&config->mutex);
|
|
|
dstr_free(&temp_file);
|
|
|
dstr_free(&backup_file);
|
|
|
return ret;
|
|
|
@@ -442,6 +479,7 @@ void config_close(config_t *config)
|
|
|
darray_free(&config->defaults);
|
|
|
darray_free(&config->sections);
|
|
|
bfree(config->file);
|
|
|
+ pthread_mutex_destroy(&config->mutex);
|
|
|
bfree(config);
|
|
|
}
|
|
|
|
|
|
@@ -453,14 +491,20 @@ size_t config_num_sections(config_t *config)
|
|
|
const char *config_get_section(config_t *config, size_t idx)
|
|
|
{
|
|
|
struct config_section *section;
|
|
|
+ const char *name = NULL;
|
|
|
+
|
|
|
+ pthread_mutex_lock(&config->mutex);
|
|
|
|
|
|
if (idx >= config->sections.num)
|
|
|
- return NULL;
|
|
|
+ goto unlock;
|
|
|
|
|
|
section = darray_item(sizeof(struct config_section), &config->sections,
|
|
|
idx);
|
|
|
+ name = section->name;
|
|
|
|
|
|
- return section->name;
|
|
|
+unlock:
|
|
|
+ pthread_mutex_unlock(&config->mutex);
|
|
|
+ return name;
|
|
|
}
|
|
|
|
|
|
static const struct config_item *config_find_item(const struct darray *sections,
|
|
|
@@ -487,14 +531,16 @@ static const struct config_item *config_find_item(const struct darray *sections,
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
-static void config_set_item(struct darray *sections, const char *section,
|
|
|
- const char *name, char *value)
|
|
|
+static void config_set_item(config_t *config, struct darray *sections,
|
|
|
+ const char *section, const char *name, char *value)
|
|
|
{
|
|
|
struct config_section *sec = NULL;
|
|
|
struct config_section *array = sections->array;
|
|
|
struct config_item *item;
|
|
|
size_t i, j;
|
|
|
|
|
|
+ pthread_mutex_lock(&config->mutex);
|
|
|
+
|
|
|
for (i = 0; i < sections->num; i++) {
|
|
|
struct config_section *cur_sec = array+i;
|
|
|
struct config_item *items = cur_sec->items.array;
|
|
|
@@ -506,7 +552,7 @@ static void config_set_item(struct darray *sections, const char *section,
|
|
|
if (astrcmpi(item->name, name) == 0) {
|
|
|
bfree(item->value);
|
|
|
item->value = value;
|
|
|
- return;
|
|
|
+ goto unlock;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -524,6 +570,9 @@ static void config_set_item(struct darray *sections, const char *section,
|
|
|
item = darray_push_back_new(sizeof(struct config_item), &sec->items);
|
|
|
item->name = bstrdup(name);
|
|
|
item->value = value;
|
|
|
+
|
|
|
+unlock:
|
|
|
+ pthread_mutex_unlock(&config->mutex);
|
|
|
}
|
|
|
|
|
|
void config_set_string(config_t *config, const char *section,
|
|
|
@@ -531,7 +580,8 @@ void config_set_string(config_t *config, const char *section,
|
|
|
{
|
|
|
if (!value)
|
|
|
value = "";
|
|
|
- config_set_item(&config->sections, section, name, bstrdup(value));
|
|
|
+ config_set_item(config, &config->sections, section, name,
|
|
|
+ bstrdup(value));
|
|
|
}
|
|
|
|
|
|
void config_set_int(config_t *config, const char *section,
|
|
|
@@ -540,7 +590,7 @@ void config_set_int(config_t *config, const char *section,
|
|
|
struct dstr str;
|
|
|
dstr_init(&str);
|
|
|
dstr_printf(&str, "%"PRId64, value);
|
|
|
- config_set_item(&config->sections, section, name, str.array);
|
|
|
+ config_set_item(config, &config->sections, section, name, str.array);
|
|
|
}
|
|
|
|
|
|
void config_set_uint(config_t *config, const char *section,
|
|
|
@@ -549,14 +599,14 @@ void config_set_uint(config_t *config, const char *section,
|
|
|
struct dstr str;
|
|
|
dstr_init(&str);
|
|
|
dstr_printf(&str, "%"PRIu64, value);
|
|
|
- config_set_item(&config->sections, section, name, str.array);
|
|
|
+ config_set_item(config, &config->sections, section, name, str.array);
|
|
|
}
|
|
|
|
|
|
void config_set_bool(config_t *config, const char *section,
|
|
|
const char *name, bool value)
|
|
|
{
|
|
|
char *str = bstrdup(value ? "true" : "false");
|
|
|
- config_set_item(&config->sections, section, name, str);
|
|
|
+ config_set_item(config, &config->sections, section, name, str);
|
|
|
}
|
|
|
|
|
|
void config_set_double(config_t *config, const char *section,
|
|
|
@@ -564,7 +614,7 @@ void config_set_double(config_t *config, const char *section,
|
|
|
{
|
|
|
char *str = bzalloc(64);
|
|
|
os_dtostr(value, str, 64);
|
|
|
- config_set_item(&config->sections, section, name, str);
|
|
|
+ config_set_item(config, &config->sections, section, name, str);
|
|
|
}
|
|
|
|
|
|
void config_set_default_string(config_t *config, const char *section,
|
|
|
@@ -572,7 +622,8 @@ void config_set_default_string(config_t *config, const char *section,
|
|
|
{
|
|
|
if (!value)
|
|
|
value = "";
|
|
|
- config_set_item(&config->defaults, section, name, bstrdup(value));
|
|
|
+ config_set_item(config, &config->defaults, section, name,
|
|
|
+ bstrdup(value));
|
|
|
}
|
|
|
|
|
|
void config_set_default_int(config_t *config, const char *section,
|
|
|
@@ -581,7 +632,7 @@ void config_set_default_int(config_t *config, const char *section,
|
|
|
struct dstr str;
|
|
|
dstr_init(&str);
|
|
|
dstr_printf(&str, "%"PRId64, value);
|
|
|
- config_set_item(&config->defaults, section, name, str.array);
|
|
|
+ config_set_item(config, &config->defaults, section, name, str.array);
|
|
|
}
|
|
|
|
|
|
void config_set_default_uint(config_t *config, const char *section,
|
|
|
@@ -590,14 +641,14 @@ void config_set_default_uint(config_t *config, const char *section,
|
|
|
struct dstr str;
|
|
|
dstr_init(&str);
|
|
|
dstr_printf(&str, "%"PRIu64, value);
|
|
|
- config_set_item(&config->defaults, section, name, str.array);
|
|
|
+ config_set_item(config, &config->defaults, section, name, str.array);
|
|
|
}
|
|
|
|
|
|
void config_set_default_bool(config_t *config, const char *section,
|
|
|
const char *name, bool value)
|
|
|
{
|
|
|
char *str = bstrdup(value ? "true" : "false");
|
|
|
- config_set_item(&config->defaults, section, name, str);
|
|
|
+ config_set_item(config, &config->defaults, section, name, str);
|
|
|
}
|
|
|
|
|
|
void config_set_default_double(config_t *config, const char *section,
|
|
|
@@ -606,20 +657,25 @@ void config_set_default_double(config_t *config, const char *section,
|
|
|
struct dstr str;
|
|
|
dstr_init(&str);
|
|
|
dstr_printf(&str, "%g", value);
|
|
|
- config_set_item(&config->defaults, section, name, str.array);
|
|
|
+ config_set_item(config, &config->defaults, section, name, str.array);
|
|
|
}
|
|
|
|
|
|
-const char *config_get_string(const config_t *config, const char *section,
|
|
|
+const char *config_get_string(config_t *config, const char *section,
|
|
|
const char *name)
|
|
|
{
|
|
|
- const struct config_item *item = config_find_item(&config->sections,
|
|
|
- section, name);
|
|
|
+ const struct config_item *item;
|
|
|
+ const char *value = NULL;
|
|
|
+
|
|
|
+ pthread_mutex_lock(&config->mutex);
|
|
|
+
|
|
|
+ item = config_find_item(&config->sections, section, name);
|
|
|
if (!item)
|
|
|
item = config_find_item(&config->defaults, section, name);
|
|
|
- if (!item)
|
|
|
- return NULL;
|
|
|
+ if (item)
|
|
|
+ value = item->value;
|
|
|
|
|
|
- return item->value;
|
|
|
+ pthread_mutex_unlock(&config->mutex);
|
|
|
+ return value;
|
|
|
}
|
|
|
|
|
|
static inline int64_t str_to_int64(const char *str)
|
|
|
@@ -644,7 +700,7 @@ static inline uint64_t str_to_uint64(const char *str)
|
|
|
return strtoull(str, NULL, 10);
|
|
|
}
|
|
|
|
|
|
-int64_t config_get_int(const config_t *config, const char *section,
|
|
|
+int64_t config_get_int(config_t *config, const char *section,
|
|
|
const char *name)
|
|
|
{
|
|
|
const char *value = config_get_string(config, section, name);
|
|
|
@@ -654,7 +710,7 @@ int64_t config_get_int(const config_t *config, const char *section,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-uint64_t config_get_uint(const config_t *config, const char *section,
|
|
|
+uint64_t config_get_uint(config_t *config, const char *section,
|
|
|
const char *name)
|
|
|
{
|
|
|
const char *value = config_get_string(config, section, name);
|
|
|
@@ -664,7 +720,7 @@ uint64_t config_get_uint(const config_t *config, const char *section,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-bool config_get_bool(const config_t *config, const char *section,
|
|
|
+bool config_get_bool(config_t *config, const char *section,
|
|
|
const char *name)
|
|
|
{
|
|
|
const char *value = config_get_string(config, section, name);
|
|
|
@@ -675,7 +731,7 @@ bool config_get_bool(const config_t *config, const char *section,
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-double config_get_double(const config_t *config, const char *section,
|
|
|
+double config_get_double(config_t *config, const char *section,
|
|
|
const char *name)
|
|
|
{
|
|
|
const char *value = config_get_string(config, section, name);
|
|
|
@@ -689,6 +745,9 @@ bool config_remove_value(config_t *config, const char *section,
|
|
|
const char *name)
|
|
|
{
|
|
|
struct darray *sections = &config->sections;
|
|
|
+ bool success = false;
|
|
|
+
|
|
|
+ pthread_mutex_lock(&config->mutex);
|
|
|
|
|
|
for (size_t i = 0; i < sections->num; i++) {
|
|
|
struct config_section *sec = darray_item(
|
|
|
@@ -706,27 +765,34 @@ bool config_remove_value(config_t *config, const char *section,
|
|
|
config_item_free(item);
|
|
|
darray_erase(sizeof(struct config_item),
|
|
|
&sec->items, j);
|
|
|
- return true;
|
|
|
+ success = true;
|
|
|
+ goto unlock;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return false;
|
|
|
+unlock:
|
|
|
+ pthread_mutex_unlock(&config->mutex);
|
|
|
+ return success;
|
|
|
}
|
|
|
|
|
|
-const char *config_get_default_string(const config_t *config,
|
|
|
+const char *config_get_default_string(config_t *config,
|
|
|
const char *section, const char *name)
|
|
|
{
|
|
|
const struct config_item *item;
|
|
|
+ const char *value = NULL;
|
|
|
+
|
|
|
+ pthread_mutex_lock(&config->mutex);
|
|
|
|
|
|
item = config_find_item(&config->defaults, section, name);
|
|
|
- if (!item)
|
|
|
- return NULL;
|
|
|
+ if (item)
|
|
|
+ value = item->value;
|
|
|
|
|
|
- return item->value;
|
|
|
+ pthread_mutex_unlock(&config->mutex);
|
|
|
+ return value;
|
|
|
}
|
|
|
|
|
|
-int64_t config_get_default_int(const config_t *config, const char *section,
|
|
|
+int64_t config_get_default_int(config_t *config, const char *section,
|
|
|
const char *name)
|
|
|
{
|
|
|
const char *value = config_get_default_string(config, section, name);
|
|
|
@@ -736,7 +802,7 @@ int64_t config_get_default_int(const config_t *config, const char *section,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-uint64_t config_get_default_uint(const config_t *config, const char *section,
|
|
|
+uint64_t config_get_default_uint(config_t *config, const char *section,
|
|
|
const char *name)
|
|
|
{
|
|
|
const char *value = config_get_default_string(config, section, name);
|
|
|
@@ -746,7 +812,7 @@ uint64_t config_get_default_uint(const config_t *config, const char *section,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-bool config_get_default_bool(const config_t *config, const char *section,
|
|
|
+bool config_get_default_bool(config_t *config, const char *section,
|
|
|
const char *name)
|
|
|
{
|
|
|
const char *value = config_get_default_string(config, section, name);
|
|
|
@@ -757,7 +823,7 @@ bool config_get_default_bool(const config_t *config, const char *section,
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-double config_get_default_double(const config_t *config, const char *section,
|
|
|
+double config_get_default_double(config_t *config, const char *section,
|
|
|
const char *name)
|
|
|
{
|
|
|
const char *value = config_get_default_string(config, section, name);
|
|
|
@@ -767,15 +833,23 @@ double config_get_default_double(const config_t *config, const char *section,
|
|
|
return 0.0;
|
|
|
}
|
|
|
|
|
|
-bool config_has_user_value(const config_t *config, const char *section,
|
|
|
+bool config_has_user_value(config_t *config, const char *section,
|
|
|
const char *name)
|
|
|
{
|
|
|
- return config_find_item(&config->sections, section, name) != NULL;
|
|
|
+ bool success;
|
|
|
+ pthread_mutex_lock(&config->mutex);
|
|
|
+ success = config_find_item(&config->sections, section, name) != NULL;
|
|
|
+ pthread_mutex_unlock(&config->mutex);
|
|
|
+ return success;
|
|
|
}
|
|
|
|
|
|
-bool config_has_default_value(const config_t *config, const char *section,
|
|
|
+bool config_has_default_value(config_t *config, const char *section,
|
|
|
const char *name)
|
|
|
{
|
|
|
- return config_find_item(&config->defaults, section, name) != NULL;
|
|
|
+ bool success;
|
|
|
+ pthread_mutex_lock(&config->mutex);
|
|
|
+ success = config_find_item(&config->defaults, section, name) != NULL;
|
|
|
+ pthread_mutex_unlock(&config->mutex);
|
|
|
+ return success;
|
|
|
}
|
|
|
|