~emersion/mrsh

629695102317248c6f87fc0803c82984dd3b9220 — Drew DeVault 3 years ago 04d1ca7
Implement export builtin
6 files changed, 110 insertions(+), 39 deletions(-)

M builtin/builtin.c
A builtin/export.c
M builtin/set.c
M include/builtin.h
M include/mrsh/builtin.h
M meson.build
M builtin/builtin.c => builtin/builtin.c +44 -0
@@ 20,6 20,7 @@ static const struct builtin builtins[] = {
	{ "cd", builtin_cd, false },
	{ "eval", builtin_eval, true },
	{ "exit", builtin_exit, true },
	{ "export", builtin_export, true },
	{ "false", builtin_false, false },
	{ "set", builtin_set, true },
	{ "shift", builtin_shift, true },


@@ 81,3 82,46 @@ void print_escaped(const char *value) {
		printf("'");
	}
}

struct collect_iter {
	size_t len;
	size_t count;
	uint32_t attribs;
	struct mrsh_collect_var *values;
};

static void collect_vars(const char *key, void *_var, void *user_data) {
	const struct mrsh_variable *var = _var;
	struct collect_iter *iter = user_data;
	if (iter->attribs != MRSH_VAR_ATTRIB_NONE
			&& !(var->attribs & iter->attribs)) {
		return;
	}
	if ((iter->count + 1) * sizeof(struct mrsh_collect_var) >= iter->len) {
		iter->len *= 2;
		iter->values = realloc(iter->values,
				iter->len * sizeof(struct mrsh_collect_var));
	}
	iter->values[iter->count].key = key;
	iter->values[iter->count++].value = var->value;
}

static int varcmp(const void *p1, const void *p2) {
	const struct mrsh_collect_var *v1 = p1;
	const struct mrsh_collect_var *v2 = p2;
	return strcmp(v1->key, v2->key);
}

struct mrsh_collect_var *mrsh_collect_vars(struct mrsh_state *state,
		uint32_t attribs, size_t *count) {
	struct collect_iter iter = {
		.len = 64,
		.count = 0,
		.values = malloc(64 * sizeof(struct mrsh_collect_var)),
		.attribs = attribs,
	};
	mrsh_hashtable_for_each(&state->variables, collect_vars, &iter);
	qsort(iter.values, iter.count, sizeof(struct mrsh_collect_var), varcmp);
	*count = iter.count;
	return iter.values;
}

A builtin/export.c => builtin/export.c +47 -0
@@ 0,0 1,47 @@
#define _POSIX_C_SOURCE 200809L
#include <mrsh/builtin.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "builtin.h"

static const char export_usage[] = "usage: export (-p|name[=word]...)\n";

int builtin_export(struct mrsh_state *state, int argc, char *argv[]) {
	if (argc < 2) {
		fprintf(stderr, export_usage);
		return EXIT_FAILURE;
	} else if (argc == 2 && strcmp(argv[1], "-p") == 0) {
		size_t count;
		struct mrsh_collect_var *vars = mrsh_collect_vars(
				state, MRSH_VAR_ATTRIB_EXPORT, &count);
		for (size_t i = 0; i < count; ++i) {
			printf("export %s=", vars[i].key);
			print_escaped(vars[i].value);
			printf("\n");
		}
		free(vars);
		return EXIT_SUCCESS;
	}

	for (int i = 1; i < argc; ++i) {
		char *eql, *key;
		const char *val;
		eql = strchr(argv[i], '=');
		if (eql) {
			size_t klen = eql - argv[i];
			key = strndup(argv[i], klen);
			val = &eql[1];
		} else {
			key = strdup(argv[i]);
			val = mrsh_env_get(state, key, NULL);
			if (!val) {
				val = "";
			}
		}
		mrsh_env_set(state, key, val, MRSH_VAR_ATTRIB_EXPORT);
		free(key);
	}

	return EXIT_SUCCESS;
}

M builtin/set.c => builtin/set.c +7 -39
@@ 83,49 83,17 @@ static void argv_free(int argc, char **argv) {
	free(argv);
}

struct collect_var {
	const char *key, *value;
};

struct collect_iter {
	size_t len;
	size_t count;
	struct collect_var *values;
};

static void collect_vars(const char *key, void *_var, void *user_data) {
	const struct mrsh_variable *var = _var;
	struct collect_iter *iter = user_data;
	if ((iter->count + 1) * sizeof(struct collect_var) >= iter->len) {
		iter->len *= 2;
		iter->values = realloc(iter->values,
				iter->len * sizeof(struct collect_var));
	}
	iter->values[iter->count].key = key;
	iter->values[iter->count++].value = var->value;
}

static int varcmp(const void *p1, const void *p2) {
	const struct collect_var *v1 = p1;
	const struct collect_var *v2 = p2;
	return strcmp(v1->key, v2->key);
}

static int set(struct mrsh_state *state, int argc, char *argv[], bool cmdline) {
	if (argc == 1 && !cmdline) {
		struct collect_iter iter = {
			.len = 64,
			.count = 0,
			.values = malloc(64 * sizeof(struct collect_var)),
		};
		mrsh_hashtable_for_each(&state->variables, collect_vars, &iter);
		qsort(iter.values, iter.count, sizeof(struct collect_var), varcmp);
		for (size_t i = 0; i < iter.count; ++i) {
			printf("%s=", iter.values[i].key);
			print_escaped(iter.values[i].value);
		size_t count;
		struct mrsh_collect_var *vars = mrsh_collect_vars(
				state, MRSH_VAR_ATTRIB_NONE, &count);
		for (size_t i = 0; i < count; ++i) {
			printf("%s=", vars[i].key);
			print_escaped(vars[i].value);
			printf("\n");
		}
		free(iter.values);
		free(vars);
		return EXIT_SUCCESS;
	}


M include/builtin.h => include/builtin.h +1 -0
@@ 12,6 12,7 @@ int builtin_alias(struct mrsh_state *state, int argc, char *argv[]);
int builtin_cd(struct mrsh_state *state, int argc, char *argv[]);
int builtin_colon(struct mrsh_state *state, int argc, char *argv[]);
int builtin_exit(struct mrsh_state *state, int argc, char *argv[]);
int builtin_export(struct mrsh_state *state, int argc, char *argv[]);
int builtin_eval(struct mrsh_state *state, int argc, char *argv[]);
int builtin_shift(struct mrsh_state *state, int argc, char *argv[]);
int builtin_source(struct mrsh_state *state, int argc, char *argv[]);

M include/mrsh/builtin.h => include/mrsh/builtin.h +10 -0
@@ 9,4 9,14 @@ int mrsh_run_builtin(struct mrsh_state *state, int argc, char *argv[]);

int mrsh_process_args(struct mrsh_state *state, int argc, char *argv[]);

struct mrsh_collect_var {
	const char *key, *value;
};

/** Collects and alpha-sorts variables matching attribs. Count will be set to
 * the number of matching variables. You are responsible for freeing the return
 * value when you're done.*/
struct mrsh_collect_var *mrsh_collect_vars(struct mrsh_state *state,
		uint32_t attribs, size_t *count);

#endif

M meson.build => meson.build +1 -0
@@ 38,6 38,7 @@ lib_mrsh = library(
		'builtin/colon.c',
		'builtin/eval.c',
		'builtin/exit.c',
		'builtin/export.c',
		'builtin/set.c',
		'builtin/shift.c',
		'builtin/source.c',