#include "declarations.h"
#include "barrier.h"
#include "dsl_helper.h"
#include "dsl_shr.h"
#include "dep_shr.h"
#include "dep.h"



/**
 * @brief Parse and evaluate LISP-style S-expressions.
 *
 * Returns environment handle which can be reused. Environment keeps the state
 * available for future runs. Call dep_free() when done with the environment.
 *
 * @param[in] h   Environment handle returned by earlier dep_run() call or zero
 *                to create new environment
 * @param[in] flg Evaluation mode flags (DEP_MODE_*)
 * @param[in] s   DEP-string to parse and evaluate
 *
 * @example
 *
 * First example calls external function with four parameters, first casted to
 * int, second is the result of an expression, and last two are ordinary
 * strings:
 *
 *  const char *str = "\
 *   (ano_func [int] 123 (add 10 (sub 20 5)) \
 *   \"Hello!\" \"Hello, \\\"world!\\\"\")";
 *
 *  hnd = dep_run(0, DEP_MODE_LOCAL, str);
 *
 *  dep_free(hnd);
 *
 * Another example reuses the same environment to remember defined things in
 * previous run:
 *
 *  const char *str_a = "(define pi 3.14)";
 *  const char *str_b = "(define radius 10)";
 *  const char *str_c = "(mul pi radius radius)";
 *
 *  const char *str_d = "(div 100 2 10)";
 *
 *  const char *str_e = "(define x 42)";
 *  const char *str_f = "(if (> x 50) 100 0)";
 *  const char *str_g = "(if (and (> x 30) (< x 50)) \"Hit\" \"Miss\")";
 *
 *  const char *str_h = "(define y (add 10 (sub 20 5)))";
 *  const char *str_i = "(define z (if (and (> y 20) (< y 30)) \
 *                      \"y is between 20 and 30\" \"y is something else\"))";
 *
 *  hnd = dep_run(0, DEP_MODE_LOCAL, str_a);
 *
 *  dep_run(hnd, DEP_MODE_LOCAL, str_b);
 *  dep_run(hnd, DEP_MODE_LOCAL, str_c);
 *
 *  dep_run(hnd, DEP_MODE_LOCAL, str_d);
 *
 *  dep_run(hnd, DEP_MODE_LOCAL, str_e);
 *  dep_run(hnd, DEP_MODE_LOCAL, str_f);
 *  dep_run(hnd, DEP_MODE_LOCAL, str_g);
 *
 *  dep_run(hnd, DEP_MODE_LOCAL, str_h);
 *  dep_run(hnd, DEP_MODE_LOCAL, str_i);
 *
 *  dep_free(hnd);
 *
 * @retval Environment handle or zero on error
 *
 */

D_HANDLE dep_run(D_HANDLE h, int flg, const char *s) {
	D_HANDLE d;

	struct dep_env *e;
	struct dep_node *n, *r;

	/* Get environment for this session */
	if((e = dep_run_op(h, &d)) == NULL) {
		return(0);
	}

	if((n = dep_parse(&s)) == NULL) {
		(void) dep_free(d);

		return(0);
	}

	if((r = dep_eval(n, e, flg)) == NULL) {
		(void) dep_free_tree(n);
		(void) dep_free(d);

		return(0);
	}

	/* Store expression result to be used later */
	(void) dep_run_at(d, r);

	(void) dep_free_tree(n);

	return(d);
}

static struct dep_env *dep_run_op(D_HANDLE h, D_HANDLE *d) {
	unsigned int i;

	size_t u;

	struct dep_env *e;
	struct dep_hnd **t;

	if(h == 0) {
		/* Create new environment... */
		if((e = dep_env_new()) == NULL) {
			return(NULL);
		}

		/* ...try to use existing slot for it... */
		(void) darkroom_reader_entry((void *) &t_sem_p);

		for(i = 0; i < c_env; i++) {
			if(a_env[i] != NULL) {
				continue;
			}

			u = sizeof(struct dep_hnd);

			if((a_env[i] = malloc(u)) == NULL) {
				LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
					_("Failed to allocate %zu bytes of"
					  " memory"), u);

				(void) darkroom_reader_exit((void *) &t_sem_p);

				(void) free(e);

				return(NULL);
			}

			a_env[i]->hnd = (D_HANDLE) i + 1;
			a_env[i]->env = e;
			a_env[i]->ret = NULL;

			/* Return new handle and environment to caller */
			*d = a_env[i]->hnd;

			D_MEM_BARRIER;

			(void) darkroom_reader_exit((void *) &t_sem_p);

			return(e);
		}

		(void) darkroom_reader_exit((void *) &t_sem_p);

		/* ...or create new slot */
		u = sizeof(struct dep_hnd **) * (c_env + 1);

		D_MEM_BARRIER;

		(void) darkroom_writer_entry((void *) &t_sem_p);

		if((t = realloc(a_env, u)) == NULL) {
			LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
				_("Failed to allocate %zu bytes of"
				  " memory"), u);

			(void) darkroom_writer_exit((void *) &t_sem_p);

			(void) dep_free_envs(e);

			return(NULL);
		}

		a_env = t;

		c_env++;

		u = sizeof(struct dep_hnd);

		if((a_env[c_env - 1] = malloc(u)) == NULL) {
			LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
				_("Failed to allocate %zu bytes of"
				  " memory"), u);

			(void) darkroom_writer_exit((void *) &t_sem_p);

			(void) dep_free_envs(e);

			return(NULL);
		}

		a_env[c_env - 1]->hnd = (D_HANDLE) c_env;
		a_env[c_env - 1]->env = e;
		a_env[c_env - 1]->ret = NULL;

		/* Return new handle and environment to caller */
		*d = (D_HANDLE) a_env[c_env - 1]->hnd;

		D_MEM_BARRIER;

		(void) darkroom_writer_exit((void *) &t_sem_p);

		return(e);
	}

	/* ...or use existing environment */
	(void) darkroom_reader_entry((void *) &t_sem_p);

	for(i = 0; i < c_env; i++) {
		if(a_env[i] == NULL) {
			continue;
		}

		if(a_env[i]->hnd == h) {
			/* Clear possible previous expression result */
			if(a_env[i]->ret != NULL) {
				(void) dep_free_tree(a_env[i]->ret);

				a_env[i]->ret = NULL;
			}

			e = a_env[i]->env;

			D_MEM_BARRIER;

			(void) darkroom_reader_exit((void *) &t_sem_p);

			/* Return existing handle and environment to caller */
			*d = h;

			return(e);
		}
	}

	(void) darkroom_reader_exit((void *) &t_sem_p);

	(void) flush_error();

	LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
		_("Failed to find environment for provided handle"));

	return(NULL);
}

static void dep_run_at(D_HANDLE h, struct dep_node *n) {
	unsigned int i;

	(void) darkroom_reader_entry((void *) &t_sem_p);

	for(i = 0; i < c_env; i++) {
		if(a_env[i] == NULL) {
			continue;
		}

		if(a_env[i]->hnd == h) {
			a_env[i]->ret = n;

			break;
		}
	}

	(void) darkroom_reader_exit((void *) &t_sem_p);
}

/**
 * @brief Get expression result.
 *
 * Get the result returned by expression.
 *
 * @param[in] h Environment handle returned by dep_run()
 * @param[out] r Pointer to data to return
 *
 * @retval Result type (DSL_PARAM_TYPE_*)
 *
 */

unsigned int dep_ret(D_HANDLE h, void **r) {
	unsigned int i, k;

	struct dep_node *n;

	(void) darkroom_reader_entry((void *) &t_sem_p);

	k = DSL_PARAM_TYPE_NONE;

	for(i = 0; i < c_env; i++) {
		if(a_env[i] == NULL) {
			continue;
		}

		if(a_env[i]->hnd == h) {
			if((n = a_env[i]->ret) == NULL) {
				break;
			}

			/* Get expression result by type */
			k = dep_ret_op(n, r);

			break;
		}
	}

	(void) darkroom_reader_exit((void *) &t_sem_p);

	return(k);
}

static unsigned int dep_ret_op(struct dep_node *n, void **r) {
	unsigned int k;

	switch(n->c) {
		case NODE_TYPE_NUMBER:
			k = DSL_PARAM_TYPE_NUMBER;

			*r = (void *) &n->value.num;

			break;
		case NODE_TYPE_STRING:
			k = DSL_PARAM_TYPE_STRING;

			*r = (void *) n->value.str;

			break;
		default:
			k = DSL_PARAM_TYPE_NONE;

			break;
	}

	return(k);
}

/**
 * @brief Free environment.
 *
 * After this call returns, handle is gone for good and should not be used
 * anymore.
 *
 * @param[in] h Environment handle returned by dep_run()
 *
 */

void dep_free(D_HANDLE h) {
	unsigned int i, k;

	(void) darkroom_reader_entry((void *) &t_sem_p);

	for(i = 0; i < c_env; i++) {
		if(a_env[i] == NULL) {
			continue;
		}

		if(a_env[i]->hnd == h) {
			(void) dep_free_tree(a_env[i]->ret);
			(void) dep_free_envs(a_env[i]->env);

			(void) free(a_env[i]);

			a_env[i] = NULL;

			break;
		}
	}

	/* Free environment array also if last handle was closed */
	for(i = 0, k = 0; i < c_env; i++) {
		if(a_env[i] != NULL) {
			k++;

			break;
		}
	}

	(void) darkroom_reader_exit((void *) &t_sem_p);

	if(k == 0) {
		(void) darkroom_writer_entry((void *) &t_sem_p);

		D_MEM_BARRIER;

		(void) free(a_env);

		c_env = 0;
		a_env = NULL;

		D_MEM_BARRIER;

		(void) darkroom_writer_exit((void *) &t_sem_p);
	}
}

static struct dep_node *dep_parse(const char **s) {
	size_t t;

	struct dep_node *n;

	char e[DEP_TOKEN_SIZE];

	/* Skip over initial spaces... */
	while(**s && (
		**s == ' ' || **s == '\t' || **s == '\f' ||
		**s == '\v' || **s == '\r' || **s == '\n')) {

		(*s)++;
	}

	if(**s == 0) {
		return(NULL);
	}

	/* ...and go for it, check if this is list... */
	if(**s == '(') {
		return(dep_parse_list(s));
	}

	/* ...then check for string... */
	if(**s == '"') {
		return(dep_parse_str(s));
	}

	/* ...and for variable */
	if(**s == '$') {
		return(dep_parse_var(s));
	}

	/* This was not list, string or variable, it is an operator of some
	   kind then */
	t = 0;

	while(**s && (
		**s != ' ' && **s != '\t' && **s != '\f' &&
		**s != '\v' && **s != '\r' && **s != '\n' &&
		**s != '(' && **s != ')' && **s != '"')) {

		if(t < sizeof(e) - 1) {
			e[t++] = **s;
		}

		(*s)++;
	}

	if(t == 0) {
		return(NULL);
	}

	e[t] = 0;

	/* Check if this operator is a number... */
	if(dep_parse_num_op(e) == 0) {
		if((n = dep_node_new(NODE_TYPE_NUMBER)) == NULL) {
			return(NULL);
		}

		if(dep_parse_num_at(&n->value.num, e, t) != 0) {
			(void) free(n);

			return(NULL);
		}

		return(n);
	}

	/* ...a cast... */
	if(t > 2 && e[0] == '[' && e[t - 1] == ']') {
		if((n = dep_node_new(NODE_TYPE_CAST)) == NULL) {
			return(NULL);
		}

		e[t - 1] = 0;

		if(dsl_get_num_by_name(e + 1, t - 2,
			(unsigned int *) &n->d) != 0) {

			(void) flush_error();

			LOGWARN(ERROR_NOERROR, SUBSYSTEM,
				_("Failed to recognize cast identifier '%s'"),
					e + 1);

			(void) free(n);

			return(NULL);
		}

		return(n);
	}

	/* ...or symbol name for better keep */
	if((n = dep_node_new(NODE_TYPE_SYMBOL)) == NULL) {
		return(NULL);
	}

	(void) memcpy((void *) n->value.sym, e, t);

	n->value.sym[t] = 0;

	return(n);
}

static struct dep_node *dep_parse_list(const char **s) {
	struct dep_node *n, *c;

	(*s)++;

	/* Save all recursive nodes for later use */
	if((n = dep_node_new(NODE_TYPE_LIST)) == NULL) {
		return(NULL);
	}

	while(**s && **s != ')') {
		if((c = dep_parse(s)) != NULL) {
			if(dep_node_add(n, c) != 0) {
				(void) dep_free_tree(c);

				(void) free(n);

				return(NULL);
			}
		}
	}

