aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2016-04-17 16:34:47 -0500
committerRob Landley <rob@landley.net>2016-04-17 16:34:47 -0500
commitd85d4e847b1eb347b17c9f38afb77d3d676b3d09 (patch)
tree62e694451a3467a362fb105f609214b1ae8e0710
parente57cb179608077b7459b95bb3219035dd0045912 (diff)
downloadtoybox-d85d4e847b1eb347b17c9f38afb77d3d676b3d09.tar.gz
Dust off toysh, remove ancient config debris, add start of prompt logic.
-rw-r--r--toys/pending/sh.c212
1 files changed, 79 insertions, 133 deletions
diff --git a/toys/pending/sh.c b/toys/pending/sh.c
index e221960a..76b4e13b 100644
--- a/toys/pending/sh.c
+++ b/toys/pending/sh.c
@@ -19,7 +19,23 @@
*
* Things like the bash man page are good to read too.
*
+ * TODO: "make sh" doesn't work (nofork builtins need to be included)
+ * TODO: test that $PS1 color changes work without stupid \[ \] hack
+ * TODO: make fake pty wrapper for test infrastructure
* TODO: // Handle embedded NUL bytes in the command line.
+ * TODO: var=val command
+ * existing but considered builtins: false kill pwd true
+ * buitins: alias bg command fc fg getopts jobs newgrp read umask unalias wait
+ * "special" builtins: break continue : . eval exec export readonly return set
+ * shift times trap unset
+ * | & ; < > ( ) $ ` \ " ' <space> <tab> <newline>
+ * * ? [ # ~ = %
+ * ! { } case do done elif else esac fi for if in then until while
+ * [[ ]] function select
+ * $@ $* $# $? $- $$ $! $0
+ * ENV HOME IFS LANG LC_ALL LINENO PATH PPID PS1 PS2 PS4 PWD
+ * label:
+ * TODO: test exit from "trap EXIT" doesn't recurse
USE_SH(NEWTOY(cd, NULL, TOYFLAG_NOFORK))
USE_SH(NEWTOY(exit, NULL, TOYFLAG_NOFORK))
@@ -42,16 +58,6 @@ config SH
-c command line to execute
-i interactive mode (default when STDIN is a tty)
-config EXIT
- bool
- default n
- depends on SH
- help
- usage: exit [status]
-
- Exit shell. If no return value supplied on command line, use value
- of most recent command, or 0 if none.
-
config CD
bool
default n
@@ -63,112 +69,16 @@ config CD
-P Physical path: resolve symlinks in path.
-L Local path: .. trims directories off $PWD (default).
-*/
-
-/*
-This level of micromanagement is silly, it adds more complexity than it's
-worth. (Not just to the code, but decision fatigue configuring it.)
-
-That said, the following list is kept for the moment as a todo list of
-features I need to implement.
-
-config SH_PROFILE
- bool "Profile support"
- default n
- depends on SH_TTY
- help
- Read /etc/profile and ~/.profile when running interactively.
-
- Also enables the built-in command "source".
-
-config SH_JOBCTL
- bool "Job Control (fg, bg, jobs)"
- default n
- depends on SH_TTY
- help
- Add job control to toysh. This lets toysh handle CTRL-Z, and enables
- the built-in commands "fg", "bg", and "jobs".
-
- With pipe support, enable use of "&" to run background processes.
-
-config SH_FLOWCTL
- bool "Flow control (if, while, for, functions)"
- default n
- depends on SH
- help
- Add flow control to toysh. This enables the if/then/else/fi,
- while/do/done, and for/do/done constructs.
-
- With pipe support, this enables the ability to define functions
- using the "function name" or "name()" syntax, plus curly brackets
- "{ }" to group commands.
-
-config SH_QUOTES
- bool "Smarter argument parsing (quotes)"
- default n
- depends on SH
- help
- Add support for parsing "" and '' style quotes to the toysh command
- parser, with lets arguments have spaces in them.
-
-config SH_WILDCARDS
- bool "Wildcards ( ?*{,} )"
- default n
- depends on SH_QUOTES
- help
- Expand wildcards in argument names, ala "ls -l *.t?z" and
- "rm subdir/{one,two,three}.txt".
-
-config SH_PROCARGS
- bool "Executable arguments ( `` and $() )"
- default n
- depends on SH_QUOTES
- help
- Add support for executing arguments contianing $() and ``, using
- the output of the command as the new argument value(s).
-
- (Bash calls this "command substitution".)
-
-config SH_ENVVARS
- bool "Environment variable support"
- default n
- depends on SH_QUOTES
- help
- Substitute environment variable values for $VARNAME or ${VARNAME},
- and enable the built-in command "export".
-
-config SH_LOCALS
- bool "Local variables"
- default n
- depends on SH_ENVVARS
- help
- Support for local variables, fancy prompts ($PS1), the "set" command,
- and $?.
-
-config SH_ARRAYS
- bool "Array variables"
- default n
- depends on SH_LOCALS
- help
- Support for ${blah[blah]} style array variables.
-config SH_PIPES
- bool "Pipes and redirects ( | > >> < << & && | || () ; )"
+config EXIT
+ bool
default n
depends on SH
help
- Support multiple commands on the same command line. This includes
- | pipes, > >> < redirects, << here documents, || && conditional
- execution, () subshells, ; sequential execution, and (with job
- control) & background processes.
+ usage: exit [status]
-config SH_BUILTINS
- bool "Builtin commands"
- default n
- depends on SH
- help
- Adds the commands exec, fg, bg, help, jobs, pwd, export, source, set,
- unset, read, alias.
+ Exit shell. If no return value supplied on command line, use value
+ of most recent command, or 0 if none.
*/
#define FOR_sh
@@ -176,17 +86,9 @@ config SH_BUILTINS
GLOBALS(
char *command;
-)
-// A single executable, its arguments, and other information we know about it.
-#define SH_FLAG_EXIT 1
-#define SH_FLAG_SUSPEND 2
-#define SH_FLAG_PIPE 4
-#define SH_FLAG_AND 8
-#define SH_FLAG_OR 16
-#define SH_FLAG_AMP 32
-#define SH_FLAG_SEMI 64
-#define SH_FLAG_PAREN 128
+ long lineno;
+)
// What we know about a single process.
struct command {
@@ -206,6 +108,18 @@ struct pipeline {
int cmdlinelen; // How long is cmdline?
};
+void cd_main(void)
+{
+ char *dest = *toys.optargs ? *toys.optargs : getenv("HOME");
+
+ xchdir(dest ? dest : "/");
+}
+
+void exit_main(void)
+{
+ exit(*toys.optargs ? atoi(*toys.optargs) : 0);
+}
+
// Parse one word from the command line, appending one or more argv[] entries
// to struct command. Handles environment variable substitution and
// substrings. Returns pointer to next used byte, or NULL if it
@@ -287,6 +201,7 @@ static void run_pipeline(struct pipeline *line)
if (!cmd || !cmd->argc) return;
tl = toy_find(cmd->argv[0]);
+
// Is this command a builtin that should run in this process?
if (tl && (tl->flags & TOYFLAG_NOFORK)) {
struct toy_context temp;
@@ -351,34 +266,65 @@ static void handle(char *command)
}
}
-void cd_main(void)
+static void do_prompt(void)
{
- char *dest = *toys.optargs ? *toys.optargs : getenv("HOME");
+ char *prompt = getenv("PS1"), *s, c, cc;
- xchdir(dest ? dest : "/");
-}
+ if (!prompt) prompt = "\\$ ";
+ while (*prompt) {
+ c = *(prompt++);
-void exit_main(void)
-{
- exit(*toys.optargs ? atoi(*toys.optargs) : 0);
+ if (c=='!') {
+ if (*prompt=='!') prompt++;
+ else {
+ printf("%ld", TT.lineno);
+ continue;
+ }
+ } else if (c=='\\') {
+ cc = *(prompt++);
+ if (!cc) goto down;
+
+ // \nnn \dD{}hHjlstT@AuvVwW!#$
+ // Ignore bash's "nonprintable" hack; query our cursor position instead.
+ if (cc=='[' || cc==']') continue;
+ else if (cc=='$') putchar(getuid() ? '$' : '#');
+ else if (cc=='h' || cc=='H') {
+ *toybuf = 0;
+ gethostname(toybuf, sizeof(toybuf)-1);
+ if (cc=='h' && (s = strchr(toybuf, '.'))) *s = 0;
+ fputs(toybuf, stdout);
+ } else if (cc=='s') fputs(getbasename(*toys.argv), stdout);
+ else {
+ if (!(c = unescape(cc))) {
+ c = '\\';
+ prompt--;
+ }
+
+ goto down;
+ }
+ continue;
+ }
+down:
+ putchar(c);
+ }
}
void sh_main(void)
{
- FILE *f;
+ FILE *f = 0;
// Set up signal handlers and grab control of this tty.
if (isatty(0)) toys.optflags |= FLAG_i;
- f = *toys.optargs ? xfopen(*toys.optargs, "r") : NULL;
- if (TT.command) handle(TT.command);
+ if (*toys.optargs) f = xfopen(*toys.optargs, "r");
+ if (TT.command) handle(xstrdup(TT.command));
else {
size_t cmdlen = 0;
for (;;) {
- char *prompt = getenv("PS1"), *command = 0;
+ char *command = 0;
// TODO: parse escapes in prompt
- if (!f) printf("%s", prompt ? prompt : "$ ");
+ if (!f) do_prompt();
if (1 > getline(&command, &cmdlen, f ? f : stdin)) break;
handle(command);
free(command);