2 * \file control/control.c
3 * \brief CTL interface - parse ASCII identifiers and values
4 * \author Jaroslav Kysela <perex@perex.cz>
8 * Control Interface - ASCII parser
9 * Copyright (c) 2010 by Jaroslav Kysela <perex@perex.cz>
12 * This library is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License as
14 * published by the Free Software Foundation; either version 2.1 of
15 * the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include "control_local.h"
34 /* Function to convert from percentage to volume. val = percentage */
36 #ifdef HAVE_SOFT_FLOAT
37 static inline long int convert_prange1(long val, long min, long max)
39 long temp = val * (max - min);
40 return temp / 100 + min + ((temp % 100) == 0 ? 0 : 1);
44 #define convert_prange1(val, min, max) \
45 ceil((val) * ((max) - (min)) * 0.01 + (min))
48 #define check_range(val, min, max) \
49 ((val < min) ? (min) : ((val > max) ? (max) : (val)))
51 static long get_integer(const char **ptr, long min, long max)
54 char *p = (char *)*ptr, *s;
58 if (*p == '\0' || (!isdigit(*p) && *p != '-'))
62 val = strtol(s, &p, 10);
68 val = (long)convert_prange1(strtod(s, NULL), min, max);
71 val = check_range(val, min, max);
79 static long long get_integer64(const char **ptr, long long min, long long max)
82 char *p = (char *)*ptr, *s;
86 if (*p == '\0' || (!isdigit(*p) && *p != '-'))
90 val = strtol(s, &p, 10);
96 val = (long long)convert_prange1(strtod(s, NULL), min, max);
99 val = check_range(val, min, max);
108 * \brief return ASCII CTL element identifier name
109 * \param id CTL identifier
110 * \return ascii identifier of CTL element
112 * The string is allocated using strdup().
114 char *snd_ctl_ascii_elem_id_get(snd_ctl_elem_id_t *id)
116 unsigned int index, device, subdevice;
117 char buf[256], buf1[32];
119 snprintf(buf, sizeof(buf), "numid=%u,iface=%s,name='%s'",
120 snd_ctl_elem_id_get_numid(id),
121 snd_ctl_elem_iface_name(
122 snd_ctl_elem_id_get_interface(id)),
123 snd_ctl_elem_id_get_name(id));
124 buf[sizeof(buf)-1] = '\0';
125 index = snd_ctl_elem_id_get_index(id);
126 device = snd_ctl_elem_id_get_device(id);
127 subdevice = snd_ctl_elem_id_get_subdevice(id);
129 snprintf(buf1, sizeof(buf1), ",index=%i", index);
130 if (strlen(buf) + strlen(buf1) < sizeof(buf))
134 snprintf(buf1, sizeof(buf1), ",device=%i", device);
135 if (strlen(buf) + strlen(buf1) < sizeof(buf))
139 snprintf(buf1, sizeof(buf1), ",subdevice=%i", subdevice);
140 if (strlen(buf) + strlen(buf1) < sizeof(buf))
147 * \brief parse ASCII string as CTL element identifier
148 * \param dst destination CTL identifier
149 * \param str source ASCII string
150 * \return zero on success, otherwise a negative error code
152 int snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str)
157 while (*str == ' ' || *str == '\t')
161 snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_MIXER); /* default */
163 if (!strncasecmp(str, "numid=", 6)) {
167 fprintf(stderr, "amixer: Invalid numid %d\n", numid);
170 snd_ctl_elem_id_set_numid(dst, atoi(str));
171 while (isdigit(*str))
173 } else if (!strncasecmp(str, "iface=", 6)) {
175 if (!strncasecmp(str, "card", 4)) {
176 snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_CARD);
178 } else if (!strncasecmp(str, "mixer", 5)) {
179 snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_MIXER);
181 } else if (!strncasecmp(str, "pcm", 3)) {
182 snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_PCM);
184 } else if (!strncasecmp(str, "rawmidi", 7)) {
185 snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_RAWMIDI);
187 } else if (!strncasecmp(str, "timer", 5)) {
188 snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_TIMER);
190 } else if (!strncasecmp(str, "sequencer", 9)) {
191 snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_SEQUENCER);
196 } else if (!strncasecmp(str, "name=", 5)) {
201 if (*str == '\'' || *str == '\"') {
203 while (*str && *str != c) {
204 if (size < (int)sizeof(buf)) {
213 while (*str && *str != ',') {
214 if (size < (int)sizeof(buf)) {
222 snd_ctl_elem_id_set_name(dst, buf);
223 } else if (!strncasecmp(str, "index=", 6)) {
225 snd_ctl_elem_id_set_index(dst, atoi(str));
226 while (isdigit(*str))
228 } else if (!strncasecmp(str, "device=", 7)) {
230 snd_ctl_elem_id_set_device(dst, atoi(str));
231 while (isdigit(*str))
233 } else if (!strncasecmp(str, "subdevice=", 10)) {
235 snd_ctl_elem_id_set_subdevice(dst, atoi(str));
236 while (isdigit(*str))
249 static int get_ctl_enum_item_index(snd_ctl_t *handle,
250 snd_ctl_elem_info_t *info,
253 char *ptr = (char *)*ptrp;
257 items = snd_ctl_elem_info_get_items(info);
261 for (i = 0; i < items; i++) {
262 snd_ctl_elem_info_set_item(info, i);
263 if (snd_ctl_elem_info(handle, info) < 0)
265 name = snd_ctl_elem_info_get_item_name(info);
267 if (! strncmp(name, ptr, len)) {
268 if (! ptr[len] || ptr[len] == ',' || ptr[len] == '\n') {
279 * \brief parse ASCII string as CTL element value
280 * \param dst destination CTL element value
281 * \param info CTL element info structure
282 * \param value source ASCII string
283 * \return zero on success, otherwise a negative error code
285 int snd_ctl_ascii_value_parse(snd_ctl_t *handle,
286 snd_ctl_elem_value_t *dst,
287 snd_ctl_elem_info_t *info,
290 const char *ptr = value;
291 snd_ctl_elem_id_t *myid;
292 snd_ctl_elem_type_t type;
293 unsigned int idx, count;
297 snd_ctl_elem_id_alloca(&myid);
298 snd_ctl_elem_info_get_id(info, myid);
299 type = snd_ctl_elem_info_get_type(info);
300 count = snd_ctl_elem_info_get_count(info);
301 snd_ctl_elem_value_set_id(dst, myid);
303 for (idx = 0; idx < count && idx < 128 && ptr && *ptr; idx++) {
305 case SND_CTL_ELEM_TYPE_BOOLEAN:
307 if (!strncasecmp(ptr, "on", 2) ||
308 !strncasecmp(ptr, "up", 2)) {
311 } else if (!strncasecmp(ptr, "yes", 3)) {
314 } else if (!strncasecmp(ptr, "toggle", 6)) {
315 tmp = snd_ctl_elem_value_get_boolean(dst, idx);
316 tmp = tmp > 0 ? 0 : 1;
318 } else if (isdigit(*ptr)) {
319 tmp = atoi(ptr) > 0 ? 1 : 0;
320 while (isdigit(*ptr))
323 while (*ptr && *ptr != ',')
326 snd_ctl_elem_value_set_boolean(dst, idx, tmp);
328 case SND_CTL_ELEM_TYPE_INTEGER:
329 tmp = get_integer(&ptr,
330 snd_ctl_elem_info_get_min(info),
331 snd_ctl_elem_info_get_max(info));
332 snd_ctl_elem_value_set_integer(dst, idx, tmp);
334 case SND_CTL_ELEM_TYPE_INTEGER64:
335 tmp64 = get_integer64(&ptr,
336 snd_ctl_elem_info_get_min64(info),
337 snd_ctl_elem_info_get_max64(info));
338 snd_ctl_elem_value_set_integer64(dst, idx, tmp64);
340 case SND_CTL_ELEM_TYPE_ENUMERATED:
341 tmp = get_ctl_enum_item_index(handle, info, &ptr);
343 tmp = get_integer(&ptr, 0,
344 snd_ctl_elem_info_get_items(info) - 1);
345 snd_ctl_elem_value_set_enumerated(dst, idx, tmp);
347 case SND_CTL_ELEM_TYPE_BYTES:
348 tmp = get_integer(&ptr, 0, 255);
349 snd_ctl_elem_value_set_byte(dst, idx, tmp);
354 if (!strchr(value, ','))
356 else if (*ptr == ',')