📄 init_parse.c
字号:
/* * Advanced Linux Sound Architecture Control Program - Parse initialization files * Copyright (c) by Jaroslav Kysela <perex@perex.cz>, * Greg Kroah-Hartman <greg@kroah.com>, * Kay Sievers <kay.sievers@vrfy.org> * * * 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, 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#include <stdlib.h>#include <stdio.h>#include <stddef.h>#include <unistd.h>#include <string.h>#include <fcntl.h>#include <ctype.h>#include <errno.h>#include <fnmatch.h>#include <sys/stat.h>#include <sys/un.h>#include <sys/wait.h>#include <sys/select.h>#include <sys/types.h>#include <dirent.h>#include <math.h>#include <alsa/asoundlib.h>#include "aconfig.h"#include "alsactl.h"#include "list.h"#define PATH_SIZE 512#define NAME_SIZE 128#define EJUSTRETURN 0x7fffffffenum key_op { KEY_OP_UNSET, KEY_OP_MATCH, KEY_OP_NOMATCH, KEY_OP_ADD, KEY_OP_ASSIGN, KEY_OP_ASSIGN_FINAL};struct pair { char *key; char *value; struct pair *next;};struct space { struct pair *pairs; char *rootdir; char *go_to; char *program_result; const char *filename; int linenum; int log_run; int exit_code; int quit; unsigned int ctl_id_changed; snd_hctl_t *ctl_handle; snd_ctl_card_info_t *ctl_card_info; snd_ctl_elem_id_t *ctl_id; snd_ctl_elem_info_t *ctl_info; snd_ctl_elem_value_t *ctl_value;};static void Perror(struct space *space, const char *fmt, ...){ va_list arg; va_start(arg, fmt); fprintf(stderr, "%s:%i: ", space->filename, space->linenum); vfprintf(stderr, fmt, arg); putc('\n', stderr); va_end(arg);}#include "init_sysdeps.c"#include "init_utils_string.c"#include "init_utils_run.c"#include "init_sysfs.c"static void free_space(struct space *space){ struct pair *pair = space->pairs; struct pair *next = pair; while (next) { pair = next; next = pair->next; free(pair->value); free(pair->key); free(pair); } space->pairs = NULL; if (space->ctl_value) { snd_ctl_elem_value_free(space->ctl_value); space->ctl_value = NULL; } if (space->ctl_info) { snd_ctl_elem_info_free(space->ctl_info); space->ctl_info = NULL; } if (space->ctl_id) { snd_ctl_elem_id_free(space->ctl_id); space->ctl_id = NULL; } if (space->ctl_card_info) { snd_ctl_card_info_free(space->ctl_card_info); space->ctl_card_info = NULL; } if (space->ctl_handle) { snd_hctl_close(space->ctl_handle); space->ctl_handle = NULL; } if (space->rootdir) free(space->rootdir); if (space->program_result) free(space->program_result); if (space->go_to) free(space->go_to); free(space);}static struct pair *value_find(struct space *space, const char *key){ struct pair *pair = space->pairs; while (pair && strcmp(pair->key, key) != 0) pair = pair->next; return pair;}static int value_set(struct space *space, const char *key, const char *value){ struct pair *pair; pair = value_find(space, key); if (pair) { free(pair->value); pair->value = strdup(value); if (pair->value == NULL) return -ENOMEM; } else { pair = malloc(sizeof(struct pair)); if (pair == NULL) return -ENOMEM; pair->key = strdup(key); if (pair->key == NULL) { free(pair); return -ENOMEM; } pair->value = strdup(value); if (pair->value == NULL) { free(pair->key); free(pair); return -ENOMEM; } pair->next = space->pairs; space->pairs = pair; } return 0;}static int init_space(struct space **space, int card){ struct space *res; char device[16]; int err; res = calloc(1, sizeof(struct space)); if (res == NULL) return -ENOMEM; res->ctl_id_changed = ~0; res->linenum = -1; sprintf(device, "hw:%u", card); err = snd_hctl_open(&res->ctl_handle, device, 0); if (err < 0) goto error; err = snd_hctl_load(res->ctl_handle); if (err < 0) goto error; err = snd_ctl_card_info_malloc(&res->ctl_card_info); if (err < 0) goto error; err = snd_ctl_card_info(snd_hctl_ctl(res->ctl_handle), res->ctl_card_info); if (err < 0) goto error; err = snd_ctl_elem_id_malloc(&res->ctl_id); if (err < 0) goto error; err = snd_ctl_elem_info_malloc(&res->ctl_info); if (err < 0) goto error; err = snd_ctl_elem_value_malloc(&res->ctl_value); if (err < 0) goto error; *space = res; return 0; error: free_space(res); return err;}static const char *cardinfo_get(struct space *space, const char *attr){ if (strncasecmp(attr, "CARD", 4) == 0) { static char res[16]; sprintf(res, "%u", snd_ctl_card_info_get_card(space->ctl_card_info)); return res; } if (strncasecmp(attr, "ID", 2) == 0) return snd_ctl_card_info_get_id(space->ctl_card_info); if (strncasecmp(attr, "DRIVER", 6) == 0) return snd_ctl_card_info_get_driver(space->ctl_card_info); if (strncasecmp(attr, "NAME", 4) == 0) return snd_ctl_card_info_get_name(space->ctl_card_info); if (strncasecmp(attr, "LONGNAME", 8) == 0) return snd_ctl_card_info_get_longname(space->ctl_card_info); if (strncasecmp(attr, "MIXERNAME", 9) == 0) return snd_ctl_card_info_get_mixername(space->ctl_card_info); if (strncasecmp(attr, "COMPONENTS", 10) == 0) return snd_ctl_card_info_get_components(space->ctl_card_info); Perror(space, "unknown cardinfo{} attribute '%s'", attr); return NULL;}static int check_id_changed(struct space *space, unsigned int what){ snd_hctl_elem_t *elem; int err; if ((space->ctl_id_changed & what & 1) != 0) { snd_ctl_elem_id_set_numid(space->ctl_id, 0); elem = snd_hctl_find_elem(space->ctl_handle, space->ctl_id); if (!elem) return -ENOENT; err = snd_hctl_elem_info(elem, space->ctl_info); if (err == 0) space->ctl_id_changed &= ~1; return err; } if ((space->ctl_id_changed & what & 2) != 0) { snd_ctl_elem_id_set_numid(space->ctl_id, 0); elem = snd_hctl_find_elem(space->ctl_handle, space->ctl_id); if (!elem) return -ENOENT; err = snd_hctl_elem_read(elem, space->ctl_value); if (err == 0) space->ctl_id_changed &= ~2; return err; } return 0;}static const char *get_ctl_value(struct space *space){ snd_ctl_elem_type_t type; unsigned int idx, count; static char res[1024], tmp[16]; static const char hex[] = "0123456789abcdef"; char *pos; const char *pos1; type = snd_ctl_elem_info_get_type(space->ctl_info); count = snd_ctl_elem_info_get_count(space->ctl_info); res[0] = '\0'; switch (type) { case SND_CTL_ELEM_TYPE_BOOLEAN: for (idx = 0; idx < count; idx++) { if (idx > 0) strlcat(res, ",", sizeof(res)); strlcat(res, snd_ctl_elem_value_get_boolean(space->ctl_value, idx) ? "on" : "off", sizeof(res)); } break; case SND_CTL_ELEM_TYPE_INTEGER: for (idx = 0; idx < count; idx++) { if (idx > 0) strlcat(res, ",", sizeof(res)); snprintf(tmp, sizeof(tmp), "%li", snd_ctl_elem_value_get_integer(space->ctl_value, idx)); strlcat(res, tmp, sizeof(res)); } break; case SND_CTL_ELEM_TYPE_INTEGER64: for (idx = 0; idx < count; idx++) { if (idx > 0) strlcat(res, ",", sizeof(res)); snprintf(tmp, sizeof(tmp), "%lli", snd_ctl_elem_value_get_integer64(space->ctl_value, idx)); strlcat(res, tmp, sizeof(res)); } break; case SND_CTL_ELEM_TYPE_ENUMERATED: for (idx = 0; idx < count; idx++) { if (idx > 0) strlcat(res, ",", sizeof(res)); snprintf(tmp, sizeof(tmp), "%u", snd_ctl_elem_value_get_enumerated(space->ctl_value, idx)); strlcat(res, tmp, sizeof(res)); } break; case SND_CTL_ELEM_TYPE_BYTES: case SND_CTL_ELEM_TYPE_IEC958: if (type == SND_CTL_ELEM_TYPE_IEC958) count = sizeof(snd_aes_iec958_t); if (count > (sizeof(res)-1)/2) count = (sizeof(res)-1/2); pos = res; pos1 = snd_ctl_elem_value_get_bytes(space->ctl_value); while (count > 0) { idx = *pos1++; *pos++ = hex[idx >> 4]; *pos++ = hex[idx & 0x0f]; count++; } *pos++ = '\0'; break; default: Perror(space, "unknown element type '%i'", type); return NULL; } return res;}/* Function to convert from percentage to volume. val = percentage */#define convert_prange1(val, min, max) \ ceil((val) * ((max) - (min)) * 0.01 + (min))static int set_ctl_value(struct space *space, const char *value, int all){ snd_ctl_elem_type_t type; unsigned int idx, idx2, count, items; const char *pos, *pos2; snd_hctl_elem_t *elem; int val; long lval; type = snd_ctl_elem_info_get_type(space->ctl_info); count = snd_ctl_elem_info_get_count(space->ctl_info); switch (type) { case SND_CTL_ELEM_TYPE_BOOLEAN: for (idx = 0; idx < count; idx++) { while (*value == ' ') value++; if (*value == '\0') goto missing; val = strncasecmp(value, "true", 4) == 0 || strncasecmp(value, "yes", 3) == 0 || strncasecmp(value, "on", 2) == 0 || strncasecmp(value, "1", 1) == 0; snd_ctl_elem_value_set_boolean(space->ctl_value, idx, val); if (all) continue; pos = strchr(value, ','); value = pos ? pos + 1 : value + strlen(value) - 1; } break; case SND_CTL_ELEM_TYPE_INTEGER: for (idx = 0; idx < count; idx++) { while (*value == ' ') value++; pos = strchr(value, ','); if (pos) *(char *)pos = '\0'; remove_trailing_chars((char *)value, ' '); items = pos ? pos - value : strlen(value); if (items > 1 && value[items-1] == '%') { val = convert_prange1(strtol(value, NULL, 0), snd_ctl_elem_info_get_min(space->ctl_info), snd_ctl_elem_info_get_max(space->ctl_info)); snd_ctl_elem_value_set_integer(space->ctl_value, idx, val); } else if (items > 2 && value[items-2] == 'd' && value[items-1] == 'B') { val = strtol(value, NULL, 0) * 100; if ((pos2 = index(value, '.')) != NULL) { if (isdigit(*(pos2-1)) && isdigit(*(pos2-2))) { if (val < 0) val -= strtol(pos2 + 1, NULL, 0); else val += strtol(pos2 + 1, NULL, 0); } else if (isdigit(*(pos2-1))) { if (val < 0) val -= strtol(pos2 + 1, NULL, 0) * 10; else val += strtol(pos2 + 1, NULL, 0) * 10; } } val = snd_ctl_convert_from_dB(snd_hctl_ctl(space->ctl_handle), space->ctl_id, val, &lval, -1); if (val < 0) { Perror(space, "unable to convert dB value '%s' to internal integer range", value); return val; } snd_ctl_elem_value_set_integer(space->ctl_value, idx, lval); } else { snd_ctl_elem_value_set_integer(space->ctl_value, idx, strtol(value, NULL, 0)); } if (all) continue; value = pos ? pos + 1 : value + strlen(value) - 1; } break; case SND_CTL_ELEM_TYPE_INTEGER64: for (idx = 0; idx < count; idx++) { while (*value == ' ') value++; snd_ctl_elem_value_set_integer64(space->ctl_value, idx, strtoll(value, NULL, 0)); if (all) continue; pos = strchr(value, ','); value = pos ? pos + 1 : value + strlen(value) - 1; } break; case SND_CTL_ELEM_TYPE_ENUMERATED: for (idx = 0; idx < count; idx++) { while (*value == ' ') value++; pos = strchr(value, ','); if (isdigit(value[0]) || value[0] == '-') { snd_ctl_elem_value_set_enumerated(space->ctl_value, idx, strtol(value, NULL, 0)); } else { if (pos) *(char *)pos = '\0'; remove_trailing_chars((char *)value, ' '); items = snd_ctl_elem_info_get_items(space->ctl_info); for (idx2 = 0; idx2 < items; idx2++) { snd_ctl_elem_info_set_item(space->ctl_info, idx2); elem = snd_hctl_find_elem(space->ctl_handle, space->ctl_id); if (elem == NULL) return -ENOENT; val = snd_hctl_elem_info(elem, space->ctl_info); if (val < 0) return val; if (strcasecmp(snd_ctl_elem_info_get_item_name(space->ctl_info), value) == 0) { snd_ctl_elem_value_set_enumerated(space->ctl_value, idx, idx2); break; } } if (idx2 >= items) { Perror(space, "wrong enum identifier '%s'", value); return -EINVAL; } } if (all) continue; value = pos ? pos + 1 : value + strlen(value) - 1; } break; case SND_CTL_ELEM_TYPE_BYTES: case SND_CTL_ELEM_TYPE_IEC958: if (type == SND_CTL_ELEM_TYPE_IEC958) count = sizeof(snd_aes_iec958_t); while (*value == ' ') value++; if (strlen(value) != count * 2) { Perror(space, "bad ctl value hexa length (should be %u bytes)", count); return -EINVAL; } for (idx = 0; idx < count; idx += 2) { val = hextodigit(*(value++)) << 4; val |= hextodigit(*(value++)); if (val > 255) { Perror(space, "bad ctl hexa value"); return -EINVAL; } snd_ctl_elem_value_set_byte(space->ctl_value, idx, val); } break; default: Perror(space, "unknown element type '%i'", type); return -EINVAL; } return 0; missing: printf("%i %i\n", type, count); Perror(space, "missing some ctl values (line %i)", space->linenum); return -EINVAL;}static const char *elemid_get(struct space *space, const char *attr){ long long val; snd_ctl_elem_type_t type; static char res[256]; if (strncasecmp(attr, "numid", 5) == 0) { val = snd_ctl_elem_id_get_numid(space->ctl_id); goto value; } if (strncasecmp(attr, "iface", 5) == 0 || strncasecmp(attr, "interface", 9) == 0) return snd_ctl_elem_iface_name(snd_ctl_elem_id_get_interface(space->ctl_id)); if (strncasecmp(attr, "device", 6) == 0) { val = snd_ctl_elem_id_get_device(space->ctl_id); goto value; } if (strncasecmp(attr, "subdev", 6) == 0) { val = snd_ctl_elem_id_get_subdevice(space->ctl_id); goto value; } if (strncasecmp(attr, "name", 4) == 0) return snd_ctl_elem_id_get_name(space->ctl_id); if (strncasecmp(attr, "index", 5) == 0) { val = snd_ctl_elem_id_get_index(space->ctl_id); goto value; } if (strncasecmp(attr, "type", 4) == 0) { if (check_id_changed(space, 1)) return NULL; return snd_ctl_elem_type_name(snd_ctl_elem_info_get_type(space->ctl_info)); } if (strncasecmp(attr, "attr", 4) == 0) { if (check_id_changed(space, 1)) return NULL; res[0] = '\0'; if (snd_ctl_elem_info_is_readable(space->ctl_info)) strcat(res, "r"); if (snd_ctl_elem_info_is_writable(space->ctl_info)) strcat(res, "w"); if (snd_ctl_elem_info_is_volatile(space->ctl_info)) strcat(res, "v"); if (snd_ctl_elem_info_is_inactive(space->ctl_info)) strcat(res, "i"); if (snd_ctl_elem_info_is_locked(space->ctl_info)) strcat(res, "l"); if (snd_ctl_elem_info_is_tlv_readable(space->ctl_info)) strcat(res, "R"); if (snd_ctl_elem_info_is_tlv_writable(space->ctl_info)) strcat(res, "W"); if (snd_ctl_elem_info_is_tlv_commandable(space->ctl_info)) strcat(res, "C"); if (snd_ctl_elem_info_is_owner(space->ctl_info)) strcat(res, "o"); if (snd_ctl_elem_info_is_user(space->ctl_info)) strcat(res, "u"); return res; } if (strncasecmp(attr, "owner", 5) == 0) { if (check_id_changed(space, 1)) return NULL; val = snd_ctl_elem_info_get_owner(space->ctl_info); goto value; } if (strncasecmp(attr, "count", 5) == 0) { if (check_id_changed(space, 1)) return NULL; val = snd_ctl_elem_info_get_count(space->ctl_info); goto value; } if (strncasecmp(attr, "min", 3) == 0) { if (check_id_changed(space, 1)) return NULL; type = snd_ctl_elem_info_get_type(space->ctl_info); if (type == SND_CTL_ELEM_TYPE_INTEGER64) val = snd_ctl_elem_info_get_min64(space->ctl_info); else if (type == SND_CTL_ELEM_TYPE_INTEGER) val = snd_ctl_elem_info_get_min(space->ctl_info); else goto empty; goto value; } if (strncasecmp(attr, "max", 3) == 0) { if (check_id_changed(space, 1)) return NULL; type = snd_ctl_elem_info_get_type(space->ctl_info); if (type == SND_CTL_ELEM_TYPE_INTEGER64) val = snd_ctl_elem_info_get_max64(space->ctl_info); else if (type == SND_CTL_ELEM_TYPE_INTEGER) val = snd_ctl_elem_info_get_max(space->ctl_info); else goto empty; goto value;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -