Example #1
0
int main(int argc, char **argv) {

    const int maxThreads = omp_get_max_threads();

    if (argc < 4) {
        fprintf(stderr, "Usage: bench <csv file> <input size> <num threads> [<num threads> ...]\n");
        return -1;
    }

    FILE *const csvFile = csv_open(argv[1]);
    if (csvFile == NULL) {
        return -1;
    }

    const int len = safe_strtol(argv[2]);
    if (len < 1) {
        fprintf(stderr, "Input size must be positive\n");
        return -1;
    }

    TYPE *nrs = random_array(len, time(NULL));
    if (nrs == NULL) {
        return -1;
    }

    for (int i = 3; i < argc; i++) {
        int threads = safe_strtol(argv[i]);
        if (threads < 1) {
            threads = maxThreads;
        }

        omp_set_num_threads(threads);
        printf("%s. omp_get_max_threads() == %d\n", algorithm_name, threads);

        /* Bench the parallel implementation. */

        double start = omp_get_wtime();
        if (prefix_sums(nrs, len, NULL) != 0) {
            return -1;
        }
        double par_time = omp_get_wtime() - start;

        printf("elements: %d; par time: %f\n\n",
                len, par_time);

        fprintf(csvFile, "%s,%d,%d,%f\n", algorithm_name, threads, len, par_time);
    }

    free(nrs);

    csv_close(csvFile);

    return 0;
}
Example #2
0
static enum test_return test_safe_strtol(void) {
    int32_t val;
    assert(safe_strtol("123", &val));
    assert(val == 123);
    assert(safe_strtol("+123", &val));
    assert(val == 123);
    assert(safe_strtol("-123", &val));
    assert(val == -123);
    assert(!safe_strtol("", &val));  /* empty */
    assert(!safe_strtol("123BOGUS", &val));  /* non-numeric */
    assert(!safe_strtol("92837498237498237498029383", &val)); /* out of range */

    /* extremes: */
    /* This actually works on 64-bit ubuntu
       assert(!safe_strtol("2147483648", &val)); // (expt 2.0 31.0)
    */
    assert(safe_strtol("2147483647", &val)); /* (- (expt 2.0 31) 1) */
    assert(val == 2147483647L);
    /* This actually works on 64-bit ubuntu
       assert(!safe_strtol("-2147483649", &val)); // (- (expt -2.0 31) 1)
    */

    /* We'll allow space to terminate the string.  And leading space. */
    assert(safe_strtol(" 123 foo", &val));
    assert(val == 123);
    return TEST_PASS;
}
Example #3
0
END_TEST

