19c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
29c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * Use of this source code is governed by a BSD-style license that can be
39c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * found in the LICENSE file.
49c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid */
59c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
69c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid#include <ctype.h>
79c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid#include <stdlib.h>
89c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid#include <syslog.h>
99c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
109c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid#include "array.h"
119c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid#include "cras_expr.h"
129c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
139c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic const char *copy_str(const char *begin, const char *end)
149c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
159c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	char *s = malloc(end - begin + 1);
169c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	memcpy(s, begin, end - begin);
179c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	s[end - begin] = '\0';
189c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return s;
199c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
209c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
219c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic void value_set_boolean(struct cras_expr_value *value, char boolean)
229c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
239c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	cras_expr_value_free(value);
249c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value->type = CRAS_EXPR_VALUE_TYPE_BOOLEAN;
259c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value->u.boolean = !!boolean;
269c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
279c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
289c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic void value_set_integer(struct cras_expr_value *value, int integer)
299c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
309c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	cras_expr_value_free(value);
319c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value->type = CRAS_EXPR_VALUE_TYPE_INT;
329c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value->u.integer = integer;
339c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
349c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
359c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic void value_set_string2(struct cras_expr_value *value, const char *begin,
369c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			      const char *end)
379c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
389c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	cras_expr_value_free(value);
399c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value->type = CRAS_EXPR_VALUE_TYPE_STRING;
409c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value->u.string = copy_str(begin, end);
419c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
429c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
439c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic void value_set_string(struct cras_expr_value *value, const char *str)
449c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
459c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value_set_string2(value, str, str + strlen(str));
469c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
479c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
489c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic void cras_expr_value_set_function(struct cras_expr_value *value,
499c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					 cras_expr_function_type function)
509c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
519c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	cras_expr_value_free(value);
529c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value->type = CRAS_EXPR_VALUE_TYPE_FUNCTION;
539c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value->u.function = function;
549c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
559c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
569c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic void copy_value(struct cras_expr_value *value,
579c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		       struct cras_expr_value *original)
589c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
599c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	cras_expr_value_free(value);  /* free the original value first */
609c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value->type = original->type;
619c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	switch (value->type) {
629c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	case CRAS_EXPR_VALUE_TYPE_NONE:
639c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		break;
649c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	case CRAS_EXPR_VALUE_TYPE_BOOLEAN:
659c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		value->u.boolean = original->u.boolean;
669c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		break;
679c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	case CRAS_EXPR_VALUE_TYPE_INT:
689c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		value->u.integer = original->u.integer;
699c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		break;
709c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	case CRAS_EXPR_VALUE_TYPE_STRING:
719c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		value->u.string = strdup(original->u.string);
729c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		break;
739c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	case CRAS_EXPR_VALUE_TYPE_FUNCTION:
749c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		value->u.function = original->u.function;
759c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		break;
769c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
779c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
789c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
799c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidvoid cras_expr_value_free(struct cras_expr_value *value)
809c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
819c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	switch (value->type) {
829c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	case CRAS_EXPR_VALUE_TYPE_STRING:
839c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		free((char *)value->u.string);
849c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		value->u.string = NULL;
859c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		break;
869c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	case CRAS_EXPR_VALUE_TYPE_NONE:
879c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	case CRAS_EXPR_VALUE_TYPE_BOOLEAN:
889c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	case CRAS_EXPR_VALUE_TYPE_INT:
899c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	case CRAS_EXPR_VALUE_TYPE_FUNCTION:
909c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		break;
919c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
929c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value->type = CRAS_EXPR_VALUE_TYPE_NONE;
939c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
949c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
959c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic struct cras_expr_value *find_value(struct cras_expr_env *env,
969c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					  const char *name)
979c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
989c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
999c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	const char **key;
1009c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1019c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&env->keys, i, key) {
1029c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (strcmp(*key, name) == 0)
1039c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			return ARRAY_ELEMENT(&env->values, i);
1049c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
1059c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return NULL;
1069c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
1079c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1089c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid/* Insert a (key, value) pair to the environment. The value is
1099c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * initialized to zero. Return the pointer to value so it can be set
1109c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * to the proper value. */
1119c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic struct cras_expr_value *insert_value(struct cras_expr_env *env,
1129c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					    const char *key)
1139c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
1149c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	*ARRAY_APPEND_ZERO(&env->keys) = strdup(key);
1159c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return ARRAY_APPEND_ZERO(&env->values);
1169c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
1179c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1189c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic struct cras_expr_value *find_or_insert_value(struct cras_expr_env *env,
1199c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid						    const char *key)
1209c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
1219c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct cras_expr_value *value = find_value(env, key);
1229c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (!value)
1239c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		value = insert_value(env, key);
1249c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return value;
1259c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
1269c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1279c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic void function_not(cras_expr_value_array *operands,
1289c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			 struct cras_expr_value *result)
1299c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
1309c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct cras_expr_value *value;
1319c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int is_false;
1329c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1339c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (ARRAY_COUNT(operands) != 2) {
1349c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		cras_expr_value_free(result);
1359c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		syslog(LOG_ERR, "not takes one argument");
1369c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return;
1379c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
1389c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1399c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value = ARRAY_ELEMENT(operands, 1);
1409c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	is_false = (value->type == CRAS_EXPR_VALUE_TYPE_BOOLEAN &&
1419c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		    !value->u.boolean);
1429c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value_set_boolean(result, is_false);
1439c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
1449c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1459c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic void function_and(cras_expr_value_array *operands,
1469c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			 struct cras_expr_value *result)
1479c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
1489c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
1499c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct cras_expr_value *value;
1509c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int n = ARRAY_COUNT(operands);
1519c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1529c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* no operands -- return #t */
1539c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (n <= 1) {
1549c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		value_set_boolean(result, 1);
1559c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return;
1569c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
1579c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1589c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* if there is any #f, return it */
1599c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(operands, i, value) {
1609c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (i == 0)
1619c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			continue;  /* ignore "and" itself */
1629c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (value->type == CRAS_EXPR_VALUE_TYPE_BOOLEAN &&
1639c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		    !value->u.boolean) {
1649c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			value_set_boolean(result, 0);
1659c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			return;
1669c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
1679c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
1689c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1699c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* otherwise return the last element */
1709c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	copy_value(result, ARRAY_ELEMENT(operands, n - 1));
1719c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
1729c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1739c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic void function_or(cras_expr_value_array *operands,
1749c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			struct cras_expr_value *result)
1759c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
1769c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
1779c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct cras_expr_value *value;
1789c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1799c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(operands, i, value) {
1809c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (i == 0)
1819c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			continue;  /* ignore "or" itself */
1829c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (value->type != CRAS_EXPR_VALUE_TYPE_BOOLEAN ||
1839c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		    value->u.boolean) {
1849c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			copy_value(result, value);
1859c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			return;
1869c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
1879c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
1889c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1899c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value_set_boolean(result, 0);
1909c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
1919c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1929c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic char function_equal_real(cras_expr_value_array *operands)
1939c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
1949c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
1959c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct cras_expr_value *value, *prev;
1969c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1979c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(operands, i, value) {
1989c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (i <= 1)
1999c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			continue;  /* ignore equal? and first operand */
2009c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		/* compare with the previous operand */
2019c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2029c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		prev = ARRAY_ELEMENT(operands, i - 1);
2039c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2049c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (prev->type != value->type)
2059c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			return 0;
2069c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2079c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		switch (prev->type) {
2089c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		case CRAS_EXPR_VALUE_TYPE_NONE:
2099c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			break;
2109c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		case CRAS_EXPR_VALUE_TYPE_BOOLEAN:
2119c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			if (prev->u.boolean != value->u.boolean)
2129c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				return 0;
2139c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			break;
2149c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		case CRAS_EXPR_VALUE_TYPE_INT:
2159c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			if (prev->u.integer != value->u.integer)
2169c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				return 0;
2179c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			break;
2189c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		case CRAS_EXPR_VALUE_TYPE_STRING:
2199c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			if (strcmp(prev->u.string, value->u.string) != 0)
2209c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				return 0;
2219c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			break;
2229c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		case CRAS_EXPR_VALUE_TYPE_FUNCTION:
2239c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			if (prev->u.function != value->u.function)
2249c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				return 0;
2259c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			break;
2269c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
2279c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
2289c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2299c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return 1;
2309c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
2319c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2329c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic void function_equal(cras_expr_value_array *operands,
2339c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			   struct cras_expr_value *result)
2349c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
2359c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value_set_boolean(result, function_equal_real(operands));
2369c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
2379c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2389c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic void env_set_variable(struct cras_expr_env *env, const char *name,
2399c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			     struct cras_expr_value *new_value)
2409c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
2419c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct cras_expr_value *value = find_or_insert_value(env, name);
2429c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	copy_value(value, new_value);
2439c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
2449c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2459c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidvoid cras_expr_env_install_builtins(struct cras_expr_env *env)
2469c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
2479c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct cras_expr_value value = CRAS_EXPR_VALUE_INIT;
2489c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2499c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* initialize env with builtin functions */
2509c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	cras_expr_value_set_function(&value, &function_not);
2519c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	env_set_variable(env, "not", &value);
2529c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2539c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	cras_expr_value_set_function(&value, &function_and);
2549c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	env_set_variable(env, "and", &value);
2559c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2569c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	cras_expr_value_set_function(&value, &function_or);
2579c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	env_set_variable(env, "or", &value);
2589c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2599c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	cras_expr_value_set_function(&value, &function_equal);
2609c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	env_set_variable(env, "equal?", &value);
2619c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2629c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	cras_expr_value_free(&value);
2639c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
2649c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2659c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidvoid cras_expr_env_set_variable_boolean(struct cras_expr_env *env,
2669c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					const char *name, char boolean)
2679c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
2689c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct cras_expr_value *value = find_or_insert_value(env, name);
2699c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value_set_boolean(value, boolean);
2709c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
2719c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2729c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidvoid cras_expr_env_set_variable_integer(struct cras_expr_env *env,
2739c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					const char *name, int integer)
2749c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
2759c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct cras_expr_value *value = find_or_insert_value(env, name);
2769c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value_set_integer(value, integer);
2779c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
2789c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2799c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidvoid cras_expr_env_set_variable_string(struct cras_expr_env *env,
2809c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				       const char *name, const char *str)
2819c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
2829c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct cras_expr_value *value = find_or_insert_value(env, name);
2839c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value_set_string(value, str);
2849c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
2859c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2869c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidvoid cras_expr_env_free(struct cras_expr_env *env)
2879c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
2889c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
2899c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	const char **key;
2909c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct cras_expr_value *value;
2919c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2929c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&env->keys, i, key) {
2939c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		free((char *)*key);
2949c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
2959c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2969c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&env->values, i, value) {
2979c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		cras_expr_value_free(value);
2989c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
2999c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3009c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	ARRAY_FREE(&env->keys);
3019c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	ARRAY_FREE(&env->values);
3029c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
3039c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3049c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic struct cras_expr_expression *new_boolean_literal(char boolean)
3059c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
3069c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct cras_expr_expression *expr;
3079c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	expr = calloc(1, sizeof(struct cras_expr_expression));
3089c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	expr->type = EXPR_TYPE_LITERAL;
3099c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value_set_boolean(&expr->u.literal, boolean);
3109c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return expr;
3119c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
3129c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3139c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic struct cras_expr_expression *new_integer_literal(int integer)
3149c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
3159c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct cras_expr_expression *expr;
3169c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	expr = calloc(1, sizeof(struct cras_expr_expression));
3179c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	expr->type = EXPR_TYPE_LITERAL;
3189c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value_set_integer(&expr->u.literal, integer);
3199c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return expr;
3209c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
3219c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3229c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic struct cras_expr_expression *new_string_literal(const char *begin,
3239c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid						       const char *end)
3249c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
3259c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct cras_expr_expression *expr;
3269c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	expr = calloc(1, sizeof(struct cras_expr_expression));
3279c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	expr->type = EXPR_TYPE_LITERAL;
3289c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	value_set_string2(&expr->u.literal, begin, end);
3299c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return expr;
3309c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
3319c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3329c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic struct cras_expr_expression *new_variable(const char *begin,
3339c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid						 const char *end)
3349c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
3359c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct cras_expr_expression *expr;
3369c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	expr = calloc(1, sizeof(struct cras_expr_expression));
3379c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	expr->type = EXPR_TYPE_VARIABLE;
3389c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	expr->u.variable = copy_str(begin, end);
3399c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return expr;
3409c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
3419c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3429c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic struct cras_expr_expression *new_compound_expression()
3439c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
3449c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct cras_expr_expression *expr;
3459c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	expr = calloc(1, sizeof(struct cras_expr_expression));
3469c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	expr->type = EXPR_TYPE_COMPOUND;
3479c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return expr;
3489c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
3499c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3509c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic void add_sub_expression(struct cras_expr_expression *expr,
3519c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			       struct cras_expr_expression *sub)
3529c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
3539c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	ARRAY_APPEND(&expr->u.children, sub);
3549c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
3559c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3569c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic int is_identifier_char(char c)
3579c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
3589c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (isspace(c))
3599c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return 0;
3609c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (c == '\0')
3619c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return 0;
3629c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (isalpha(c))
3639c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return 1;
3649c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (c == '_' || c == '-' || c == '?')
3659c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return 1;
3669c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return 0;
3679c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
3689c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3699c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic struct cras_expr_expression *parse_one_expr(const char **str)
3709c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
3719c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* skip whitespace */
3729c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	while (isspace(**str))
3739c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		(*str)++;
3749c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3759c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (**str == '\0')
3769c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return NULL;
3779c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3789c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* boolean literal: #t, #f */
3799c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (**str == '#') {
3809c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		(*str)++;
3819c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		char c = **str;
3829c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (c == 't' || c == 'f') {
3839c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			(*str)++;
3849c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			return new_boolean_literal(c == 't');
3859c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		} else {
3869c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			syslog(LOG_ERR, "unexpected char after #: '%c'",
3879c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			       c);
3889c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
3899c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return NULL;
3909c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
3919c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3929c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* integer literal: (-)[0-9]+ */
3939c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (isdigit(**str) || (**str == '-' && isdigit((*str)[1])))
3949c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return new_integer_literal(strtol(*str, (char **)str, 10));
3959c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3969c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* string literal: "..." */
3979c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (**str == '"') {
3989c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		const char *begin = *str + 1;
3999c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		const char *end = strchr(begin, '"');
4009c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (end == NULL) {
4019c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			syslog(LOG_ERR, "no matching \"");
4029c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			end = begin;
4039c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			*str = begin;
4049c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		} else {
4059c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			*str = end + 1;
4069c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
4079c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return new_string_literal(begin, end);
4089c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
4099c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4109c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* compound expression: (expr1 expr2 ...) */
4119c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (**str == '(') {
4129c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		(*str)++;
4139c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		struct cras_expr_expression *expr = new_compound_expression();
4149c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		while (1) {
4159c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			struct cras_expr_expression *next = parse_one_expr(str);
4169c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			if (next == NULL)
4179c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				break;
4189c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			add_sub_expression(expr, next);
4199c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
4209c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (**str != ')') {
4219c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			syslog(LOG_ERR, "no matching ): found '%c'", **str);
4229c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			cras_expr_expression_free(expr);
4239c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			return NULL;
4249c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		} else {
4259c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			(*str)++;
4269c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
4279c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return expr;
4289c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
4299c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4309c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* variable name */
4319c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (is_identifier_char(**str)) {
4329c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		const char *begin = *str;
4339c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		while (is_identifier_char(**str))
4349c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			(*str)++;
4359c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return new_variable(begin, *str);
4369c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
4379c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4389c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return NULL;
4399c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
4409c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4419c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstruct cras_expr_expression *cras_expr_expression_parse(const char *str)
4429c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
4439c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (!str)
4449c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return NULL;
4459c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return parse_one_expr(&str);
4469c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
4479c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4489c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidvoid cras_expr_expression_free(struct cras_expr_expression *expr)
4499c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
4509c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (!expr)
4519c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return;
4529c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4539c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	switch (expr->type) {
4549c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	case EXPR_TYPE_NONE:
4559c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		break;
4569c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	case EXPR_TYPE_LITERAL:
4579c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		cras_expr_value_free(&expr->u.literal);
4589c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		break;
4599c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	case EXPR_TYPE_VARIABLE:
4609c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		free((char *)expr->u.variable);
4619c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		break;
4629c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	case EXPR_TYPE_COMPOUND:
4639c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	{
4649c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		int i;
4659c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		struct cras_expr_expression **psub;
4669c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		FOR_ARRAY_ELEMENT(&expr->u.children, i, psub) {
4679c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			cras_expr_expression_free(*psub);
4689c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
4699c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		ARRAY_FREE(&expr->u.children);
4709c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		break;
4719c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
4729c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
4739c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	free(expr);
4749c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
4759c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4769c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidvoid cras_expr_expression_eval(struct cras_expr_expression *expr,
4779c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			       struct cras_expr_env *env,
4789c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			       struct cras_expr_value *result)
4799c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
4809c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	cras_expr_value_free(result);
4819c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4829c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	switch (expr->type) {
4839c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	case EXPR_TYPE_NONE:
4849c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		break;
4859c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	case EXPR_TYPE_LITERAL:
4869c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		copy_value(result, &expr->u.literal);
4879c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		break;
4889c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	case EXPR_TYPE_VARIABLE:
4899c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	{
4909c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		struct cras_expr_value *value = find_value(env,
4919c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid							   expr->u.variable);
4929c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (value == NULL) {
4939c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			syslog(LOG_ERR, "cannot find value for %s",
4949c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			       expr->u.variable);
4959c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		} else {
4969c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			copy_value(result, value);
4979c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
4989c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		break;
4999c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
5009c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	case EXPR_TYPE_COMPOUND:
5019c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	{
5029c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		int i;
5039c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		struct cras_expr_expression **psub;
5049c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		cras_expr_value_array values = ARRAY_INIT;
5059c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		struct cras_expr_value *value;
5069c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5079c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		FOR_ARRAY_ELEMENT(&expr->u.children, i, psub) {
5089c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			value = ARRAY_APPEND_ZERO(&values);
5099c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			cras_expr_expression_eval(*psub, env, value);
5109c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
5119c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5129c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (ARRAY_COUNT(&values) > 0) {
5139c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			struct cras_expr_value *f = ARRAY_ELEMENT(&values, 0);
5149c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			if (f->type == CRAS_EXPR_VALUE_TYPE_FUNCTION)
5159c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				f->u.function(&values, result);
5169c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			else
5179c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				syslog(LOG_ERR,
5189c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				       "first element is not a function");
5199c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		} else {
5209c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			syslog(LOG_ERR, "empty compound expression?");
5219c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
5229c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5239c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		FOR_ARRAY_ELEMENT(&values, i, value) {
5249c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			cras_expr_value_free(value);
5259c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
5269c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5279c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		ARRAY_FREE(&values);
5289c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		break;
5299c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
5309c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
5319c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
5329c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5339c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidint cras_expr_expression_eval_int(struct cras_expr_expression *expr,
5349c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				  struct cras_expr_env *env,
5359c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				  int *integer)
5369c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
5379c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int rc = 0;
5389c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct cras_expr_value value = CRAS_EXPR_VALUE_INIT;
5399c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5409c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	cras_expr_expression_eval(expr, env, &value);
5419c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (value.type == CRAS_EXPR_VALUE_TYPE_INT) {
5429c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		*integer = value.u.integer;
5439c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	} else {
5449c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		syslog(LOG_ERR, "value type is not integer (%d)", value.type);
5459c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		rc = -1;
5469c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
5479c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	cras_expr_value_free(&value);
5489c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return rc;
5499c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
5509c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5519c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidint cras_expr_expression_eval_boolean(struct cras_expr_expression *expr,
5529c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				      struct cras_expr_env *env,
5539c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				      char *boolean)
5549c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
5559c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int rc = 0;
5569c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct cras_expr_value value = CRAS_EXPR_VALUE_INIT;
5579c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5589c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	cras_expr_expression_eval(expr, env, &value);
5599c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (value.type == CRAS_EXPR_VALUE_TYPE_BOOLEAN) {
5609c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		*boolean = value.u.boolean;
5619c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	} else {
5629c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		syslog(LOG_ERR, "value type is not boolean (%d)", value.type);
5639c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		rc = -1;
5649c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
5659c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	cras_expr_value_free(&value);
5669c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return rc;
5679c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
568