~emersion/mrsh

ref: b4af69aa4d47bdeba233833a9d4084eb85c6fc30 mrsh/builtin/builtin.c -rw-r--r-- 3.2 KiB
b4af69aaemersion builtin/cd: fix segfault when PWD is not set 3 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <assert.h>
#include <mrsh/builtin.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "builtin.h"

struct builtin {
	const char *name;
	mrsh_builtin_func_t func;
	bool special;
};

static const struct builtin builtins[] = {
	// Keep alpha sorted
	{ ".", builtin_source, true },
	{ ":", builtin_colon, true },
	{ "alias", builtin_alias, false },
	{ "cd", builtin_cd, false },
	{ "eval", builtin_eval, true },
	{ "exit", builtin_exit, true },
	{ "export", builtin_export, true },
	{ "false", builtin_false, false },
	{ "readonly", builtin_export, true },
	{ "set", builtin_set, true },
	{ "shift", builtin_shift, true },
	{ "times", builtin_times, true },
	{ "true", builtin_true, false },
	{ "unset", builtin_unset, true },
};

static int builtin_compare(const void *_a, const void *_b) {
	const struct builtin *a = _a, *b = _b;
	return strcmp(a->name, b->name);
}

static const struct builtin *get_builtin(const char *name) {
	struct builtin key = { .name = name };
	return bsearch(&key, builtins, sizeof(builtins) / sizeof(builtins[0]),
		sizeof(builtins[0]), builtin_compare);
}

bool mrsh_has_builtin(const char *name) {
	return get_builtin(name) != NULL;
}

bool mrsh_has_special_builtin(const char *name) {
	const struct builtin *builtin = get_builtin(name);
	return builtin != NULL && builtin->special;
}

int mrsh_run_builtin(struct mrsh_state *state, int argc, char *argv[]) {
	assert(argc > 0);

	const char *name = argv[0];
	const struct builtin *builtin = get_builtin(name);
	if (builtin == NULL) {
		return -1;
	}

	return builtin->func(state, argc, argv);
}

void print_escaped(const char *value) {
	const char safe[] = "@%+=:,./-";
	size_t i;
	for (i = 0; value[i] != '\0'; ++i) {
		if (!isalnum(value[i]) && !strchr(safe, value[i])) {
			break;
		}
	}
	if (value[i] == '\0') {
		printf("%s", value);
	} else {
		printf("'");
		for (size_t i = 0; value[i] != '\0'; ++i) {
			if (value[i] == '\'') {
				printf("'\"'\"'");
			} else {
				printf("%c", value[i]);
			}
		}
		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;
}