START_TEST (test_safe_strtol)
{
    int32_t val;
    fail_unless(safe_strtol("123", &val), "Failed parsing 123");
    fail_unless(val == 123, "123 != 123");
    fail_unless(safe_strtol("+123", &val), "Failed parsing +123");
    fail_unless(val == 123, "+123 != 123");
    fail_unless(safe_strtol("-123", &val), "Failed parsing -123");
    fail_unless(val == -123, "-123 != -123");
    fail_if(safe_strtol("", &val), "Parsing empty string");
    fail_if(safe_strtol("123BOGUS", &val), "Parsed 123BOGUS");
    fail_if(safe_strtol("92837498237498237498029383", &val),
            "Parsed out of range value.");

    /* extremes: */
    /* This actually works on 64-bit ubuntu
       assert(!safe_strtol("2147483648", &val)); /* (expt 2.0 31.0) */
    */
    fail_unless(safe_strtol("2147483647", &val),
                "Failed parsing upper limit."); /* (- (expt 2.0 31) 1) */
    fail_unless(val == 2147483647L, "2147483647 != 2147483647L");
    /* This actually works on 64-bit ubuntu
       assert(!safe_strtol("-2147483649", &val)); /* (- (expt -2.0 31) 1) */
    */

    /* We'll allow space to terminate the string.  And leading space. */
    fail_unless(safe_strtol(" 123 foo", &val), "Failed parsing \" 123 foo\"");
    fail_unless(val == 123, "\" 123 foo\" != 123");
}
Example #4
0
static int snd_func_iops(snd_config_t **dst,
			 snd_config_t *root,
			 snd_config_t *src,
			 snd_config_t *private_data,
			 int op)
{
	snd_config_t *n;
	snd_config_iterator_t i, next;
	const char *id;
	char *res = NULL;
	long result = 0, val;
	int idx = 0, err, hit;
	
	err = snd_config_search(src, "integers", &n);
	if (err < 0) {
		SNDERR("field integers not found");
		goto __error;
	}
	err = snd_config_evaluate(n, root, private_data, NULL);
	if (err < 0) {
		SNDERR("error evaluating integers");
		goto __error;
	}
	do {
		hit = 0;
		snd_config_for_each(i, next, n) {
			snd_config_t *n = snd_config_iterator_entry(i);
			const char *id;
			long i;
			if (snd_config_get_id(n, &id) < 0)
				continue;
			err = safe_strtol(id, &i);
			if (err < 0) {
				SNDERR("id of field %s is not an integer", id);
				err = -EINVAL;
				goto __error;
			}
			if (i == idx) {
				idx++;
				err = snd_config_get_integer(n, &val);
				if (err < 0) {
					SNDERR("invalid integer for id %s", id);
					err = -EINVAL;
					goto __error;
				}
				switch (op) {
				case 0: result += val; break;
				case 1: result *= val; break;
				}
				hit = 1;
			}
		}
	} while (hit);
	err = snd_config_get_id(src, &id);
	if (err >= 0)
		err = snd_config_imake_integer(dst, id, result);
	free(res);
      __error:
	return err;
}
Example #5
0
/**
 * \brief Returns an integer environment value.
 * \param dst The function puts the handle to the result configuration node
 *            (with type integer) at the address specified by \p dst.
 * \param root Handle to the root source node.
 * \param src Handle to the source node, with definitions for \c vars and
 *            \c default.
 * \param private_data Handle to the \c private_data node.
 * \return Zero if successful, otherwise a negative error code.
 *
 * Example:
\code
	{
		@func igetenv
		vars [ MY_DEVICE DEVICE D ]
		default 0
	}
\endcode
 */ 
int snd_func_igetenv(snd_config_t **dst, snd_config_t *root, snd_config_t *src,
		     snd_config_t *private_data)
{
	snd_config_t *d;
	const char *str, *id;
	int err;
	long v;

	err = snd_func_getenv(&d, root, src, private_data);
	if (err < 0)
		return err;
	err = snd_config_get_string(d, &str);
	if (err < 0) {
		snd_config_delete(d);
		return err;
	}
	err = safe_strtol(str, &v);
	if (err < 0) {
		snd_config_delete(d);
		return err;
	}
	snd_config_delete(d);
	err = snd_config_get_id(src, &id);
	if (err < 0)
		return err;
	err = snd_config_imake_integer(dst, id, v);
	if (err < 0)
		return err;
	return 0;
}
Example #6
0
static void load_ping_recipe(char **params,
                             struct ping_test_recipe *out)
{
    assert(params);
    assert(out);

    for (int i = 0; params[i]; i++) {
        int value = 0;
        char *p = NULL;

        p = strchr(params[i], '=');
        assert(p);

        if (!safe_strtol(p+1, &value)) {
            moxi_log_write("Failed to parse ``%s'' as number\n", p+1);
            assert(false);
        }

        if (starts_with("ksize=", params[i])) {
            out->keysize = value;
        } else if (starts_with("vsize=", params[i])) {
            out->valsize = value;
        } else if (starts_with("iterations=", params[i])) {
            out->iterations = value;
        } else {
            if (settings.verbose > 1) {
                moxi_log_write("Unknown recipe property:  %s\n", params[i]);
            }
        }
    }
}
Example #7
0
int safe_strtoi(char *arg, int* value)
{
	int error;
	long lvalue = *value;
	error = safe_strtol(arg, &lvalue);
	*value = (int) lvalue;
	return error;
}
Example #8
0
/**
 * \brief Gets the control interface index from the given ASCII string.
 * \param ascii The string to be parsed.
 * \return The control interface index if successful, otherwise a negative error code.
 */ 
