This is specified by POSIX and easily implemented.
---
builtin/set.c | 139 ++++++++++++++++++++++++++++++--------------------
1 file changed, 83 insertions(+), 56 deletions(-)
diff --git a/builtin/set.c b/builtin/set.c
index c3ad0e6..fc65eaa 100644
--- a/builtin/set.c
@@ -1,51 +1,55 @@
#define _POSIX_C_SOURCE 200809L
+#include "builtin.h"
+#include "shell/shell.h"
+
#include <errno.h>
-#include <mrsh/builtin.h>
-#include <mrsh/shell.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+
#include <unistd.h>
-#include "builtin.h"
-#include "shell/shell.h"
+
+#include <mrsh/builtin.h>
+#include <mrsh/shell.h>
static const char set_usage[] =
- "usage: set [(-|+)abCefhmnuvx] [-o option] [args...]\n"
- " set [(-|+)abCefhmnuvx] [+o option] [args...]\n"
- " set -- [args...]\n"
- " set -o\n"
- " set +o\n";
+ "usage: set [(-|+)abCefhmnuvx] [-o option] [args...]\n"
+ " set [(-|+)abCefhmnuvx] [+o option] [args...]\n"
+ " set -- [args...]\n"
+ " set -o\n"
+ " set +o\n";
struct option_map {
- const char *name;
+ const char* name;
char short_name;
enum mrsh_option value;
};
static const struct option_map options[] = {
- { "allexport", 'a', MRSH_OPT_ALLEXPORT },
- { "notify", 'b', MRSH_OPT_NOTIFY },
- { "noclobber", 'C', MRSH_OPT_NOCLOBBER },
- { "errexit", 'e', MRSH_OPT_ERREXIT },
- { "noglob", 'f', MRSH_OPT_NOGLOB },
- { NULL, 'h', MRSH_OPT_PRELOOKUP },
- { "monitor", 'm', MRSH_OPT_MONITOR },
- { "noexec", 'n', MRSH_OPT_NOEXEC },
- { "ignoreeof", 0, MRSH_OPT_IGNOREEOF },
- { "nolog", 0, MRSH_OPT_NOLOG },
- { "vi", 0, MRSH_OPT_VI },
- { "nounset", 'u', MRSH_OPT_NOUNSET },
- { "verbose", 'v', MRSH_OPT_VERBOSE },
- { "xtrace", 'x', MRSH_OPT_XTRACE },
+ {"allexport", 'a', MRSH_OPT_ALLEXPORT},
+ {"notify", 'b', MRSH_OPT_NOTIFY},
+ {"noclobber", 'C', MRSH_OPT_NOCLOBBER},
+ {"errexit", 'e', MRSH_OPT_ERREXIT},
+ {"noglob", 'f', MRSH_OPT_NOGLOB},
+ {NULL, 'h', MRSH_OPT_PRELOOKUP},
+ {"monitor", 'm', MRSH_OPT_MONITOR},
+ {"noexec", 'n', MRSH_OPT_NOEXEC},
+ {"ignoreeof", 0, MRSH_OPT_IGNOREEOF},
+ {"nolog", 0, MRSH_OPT_NOLOG},
+ {"vi", 0, MRSH_OPT_VI},
+ {"nounset", 'u', MRSH_OPT_NOUNSET},
+ {"verbose", 'v', MRSH_OPT_VERBOSE},
+ {"xtrace", 'x', MRSH_OPT_XTRACE},
};
-const char *state_get_options(struct mrsh_state *state) {
+const char* state_get_options(struct mrsh_state* state)
+{
static char opts[sizeof(options) / sizeof(options[0]) + 1];
int i = 0;
for (size_t j = 0; j < sizeof(options) / sizeof(options[0]); ++j) {
if (options[j].short_name != '\0' &&
- (state->options & options[j].value)) {
+ (state->options & options[j].value)) {
opts[i++] = options[j].short_name;
}
}
@@ -53,17 +57,19 @@ const char *state_get_options(struct mrsh_state *state) {
return opts;
}
-static void print_options(struct mrsh_state *state) {
+static void print_options(struct mrsh_state* state)
+{
for (size_t j = 0; j < sizeof(options) / sizeof(options[0]); ++j) {
if (options[j].name != NULL) {
printf("set %co %s\n",
- (state->options & options[j].value) ? '-' : '+',
- options[j].name);
+ (state->options & options[j].value) ? '-' : '+',
+ options[j].name);
}
}
}
-static const struct option_map *find_option(char opt) {
+static const struct option_map* find_option(char opt)
+{
for (size_t i = 0; i < sizeof(options) / sizeof(options[0]); ++i) {
if (options[i].short_name && options[i].short_name == opt) {
return &options[i];
@@ -72,7 +78,8 @@ static const struct option_map *find_option(char opt) {
return NULL;
}
-static const struct option_map *find_long_option(const char *opt) {
+static const struct option_map* find_long_option(const char* opt)
+{
for (size_t i = 0; i < sizeof(options) / sizeof(options[0]); ++i) {
if (options[i].name && strcmp(options[i].name, opt) == 0) {
return &options[i];
@@ -81,8 +88,9 @@ static const struct option_map *find_long_option(const char *opt) {
return NULL;
}
-static char **argv_dup(char *argv_0, int argc, char *argv[]) {
- char **_argv = calloc(argc + 1, sizeof(char *));
+static char** argv_dup(char* argv_0, int argc, char* argv[])
+{
+ char** _argv = calloc(argc + 1, sizeof(char*));
_argv[0] = argv_0;
for (int i = 1; i < argc; ++i) {
_argv[i] = strdup(argv[i - 1]);
@@ -90,7 +98,8 @@ static char **argv_dup(char *argv_0, int argc, char *argv[]) {
return _argv;
}
-static void argv_free(int argc, char **argv) {
+static void argv_free(int argc, char** argv)
+{
if (!argv) {
return;
}
@@ -100,12 +109,13 @@ static void argv_free(int argc, char **argv) {
free(argv);
}
-static int set(struct mrsh_state *state, int argc, char *argv[],
- struct mrsh_init_args *init_args, uint32_t *populated_opts) {
+static int set(struct mrsh_state* state, int argc, char* argv[],
+ struct mrsh_init_args* init_args, uint32_t* populated_opts)
+{
if (argc == 1 && init_args == NULL) {
size_t count;
- struct mrsh_collect_var *vars = collect_vars(
- state, MRSH_VAR_ATTRIB_NONE, &count);
+ struct mrsh_collect_var* vars =
+ 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);
@@ -130,7 +140,7 @@ static int set(struct mrsh_state *state, int argc, char *argv[],
fprintf(stderr, set_usage);
return 1;
}
- const struct option_map *option;
+ const struct option_map* option;
switch (argv[i][1]) {
case 'o':
if (i + 1 == argc) {
@@ -144,7 +154,8 @@ static int set(struct mrsh_state *state, int argc, char *argv[],
}
if (argv[i][0] == '-') {
state->options |= option->value;
- } else {
+ }
+ else {
state->options &= ~option->value;
}
if (populated_opts != NULL) {
@@ -160,6 +171,13 @@ static int set(struct mrsh_state *state, int argc, char *argv[],
init_args->command_str = argv[i + 1];
++i;
break;
+ case 'i':
+ if (init_args == NULL) {
+ fprintf(stderr, set_usage);
+ return 1;
+ }
+ state->interactive = argv[i][0] == '-';
+ break;
case 's':
if (init_args == NULL) {
fprintf(stderr, set_usage);
@@ -177,7 +195,8 @@ static int set(struct mrsh_state *state, int argc, char *argv[],
}
if (argv[i][0] == '-') {
state->options |= option->value;
- } else {
+ }
+ else {
state->options &= ~option->value;
}
if (populated_opts != NULL) {
@@ -189,31 +208,35 @@ static int set(struct mrsh_state *state, int argc, char *argv[],
}
if (i != argc || force_positional) {
- char *argv_0;
+ char* argv_0;
if (init_args != NULL) {
argv_0 = strdup(argv[i++]);
init_args->command_file = argv_0;
- } else if (state->frame->argv) {
+ }
+ else if (state->frame->argv) {
argv_0 = strdup(state->frame->argv[0]);
- } else {
+ }
+ else {
fprintf(stderr, set_usage);
return 1;
}
argv_free(state->frame->argc, state->frame->argv);
state->frame->argc = argc - i + 1;
state->frame->argv = argv_dup(argv_0, state->frame->argc, &argv[i]);
- } else
-out:
- if (init_args != NULL) {
- // No args given, but we need to initialize state->argv
- state->frame->argc = 1;
- state->frame->argv = argv_dup(strdup(argv[0]), 1, argv);
}
+ else
+ out:
+ if (init_args != NULL) {
+ // No args given, but we need to initialize state->argv
+ state->frame->argc = 1;
+ state->frame->argv = argv_dup(strdup(argv[0]), 1, argv);
+ }
return 0;
}
-int builtin_set(struct mrsh_state *state, int argc, char *argv[]) {
+int builtin_set(struct mrsh_state* state, int argc, char* argv[])
+{
uint32_t populated_opts = 0;
int ret = set(state, argc, argv, NULL, &populated_opts);
if (ret != 0) {
@@ -229,9 +252,10 @@ int builtin_set(struct mrsh_state *state, int argc, char *argv[]) {
return 0;
}
-int mrsh_process_args(struct mrsh_state *state, struct mrsh_init_args *init_args,
- int argc, char *argv[]) {
- struct mrsh_state_priv *priv = state_get_priv(state);
+int mrsh_process_args(struct mrsh_state* state,
+ struct mrsh_init_args* init_args, int argc, char* argv[])
+{
+ struct mrsh_state_priv* priv = state_get_priv(state);
uint32_t populated_opts = 0;
int ret = set(state, argc, argv, init_args, &populated_opts);
@@ -239,8 +263,11 @@ int mrsh_process_args(struct mrsh_state *state, struct mrsh_init_args *init_args
return ret;
}
- state->interactive = isatty(priv->term_fd) &&
- init_args->command_str == NULL && init_args->command_file == NULL;
+ if (!state->interactive) {
+ state->interactive = isatty(priv->term_fd) &&
+ init_args->command_str == NULL &&
+ init_args->command_file == NULL;
+ }
if (state->interactive && !(populated_opts & MRSH_OPT_MONITOR)) {
state->options |= MRSH_OPT_MONITOR;
}
--
2.34.1