	/* Skip over last closing parenthesis */
	if(**s == ')') {
		(*s)++;
	}

	return(n);
}

static struct dep_node *dep_parse_str(const char **s) {
	size_t k;

	const char *p;

	struct dep_node *n;

	(*s)++;

	if((n = dep_node_new(NODE_TYPE_STRING)) == NULL) {
		return(NULL);
	}

	/* Save string for later use */
	p = *s;
	k = dep_parse_str_op(s);

	if((n->value.str = malloc(k + 1)) == NULL) {
		LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
			_("Failed to allocate %zu bytes of memory"),
				k + 1);

		(void) free(n);

		return(NULL);
	}

	(void) memcpy((void *) n->value.str, (const void *) p, k);

	n->value.str[k] = 0;

	/* Replace escaped characters... */
	(void) dep_parse_str_at(n->value.str);

	/* ...and skip over last closing quote */
	if(**s == '"') {
		(*s)++;
	}

	return(n);
}

static size_t dep_parse_str_op(const char **s) {
	size_t c, r;

	const char *e, *p;

	e = *s;
	r = 0;

	/* Get length of string taking escaped quotes into account */
	while(**s) {
		if(**s == '"') {
			p = *s - 1;
			c = 0;

			while(p >= e && *p == '\\') {
				c++;
				p--;
			}

			if(c % 2 == 0) {
				break;
			}
		}

		(*s)++;

		r++;
	}

	return(r);
}

static void dep_parse_str_at(char *s) {
	char *d;

	d = s;

	/* Replace escaped characters with real ones */
	while(*s != 0) {
		if(*s == '\\') {
			s++;

			switch(*s) {
				case 'a':
					*d++ = '\a';

					s++;

					break;
				case 'b':
					*d++ = '\b';

					s++;

					break;
				case 't':
					*d++ = '\t';

					s++;

					break;
				case 'v':
					*d++ = '\v';

					s++;

					break;
				case 'f':
					*d++ = '\f';

					s++;

					break;
				case 'e':
					*d++ = '\x1b';

					s++;

					break;
				case 'n':
					*d++ = '\n';

					s++;

					break;
				case 'r':
					*d++ = '\r';

					s++;

					break;
				case '\'':
					*d++ = '\'';

					s++;

					break;
				case '"':
					*d++ = '"';

					s++;

					break;
				case '\\':
					*d++ = '\\';

					s++;

					break;
				case 0:
					/* Last character was backslash */
					*d++ = '\\';

					break;
				default:
					/* Retain backslash and escaped
					   character */
					*d++ = '\\';
					*d++ = *s++;

					break;
			}

			continue;
		}

		*d++ = *s++;
	}

	*d = 0;
}

static struct dep_node *dep_parse_var(const char **s) {
	size_t t;

	struct dep_node *n;

	(*s)++;

	if((n = dep_node_new(NODE_TYPE_ANOVAR)) == NULL) {
		return(NULL);
	}

	t = 0;

	while(**s && (
		**s != ' ' && **s != '\t' && **s != '\f' &&
		**s != '\v' && **s != '\r' && **s != '\n' &&
		**s != '(' && **s != ')' && **s != '"')) {

		if(t < sizeof(n->value.sym) - 1) {
			n->value.sym[t++] = **s;
		}

		(*s)++;
	}

	if(t == 0) {
		(void) free(n);

		return(NULL);
	}

	n->value.sym[t] = 0;

	return(n);
}

static int dep_parse_num_op(char *s) {
	int a, b, c;

	if(*s == 0) {
		return(-1);
	}

	/* Skip over optional sign */
	if(*s == '+' || *s == '-') {
		s++;
	}

	/* Read integer part and optional fractional part */
	a = 0;
	b = 0;

	while(*s != 0) {
		if(*s >= '0' && *s <= '9') {
			a++;
			s++;
		}
		else if(*s == '.') {
			/* Only one period is allowed */
			if(b != 0) {
				return(-1);
			}

			b++;
			s++;
		}
		else {
			break;
		}
	}

	/* If no numbers so far, this is not a number */
	if(a == 0) {
		return(-1);
	}

	/* Check possible exponent */
	c = 0;

	if(*s == 'e' || *s == 'E') {
		s++;

		/* Exponent may have sign */
		if(*s == '+' || *s == '-') {
			s++;
		}

		/* There must be at least one number after exponent */
		while(*s >= '0' && *s <= '9') {
			c++;
			s++;
		}

		if(c == 0 || *s != 0) {
			return(-1);
		}
	}

	return(0);
}

static int dep_parse_num_at(D_NUMBER *d, char *s, size_t t) {
	int e;

	D_NUMBER r;

	char *f;

	(void) flush_error();

	r = (D_NUMBER) strtod((const char *) s, &f);

	(void) get_error(&e);

	if(e == ERANGE || (uintptr_t) s == (uintptr_t) f ||
		(size_t) ((uintptr_t) f - (uintptr_t) s) != t) {

		LOGWARN(ERROR_NOERROR, SUBSYSTEM,
			_("Failed to convert string to number"));

		return(-1);
	}

	*d = r;

	return(0);
}

static struct dep_node *dep_eval(struct dep_node *n, struct dep_env *e, int flg) {
	struct dep_node *c;

	if(n == NULL) {
		return(NULL);
	}

	switch(n->c) {
		case NODE_TYPE_ANOVAR:
			if(dep_eval_var(n) != 0) {
				return(NULL);
			}

			break;
		case NODE_TYPE_SYMBOL:
			if((c = dep_env_get(e, n->value.sym)) != NULL) {
				return(dep_node_cpy(c));
			}

			break;
		case NODE_TYPE_LIST:
			return(dep_eval_list(n, e, flg));
		default:
			break;
	}

	return(dep_node_cpy(n));
}

static struct dep_node *dep_eval_list(struct dep_node *n, struct dep_env *e, int flg) {
	ssize_t i;

	size_t t;

	struct dep_node *c;
	struct dep_node *(*fn)(struct dep_node *, struct dep_env *, int);

	if(n->value.list.c == 0) {
		return(dep_node_cpy(n));
	}

	c = n->value.list.child[0];

	if(c->c != NODE_TYPE_SYMBOL) {
		(void) flush_error();

		LOGWARN(ERROR_NOERROR, SUBSYSTEM,
			_("List must start with symbol"));

		return(NULL);
	}

	/* Call operator function for this symbol... */
	if(c->offs != -1) {
		fn = t_dep_eval_t[c->offs].fn;

		return((*fn)(n, e, t_dep_eval_t[c->offs].e));
	}

	/* ...or figure it out first */
	t = str_len(c->value.sym, STRING_ASCII);

	for(i = 0; ; i++) {
		if(t_dep_eval_t[i].s == NULL) {
			/* Symbol was unknown, treat it as function then */
			return(dep_eval_func(n, e, c->value.sym, flg));
		}

		if(t_dep_eval_t[i].t != t) {
			continue;
		}

		if(strncasecmp(t_dep_eval_t[i].s,
			(const char *) c->value.sym, t) == 0) {

			fn = t_dep_eval_t[i].fn;

			/* Keep the offset for this symbol for next run */
			c->offs = i;

			return((*fn)(n, e, t_dep_eval_t[i].e));
		}
	}

	return(NULL);
}

static struct dep_node *dep_eval_func(struct dep_node *n, struct dep_env *e, char *p, int flg) {
	size_t i;

	int c, d;

	struct d_par dp;

	struct dep_node *r, *s;

	/* Check if remotely called function is allowed to run */
	if((flg & DEP_MODE_REMOTE) == DEP_MODE_REMOTE) {
		if(dsl_get_remote((const char *) p) != IS_YES) {
			return(NULL);
		}
	}

	(void) memset((void *) &dp, 0, sizeof(dp));

	dp.s = p;
	dp.c = 0;

	s = NULL;

	for(i = 1, d = -1; i < n->value.list.c; i++) {
		if(dp.c >= D_PAR_MAX_PARAMS) {
			(void) flush_error();

			LOGWARN(ERROR_NOERROR, SUBSYSTEM,
				_("Failed to handle parameter, parameter"
				  " count %u exceeded"),
					(unsigned int) D_PAR_MAX_PARAMS);

			(void) dep_eval_func_et(s, &dp);

			return(NULL);
		}

		if((s = dep_eval(n->value.list.child[i], e, flg)) == NULL) {
			(void) dep_eval_func_et(s, &dp);

			return(NULL);
		}

		switch(s->c) {
			case NODE_TYPE_CAST:
				/* Cast is always in previous node to what it
				   casts, store it for next iteration */
				d = s->d;

				break;
			default:
				break;
		}

		D_MEM_BARRIER;

		switch(s->c) {
			case NODE_TYPE_NUMBER:
				if(dep_eval_func_num(s,
					&dp.dp[dp.c++], d) != 0) {

					(void) dep_eval_func_et(s, &dp);

					return(NULL);
				}

				break;
			case NODE_TYPE_STRING:
				if(dep_eval_func_str(s,
					&dp.dp[dp.c++]) != 0) {

					(void) dep_eval_func_et(s, &dp);

					return(NULL);
				}

				break;
			case NODE_TYPE_ANOVAR:
				switch(n->value.list.child[i]->offs) {
					case DSL_PARAM_TYPE_NUMBER:
						if(dep_eval_func_num(s,
							&dp.dp[dp.c++], d) != 0) {

							(void) dep_eval_func_et(s, &dp);

							return(NULL);
						}

						break;
					case DSL_PARAM_TYPE_STRING:
						if(dep_eval_func_str(s,
							&dp.dp[dp.c++]) != 0) {

							(void) dep_eval_func_et(s, &dp);

							return(NULL);
						}

						break;
					default:
						break;
				}

				break;
			default:
				break;
		}

		/* Cast is consumed, reset it */
		if(s->c != NODE_TYPE_CAST) {
			d = -1;
		}

		(void) dep_free_tree(s);

		s = NULL;
	}

	/* Inject end label in top of stack so ret command after called
	   function jumps there... */
	if(dsl_stack_node_inject(DSL_RUN_END) != 0) {
		(void) dep_eval_func_et(s, &dp);

		return(NULL);
	}

	/* ...and run the function */
	if((flg & DEP_MODE_INSTANCE) == DEP_MODE_INSTANCE) {
		c = dsl_run_sub_inst(&dp);
	}
	else {
		c = dsl_run_sub(NULL, &dp);
	}

	if((r = dep_eval_func_rt(c)) == NULL) {
		(void) dep_eval_func_et(s, &dp);

		return(NULL);
	}

	/* Free allocated parameter stuff */
	(void) dep_eval_func_et(s, &dp);

	return(r);
}

static struct dep_node *dep_eval_func_rt(int r) {
	size_t t;

	struct dep_node *n;

	struct dsl_ctx *c;
	struct dsl_var *v;

	c = dsl_get_main_ctx();

	/* Get global variable rc... */
	if((v = dsl_var_get_struct_by_name(dsl_get_rc_var(),
		&c->global)) == NULL) {

		return(NULL);
	}

	/* ...and get function return value from there */
	n = NULL;

	switch(v->c) {
		case DSL_PARAM_TYPE_NONE:
			/* Function does not necessarily set return code,
			   use default end code in that case */
			if((n = dep_node_new(NODE_TYPE_NUMBER)) == NULL) {
				return(NULL);
			}

			n->offs = DSL_PARAM_TYPE_NUMBER;
			n->value.num = (D_NUMBER) r;

			break;
		case DSL_PARAM_TYPE_NUMBER:
			if((n = dep_node_new(NODE_TYPE_NUMBER)) == NULL) {
				return(NULL);
			}

			n->offs = DSL_PARAM_TYPE_NUMBER;
			n->value.num = dsl_num_get_number(v->number->c,
				v->number, c);

			break;
		case DSL_PARAM_TYPE_STRING:
			if((n = dep_node_new(NODE_TYPE_STRING)) == NULL) {
				return(NULL);
			}

			t = dsl_str_get_length(v->string);

			if((n->value.str = malloc(t + sizeof(char))) == NULL) {
				LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
					_("Failed to allocate %zu bytes of"
					  " memory"), t + sizeof(char));

				(void) free(n);

				return(NULL);
			}

			n->offs = DSL_PARAM_TYPE_STRING;

			(void) memcpy((void *) n->value.str,
				(const void *) dsl_str_get_string(v->string), t);

			n->value.str[t] = 0;

			break;
		default:
			(void) flush_error();

			LOGWARN(ERROR_NOERROR, SUBSYSTEM,
				_("Return value type is incompatible"));

			break;
	}

	return(n);
}