int snd_config_get_ctl_iface_ascii(const char *ascii)
{
	long v;
	snd_ctl_elem_iface_t idx;
	if (isdigit(ascii[0])) {
		if (safe_strtol(ascii, &v) >= 0) {
			if (v < 0 || v > SND_CTL_ELEM_IFACE_LAST)
				return -EINVAL;
			return v;
		}
	}
	for (idx = 0; idx <= SND_CTL_ELEM_IFACE_LAST; idx++) {
		if (strcasecmp(snd_ctl_elem_iface_name(idx), ascii) == 0)
			return idx;
	}
	return -EINVAL;
}
Example #9
0
// process a memcached set command.
void process_update_command(conn *c, token_t *tokens,
                            const size_t ntokens,
                            int comm, bool handle_cas) {
	int vlen;
	assert(c != NULL);

	if (tokens[KEY_TOKEN].length > KEY_MAX_LENGTH ||
	    !safe_strtol(tokens[4].value, (int32_t *)&vlen)) {
		error_response(c, "CLIENT_ERROR bad command line format");
		return;
	}

	if (vlen < 0) {
		error_response(c, "CLIENT_ERROR bad command line format");
		return;
	}

	// setup value to be read
	c->sbytes = vlen + 2; // for \r\n consumption.
	conn_set_state(c, conn_read_value);
}
Example #10
0
/**
 * Function to start the server and let it listen on a random port
 *
 * @param port_out where to store the TCP port number the server is
 *                 listening on
 * @param is_daemon set to true if you want to run the memcached server
 *               as a daemon process
 * @return the pid of the memcached server
 */
