Пример #1
0
void
test_lookup (void)
{
	char        **env = NULL;
	size_t        len = 0;
	char * const *ret;

	TEST_FUNCTION ("environ_lookup");

	len = 0;
	env = nih_str_array_new (NULL);


	/* Check that an empty table always returns NULL. */
	TEST_FEATURE ("with empty table");
	ret = environ_lookup (env, "FOO", 3);

	TEST_EQ_P (ret, NULL);


	assert (nih_str_array_add (&env, NULL, &len, "FOOLISH=no"));
	assert (nih_str_array_add (&env, NULL, &len, "BAR=BAZ"));


	/* Check that a key that is present is returned. */
	TEST_FEATURE ("with key to be found");
	ret = environ_lookup (env, "BAR", 3);

	TEST_EQ_P (ret, &env[1]);


	/* Check that a key that doesn't exist returns NULL. */
	TEST_FEATURE ("with key not found");
	ret = environ_lookup (env, "MEEP", 4);

	TEST_EQ_P (ret, NULL);


	/* Check that the key is not prefix-matched. */
	TEST_FEATURE ("with key that is prefix of another");
	ret = environ_lookup (env, "FOO", 3);

	TEST_EQ_P (ret, NULL);


	/* Check that the length is honoured. */
	TEST_FEATURE ("with longer key");
	ret = environ_lookup (env, "FOOLISH", 3);

	TEST_EQ_P (ret, NULL);


	nih_free (env);
}
Пример #2
0
/**
 * Substitute variable references in a value.
 *
 * Substitutes variable references in a value (entirely replaces reference
 * values, and substitutes variables within strings). If the value is a list,
 * will recurse onto the values contained within the list. If an error occurs
 * while substituting variables, the error will be raised with config_error()
 * and the function will return false. For strings/references, if an error
 * occurs, the value will not be changed.
 *
 * @param value         Value to substitute in.
 * @param env           Environment to take variables from.
 *
 * @return              Whether variables were successfully substituted.
 */
bool value_substitute(value_t *value, environ_t *env) {
    const value_t *target;
    char *str;
    size_t i, start;

    switch (value->type) {
    case VALUE_TYPE_REFERENCE:
        /* Non-string variable reference, replace the whole value. */
        target = environ_lookup(env, value->string);
        if (!target) {
            config_error("Variable '%s' not found", value->string);
            return false;
        }

        free(value->string);
        value_copy(target, value);
        break;
    case VALUE_TYPE_STRING:
        /* Search for in-string variable references, which we substitute in the
         * string for a string representation of the variable. */
        str = strdup(value->string);
        i = 0;
        start = 0;
        while (str[i]) {
            if (start) {
                if (isalnum(str[i]) || str[i] == '_') {
                    i++;
                } else if (str[i] == '}') {
                    const char *name;
                    char *subst;
                    size_t prefix_len, var_len, len;

                    str[start - 2] = 0;
                    str[i] = 0;

                    /* We have a whole reference. */
                    name = &str[start];
                    target = environ_lookup(env, name);
                    if (!target) {
                        config_error("Variable '%s' not found", name);
                        free(str);
                        return false;
                    }

                    /* Stringify the target into the temporary buffer. */
                    switch (target->type) {
                    case VALUE_TYPE_INTEGER:
                        snprintf(temp_buf, TEMP_BUF_LEN, "%llu", target->integer);
                        break;
                    case VALUE_TYPE_BOOLEAN:
                        snprintf(temp_buf, TEMP_BUF_LEN, (target->boolean) ? "true" : "false");
                        break;
                    case VALUE_TYPE_STRING:
                        snprintf(temp_buf, TEMP_BUF_LEN, "%s", target->string);
                        break;
                    default:
                        config_error("Variable '%s' cannot be converted to string", name);
                        free(str);
                        return false;
                    }

                    /* Now allocate a new string. The start and end characters
                     * of the reference have been replaced with null terminators
                     * effectively splitting up the string into 3 parts. */
                    prefix_len = strlen(str);
                    var_len = strlen(temp_buf);
                    len = prefix_len + var_len + strlen(&str[i + 1]) + 1;
                    subst = malloc(len);
                    snprintf(subst, len, "%s%s%s", str, temp_buf, &str[i + 1]);

                    /* Replace the string and continue after the substituted
                     * portion. */
                    free(str);
                    str = subst;
                    i = prefix_len + var_len;
                    start = 0;
                } else {
                    start = 0;
                    i++;
                }
            } else {
                if (str[i] == '$' && str[i + 1] == '{') {
                    i += 2;
                    start = i;
                } else {
                    i++;
                }
            }
        }

        free(value->string);
        value->string = str;
        break;
    case VALUE_TYPE_LIST:
        for (i = 0; i < value->list->count; i++) {
            if (!value_substitute(&value->list->values[i], env))
                return false;
        }

        break;
    default:
        break;
    }

    return true;
}