void eval_line(const char* s) { int type; char* token; // Your code here! // build the command command* c = command_alloc(); while ((s = parse_shell_token(s, &type, &token)) != NULL) command_append_arg(c, token); // execute it if (c->argc) run_list(c); command_free(c); }
command_t * command_parse(parsestate_t *parsestate) { int i = 0; command_t *cmd = command_alloc(); if (!cmd) return NULL; int flag_in=0; int flag_out=0; int flag_err=0; while (1) { // EXERCISE: Read the next token from 'parsestate'. // Normal tokens go in the cmd->argv[] array. // Redirection file names go into cmd->redirect_filename[]. // Open parenthesis tokens indicate a subshell command. // Other tokens complete the current command // and are not actually part of it; // use parse_ungettoken() to save those tokens for later. // There are a couple errors you should check. // First, be careful about overflow on normal tokens. // Each command_t only has space for MAXTOKENS tokens in // 'argv'. If there are too many tokens, reject the whole // command. // Second, redirection tokens (<, >, 2>) must be followed by // TOK_NORMAL tokens containing file names. // Third, a parenthesized subcommand can't be part of the // same command as other normal tokens. For example, // "echo ( echo foo )" and "( echo foo ) echo" are both errors. // (You should figure out exactly how to check for this kind // of error. Try interacting with the actual 'bash' shell // for some ideas.) // 'goto error' when you encounter one of these errors, // which frees the current command and returns NULL. // Hint: An open parenthesis should recursively call // command_line_parse(). The command_t structure has a slot // you can use for parens; figure out how to use it! token_t token; memset(&token, 0, sizeof(token)); parse_gettoken(parsestate, &token); switch (token.type) { case TOK_NORMAL: if(flag_out){ flag_out=0; cmd->redirect_filename[1]=strdup(token.buffer); break; } else if(flag_in){ flag_in=0; cmd->redirect_filename[0]=strdup(token.buffer); break; } else if(flag_err){ flag_err=0; cmd->redirect_filename[2]=strdup(token.buffer); break; } if(i==MAXTOKENS) goto error; cmd->argv[i] = strdup(token.buffer); i++; break; case TOK_PIPE: cmd->controlop=CMD_PIPE; parse_ungettoken(parsestate); goto done; case TOK_DOUBLEPIPE: cmd->controlop=CMD_OR; parse_ungettoken(parsestate); goto done; case TOK_AMPERSAND: cmd->controlop=CMD_BACKGROUND; parse_ungettoken(parsestate); goto done; case TOK_DOUBLEAMP: cmd->controlop=CMD_AND; parse_ungettoken(parsestate); goto done; case TOK_SEMICOLON: cmd->controlop=CMD_SEMICOLON; parse_ungettoken(parsestate); goto done; case TOK_OPEN_PAREN: cmd->subshell=command_line_parse(parsestate,1); break; case TOK_CLOSE_PAREN: parse_ungettoken(parsestate); goto done; case TOK_END: parse_ungettoken(parsestate); cmd->controlop=CMD_END; goto done; case TOK_ERROR: goto error; case TOK_GREATER_THAN: flag_out=1; break; case TOK_LESS_THAN: flag_in=1; break; case TOK_2_GREATER_THAN: flag_err=1; break; default: parse_ungettoken(parsestate); goto done; } } done: // NULL-terminate the argv list cmd->argv[i] = 0; // EXERCISE: Make sure you return the right return value! if (i == 0 && cmd->subshell==NULL) { /* Empty command */ command_free(cmd); return NULL; } else return cmd; error: command_free(cmd); return NULL; }
command_t * command_parse(parsestate_t *parsestate) { int i = 0; command_t *cmd = command_alloc(); if (!cmd) { printf("cmd alloc error\n"); return NULL; } while (1) { // EXERCISE: Read the next token from 'parsestate'. // Normal tokens go in the cmd->argv[] array. // Redirection file names go into cmd->redirect_filename[]. // Open parenthesis tokens indicate a subshell command. // Other tokens complete the current command // and are not actually part of it; // use parse_ungettoken() to save those tokens for later. // There are a couple errors you should check. // First, be careful about overflow on normal tokens. // Each command_t only has space for MAXTOKENS tokens in // 'argv'. If there are too many tokens, reject the whole // command. // Second, redirection tokens (<, >, 2>) must be followed by // TOK_NORMAL tokens containing file names. // Third, a parenthesized subcommand can't be part of the // same command as other normal tokens. For example, // "echo ( echo foo )" and "( echo foo ) echo" are both errors. // (You should figure out exactly how to check for this kind // of error. Try interacting with the actual 'bash' shell // for some ideas.) // 'goto error' when you encounter one of these errors, // which frees the current command and returns NULL. // Hint: An open parenthesis should recursively call // command_line_parse(). The command_t structure has a slot // you can use for parens; figure out how to use it! if (i > MAXTOKENS) goto error; token_t token; parse_gettoken(parsestate, &token); switch (token.type) { case TOK_NORMAL: //printf("%s len: %d", token.buffer, strlen(token.buffer)); if (cmd->subshell != NULL) { parse_ungettoken(parsestate); goto done; } if (strlen(token.buffer) != 0) { cmd->argv[i] = strdup(token.buffer); i++; } break; case TOK_LESS_THAN: //printf("input red\n"); parse_gettoken(parsestate, &token); if (token.type != TOK_NORMAL) goto error; cmd->redirect_filename[0] = strdup(token.buffer); break; case TOK_GREATER_THAN: //printf("output red\n"); parse_gettoken(parsestate, &token); if (token.type != TOK_NORMAL) goto error; cmd->redirect_filename[1] = strdup(token.buffer); break; case TOK_2_GREATER_THAN: //printf("stderr red\n"); parse_gettoken(parsestate, &token); if (token.type != TOK_NORMAL) goto error; cmd->redirect_filename[2] = strdup(token.buffer); break; case TOK_OPEN_PAREN: cmd->subshell = command_line_parse(parsestate, PARENS_IN); //goto done; break; case TOK_CLOSE_PAREN: default: parse_ungettoken(parsestate); goto done; } } done: // NULL-terminate the argv list cmd->argv[i] = 0; // EXERCISE: Make sure you return the right return value! if (i == 0 && cmd->subshell == NULL) { /* Empty command */ command_free(cmd); return NULL; } else return cmd; error: command_free(cmd); return NULL; }
void eval_command_line(const char* s, zombies* z) { int type; char* token; // commandlist contains command groups separated by ';' or '&' command** commandlist = (command**) malloc(sizeof(command*)); // keep track of how many command groups wehave int listcontent = 1; // Your code here! // build the command command* c = command_alloc(); // the first command group commandlist[0] = c; while ((s = parse_shell_token(s, &type, &token)) != NULL) { if(type == TOKEN_CONTROL) { // seeing a ';' means we have to make a new command group if(token[0] == ';') { c = command_alloc(); commandlist = (command**) realloc(commandlist, (listcontent + 1)*sizeof(command*)); commandlist[listcontent] = c; ++listcontent; // seeing a '&' means we have to make a new command group } else if(token[0] == '&' && !token[1]) { c->background = 1; c = command_alloc(); commandlist = (command**) realloc(commandlist, (listcontent + 1)*sizeof(command*)); commandlist[listcontent] = c; ++listcontent; // putting into new command group so that we can conditionally evaluate it } else if(token[0] == '&' && token[1] == '&') { c = command_alloc(); c->needcondition = 0; commandlist = (command**) realloc(commandlist, (listcontent + 1)*sizeof(command*)); commandlist[listcontent] = c; ++listcontent; // within a command group, mark it as piping if seeing '|' } else if(token[0] == '|' && !token[1]) { c->piping = 1; command_append_arg(c, type, token); // putting into new command group so that we can conditionally evaluate it } else if(token[0] == '|' && token[1] == '|') { c = command_alloc(); c->needcondition = 1; commandlist = (command**) realloc(commandlist, (listcontent + 1)*sizeof(command*)); commandlist[listcontent] = c; ++listcontent; } } else if(type == TOKEN_REDIRECTION) { // redirecting standard input if(token[0] == '<' || token[0] == '0') { c->redirectstdin = 1; // redirecting standard output } else if(token[0] == '>' || token[0] == '1') { c->redirectstdout = 1; // redirecting standard error } else if(token[0] == '2' && token[1] == '>') { c->redirectstderr = 1; } } else { // the token following a redirection token must be a file name that should be dup'ed // then clears the flag if(c->redirectstdin) { c->stdinfilename = token; c->redirectstdin = 0; } else if(c->redirectstdout) { c->stdoutfilename = token; c->redirectstdout = 0; } else if(c->redirectstderr) { c->stderrfilename = token; c->redirectstderr = 0; // all other normal tokens } else { command_append_arg(c, type, token); } } } // execute the command int condition = -1; // exit condition of previous command for(int i = 0; i < listcontent; i++) { if (commandlist[i]->argc) // test if this command group should run if (commandlist[i]->needcondition == -1 || (commandlist[i]->needcondition == 0 && condition == 0) || (commandlist[i]->needcondition == 1 && condition != 0)) eval_command(commandlist[i], &condition, z); command_free(commandlist[i]); } free(commandlist); }