static pid_t start_server(in_port_t *port_out, bool is_daemon) {
    pid_t pid;
    FILE *fp;
    char buffer[80];
    char environment[80];
    char pid_file[80];
    char *filename;

    snprintf(environment, sizeof(environment),
             "MEMCACHED_PORT_FILENAME=/tmp/ports.%lu", (long)getpid());
    filename = environment + strlen("MEMCACHED_PORT_FILENAME=");
    snprintf(pid_file, sizeof(pid_file), "/tmp/pid.%lu", (long)getpid());

    remove(filename);
    remove(pid_file);

    pid = fork();
    assert(pid != -1);

    if (pid == 0) {
        /* Child */
        char *argv[20];
        int arg = 0;
        putenv(environment);
#ifdef __sun
        putenv("LD_PRELOAD=watchmalloc.so.1");
        putenv("MALLOC_DEBUG=WATCH");
#endif

        if (!is_daemon) {
            argv[arg++] = "./timedrun";
            argv[arg++] = "15";
        }
        argv[arg++] = "./memcached-debug";
        argv[arg++] = "-p";
        argv[arg++] = "-1";
        argv[arg++] = "-U";
        argv[arg++] = "0";
        /* Handle rpmbuild and the like doing this as root */
        if (getuid() == 0) {
            argv[arg++] = "-u";
            argv[arg++] = "root";
        }
        if (is_daemon) {
            argv[arg++] = "-d";
            argv[arg++] = "-P";
            argv[arg++] = pid_file;
        }
        argv[arg++] = NULL;
        assert(execv(argv[0], argv) != -1);
    }

    /* Yeah just let us "busy-wait" for the file to be created ;-) */
    while (access(filename, F_OK) == -1) {
        usleep(10);
    }

    fp = fopen(filename, "r");
    if (fp == NULL) {
        fprintf(stderr, "Failed to open the file containing port numbers: %s\n",
                strerror(errno));
        assert(false);
    }

    *port_out = (in_port_t)-1;
    while ((fgets(buffer, sizeof(buffer), fp)) != NULL) {
        if (strncmp(buffer, "TCP INET: ", 10) == 0) {
            int32_t val;
            assert(safe_strtol(buffer + 10, &val));
            *port_out = (in_port_t)val;
        }
    }

    fclose(fp);
    assert(remove(filename) == 0);

    if (is_daemon) {
        int32_t val;
        /* loop and wait for the pid file.. There is a potential race
         * condition that the server just created the file but isn't
         * finished writing the content, but I'll take the chance....
         */
        while (access(pid_file, F_OK) == -1) {
            usleep(10);
        }

        fp = fopen(pid_file, "r");
        if (fp == NULL) {
            fprintf(stderr, "Failed to open pid file: %s\n",
                    strerror(errno));
            assert(false);
        }
        assert(fgets(buffer, sizeof(buffer), fp) != NULL);
        fclose(fp);

        assert(safe_strtol(buffer, &val));
        pid = (pid_t)val;
    }

    return pid;
}
Example #11
0
int main(int argc, char **argv)
{
    int ret = 0;

    MPI_Init(&argc, &argv);

    if (argc < 4) {
        fprintf(stderr, "Usage: bench <csv file> <input size> <input upper bound>\n");
        ret = -1;
        goto out;
    }

    const int size = safe_strtol(argv[2]);
    if (size < 1) {
        fprintf(stderr, "Input size must be greater than 0\n");
        ret = -1;
        goto out;
    }

    const int upper_bound = safe_strtol(argv[3]);
    if (size < 1) {
        fprintf(stderr, "Input upper bound must be greater than 0\n");
        ret = -1;
        goto out;
    }

    int processes;
    MPI_Comm_size(MPI_COMM_WORLD, &processes);

    int rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    /* We need to generate the same array in each process. The master process
     * determines a seed and broadcasts it to all others. */

    int seed = time(NULL);
    MPI_Bcast(&seed, 1, MPI_INT, MASTER, MPI_COMM_WORLD);

    TYPE *a = random_array(size, upper_bound, seed);

    DEBUG("%s. MPI_Comm_size %d, MPI_Comm_rank %d, seed %d\n",
            algorithm_name, processes, rank, seed);

    /* Everything is set up, start sorting and time how long it takes. */

    MPI_Barrier(MPI_COMM_WORLD);
    double start = MPI_Wtime();
    TYPE *c = bucket_sort(a, size, upper_bound);
    double end = MPI_Wtime();

    double localElapsed = end - start;
    double totalElapsed;
    MPI_Reduce(&localElapsed, &totalElapsed, 1, MPI_DOUBLE, MPI_MAX, MASTER, MPI_COMM_WORLD);

    free(a);
    free(c);

    /* Only the master process (rank 0) outputs information. */

    if (rank == MASTER) {
        printf("processes: %d, elements: %d; upper bound: %d; time: %f\n",
                processes, size, upper_bound, totalElapsed);

        /* Persist this run in our csv file. */

        FILE *const csvFile = csv_open(argv[1]);
        if (csvFile == NULL) {
            return -1;
        }

        fprintf(csvFile, "%s,%d,%d,%f\n", algorithm_name, processes, size, totalElapsed);

        csv_close(csvFile);
    }

out:
    MPI_Finalize();

    return ret;
}
Example #12
0
/** Note: the key and val param buffers are modified.
 */
void cproxy_parse_behavior_key_val(char *key,
                                   char *val,
                                   proxy_behavior *behavior) {
    uint32_t ms = 0;
    uint32_t x = 0;
    bool ok = false;

    assert(behavior != NULL);

    if (key != NULL &&
        val != NULL) {
        key = trimstr(key);
        val = trimstr(val);

        if (wordeq(key, "cycle")) {
            ok = safe_strtoul(val, &behavior->cycle);
        } else if (wordeq(key, "downstream_max") ||
                   wordeq(key, "concurrency")) {
            ok = safe_strtoul(val, &behavior->downstream_max);
        } else if (wordeq(key, "downstream_conn_max")) {
            ok = safe_strtoul(val, &behavior->downstream_conn_max);
        } else if (wordeq(key, "weight") ||
                   wordeq(key, "downstream_weight")) {
            ok = safe_strtoul(val, &behavior->downstream_weight);
        } else if (wordeq(key, "retry") ||
                   wordeq(key, "downstream_retry")) {
            ok = safe_strtoul(val, &behavior->downstream_retry);
        } else if (wordeq(key, "protocol") ||
                   wordeq(key, "downstream_protocol")) {
            if (wordeq(val, "ascii") ||
                wordeq(val, "memcached-ascii") ||
                wordeq(val, "membase-ascii")) {
                behavior->downstream_protocol =
                    proxy_downstream_ascii_prot;
                ok = true;
            } else if (wordeq(val, "binary") ||
                       wordeq(val, "memcached-binary") ||
                       wordeq(val, "membase-binary")) {
                behavior->downstream_protocol =
                    proxy_downstream_binary_prot;
                ok = true;
            } else {
                if (settings.verbose > 1) {
                    moxi_log_write("unknown behavior prot: %s\n", val);
                }
            }
        } else if (wordeq(key, "timeout") ||
                   wordeq(key, "downstream_timeout") ||
                   wordeq(key, "downstream_conn_timeout")) {
            ok = safe_strtoul(val, &ms);
            behavior->downstream_timeout.tv_sec  = floor(ms / 1000.0);
            behavior->downstream_timeout.tv_usec = (ms % 1000) * 1000;
        } else if (wordeq(key, "downstream_conn_queue_timeout")) {
            ok = safe_strtoul(val, &ms);
            behavior->downstream_conn_queue_timeout.tv_sec  = floor(ms / 1000.0);
            behavior->downstream_conn_queue_timeout.tv_usec = (ms % 1000) * 1000;
        } else if (wordeq(key, "wait_queue_timeout")) {
            ok = safe_strtoul(val, &ms);
            behavior->wait_queue_timeout.tv_sec  = floor(ms / 1000.0);
            behavior->wait_queue_timeout.tv_usec = (ms % 1000) * 1000;
        } else if (wordeq(key, "connect_timeout")) {
            ok = safe_strtoul(val, &ms);
            behavior->connect_timeout.tv_sec  = floor(ms / 1000.0);
            behavior->connect_timeout.tv_usec = (ms % 1000) * 1000;
        } else if (wordeq(key, "auth_timeout")) {
            ok = safe_strtoul(val, &ms);
            behavior->auth_timeout.tv_sec  = floor(ms / 1000.0);
            behavior->auth_timeout.tv_usec = (ms % 1000) * 1000;
        } else if (wordeq(key, "time_stats")) {
            ok = safe_strtoul(val, &x);
            behavior->time_stats = x;
        } else if (wordeq(key, "mcs_opts")) {
            if (strlen(val) < sizeof(behavior->mcs_opts)) {
                strcpy(behavior->mcs_opts, val);
                ok = true;
            }
        } else if (wordeq(key, "connect_max_errors")) {
            ok = safe_strtoul(val, &behavior->connect_max_errors);
        } else if (wordeq(key, "connect_retry_interval")) {
            ok = safe_strtoul(val, &behavior->connect_retry_interval);
        } else if (wordeq(key, "front_cache_max")) {
            ok = safe_strtoul(val, &behavior->front_cache_max);
        } else if (wordeq(key, "front_cache_lifespan")) {
            ok = safe_strtoul(val, &behavior->front_cache_lifespan);
        } else if (wordeq(key, "front_cache_spec")) {
            if (strlen(val) < sizeof(behavior->front_cache_spec)) {
                strcpy(behavior->front_cache_spec, val);
                ok = true;
            }
        } else if (wordeq(key, "front_cache_unspec")) {
            if (strlen(val) < sizeof(behavior->front_cache_unspec)) {
                strcpy(behavior->front_cache_unspec, val);
                ok = true;
            }
        } else if (wordeq(key, "key_stats_max")) {
            ok = safe_strtoul(val, &behavior->key_stats_max);
        } else if (wordeq(key, "key_stats_lifespan")) {
            ok = safe_strtoul(val, &behavior->key_stats_lifespan);
        } else if (wordeq(key, "key_stats_spec")) {
            if (strlen(val) < sizeof(behavior->key_stats_spec)) {
                strcpy(behavior->key_stats_spec, val);
                ok = true;
            }
        } else if (wordeq(key, "key_stats_unspec")) {
            if (strlen(val) < sizeof(behavior->key_stats_unspec)) {
                strcpy(behavior->key_stats_unspec, val);
                ok = true;
            }
        } else if (wordeq(key, "optimize_set")) {
            if (strlen(val) < sizeof(behavior->optimize_set)) {
                strcpy(behavior->optimize_set, val);
                ok = true;
            }
        } else if (wordeq(key, "usr")) {
            if (strlen(val) < sizeof(behavior->usr)) {
                strcpy(behavior->usr, val);
                ok = true;
            }
        } else if (wordeq(key, "pwd")) {
            if (strlen(val) < sizeof(behavior->pwd)) {
                strcpy(behavior->pwd, val);
                ok = true;
            }
        } else if (wordeq(key, "host")) {
            if (strlen(val) < sizeof(behavior->host)) {
                strcpy(behavior->host, val);
                ok = true;
            }
        } else if (wordeq(key, "port")) {
            ok = safe_strtol(val, &behavior->port);
        } else if (wordeq(key, "bucket")) {
            if (strlen(val) < sizeof(behavior->bucket)) {
                strcpy(behavior->bucket, val);
                ok = true;
            }
        } else if (wordeq(key, "port_listen")) {
            ok = safe_strtol(val, &behavior->port_listen);
        } else if (wordeq(key, "default_bucket_name")) {
            if (strlen(val) < sizeof(behavior->default_bucket_name)) {
                strcpy(behavior->default_bucket_name, val);
                ok = true;
            }
        } else if (key[0] == '#') { // Comment.
            ok = true;
        } else {
            if (settings.verbose > 1) {
                moxi_log_write("ERROR: unknown behavior key: %s\n", key);
            }
        }
    }

    if (ok == false) {
        moxi_log_write("ERROR: config error in key: %s value: %s\n",
                       key, val);
    }
}
Example #13
0
/**
 * \brief Merges the given strings.
 * \param dst The function puts the handle to the result configuration node
 *            (with type string) at the address specified by \p dst.
 * \param root Handle to the root source node.
 * \param src Handle to the source node, with a definition for \c strings.
 * \param private_data Handle to the \c private_data node.
 * \return A non-negative value if successful, otherwise a negative error code.
 *
 * Example (result is "a1b2c3"):
\code
	{
		@func concat
		strings [ "a1" "b2" "c3" ]
	}
\endcode
 */ 
