mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -05:00 
			
		
		
		
	ucm: add the run-time variable substitution
Those two variables are supported:
  ${ConfName}      - configuration file name
  ${CardId}        - card identification string (like PCH)
  ${CardName}      - card name (driver)
  ${CardLongName}  - card long name (driver)
  ${env:ENV_NAME}  - returns the environment variable ENV_NAME
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
			
			
This commit is contained in:
		
							parent
							
								
									40aef87f1e
								
							
						
					
					
						commit
						0dd89f3892
					
				
					 3 changed files with 179 additions and 22 deletions
				
			
		
							
								
								
									
										183
									
								
								src/ucm/main.c
									
										
									
									
									
								
							
							
						
						
									
										183
									
								
								src/ucm/main.c
									
										
									
									
									
								
							| 
						 | 
					@ -41,9 +41,10 @@
 | 
				
			||||||
 * misc
 | 
					 * misc
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int get_value1(char **value, struct list_head *value_list,
 | 
					static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value,
 | 
				
			||||||
                      const char *identifier);
 | 
					                      struct list_head *value_list, const char *identifier);
 | 
				
			||||||
static int get_value3(char **value,
 | 
					static int get_value3(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
 | 
					                      char **value,
 | 
				
			||||||
		      const char *identifier,
 | 
							      const char *identifier,
 | 
				
			||||||
		      struct list_head *value_list1,
 | 
							      struct list_head *value_list1,
 | 
				
			||||||
		      struct list_head *value_list2,
 | 
							      struct list_head *value_list2,
 | 
				
			||||||
| 
						 | 
					@ -359,7 +360,7 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
				char *playback_ctl = NULL;
 | 
									char *playback_ctl = NULL;
 | 
				
			||||||
				char *capture_ctl = NULL;
 | 
									char *capture_ctl = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				err = get_value3(&playback_ctl, "PlaybackCTL",
 | 
									err = get_value3(uc_mgr, &playback_ctl, "PlaybackCTL",
 | 
				
			||||||
						 value_list1,
 | 
											 value_list1,
 | 
				
			||||||
						 value_list2,
 | 
											 value_list2,
 | 
				
			||||||
						 value_list3);
 | 
											 value_list3);
 | 
				
			||||||
| 
						 | 
					@ -367,7 +368,7 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
					uc_error("cdev is not defined!");
 | 
										uc_error("cdev is not defined!");
 | 
				
			||||||
					return err;
 | 
										return err;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				err = get_value3(&capture_ctl, "CaptureCTL",
 | 
									err = get_value3(uc_mgr, &capture_ctl, "CaptureCTL",
 | 
				
			||||||
						 value_list1,
 | 
											 value_list1,
 | 
				
			||||||
						 value_list2,
 | 
											 value_list2,
 | 
				
			||||||
						 value_list3);
 | 
											 value_list3);
 | 
				
			||||||
| 
						 | 
					@ -1351,8 +1352,156 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int get_value1(char **value, struct list_head *value_list,
 | 
					static char *rval_conf_name(snd_use_case_mgr_t *uc_mgr)
 | 
				
			||||||
                      const char *identifier)
 | 
					{
 | 
				
			||||||
 | 
						if (uc_mgr->conf_file_name[0])
 | 
				
			||||||
 | 
							return strdup(uc_mgr->conf_file_name);
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char *rval_card_id(snd_use_case_mgr_t *uc_mgr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct list_head *pos;
 | 
				
			||||||
 | 
						struct ctl_list *ctl_list = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each(pos, &uc_mgr->ctl_list) {
 | 
				
			||||||
 | 
							if (ctl_list) {
 | 
				
			||||||
 | 
								uc_error("multiple control device names were found!");
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ctl_list = list_entry(pos, struct ctl_list, list);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ctl_list == NULL)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return strdup(ctl_list->ctl_id);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char *rval_card_name(snd_use_case_mgr_t *uc_mgr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (uc_mgr->card_short_name)
 | 
				
			||||||
 | 
							return strdup(uc_mgr->card_short_name);
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char *rval_card_longname(snd_use_case_mgr_t *uc_mgr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (uc_mgr->card_long_name[0])
 | 
				
			||||||
 | 
							return strdup(uc_mgr->card_long_name);
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char *rval_env(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, const char *id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *e;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						e = getenv(id);
 | 
				
			||||||
 | 
						if (e)
 | 
				
			||||||
 | 
							return strdup(e);
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MATCH_VARIABLE(name, id, fcn)					\
 | 
				
			||||||
 | 
						if (strncmp((name), (id), sizeof(id) - 1) == 0) { 		\
 | 
				
			||||||
 | 
							rval = fcn(uc_mgr);					\
 | 
				
			||||||
 | 
							idsize = sizeof(id) - 1;				\
 | 
				
			||||||
 | 
							goto __rval;						\
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MATCH_VARIABLE2(name, id, fcn)					\
 | 
				
			||||||
 | 
						if (strncmp((name), (id), sizeof(id) - 1) == 0) {		\
 | 
				
			||||||
 | 
							idsize = sizeof(id) - 1;				\
 | 
				
			||||||
 | 
							tmp = strchr(value + idsize, '}');			\
 | 
				
			||||||
 | 
							if (tmp) {						\
 | 
				
			||||||
 | 
								rvalsize = tmp - (value + idsize);		\
 | 
				
			||||||
 | 
								if (rvalsize > sizeof(v2)) {			\
 | 
				
			||||||
 | 
									err = -ENOMEM;				\
 | 
				
			||||||
 | 
									goto __error;				\
 | 
				
			||||||
 | 
								}						\
 | 
				
			||||||
 | 
								strncpy(v2, value + idsize, rvalsize);		\
 | 
				
			||||||
 | 
								v2[rvalsize] = '\0';				\
 | 
				
			||||||
 | 
								idsize += rvalsize + 1;				\
 | 
				
			||||||
 | 
								rval = fcn(uc_mgr, v2);				\
 | 
				
			||||||
 | 
								goto __rval;					\
 | 
				
			||||||
 | 
							}							\
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int get_substituted_value(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
 | 
									 char **_rvalue,
 | 
				
			||||||
 | 
									 const char *value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						size_t size, nsize, idsize, rvalsize, dpos = 0;
 | 
				
			||||||
 | 
						const char *tmp;
 | 
				
			||||||
 | 
						char *r, *nr, *rval, v2[32];
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (value == NULL)
 | 
				
			||||||
 | 
							return -ENOENT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size = strlen(value) + 1;
 | 
				
			||||||
 | 
						r = malloc(size);
 | 
				
			||||||
 | 
						if (r == NULL)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (*value) {
 | 
				
			||||||
 | 
							if (*value == '$' && *(value+1) == '{') {
 | 
				
			||||||
 | 
								MATCH_VARIABLE(value, "${ConfName}", rval_conf_name);
 | 
				
			||||||
 | 
								MATCH_VARIABLE(value, "${CardId}", rval_card_id);
 | 
				
			||||||
 | 
								MATCH_VARIABLE(value, "${CardName}", rval_card_name);
 | 
				
			||||||
 | 
								MATCH_VARIABLE(value, "${CardLongName}", rval_card_longname);
 | 
				
			||||||
 | 
								MATCH_VARIABLE2(value, "${env:", rval_env);
 | 
				
			||||||
 | 
								err = -EINVAL;
 | 
				
			||||||
 | 
								tmp = strchr(value, '}');
 | 
				
			||||||
 | 
								if (tmp) {
 | 
				
			||||||
 | 
									strncpy(r, value, tmp + 1 - value);
 | 
				
			||||||
 | 
									r[tmp + 1 - value] = '\0';
 | 
				
			||||||
 | 
									uc_error("variable '%s' is not known!", r);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									uc_error("variable reference '%s' is not complete", value);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								goto __error;
 | 
				
			||||||
 | 
					__rval:
 | 
				
			||||||
 | 
								if (rval == NULL || rval[0] == '\0') {
 | 
				
			||||||
 | 
									free(rval);
 | 
				
			||||||
 | 
									strncpy(r, value, idsize);
 | 
				
			||||||
 | 
									r[idsize] = '\0';
 | 
				
			||||||
 | 
									uc_error("variable '%s' is not defined in this context!", r);
 | 
				
			||||||
 | 
									err = -EINVAL;
 | 
				
			||||||
 | 
									goto __error;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								value += idsize;
 | 
				
			||||||
 | 
								rvalsize = strlen(rval);
 | 
				
			||||||
 | 
								nsize = size + rvalsize - idsize;
 | 
				
			||||||
 | 
								if (nsize > size) {
 | 
				
			||||||
 | 
									nr = realloc(r, nsize);
 | 
				
			||||||
 | 
									if (nr == NULL) {
 | 
				
			||||||
 | 
										err = -ENOMEM;
 | 
				
			||||||
 | 
										goto __error;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									size = nsize;
 | 
				
			||||||
 | 
									r = nr;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								strcpy(r + dpos, rval);
 | 
				
			||||||
 | 
								dpos += rvalsize;
 | 
				
			||||||
 | 
								free(rval);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								r[dpos++] = *value;
 | 
				
			||||||
 | 
								value++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						r[dpos] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*_rvalue = r;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__error:
 | 
				
			||||||
 | 
						free(r);
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value,
 | 
				
			||||||
 | 
							      struct list_head *value_list, const char *identifier)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        struct ucm_value *val;
 | 
					        struct ucm_value *val;
 | 
				
			||||||
        struct list_head *pos;
 | 
					        struct list_head *pos;
 | 
				
			||||||
| 
						 | 
					@ -1363,16 +1512,20 @@ static int get_value1(char **value, struct list_head *value_list,
 | 
				
			||||||
        list_for_each(pos, value_list) {
 | 
					        list_for_each(pos, value_list) {
 | 
				
			||||||
		val = list_entry(pos, struct ucm_value, list);
 | 
							val = list_entry(pos, struct ucm_value, list);
 | 
				
			||||||
		if (check_identifier(identifier, val->name)) {
 | 
							if (check_identifier(identifier, val->name)) {
 | 
				
			||||||
 | 
								if (uc_mgr->conf_format < 2) {
 | 
				
			||||||
				*value = strdup(val->data);
 | 
									*value = strdup(val->data);
 | 
				
			||||||
				if (*value == NULL)
 | 
									if (*value == NULL)
 | 
				
			||||||
					return -ENOMEM;
 | 
										return -ENOMEM;
 | 
				
			||||||
				return 0;
 | 
									return 0;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								return get_substituted_value(uc_mgr, value, val->data);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return -ENOENT;
 | 
					        return -ENOENT;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int get_value3(char **value,
 | 
					static int get_value3(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
 | 
							      char **value,
 | 
				
			||||||
		      const char *identifier,
 | 
							      const char *identifier,
 | 
				
			||||||
		      struct list_head *value_list1,
 | 
							      struct list_head *value_list1,
 | 
				
			||||||
		      struct list_head *value_list2,
 | 
							      struct list_head *value_list2,
 | 
				
			||||||
| 
						 | 
					@ -1380,13 +1533,13 @@ static int get_value3(char **value,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = get_value1(value, value_list1, identifier);
 | 
						err = get_value1(uc_mgr, value, value_list1, identifier);
 | 
				
			||||||
	if (err >= 0 || err != -ENOENT)
 | 
						if (err >= 0 || err != -ENOENT)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	err = get_value1(value, value_list2, identifier);
 | 
						err = get_value1(uc_mgr, value, value_list2, identifier);
 | 
				
			||||||
	if (err >= 0 || err != -ENOENT)
 | 
						if (err >= 0 || err != -ENOENT)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	err = get_value1(value, value_list3, identifier);
 | 
						err = get_value1(uc_mgr, value, value_list3, identifier);
 | 
				
			||||||
	if (err >= 0 || err != -ENOENT)
 | 
						if (err >= 0 || err != -ENOENT)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	return -ENOENT;
 | 
						return -ENOENT;
 | 
				
			||||||
| 
						 | 
					@ -1423,7 +1576,7 @@ static int get_value(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
				mod = find_modifier(uc_mgr, verb,
 | 
									mod = find_modifier(uc_mgr, verb,
 | 
				
			||||||
						    mod_dev_name, 0);
 | 
											    mod_dev_name, 0);
 | 
				
			||||||
				if (mod) {
 | 
									if (mod) {
 | 
				
			||||||
					err = get_value1(value,
 | 
										err = get_value1(uc_mgr, value,
 | 
				
			||||||
							 &mod->value_list,
 | 
												 &mod->value_list,
 | 
				
			||||||
							 identifier);
 | 
												 identifier);
 | 
				
			||||||
					if (err >= 0 || err != -ENOENT)
 | 
										if (err >= 0 || err != -ENOENT)
 | 
				
			||||||
| 
						 | 
					@ -1433,7 +1586,7 @@ static int get_value(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
				dev = find_device(uc_mgr, verb,
 | 
									dev = find_device(uc_mgr, verb,
 | 
				
			||||||
						  mod_dev_name, 0);
 | 
											  mod_dev_name, 0);
 | 
				
			||||||
				if (dev) {
 | 
									if (dev) {
 | 
				
			||||||
					err = get_value1(value,
 | 
										err = get_value1(uc_mgr, value,
 | 
				
			||||||
							 &dev->value_list,
 | 
												 &dev->value_list,
 | 
				
			||||||
							 identifier);
 | 
												 identifier);
 | 
				
			||||||
					if (err >= 0 || err != -ENOENT)
 | 
										if (err >= 0 || err != -ENOENT)
 | 
				
			||||||
| 
						 | 
					@ -1444,7 +1597,7 @@ static int get_value(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
					return -ENOENT;
 | 
										return -ENOENT;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			err = get_value1(value, &verb->value_list, identifier);
 | 
								err = get_value1(uc_mgr, value, &verb->value_list, identifier);
 | 
				
			||||||
			if (err >= 0 || err != -ENOENT)
 | 
								if (err >= 0 || err != -ENOENT)
 | 
				
			||||||
				return err;
 | 
									return err;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -1453,7 +1606,7 @@ static int get_value(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
			return -ENOENT;
 | 
								return -ENOENT;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = get_value1(value, &uc_mgr->value_list, identifier);
 | 
						err = get_value1(uc_mgr, value, &uc_mgr->value_list, identifier);
 | 
				
			||||||
	if (err >= 0 || err != -ENOENT)
 | 
						if (err >= 0 || err != -ENOENT)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1464,6 +1464,7 @@ static int get_card_long_name(snd_use_case_mgr_t *mgr)
 | 
				
			||||||
			_long_name = snd_ctl_card_info_get_longname(info);
 | 
								_long_name = snd_ctl_card_info_get_longname(info);
 | 
				
			||||||
			if (!strcmp(card_name, _name) ||
 | 
								if (!strcmp(card_name, _name) ||
 | 
				
			||||||
			    !strcmp(card_name, _long_name)) {
 | 
								    !strcmp(card_name, _long_name)) {
 | 
				
			||||||
 | 
									snd_strlcpy(mgr->card_short_name, _name, sizeof(mgr->card_short_name));
 | 
				
			||||||
				snd_strlcpy(mgr->card_long_name, _long_name, sizeof(mgr->card_long_name));
 | 
									snd_strlcpy(mgr->card_long_name, _long_name, sizeof(mgr->card_long_name));
 | 
				
			||||||
				return 0;
 | 
									return 0;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -1495,6 +1496,7 @@ static int get_by_card(snd_use_case_mgr_t *mgr, const char *ctl_name)
 | 
				
			||||||
	_name = snd_ctl_card_info_get_name(info);
 | 
						_name = snd_ctl_card_info_get_name(info);
 | 
				
			||||||
	_long_name = snd_ctl_card_info_get_longname(info);
 | 
						_long_name = snd_ctl_card_info_get_longname(info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						snd_strlcpy(mgr->card_short_name, _name, sizeof(mgr->card_short_name));
 | 
				
			||||||
	snd_strlcpy(mgr->card_long_name, _long_name, sizeof(mgr->card_long_name));
 | 
						snd_strlcpy(mgr->card_long_name, _long_name, sizeof(mgr->card_long_name));
 | 
				
			||||||
	snd_strlcpy(mgr->conf_file_name, _name, sizeof(mgr->conf_file_name));
 | 
						snd_strlcpy(mgr->conf_file_name, _name, sizeof(mgr->conf_file_name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,7 @@
 | 
				
			||||||
#define SYNTAX_VERSION_MAX	2
 | 
					#define SYNTAX_VERSION_MAX	2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_FILE		256
 | 
					#define MAX_FILE		256
 | 
				
			||||||
 | 
					#define MAX_CARD_SHORT_NAME	32
 | 
				
			||||||
#define MAX_CARD_LONG_NAME	80
 | 
					#define MAX_CARD_LONG_NAME	80
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SEQUENCE_ELEMENT_TYPE_CDEV	1
 | 
					#define SEQUENCE_ELEMENT_TYPE_CDEV	1
 | 
				
			||||||
| 
						 | 
					@ -204,6 +205,7 @@ struct use_case_verb {
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct snd_use_case_mgr {
 | 
					struct snd_use_case_mgr {
 | 
				
			||||||
	char *card_name;
 | 
						char *card_name;
 | 
				
			||||||
 | 
						char card_short_name[MAX_CARD_SHORT_NAME];
 | 
				
			||||||
	char card_long_name[MAX_CARD_LONG_NAME];
 | 
						char card_long_name[MAX_CARD_LONG_NAME];
 | 
				
			||||||
	char conf_file_name[MAX_CARD_LONG_NAME];
 | 
						char conf_file_name[MAX_CARD_LONG_NAME];
 | 
				
			||||||
	char *comment;
 | 
						char *comment;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue