4296e38d1fd2c89e36f1c65cd4959c49fd3005d2 — Drew DeVault 11 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',