+// A section of code that gets repeatedly or conditionally executed is stored
+// as a string and parsed each time it's run.
+
+
+
+// Wheee, debugging.
+
+// Terminal control
+#define ENABLE_BBSH_TTY 0
+
+// &, fg, bg, jobs. (ctrl-z with tty.)
+#define ENABLE_BBSH_JOBCTL 0
+
+// Flow control (if, while, for, functions { })
+#define ENABLE_BBSH_FLOWCTL 0
+
+#define ENABLE_BBSH_ENVVARS 0 // Environment variable support
+
+// Local and synthetic variables, fancy prompts, set, $?, etc.
+#define ENABLE_BBSH_LOCALVARS 0
+
+// Pipes and redirects: | > < >> << && || & () ;
+#define ENABLE_BBSH_PIPES 0
+
+/* Fun:
+
+ echo `echo hello#comment " woot` and more
+*/
+
+#include "libbb.h"
+
+// A single executable, its arguments, and other information we know about it.
+#define BBSH_FLAG_EXIT 1
+#define BBSH_FLAG_SUSPEND 2
+#define BBSH_FLAG_PIPE 4
+#define BBSH_FLAG_AND 8
+#define BBSH_FLAG_OR 16
+#define BBSH_FLAG_AMP 32
+#define BBSH_FLAG_SEMI 64
+#define BBSH_FLAG_PAREN 128
+
+// What we know about a single process.
+struct command {
+ struct command *next;
+ int flags; // exit, suspend, && ||
+ int pid; // pid (or exit code)
+ int argc;
+ char *argv[];
+};
+
+// A collection of processes piped into/waiting on each other.
+struct pipeline {
+ struct pipeline *next;
+ int job_id;
+ struct command *cmd;
+ char *cmdline;
+ int cmdlinelen;
+};
+
+static void free_list(void *list, void (*freeit)(void *data))
+{
+ while (list) {
+ void **next = (void **)list;
+ void *list_next = *next;
+ freeit(list);
+ free(list);
+ list = list_next;
+ }
+}
+
+// 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
+// hit an ending token.
+static char *parse_word(char *start, struct command **cmd)
+{
+ char *end;
+
+ // Detect end of line (and truncate line at comment)
+ if (ENABLE_BBSH_PIPES && strchr("><&|(;", *start)) return 0;
+
+ // Grab next word. (Add dequote and envvar logic here)
+ end = start;
+ end = skip_non_whitespace(end);
+ (*cmd)->argv[(*cmd)->argc++] = xstrndup(start, end-start);
+
+ // Allocate more space if there's no room for NULL terminator.
+
+ if (!((*cmd)->argc & 7))
+ *cmd = xrealloc(*cmd,
+ sizeof(struct command) + ((*cmd)->argc+8)*sizeof(char *));
+ (*cmd)->argv[(*cmd)->argc] = 0;
+ return end;
+}