int snd_func_concat(snd_config_t **dst, snd_config_t *root, snd_config_t *src,
		    snd_config_t *private_data)
{
	snd_config_t *n;
	snd_config_iterator_t i, next;
	const char *id;
	char *res = NULL, *tmp;
	int idx = 0, len = 0, len1, err, hit;
	
	err = snd_config_search(src, "strings", &n);
	if (err < 0) {
		SNDERR("field strings not found");
		goto __error;
	}
	err = snd_config_evaluate(n, root, private_data, NULL);
	if (err < 0) {
		SNDERR("error evaluating strings");
		goto __error;
	}
	do {
		hit = 0;
		snd_config_for_each(i, next, n) {
			snd_config_t *n = snd_config_iterator_entry(i);
			char *ptr;
			const char *id;
			long i;
			if (snd_config_get_id(n, &id) < 0)
				continue;
			err = safe_strtol(id, &i);
			if (err < 0) {
				SNDERR("id of field %s is not an integer", id);
				err = -EINVAL;
				goto __error;
			}
			if (i == idx) {
				idx++;
				err = snd_config_get_ascii(n, &ptr);
				if (err < 0) {
					SNDERR("invalid ascii string for id %s", id);
					err = -EINVAL;
					goto __error;
				}
				len1 = strlen(ptr);
				tmp = realloc(res, len + len1 + 1);
				if (tmp == NULL) {
					free(ptr);
					free(res);
					err = -ENOMEM;
					goto __error;
				}
				memcpy(tmp + len, ptr, len1);
				free(ptr);
				len += len1;
				tmp[len] = '\0';
				res = tmp;
				hit = 1;
			}
		}
	} while (hit);
	if (res == NULL) {
		SNDERR("empty string is not accepted");
		err = -EINVAL;
		goto __error;
	}
	err = snd_config_get_id(src, &id);
	if (err >= 0)
		err = snd_config_imake_string(dst, id, res);
	free(res);
      __error:
	return err;
}
Example #14
0
/**
 * \brief Returns an environment value.
 * \param dst The function puts the handle to the result configuration node
 *            (with type string) at the address specified by \p dst.
 * \param root Handle to the root source node.
 * \param src Handle to the source node, with definitions for \c vars and
 *            \c default.
 * \param private_data Handle to the \c private_data node.
 * \return Zero if successful, otherwise a negative error code.
 *
 * Example:
\code
	{
		@func getenv
		vars [ MY_CARD CARD C ]
		default 0
	}
\endcode
 */ 
