aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWe-unite <3205135446@qq.com>2024-06-06 16:29:50 +0800
committerWe-unite <3205135446@qq.com>2024-06-06 16:29:50 +0800
commit71767cfd2bfd952fd94ac140d7d8c38a24bd1d6a (patch)
tree80141861bf765c15a553f7bfec655e0ab7d094d0
parent69629dbd351c7e0a555d70c7495a6f677cf06f92 (diff)
downloadbcsh-71767cfd2bfd952fd94ac140d7d8c38a24bd1d6a.tar.gz
bcsh-71767cfd2bfd952fd94ac140d7d8c38a24bd1d6a.zip
Add append && divide runcmd() into 4 funcs
-rw-r--r--bcsh.c229
-rw-r--r--cmd.h16
-rw-r--r--lex.l3
-rw-r--r--syntax.y23
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;
6char pwd[100]; 6char pwd[100];
7 7
8int main(int argc, char **argv) { 8int main(int argc, char **argv) {
9 // 获取当前登陆的用户名、系统主机名、当前工作路径 9 // get the hostname, username and current working directory
10 // to show the prompt
10 gethostname(hostname, sizeof(hostname)); 11 gethostname(hostname, sizeof(hostname));
11 getcwd(pwd, sizeof(pwd)); 12 getcwd(pwd, sizeof(pwd));
12 username = getpwuid(getuid())->pw_name; 13 username = getpwuid(getuid())->pw_name;
@@ -18,13 +19,14 @@ int main(int argc, char **argv) {
18} 19}
19 20
20void showPrompt() { 21void showPrompt() {
21 printf("\033[01;32m%s@%s\033[00m:\033[33m%s\033[00m$ ", username, hostname, 22 printf("\033[01;32m%s"
22 pwd); 23 "\033[35m@%s\033[00m:"
23 // 强制刷新缓冲区 24 "\033[33m%s\033[00m$ ",
25 username, hostname, pwd);
24 fflush(stdout); 26 fflush(stdout);
25} 27}
26 28
27Command *newcmd() { 29Command *newCmd() {
28 Command *cmd = (Command *)malloc(sizeof(Command)); 30 Command *cmd = (Command *)malloc(sizeof(Command));
29 cmd->argc = 0; 31 cmd->argc = 0;
30 cmd->args = NULL; 32 cmd->args = NULL;
@@ -39,134 +41,167 @@ Command *newcmd() {
39 return cmd; 41 return cmd;
40} 42}
41 43
42int runcmd(Command *cmd) { 44int runCmd(Command *cmd) {
43 int status; 45 int status;
44 if (cmd == NULL) { 46 if (cmd == NULL) {
45 fprintf(stderr, "cmd is NULL\n"); 47 fprintf(stderr, "cmd is NULL\n");
46 return -1; 48 return -1;
47 } 49 }
50 switch (cmd->type) {
51 case CMD_NORMAL:
52 status = runNormalCmd(cmd);
53 break;
54 case CMD_PIPE:
55 status = runPipeCmd(cmd);
56 break;
57 case CMD_AND:
58 case CMD_OR:
59 status = runAndOrCmd(cmd);
60 break;
61 }
48 62
49 if (cmd->type == CMD_NORMAL) { 63 freeCmd(cmd);
50 pid_t pid; 64 return status;
51 if (!strcmp(cmd->args[0], "exit")) { 65}
52 printf("Good Bye, %s!\n", username); 66
53 exit(0); 67int runNormalCmd(Command *cmd) {
54 } else if (!strcmp(cmd->args[0], "cd")) { 68 pid_t pid;
55 if (cmd->argc == 1) { 69 int status;
56 chdir(getenv("HOME")); 70 if (!strcmp(cmd->args[0], "exit")) {
57 } else { 71 printf("Good Bye, %s!\n", username);
58 chdir(cmd->args[1]); 72 exit(0);
59 } 73 } else if (!strcmp(cmd->args[0], "cd")) {
60 printf("\r"); 74 if (cmd->argc == 1) {
61 getcwd(pwd, sizeof(pwd)); 75 chdir(getenv("HOME"));
62 } else { 76 } else {
63 if ((pid = fork()) == 0) { 77 chdir(cmd->args[1]);
64 // consider the redirection now 78 }
65 // it's just a part of normal command 79 printf("\r");
66 // but not in other types 80 getcwd(pwd, sizeof(pwd));
67 for (int i = 0; i < 3; i++) { 81 } else {
68 if (cmd->redirectFD[i] != i) { 82 if ((pid = fork()) == 0) {
69 close(i); 83 // consider the redirection now
70 dup2(cmd->redirectFD[i], i); 84 // it's just a part of normal command
71 } else if (cmd->redirectFile[i] != NULL) { 85 // but not in other types
72 int fd = 86 redirect(cmd);
73 open(cmd->redirectFile[i], O_RDWR | O_CREAT, 0666); 87 exit(execvp(cmd->args[0], cmd->args));
74 if (fd < 0) { 88 } else {
75 fprintf(stderr, "open file %s failed\n", 89 if (!cmd->background) {
76 cmd->redirectFile[i]); 90 waitpid(pid, &status, 0);
77 exit(-1); 91 if (!WIFEXITED(status)) {
78 } 92 // when here, the child process exited abnormally
79 close(i); 93 fprintf(stderr, "Process %d exited with status %d\n", pid,
80 dup2(fd, i); 94 WEXITSTATUS(status));
81 close(fd);
82 }
83 }
84 if (cmd->background) {
85 setpgid(0, 0);
86 // no output, redirect 1 and 2 to /dev/null
87 int fd = open("/dev/null", O_RDWR);
88 dup2(fd, 1);
89 dup2(fd, 2);
90 close(fd);
91 }
92 exit(execvp(cmd->args[0], cmd->args));
93 } else {
94 if (!cmd->background) {
95 waitpid(pid, &status, 0);
96 if (!WIFEXITED(status)) {
97 // when here, the child process exited abnormally
98 fprintf(stderr, "Process %d exited with status %d\n",
99 pid, WEXITSTATUS(status));
100 }
101 } 95 }
102 } 96 }
103 // return the exit status of the child process
104 return WEXITSTATUS(status);
105 }
106 } else if (cmd->type == CMD_PIPE) {
107 // create a pipe file and gets two file descriptors
108 // fd[0] is the read end, while fd[1] the write end
109 int fd[2];
110 pid_t left, right;
111 pipe(fd);
112 if ((left = fork()) == 0) {
113 /*
114 * close the read end of the pipe, so that the child process
115 * can only write to it; then redirect the standard output
116 * to the write end of the pipe, and close the write end
117 * itself as a file descriptor.
118 */
119 close(fd[0]);
120 dup2(fd[1], 1);
121 close(fd[1]);
122 exit(runcmd(cmd->left));
123 } 97 }
124 if ((right = fork()) == 0) { 98 // return the exit status of the child process
125 close(fd[1]); 99 return WEXITSTATUS(status);
126 dup2(fd[0], 0); 100 }
127 close(fd[0]); 101}
128 exit(runcmd(cmd->right)); 102
129 } 103int runPipeCmd(Command *cmd) {
130 // close the pipe, because the parent process doesn't need it 104 int status;
131 // and wait for the two child processes to exit 105 // create a pipe file and gets two file descriptors
106 // fd[0] is the read end, while fd[1] the write end
107 int fd[2];
108 pid_t left, right;
109 pipe(fd);
110 if ((left = fork()) == 0) {
111 /*
112 * close the read end of the pipe, so that the child process
113 * can only write to it; then redirect the standard output
114 * to the write end of the pipe, and close the write end
115 * itself as a file descriptor.
116 */
132 close(fd[0]); 117 close(fd[0]);
118 dup2(fd[1], 1);
119 close(fd[1]);
120 exit(runCmd(cmd->left));
121 }
122 if ((right = fork()) == 0) {
133 close(fd[1]); 123 close(fd[1]);
134 waitpid(left, NULL, 0); 124 dup2(fd[0], 0);
135 waitpid(right, NULL, 0); 125 close(fd[0]);
136 } else if (cmd->type == CMD_AND) { 126 exit(runCmd(cmd->right));
127 }
128 // close the pipe, because the parent process doesn't need it
129 // and wait for the two child processes to exit
130 close(fd[0]);
131 close(fd[1]);
132 waitpid(left, NULL, 0);
133 waitpid(right, NULL, 0);
134}
135
136int runAndOrCmd(Command *cmd) {
137 int status;
138 if (cmd->type == CMD_AND) {
137 if (fork() == 0) { 139 if (fork() == 0) {
138 exit(runcmd(cmd->left)); 140 exit(runCmd(cmd->left));
139 } else { 141 } else {
140 waitpid(-1, &status, 0); 142 waitpid(-1, &status, 0);
141 if (WIFEXITED(status) && WEXITSTATUS(status) == 0 && fork() == 0) { 143 if (WIFEXITED(status) && WEXITSTATUS(status) == 0 && fork() == 0) {
142 status = runcmd(cmd->right); 144 status = runCmd(cmd->right);
143 } 145 }
144 wait(NULL); 146 wait(NULL);
145 } 147 }
146 } else if (cmd->type == CMD_OR) { 148 } else if (cmd->type == CMD_OR) {
147 if (fork() == 0) { 149 if (fork() == 0) {
148 exit(runcmd(cmd->left)); 150 exit(runCmd(cmd->left));
149 } else { 151 } else {
150 waitpid(-1, &status, 0); 152 waitpid(-1, &status, 0);
151 if (WIFEXITED(status) && WEXITSTATUS(status) != 0 && fork() == 0) { 153 if (WIFEXITED(status) && WEXITSTATUS(status) != 0 && fork() == 0) {
152 status = runcmd(cmd->right); 154 status = runCmd(cmd->right);
153 } 155 }
154 wait(NULL); 156 wait(NULL);
155 } 157 }
156 } 158 }
157 freecmd(cmd);
158 return status;
159} 159}
160 160
161void freecmd(Command *cmd) { 161void redirect(Command *cur) {
162 int fd;
163 char *rfile;
164 for (int i = 0; i < 3; i++) {
165 fd = cur->redirectFD[i];
166 rfile = cur->redirectFile[i];
167 if (fd < -1 || fd > 2) {
168 fprintf(stderr, "file descriptor %d is invalid\n", fd);
169 exit(1);
170 }
171 if (fd == i && rfile == NULL) {
172 continue;
173 }
174 if (fd == -1) {
175 // append
176 fd = open(rfile, O_WRONLY | O_CREAT | O_APPEND, 0666);
177 } else if (rfile != NULL) {
178 // normal redirection
179 fd = open(rfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
180 } else {
181 // file descriptor redirection
182 // when here, fd is surely in 0, 1, 2
183 ;
184 }
185
186 if (fd < 0) {
187 fprintf(stderr, "open file %s failed\n", rfile);
188 exit(1);
189 }
190 close(i);
191 dup2(fd, i);
192 close(fd);
193 }
194}
195
196void freeCmd(Command *cmd) {
162 if (cmd == NULL) { 197 if (cmd == NULL) {
163 return; 198 return;
164 } 199 }
165 if (cmd->left != NULL) { 200 if (cmd->left != NULL) {
166 freecmd(cmd->left); 201 freeCmd(cmd->left);
167 } 202 }
168 if (cmd->right != NULL) { 203 if (cmd->right != NULL) {
169 freecmd(cmd->right); 204 freeCmd(cmd->right);
170 } 205 }
171 int i; 206 int i;
172 for (i = 0; i < cmd->argc; i++) { 207 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 @@
1#ifndef CMD_H 1#ifndef CMD_H
2#define CMD_H 2#define CMD_H
3 3
4#include <fcntl.h>
4#include <pwd.h> 5#include <pwd.h>
5#include <stdbool.h> 6#include <stdbool.h>
6#include <stdio.h> 7#include <stdio.h>
@@ -9,7 +10,6 @@
9#include <sys/types.h> 10#include <sys/types.h>
10#include <sys/wait.h> 11#include <sys/wait.h>
11#include <unistd.h> 12#include <unistd.h>
12#include <fcntl.h>
13 13
14typedef enum { 14typedef enum {
15 CMD_NORMAL, 15 CMD_NORMAL,
@@ -31,9 +31,15 @@ typedef struct Command {
31} Command; 31} Command;
32 32
33void showPrompt(); 33void showPrompt();
34Command *newcmd(); 34Command *newCmd();
35int runcmd(Command *cmd); 35
36void freecmd(Command *cmd); 36int runCmd(Command *cmd);
37void printcmd(Command *cmd); 37int runNormalCmd(Command *cmd);
38int runPipeCmd(Command *cmd);
39int runAndOrCmd(Command *cmd);
40
41void freeCmd(Command *cmd);
42
43void redirect(Command *cur);
38 44
39#endif \ No newline at end of file 45#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);
16"||" { return OR; } 16"||" { return OR; }
17"<" { return REDIRECT_IN; } 17"<" { return REDIRECT_IN; }
18">" { return REDIRECT_OUT; } 18">" { return REDIRECT_OUT; }
19">>" { return APPEND; }
19"&" { return BACKGROUND; } 20"&" { return BACKGROUND; }
20[0-2]">"&[0-2] { yylval.str = strdup(yytext); return FD_REDIRECT; } 21[0-2]">"&[0-2] { yylval.str = strdup(yytext); return FD_REDIRECT; }
21[a-zA-Z0-9_\-\/\*.]+ { yylval.str = strdup(yytext); return WORD; } 22[a-zA-Z0-9_\-\/\*.]+ { yylval.str = strdup(yytext); return WORD; }
23"(" { return LPAREN; }
24")" { return RPAREN; }
22 25
23%% 26%%
24 27
diff --git a/syntax.y b/syntax.y
index 5f33c9a..a53537a 100644
--- a/syntax.y
+++ b/syntax.y
@@ -12,7 +12,7 @@
12} 12}
13 13
14%token <str> WORD STRING error FD_REDIRECT 14%token <str> WORD STRING error FD_REDIRECT
15%token NEWLINE PIPE AND OR REDIRECT_IN REDIRECT_OUT BACKGROUND 15%token NEWLINE PIPE AND OR REDIRECT_IN REDIRECT_OUT BACKGROUND LPAREN RPAREN APPEND
16 16
17%type <cmd> line command part runcommand 17%type <cmd> line command part runcommand
18%type <cmdType> separator 18%type <cmdType> separator
@@ -32,10 +32,13 @@ line:
32runcommand: 32runcommand:
33 command NEWLINE { 33 command NEWLINE {
34 $$ = $1; 34 $$ = $1;
35 runcmd($$); 35 runCmd($$);
36 showPrompt();
37 }
38 | NEWLINE {
39 $$ = NULL;
36 showPrompt(); 40 showPrompt();
37 } 41 }
38 | NEWLINE { $$ = NULL; }
39 ; 42 ;
40 43
41command: 44command:
@@ -43,11 +46,14 @@ command:
43 $$ = $1; 46 $$ = $1;
44 } 47 }
45 | part separator command { 48 | part separator command {
46 $$ = newcmd(); 49 $$ = newCmd();
47 $$->type = $2; 50 $$->type = $2;
48 $$->left = $1; 51 $$->left = $1;
49 $$->right = $3; 52 $$->right = $3;
50 } 53 }
54 | LPAREN command RPAREN {
55 $$ = $2;
56 }
51 ; 57 ;
52 58
53separator: 59separator:
@@ -65,7 +71,7 @@ part:
65 $$->args[$$->argc] = NULL; 71 $$->args[$$->argc] = NULL;
66 } 72 }
67 | WORD { 73 | WORD {
68 $$ = newcmd(); 74 $$ = newCmd();
69 $$->args = malloc(2 * sizeof(char *)); 75 $$->args = malloc(2 * sizeof(char *));
70 $$->args[$$->argc++] = $1; 76 $$->args[$$->argc++] = $1;
71 $$->args[$$->argc] = NULL; 77 $$->args[$$->argc] = NULL;
@@ -78,9 +84,14 @@ part:
78 $$ = $1; 84 $$ = $1;
79 $$->redirectFile[1] = $3; 85 $$->redirectFile[1] = $3;
80 } 86 }
87 | part APPEND WORD {
88 $$ = $1;
89 $$->redirectFile[1] = $3;
90 $$->redirectFD[1] = -1;
91 }
81 | part FD_REDIRECT { 92 | part FD_REDIRECT {
82 $$ = $1; 93 $$ = $1;
83 $$->redirectFD[$2[0]-'0']=$2[3]-'0'; 94 $$->redirectFD[$2[0] - '0'] = $2[3] - '0';
84 } 95 }
85 | part BACKGROUND { 96 | part BACKGROUND {
86 $$ = $1; 97 $$ = $1;