📄 ush.c
字号:
#include "ush.h"#include "ush-env.h"#include "ush-parse.h"#include "ush-prt.h"#include "ush-sig.h"#include "errno.h"#define MAXARG 20#define MAXFNAME 500#define MAXWORD 100#define BADFD -2static char* completeDir(char* path);static int invoke(int argc, char *argv[], int srcfd, char *srcfile,int dstfd, char *dstfile, BOOLEAN append,BOOLEAN bckgrnd);static void redirect(int srcfd, char *srcfile, int dstfd, char *dstfile,BOOLEAN append, BOOLEAN bckgrnd);static void waitfor(int pid);static BOOLEAN builtin(int argc, char *argv[], int srcfd, int dstfd);/////////////////////////////////////////////////////////////////// you should better not modify this function ///////////////////////////////////////////////////////////////////int main(){ /* real shell */ char *prompt; int pid, fd; TOKEN term; static TOKEN command(); static void waitfor(); ignoresig(); if (!EVinit()) fatal("can't initialize environment"); if ((prompt = EVget("PS2")) == NULL) prompt = ">"; printf("%s", prompt); while (1) { term = command(&pid, FALSE, NULL); if (term != T_AMP && pid != 0) waitfor(pid); if (term == T_NL) printf("%s", prompt); for (fd = 3; fd < 20; fd++) (void) close(fd); /* ignore error */ } return (0);}static TOKEN command(int *waitpid, BOOLEAN makepipe, int *pipefdp){ /* do simple cmd */ TOKEN token, term; int argc, srcfd, dstfd, pid, pfd[2],fd; char *argv[MAXARG + 1], srcfile[MAXFNAME], dstfile[MAXFNAME]; char word[MAXWORD], *malloc(); BOOLEAN append; argc = 0; srcfd = 0; dstfd = 1; while (1) { switch (token = gettoken(word)) { case T_WORD: if (argc == MAXARG) { fprintf(stderr, "Too many args\n"); break; } if ((argv[argc] = malloc(strlen(word) + 1)) == NULL) { fprintf(stderr, "Out of argmemory\n"); break; } strcpy(argv[argc], word); argc++; continue; case T_LT: if (makepipe) { fprintf(stderr, "Extra<\n"); break; } if (gettoken(srcfile) != T_WORD) { fprintf(stderr, "Illegal <\n"); break; } //将重定向的fd读入,若是std I/O,则赋为BADFD if((fd=atoi(word))!=0) srcfd = fd; else srcfd = BADFD; continue; case T_GT: if (dstfd != 1) { fprintf(stderr, "Extra > or >> \n"); break; } if (gettoken(dstfile) != T_WORD) { fprintf(stderr, "Illegal > or >> \n"); break; } //将重定向的fd读入,若是std I/O,则赋为BADFD if((fd=atoi(word))!=0) dstfd = fd; else dstfd = BADFD; append = FALSE; continue; case T_GTGT: if (dstfd != 1) { fprintf(stderr, "Extra > or >>\n"); break; } if (gettoken(dstfile) != T_WORD) { fprintf(stderr, "Illegal >or >>\n"); break; } //将重定向的fd读入,若是std I/O,则赋为BADFD if((fd=atoi(word))!=0) dstfd = fd; else dstfd = BADFD; append = TRUE; continue; case T_BAR: case T_AMP: case T_SEMI: case T_NL: argv[argc] = NULL; if (token == T_BAR) { if (dstfd != 1) { fprintf(stderr, "> or >> conflicts with |\n"); break; } term = command(waitpid, TRUE, &dstfd); } else term = token; if (makepipe) { if (pipe(pfd) == -1) syserr("pipe"); *pipefdp = pfd[1]; srcfd = pfd[0]; } //处理$name的情况,将所有$开头的参数替换为同名环境变量的值 EVsubstitute(argc,argv); if (term == T_AMP) pid = invoke(argc, argv, srcfd,srcfile, dstfd, dstfile, append, TRUE); else pid = invoke(argc, argv, srcfd, srcfile, dstfd, dstfile,append, FALSE); if (token != T_BAR) *waitpid = pid; if (argc == 0 && (token != T_NL || srcfd > 1)) fprintf(stderr, "Missing command\n"); while (--argc >= 0) free(argv[argc]); return (term); case T_EOF: exit(0); } }}//////////////////////////////////////////////////////////// You must implement the invoke function //// return the process id ///////////////////////////////////////////////////////////static int invoke(int argc, char *argv[], int srcfd, char *srcfile, int dstfd, char *dstfile, BOOLEAN append, BOOLEAN bckgrnd) /* invoke simple command */{ if (argc == 0) return 0; if(!builtin(argc,argv,srcfd,dstfd)) { pid_t pid; if ((pid = fork())<0) { syserror("fork failed."); } else if (pid == 0) { // 子进程,调用execvp. // 如果需要重定向则调用重定向的方法 if(srcfd!=0||dstfd!=1) redirect(srcfd,srcfile,dstfd,dstfile,append,bckgrnd); if((execvp(completeDir(argv[0]),argv))<0) { syserror("execvp failed."); } } else { // 父进程,只需返回pid,因为waitpid已经在main()中实现 return pid; } } else return 0; return 0;}//////////////////////////////////////////////////////////// You must implement the redirect function ///////////////////////////////////////////////////////////static void redirect(int srcfd, char *srcfile, int dstfd, char *dstfile, BOOLEAN append, BOOLEAN bckgrnd){ /* I/O redirection */ int fd; // 输入重定向 if(srcfd!=0) { fd = open(completeDir(srcfile),O_RDONLY|O_CREAT,0777); if(fd>0) if(srcfd<0) dup2(fd,STDIN_FILENO); else dup2(fd,srcfd); else syserror("Open input file failed"); } // 输出重定向 if(dstfd!=1) { if(append) fd = open(completeDir(dstfile),O_WRONLY|O_CREAT|O_APPEND,0777); else fd = open(completeDir(dstfile),O_WRONLY|O_CREAT|O_TRUNC,0777); if(fd>0) if(dstfd<0) dup2(fd,STDOUT_FILENO); else dup2(fd,dstfd); else syserror("Open output file failed"); }}static void waitfor(int pid){ /* wait for child */ int wpid, status; while ((wpid = wait(&status)) != pid && wpid != -1) statusprt(wpid, status); if (wpid == pid) statusprt(0, status);}//////////////////////////////////////////////////////////// You must implement the builtin function to do //// the builtin command. //// Note :: the builtin command should not invoke the linux standard //// function.eg, cd should not invoke chdir //// return true if a builtin command ,false other wise ////////////////////////////////////////////////////////////static BOOLEAN builtin(int argc, char *argv[], int srcfd, int dstfd) /* do built-in */{ char pwd[4] = "PWD"; int i,isPath; char* dir; DIR *testDir; if (!strcmp(argv[0],"cd")) { // 如果只有cd,没有参数,则默认为HOME的目录。 if(argc==1) { dir = EVget("HOME"); EVset("PWD",dir); } else { if(strcmp(argv[1],"..")) { dir = completeDir(argv[1]); if(opendir(dir)!=NULL) EVset("PWD",dir); else syserror("cd command failed"); } else { dir = EVget("PWD"); isPath = 0; for(i = strlen(dir); i>0; i--) { if(dir[i]=='/') break; } if(i!=0) dir[i] = '\0'; else dir = "/\0"; if(opendir(dir)!=NULL) EVset("PWD",dir); else syserror("cd command failed"); } } return TRUE; } else if (!strcmp(argv[0],"echo")) { for( i = 1; i < argc; i++) { printf("%s ", argv[i]); } printf("\n"); return TRUE; } else if (!strcmp(argv[0],"exit")) { exit(0); } else if (!strcmp(argv[0],"export")) { export(argc, argv); return TRUE; } else if (!strcmp(argv[0],"pwd")) { printf("%s\n",EVget(pwd)); return TRUE; } else if (!strcmp(argv[0],"set")) { set(argc,argv); return TRUE; } else if (!strcmp(argv[0],"unset")) { unset(argc,argv); return TRUE; } else if (strchr(argv[0], '=')) { asg(argc, argv); return TRUE; } return FALSE;}// 将相对路径根据pwd的值转化为绝对路径(cd的实现需要)static char* completeDir(char* path){ char* comPath; char* cd; int totalLength; if(path[0]=='/') return path; // 绝对路径,不需要转换。 else { cd = EVget("PWD"); totalLength = strlen(path) + strlen(cd); // pwd + 相对路径 = 绝对路径 comPath = malloc(totalLength); strcpy(comPath,cd); strcat(comPath,"/"); strcat(comPath,path); return comPath; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -