From 71767cfd2bfd952fd94ac140d7d8c38a24bd1d6a Mon Sep 17 00:00:00 2001 From: We-unite <3205135446@qq.com> Date: Thu, 6 Jun 2024 16:29:50 +0800 Subject: Add append && divide runcmd() into 4 funcs --- bcsh.c | 229 ++++++++++++++++++++++++++++++++++++--------------------------- cmd.h | 16 +++-- lex.l | 3 + syntax.y | 23 +++++-- 4 files changed, 163 insertions(+), 108 deletions(-) diff --git a/bcsh.c b/bcsh.c index 08f7ac7..656d608 100644 --- a/bcsh.c +++ b/bcsh.c @@ -6,7 +6,8 @@ char *username; char pwd[100]; int main(int argc, char **argv) { - // 获取当前登陆的用户名、系统主机名、当前工作路径 + // get the hostname, username and current working directory + // to show the prompt gethostname(hostname, sizeof(hostname)); getcwd(pwd, sizeof(pwd)); username = getpwuid(getuid())->pw_name; @@ -18,13 +19,14 @@ int main(int argc, char **argv) { } void showPrompt() { - printf("\033[01;32m%s@%s\033[00m:\033[33m%s\033[00m$ ", username, hostname, - pwd); - // 强制刷新缓冲区 + printf("\033[01;32m%s" + "\033[35m@%s\033[00m:" + "\033[33m%s\033[00m$ ", + username, hostname, pwd); fflush(stdout); } -Command *newcmd() { +Command *newCmd() { Command *cmd = (Command *)malloc(sizeof(Command)); cmd->argc = 0; cmd->args = NULL; @@ -39,134 +41,167 @@ Command *newcmd() { return cmd; } -int runcmd(Command *cmd) { +int runCmd(Command *cmd) { int status; if (cmd == NULL) { fprintf(stderr, "cmd is NULL\n"); return -1; } + switch (cmd->type) { + case CMD_NORMAL: + status = runNormalCmd(cmd); + break; + case CMD_PIPE: + status = runPipeCmd(cmd); + break; + case CMD_AND: + case CMD_OR: + status = runAndOrCmd(cmd); + break; + } - if (cmd->type == CMD_NORMAL) { - pid_t pid; - if (!strcmp(cmd->args[0], "exit")) { - printf("Good Bye, %s!\n", username); - exit(0); - } else if (!strcmp(cmd->args[0], "cd")) { - if (cmd->argc == 1) { - chdir(getenv("HOME")); - } else { - chdir(cmd->args[1]); - } - printf("\r"); - getcwd(pwd, sizeof(pwd)); + freeCmd(cmd); + return status; +} + +int runNormalCmd(Command *cmd) { + pid_t pid; + int status; + if (!strcmp(cmd->args[0], "exit")) { + printf("Good Bye, %s!\n", username); + exit(0); + } else if (!strcmp(cmd->args[0], "cd")) { + if (cmd->argc == 1) { + chdir(getenv("HOME")); } else { - if ((pid = fork()) == 0) { - // consider the redirection now - // it's just a part of normal command - // but not in other types - for (int i = 0; i < 3; i++) { - if (cmd->redirectFD[i] != i) { - close(i); - dup2(cmd->redirectFD[i], i); - } else if (cmd->redirectFile[i] != NULL) { - int fd = - open(cmd->redirectFile[i], O_RDWR | O_CREAT, 0666); - if (fd < 0) { - fprintf(stderr, "open file %s failed\n", - cmd->redirectFile[i]); - exit(-1); - } - close(i); - dup2(fd, i); - close(fd); - } - } - if (cmd->background) { - setpgid(0, 0); - // no output, redirect 1 and 2 to /dev/null - int fd = open("/dev/null", O_RDWR); - dup2(fd, 1); - dup2(fd, 2); - close(fd); - } - exit(execvp(cmd->args[0], cmd->args)); - } else { - if (!cmd->background) { - waitpid(pid, &status, 0); - if (!WIFEXITED(status)) { - // when here, the child process exited abnormally - fprintf(stderr, "Process %d exited with status %d\n", - pid, WEXITSTATUS(status)); - } + chdir(cmd->args[1]); + } + printf("\r"); + getcwd(pwd, sizeof(pwd)); + } else { + if ((pid = fork()) == 0) { + // consider the redirection now + // it's just a part of normal command + // but not in other types + redirect(cmd); + exit(execvp(cmd->args[0], cmd->args)); + } else { + if (!cmd->background) { + waitpid(pid, &status, 0); + if (!WIFEXITED(status)) { + // when here, the child process exited abnormally + fprintf(stderr, "Process %d exited with status %d\n", pid, + WEXITSTATUS(status)); } } - // return the exit status of the child process - return WEXITSTATUS(status); - } - } else if (cmd->type == CMD_PIPE) { - // create a pipe file and gets two file descriptors - // fd[0] is the read end, while fd[1] the write end - int fd[2]; - pid_t left, right; - pipe(fd); - if ((left = fork()) == 0) { - /* - * close the read end of the pipe, so that the child process - * can only write to it; then redirect the standard output - * to the write end of the pipe, and close the write end - * itself as a file descriptor. - */ - close(fd[0]); - dup2(fd[1], 1); - close(fd[1]); - exit(runcmd(cmd->left)); } - if ((right = fork()) == 0) { - close(fd[1]); - dup2(fd[0], 0); - close(fd[0]); - exit(runcmd(cmd->right)); - } - // close the pipe, because the parent process doesn't need it - // and wait for the two child processes to exit + // return the exit status of the child process + return WEXITSTATUS(status); + } +} + +int runPipeCmd(Command *cmd) { + int status; + // create a pipe file and gets two file descriptors + // fd[0] is the read end, while fd[1] the write end + int fd[2]; + pid_t left, right; + pipe(fd); + if ((left = fork()) == 0) { + /* + * close the read end of the pipe, so that the child process + * can only write to it; then redirect the standard output + * to the write end of the pipe, and close the write end + * itself as a file descriptor. + */ close(fd[0]); + dup2(fd[1], 1); + close(fd[1]); + exit(runCmd(cmd->left)); + } + if ((right = fork()) == 0) { close(fd[1]); - waitpid(left, NULL, 0); - waitpid(right, NULL, 0); - } else if (cmd->type == CMD_AND) { + dup2(fd[0], 0); + close(fd[0]); + exit(runCmd(cmd->right)); + } + // close the pipe, because the parent process doesn't need it + // and wait for the two child processes to exit + close(fd[0]); + close(fd[1]); + waitpid(left, NULL, 0); + waitpid(right, NULL, 0); +} + +int runAndOrCmd(Command *cmd) { + int status; + if (cmd->type == CMD_AND) { if (fork() == 0) { - exit(runcmd(cmd->left)); + exit(runCmd(cmd->left)); } else { waitpid(-1, &status, 0); if (WIFEXITED(status) && WEXITSTATUS(status) == 0 && fork() == 0) { - status = runcmd(cmd->right); + status = runCmd(cmd->right); } wait(NULL); } } else if (cmd->type == CMD_OR) { if (fork() == 0) { - exit(runcmd(cmd->left)); + exit(runCmd(cmd->left)); } else { waitpid(-1, &status, 0); if (WIFEXITED(status) && WEXITSTATUS(status) != 0 && fork() == 0) { - status = runcmd(cmd->right); + status = runCmd(cmd->right); } wait(NULL); } } - freecmd(cmd); - return status; } -void freecmd(Command *cmd) { +void redirect(Command *cur) { + int fd; + char *rfile; + for (int i = 0; i < 3; i++) { + fd = cur->redirectFD[i]; + rfile = cur->redirectFile[i]; + if (fd < -1 || fd > 2) { + fprintf(stderr, "file descriptor %d is invalid\n", fd); + exit(1); + } + if (fd == i && rfile == NULL) { + continue; + } + if (fd == -1) { + // append + fd = open(rfile, O_WRONLY | O_CREAT | O_APPEND, 0666); + } else if (rfile != NULL) { + // normal redirection + fd = open(rfile, O_WRONLY | O_CREAT | O_TRUNC, 0666); + } else { + // file descriptor redirection + // when here, fd is surely in 0, 1, 2 + ; + } + + if (fd < 0) { + fprintf(stderr, "open file %s failed\n", rfile); + exit(1); + } + close(i); + dup2(fd, i); + close(fd); + } +} + +void freeCmd(Command *cmd) { if (cmd == NULL) { return; } if (cmd->left != NULL) { - freecmd(cmd->left); + freeCmd(cmd->left); } if (cmd->right != NULL) { - freecmd(cmd->right); + freeCmd(cmd->right); } int i; for (i = 0; i < cmd->argc; i++) { diff --git a/cmd.h b/cmd.h index d591111..ce1d44c 100644 --- a/cmd.h +++ b/cmd.h @@ -1,6 +1,7 @@ #ifndef CMD_H #define CMD_H +#include #include #include #include @@ -9,7 +10,6 @@ #include #include #include -#include typedef enum { CMD_NORMAL, @@ -31,9 +31,15 @@ typedef struct Command { } Command; void showPrompt(); -Command *newcmd(); -int runcmd(Command *cmd); -void freecmd(Command *cmd); -void printcmd(Command *cmd); +Command *newCmd(); + +int runCmd(Command *cmd); +int runNormalCmd(Command *cmd); +int runPipeCmd(Command *cmd); +int runAndOrCmd(Command *cmd); + +void freeCmd(Command *cmd); + +void redirect(Command *cur); #endif \ No newline at end of file diff --git a/lex.l b/lex.l index 3b99f1c..4f1497a 100644 --- a/lex.l +++ b/lex.l @@ -16,9 +16,12 @@ void yyerror(const char *s); "||" { return OR; } "<" { return REDIRECT_IN; } ">" { return REDIRECT_OUT; } +">>" { return APPEND; } "&" { return BACKGROUND; } [0-2]">"&[0-2] { yylval.str = strdup(yytext); return FD_REDIRECT; } [a-zA-Z0-9_\-\/\*.]+ { yylval.str = strdup(yytext); return WORD; } +"(" { return LPAREN; } +")" { return RPAREN; } %% diff --git a/syntax.y b/syntax.y index 5f33c9a..a53537a 100644 --- a/syntax.y +++ b/syntax.y @@ -12,7 +12,7 @@ } %token WORD STRING error FD_REDIRECT -%token NEWLINE PIPE AND OR REDIRECT_IN REDIRECT_OUT BACKGROUND +%token NEWLINE PIPE AND OR REDIRECT_IN REDIRECT_OUT BACKGROUND LPAREN RPAREN APPEND %type line command part runcommand %type separator @@ -32,10 +32,13 @@ line: runcommand: command NEWLINE { $$ = $1; - runcmd($$); + runCmd($$); + showPrompt(); + } + | NEWLINE { + $$ = NULL; showPrompt(); } - | NEWLINE { $$ = NULL; } ; command: @@ -43,11 +46,14 @@ command: $$ = $1; } | part separator command { - $$ = newcmd(); + $$ = newCmd(); $$->type = $2; $$->left = $1; $$->right = $3; } + | LPAREN command RPAREN { + $$ = $2; + } ; separator: @@ -65,7 +71,7 @@ part: $$->args[$$->argc] = NULL; } | WORD { - $$ = newcmd(); + $$ = newCmd(); $$->args = malloc(2 * sizeof(char *)); $$->args[$$->argc++] = $1; $$->args[$$->argc] = NULL; @@ -78,9 +84,14 @@ part: $$ = $1; $$->redirectFile[1] = $3; } + | part APPEND WORD { + $$ = $1; + $$->redirectFile[1] = $3; + $$->redirectFD[1] = -1; + } | part FD_REDIRECT { $$ = $1; - $$->redirectFD[$2[0]-'0']=$2[3]-'0'; + $$->redirectFD[$2[0] - '0'] = $2[3] - '0'; } | part BACKGROUND { $$ = $1; -- cgit v1.2.3-70-g09d2