727 lines
20 KiB
C
727 lines
20 KiB
C
/* -*- Mode: C ; c-basic-offset: 4 -*- */
|
|
/*
|
|
Copyright (C) 2011 Nedko Arnaudov
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License.
|
|
|
|
This program 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
|
|
|
/*
|
|
* Parameter addresses:
|
|
*
|
|
* "engine"
|
|
* "engine", "driver"
|
|
* "engine", "realtime"
|
|
* "engine", ...more engine parameters
|
|
*
|
|
* "driver", "device"
|
|
* "driver", ...more driver parameters
|
|
*
|
|
* "drivers", "alsa", "device"
|
|
* "drivers", "alsa", ...more alsa driver parameters
|
|
*
|
|
* "drivers", ...more drivers
|
|
*
|
|
* "internals", "netmanager", "multicast_ip"
|
|
* "internals", "netmanager", ...more netmanager parameters
|
|
*
|
|
* "internals", ...more internals
|
|
*
|
|
*/
|
|
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <dbus/dbus.h>
|
|
|
|
#include "params.h"
|
|
#include "controller_internal.h"
|
|
|
|
#define PTNODE_ENGINE "engine"
|
|
#define PTNODE_DRIVER "driver"
|
|
#define PTNODE_DRIVERS "drivers"
|
|
#define PTNODE_INTERNALS "internals"
|
|
|
|
struct jack_parameter_container
|
|
{
|
|
struct list_head siblings;
|
|
char * name;
|
|
struct jack_parameter_container * symlink;
|
|
bool leaf;
|
|
struct list_head children;
|
|
void * obj;
|
|
};
|
|
|
|
struct jack_params
|
|
{
|
|
jackctl_server_t * server;
|
|
struct jack_parameter_container root;
|
|
struct list_head * drivers_ptr;
|
|
uint32_t drivers_count;
|
|
struct jack_parameter_container * driver_ptr;
|
|
bool driver_set; /* whether driver is manually set, if false - DEFAULT_DRIVER is auto set */
|
|
};
|
|
|
|
static bool controlapi_parameter_is_set(void * obj)
|
|
{
|
|
return jackctl_parameter_is_set((jackctl_parameter_t *)obj);
|
|
}
|
|
|
|
static bool controlapi_parameter_reset(void * obj)
|
|
{
|
|
return jackctl_parameter_reset((jackctl_parameter_t *)obj);
|
|
}
|
|
|
|
union jackctl_parameter_value controlapi_parameter_get_value(void * obj)
|
|
{
|
|
return jackctl_parameter_get_value((jackctl_parameter_t *)obj);
|
|
}
|
|
|
|
bool controlapi_parameter_set_value(void * obj, const union jackctl_parameter_value * value_ptr)
|
|
{
|
|
return jackctl_parameter_set_value((jackctl_parameter_t *)obj, value_ptr);
|
|
}
|
|
|
|
union jackctl_parameter_value controlapi_parameter_get_default_value(void * obj)
|
|
{
|
|
return jackctl_parameter_get_default_value((jackctl_parameter_t *)obj);
|
|
}
|
|
|
|
static struct jack_parameter_container * create_container(struct list_head * parent_list_ptr, const char * name)
|
|
{
|
|
struct jack_parameter_container * container_ptr;
|
|
|
|
container_ptr = malloc(sizeof(struct jack_parameter_container));
|
|
if (container_ptr == NULL)
|
|
{
|
|
jack_error("Ran out of memory trying to allocate struct jack_parameter_container");
|
|
goto fail;
|
|
}
|
|
|
|
container_ptr->name = strdup(name);
|
|
if (container_ptr->name == NULL)
|
|
{
|
|
jack_error("Ran out of memory trying to strdup parameter container name");
|
|
goto free;
|
|
}
|
|
|
|
container_ptr->leaf = false;
|
|
container_ptr->symlink = NULL;
|
|
container_ptr->obj = NULL;
|
|
INIT_LIST_HEAD(&container_ptr->children);
|
|
list_add_tail(&container_ptr->siblings, parent_list_ptr);
|
|
|
|
return container_ptr;
|
|
|
|
free:
|
|
free(container_ptr);
|
|
fail:
|
|
return NULL;
|
|
}
|
|
|
|
static bool add_controlapi_param(struct list_head * parent_list_ptr, jackctl_parameter_t * param)
|
|
{
|
|
struct jack_parameter * param_ptr;
|
|
uint32_t i;
|
|
|
|
param_ptr = malloc(sizeof(struct jack_parameter));
|
|
if (param_ptr == NULL)
|
|
{
|
|
jack_error("Ran out of memory trying to allocate struct jack_parameter");
|
|
goto fail;
|
|
}
|
|
|
|
param_ptr->ext = false;
|
|
param_ptr->obj = param;
|
|
param_ptr->vtable.is_set = controlapi_parameter_is_set;
|
|
param_ptr->vtable.reset = controlapi_parameter_reset;
|
|
param_ptr->vtable.get_value = controlapi_parameter_get_value;
|
|
param_ptr->vtable.set_value = controlapi_parameter_set_value;
|
|
param_ptr->vtable.get_default_value = controlapi_parameter_get_default_value;
|
|
|
|
param_ptr->type = jackctl_parameter_get_type(param);
|
|
param_ptr->name = jackctl_parameter_get_name(param);
|
|
param_ptr->short_decr = jackctl_parameter_get_short_description(param);
|
|
param_ptr->long_descr = jackctl_parameter_get_long_description(param);
|
|
|
|
if (jackctl_parameter_has_range_constraint(param))
|
|
{
|
|
param_ptr->constraint_flags = JACK_CONSTRAINT_FLAG_VALID;
|
|
param_ptr->constraint_range = true;
|
|
jackctl_parameter_get_range_constraint(param, ¶m_ptr->constraint.range.min, ¶m_ptr->constraint.range.max);
|
|
}
|
|
else if (jackctl_parameter_has_enum_constraint(param))
|
|
{
|
|
param_ptr->constraint_flags = JACK_CONSTRAINT_FLAG_VALID;
|
|
param_ptr->constraint_range = false;
|
|
param_ptr->constraint.enumeration.count = jackctl_parameter_get_enum_constraints_count(param);
|
|
param_ptr->constraint.enumeration.possible_values_array = malloc(sizeof(struct jack_parameter_enum) * param_ptr->constraint.enumeration.count);
|
|
if (param_ptr->constraint.enumeration.possible_values_array == NULL)
|
|
{
|
|
goto free;
|
|
}
|
|
|
|
for (i = 0; i < param_ptr->constraint.enumeration.count; i++)
|
|
{
|
|
param_ptr->constraint.enumeration.possible_values_array[i].value = jackctl_parameter_get_enum_constraint_value(param, i);
|
|
param_ptr->constraint.enumeration.possible_values_array[i].short_desc = jackctl_parameter_get_enum_constraint_description(param, i);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
param_ptr->constraint_flags = 0;
|
|
goto add;
|
|
}
|
|
|
|
if (jackctl_parameter_constraint_is_strict(param))
|
|
{
|
|
param_ptr->constraint_flags |= JACK_CONSTRAINT_FLAG_STRICT;
|
|
}
|
|
|
|
if (jackctl_parameter_constraint_is_fake_value(param))
|
|
{
|
|
param_ptr->constraint_flags |= JACK_CONSTRAINT_FLAG_FAKE_VALUE;
|
|
}
|
|
|
|
add:
|
|
list_add_tail(¶m_ptr->siblings, parent_list_ptr);
|
|
return true;
|
|
|
|
free:
|
|
free(param_ptr);
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
static void free_params(struct list_head * parent_list_ptr)
|
|
{
|
|
struct jack_parameter * param_ptr;
|
|
|
|
while (!list_empty(parent_list_ptr))
|
|
{
|
|
param_ptr = list_entry(parent_list_ptr->next, struct jack_parameter, siblings);
|
|
list_del(¶m_ptr->siblings);
|
|
|
|
if (param_ptr->ext)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ((param_ptr->constraint_flags & JACK_CONSTRAINT_FLAG_VALID) != 0 &&
|
|
!param_ptr->constraint_range &&
|
|
param_ptr->constraint.enumeration.possible_values_array != NULL)
|
|
{
|
|
free(param_ptr->constraint.enumeration.possible_values_array);
|
|
}
|
|
|
|
free(param_ptr);
|
|
}
|
|
}
|
|
|
|
static void free_containers(struct list_head * parent_list_ptr)
|
|
{
|
|
struct jack_parameter_container * container_ptr;
|
|
|
|
while (!list_empty(parent_list_ptr))
|
|
{
|
|
container_ptr = list_entry(parent_list_ptr->next, struct jack_parameter_container, siblings);
|
|
list_del(&container_ptr->siblings);
|
|
|
|
if (container_ptr->leaf)
|
|
{
|
|
free_params(&container_ptr->children);
|
|
}
|
|
else
|
|
{
|
|
free_containers(&container_ptr->children);
|
|
}
|
|
|
|
free(container_ptr->name);
|
|
free(container_ptr);
|
|
}
|
|
}
|
|
|
|
static struct jack_parameter_container * find_container(struct jack_parameter_container * parent_ptr, const char * const * address, int max_depth)
|
|
{
|
|
struct list_head * node_ptr;
|
|
struct jack_parameter_container * container_ptr;
|
|
|
|
if (max_depth == 0 || *address == NULL)
|
|
{
|
|
return parent_ptr;
|
|
}
|
|
|
|
if (parent_ptr->leaf)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (max_depth > 0)
|
|
{
|
|
max_depth--;
|
|
}
|
|
|
|
list_for_each(node_ptr, &parent_ptr->children)
|
|
{
|
|
container_ptr = list_entry(node_ptr, struct jack_parameter_container, siblings);
|
|
if (strcmp(container_ptr->name, *address) == 0)
|
|
{
|
|
if (container_ptr->symlink != NULL)
|
|
{
|
|
container_ptr = container_ptr->symlink;
|
|
}
|
|
|
|
return find_container(container_ptr, address + 1, max_depth);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static bool init_leaf(struct list_head * parent_list_ptr, const char * name, const JSList * params_list, void * obj)
|
|
{
|
|
struct jack_parameter_container * container_ptr;
|
|
|
|
container_ptr = create_container(parent_list_ptr, name);
|
|
if (container_ptr == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
container_ptr->leaf = true;
|
|
container_ptr->obj = obj;
|
|
|
|
while (params_list)
|
|
{
|
|
if (!add_controlapi_param(&container_ptr->children, params_list->data))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
params_list = jack_slist_next(params_list);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool init_engine(struct jack_params * params_ptr)
|
|
{
|
|
return init_leaf(¶ms_ptr->root.children, PTNODE_ENGINE, jackctl_server_get_parameters(params_ptr->server), NULL);
|
|
}
|
|
|
|
static bool init_drivers(struct jack_params * params_ptr)
|
|
{
|
|
const JSList * list;
|
|
struct jack_parameter_container * container_ptr;
|
|
|
|
container_ptr = create_container(¶ms_ptr->root.children, PTNODE_DRIVERS);
|
|
if (container_ptr == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
params_ptr->drivers_ptr = &container_ptr->children;
|
|
params_ptr->drivers_count = 0;
|
|
|
|
list = jackctl_server_get_drivers_list(params_ptr->server);
|
|
while (list)
|
|
{
|
|
if (!init_leaf(&container_ptr->children, jackctl_driver_get_name(list->data), jackctl_driver_get_parameters(list->data), list->data))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
params_ptr->drivers_count++;
|
|
|
|
list = jack_slist_next(list);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool init_internals(struct jack_params * params_ptr)
|
|
{
|
|
const JSList * list;
|
|
struct jack_parameter_container * container_ptr;
|
|
|
|
container_ptr = create_container(¶ms_ptr->root.children, PTNODE_INTERNALS);
|
|
if (container_ptr == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
list = jackctl_server_get_internals_list(params_ptr->server);
|
|
while (list)
|
|
{
|
|
if (!init_leaf(&container_ptr->children, jackctl_internal_get_name(list->data), jackctl_internal_get_parameters(list->data), NULL))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
list = jack_slist_next(list);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool init_driver(struct jack_params * params_ptr)
|
|
{
|
|
struct jack_parameter_container * container_ptr;
|
|
|
|
container_ptr = create_container(¶ms_ptr->root.children, PTNODE_DRIVER);
|
|
if (container_ptr == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
params_ptr->driver_ptr = container_ptr;
|
|
|
|
return true;
|
|
}
|
|
|
|
#define params_ptr ((struct jack_params *)obj)
|
|
|
|
static bool engine_driver_parameter_is_set(void * obj)
|
|
{
|
|
return params_ptr->driver_set;
|
|
}
|
|
|
|
static bool engine_driver_parameter_reset(void * obj)
|
|
{
|
|
if (!jack_params_set_driver(obj, DEFAULT_DRIVER))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
params_ptr->driver_set = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
union jackctl_parameter_value engine_driver_parameter_get_value(void * obj)
|
|
{
|
|
union jackctl_parameter_value value;
|
|
|
|
strcpy(value.str, params_ptr->driver_ptr->symlink->name);
|
|
|
|
return value;
|
|
}
|
|
|
|
bool engine_driver_parameter_set_value(void * obj, const union jackctl_parameter_value * value_ptr)
|
|
{
|
|
return jack_params_set_driver(obj, value_ptr->str);
|
|
}
|
|
|
|
union jackctl_parameter_value engine_driver_parameter_get_default_value(void * obj)
|
|
{
|
|
union jackctl_parameter_value value;
|
|
|
|
strcpy(value.str, DEFAULT_DRIVER);
|
|
|
|
return value;
|
|
}
|
|
|
|
#undef params_ptr
|
|
|
|
static bool add_engine_driver_enum_constraint(void * context, const char * name)
|
|
{
|
|
strcpy((*((struct jack_parameter_enum **)context))->value.str, name);
|
|
(*((struct jack_parameter_enum **)context))->short_desc = name;
|
|
(*((struct jack_parameter_enum **)context))++;
|
|
return true;
|
|
}
|
|
|
|
static bool init_engine_driver_parameter(struct jack_params * params_ptr)
|
|
{
|
|
struct jack_parameter * param_ptr;
|
|
const char * address[PARAM_ADDRESS_SIZE] = {PTNODE_ENGINE, NULL};
|
|
struct jack_parameter_container * engine_ptr;
|
|
struct jack_parameter_enum * possible_value;
|
|
|
|
engine_ptr = find_container(¶ms_ptr->root, address, PARAM_ADDRESS_SIZE);
|
|
if (engine_ptr == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
param_ptr = malloc(sizeof(struct jack_parameter));
|
|
if (param_ptr == NULL)
|
|
{
|
|
jack_error("Ran out of memory trying to allocate struct jack_parameter");
|
|
goto fail;
|
|
}
|
|
|
|
param_ptr->ext = false;
|
|
param_ptr->obj = params_ptr;
|
|
param_ptr->vtable.is_set = engine_driver_parameter_is_set;
|
|
param_ptr->vtable.reset = engine_driver_parameter_reset;
|
|
param_ptr->vtable.get_value = engine_driver_parameter_get_value;
|
|
param_ptr->vtable.set_value = engine_driver_parameter_set_value;
|
|
param_ptr->vtable.get_default_value = engine_driver_parameter_get_default_value;
|
|
|
|
param_ptr->type = JackParamString;
|
|
param_ptr->name = "driver";
|
|
param_ptr->short_decr = "Driver to use";
|
|
param_ptr->long_descr = "";
|
|
|
|
param_ptr->constraint_flags = JACK_CONSTRAINT_FLAG_VALID | JACK_CONSTRAINT_FLAG_STRICT | JACK_CONSTRAINT_FLAG_FAKE_VALUE;
|
|
param_ptr->constraint_range = false;
|
|
param_ptr->constraint.enumeration.count = params_ptr->drivers_count;
|
|
param_ptr->constraint.enumeration.possible_values_array = malloc(sizeof(struct jack_parameter_enum) * params_ptr->drivers_count);
|
|
if (param_ptr->constraint.enumeration.possible_values_array == NULL)
|
|
{
|
|
goto free;
|
|
}
|
|
|
|
address[0] = PTNODE_DRIVERS;
|
|
possible_value = param_ptr->constraint.enumeration.possible_values_array;
|
|
jack_params_iterate_container((jack_params_handle)params_ptr, address, add_engine_driver_enum_constraint, &possible_value);
|
|
|
|
list_add(¶m_ptr->siblings, &engine_ptr->children);
|
|
return true;
|
|
|
|
free:
|
|
free(param_ptr);
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
jack_params_handle jack_params_create(jackctl_server_t * server)
|
|
{
|
|
struct jack_params * params_ptr;
|
|
|
|
params_ptr = malloc(sizeof(struct jack_params));
|
|
if (params_ptr == NULL)
|
|
{
|
|
jack_error("Ran out of memory trying to allocate struct jack_params");
|
|
return NULL;
|
|
}
|
|
|
|
params_ptr->server = server;
|
|
INIT_LIST_HEAD(¶ms_ptr->root.children);
|
|
params_ptr->root.leaf = false;
|
|
params_ptr->root.name = NULL;
|
|
|
|
if (!init_engine(params_ptr) ||
|
|
!init_drivers(params_ptr) ||
|
|
!init_driver(params_ptr) ||
|
|
!init_engine_driver_parameter(params_ptr) ||
|
|
!jack_params_set_driver((jack_params_handle)params_ptr, DEFAULT_DRIVER) ||
|
|
!init_internals(params_ptr))
|
|
{
|
|
jack_params_destroy((jack_params_handle)params_ptr);
|
|
return NULL;
|
|
}
|
|
|
|
params_ptr->driver_set = false;
|
|
|
|
assert(strcmp(params_ptr->driver_ptr->symlink->name, DEFAULT_DRIVER) == 0);
|
|
|
|
return (jack_params_handle)params_ptr;
|
|
}
|
|
|
|
#define params_ptr ((struct jack_params *)params)
|
|
|
|
void jack_params_destroy(jack_params_handle params)
|
|
{
|
|
free_containers(¶ms_ptr->root.children);
|
|
free(params);
|
|
}
|
|
|
|
bool jack_params_set_driver(jack_params_handle params, const char * name)
|
|
{
|
|
struct list_head * node_ptr;
|
|
struct jack_parameter_container * container_ptr;
|
|
|
|
list_for_each(node_ptr, params_ptr->drivers_ptr)
|
|
{
|
|
container_ptr = list_entry(node_ptr, struct jack_parameter_container, siblings);
|
|
if (strcmp(container_ptr->name, name) == 0)
|
|
{
|
|
params_ptr->driver_ptr->symlink = container_ptr;
|
|
params_ptr->driver_set = true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
jackctl_driver_t * jack_params_get_driver(jack_params_handle params)
|
|
{
|
|
return params_ptr->driver_ptr->symlink->obj;
|
|
}
|
|
|
|
bool jack_params_check_address(jack_params_handle params, const char * const * address, bool want_leaf)
|
|
{
|
|
struct jack_parameter_container * container_ptr;
|
|
|
|
container_ptr = find_container(¶ms_ptr->root, address, PARAM_ADDRESS_SIZE);
|
|
if (container_ptr == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (want_leaf && !container_ptr->leaf)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool jack_params_is_leaf_container(jack_params_handle params, const char * const * address)
|
|
{
|
|
struct jack_parameter_container * container_ptr;
|
|
|
|
container_ptr = find_container(¶ms_ptr->root, address, PARAM_ADDRESS_SIZE);
|
|
if (container_ptr == NULL)
|
|
{
|
|
assert(false);
|
|
return false;
|
|
}
|
|
|
|
return container_ptr->leaf;
|
|
}
|
|
|
|
bool
|
|
jack_params_iterate_container(
|
|
jack_params_handle params,
|
|
const char * const * address,
|
|
bool (* callback)(void * context, const char * name),
|
|
void * context)
|
|
{
|
|
struct jack_parameter_container * container_ptr;
|
|
struct list_head * node_ptr;
|
|
const char * name;
|
|
|
|
container_ptr = find_container(¶ms_ptr->root, address, PARAM_ADDRESS_SIZE);
|
|
if (container_ptr == NULL)
|
|
{
|
|
assert(false);
|
|
return true;
|
|
}
|
|
|
|
list_for_each(node_ptr, &container_ptr->children)
|
|
{
|
|
if (container_ptr->leaf)
|
|
{
|
|
name = list_entry(node_ptr, struct jack_parameter, siblings)->name;
|
|
}
|
|
else
|
|
{
|
|
name = list_entry(node_ptr, struct jack_parameter_container, siblings)->name;
|
|
}
|
|
|
|
if (!callback(context, name))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
jack_params_iterate_params(
|
|
jack_params_handle params,
|
|
const char * const * address,
|
|
bool (* callback)(void * context, const struct jack_parameter * param_ptr),
|
|
void * context)
|
|
{
|
|
struct jack_parameter_container * container_ptr;
|
|
struct list_head * node_ptr;
|
|
struct jack_parameter * param_ptr;
|
|
|
|
container_ptr = find_container(¶ms_ptr->root, address, PARAM_ADDRESS_SIZE);
|
|
if (container_ptr == NULL || !container_ptr->leaf)
|
|
{
|
|
assert(false);
|
|
return true;
|
|
}
|
|
|
|
list_for_each(node_ptr, &container_ptr->children)
|
|
{
|
|
param_ptr = list_entry(node_ptr, struct jack_parameter, siblings);
|
|
if (!callback(context, param_ptr))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
const struct jack_parameter * jack_params_get_parameter(jack_params_handle params, const char * const * address)
|
|
{
|
|
int depth;
|
|
struct jack_parameter_container * container_ptr;
|
|
struct list_head * node_ptr;
|
|
struct jack_parameter * param_ptr;
|
|
|
|
for (depth = 0; depth < PARAM_ADDRESS_SIZE; depth++)
|
|
{
|
|
if (address[depth] == NULL)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
depth--;
|
|
|
|
container_ptr = find_container(¶ms_ptr->root, address, depth);
|
|
if (container_ptr == NULL || !container_ptr->leaf)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
list_for_each(node_ptr, &container_ptr->children)
|
|
{
|
|
param_ptr = list_entry(node_ptr, struct jack_parameter, siblings);
|
|
if (strcmp(param_ptr->name, address[depth]) == 0)
|
|
{
|
|
return param_ptr;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void jack_params_add_parameter(jack_params_handle params, const char * const * address, bool end, struct jack_parameter * param_ptr)
|
|
{
|
|
struct jack_parameter_container * container_ptr;
|
|
|
|
container_ptr = find_container(¶ms_ptr->root, address, PARAM_ADDRESS_SIZE);
|
|
if (container_ptr == NULL || !container_ptr->leaf)
|
|
{
|
|
assert(false);
|
|
return;
|
|
}
|
|
|
|
param_ptr->ext = true;
|
|
|
|
if (end)
|
|
{
|
|
list_add_tail(¶m_ptr->siblings, &container_ptr->children);
|
|
}
|
|
else
|
|
{
|
|
list_add(¶m_ptr->siblings, &container_ptr->children);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#undef params_ptr
|