static void dep_eval_func_et(struct dep_node *n, struct d_par *dp) {
	unsigned int i;

	if(n != NULL) {
		(void) dep_free_tree(n);
	}

	for(i = 0; i < dp->c; i++) {
		switch(dp->dp[i].c) {
			case DSL_PARAM_TYPE_STRING:
				(void) free(dp->dp[i].p.str);

				break;
			default:
				break;
		}
	}
}

static int dep_eval_func_num(struct dep_node *n, struct d_par_t *dt, int d) {
	unsigned int c;

	if(d == -1) {
		c = DSL_NUMBER_TYPE_DEFAULT;
	}
	else {
		c = (unsigned int) d;
	}

	dt->c = DSL_PARAM_TYPE_NUMBER;
	dt->d = c;

	dt->p.num = n->value.num;

	return(0);
}

static int dep_eval_func_str(struct dep_node *n, struct d_par_t *dt) {
	size_t t;

	char *s;

	t = str_len(n->value.str, STRING_ASCII);

	if((s = malloc(t + sizeof(char))) == NULL) {
		LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
			_("Failed to allocate %zu bytes of memory"), t);

		return(-1);
	}

	(void) memcpy((void *) s, (const void *) n->value.str, t);

	s[t] = 0;

	dt->c = DSL_PARAM_TYPE_STRING;
	dt->t = t;

	dt->p.str = s;

	return(0);
}

static int dep_eval_var(struct dep_node *n) {
	struct dsl_ctx *c;
	struct dsl_var *v;

	struct dsl_str s;

	c = dsl_get_main_ctx();

	(void) memset((void *) &s, 0, sizeof(s));

	(void) dsl_var_init_default(&s, n->value.sym,
		str_len(n->value.sym, STRING_ASCII), 0);

	(void) dsl_var_init_default_cs(&s,
		STRING_UTF8,
		CHARSET_DEFAULT,
		CHARSET_DEFAULT_SIZE, 0);

	if((v = dsl_var_get_struct_by_name(&s, &c->global)) == NULL) {
		(void) flush_error();

		LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
			_("Variable is not defined in this scope"));

		return(-1);
	}

	switch(v->c) {
		case DSL_PARAM_TYPE_NUMBER:
			n->offs = DSL_PARAM_TYPE_NUMBER;
			n->value.num = dsl_num_get_number(v->number->c,
				v->number, c);

			break;
		case DSL_PARAM_TYPE_STRING:
			n->offs = DSL_PARAM_TYPE_STRING;
			n->value.str = dsl_str_get_string(v->string);

			break;
		default:
			(void) flush_error();

			LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
				_("Variable type is incompatible"));

			return(-1);
	}

	return(0);
}

static struct dep_node *dep_eval_define(struct dep_node *n, struct dep_env *e, __UNUSED__ int p) {
	struct dep_node *c, *r;

	if(n->value.list.c != 3) {
		(void) flush_error();

		LOGWARN(ERROR_NOERROR, SUBSYSTEM,
			_("Wrong number of arguments %zu for define,"
			  " two is required"), n->value.list.c - 1);

		return(NULL);
	}

	if((r = dep_eval(n->value.list.child[2], e,
		DEP_MODE_LOCAL)) == NULL) {

		return(NULL);
	}

	c = n->value.list.child[1];

	if(dep_env_set(e, c->value.sym, r) != 0) {
		return(NULL);
	}

	return(r);
}

static struct dep_node *dep_eval_if(struct dep_node *n, struct dep_env *e, __UNUSED__ int p) {
	struct dep_node *c, *r;

	if(n->value.list.c < 3) {
		(void) flush_error();

		LOGWARN(ERROR_NOERROR, SUBSYSTEM,
			_("Wrong number of arguments %zu for if statement,"
			  " at least two is required"), n->value.list.c - 1);

		return(NULL);
	}

	if((c = dep_eval(n->value.list.child[1], e,
		DEP_MODE_LOCAL)) == NULL) {

		return(NULL);
	}

	if(dep_eval_true(c)) {
		if((r = dep_eval(n->value.list.child[2], e,
			DEP_MODE_LOCAL)) == NULL) {

			(void) dep_free_tree(c);

			return(NULL);
		}
	}
	else if(n->value.list.c > 3) {
		if((r = dep_eval(n->value.list.child[3], e,
			DEP_MODE_LOCAL)) == NULL) {

			(void) dep_free_tree(c);

			return(NULL);
		}
	}
	else {
		r = NULL;
	}

	(void) dep_free_tree(c);

	return(r);
}

static struct dep_node *dep_eval_cmp(struct dep_node *n, struct dep_env *e, int p) {
	int c;

	D_NUMBER lc, rc;

	struct dep_node *l, *r;

	if(n->value.list.c != 3) {
		(void) flush_error();

		LOGWARN(ERROR_NOERROR, SUBSYSTEM,
			_("Wrong number of arguments %zu for comparison,"
			  " two is required"), n->value.list.c - 1);

		return(NULL);
	}

	if((l = dep_eval(n->value.list.child[1], e,
		DEP_MODE_LOCAL)) == NULL) {

		return(NULL);
	}

	if(dep_eval_cmp_op(l, &lc) != 0) {
		(void) dep_free_tree(l);

		return(NULL);
	}

	if((r = dep_eval(n->value.list.child[2], e,
		DEP_MODE_LOCAL)) == NULL) {

		(void) dep_free_tree(l);

		return(NULL);
	}

	if(dep_eval_cmp_op(r, &rc) != 0) {
		(void) dep_free_tree(l);
		(void) dep_free_tree(r);

		return(NULL);
	}

	if((c = dep_eval_cmp_at(lc, rc, p)) == -1) {
		(void) dep_free_tree(l);
		(void) dep_free_tree(r);

		return(NULL);
	}

	(void) dep_free_tree(l);
	(void) dep_free_tree(r);

	return(dep_eval_bool(c));
}

static int dep_eval_cmp_op(struct dep_node *n, D_NUMBER *r) {
	switch(n->c) {
		case NODE_TYPE_NUMBER:
			*r = n->value.num;

			break;
		case NODE_TYPE_ANOVAR:
			switch(n->offs) {
				case DSL_PARAM_TYPE_NUMBER:
					*r = n->value.num;

					break;
				default:
					(void) flush_error();

					LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
						_("Variable type is"
						  " incompatible"));

					return(-1);
			}

			break;
		default:
			(void) flush_error();

			LOGWARN(ERROR_NOERROR, SUBSYSTEM,
				_("Wrong number of arguments %zu for"
				  " comparison, two numbers or variables"
				  " is required"),
				  	n->value.list.c - 1);

			return(-1);
	}

	return(0);
}

