~emersion/mrsh

4296e38d1fd2c89e36f1c65cd4959c49fd3005d2 — Drew DeVault 1 year, 8 months ago a217d07
Abort when unspecified commands are attempted
4 files changed, 42 insertions(+), 0 deletions(-)

M builtin/builtin.c
A builtin/unspecified.c
M include/builtin.h
M meson.build
M builtin/builtin.c => builtin/builtin.c +28 -0
@@ 36,12 36,40 @@ static const struct builtin builtins[] = {
	{ "unset", builtin_unset, true },
};

// The following commands are explicitly unspecified by POSIX
static const char *unspecified_names[] = {
	"alloc", "autoload", "bind", "bindkey", "builtin", "bye", "caller", "cap",
	"chdir", "clone", "comparguments", "compcall", "compctl", "compdescribe",
	"compfiles", "compgen", "compgroups", "complete", "compquote", "comptags",
	"comptry", "compvalues", "declare", "dirs", "disable", "disown", "dosh",
	"echotc", "echoti", "help", "history", "hist", "let", "local", "login",
	"logout", "map", "mapfile", "popd", "print", "pushd", "readarray", "repeat",
	"savehistory", "source", "shopt", "stop", "suspend", "typeset", "whence"
};

static const struct builtin unspecified = {
	.name = "unspecified",
	.func = builtin_unspecified,
	.special = false,
};

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

static int unspecified_compare(const void *_a, const void *_b) {
	const char *a = _a;
	const char * const *b = _b;
	return strcmp(a, *b);
}

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

A builtin/unspecified.c => builtin/unspecified.c +11 -0
@@ 0,0 1,11 @@
#include <mrsh/shell.h>
#include <stdlib.h>
#include <stdio.h>
#include "builtin.h"

int builtin_unspecified(struct mrsh_state *state, int argc, char *argv[]) {
	// Ref: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_01_01
	fprintf(stderr, "%s: The behavior of this command is undefined. "
			"This is an error in your script. Aborting.\n", argv[0]);
	exit(1);
}

M include/builtin.h => include/builtin.h +2 -0
@@ 28,6 28,8 @@ int builtin_umask(struct mrsh_state *state, int argc, char *argv[]);
int builtin_unalias(struct mrsh_state *state, int argc, char *argv[]);
int builtin_unset(struct mrsh_state *state, int argc, char *argv[]);

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

const char *print_options(struct mrsh_state *state);

#endif

M meson.build => meson.build +1 -0
@@ 67,6 67,7 @@ lib_mrsh = library(
		'builtin/umask.c',
		'builtin/unalias.c',
		'builtin/unset.c',
		'builtin/unspecified.c',
		'getopt.c',
		'hashtable.c',
		'parser/arithm.c',