#include "env.h"
#include "parse.h"
#include "execute_cmd.h"
#include "print_cmd.h"
#include "free_cmd.h"
#include "lex.h"
#include "jobs.h"
#include "getc.h"
#include "util.h"
#include "safe_malloc.h"
#include "error.h"
#include "vars.h"
#include <readline/readline.h>
#include <readline/history.h>
#include <getopt.h>
#include <error.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
static void __attribute__ ((noreturn)) die_bad_usage()
{
fprintf(stderr, "Try `%s --help' for more information.\n", program_invocation_name);
exit(EXIT_FAILURE);
}
static void print_help()
{
printf("Usage: %s [OPTION]... [FILE]\n", program_invocation_name);
puts("Read and execute commands.");
putchar('\n');
puts(" -c read commands from the string operand");
puts(" -i specify that the shell is interactive");
puts(" -s read commands from the standard input");
puts(" -h, --help display this help and exit");
}
static void initialize_readline()
{
rl_instream = stdin;
rl_outstream = stderr;
}
static int read_command()
{
int rv;
display_unreported_jobs();
history_line = NULL;
primary_prompt = safe_strdup(getenv("PS1"));
secondary_prompt = safe_strdup(getenv("PS2"));
rv = parse();
free(primary_prompt);
free(secondary_prompt);
if (history_line) {
if (*history_line)
add_history(history_line);
free(history_line);
}
return rv;
}
static void execute_current_command()
{
struct exec_env_desc_struct exec_env_desc;
struct string_buffer_struct string_buffer;
if (buffered_input_stream)
sync_input_stream();
string_buffer_init(&string_buffer);
print_list(current_list, &exec_env_desc.line_number, &string_buffer);
exec_env_desc.command = string_buffer_release(&string_buffer);
exec_env_desc.subshell = 0;
exec_env_desc.no_fork = full_str ? 1 : 0;
exec_env_desc.builtin = 0;
redirect_list_list_init(&exec_env_desc.redirect_list_list);
execute_list(current_list, &exec_env_desc);
}
int main(int argc, char **argv)
{
static const struct option longopts[] = {
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
struct {
unsigned string_op : 1;
unsigned interactive : 1;
unsigned stdin : 1;
} options;
int c;
options.string_op = 0;
options.interactive = 0;
options.stdin = 0;
while ((c = getopt_long(argc, argv, "cish", longopts, NULL)) != -1)
switch (c) {
case 'c':
options.string_op = 1;
break;
case 'i':
options.interactive = 1;
break;
case 's':
options.stdin = 1;
break;
case 'h':
print_help();
return EXIT_SUCCESS;
case '?':
die_bad_usage();
}
if (optind < argc && !strcmp(argv[optind], "-"))
optind++;
if (options.string_op && optind == argc)
error(EXIT_FAILURE, 0, "string expected after -c");
interactive = options.interactive || (!options.string_op && (options.stdin || optind == argc) && isatty(fileno(stdin)) && isatty(fileno(stderr)));
script_name = !options.string_op && !options.stdin && optind < argc ? argv[optind] : NULL;
line_number = 1;
print_line_number_on_error = !interactive || script_name;
current_builtin = NULL;
last_command_status = EXIT_SUCCESS;
pwd = get_working_directory();
oldpwd = NULL;
setlinebuf(stdout);
setlinebuf(stderr);
buffered_input_stream = 0;
if (options.string_op) {
command_str = argv[optind];
lexer_getc_func = string_getc;
}
else if (interactive && !script_name) {
initialize_readline();
lexer_getc_func = readline_getc;
}
else {
if (script_name) {
if ((input_stream_fd = open(script_name, O_RDONLY)) == -1)
error(EXIT_FAILURE, errno, script_name);
}
else
input_stream_fd = fileno(stdin);
lexer_getc_func = stream_getc;
buffered_input_stream = 1;
}
init_job_control();
if (interactive) {
setup_environment();
fputs("Welcome to xsh, the XOS shell :-)\n", stderr);
fflush(stderr);
}
done = 0;
while (!done)
if (read_command() == 0) {
if (parser_eof)
done = 1;
else if (current_list) {
execute_current_command();
free_list(current_list);
}
}
else {
last_command_status = EXIT_FAILURE;
if (!interactive)
done = 1;
}
end_job_control();
if (script_name)
close(input_stream_fd);
return last_command_status;
}