static int dep_eval_cmp_at(D_NUMBER l, D_NUMBER r, int p) {
	int c;

	switch(p) {
		case 1:
#if (D_NUMBER_IS_WHICH == 1)
			if(is_eq_double((double) l, (double) r)) {
				c = 1;
			}
			else {
				c = 0;
			}
#else
			c = (l == r);
#endif
			break;
		case 2:
#if (D_NUMBER_IS_WHICH == 1)
			if(is_eq_double((double) l, (double) r)) {
				c = 0;
			}
			else {
				c = 1;
			}
#else
			c = (l != r);
#endif
			break;
		case 3:
			c = (l < r);

			break;
		case 4:
			c = (l > r);

			break;
		case 5:
			c = (l <= r);

			break;
		case 6:
			c = (l >= r);

			break;
		default:
			c = -1;

			break;
	}

	return(c);
}

static struct dep_node *dep_eval_and(struct dep_node *n, struct dep_env *e, __UNUSED__ int p) {
	size_t i;

	struct dep_node *r;

	if(n->value.list.c < 2) {
		(void) flush_error();

		LOGWARN(ERROR_NOERROR, SUBSYSTEM,
			_("Wrong number of arguments %zu for and operator,"
			  " at least one is required"), n->value.list.c - 1);

		return(NULL);
	}

	for(i = 1; i < n->value.list.c; i++) {
		if((r = dep_eval(n->value.list.child[i], e,
			DEP_MODE_LOCAL)) == NULL) {

			return(NULL);
		}

		if(!dep_eval_true(r)) {
			(void) dep_free_tree(r);

			return(dep_eval_bool(0));
		}

		if(i == n->value.list.c - 1) {
			/* Return last value */
			return(r);
		}

		(void) dep_free_tree(r);
	}

	return(dep_eval_bool(1));
}

static struct dep_node *dep_eval_or(struct dep_node *n, struct dep_env *e, __UNUSED__ int p) {
	size_t i;

	struct dep_node *r;

	if(n->value.list.c < 2) {
		(void) flush_error();

		LOGWARN(ERROR_NOERROR, SUBSYSTEM,
			_("Wrong number of arguments %zu for or operator,"
			  " at least one is required"), n->value.list.c - 1);

		return(NULL);
	}

	for(i = 1; i < n->value.list.c; i++) {
		if((r = dep_eval(n->value.list.child[i], e,
			DEP_MODE_LOCAL)) == NULL) {

			return(NULL);
		}

		if(dep_eval_true(r)) {
			/* Return first true value */
			return(r);
		}

		(void) dep_free_tree(r);
	}

	return(dep_eval_bool(0));
}

static struct dep_node *dep_eval_not(struct dep_node *n, struct dep_env *e, __UNUSED__ int p) {
	int v;

	struct dep_node *r;

	if(n->value.list.c != 2) {
		(void) flush_error();

		LOGWARN(ERROR_NOERROR, SUBSYSTEM,
			_("Wrong number of arguments %zu for not operator,"
			  " one is required"), n->value.list.c - 1);

		return(NULL);
	}

	if((r = dep_eval(n->value.list.child[1], e,
		DEP_MODE_LOCAL)) == NULL) {

		return(NULL);
	}

	v = !dep_eval_true(r);

	(void) dep_free_tree(r);

	return(dep_eval_bool(v));
}

static struct dep_node *dep_eval_abs(struct dep_node *n, struct dep_env *e, __UNUSED__ int p) {
	D_NUMBER v;

	struct dep_node *r, *s;

	if(n->value.list.c != 2) {
		(void) flush_error();

		LOGWARN(ERROR_NOERROR, SUBSYSTEM,
			_("Wrong number of arguments %zu for abs operator,"
			  " one is required"), n->value.list.c - 1);

		return(NULL);
	}

	if((s = dep_eval(n->value.list.child[1], e,
		DEP_MODE_LOCAL)) == NULL) {

		return(NULL);
	}

	v = s->value.num;

	switch(s->c) {
		case NODE_TYPE_NUMBER:
			v = fabs((double) v);

			break;
		case NODE_TYPE_ANOVAR:
			switch(s->offs) {
				case DSL_PARAM_TYPE_NUMBER:
					v = fabs((double) v);

					break;
				default:
					(void) flush_error();

					LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
						_("Variable type is"
						  " incompatible"));

					(void) dep_free_tree(s);

					return(NULL);
			}

			break;
		default:
			break;
	}

	(void) dep_free_tree(s);

	if((r = dep_node_new(NODE_TYPE_NUMBER)) == NULL) {
		return(NULL);
	}

	r->value.num = v;

	return(r);
}

static struct dep_node *dep_eval_add(struct dep_node *n, struct dep_env *e, __UNUSED__ int p) {
	size_t i;

	D_NUMBER v;

	struct dep_node *r, *s;

	if(n->value.list.c < 2) {
		(void) flush_error();

		LOGWARN(ERROR_NOERROR, SUBSYSTEM,
			_("Wrong number of arguments %zu for addition,"
			  " at least one is required"), n->value.list.c - 1);

		return(NULL);
	}

	for(i = 1, v = 0; i < n->value.list.c; i++) {
		if((s = dep_eval(n->value.list.child[i], e,
			DEP_MODE_LOCAL)) == NULL) {

			return(NULL);
		}

		switch(s->c) {
			case NODE_TYPE_NUMBER:
				v += s->value.num;

				break;
			case NODE_TYPE_ANOVAR:
				switch(s->offs) {
					case DSL_PARAM_TYPE_NUMBER:
						v += s->value.num;

						break;
					default:
						(void) flush_error();

						LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
							_("Variable type is"
							  " incompatible"));

						(void) dep_free_tree(s);

						return(NULL);
				}

				break;
			default:
				break;
		}

		(void) dep_free_tree(s);
	}

	if((r = dep_node_new(NODE_TYPE_NUMBER)) == NULL) {
		return(NULL);
	}

	r->value.num = v;

	return(r);
}

static struct dep_node *dep_eval_sub(struct dep_node *n, struct dep_env *e, __UNUSED__ int p) {
	size_t i;

