diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 14 | ||||
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | bcsh.c | 209 | ||||
-rw-r--r-- | cmd.c | 195 | ||||
-rw-r--r-- | cmd.h | 11 | ||||
-rw-r--r-- | lex.l | 1 | ||||
-rw-r--r-- | ohoshell.sh | 2 | ||||
-rw-r--r-- | syntax.y | 20 |
9 files changed, 251 insertions, 210 deletions
@@ -1,6 +1,7 @@ | |||
1 | * | 1 | * |
2 | !*.* | 2 | !*.* |
3 | !*/* | 3 | !*/* |
4 | .vscode/* | ||
4 | !Makefile | 5 | !Makefile |
5 | *.o | 6 | *.o |
6 | *.tab* | 7 | *.tab* |
@@ -1,5 +1,11 @@ | |||
1 | bcsh: syntax.tab.o bcsh.c | 1 | bcsh: syntax.tab.o bcsh.o cmd.o |
2 | gcc -g -o bcsh bcsh.c syntax.tab.o -lfl | 2 | gcc -g -o bcsh bcsh.o cmd.o syntax.tab.o -lfl |
3 | |||
4 | bcsh.o: bcsh.c | ||
5 | gcc -g -c bcsh.c -o bcsh.o | ||
6 | |||
7 | cmd.o: cmd.c | ||
8 | gcc -g -c cmd.c -o cmd.o | ||
3 | 9 | ||
4 | syntax.tab.o: lex.yy.c syntax.tab.c | 10 | syntax.tab.o: lex.yy.c syntax.tab.c |
5 | gcc -g -c syntax.tab.c -o syntax.tab.o | 11 | gcc -g -c syntax.tab.c -o syntax.tab.o |
@@ -11,4 +17,6 @@ syntax.tab.c: syntax.y | |||
11 | bison -o syntax.tab.c -d -v syntax.y -Wcounterexamples | 17 | bison -o syntax.tab.c -d -v syntax.y -Wcounterexamples |
12 | 18 | ||
13 | clean: | 19 | clean: |
14 | rm -f bcsh lex.yy.c syntax.tab.c syntax.tab.h syntax.output syntax.tab.o | 20 | rm -f bcsh |
21 | rm -f bcsh.o cmd.o syntax.tab.o | ||
22 | rm -f lex.yy.c syntax.tab.c syntax.tab.h syntax.output | ||
@@ -1,8 +1,6 @@ | |||
1 | [toc] | ||
2 | |||
3 | # 我与 shell | 1 | # 我与 shell |
4 | 2 | ||
5 | 我是个喜欢用 Linux 命令行的人,**喜欢用命令行来完成一切工作,喜欢这种自己独掌系统一切的感觉**,仿佛自己是这台电脑的创世神~~,虽然现实中我只是废柴一个~~。对于每个学习 Linux 的人来说,bash 绝对是一座绕不过去的山,即使已有了 zsh、fish shell 等更加现代化、更加友好的工具,bash 由于其普适性和强大的功能,依然是大多数生产环境的首选。 | 3 | 我是个喜欢用 Linux 命令行的人,**喜欢用命令行来完成一切工作,喜欢这种自己独掌系统一切的感觉**,仿佛自己是这台电脑的创世神(虽然现实中只是废柴一个)。对于每个学习 Linux 的人来说,bash 绝对是一座绕不过去的山,即使已有了 zsh、fish shell 等更加现代化、更加友好的工具,bash 由于其普适性和强大的功能,依然是大多数生产环境的首选。 |
6 | 4 | ||
7 | 但我在学 bash 时遇到了不小的困难,我发现 bash 的语法规定过于奇怪繁杂,完全不像其他编程语言,甚至就连 if 和括号之间都要求必须插入空格,第一次学的时候我在这里犯错,还找了好久。相比之下,我更喜欢 C 语言的语法(也许是我计算机入门学的就是 C 的缘故吧),多简洁明了啊! | 5 | 但我在学 bash 时遇到了不小的困难,我发现 bash 的语法规定过于奇怪繁杂,完全不像其他编程语言,甚至就连 if 和括号之间都要求必须插入空格,第一次学的时候我在这里犯错,还找了好久。相比之下,我更喜欢 C 语言的语法(也许是我计算机入门学的就是 C 的缘故吧),多简洁明了啊! |
8 | 6 | ||
@@ -10,7 +8,7 @@ | |||
10 | 8 | ||
11 | 在学习 Linux-0.12 的过程中,我第一次了解到,**原来 shell 和我们自己编写的其他程序一样,是一个独立于操作系统之外的用户态程序**,因而是可以替换的、甚至是可以自己编写的。本来这件事遥遥无期,也许一辈子都不会去做,但我偏偏遇到了网络信息技术大赛,看到了开源鸿蒙 Terminal 应用开发这条赛道。嗯……shell 开发怎么不算 Terminal 应用开发呢?(笑。)于是一个计划生根发芽。 | 9 | 在学习 Linux-0.12 的过程中,我第一次了解到,**原来 shell 和我们自己编写的其他程序一样,是一个独立于操作系统之外的用户态程序**,因而是可以替换的、甚至是可以自己编写的。本来这件事遥遥无期,也许一辈子都不会去做,但我偏偏遇到了网络信息技术大赛,看到了开源鸿蒙 Terminal 应用开发这条赛道。嗯……shell 开发怎么不算 Terminal 应用开发呢?(笑。)于是一个计划生根发芽。 |
12 | 10 | ||
13 | 我的计划是这样的:**我要自己编写一个 shell,这个 shell 要能够完全替代 bash,而且要比 bash 更加简洁易用**。这个 shell 的名字就叫 bcsh,意为“Better C Shell”。我希望通过这个 shell 的开发,能够更加深入地了解 shell 的工作原理,同时也能够提高自己的编程能力。 | 11 | 我的计划是这样的:**我要自己编写一个 shell,这个 shell 要能够完全替代 bash,而且要比 bash 更加简洁易用**。我希望通过这个 shell 的开发,能够更加深入地了解 shell 的工作原理,同时也能够提高自己的编程能力。 |
14 | 12 | ||
15 | 我的设计初衷是,在基本命令与功能上,尽可能地贴近 bash,以免影响我自己的使用习惯;同时,在 case、if、循环等语法上,向 C 语言靠拢,让初学者(主要是我自己)更容易上手。当然,我也会在这个过程中,尽可能地保持代码的简洁性和可读性。因而我为它取了"bcsh"这个名字: | 13 | 我的设计初衷是,在基本命令与功能上,尽可能地贴近 bash,以免影响我自己的使用习惯;同时,在 case、if、循环等语法上,向 C 语言靠拢,让初学者(主要是我自己)更容易上手。当然,我也会在这个过程中,尽可能地保持代码的简洁性和可读性。因而我为它取了"bcsh"这个名字: |
16 | 14 | ||
@@ -29,7 +27,7 @@ | |||
29 | 27 | ||
30 | ## TODO list | 28 | ## TODO list |
31 | 29 | ||
32 | - Ctrl+C、Ctrl+D、Ctrl+Z 等信号的处理 | 30 | - Ctrl+Z 等信号的处理 |
33 | - 复杂语法的支持:if、case、循环等 | 31 | - 复杂语法的支持:if、case、循环等 |
34 | - 设置与显示环境变量 | 32 | - 设置与显示环境变量 |
35 | - 命令历史记录 | 33 | - 命令历史记录 |
@@ -19,199 +19,30 @@ int main(int argc, char **argv) { | |||
19 | } | 19 | } |
20 | 20 | ||
21 | void showPrompt() { | 21 | void showPrompt() { |
22 | printf("\033[01;32m%s" | 22 | if (getuid() == 0) { |
23 | "\033[35m@%s\033[00m:" | 23 | printf("%s@%s:%s# ", username, hostname, pwd); |
24 | "\033[33m%s\033[00m$ ", | ||
25 | username, hostname, pwd); | ||
26 | fflush(stdout); | ||
27 | } | ||
28 | |||
29 | Command *newCmd() { | ||
30 | Command *cmd = (Command *)malloc(sizeof(Command)); | ||
31 | cmd->argc = 0; | ||
32 | cmd->args = NULL; | ||
33 | cmd->type = CMD_NORMAL; | ||
34 | cmd->left = NULL; | ||
35 | cmd->right = NULL; | ||
36 | for (int i = 0; i < 3; i++) { | ||
37 | cmd->redirectFile[i] = NULL; | ||
38 | cmd->redirectFD[i] = i; | ||
39 | } | ||
40 | cmd->background = false; | ||
41 | return cmd; | ||
42 | } | ||
43 | |||
44 | int runCmd(Command *cmd) { | ||
45 | int status; | ||
46 | if (cmd == NULL) { | ||
47 | fprintf(stderr, "cmd is NULL\n"); | ||
48 | return -1; | ||
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 | } | ||
62 | |||
63 | freeCmd(cmd); | ||
64 | return status; | ||
65 | } | ||
66 | |||
67 | int runNormalCmd(Command *cmd) { | ||
68 | pid_t pid; | ||
69 | int status; | ||
70 | if (!strcmp(cmd->args[0], "exit")) { | ||
71 | printf("Good Bye, %s!\n", username); | ||
72 | exit(0); | ||
73 | } else if (!strcmp(cmd->args[0], "cd")) { | ||
74 | if (cmd->argc == 1) { | ||
75 | chdir(getenv("HOME")); | ||
76 | } else { | ||
77 | chdir(cmd->args[1]); | ||
78 | } | ||
79 | printf("\r"); | ||
80 | getcwd(pwd, sizeof(pwd)); | ||
81 | } else { | 24 | } else { |
82 | if ((pid = fork()) == 0) { | 25 | printf("\033[01;32m%s" |
83 | // consider the redirection now | 26 | "\033[35m@%s\033[00m:" |
84 | // it's just a part of normal command | 27 | "\033[33m%s\033[00m$ ", |
85 | // but not in other types | 28 | username, hostname, pwd); |
86 | redirect(cmd); | ||
87 | exit(execvp(cmd->args[0], cmd->args)); | ||
88 | } else { | ||
89 | if (!cmd->background) { | ||
90 | waitpid(pid, &status, 0); | ||
91 | if (!WIFEXITED(status)) { | ||
92 | // when here, the child process exited abnormally | ||
93 | fprintf(stderr, "Process %d exited with status %d\n", pid, | ||
94 | WEXITSTATUS(status)); | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | // return the exit status of the child process | ||
99 | return WEXITSTATUS(status); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | int runPipeCmd(Command *cmd) { | ||
104 | int status; | ||
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 | */ | ||
117 | close(fd[0]); | ||
118 | dup2(fd[1], 1); | ||
119 | close(fd[1]); | ||
120 | exit(runCmd(cmd->left)); | ||
121 | } | ||
122 | if ((right = fork()) == 0) { | ||
123 | close(fd[1]); | ||
124 | dup2(fd[0], 0); | ||
125 | close(fd[0]); | ||
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 | |||
136 | int runAndOrCmd(Command *cmd) { | ||
137 | int status; | ||
138 | if (cmd->type == CMD_AND) { | ||
139 | if (fork() == 0) { | ||
140 | exit(runCmd(cmd->left)); | ||
141 | } else { | ||
142 | waitpid(-1, &status, 0); | ||
143 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0 && fork() == 0) { | ||
144 | status = runCmd(cmd->right); | ||
145 | } | ||
146 | wait(NULL); | ||
147 | } | ||
148 | } else if (cmd->type == CMD_OR) { | ||
149 | if (fork() == 0) { | ||
150 | exit(runCmd(cmd->left)); | ||
151 | } else { | ||
152 | waitpid(-1, &status, 0); | ||
153 | if (WIFEXITED(status) && WEXITSTATUS(status) != 0 && fork() == 0) { | ||
154 | status = runCmd(cmd->right); | ||
155 | } | ||
156 | wait(NULL); | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | |||
161 | void 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 | } | 29 | } |
30 | fflush(stdout); | ||
194 | } | 31 | } |
195 | 32 | ||
196 | void freeCmd(Command *cmd) { | 33 | void argInsert(struct Command *cmd, char *s, bool isStr) { |
197 | if (cmd == NULL) { | 34 | if (cmd->argc == 0) { |
198 | return; | 35 | cmd->args = malloc(2 * sizeof(char *)); |
199 | } | 36 | } else { |
200 | if (cmd->left != NULL) { | 37 | cmd->args = realloc(cmd->args, (cmd->argc + 2) * sizeof(char *)); |
201 | freeCmd(cmd->left); | ||
202 | } | ||
203 | if (cmd->right != NULL) { | ||
204 | freeCmd(cmd->right); | ||
205 | } | ||
206 | int i; | ||
207 | for (i = 0; i < cmd->argc; i++) { | ||
208 | free(cmd->args[i]); | ||
209 | } | 38 | } |
210 | free(cmd->args); | 39 | if (isStr) { |
211 | for (i = 0; i < 3; i++) { | 40 | cmd->args[cmd->argc] = strdup(s + 1); |
212 | if (cmd->redirectFile[i] != NULL) { | 41 | cmd->args[cmd->argc][strlen(cmd->args[cmd->argc]) - 1] = '\0'; |
213 | free(cmd->redirectFile[i]); | 42 | free(s); |
214 | } | 43 | } else { |
44 | cmd->args[cmd->argc] = s; | ||
215 | } | 45 | } |
216 | free(cmd); | 46 | cmd->args[cmd->argc + 1] = NULL; |
47 | cmd->argc++; | ||
217 | } \ No newline at end of file | 48 | } \ No newline at end of file |
@@ -0,0 +1,195 @@ | |||
1 | #include "cmd.h" | ||
2 | |||
3 | Command *newCmd() { | ||
4 | Command *cmd = (Command *)malloc(sizeof(Command)); | ||
5 | cmd->argc = 0; | ||
6 | cmd->args = NULL; | ||
7 | cmd->type = CMD_NORMAL; | ||
8 | cmd->left = NULL; | ||
9 | cmd->right = NULL; | ||
10 | for (int i = 0; i < 3; i++) { | ||
11 | cmd->redirectFile[i] = NULL; | ||
12 | cmd->redirectFD[i] = i; | ||
13 | } | ||
14 | cmd->background = false; | ||
15 | return cmd; | ||
16 | } | ||
17 | |||
18 | void freeCmd(Command *cmd) { | ||
19 | if (cmd == NULL) { | ||
20 | return; | ||
21 | } | ||
22 | if (cmd->left != NULL) { | ||
23 | freeCmd(cmd->left); | ||
24 | } | ||
25 | if (cmd->right != NULL) { | ||
26 | freeCmd(cmd->right); | ||
27 | } | ||
28 | int i; | ||
29 | for (i = 0; i < cmd->argc; i++) { | ||
30 | free(cmd->args[i]); | ||
31 | } | ||
32 | free(cmd->args); | ||
33 | for (i = 0; i < 3; i++) { | ||
34 | if (cmd->redirectFile[i] != NULL) { | ||
35 | free(cmd->redirectFile[i]); | ||
36 | } | ||
37 | } | ||
38 | free(cmd); | ||
39 | } | ||
40 | |||
41 | int runCmd(Command *cmd) { | ||
42 | int status; | ||
43 | if (cmd == NULL) { | ||
44 | fprintf(stderr, "cmd is NULL\n"); | ||
45 | return -1; | ||
46 | } | ||
47 | switch (cmd->type) { | ||
48 | case CMD_NORMAL: | ||
49 | status = runNormalCmd(cmd); | ||
50 | break; | ||
51 | case CMD_PIPE: | ||
52 | status = runPipeCmd(cmd); | ||
53 | break; | ||
54 | case CMD_AND: | ||
55 | case CMD_OR: | ||
56 | status = runAndOrCmd(cmd); | ||
57 | break; | ||
58 | } | ||
59 | |||
60 | freeCmd(cmd); | ||
61 | return status; | ||
62 | } | ||
63 | |||
64 | int runNormalCmd(Command *cmd) { | ||
65 | pid_t pid; | ||
66 | int status; | ||
67 | if (!strcmp(cmd->args[0], "exit")) { | ||
68 | printf("Good Bye, %s!\n", username); | ||
69 | exit(0); | ||
70 | } else if (!strcmp(cmd->args[0], "cd")) { | ||
71 | if (cmd->argc == 1) { | ||
72 | chdir(getenv("HOME")); | ||
73 | } else { | ||
74 | chdir(cmd->args[1]); | ||
75 | } | ||
76 | printf("\r"); | ||
77 | getcwd(pwd, sizeof(pwd)); | ||
78 | } else { | ||
79 | if ((pid = fork()) == 0) { | ||
80 | // consider the redirection now | ||
81 | // it's just a part of normal command | ||
82 | // but not in other commands | ||
83 | redirect(cmd); | ||
84 | exit(execvp(cmd->args[0], cmd->args)); | ||
85 | } else { | ||
86 | if (!cmd->background) { | ||
87 | waitpid(pid, &status, 0); | ||
88 | if (!WIFEXITED(status)) { | ||
89 | if (WIFSIGNALED(status)) { | ||
90 | fprintf(stderr, "Process %d was killed by signal %d\n", | ||
91 | pid, WTERMSIG(status)); | ||
92 | } else { | ||
93 | fprintf(stderr, "Process %d exited with status %d\n", | ||
94 | pid, WEXITSTATUS(status)); | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | // return the exit status of the child process | ||
100 | return WEXITSTATUS(status); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | int runPipeCmd(Command *cmd) { | ||
105 | int status; | ||
106 | // create a pipe file and gets two file descriptors | ||
107 | // fd[0] is the read end, while fd[1] the write end | ||
108 | int fd[2]; | ||
109 | pid_t left, right; | ||
110 | pipe(fd); | ||
111 | if ((left = fork()) == 0) { | ||
112 | /* | ||
113 | * close the read end of the pipe, so that the child process | ||
114 | * can only write to it; then redirect the standard output | ||
115 | * to the write end of the pipe, and close the write end | ||
116 | * itself as a file descriptor. | ||
117 | */ | ||
118 | close(fd[0]); | ||
119 | dup2(fd[1], 1); | ||
120 | close(fd[1]); | ||
121 | exit(runCmd(cmd->left)); | ||
122 | } | ||
123 | if ((right = fork()) == 0) { | ||
124 | close(fd[1]); | ||
125 | dup2(fd[0], 0); | ||
126 | close(fd[0]); | ||
127 | exit(runCmd(cmd->right)); | ||
128 | } | ||
129 | // close the pipe, because the parent process doesn't need it | ||
130 | // and wait for the two child processes to exit | ||
131 | close(fd[0]); | ||
132 | close(fd[1]); | ||
133 | waitpid(left, NULL, 0); | ||
134 | waitpid(right, NULL, 0); | ||
135 | } | ||
136 | |||
137 | int runAndOrCmd(Command *cmd) { | ||
138 | int status; | ||
139 | if (cmd->type == CMD_AND) { | ||
140 | if (fork() == 0) { | ||
141 | exit(runCmd(cmd->left)); | ||
142 | } else { | ||
143 | waitpid(-1, &status, 0); | ||
144 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0 && fork() == 0) { | ||
145 | status = runCmd(cmd->right); | ||
146 | } | ||
147 | wait(NULL); | ||
148 | } | ||
149 | } else if (cmd->type == CMD_OR) { | ||
150 | if (fork() == 0) { | ||
151 | exit(runCmd(cmd->left)); | ||
152 | } else { | ||
153 | waitpid(-1, &status, 0); | ||
154 | if (WIFEXITED(status) && WEXITSTATUS(status) != 0 && fork() == 0) { | ||
155 | status = runCmd(cmd->right); | ||
156 | } | ||
157 | wait(NULL); | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | |||
162 | void redirect(Command *cur) { | ||
163 | int fd; | ||
164 | char *rfile; | ||
165 | for (int i = 0; i < 3; i++) { | ||
166 | fd = cur->redirectFD[i]; | ||
167 | rfile = cur->redirectFile[i]; | ||
168 | if (fd < -1 || fd > 2) { | ||
169 | fprintf(stderr, "file descriptor %d is invalid\n", fd); | ||
170 | exit(1); | ||
171 | } | ||
172 | if (fd == i && rfile == NULL) { | ||
173 | continue; | ||
174 | } | ||
175 | if (fd == -1) { | ||
176 | // append | ||
177 | fd = open(rfile, O_WRONLY | O_CREAT | O_APPEND, 0666); | ||
178 | } else if (rfile != NULL) { | ||
179 | // normal redirection | ||
180 | fd = open(rfile, O_WRONLY | O_CREAT | O_TRUNC, 0666); | ||
181 | } else { | ||
182 | // file descriptor redirection | ||
183 | // when here, fd is surely in 0, 1, 2 | ||
184 | ; | ||
185 | } | ||
186 | |||
187 | if (fd < 0) { | ||
188 | fprintf(stderr, "open file %s failed\n", rfile); | ||
189 | exit(1); | ||
190 | } | ||
191 | close(i); | ||
192 | dup2(fd, i); | ||
193 | close(fd); | ||
194 | } | ||
195 | } \ No newline at end of file | ||
@@ -30,16 +30,19 @@ typedef struct Command { | |||
30 | bool background; | 30 | bool background; |
31 | } Command; | 31 | } Command; |
32 | 32 | ||
33 | extern char hostname[100]; | ||
34 | extern char *username; | ||
35 | extern char pwd[100]; | ||
36 | |||
33 | void showPrompt(); | 37 | void showPrompt(); |
34 | Command *newCmd(); | 38 | void argInsert(struct Command *cmd, char *s, bool isStr); |
35 | 39 | ||
40 | Command *newCmd(); | ||
41 | void freeCmd(Command *cmd); | ||
36 | int runCmd(Command *cmd); | 42 | int runCmd(Command *cmd); |
37 | int runNormalCmd(Command *cmd); | 43 | int runNormalCmd(Command *cmd); |
38 | int runPipeCmd(Command *cmd); | 44 | int runPipeCmd(Command *cmd); |
39 | int runAndOrCmd(Command *cmd); | 45 | int runAndOrCmd(Command *cmd); |
40 | |||
41 | void freeCmd(Command *cmd); | ||
42 | |||
43 | void redirect(Command *cur); | 46 | void redirect(Command *cur); |
44 | 47 | ||
45 | #endif \ No newline at end of file | 48 | #endif \ No newline at end of file |
@@ -19,6 +19,7 @@ void yyerror(const char *s); | |||
19 | ">>" { return APPEND; } | 19 | ">>" { return APPEND; } |
20 | "&" { return BACKGROUND; } | 20 | "&" { return BACKGROUND; } |
21 | [0-2]">"&[0-2] { yylval.str = strdup(yytext); return FD_REDIRECT; } | 21 | [0-2]">"&[0-2] { yylval.str = strdup(yytext); return FD_REDIRECT; } |
22 | \"[^\"]*\" { yylval.str = strdup(yytext); return STRING; } | ||
22 | [a-zA-Z0-9_\-\/\*.]+ { yylval.str = strdup(yytext); return WORD; } | 23 | [a-zA-Z0-9_\-\/\*.]+ { yylval.str = strdup(yytext); return WORD; } |
23 | "(" { return LPAREN; } | 24 | "(" { return LPAREN; } |
24 | ")" { return RPAREN; } | 25 | ")" { return RPAREN; } |
diff --git a/ohoshell.sh b/ohoshell.sh index 341b5ad..f45f584 100644 --- a/ohoshell.sh +++ b/ohoshell.sh | |||
@@ -36,7 +36,7 @@ esac | |||
36 | flex -o lex.yy.c lex.l | 36 | flex -o lex.yy.c lex.l |
37 | bison -o syntax.tab.c -d -v syntax.y -Wcounterexamples | 37 | bison -o syntax.tab.c -d -v syntax.y -Wcounterexamples |
38 | 38 | ||
39 | $compiler -o bcsh bcsh.c syntax.tab.c -Wall \ | 39 | $compiler -o bcsh bcsh.c cmd.c syntax.tab.c -Wall \ |
40 | --target=$targetPlatform \ | 40 | --target=$targetPlatform \ |
41 | --sysroot=$native/sysroot \ | 41 | --sysroot=$native/sysroot \ |
42 | -march=$arch -mfloat-abi=softfp \ No newline at end of file | 42 | -march=$arch -mfloat-abi=softfp \ No newline at end of file |
@@ -2,6 +2,7 @@ | |||
2 | #include "cmd.h" | 2 | #include "cmd.h" |
3 | #include "lex.yy.c" | 3 | #include "lex.yy.c" |
4 | #include <stdio.h> | 4 | #include <stdio.h> |
5 | |||
5 | %} | 6 | %} |
6 | 7 | ||
7 | %union { | 8 | %union { |
@@ -65,16 +66,19 @@ separator: | |||
65 | part: | 66 | part: |
66 | part WORD { | 67 | part WORD { |
67 | $$ = $1; | 68 | $$ = $1; |
68 | $$->argc++; | 69 | argInsert($$, $2, false); |
69 | $$->args = realloc($$->args, ($$->argc + 1) * sizeof(char *)); | ||
70 | $$->args[$$->argc - 1] = $2; | ||
71 | $$->args[$$->argc] = NULL; | ||
72 | } | 70 | } |
73 | | WORD { | 71 | | WORD { |
74 | $$ = newCmd(); | 72 | $$ = newCmd(); |
75 | $$->args = malloc(2 * sizeof(char *)); | 73 | argInsert($$, $1, false); |
76 | $$->args[$$->argc++] = $1; | 74 | } |
77 | $$->args[$$->argc] = NULL; | 75 | | part STRING { |
76 | $$ = $1; | ||
77 | argInsert($$, $2, true); | ||
78 | } | ||
79 | | STRING { | ||
80 | $$ = newCmd(); | ||
81 | argInsert($$, $1, true); | ||
78 | } | 82 | } |
79 | | part REDIRECT_IN WORD { | 83 | | part REDIRECT_IN WORD { |
80 | $$ = $1; | 84 | $$ = $1; |
@@ -99,4 +103,4 @@ part: | |||
99 | } | 103 | } |
100 | ; | 104 | ; |
101 | 105 | ||
102 | %% | 106 | %% \ No newline at end of file |