Question
One can incidentally terminate sushi by pressing Ctrl+C (Ctrl+Break, Command+dot) or a similar combination of keys that sends SIGNIT to the shell. Function prevent_interruption() sets
One can incidentally terminate sushi by pressing Ctrl+C
(Ctrl+Break, Command+dot) or a similar combination of keys that sends
SIGNIT to the shell. Function prevent_interruption() sets up a signal
handler that intercepts SIGINT and displays message Type exit to
exit the shell on stderr. The name of the handler is
refuse_to_die(), its skeleton and the skeleton of
prevent_interruption() are provided in sushi.c. Hint: use system call
sigaction() to set up the handler. As a result, when you attempt to
interrupt the shell, it will display the message and continue.
II. (Non-actionable.) File sushi_yyparser.y has been refactored for
clarity. It also has mechanisms for building the command line. The
definitions of the supporting data structures: arglist_t, prog_t, and
redirection_t have been added to sushi.h. Familiarize yourself
with the definitions of the rules (non-terminal symbols) exe, args,
and arg.
exe, the command line program, is simply a list of arguments with some additional information stored in prog_t. An instance of the structure is created dynamically with malloc (lines 87 92). It must be freed after the command execution.
args is an array (not a list) of char*, each holding one argument (lines 9498). It is reallocated each time a new argument is discovered (lines 98103). It must be freed after the command execution.
arg, a command-line argument, is simply a string returned by the lexer (lines 105107). It must be freed after the command execution.
Once the command line is collected, it is passed to function int
spawn(prog_t *exe, prog_t *pipe, int bgmode), lines 4142. You can
disregard the second and the third parameters for now.
Sushi.c
#include
#include
#include "sushi.h"
#include
#include
int sushi_exit = 0;
static void refuse_to_die(int sig)
{
// TODO
}
static void prevent_interruption() {
// TODO
}
int main() {
char *file;
char *fileName = "/sushi.conf";
// read the commands from the file sushi.conf, located in the $HOME directory.
file = malloc(strlen(getenv("HOME")) + strlen(fileName) + 1);
strcat(strcpy(file, getenv("HOME")), fileName);
sushi_read_config(file);
prevent_interruption();
while (sushi_exit == 0) {
// display the prompt SUSHI_DEFAULT_PROMPT
printf("%s", SUSHI_DEFAULT_PROMPT);
char *commandLine = sushi_read_line(stdin);
if (commandLine != NULL){
// Call sushi_parse_command() if sushi_read_line() is successfully called
if (sushi_parse_command(commandLine) == 0) {
// store the returnValue to history if no syntax error found.
sushi_store(commandLine);
};
}
}
return EXIT_SUCCESS;
}
Sushi.h
#ifndefSUSHI_H
#defineSUSHI_H
#include
#include
#include
#include
#defineSUSHI_MAX_INPUT80/* really modest :) */
#defineSUSHI_HISTORY_LENGTH32
#defineSUSHI_DEFAULT_PROMPT"> "
char*sushi_read_line(FILE*in);
intsushi_read_config(char*fname);
voidsushi_store(char*line);
voidsushi_show_history();
char*sushi_unquote(char* s);
intsushi_parse_command(char*command);
externintsushi_exit;// The global exit flag
// Support for the primitive parse tree
// An array of arguments, eventually NULL-terminated
typedefstruct{
intsize;
char**args;
}arglist_t;
// I/O redirection, as in "foobar < foo > bar"
typedefstruct{
char*in, *out1, *out2;// stdin, stdout-write, stdout-append
}redirection_t;
// The program to be executed
typedefstructprog {
arglist_targs;// Arguments, including the program name
redirection_tredirection;// Optional redirections
structprog *next;// The next program in the pipeline, if any; NULL otherwise
}prog_t;
// Start a new program
intspawn(prog_t*exe,prog_t*pipe,intbgmode);
// Report unimplemented functions
void__not_implemented__();
// Replace standard malloc and realloc: abort() if malloc/realloc fails
// The likelyhood of the event is low, but the consequences are grave
void*super_malloc(size_tsize);
void*super_realloc(void*ptr,size_tsize);
#endif
sushi_yyparser.y
%{
#include "sushi.h"
int yylex();
void yyerror(const char* s);
%}
%union {
char *s;
int i;
arglist_t alist;
prog_t *exe;
redirection_t redir;
}
%token YY_SUSHI_SET
%token YY_SUSHI_HISTORY
%token YY_SUSHI_EXIT
%token YY_SUSHI_JOBS
%token YY_SUSHI_PWD
%token YY_SUSHI_CD
%token YY_SUSHI_UNKNOWN
%token YY_SUSHI_LESS
%token YY_SUSHI_MORE
%token YY_SUSHI_MOREMORE
%token YY_SUSHI_AMP
%token YY_SUSHI_BAR
%token YY_SUSHI_TOK
%type arg
%type
%type
%type bg_mode
%type
%start cmdline
%%
cmdline:
{ /* an empty line is valid, too! Do nothing */ }
| redir_exe bg_mode { spawn($1, NULL, $2); }
| in_exe pipe bg_mode { spawn($1, $2, $3); }
| arg YY_SUSHI_SET arg { __not_implemented__(); } /* TODO */
| YY_SUSHI_JOBS { __not_implemented__(); } /* TODO */
| YY_SUSHI_PWD { __not_implemented__(); } /* TODO */
| YY_SUSHI_CD arg { __not_implemented__(); } /* TODO */
| YY_SUSHI_HISTORY { sushi_show_history(stdout); }
| YY_SUSHI_EXIT { sushi_exit = 1; }
pipe:
YY_SUSHI_BAR out_exe { __not_implemented__(); } /* TODO */
| YY_SUSHI_BAR exe pipe { __not_implemented__(); } /* TODO */
redir_exe:
exe { $$ = $1; }
| exe any_redir { $$ = $1; $$->redirection = $2; __not_implemented__(); }
in_exe:
exe { $$ = $1; }
| exe in_redir { $$ = $1; $$->redirection = $2; __not_implemented__(); }
out_exe:
exe { $$ = $1; }
| exe out_redir { $$ = $1; $$->redirection = $2; __not_implemented__(); }
inout_redir:
in_redir out_redir { $$.in = $1.in; $$.out1 = $2.out1; $$.out2 = $2.out2; }
| out_redir in_redir { $$.in = $2.in; $$.out1 = $1.out1; $$.out2 = $1.out2; }
out_redir:
out1_redir { $$ = $1; }
| out2_redir { $$ = $1; }
any_redir:
in_redir { $$ = $1; }
| out_redir { $$ = $1; }
| inout_redir { $$ = $1; }
in_redir: YY_SUSHI_LESS arg { $$.in = $2; $$.out1 = $$.out2 = NULL; }
out1_redir: YY_SUSHI_MORE arg { $$.out1 = $2; $$.in = $$.out2 = NULL; }
out2_redir: YY_SUSHI_MOREMORE arg { $$.out2 = $2; $$.in = $$.out1 = NULL; }
bg_mode:
{ $$ = 0; }
| YY_SUSHI_AMP { $$ = 1; __not_implemented__(); }
exe:
args {
$$ = malloc(sizeof(prog_t));
$$->args = $1;
$$->redirection.in= $$->redirection.out1 = $$->redirection.out2 = NULL;
$$->next = NULL; }
args:
arg {
$$.args = malloc(sizeof(char*)); // New argument array
$$.args[0] = $1; // Its first element
$$.size = 1; }
| args arg {
$$ = $1;
$$.size++; // Increase argument array size
$$.args = realloc($$.args, sizeof(char*) * $$.size); // Add storage
$$.args[$$.size - 1] = $2; } // Add the last element
arg:
YY_SUSHI_TOK { $$ = $1; }
%%
/* This section is empty */
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started