	D_NUMBER v;

	struct dep_node *r, *s;

	if(n->value.list.c < 2) {
		(void) flush_error();

		LOGWARN(ERROR_NOERROR, SUBSYSTEM,
			_("Wrong number of arguments %zu for subtract,"
			  " at least one is required"), n->value.list.c - 1);

		return(NULL);
	}

	/* Get first number... */
	if((s = dep_eval(n->value.list.child[1], e,
		DEP_MODE_LOCAL)) == NULL) {

		return(NULL);
	}

	switch(s->c) {
		case NODE_TYPE_NUMBER:
			v = s->value.num;

			break;
		case NODE_TYPE_ANOVAR:
			switch(s->offs) {
				case DSL_PARAM_TYPE_NUMBER:
					v = s->value.num;

					break;
				default:
					(void) flush_error();

					LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
						_("Variable type is"
						  " incompatible"));

					(void) dep_free_tree(s);

					return(NULL);
			}

			break;
		default:
			(void) dep_free_tree(s);

			return(NULL);
	}

	(void) dep_free_tree(s);

	/* ...and handle the rest */
	if(n->value.list.c == 2) {
		/* Return complement if only one value was given */
		v = -v;
	}
	else {
		for(i = 2; i < n->value.list.c; i++) {
			if((s = dep_eval(n->value.list.child[i], e,
				DEP_MODE_LOCAL)) == NULL) {

				return(NULL);
			}

			switch(s->c) {
				case NODE_TYPE_NUMBER:
					v -= s->value.num;

					break;
				case NODE_TYPE_ANOVAR:
					switch(s->offs) {
						case DSL_PARAM_TYPE_NUMBER:
							v -= s->value.num;

							break;
						default:
							(void) flush_error();

							LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
								_("Variable type is"
								  " incompatible"));

							(void) dep_free_tree(s);

							return(NULL);
					}

					break;
				default:
					break;
			}

			(void) dep_free_tree(s);
		}
	}

	if((r = dep_node_new(NODE_TYPE_NUMBER)) == NULL) {
		return(NULL);
	}

	r->value.num = v;

	return(r);
}

static struct dep_node *dep_eval_mul(struct dep_node *n, struct dep_env *e, __UNUSED__ int p) {
	size_t i;

	D_NUMBER v;

	struct dep_node *r, *s;

	if(n->value.list.c < 2) {
		(void) flush_error();

		LOGWARN(ERROR_NOERROR, SUBSYSTEM,
			_("Wrong number of arguments %zu for multiply,"
			  " at least one is required"), n->value.list.c - 1);

		return(NULL);
	}

	for(i = 1, v = 1; i < n->value.list.c; i++) {
		if((s = dep_eval(n->value.list.child[i], e,
			DEP_MODE_LOCAL)) == NULL) {

			return(NULL);
		}

		switch(s->c) {
			case NODE_TYPE_NUMBER:
				v *= s->value.num;

				break;
			case NODE_TYPE_ANOVAR:
				switch(s->offs) {
					case DSL_PARAM_TYPE_NUMBER:
						v *= s->value.num;

						break;
					default:
						(void) flush_error();

						LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
							_("Variable type is"
							  " incompatible"));

						(void) dep_free_tree(s);

						return(NULL);
				}

				break;
			default:
				break;
		}

		(void) dep_free_tree(s);
	}

	if((r = dep_node_new(NODE_TYPE_NUMBER)) == NULL) {
		return(NULL);
	}

	r->value.num = v;

	return(r);
}

static struct dep_node *dep_eval_div(struct dep_node *n, struct dep_env *e, int p) {
	size_t i;

	D_NUMBER v;

	struct dep_node *r, *s;

	if(n->value.list.c < 2) {
		(void) flush_error();

		LOGWARN(ERROR_NOERROR, SUBSYSTEM,
			_("Wrong number of arguments %zu for divide,"
			  " at least one is required"), n->value.list.c - 1);

		return(NULL);
	}

	/* Get first number... */
	if((s = dep_eval(n->value.list.child[1], e,
		DEP_MODE_LOCAL)) == NULL) {

		return(NULL);
	}

	switch(s->c) {
		case NODE_TYPE_NUMBER:
			v = s->value.num;

			break;
		case NODE_TYPE_ANOVAR:
			switch(s->offs) {
				case DSL_PARAM_TYPE_NUMBER:
					v = s->value.num;

					break;
				default:
					(void) flush_error();

					LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
						_("Variable type is"
						  " incompatible"));

					(void) dep_free_tree(s);

					return(NULL);
			}

			break;
		default:
			(void) dep_free_tree(s);

			return(NULL);
	}

	(void) dep_free_tree(s);

	/* ...and handle the rest */
	for(i = 2; i < n->value.list.c; i++) {
		if((s = dep_eval(n->value.list.child[i], e,
			DEP_MODE_LOCAL)) == NULL) {

			return(NULL);
		}

		switch(s->c) {
			case NODE_TYPE_NUMBER:
#if (D_NUMBER_IS_WHICH == 1)
				if(is_eq_double((double) s->value.num, 0.0)) {
#else
				if(s->value.num == 0) {
#endif
					(void) flush_error();

					LOGWARN(ERROR_NOERROR, SUBSYSTEM,
						_("Division by zero"));

					(void) dep_free_tree(s);

					return(NULL);
				}

				switch(p) {
					case 1:
						v /= s->value.num;

						break;
					case 2:
#if (D_NUMBER_IS_WHICH == 1)
						v = (D_NUMBER) fmod((double) v,
							(double) s->value.num);
#else
						v %= s->value.num;
#endif
						break;
					default:
						break;
				}

				break;
			case NODE_TYPE_ANOVAR:
				switch(s->offs) {
					case DSL_PARAM_TYPE_NUMBER:
#if (D_NUMBER_IS_WHICH == 1)
						if(is_eq_double((double) s->value.num, 0.0)) {
#else
						if(s->value.num == 0) {
#endif
							(void) flush_error();

							LOGWARN(ERROR_NOERROR, SUBSYSTEM,
								_("Division by zero"));

							(void) dep_free_tree(s);

							return(NULL);
						}

						switch(p) {
							case 1:
								v /= s->value.num;

								break;
							case 2:
#if (D_NUMBER_IS_WHICH == 1)
								v = (D_NUMBER) fmod((double) v,
									(double) s->value.num);
#else
								v %= s->value.num;
#endif
								break;
							default:
								break;
						}

						break;
					default:
						(void) flush_error();

						LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
							_("Variable type is"
							  " incompatible"));

						break;
				}

				break;
			default:
				break;
		}

		(void) dep_free_tree(s);
	}

	if((r = dep_node_new(NODE_TYPE_NUMBER)) == NULL) {
		return(NULL);
	}

	r->value.num = v;

	return(r);
}