int snd_func_getenv(snd_config_t **dst, snd_config_t *root, snd_config_t *src,
		    snd_config_t *private_data)
{
	snd_config_t *n, *d;
	snd_config_iterator_t i, next;
	const char *res, *id;
	char *def = NULL;
	int idx = 0, err, hit;
	
	err = snd_config_search(src, "vars", &n);
	if (err < 0) {
		SNDERR("field vars not found");
		goto __error;
	}
	err = snd_config_evaluate(n, root, private_data, NULL);
	if (err < 0) {
		SNDERR("error evaluating vars");
		goto __error;
	}
	err = snd_config_search(src, "default", &d);
	if (err < 0) {
		SNDERR("field default not found");
		goto __error;
	}
	err = snd_config_evaluate(d, root, private_data, NULL);
	if (err < 0) {
		SNDERR("error evaluating default");
		goto __error;
	}
	err = snd_config_get_ascii(d, &def);
	if (err < 0) {
		SNDERR("error getting field default");
		goto __error;
	}
	do {
		hit = 0;
		snd_config_for_each(i, next, n) {
			snd_config_t *n = snd_config_iterator_entry(i);
			const char *ptr;
			long i;
			if (snd_config_get_id(n, &id) < 0)
				continue;
			if (snd_config_get_type(n) != SND_CONFIG_TYPE_STRING) {
				SNDERR("field %s is not a string", id);
				err = -EINVAL;
				goto __error;
			}
			err = safe_strtol(id, &i);
			if (err < 0) {
				SNDERR("id of field %s is not an integer", id);
				err = -EINVAL;
				goto __error;
			}
			if (i == idx) {
				idx++;
				err = snd_config_get_string(n, &ptr);
				if (err < 0) {
					SNDERR("invalid string for id %s", id);
					err = -EINVAL;
					goto __error;
				}
				res = getenv(ptr);
				if (res != NULL && *res != '\0')
					goto __ok;
				hit = 1;
			}
		}
	} while (hit);
	res = def;
      __ok:
	err = snd_config_get_id(src, &id);
	if (err >= 0)
		err = snd_config_imake_string(dst, id, res);
      __error:
	free(def);
	return err;
}