初次完成是程序,又蠢又长,还有bug,贴下来铭记要好好学习
/** * zsh.c : 简单的shell程序 * * created: zh * date: 2014.5.28~2014.6.8 * version1.0: first version * * *********************************************/
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <pwd.h>
#include <libgen.h>
#include <sys/types.h>
#include <readline/readline.h>
#include <readline/history.h>
int do_exit(int, char **);
int do_export(int, char **);
int do_echo(int, char **);
int do_cd(int, char **);
int do_history(int, char **);
void do_line(char *line);
void do_pipe_cmd(char *line);
int do_simple_cmd(int argc, char **argv, int prefd[], int postfd[]);
int isBgProgram(int len, char *line[10]);
char **arrayToPointer(int num, char *argv[10]);
int predo_for_redirect(int argc, char **argv, int *re);
char lastdir[100];
char **arg;
typedef int (*buildin_cmd_handle) (int, char **);
typedef struct {
const char *cmd;
buildin_cmd_handle handle;
} CMD_ENTRY;
const CMD_ENTRY buildin_cmd_table[] = {
{"exit", do_exit},
{"cd", do_cd},
{"echo", do_echo},
{"export", do_export},
{"history", do_history},
{0, 0}
};
void history_finish()
{
append_history(history_length, "/tmp/msh_history");
history_truncate_file("/tmp/msh_history", history_max_entries);
}
/** * 用于获取函数句柄 */
buildin_cmd_handle get_cmd_handle(const char *cmd)
{
int i = 0;
while (buildin_cmd_table[i].cmd) {
if (strcmp(buildin_cmd_table[i].cmd, cmd) == 0)
return buildin_cmd_table[i].handle;
i++;
}
return 0;
}
/** * 用于显示历史输入信息 */
void display_history_list()
{
HIST_ENTRY **h = history_list();
if (h) {
int i = 0;
while (h[i]) {
printf("%d: %s\n", i, h[i]->line);
i++;
}
}
}
/*** * 功能:执行exit命令,退出shell解释器 * 输入:argc:命令行字符串数目;argv:命令行字符串组 */
int do_exit(int argc, char **argv)
{
int val = 0;
if (argc > 1)
val = atoi(argv[1]);
//free_resource();
history_finish();
exit(val);
return 0;
}
/*** * 功能:执行cd命令,切换shell当前路径 * 输入:argc:命令行字符串数目;argv:命令行字符串组 */
int do_cd(int argc, char **argv)
{
char *dir;
char cwd[100];
if (argc == 1) {
if (!(dir = getenv("HOME"))) {
printf("cd: %s\n", strerror(errno));
return -1;
}
} else if (argc == 2) {
if (strcmp(argv[1], "-") == 0) {
dir = lastdir;
} else if (strcmp(argv[1], "~") == 0) {
if (!(dir = getenv("HOME"))) {
printf("cd: %s\n", strerror(errno));
return -1;
}
} else
dir = argv[1];
} else {
printf("Usage: cd [dir]\n");
return -1;
}
getcwd(cwd, 99);
if (chdir(dir) == -1) {
printf("cd: %s\n", strerror(errno));
return -1;
}
strcpy(lastdir, cwd);
return 0;
}
/*** * 功能:执行export命令,导入或显示环境变量 * 输入:argc:命令行字符串数目;argv:命令行字符串组 */
int do_export(int argc, char **argv)
{
int i = 1;
char *p;
while (argv[i]) {
if ((p = strchr(argv[i], '='))) {
*p = 0;
if (strpbrk(argv[i], "~`!@#$%^&*()-_+=|\\{}[];:'\"<>,.?/")) {
*p = '=';
printf("export: %s: not a valid indentifier\n", argv[i]);
i++;
continue;
}
if (setenv(argv[i], p + 1, 1) == -1)
printf("export: %s\n", strerror(errno));
*p = '=';
}
i++;
}
return 0;
}
/*** * 功能:执行echo命令,回显变量 * 输入:argc:命令行字符串数目;argv:命令行字符串组 */
int do_echo(int argc, char **argv)
{
int i = 1;
int j;
int argn = 0;
int arge = 0;
if (argv[1]) {
if (strcmp(argv[1], "-n") == 0) {
argn = 1;
i = 2;
} else if (strcmp(argv[1], "-e") == 0) {
arge = 1;
i = 2;
} else if ((strcmp(argv[1], "-ne") == 0)
|| (strcmp(argv[1], "-en") == 0)) {
argn = arge = 1;
i = 2;
}
}
j = i;
while (argv[i]) {
if (i > j)
printf(" %s", argv[i]);
else
printf("%s", argv[i]);
i++;
}
if (argn == 0)
printf("\n");
return 0;
}
/*** * 功能:执行history命令,显示历史信息 * 输入:argc:命令行字符串数目;argv:命令行字符串组 */
int do_history(int argc, char **argv)
{
display_history_list();
return 0;
}
/** * 设置shell命令提示符,可通过设置环境变量envprompt改变 */
void setShellPrompt(char *prompt)
{
char host[100];
char cwd[100];
struct passwd *pwp;
if (gethostname(host, 99) == -1) {
strcpy(host, "unknown");
} else {
char *p = strchr(host, '.');
if (p)
*p = 0;
}
if (!getcwd(cwd, 99)) {
strcpy(cwd, "unknown");
} else {
if (strcmp(cwd, "/") != 0)
strcpy(cwd, basename(cwd));
}
pwp = getpwuid(getuid());
sprintf(prompt, "[%s@%s %s]# ", (pwp ? pwp->pw_name : "unknown"), host,
cwd);
}
/** * 释放程序中申请的内存 */
void free_source(int num, char **name)
{
int n;
for (n = 0; n < num; n++) {
free(name[n]);
name[n] = 0;
}
}
int main(int argc, char **argv)
{
char prompt[200];
setShellPrompt(prompt);
//signal(SIGINT,SIG_IGN);
char *line; //char line[300];//
line = malloc(200);
memset(line, 0, 200);
char *env;
env = malloc(strlen(prompt) + 11);
strcpy(env, "envprompt=");
strcat(env, prompt);
putenv(env);
char *tmpline;
tmpline = malloc(strlen(prompt));
while (1) {
tmpline = getenv("envprompt");
if (!(line = readline(tmpline))) {
break;
}
if (*line) {
add_history(line);
}
//printf("%s + %d\n",line, strlen(line));
do_line(line);
putenv(line);
}
free(env);
env = NULL;
free(tmpline);
tmpline = NULL;
free(line);
line = NULL;
return 0;
}
/** * 功能:解析输入命令,并按";"解析命令,并传入到函数do_pipe_cmd() * 输入:原始命令行 */
void do_line(char *line)
{
int len, i, j = 0, k = 0;
char *argv[20];
int m = 0;
len = strlen(line);
//printf("---%s---||---%d---\n",line,len);
for (i = 0; i <= len; i++) {
if (line[i] == ';') {
if ((argv[k] = (char *) malloc((i - j) * sizeof(char))) == 0) {
fprintf(stderr, "error! can't malloc space for argv\n");
} else {
memset(argv[k], 0, (i - j) * sizeof(char));
for (m = 0; m < i - j; m++) {
argv[k][m] = line[j + m];
}
argv[k][m] = '\0';
//printf("---%s---\n",argv[k]);
do_pipe_cmd(argv[k]);
j = i + 1;
k++;
}
} else if (line[i] == '\n' || (i == len && i != 0)) {
if ((argv[k] = (char *) malloc((i - j) * sizeof(char))) == 0) {
fprintf(stderr, "error! can't malloc space for argv\n");
} else {
memset(argv[k], 0, (i - j) * sizeof(char));
//printf("(i - j) * sizeof(char) is %d\n",(i - j) * sizeof(char));
//printf("---%s---%d---%d---\n",argv[k],m,strlen(argv[k]));
for (m = 0; m < i - j; m++) {
argv[k][m] = line[j + m];
}
argv[k][m] = '\0';
//printf("---%s---%d---%d---\n",argv[k],m,strlen(argv[k]));
do_pipe_cmd(argv[k]);
j = i;
k++;
}
}
}
free_source(k - 1, argv);
}
/** * 功能:解析输入命令,并按"|"解析简单命令,并传入到函数do_simple_cmd() * 输入:函数do_line()解析后的简单命令 */
void do_pipe_cmd(char *line)
{
//printf("the line in pipe_cmd is %s\n",line);
int len, i, j = 0, k = 0;
char *argv[20];
int m;
len = strlen(line);
int prepipe = 0;
int prefd[2];
int postfd[2];
char *args[10];
int num = 0;
for (i = 0; i <= len; i++) {
if (line[i] == '|') {
if ((argv[k] = (char *) malloc((i - j) * sizeof(char))) == 0) {
fprintf(stderr, "error! can't malloc space for argv\n");
} else {
memset(argv[k], 0, (i - j) * sizeof(char));
for (m = 0; m < i - j; m++) {
argv[k][m] = line[j + m];
}
argv[k][m] = '\0';
num = add_arg(argv[k], args);
j = i + 1;
k++;
pipe(postfd);
if (prepipe)
do_simple_cmd(num, arrayToPointer(num, args), prefd,
postfd);
else
do_simple_cmd(num, arrayToPointer(num, args), 0,
postfd);
prepipe = 1;
prefd[0] = postfd[0];
prefd[1] = postfd[1];
}
} else if (i == len && i != 0) {
if ((argv[k] = (char *) malloc((i - j) * sizeof(char))) == 0) {
fprintf(stderr, "error! can't malloc space for argv\n");
} else {
memset(argv[k], 0, (i - j) * sizeof(char));
for (m = 0; m < i - j; m++) {
argv[k][m] = line[j + m];
}
argv[k][m] = '\0';
num = add_arg(argv[k], args);
j = i;
k++;
pipe(postfd);
if (prepipe) {
do_simple_cmd(num, arrayToPointer(num, args), prefd,
postfd);
} else {
do_simple_cmd(num, arrayToPointer(num, args), 0, 0);
}
}
}
}
free_source(k - 1, argv);
free_source(k - 1, args);
free_source(num, arg);
}
/** * 功能:执行简单命令 * 输入:argc:命令行字符串数目;argv:命令行字符串组 * prefd,postfd:管道参数 */
int do_simple_cmd(int argc, char **argv, int prefd[], int postfd[])
{
int pid;
int status;
buildin_cmd_handle hd;
if (argc == 0)
return 0;
if (prefd == 0 && postfd == 0) {
if ((hd = get_cmd_handle(argv[0]))) {
if (predo_for_redirect(argc, argv, 0))
return 1;
(*hd) (argc, argv);
return 0;
}
}
if ((pid = fork()) == 0) { //子进程
// 重置signal INT handle为默认
int redirect = 0;
signal(SIGINT, SIG_DFL);
if (predo_for_redirect(argc, argv, &redirect))
exit(1);
if (redirect != 1 && prefd) {
close(prefd[1]);
if (prefd[0] != STDIN_FILENO) {
dup2(prefd[0], STDIN_FILENO);
close(prefd[0]);
}
}
if (redirect != 2 && postfd) {
close(postfd[0]);
if (postfd[1] != STDOUT_FILENO) {
dup2(postfd[1], STDOUT_FILENO);
close(postfd[1]);
}
}
if ((hd = get_cmd_handle(argv[0]))) {
(*hd) (argc, argv);
exit(0);
}
char buffer[100];
if (file_exist(argv[0], buffer)) {
execv(buffer, argv);
} else {
fprintf(stderr, "-zsh: %s: command not found\n", argv[0]);
exit(0);
}
} else if (pid < 0) {
} else {
if (isBgProgram(argc, argv) == 0) {
//printf("this is not bg\n");
waitpid(pid, &status, 0);
}
}
if (postfd) {
close(postfd[1]); // 关闭这个fd.
}
return 0;
}
/** * 将指针数组转换为二维指针,恕我学识浅薄,尚不明白为何一定要这样, * 只是这样才能通过编译....容我再学习 */
char **arrayToPointer(int num, char *argv[10])
{
arg = (char **) malloc((num) * sizeof(char *));
memset(arg,0, (num)*sizeof(char *));
int p = 0;
for (p = 0; p < num && num < 10; p++) {
arg[p] = argv[p];
}
return arg;
}
/** * 功能:判断简单命令是否需要后台运行,通过“&”判别 */
int isBgProgram(int len, char **line)
{
if (strcmp(line[len - 1], "&") == 0) {
line[len - 1] = "\0";
return 1;
}
return 0;
}
/** * 功能:将简单命令(字符串)转换为字符串数组,数组每个元素即为一个标记 */
int add_arg(char *line, char *args[10])
{
int len, i, j = 0, k = 0;
//char *args[10];
len = strlen(line);
int m = 0;
char *newline;
if ((newline = (char *) malloc(len * sizeof(char))) == 0) {
fprintf(stderr, "error! can't malloc space for argv\n");
}
for (i = 0; i <= len;) {
if (line[i] == ' ' && line[i + 1] == ' ' || line[i] == '\t')
i++;
else {
newline[j] = line[i];
j++;
i++;
}
}
i = 0;
while (newline[i] == ' ' || newline[i] == '\t')
i++;
j = i; //重新置为零
for (; i <= len; i++) {
if (newline[i] == ' ') {
if ((args[k] = (char *) malloc((i - j) * sizeof(char))) == 0) {
fprintf(stderr, "error! can't malloc space for argv\n");
} else {
memset(args[k], 0, (i - j) * sizeof(char));
for (m = 0; m < i - j; m++) {
args[k][m] = newline[j + m];
}
args[k][m] = '\0';
j = i + 1;
k++;
}
} else if (i == len) {
if ((args[k] = (char *) malloc((i - j) * sizeof(char))) == 0) {
fprintf(stderr, "error! can't malloc space for argv\n");
} else {
for (m = 0; m < i - j; m++) {
args[k][m] = newline[j + m];
}
args[k][m] = '\0';
j = i;
k++;
}
}
}
return k;
}
/** * 功能:判断文件是否存在 */
int file_exist(const char *file, char *buffer)
{
int i = 0;
const char *p;
const char *path = getenv("PATH");
p = path;
while (*p != 0) {
if (*p != ':')
buffer[i++] = *p;
else {
buffer[i++] = '/';
buffer[i] = 0;
strcat(buffer, file);
if (access(buffer, F_OK) == 0)
return 1;
i = 0;
}
p++;
}
const char *p2 = getenv("PWD");
p = p2;
i = 0;
while (*p != 0) {
buffer[i++] = *p;
p++;
}
buffer[i++] = '/';
buffer[i] = 0;
strcat(buffer, file);
if (access(buffer, F_OK) == 0)
return 1;
return 0;
}
/** * 功能:完成重定向功能 */
int predo_for_redirect(int argc, char **argv, int *re)
{
int i;
int redirect = 0;
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "<") == 0) {
redirect = 1;
argv[i] = 0;
break;
} else if (strcmp(argv[i], ">") == 0) {
redirect = 2;
argv[i] = 0;
break;
}
}
if (redirect) {
if (argv[i + 1]) {
int fd;
if (redirect == 2) {
if ((fd =
open(argv[i + 1], O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR)) == -1) {
fprintf(stderr, "Open out %s failed\n", argv[i + 1]);
return 1;
}
dup2(fd, STDOUT_FILENO);
} else { //redirect == 1
if ((fd =
open(argv[i + 1], O_RDONLY,
S_IRUSR | S_IWUSR)) == -1) {
fprintf(stderr, "Open in %s failed\n", argv[i + 1]);
return 1;
}
dup2(fd, STDIN_FILENO);
}
} else {
fprintf(stderr, "Bad redirect, need more arg\n");
return 1;
}
}
if (re)
*re = redirect;
return 0;
}