13
0
livetrax/libs/fluidsynth/src/fluid_settings.c

2000 lines
52 KiB
C

/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#include "fluid_sys.h"
#include "fluid_hash.h"
#include "fluid_synth.h"
#include "fluid_settings.h"
#include "fluid_midi.h"
/* maximum allowed components of a settings variable (separated by '.') */
#define MAX_SETTINGS_TOKENS 8 /* currently only a max of 3 are used */
#define MAX_SETTINGS_LABEL 256 /* max length of a settings variable label */
static void fluid_settings_init(fluid_settings_t *settings);
static void fluid_settings_key_destroy_func(void *value);
static void fluid_settings_value_destroy_func(void *value);
static int fluid_settings_tokenize(const char *s, char *buf, char **ptr);
/* Common structure to all settings nodes */
typedef struct
{
char *value;
char *def;
int hints;
fluid_list_t *options;
fluid_str_update_t update;
void *data;
} fluid_str_setting_t;
typedef struct
{
double value;
double def;
double min;
double max;
int hints;
fluid_num_update_t update;
void *data;
} fluid_num_setting_t;
typedef struct
{
int value;
int def;
int min;
int max;
int hints;
fluid_int_update_t update;
void *data;
} fluid_int_setting_t;
typedef struct
{
fluid_hashtable_t *hashtable;
} fluid_set_setting_t;
typedef struct
{
int type; /**< fluid_types_enum */
union
{
fluid_str_setting_t str;
fluid_num_setting_t num;
fluid_int_setting_t i;
fluid_set_setting_t set;
};
} fluid_setting_node_t;
static fluid_setting_node_t *
new_fluid_str_setting(const char *value, const char *def, int hints)
{
fluid_setting_node_t *node;
fluid_str_setting_t *str;
node = FLUID_NEW(fluid_setting_node_t);
if(!node)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
node->type = FLUID_STR_TYPE;
str = &node->str;
str->value = value ? FLUID_STRDUP(value) : NULL;
str->def = def ? FLUID_STRDUP(def) : NULL;
str->hints = hints;
str->options = NULL;
str->update = NULL;
str->data = NULL;
return node;
}
static void
delete_fluid_str_setting(fluid_setting_node_t *node)
{
fluid_return_if_fail(node != NULL);
FLUID_ASSERT(node->type == FLUID_STR_TYPE);
FLUID_FREE(node->str.value);
FLUID_FREE(node->str.def);
if(node->str.options)
{
fluid_list_t *list = node->str.options;
while(list)
{
FLUID_FREE(list->data);
list = fluid_list_next(list);
}
delete_fluid_list(node->str.options);
}
FLUID_FREE(node);
}
static fluid_setting_node_t *
new_fluid_num_setting(double min, double max, double def, int hints)
{
fluid_setting_node_t *node;
fluid_num_setting_t *num;
node = FLUID_NEW(fluid_setting_node_t);
if(!node)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
node->type = FLUID_NUM_TYPE;
num = &node->num;
num->value = def;
num->def = def;
num->min = min;
num->max = max;
num->hints = hints;
num->update = NULL;
num->data = NULL;
return node;
}
static void
delete_fluid_num_setting(fluid_setting_node_t *node)
{
fluid_return_if_fail(node != NULL);
FLUID_ASSERT(node->type == FLUID_NUM_TYPE);
FLUID_FREE(node);
}
static fluid_setting_node_t *
new_fluid_int_setting(int min, int max, int def, int hints)
{
fluid_setting_node_t *node;
fluid_int_setting_t *i;
node = FLUID_NEW(fluid_setting_node_t);
if(!node)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
node->type = FLUID_INT_TYPE;
i = &node->i;
i->value = def;
i->def = def;
i->min = min;
i->max = max;
i->hints = hints;
i->update = NULL;
i->data = NULL;
return node;
}
static void
delete_fluid_int_setting(fluid_setting_node_t *node)
{
fluid_return_if_fail(node != NULL);
FLUID_ASSERT(node->type == FLUID_INT_TYPE);
FLUID_FREE(node);
}
static fluid_setting_node_t *
new_fluid_set_setting(void)
{
fluid_setting_node_t *node;
fluid_set_setting_t *set;
node = FLUID_NEW(fluid_setting_node_t);
if(!node)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
node->type = FLUID_SET_TYPE;
set = &node->set;
set->hashtable = new_fluid_hashtable_full(fluid_str_hash, fluid_str_equal,
fluid_settings_key_destroy_func,
fluid_settings_value_destroy_func);
if(!set->hashtable)
{
FLUID_FREE(node);
return NULL;
}
return node;
}
static void
delete_fluid_set_setting(fluid_setting_node_t *node)
{
fluid_return_if_fail(node != NULL);
FLUID_ASSERT(node->type == FLUID_SET_TYPE);
delete_fluid_hashtable(node->set.hashtable);
FLUID_FREE(node);
}
/**
* Create a new settings object
*
* @return the pointer to the settings object
*/
fluid_settings_t *
new_fluid_settings(void)
{
fluid_settings_t *settings;
settings = new_fluid_hashtable_full(fluid_str_hash, fluid_str_equal,
fluid_settings_key_destroy_func,
fluid_settings_value_destroy_func);
if(settings == NULL)
{
return NULL;
}
fluid_rec_mutex_init(settings->mutex);
fluid_settings_init(settings);
return settings;
}
/**
* Delete the provided settings object
*
* @param settings a settings object
*/
void
delete_fluid_settings(fluid_settings_t *settings)
{
fluid_return_if_fail(settings != NULL);
fluid_rec_mutex_destroy(settings->mutex);
delete_fluid_hashtable(settings);
}
/* Settings hash key destroy function */
static void
fluid_settings_key_destroy_func(void *value)
{
FLUID_FREE(value); /* Free the string key value */
}
/* Settings hash value destroy function */
static void
fluid_settings_value_destroy_func(void *value)
{
fluid_setting_node_t *node = value;
switch(node->type)
{
case FLUID_NUM_TYPE:
delete_fluid_num_setting(node);
break;
case FLUID_INT_TYPE:
delete_fluid_int_setting(node);
break;
case FLUID_STR_TYPE:
delete_fluid_str_setting(node);
break;
case FLUID_SET_TYPE:
delete_fluid_set_setting(node);
break;
}
}
void
fluid_settings_init(fluid_settings_t *settings)
{
fluid_return_if_fail(settings != NULL);
fluid_synth_settings(settings);
#if 0
fluid_shell_settings(settings);
fluid_player_settings(settings);
fluid_file_renderer_settings(settings);
fluid_audio_driver_settings(settings);
fluid_midi_driver_settings(settings);
#endif
}
static int
fluid_settings_tokenize(const char *s, char *buf, char **ptr)
{
char *tokstr, *tok;
int n = 0;
if(FLUID_STRLEN(s) > MAX_SETTINGS_LABEL)
{
FLUID_LOG(FLUID_ERR, "Setting variable name exceeded max length of %d chars",
MAX_SETTINGS_LABEL);
return 0;
}
FLUID_STRCPY(buf, s); /* copy string to buffer, since it gets modified */
tokstr = buf;
while((tok = fluid_strtok(&tokstr, ".")))
{
if(n >= MAX_SETTINGS_TOKENS)
{
FLUID_LOG(FLUID_ERR, "Setting variable name exceeded max token count of %d",
MAX_SETTINGS_TOKENS);
return 0;
}
else
{
ptr[n++] = tok;
}
}
return n;
}
/**
* Get a setting name, value and type
*
* @param settings a settings object
* @param name Settings name
* @param value Location to store setting node if found
* @return #FLUID_OK if the node exists, #FLUID_FAILED otherwise
*/
static int
fluid_settings_get(fluid_settings_t *settings, const char *name,
fluid_setting_node_t **value)
{
fluid_hashtable_t *table = settings;
fluid_setting_node_t *node = NULL;
char *tokens[MAX_SETTINGS_TOKENS];
char buf[MAX_SETTINGS_LABEL + 1];
int ntokens;
int n;
ntokens = fluid_settings_tokenize(name, buf, tokens);
if(table == NULL || ntokens <= 0)
{
return FLUID_FAILED;
}
for(n = 0; n < ntokens; n++)
{
node = fluid_hashtable_lookup(table, tokens[n]);
if(!node)
{
return FLUID_FAILED;
}
table = (node->type == FLUID_SET_TYPE) ? node->set.hashtable : NULL;
}
if(value)
{
*value = node;
}
return FLUID_OK;
}
/**
* Set a setting name, value and type, replacing it if already exists
*
* @param settings a settings object
* @param name Settings name
* @param value Node instance to assign (used directly)
* @return #FLUID_OK if the value has been set, #FLUID_FAILED otherwise
*/
static int
fluid_settings_set(fluid_settings_t *settings, const char *name, fluid_setting_node_t *value)
{
fluid_hashtable_t *table = settings;
fluid_setting_node_t *node;
char *tokens[MAX_SETTINGS_TOKENS];
char buf[MAX_SETTINGS_LABEL + 1];
int n, num;
char *dupname;
num = fluid_settings_tokenize(name, buf, tokens);
if(num == 0)
{
return FLUID_FAILED;
}
num--;
for(n = 0; n < num; n++)
{
node = fluid_hashtable_lookup(table, tokens[n]);
if(node)
{
if(node->type == FLUID_SET_TYPE)
{
table = node->set.hashtable;
}
else
{
/* path ends prematurely */
FLUID_LOG(FLUID_ERR, "'%s' is not a node. Name of the setting was '%s'", tokens[n], name);
return FLUID_FAILED;
}
}
else
{
/* create a new node */
fluid_setting_node_t *setnode;
dupname = FLUID_STRDUP(tokens[n]);
setnode = new_fluid_set_setting();
if(!dupname || !setnode)
{
if(dupname)
{
FLUID_FREE(dupname);
}
else
{
FLUID_LOG(FLUID_ERR, "Out of memory");
}
if(setnode)
{
delete_fluid_set_setting(setnode);
}
return FLUID_FAILED;
}
fluid_hashtable_insert(table, dupname, setnode);
table = setnode->set.hashtable;
}
}
dupname = FLUID_STRDUP(tokens[num]);
if(!dupname)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
return FLUID_FAILED;
}
fluid_hashtable_insert(table, dupname, value);
return FLUID_OK;
}
/**
* Registers a new string value for the specified setting.
*
* @param settings a settings object
* @param name the setting's name
* @param def the default value for the setting
* @param hints the hints for the setting
* @return #FLUID_OK if the value has been register correctly, #FLUID_FAILED otherwise
*/
int
fluid_settings_register_str(fluid_settings_t *settings, const char *name, const char *def, int hints)
{
fluid_setting_node_t *node;
int retval = FLUID_FAILED;
fluid_return_val_if_fail(settings != NULL, retval);
fluid_return_val_if_fail(name != NULL, retval);
fluid_return_val_if_fail(name[0] != '\0', retval);
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) != FLUID_OK)
{
node = new_fluid_str_setting(def, def, hints);
retval = fluid_settings_set(settings, name, node);
if(retval != FLUID_OK)
{
delete_fluid_str_setting(node);
}
}
else
{
/* if variable already exists, don't change its value. */
if(node->type == FLUID_STR_TYPE)
{
fluid_str_setting_t *setting = &node->str;
FLUID_FREE(setting->def);
setting->def = def ? FLUID_STRDUP(def) : NULL;
setting->hints = hints;
retval = FLUID_OK;
}
else
{
FLUID_LOG(FLUID_ERR, "Failed to register string setting '%s' as it already exists with a different type", name);
}
}
fluid_rec_mutex_unlock(settings->mutex);
return retval;
}
/**
* Registers a new float value for the specified setting.
*
* @param settings a settings object
* @param name the setting's name
* @param def the default value for the setting
* @param min the smallest allowed value for the setting
* @param max the largest allowed value for the setting
* @param hints the hints for the setting
* @return #FLUID_OK if the value has been register correctly, #FLUID_FAILED otherwise
*/
int
fluid_settings_register_num(fluid_settings_t *settings, const char *name, double def,
double min, double max, int hints)
{
fluid_setting_node_t *node;
int retval = FLUID_FAILED;
fluid_return_val_if_fail(settings != NULL, retval);
fluid_return_val_if_fail(name != NULL, retval);
fluid_return_val_if_fail(name[0] != '\0', retval);
/* For now, all floating point settings are bounded below and above */
hints |= FLUID_HINT_BOUNDED_BELOW | FLUID_HINT_BOUNDED_ABOVE;
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) != FLUID_OK)
{
/* insert a new setting */
node = new_fluid_num_setting(min, max, def, hints);
retval = fluid_settings_set(settings, name, node);
if(retval != FLUID_OK)
{
delete_fluid_num_setting(node);
}
}
else
{
if(node->type == FLUID_NUM_TYPE)
{
/* update the existing setting but don't change its value */
fluid_num_setting_t *setting = &node->num;
setting->min = min;
setting->max = max;
setting->def = def;
setting->hints = hints;
retval = FLUID_OK;
}
else
{
/* type mismatch */
FLUID_LOG(FLUID_ERR, "Failed to register numeric setting '%s' as it already exists with a different type", name);
}
}
fluid_rec_mutex_unlock(settings->mutex);
return retval;
}
/**
* Registers a new integer value for the specified setting.
*
* @param settings a settings object
* @param name the setting's name
* @param def the default value for the setting
* @param min the smallest allowed value for the setting
* @param max the largest allowed value for the setting
* @param hints the hints for the setting
* @return #FLUID_OK if the value has been register correctly, #FLUID_FAILED otherwise
*/
int
fluid_settings_register_int(fluid_settings_t *settings, const char *name, int def,
int min, int max, int hints)
{
fluid_setting_node_t *node;
int retval = FLUID_FAILED;
fluid_return_val_if_fail(settings != NULL, retval);
fluid_return_val_if_fail(name != NULL, retval);
fluid_return_val_if_fail(name[0] != '\0', retval);
/* For now, all integer settings are bounded below and above */
hints |= FLUID_HINT_BOUNDED_BELOW | FLUID_HINT_BOUNDED_ABOVE;
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) != FLUID_OK)
{
/* insert a new setting */
node = new_fluid_int_setting(min, max, def, hints);
retval = fluid_settings_set(settings, name, node);
if(retval != FLUID_OK)
{
delete_fluid_int_setting(node);
}
}
else
{
if(node->type == FLUID_INT_TYPE)
{
/* update the existing setting but don't change its value */
fluid_int_setting_t *setting = &node->i;
setting->min = min;
setting->max = max;
setting->def = def;
setting->hints = hints;
retval = FLUID_OK;
}
else
{
/* type mismatch */
FLUID_LOG(FLUID_ERR, "Failed to register int setting '%s' as it already exists with a different type", name);
}
}
fluid_rec_mutex_unlock(settings->mutex);
return retval;
}
/**
* Registers a callback for the specified string setting.
*
* @param settings a settings object
* @param name the setting's name
* @param callback an update function for the setting
* @param data user supplied data passed to the update function
* @return #FLUID_OK if the callback has been set, #FLUID_FAILED otherwise
*/
int fluid_settings_callback_str(fluid_settings_t *settings, const char *name,
fluid_str_update_t callback, void *data)
{
fluid_setting_node_t *node;
fluid_str_setting_t *setting;
fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
fluid_rec_mutex_lock(settings->mutex);
if((fluid_settings_get(settings, name, &node) != FLUID_OK)
|| node->type != FLUID_STR_TYPE)
{
fluid_rec_mutex_unlock(settings->mutex);
return FLUID_FAILED;
}
setting = &node->str;
setting->update = callback;
setting->data = data;
fluid_rec_mutex_unlock(settings->mutex);
return FLUID_OK;
}
/**
* Registers a callback for the specified numeric setting.
*
* @param settings a settings object
* @param name the setting's name
* @param callback an update function for the setting
* @param data user supplied data passed to the update function
* @return #FLUID_OK if the callback has been set, #FLUID_FAILED otherwise
*/
int fluid_settings_callback_num(fluid_settings_t *settings, const char *name,
fluid_num_update_t callback, void *data)
{
fluid_setting_node_t *node;
fluid_num_setting_t *setting;
fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
fluid_rec_mutex_lock(settings->mutex);
if((fluid_settings_get(settings, name, &node) != FLUID_OK)
|| node->type != FLUID_NUM_TYPE)
{
fluid_rec_mutex_unlock(settings->mutex);
return FLUID_FAILED;
}
setting = &node->num;
setting->update = callback;
setting->data = data;
fluid_rec_mutex_unlock(settings->mutex);
return FLUID_OK;
}
/**
* Registers a callback for the specified int setting.
*
* @param settings a settings object
* @param name the setting's name
* @param callback an update function for the setting
* @param data user supplied data passed to the update function
* @return #FLUID_OK if the callback has been set, #FLUID_FAILED otherwise
*/
int fluid_settings_callback_int(fluid_settings_t *settings, const char *name,
fluid_int_update_t callback, void *data)
{
fluid_setting_node_t *node;
fluid_int_setting_t *setting;
fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
fluid_rec_mutex_lock(settings->mutex);
if((fluid_settings_get(settings, name, &node) != FLUID_OK)
|| node->type != FLUID_INT_TYPE)
{
fluid_rec_mutex_unlock(settings->mutex);
return FLUID_FAILED;
}
setting = &node->i;
setting->update = callback;
setting->data = data;
fluid_rec_mutex_unlock(settings->mutex);
return FLUID_OK;
}
void* fluid_settings_get_user_data(fluid_settings_t * settings, const char *name)
{
fluid_setting_node_t *node;
void* retval = NULL;
fluid_return_val_if_fail(settings != NULL, NULL);
fluid_return_val_if_fail(name != NULL, NULL);
fluid_return_val_if_fail(name[0] != '\0', NULL);
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) == FLUID_OK)
{
if(node->type == FLUID_NUM_TYPE)
{
fluid_num_setting_t *setting = &node->num;
retval = setting->data;
}
else if(node->type == FLUID_STR_TYPE)
{
fluid_str_setting_t *setting = &node->str;
retval = setting->data;
}
else if(node->type == FLUID_INT_TYPE)
{
fluid_int_setting_t *setting = &node->i;
retval = setting->data;
}
}
fluid_rec_mutex_unlock(settings->mutex);
return retval;
}
/**
* Get the type of the setting with the given name
*
* @param settings a settings object
* @param name a setting's name
* @return the type for the named setting (see #fluid_types_enum), or #FLUID_NO_TYPE when it does not exist
*/
int
fluid_settings_get_type(fluid_settings_t *settings, const char *name)
{
fluid_setting_node_t *node;
int type = FLUID_NO_TYPE;
fluid_return_val_if_fail(settings != NULL, type);
fluid_return_val_if_fail(name != NULL, type);
fluid_return_val_if_fail(name[0] != '\0', type);
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) == FLUID_OK)
{
type = node->type;
}
fluid_rec_mutex_unlock(settings->mutex);
return type;
}
/**
* Get the hints for the named setting as an integer bitmap
*
* @param settings a settings object
* @param name a setting's name
* @param hints set to the hints associated to the setting if it exists
* @return #FLUID_OK if hints associated to the named setting exist, #FLUID_FAILED otherwise
*/
int
fluid_settings_get_hints(fluid_settings_t *settings, const char *name, int *hints)
{
fluid_setting_node_t *node;
int retval = FLUID_FAILED;
fluid_return_val_if_fail(settings != NULL, retval);
fluid_return_val_if_fail(name != NULL, retval);
fluid_return_val_if_fail(name[0] != '\0', retval);
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) == FLUID_OK)
{
if(node->type == FLUID_NUM_TYPE)
{
fluid_num_setting_t *setting = &node->num;
*hints = setting->hints;
retval = FLUID_OK;
}
else if(node->type == FLUID_STR_TYPE)
{
fluid_str_setting_t *setting = &node->str;
*hints = setting->hints;
retval = FLUID_OK;
}
else if(node->type == FLUID_INT_TYPE)
{
fluid_int_setting_t *setting = &node->i;
*hints = setting->hints;
retval = FLUID_OK;
}
}
fluid_rec_mutex_unlock(settings->mutex);
return retval;
}
/**
* Ask whether the setting is changeable in real-time.
*
* @param settings a settings object
* @param name a setting's name
* @return TRUE if the setting is changeable in real-time, FALSE otherwise
*
* @note Before using this function, make sure the @p settings object has already been used to create
* a synthesizer, a MIDI driver, an audio driver, a MIDI player, or a command handler (depending on
* which settings you want to query).
*/
int
fluid_settings_is_realtime(fluid_settings_t *settings, const char *name)
{
fluid_setting_node_t *node;
int isrealtime = FALSE;
fluid_return_val_if_fail(settings != NULL, 0);
fluid_return_val_if_fail(name != NULL, 0);
fluid_return_val_if_fail(name[0] != '\0', 0);
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) == FLUID_OK)
{
if(node->type == FLUID_NUM_TYPE)
{
fluid_num_setting_t *setting = &node->num;
isrealtime = setting->update != NULL;
}
else if(node->type == FLUID_STR_TYPE)
{
fluid_str_setting_t *setting = &node->str;
isrealtime = setting->update != NULL;
}
else if(node->type == FLUID_INT_TYPE)
{
fluid_int_setting_t *setting = &node->i;
isrealtime = setting->update != NULL;
}
}
fluid_rec_mutex_unlock(settings->mutex);
return isrealtime;
}
/**
* Set a string value for a named setting
*
* @param settings a settings object
* @param name a setting's name
* @param str new string value
* @return #FLUID_OK if the value has been set, #FLUID_FAILED otherwise
*/
int
fluid_settings_setstr(fluid_settings_t *settings, const char *name, const char *str)
{
fluid_setting_node_t *node;
fluid_str_setting_t *setting;
char *new_value = NULL;
fluid_str_update_t callback = NULL;
void *data = NULL;
fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
fluid_rec_mutex_lock(settings->mutex);
if((fluid_settings_get(settings, name, &node) != FLUID_OK)
|| (node->type != FLUID_STR_TYPE))
{
FLUID_LOG(FLUID_ERR, "Unknown string setting '%s'", name);
goto error_recovery;
}
setting = &node->str;
if(setting->value)
{
FLUID_FREE(setting->value);
}
if(str)
{
new_value = FLUID_STRDUP(str);
if(new_value == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
goto error_recovery;
}
}
setting->value = new_value;
callback = setting->update;
data = setting->data;
/* Release the mutex before calling the update callback, to avoid
* possible deadlocks with FluidSynths API lock */
fluid_rec_mutex_unlock(settings->mutex);
if(callback)
{
(*callback)(data, name, new_value);
}
return FLUID_OK;
error_recovery:
fluid_rec_mutex_unlock(settings->mutex);
return FLUID_FAILED;
}
/**
* Copy the value of a string setting into the provided buffer (thread safe)
*
* @param settings a settings object
* @param name a setting's name
* @param str Caller supplied buffer to copy string value to
* @param len Size of 'str' buffer (no more than len bytes will be written, which
* will always include a zero terminator)
* @return #FLUID_OK if the value exists, #FLUID_FAILED otherwise
*
* @note A size of 256 should be more than sufficient for the string buffer.
*
* @since 1.1.0
*/
int
fluid_settings_copystr(fluid_settings_t *settings, const char *name,
char *str, int len)
{
fluid_setting_node_t *node;
int retval = FLUID_FAILED;
fluid_return_val_if_fail(settings != NULL, retval);
fluid_return_val_if_fail(name != NULL, retval);
fluid_return_val_if_fail(name[0] != '\0', retval);
fluid_return_val_if_fail(str != NULL, retval);
fluid_return_val_if_fail(len > 0, retval);
str[0] = 0;
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) == FLUID_OK)
{
if(node->type == FLUID_STR_TYPE)
{
fluid_str_setting_t *setting = &node->str;
if(setting->value)
{
FLUID_STRNCPY(str, setting->value, len);
}
retval = FLUID_OK;
}
else if(node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */
{
fluid_int_setting_t *setting = &node->i;
if(setting->hints & FLUID_HINT_TOGGLED)
{
FLUID_STRNCPY(str, setting->value ? "yes" : "no", len);
retval = FLUID_OK;
}
}
}
fluid_rec_mutex_unlock(settings->mutex);
return retval;
}
/**
* Duplicate the value of a string setting
*
* @param settings a settings object
* @param name a setting's name
* @param str Location to store pointer to allocated duplicate string
* @return #FLUID_OK if the value exists and was successfully duplicated, #FLUID_FAILED otherwise
*
* Like fluid_settings_copystr() but allocates a new copy of the string. Caller
* owns the string and should free it with fluid_free() when done using it.
*
* @since 1.1.0
*/
int
fluid_settings_dupstr(fluid_settings_t *settings, const char *name, char **str)
{
fluid_setting_node_t *node;
int retval = FLUID_FAILED;
fluid_return_val_if_fail(settings != NULL, retval);
fluid_return_val_if_fail(name != NULL, retval);
fluid_return_val_if_fail(name[0] != '\0', retval);
fluid_return_val_if_fail(str != NULL, retval);
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) == FLUID_OK)
{
if(node->type == FLUID_STR_TYPE)
{
fluid_str_setting_t *setting = &node->str;
if(setting->value)
{
*str = FLUID_STRDUP(setting->value);
if(!*str)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
}
}
if(!setting->value || *str)
{
retval = FLUID_OK; /* Don't set to FLUID_OK if out of memory */
}
}
else if(node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */
{
fluid_int_setting_t *setting = &node->i;
if(setting->hints & FLUID_HINT_TOGGLED)
{
*str = FLUID_STRDUP(setting->value ? "yes" : "no");
if(!*str)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
}
if(!setting->value || *str)
{
retval = FLUID_OK; /* Don't set to FLUID_OK if out of memory */
}
}
}
}
fluid_rec_mutex_unlock(settings->mutex);
return retval;
}
/**
* Test a string setting for some value.
*
* @param settings a settings object
* @param name a setting's name
* @param s a string to be tested
* @return TRUE if the value exists and is equal to \c s, FALSE otherwise
*/
int
fluid_settings_str_equal(fluid_settings_t *settings, const char *name, const char *s)
{
fluid_setting_node_t *node;
int retval = FALSE;
fluid_return_val_if_fail(settings != NULL, retval);
fluid_return_val_if_fail(name != NULL, retval);
fluid_return_val_if_fail(name[0] != '\0', retval);
fluid_return_val_if_fail(s != NULL, retval);
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) == FLUID_OK)
{
if(node->type == FLUID_STR_TYPE)
{
fluid_str_setting_t *setting = &node->str;
if(setting->value)
{
retval = FLUID_STRCMP(setting->value, s) == 0;
}
}
else if(node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */
{
fluid_int_setting_t *setting = &node->i;
if(setting->hints & FLUID_HINT_TOGGLED)
{
retval = FLUID_STRCMP(setting->value ? "yes" : "no", s) == 0;
}
}
}
fluid_rec_mutex_unlock(settings->mutex);
return retval;
}
/**
* Get the default value of a string setting.
*
* @param settings a settings object
* @param name a setting's name
* @param def the default string value of the setting if it exists
* @return FLUID_OK if a default vaule exists, FLUID_FAILED otherwise
*
* @note The returned string is not owned by the caller and should not be modified or freed.
*/
int
fluid_settings_getstr_default(fluid_settings_t *settings, const char *name, char const **def)
{
fluid_setting_node_t *node;
char const *retval = NULL;
fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) == FLUID_OK)
{
if(node->type == FLUID_STR_TYPE)
{
fluid_str_setting_t *setting = &node->str;
retval = setting->def;
}
else if(node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */
{
fluid_int_setting_t *setting = &node->i;
if(setting->hints & FLUID_HINT_TOGGLED)
{
retval = setting->def ? "yes" : "no";
}
}
}
*def = retval;
fluid_rec_mutex_unlock(settings->mutex);
return retval != NULL ? FLUID_OK : FLUID_FAILED;
}
/**
* Add an option to a string setting (like an enumeration value).
*
* @param settings a settings object
* @param name a setting's name
* @param s option string to add
* @return #FLUID_OK if the setting exists and option was added, #FLUID_FAILED otherwise
*
* Causes the setting's #FLUID_HINT_OPTIONLIST hint to be set.
*/
int
fluid_settings_add_option(fluid_settings_t *settings, const char *name, const char *s)
{
fluid_setting_node_t *node;
int retval = FLUID_FAILED;
fluid_return_val_if_fail(settings != NULL, retval);
fluid_return_val_if_fail(name != NULL, retval);
fluid_return_val_if_fail(name[0] != '\0', retval);
fluid_return_val_if_fail(s != NULL, retval);
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) == FLUID_OK
&& (node->type == FLUID_STR_TYPE))
{
fluid_str_setting_t *setting = &node->str;
char *copy = FLUID_STRDUP(s);
setting->options = fluid_list_append(setting->options, copy);
setting->hints |= FLUID_HINT_OPTIONLIST;
retval = FLUID_OK;
}
fluid_rec_mutex_unlock(settings->mutex);
return retval;
}
/**
* Remove an option previously assigned by fluid_settings_add_option().
*
* @param settings a settings object
* @param name a setting's name
* @param s option string to remove
* @return #FLUID_OK if the setting exists and option was removed, #FLUID_FAILED otherwise
*/
int
fluid_settings_remove_option(fluid_settings_t *settings, const char *name, const char *s)
{
fluid_setting_node_t *node;
int retval = FLUID_FAILED;
fluid_return_val_if_fail(settings != NULL, retval);
fluid_return_val_if_fail(name != NULL, retval);
fluid_return_val_if_fail(name[0] != '\0', retval);
fluid_return_val_if_fail(s != NULL, retval);
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) == FLUID_OK
&& (node->type == FLUID_STR_TYPE))
{
fluid_str_setting_t *setting = &node->str;
fluid_list_t *list = setting->options;
while(list)
{
char *option = (char *) fluid_list_get(list);
if(FLUID_STRCMP(s, option) == 0)
{
FLUID_FREE(option);
setting->options = fluid_list_remove_link(setting->options, list);
retval = FLUID_OK;
break;
}
list = fluid_list_next(list);
}
}
fluid_rec_mutex_unlock(settings->mutex);
return retval;
}
/**
* Set a numeric value for a named setting.
*
* @param settings a settings object
* @param name a setting's name
* @param val new setting's value
* @return #FLUID_OK if the value has been set, #FLUID_FAILED otherwise
*/
int
fluid_settings_setnum(fluid_settings_t *settings, const char *name, double val)
{
fluid_setting_node_t *node;
fluid_num_setting_t *setting;
fluid_num_update_t callback = NULL;
void *data = NULL;
fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
fluid_rec_mutex_lock(settings->mutex);
if((fluid_settings_get(settings, name, &node) != FLUID_OK)
|| (node->type != FLUID_NUM_TYPE))
{
FLUID_LOG(FLUID_ERR, "Unknown numeric setting '%s'", name);
goto error_recovery;
}
setting = &node->num;
if(val < setting->min || val > setting->max)
{
FLUID_LOG(FLUID_ERR, "requested set value for '%s' out of range", name);
goto error_recovery;
}
setting->value = val;
callback = setting->update;
data = setting->data;
/* Release the mutex before calling the update callback, to avoid
* possible deadlocks with FluidSynths API lock */
fluid_rec_mutex_unlock(settings->mutex);
if(callback)
{
(*callback)(data, name, val);
}
return FLUID_OK;
error_recovery:
fluid_rec_mutex_unlock(settings->mutex);
return FLUID_FAILED;
}
/**
* Get the numeric value of a named setting
*
* @param settings a settings object
* @param name a setting's name
* @param val variable pointer to receive the setting's numeric value
* @return #FLUID_OK if the value exists, #FLUID_FAILED otherwise
*/
int
fluid_settings_getnum(fluid_settings_t *settings, const char *name, double *val)
{
fluid_setting_node_t *node;
int retval = FLUID_FAILED;
fluid_return_val_if_fail(settings != NULL, retval);
fluid_return_val_if_fail(name != NULL, retval);
fluid_return_val_if_fail(name[0] != '\0', retval);
fluid_return_val_if_fail(val != NULL, retval);
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) == FLUID_OK
&& (node->type == FLUID_NUM_TYPE))
{
fluid_num_setting_t *setting = &node->num;
*val = setting->value;
retval = FLUID_OK;
}
fluid_rec_mutex_unlock(settings->mutex);
return retval;
}
/**
* float-typed wrapper for fluid_settings_getnum
*
* @param settings a settings object
* @param name a setting's name
* @param val variable pointer to receive the setting's float value
* @return #FLUID_OK if the value exists, #FLUID_FAILED otherwise
*/
int fluid_settings_getnum_float(fluid_settings_t *settings, const char *name, float *val)
{
double tmp;
if(fluid_settings_getnum(settings, name, &tmp) == FLUID_OK)
{
*val = tmp;
return FLUID_OK;
}
return FLUID_FAILED;
}
/**
* Get the range of values of a numeric setting
*
* @param settings a settings object
* @param name a setting's name
* @param min setting's range lower limit
* @param max setting's range upper limit
* @return #FLUID_OK if the setting's range exists, #FLUID_FAILED otherwise
*/
int
fluid_settings_getnum_range(fluid_settings_t *settings, const char *name,
double *min, double *max)
{
fluid_setting_node_t *node;
int retval = FLUID_FAILED;
fluid_return_val_if_fail(settings != NULL, retval);
fluid_return_val_if_fail(name != NULL, retval);
fluid_return_val_if_fail(name[0] != '\0', retval);
fluid_return_val_if_fail(min != NULL, retval);
fluid_return_val_if_fail(max != NULL, retval);
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) == FLUID_OK
&& (node->type == FLUID_NUM_TYPE))
{
fluid_num_setting_t *setting = &node->num;
*min = setting->min;
*max = setting->max;
retval = FLUID_OK;
}
fluid_rec_mutex_unlock(settings->mutex);
return retval;
}
/**
* Get the default value of a named numeric (double) setting
*
* @param settings a settings object
* @param name a setting's name
* @param val set to the default value if the named setting exists
* @return #FLUID_OK if the default value of the named setting exists, #FLUID_FAILED otherwise
*/
int
fluid_settings_getnum_default(fluid_settings_t *settings, const char *name, double *val)
{
fluid_setting_node_t *node;
int retval = FLUID_FAILED;
fluid_return_val_if_fail(settings != NULL, retval);
fluid_return_val_if_fail(name != NULL, retval);
fluid_return_val_if_fail(name[0] != '\0', retval);
fluid_return_val_if_fail(val != NULL, retval);
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) == FLUID_OK
&& (node->type == FLUID_NUM_TYPE))
{
fluid_num_setting_t *setting = &node->num;
*val = setting->def;
retval = FLUID_OK;
}
fluid_rec_mutex_unlock(settings->mutex);
return retval;
}
/**
* Set an integer value for a setting
*
* @param settings a settings object
* @param name a setting's name
* @param val new setting's integer value
* @return #FLUID_OK if the value has been set, #FLUID_FAILED otherwise
*/
int
fluid_settings_setint(fluid_settings_t *settings, const char *name, int val)
{
fluid_setting_node_t *node;
fluid_int_setting_t *setting;
fluid_int_update_t callback = NULL;
void *data = NULL;
fluid_return_val_if_fail(settings != NULL, FLUID_FAILED);
fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED);
fluid_rec_mutex_lock(settings->mutex);
if((fluid_settings_get(settings, name, &node) != FLUID_OK)
|| (node->type != FLUID_INT_TYPE))
{
FLUID_LOG(FLUID_ERR, "Unknown integer parameter '%s'", name);
goto error_recovery;
}
setting = &node->i;
if(val < setting->min || val > setting->max)
{
FLUID_LOG(FLUID_ERR, "requested set value for setting '%s' out of range", name);
goto error_recovery;
}
setting->value = val;
callback = setting->update;
data = setting->data;
/* Release the mutex before calling the update callback, to avoid
* possible deadlocks with FluidSynths API lock */
fluid_rec_mutex_unlock(settings->mutex);
if(callback)
{
(*callback)(data, name, val);
}
return FLUID_OK;
error_recovery:
fluid_rec_mutex_unlock(settings->mutex);
return FLUID_FAILED;
}
/**
* Get an integer value setting.
*
* @param settings a settings object
* @param name a setting's name
* @param val pointer to a variable to receive the setting's integer value
* @return #FLUID_OK if the value exists, #FLUID_FAILED otherwise
*/
int
fluid_settings_getint(fluid_settings_t *settings, const char *name, int *val)
{
fluid_setting_node_t *node;
int retval = FLUID_FAILED;
fluid_return_val_if_fail(settings != NULL, retval);
fluid_return_val_if_fail(name != NULL, retval);
fluid_return_val_if_fail(name[0] != '\0', retval);
fluid_return_val_if_fail(val != NULL, retval);
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) == FLUID_OK
&& (node->type == FLUID_INT_TYPE))
{
fluid_int_setting_t *setting = &node->i;
*val = setting->value;
retval = FLUID_OK;
}
fluid_rec_mutex_unlock(settings->mutex);
return retval;
}
/**
* Get the range of values of an integer setting
*
* @param settings a settings object
* @param name a setting's name
* @param min setting's range lower limit
* @param max setting's range upper limit
* @return #FLUID_OK if the setting's range exists, #FLUID_FAILED otherwise
*/
int
fluid_settings_getint_range(fluid_settings_t *settings, const char *name,
int *min, int *max)
{
fluid_setting_node_t *node;
int retval = FLUID_FAILED;
fluid_return_val_if_fail(settings != NULL, retval);
fluid_return_val_if_fail(name != NULL, retval);
fluid_return_val_if_fail(name[0] != '\0', retval);
fluid_return_val_if_fail(min != NULL, retval);
fluid_return_val_if_fail(max != NULL, retval);
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) == FLUID_OK
&& (node->type == FLUID_INT_TYPE))
{
fluid_int_setting_t *setting = &node->i;
*min = setting->min;
*max = setting->max;
retval = FLUID_OK;
}
fluid_rec_mutex_unlock(settings->mutex);
return retval;
}
/**
* Get the default value of an integer setting.
*
* @param settings a settings object
* @param name a setting's name
* @param val set to the setting's default integer value if it exists
* @return #FLUID_OK if the setting's default integer value exists, #FLUID_FAILED otherwise
*/
int fluid_settings_getint_default(fluid_settings_t *settings, const char *name, int *val)
{
fluid_setting_node_t *node;
int retval = FLUID_FAILED;
fluid_return_val_if_fail(settings != NULL, retval);
fluid_return_val_if_fail(name != NULL, retval);
fluid_return_val_if_fail(name[0] != '\0', retval);
fluid_return_val_if_fail(val != NULL, retval);
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) == FLUID_OK
&& (node->type == FLUID_INT_TYPE))
{
fluid_int_setting_t *setting = &node->i;
*val = setting->def;
retval = FLUID_OK;
}
fluid_rec_mutex_unlock(settings->mutex);
return retval;
}
/**
* Iterate the available options for a named string setting, calling the provided
* callback function for each existing option.
*
* @param settings a settings object
* @param name a setting's name
* @param data any user provided pointer
* @param func callback function to be called on each iteration
*
* @note Starting with FluidSynth 1.1.0 the \p func callback is called for each
* option in alphabetical order. Sort order was undefined in previous versions.
*/
void
fluid_settings_foreach_option(fluid_settings_t *settings, const char *name,
void *data, fluid_settings_foreach_option_t func)
{
fluid_setting_node_t *node;
fluid_str_setting_t *setting;
fluid_list_t *p, *newlist = NULL;
fluid_return_if_fail(settings != NULL);
fluid_return_if_fail(name != NULL);
fluid_return_if_fail(name[0] != '\0');
fluid_return_if_fail(func != NULL);
fluid_rec_mutex_lock(settings->mutex); /* ++ lock */
if(fluid_settings_get(settings, name, &node) != FLUID_OK
|| node->type != FLUID_STR_TYPE)
{
fluid_rec_mutex_unlock(settings->mutex); /* -- unlock */
return;
}
setting = &node->str;
/* Duplicate option list */
for(p = setting->options; p; p = p->next)
{
newlist = fluid_list_append(newlist, fluid_list_get(p));
}
/* Sort by name */
newlist = fluid_list_sort(newlist, fluid_list_str_compare_func);
for(p = newlist; p; p = p->next)
{
(*func)(data, name, (const char *)fluid_list_get(p));
}
fluid_rec_mutex_unlock(settings->mutex); /* -- unlock */
delete_fluid_list(newlist);
}
/**
* Count option string values for a string setting.
*
* @param settings a settings object
* @param name Name of setting
* @return Count of options for this string setting (0 if none, -1 if not found
* or not a string setting)
*
* @since 1.1.0
*/
int
fluid_settings_option_count(fluid_settings_t *settings, const char *name)
{
fluid_setting_node_t *node;
int count = -1;
fluid_return_val_if_fail(settings != NULL, -1);
fluid_return_val_if_fail(name != NULL, -1);
fluid_return_val_if_fail(name[0] != '\0', -1);
fluid_rec_mutex_lock(settings->mutex);
if(fluid_settings_get(settings, name, &node) == FLUID_OK
&& node->type == FLUID_STR_TYPE)
{
count = fluid_list_size(node->str.options);
}
fluid_rec_mutex_unlock(settings->mutex);
return (count);
}
/**
* Concatenate options for a string setting together with a separator between.
*
* @param settings Settings object
* @param name Settings name
* @param separator String to use between options (NULL to use ", ")
* @return Newly allocated string or NULL on error (out of memory, not a valid
* setting \p name or not a string setting). Free the string when finished with it by using fluid_free().
*
* @since 1.1.0
*/
char *
fluid_settings_option_concat(fluid_settings_t *settings, const char *name,
const char *separator)
{
fluid_setting_node_t *node;
fluid_list_t *p, *newlist = NULL;
size_t count, len;
char *str, *option;
fluid_return_val_if_fail(settings != NULL, NULL);
fluid_return_val_if_fail(name != NULL, NULL);
fluid_return_val_if_fail(name[0] != '\0', NULL);
if(!separator)
{
separator = ", ";
}
fluid_rec_mutex_lock(settings->mutex); /* ++ lock */
if(fluid_settings_get(settings, name, &node) != FLUID_OK
|| node->type != FLUID_STR_TYPE)
{
fluid_rec_mutex_unlock(settings->mutex); /* -- unlock */
return (NULL);
}
/* Duplicate option list, count options and get total string length */
for(p = node->str.options, count = 0, len = 0; p; p = p->next)
{
option = fluid_list_get(p);
if(option)
{
newlist = fluid_list_append(newlist, option);
len += FLUID_STRLEN(option);
count++;
}
}
if(count > 1)
{
len += (count - 1) * FLUID_STRLEN(separator);
}
len++; /* For terminator */
/* Sort by name */
newlist = fluid_list_sort(newlist, fluid_list_str_compare_func);
str = FLUID_MALLOC(len);
if(str)
{
str[0] = 0;
for(p = newlist; p; p = p->next)
{
option = fluid_list_get(p);
strcat(str, option);
if(p->next)
{
strcat(str, separator);
}
}
}
fluid_rec_mutex_unlock(settings->mutex); /* -- unlock */
delete_fluid_list(newlist);
if(!str)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
}
return (str);
}
/* Structure passed to fluid_settings_foreach_iter recursive function */
typedef struct
{
char path[MAX_SETTINGS_LABEL + 1]; /* Maximum settings label length */
fluid_list_t *names; /* For fluid_settings_foreach() */
} fluid_settings_foreach_bag_t;
static int
fluid_settings_foreach_iter(void *key, void *value, void *data)
{
fluid_settings_foreach_bag_t *bag = data;
char *keystr = key;
fluid_setting_node_t *node = value;
size_t pathlen;
char *s;
pathlen = FLUID_STRLEN(bag->path);
if(pathlen > 0)
{
bag->path[pathlen] = '.';
bag->path[pathlen + 1] = 0;
}
strcat(bag->path, keystr);
switch(node->type)
{
case FLUID_NUM_TYPE:
case FLUID_INT_TYPE:
case FLUID_STR_TYPE:
s = FLUID_STRDUP(bag->path);
if(s)
{
bag->names = fluid_list_append(bag->names, s);
}
break;
case FLUID_SET_TYPE:
fluid_hashtable_foreach(node->set.hashtable,
fluid_settings_foreach_iter, bag);
break;
}
bag->path[pathlen] = 0;
return 0;
}
/**
* Iterate the existing settings defined in a settings object, calling the
* provided callback function for each setting.
*
* @param settings a settings object
* @param data any user provided pointer
* @param func callback function to be called on each iteration
*
* @note Starting with FluidSynth 1.1.0 the \p func callback is called for each
* setting in alphabetical order. Sort order was undefined in previous versions.
*/
void
fluid_settings_foreach(fluid_settings_t *settings, void *data,
fluid_settings_foreach_t func)
{
fluid_settings_foreach_bag_t bag;
fluid_setting_node_t *node;
fluid_list_t *p;
fluid_return_if_fail(settings != NULL);
fluid_return_if_fail(func != NULL);
bag.path[0] = 0;
bag.names = NULL;
fluid_rec_mutex_lock(settings->mutex);
/* Add all node names to the bag.names list */
fluid_hashtable_foreach(settings, fluid_settings_foreach_iter, &bag);
/* Sort names */
bag.names = fluid_list_sort(bag.names, fluid_list_str_compare_func);
/* Loop over names and call the callback */
for(p = bag.names; p; p = p->next)
{
if(fluid_settings_get(settings, (const char *)(p->data), &node) == FLUID_OK
&& node)
{
(*func)(data, (const char *)(p->data), node->type);
}
FLUID_FREE(p->data); /* -- Free name */
}
fluid_rec_mutex_unlock(settings->mutex);
delete_fluid_list(bag.names); /* -- Free names list */
}
/**
* Split a comma-separated list of integers and fill the passed
* in buffer with the parsed values.
*
* @param str the comma-separated string to split
* @param buf user-supplied buffer to hold the parsed numbers
* @param buf_len length of user-supplied buffer
* @return number of parsed values or -1 on failure
*/
int fluid_settings_split_csv(const char *str, int *buf, int buf_len)
{
char *s;
char *tok;
char *tokstr;
int n = 0;
s = tokstr = FLUID_STRDUP(str);
if(s == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
return -1;
}
while((tok = fluid_strtok(&tokstr, ",")) && n < buf_len)
{
buf[n++] = atoi(tok);
}
FLUID_FREE(s);
return n;
}