/* Interpreteur de commandes pour XOS */
/* Copyright (C) 2008 Emmanuel Varoquaux
This file is part of XOS.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
/* Liens :
* http://www.gnu.org/software/libtool/manual/libc/Implementing-a-Shell.html
* http://www.opengroup.org/onlinepubs/000095399/utilities/xcu_chap02.html
* http://www.opengroup.org/onlinepubs/000095399/utilities/sh.html
* http://www.gnu.org/software/bash/manual/bashref.html
* http://tldp.org/LDP/abs/html/
*/
#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
#include
#include
#include
#include
#include
#include
#include
#include
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;
}
/* Lit une commande. Si la commande est non nulle, la place dans l'historique.
*/
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;
}
/* Execute la commande courante. */
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;
/* lecture des options de la ligne de commande */
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");
/* initialisation */
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;
/* On force l'utilisation d'un tampon de ligne pour les sorties pour eviter
que le type de tampon ne soit determine lors de l'appel d'une commande
interne avec redirections. */
setlinebuf(stdout);
setlinebuf(stderr);
/* selection de la source de lecture */
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();
/* lecture et execution des commandes */
if (interactive) {
/* environnement */
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;
}