alsa-lib/src/conf.c

1113 lines
22 KiB
C
Raw Normal View History

2001-01-17 11:00:32 +00:00
/*
* Configuration helper functions
* Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
*
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
2001-02-07 11:34:33 +00:00
#define _snd_config_iterator list_head
2001-01-17 11:00:32 +00:00
#include <stdarg.h>
#include <sys/stat.h>
#include "local.h"
#include "list.h"
2001-02-07 11:34:33 +00:00
struct _snd_config {
char *id;
snd_config_type_t type;
union {
long integer;
char *string;
double real;
struct {
struct list_head fields;
int join;
} compound;
} u;
struct list_head list;
snd_config_t *father;
};
2001-01-17 11:00:32 +00:00
#define SYS_ASOUNDRC "/etc/asound.conf"
#define USR_ASOUNDRC ".asoundrc"
struct filedesc {
char *name;
snd_input_t *in;
unsigned int line, column;
struct filedesc *next;
};
typedef struct {
struct filedesc *current;
int unget;
int ch;
enum {
UNTERMINATED_STRING = -1,
UNTERMINATED_QUOTE = -2,
UNEXPECTED_CHAR = -3,
UNEXPECTED_EOF = -4,
} error;
} input_t;
static int get_char(input_t *input)
{
int c;
struct filedesc *fd;
if (input->unget) {
input->unget = 0;
return input->ch;
}
again:
fd = input->current;
c = snd_input_getc(fd->in);
switch (c) {
case '\n':
fd->column = 0;
fd->line++;
break;
case '\t':
fd->column += 8 - fd->column % 8;
break;
case EOF:
if (fd->next) {
snd_input_close(fd->in);
free(fd->name);
input->current = fd->next;
free(fd);
goto again;
}
break;
default:
fd->column++;
break;
}
return c;
}
static void unget_char(int c, input_t *input)
{
assert(!input->unget);
input->ch = c;
input->unget = 1;
}
static int get_delimstring(char **string, int delim, input_t *input);
static int get_char_skip_comments(input_t *input)
{
int c;
while (1) {
c = get_char(input);
if (c == '<') {
char *file;
snd_input_t *in;
struct filedesc *fd;
int err = get_delimstring(&file, '>', input);
if (err < 0)
return err;
err = snd_input_stdio_open(&in, file);
if (err < 0)
return err;
fd = malloc(sizeof(*fd));
fd->name = file;
fd->in = in;
fd->next = input->current;
fd->line = 1;
fd->column = 0;
input->current = fd;
continue;
}
if (c != '#')
break;
while (1) {
c = get_char(input);
if (c == EOF)
return c;
if (c == '\n')
break;
}
}
return c;
}
static int get_nonwhite(input_t *input)
{
int c;
while (1) {
c = get_char_skip_comments(input);
switch (c) {
case ' ':
case '\f':
case '\t':
case '\n':
case '\r':
break;
default:
return c;
}
}
}
static int get_quotedchar(input_t *input)
{
int c;
c = get_char(input);
switch (c) {
case 'n':
return '\n';
case 't':
return '\t';
case 'v':
return '\v';
case 'b':
return '\b';
case 'r':
return '\r';
case 'f':
return '\f';
case '0' ... '7':
{
int num = c - '0';
int i = 1;
do {
c = get_char(input);
if (c < '0' || c > '7') {
unget_char(c, input);
break;
}
num = num * 8 + c - '0';
i++;
} while (i < 3);
return num;
}
default:
return c;
}
}
static int get_freestring(char **string, int id, input_t *input)
{
const size_t bufsize = 256;
char _buf[bufsize];
char *buf = _buf;
size_t alloc = bufsize;
size_t idx = 0;
int c;
while (1) {
c = get_char(input);
switch (c) {
case '.':
if (!id)
break;
case ' ':
case '\f':
case '\t':
case '\n':
case '\r':
case EOF:
case '=':
case '{':
case '}':
case ',':
case ';':
case '\'':
case '"':
case '\\':
case '#':
{
char *s = malloc(idx + 1);
unget_char(c, input);
memcpy(s, buf, idx);
s[idx] = '\0';
*string = s;
return 0;
}
default:
break;
}
if (idx >= alloc) {
size_t old_alloc = alloc;
alloc += bufsize;
if (old_alloc == bufsize) {
buf = malloc(alloc);
memcpy(buf, _buf, old_alloc);
} else
buf = realloc(buf, alloc);
}
buf[idx++] = c;
}
return 0;
}
static int get_delimstring(char **string, int delim, input_t *input)
{
const size_t bufsize = 256;
char _buf[bufsize];
char *buf = _buf;
size_t alloc = bufsize;
size_t idx = 0;
int c;
while (1) {
c = get_char(input);
switch (c) {
case EOF:
input->error = UNTERMINATED_STRING;
return -EINVAL;
case '\\':
c = get_quotedchar(input);
if (c < 0) {
input->error = UNTERMINATED_QUOTE;
return -EINVAL;
}
break;
default:
if (c == delim) {
char *s = malloc(idx + 1);
memcpy(s, buf, idx);
s[idx] = '\0';
*string = s;
return 0;
}
}
if (idx >= alloc) {
size_t old_alloc = alloc;
alloc += bufsize;
if (old_alloc == bufsize) {
buf = malloc(alloc);
memcpy(buf, _buf, old_alloc);
} else
buf = realloc(buf, alloc);
}
buf[idx++] = c;
}
return 0;
}
/* Return 0 for free string, 1 for delimited string */
static int get_string(char **string, int id, input_t *input)
{
int c = get_nonwhite(input);
int err;
switch (c) {
case EOF:
input->error = UNEXPECTED_EOF;
return -EINVAL;
case '=':
#if 0
/* I'm not sure to want unnamed fields */
*string = 0;
return 0;
#endif
case '.':
case '{':
case '}':
case ',':
case ';':
input->error = UNEXPECTED_CHAR;
return -EINVAL;
case '\'':
case '"':
err = get_delimstring(string, c, input);
if (err < 0)
return err;
return 1;
default:
unget_char(c, input);
err = get_freestring(string, id, input);
if (err < 0)
return err;
return 0;
}
}
2001-02-07 11:34:33 +00:00
snd_config_type_t snd_config_get_type(snd_config_t *config)
{
return config->type;
}
const char *snd_config_get_id(snd_config_t *config)
2001-02-07 11:34:33 +00:00
{
return config->id;
}
2001-01-17 11:00:32 +00:00
static int _snd_config_make(snd_config_t **config, char *id,
snd_config_type_t type)
{
snd_config_t *n;
n = calloc(1, sizeof(*n));
if (n == NULL) {
if (id)
free(id);
return -ENOMEM;
}
n->id = id;
n->type = type;
if (type == SND_CONFIG_TYPE_COMPOUND)
INIT_LIST_HEAD(&n->u.compound.fields);
*config = n;
return 0;
}
static int _snd_config_make_add(snd_config_t **config, char *id,
snd_config_type_t type, snd_config_t *father)
{
snd_config_t *n;
int err;
assert(father->type == SND_CONFIG_TYPE_COMPOUND);
err = _snd_config_make(&n, id, type);
if (err < 0)
return err;
n->father = father;
list_add_tail(&n->list, &father->u.compound.fields);
*config = n;
return 0;
}
static int _snd_config_search(snd_config_t *config, const char *id, int len, snd_config_t **result)
2001-01-17 11:00:32 +00:00
{
snd_config_iterator_t i, next;
snd_config_for_each(i, next, config) {
2001-02-07 11:34:33 +00:00
snd_config_t *n = snd_config_iterator_entry(i);
2001-01-17 11:00:32 +00:00
if (len < 0) {
if (strcmp(n->id, id) == 0) {
*result = n;
return 0;
}
} else {
if (strlen(n->id) != (size_t) len)
continue;
if (memcmp(n->id, id, len) == 0) {
*result = n;
return 0;
}
}
}
return -ENOENT;
}
static int parse_defs(snd_config_t *father, input_t *input);
static int parse_def(snd_config_t *father, input_t *input)
{
char *id;
int c;
int err;
snd_config_t *n;
enum {MERGE, NOCREATE, REMOVE} mode;
while (1) {
#if 0
c = get_nonwhite(input);
switch (c) {
case '?':
mode = NOCREATE;
break;
case '!':
mode = REMOVE;
break;
default:
mode = MERGE;
unget_char(c, input);
}
#else
mode = MERGE;
#endif
err = get_string(&id, 1, input);
if (err < 0)
return err;
c = get_nonwhite(input);
if (c != '.')
break;
if (_snd_config_search(father, id, -1, &n) == 0) {
if (mode != REMOVE) {
if (n->type != SND_CONFIG_TYPE_COMPOUND) {
ERR("%s is not a compound", id);
return -EINVAL;
}
n->u.compound.join = 1;
father = n;
free(id);
continue;
}
snd_config_delete(n);
}
if (mode == NOCREATE) {
ERR("%s does not exists", id);
free(id);
return -ENOENT;
}
err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_COMPOUND, father);
if (err < 0)
return err;
n->u.compound.join = 1;
father = n;
}
if (c == '=' )
c = get_nonwhite(input);
if (_snd_config_search(father, id, -1, &n) == 0) {
if (mode == REMOVE) {
snd_config_delete(n);
n = NULL;
}
else
free(id);
} else {
n = NULL;
if (mode == NOCREATE) {
ERR("%s does not exists", id);
free(id);
return -ENOENT;
}
}
switch (c) {
case '{':
{
if (n) {
if (n->type != SND_CONFIG_TYPE_COMPOUND) {
ERR("%s is not a compound", id);
return -EINVAL;
}
} else {
err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_COMPOUND, father);
if (err < 0)
return err;
}
err = parse_defs(n, input);
if (err < 0) {
snd_config_delete(n);
return err;
}
c = get_nonwhite(input);
if (c != '}') {
snd_config_delete(n);
input->error = (c == EOF ? UNEXPECTED_EOF : UNEXPECTED_CHAR);
return -EINVAL;
}
break;
}
default:
{
char *s;
unget_char(c, input);
err = get_string(&s, 0, input);
if (err < 0)
return err;
if (!err && ((s[0] >= '0' && s[0] <= '9') || s[0] == '-')) {
char *ptr;
long i;
errno = 0;
i = strtol(s, &ptr, 0);
if (*ptr == '.' || errno != 0) {
double r;
errno = 0;
r = strtod(s, &ptr);
if (errno == 0) {
free(s);
if (n) {
if (n->type != SND_CONFIG_TYPE_REAL) {
ERR("%s is not a real", id);
return -EINVAL;
}
} else {
err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_REAL, father);
if (err < 0)
return err;
}
n->u.real = r;
break;
}
} else if (*ptr == '\0') {
free(s);
if (n) {
if (n->type != SND_CONFIG_TYPE_INTEGER) {
ERR("%s is not an integer", id);
return -EINVAL;
}
} else {
err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER, father);
if (err < 0)
return err;
}
n->u.integer = i;
break;
}
}
if (n) {
if (n->type != SND_CONFIG_TYPE_STRING) {
ERR("%s is not a string", id);
free(s);
return -EINVAL;
}
} else {
err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_STRING, father);
if (err < 0)
return err;
}
if (n->u.string)
free(n->u.string);
n->u.string = s;
}
}
c = get_nonwhite(input);
switch (c) {
case ';':
case ',':
break;
default:
unget_char(c, input);
}
return err;
}
static int parse_defs(snd_config_t *father, input_t *input)
{
while (1) {
int c = get_nonwhite(input);
int err;
if (c == EOF)
return 0;
unget_char(c, input);
if (c == '}')
return 0;
err = parse_def(father, input);
if (err < 0)
return err;
}
return 0;
}
int snd_config_top(snd_config_t **config)
{
assert(config);
return _snd_config_make(config, 0, SND_CONFIG_TYPE_COMPOUND);
}
int snd_config_load(snd_config_t *config, snd_input_t *in)
{
int err;
input_t input;
struct filedesc *fd;
assert(config && in);
fd = malloc(sizeof(*fd));
fd->name = NULL;
fd->in = in;
fd->line = 1;
fd->column = 0;
fd->next = NULL;
input.current = fd;
input.unget = 0;
input.error = 0;
err = parse_defs(config, &input);
fd = input.current;
if (err < 0) {
if (input.error < 0) {
char *str;
switch (input.error) {
case UNTERMINATED_STRING:
str = "Unterminated string";
break;
case UNTERMINATED_QUOTE:
str = "Unterminated quote";
break;
case UNEXPECTED_CHAR:
str = "Unexpected char";
break;
case UNEXPECTED_EOF:
str = "Unexpected end of file";
break;
default:
assert(0);
break;
}
ERR("%s:%d:%d:%s", fd->name ? fd->name : "",
fd->line, fd->column, str);
}
snd_config_delete(config);
goto _end;
}
if (get_char(&input) != EOF) {
ERR("%s:%d:%d:Unexpected }", fd->name ? fd->name : "",
fd->line, fd->column);
snd_config_delete(config);
err = -EINVAL;
goto _end;
}
_end:
while (fd->next) {
snd_input_close(fd->in);
free(fd->name);
free(fd);
fd = fd->next;
}
free(fd);
return err;
}
int snd_config_add(snd_config_t *father, snd_config_t *leaf)
{
snd_config_iterator_t i, next;
2001-01-17 11:00:32 +00:00
assert(father && leaf);
snd_config_for_each(i, next, father) {
2001-02-07 11:34:33 +00:00
snd_config_t *n = snd_config_iterator_entry(i);
2001-01-17 11:00:32 +00:00
if (strcmp(leaf->id, n->id) == 0)
return -EEXIST;
}
leaf->father = father;
list_add_tail(&leaf->list, &father->u.compound.fields);
return 0;
}
int snd_config_delete(snd_config_t *config)
{
assert(config);
switch (snd_enum_to_int(config->type)) {
2001-01-17 11:00:32 +00:00
case SND_CONFIG_TYPE_COMPOUND:
{
int err;
struct list_head *i;
i = config->u.compound.fields.next;
while (i != &config->u.compound.fields) {
struct list_head *nexti = i->next;
2001-02-07 11:34:33 +00:00
snd_config_t *leaf = snd_config_iterator_entry(i);
2001-01-17 11:00:32 +00:00
err = snd_config_delete(leaf);
if (err < 0)
return err;
i = nexti;
}
break;
}
case SND_CONFIG_TYPE_STRING:
if (config->u.string)
free(config->u.string);
break;
default:
break;
}
if (config->father)
list_del(&config->list);
return 0;
}
int snd_config_make(snd_config_t **config, const char *id,
2001-01-17 11:00:32 +00:00
snd_config_type_t type)
{
char *id1;
assert(config);
if (id) {
id1 = strdup(id);
if (!id1)
return -ENOMEM;
} else
id1 = NULL;
return _snd_config_make(config, id1, type);
}
2001-02-07 11:34:33 +00:00
int snd_config_make_integer(snd_config_t **config, const char *id)
2001-01-17 11:00:32 +00:00
{
return snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER);
}
2001-02-07 11:34:33 +00:00
int snd_config_make_real(snd_config_t **config, const char *id)
2001-01-17 11:00:32 +00:00
{
return snd_config_make(config, id, SND_CONFIG_TYPE_REAL);
}
2001-02-07 11:34:33 +00:00
int snd_config_make_string(snd_config_t **config, const char *id)
2001-01-17 11:00:32 +00:00
{
return snd_config_make(config, id, SND_CONFIG_TYPE_STRING);
}
2001-02-07 11:34:33 +00:00
int snd_config_make_compound(snd_config_t **config, const char *id,
2001-01-17 11:00:32 +00:00
int join)
{
int err;
err = snd_config_make(config, id, SND_CONFIG_TYPE_COMPOUND);
if (err < 0)
return err;
(*config)->u.compound.join = join;
return 0;
}
2001-02-07 11:34:33 +00:00
int snd_config_set_integer(snd_config_t *config, long value)
2001-01-17 11:00:32 +00:00
{
assert(config);
if (config->type != SND_CONFIG_TYPE_INTEGER)
return -EINVAL;
config->u.integer = value;
return 0;
}
2001-02-07 11:34:33 +00:00
int snd_config_set_real(snd_config_t *config, double value)
2001-01-17 11:00:32 +00:00
{
assert(config);
if (config->type != SND_CONFIG_TYPE_REAL)
return -EINVAL;
config->u.real = value;
return 0;
}
2001-02-07 11:34:33 +00:00
int snd_config_set_string(snd_config_t *config, const char *value)
2001-01-17 11:00:32 +00:00
{
assert(config);
if (config->type != SND_CONFIG_TYPE_STRING)
return -EINVAL;
if (config->u.string)
free(config->u.string);
config->u.string = strdup(value);
if (!config->u.string)
return -ENOMEM;
return 0;
}
2001-02-07 11:34:33 +00:00
int snd_config_get_integer(snd_config_t *config, long *ptr)
2001-01-17 11:00:32 +00:00
{
assert(config && ptr);
if (config->type != SND_CONFIG_TYPE_INTEGER)
return -EINVAL;
*ptr = config->u.integer;
return 0;
}
2001-02-07 11:34:33 +00:00
int snd_config_get_real(snd_config_t *config, double *ptr)
2001-01-17 11:00:32 +00:00
{
assert(config && ptr);
if (config->type != SND_CONFIG_TYPE_REAL)
return -EINVAL;
*ptr = config->u.real;
return 0;
}
2001-02-07 11:34:33 +00:00
int snd_config_get_string(snd_config_t *config, const char **ptr)
2001-01-17 11:00:32 +00:00
{
assert(config && ptr);
if (config->type != SND_CONFIG_TYPE_STRING)
return -EINVAL;
*ptr = config->u.string;
return 0;
}
void string_print(char *str, int id, snd_output_t *out)
{
unsigned char *p = str;
if (!id) {
switch (*p) {
2001-02-09 11:20:31 +00:00
case 0:
assert(0);
break;
2001-01-17 11:00:32 +00:00
case '0' ... '9':
case '-':
goto quoted;
}
}
2001-02-09 11:20:31 +00:00
if (!*p) {
snd_output_puts(out, "''");
return;
}
2001-01-17 11:00:32 +00:00
loop:
switch (*p) {
case 0:
goto nonquoted;
case 1 ... 31:
case 127 ... 255:
case ' ':
case '=':
case '.':
case '{':
case '}':
case ';':
case ',':
case '\'':
case '"':
goto quoted;
default:
p++;
goto loop;
}
nonquoted:
snd_output_puts(out, str);
return;
quoted:
snd_output_putc(out, '\'');
p = str;
while (*p) {
int c;
c = *p;
switch (c) {
case '\n':
snd_output_putc(out, '\\');
snd_output_putc(out, 'n');
break;
case '\t':
snd_output_putc(out, '\\');
snd_output_putc(out, 't');
break;
case '\v':
snd_output_putc(out, '\\');
snd_output_putc(out, 'v');
break;
case '\b':
snd_output_putc(out, '\\');
snd_output_putc(out, 'b');
break;
case '\r':
snd_output_putc(out, '\\');
snd_output_putc(out, 'r');
break;
case '\f':
snd_output_putc(out, '\\');
snd_output_putc(out, 'f');
break;
case '\'':
snd_output_putc(out, '\\');
snd_output_putc(out, c);
break;
case 32 ... '\'' - 1:
case '\'' + 1 ... 126:
snd_output_putc(out, c);
break;
default:
snd_output_printf(out, "\\%04o", c);
break;
}
p++;
}
snd_output_putc(out, '\'');
}
static int _snd_config_save_leaves(snd_config_t *config, snd_output_t *out, unsigned int level, unsigned int joins);
static int _snd_config_save_leaf(snd_config_t *n, snd_output_t *out,
unsigned int level)
{
int err;
unsigned int k;
switch (snd_enum_to_int(n->type)) {
2001-01-17 11:00:32 +00:00
case SND_CONFIG_TYPE_INTEGER:
snd_output_printf(out, "%ld", n->u.integer);
break;
case SND_CONFIG_TYPE_REAL:
snd_output_printf(out, "%16g", n->u.real);
break;
case SND_CONFIG_TYPE_STRING:
string_print(n->u.string, 0, out);
break;
case SND_CONFIG_TYPE_COMPOUND:
snd_output_putc(out, '{');
snd_output_putc(out, '\n');
err = _snd_config_save_leaves(n, out, level + 1, 0);
if (err < 0)
return err;
for (k = 0; k < level; ++k) {
snd_output_putc(out, '\t');
}
snd_output_putc(out, '}');
break;
}
return 0;
}
static void id_print(snd_config_t *n, snd_output_t *out, unsigned int joins)
{
if (joins > 0) {
assert(n->father);
id_print(n->father, out, joins - 1);
snd_output_putc(out, '.');
}
string_print(n->id, 1, out);
}
static int _snd_config_save_leaves(snd_config_t *config, snd_output_t *out, unsigned int level, unsigned int joins)
{
unsigned int k;
int err;
snd_config_iterator_t i, next;
2001-01-17 11:00:32 +00:00
assert(config && out);
snd_config_for_each(i, next, config) {
2001-02-07 11:34:33 +00:00
snd_config_t *n = snd_config_iterator_entry(i);
2001-01-17 11:00:32 +00:00
if (n->type == SND_CONFIG_TYPE_COMPOUND &&
n->u.compound.join) {
err = _snd_config_save_leaves(n, out, level, joins + 1);
if (err < 0)
return err;
continue;
}
for (k = 0; k < level; ++k) {
snd_output_putc(out, '\t');
}
id_print(n, out, joins);
snd_output_putc(out, ' ');
snd_output_putc(out, '=');
snd_output_putc(out, ' ');
err = _snd_config_save_leaf(n, out, level);
if (err < 0)
return err;
snd_output_putc(out, ';');
snd_output_putc(out, '\n');
}
return 0;
}
int snd_config_save(snd_config_t *config, snd_output_t *out)
{
assert(config && out);
return _snd_config_save_leaves(config, out, 0, 0);
}
int snd_config_search(snd_config_t *config, const char *key, snd_config_t **result)
2001-01-17 11:00:32 +00:00
{
assert(config && key && result);
while (1) {
snd_config_t *n;
int err;
const char *p = strchr(key, '.');
2001-01-17 11:00:32 +00:00
if (config->type != SND_CONFIG_TYPE_COMPOUND)
return -ENOENT;
if (p) {
err = _snd_config_search(config, key, p - key, &n);
if (err < 0)
return err;
config = n;
key = p + 1;
} else
return _snd_config_search(config, key, -1, result);
}
}
int snd_config_searchv(snd_config_t *config,
snd_config_t **result, ...)
{
snd_config_t *n;
va_list arg;
assert(config && result);
va_start(arg, result);
while (1) {
const char *k = va_arg(arg, const char *);
2001-01-17 11:00:32 +00:00
int err;
if (!k)
break;
if (config->type != SND_CONFIG_TYPE_COMPOUND)
return -ENOENT;
err = _snd_config_search(config, k, -1, &n);
if (err < 0)
return err;
config = n;
}
va_end(arg);
*result = n;
return 0;
}
snd_config_t *snd_config = 0;
static dev_t sys_asoundrc_device;
static ino_t sys_asoundrc_inode;
static time_t sys_asoundrc_mtime;
static dev_t usr_asoundrc_device;
static ino_t usr_asoundrc_inode;
static time_t usr_asoundrc_mtime;
int snd_config_update()
{
int err;
char *usr_asoundrc = NULL;
char *home = getenv("HOME");
struct stat usr_st, sys_st;
int reload;
snd_input_t *in;
if (home) {
size_t len = strlen(home);
size_t len1 = strlen(USR_ASOUNDRC);
usr_asoundrc = alloca(len + len1 + 2);
memcpy(usr_asoundrc, home, len);
usr_asoundrc[len] = '/';
memcpy(usr_asoundrc + len + 1, USR_ASOUNDRC, len1);
usr_asoundrc[len + 1 + len1] = '\0';
}
reload = (snd_config == NULL);
if (stat(SYS_ASOUNDRC, &sys_st) == 0 &&
(sys_st.st_dev != sys_asoundrc_device ||
sys_st.st_ino != sys_asoundrc_inode ||
sys_st.st_mtime != sys_asoundrc_mtime))
reload = 1;
if (stat(usr_asoundrc, &usr_st) == 0 &&
(usr_st.st_dev != usr_asoundrc_device ||
usr_st.st_ino != usr_asoundrc_inode ||
usr_st.st_mtime != usr_asoundrc_mtime))
reload = 1;
if (!reload)
return 0;
if (snd_config) {
err = snd_config_delete(snd_config);
if (err < 0)
return err;
snd_config = 0;
}
err = snd_config_top(&snd_config);
if (err < 0)
return err;
err = snd_input_stdio_open(&in, SYS_ASOUNDRC);
if (err >= 0) {
err = snd_config_load(snd_config, in);
snd_input_close(in);
if (err < 0) {
snd_config = NULL;
return err;
}
sys_asoundrc_device = sys_st.st_dev;
sys_asoundrc_inode = sys_st.st_ino;
sys_asoundrc_mtime = sys_st.st_mtime;
}
err = snd_input_stdio_open(&in, usr_asoundrc);
if (err >= 0) {
err = snd_config_load(snd_config, in);
snd_input_close(in);
if (err < 0) {
snd_config = NULL;
return err;
}
usr_asoundrc_device = usr_st.st_dev;
usr_asoundrc_inode = usr_st.st_ino;
usr_asoundrc_mtime = usr_st.st_mtime;
}
return 0;
}
2001-02-07 11:34:33 +00:00
snd_config_iterator_t snd_config_iterator_first(snd_config_t *node)
{
assert(node->type == SND_CONFIG_TYPE_COMPOUND);
return node->u.compound.fields.next;
}
snd_config_iterator_t snd_config_iterator_next(snd_config_iterator_t iterator)
{
return iterator->next;
}
snd_config_iterator_t snd_config_iterator_end(snd_config_t *node)
{
assert(node->type == SND_CONFIG_TYPE_COMPOUND);
return &node->u.compound.fields;
}
snd_config_t *snd_config_iterator_entry(snd_config_iterator_t iterator)
{
return list_entry(iterator, snd_config_t, list);
}