/* 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; }