static struct dep_node *dep_eval_bool(int v) {
	struct dep_node *n;

	if((n = dep_node_new(NODE_TYPE_SYMBOL)) == NULL) {
		return(NULL);
	}

	(void) memcpy((void *) n->value.sym, v ? "#t" : "#f", 2);

	n->value.sym[2] = 0;

	return(n);
}

static int dep_eval_true(struct dep_node *n) {
	if(n != NULL && n->c == NODE_TYPE_SYMBOL) {
		/* Check for true which is '#t' */
		if(n->value.sym[0] == '#' && n->value.sym[1] == 't' &&
			n->value.sym[2] == 0) {

			return(1);
		}
	}

	return(0);
}

static int dep_node_add(struct dep_node *p, struct dep_node *c) {
	size_t t;

	struct dep_node **n;

	t = (p->value.list.c + 1) * sizeof(struct dep_node *);

	if((n = realloc(p->value.list.child, t)) == NULL) {
		LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
			_("Failed to allocate %zu bytes of memory"), t);

		return(-1);
	}

	p->value.list.child = n;

	p->value.list.child[p->value.list.c++] = c;

	return(0);
}

static struct dep_node *dep_node_cpy(struct dep_node *n) {
	size_t i;

	struct dep_node *c, *d, *e;

	if(n == NULL) {
		return(NULL);
	}

	if((d = dep_node_new(n->c)) == NULL) {
		return(NULL);
	}

	switch(n->c) {
		case NODE_TYPE_NUMBER:
			d->value.num = n->value.num;

			break;
		case NODE_TYPE_STRING:
			if((d->value.str = str_dup((const char *) n->value.str,
				STRING_ASCII)) == NULL) {

				(void) free(d);

				return(NULL);
			}

			break;
		case NODE_TYPE_ANOVAR:
			/* Falls through */
		case NODE_TYPE_SYMBOL:
			d->offs = n->offs;

			(void) memcpy((void *) d->value.sym,
				(const void *) n->value.sym,
					sizeof(d->value.sym));

			break;
		case NODE_TYPE_CAST:
			d->d = n->d;

			break;
		case NODE_TYPE_LIST:
			for(i = 0; i < n->value.list.c; i++) {
				c = n->value.list.child[i];

				if((e = dep_node_cpy(c)) == NULL) {
					(void) free(d);

					return(NULL);
				}

				if(dep_node_add(d, e) != 0) {
					(void) free(e);
					(void) free(d);

					return(NULL);
				}
			}

			break;
		default:
			break;
	}

	return(d);
}

static struct dep_node *dep_node_new(int c) {
	struct dep_node *n;

	if((n = malloc(sizeof(struct dep_node))) == NULL) {
		LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
			_("Failed to allocate %zu bytes of memory"),
				sizeof(struct dep_node));

		return(NULL);
	}

	(void) memset((void *) n, 0, sizeof(struct dep_node));

	n->c = c;
	n->d = -1;

	n->offs = -1;

	n->value.str = NULL;

	n->value.list.c = 0;
	n->value.list.child = NULL;

	return(n);
}

static struct dep_env *dep_env_new(void) {
	struct dep_env *e;

	if((e = malloc(sizeof(struct dep_env))) == NULL) {
		LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
			_("Failed to allocate %zu bytes of memory"),
				sizeof(struct dep_env));

		return(NULL);
	}

	e->head = NULL;

	return(e);
}

static struct dep_node *dep_env_get(struct dep_env *e, char *s) {
	size_t t;

	struct dep_env_it *c;

	t = str_len(s, STRING_ASCII);

	if(t >= DEP_TOKEN_SIZE) {
		t = DEP_TOKEN_SIZE - 1;
	}

	c = e->head;

	while(c != NULL) {
		if(str_len(c->name, STRING_ASCII) == t) {
			if(strncasecmp((const char *) c->name,
				(const char *) s, t) == 0) {

				return(c->value);
			}
		}

		c = c->next;
	}

	return(NULL);
}

static int dep_env_set(struct dep_env *e, char *s, struct dep_node *v) {
	size_t t;

	struct dep_env_it *c, *d;

	t = str_len(s, STRING_ASCII);

	if(t >= DEP_TOKEN_SIZE) {
		t = DEP_TOKEN_SIZE - 1;
	}

	c = e->head;

	while(c != NULL) {
		if(str_len(c->name, STRING_ASCII) == t) {
			if(strncasecmp((const char *) c->name,
				(const char *) s, t) == 0) {

				(void) dep_free_tree(c->value);

				c->value = dep_node_cpy(v);

				return(0);
			}
		}

		c = c->next;
	}

	if((d = malloc(sizeof(struct dep_env_it))) == NULL) {
		LOGWARN(ERROR_SLIGHT, SUBSYSTEM,
			_("Failed to allocate %zu bytes of memory"),
				sizeof(struct dep_env_it));

		return(-1);
	}

	(void) memcpy((void *) d->name, (const void *) s, t);

	d->name[t] = 0;

	d->value = dep_node_cpy(v);
	d->next = e->head;

	e->head = d;

	return(0);
}

static void dep_free_tree(struct dep_node *n) {
	size_t i;

	struct dep_node *c;

	if(n == NULL) {
		return;
	}

	switch(n->c) {
		case NODE_TYPE_STRING:
			(void) free(n->value.str);

			break;
		case NODE_TYPE_LIST:
			for(i = 0; i < n->value.list.c; i++) {
				c = n->value.list.child[i];

				(void) dep_free_tree(c);
			}

			(void) free(n->value.list.child);

			break;
		default:
			break;
	}

	(void) free(n);
}

static void dep_free_envs(struct dep_env *e) {
	struct dep_env_it *h, *n;

	if(e == NULL) {
		return;
	}

	h = e->head;

	while(h != NULL) {
		n = h->next;

		(void) dep_free_tree(h->value);

		(void) free(h);

		h = n;
	}

	(void) free(e);
}
