📄 shell.cpp
字号:
// Shell.cpp: implementation of the Shell class.////////////////////////////////////////////////////////////////////////#include "Shell.h"#include "mystring.h"#include "synchro.h"#include <iostream>#include <iomanip>#include <string.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <dirent.h>#include <sys/types.h>#include <sys/stat.h>#include <fnmatch.h>#include <pwd.h>#include <sys/wait.h>#include <fcntl.h>#include <signal.h>using namespace std;static bool showStringArrayFlag = true; //if more over, the sig_more_over is be called, and sig_more_over will set //showStringArrayFlag flase. then showStringArray will stop writing pipestatic void sig_more_over(int); //the is a function that is called when a SIGPIPE signal is sended by os void sig_more_over(int signo) { if(signo == SIGPIPE); showStringArrayFlag = false;}void showStringArray(char** buf);void showStringArrayWithMore(char** buf);void showStringArray(char** buf){ if(!buf) return; showStringArrayFlag = true; char** temp = buf; int i = 0; cout.setf(ios::left, ios::adjustfield); while(*temp) { if(showStringArrayFlag) { cout<<setw(40)<<(*temp); if((++i)%3 == 0) cout<<endl; temp++; } else break; } cout.unsetf(ios::left); cout<<endl;}void showStringArrayWithMore(char** buf){ int pid[2]; int fid; while ( 0 != pipe(pid)); while(-1 == (fid = fork())); if(fid > 0) { int save = close(1); dup(pid[1]); close(pid[0]); signal(SIGPIPE, sig_more_over); showStringArray(buf); close(1); dup(save); close(pid[1]); wait(0); } else { close(pid[1]); close(0); dup(pid[0]); execl("/bin/more", "/bin/more", 0); //if more is invalid , I'll call less. if less is invalid. execl("/usr/bin/less", "/usr/bin/less", 0); }}//the special character string of loverconst char* Shell::spechar = "*?[-]!\\;'\"|&>";//flag for search file//ALL: all file //DIR_: directory file//NORMALFILE: all file expect directory file const int DIR_ = 4; const int NORMALFILE = 8;const int ALL = 0; static process_node* head = 0; //the head point of the process list.static process_node* tail = 0; //the tail point of the process liststatic process_node* cur = 0; //the current point of the process listvoid sig_chld(int signo){ if(signo == SIGCHLD && head) { int status; int pid; pid = wait(&status); cur = head; while(cur->pro.id != pid ) cur = cur->next; if(cur->pipe_read >= 0 && cur->readFlag) close(cur->pipe_read); if(cur->pipe_write >= 0 && cur->writeFlag) close(cur->pipe_write); process_node* temp; process_node* temp1; temp = head; while(temp != cur) { if(temp->pipe_read >= 0 && temp->readFlag) close(cur->pipe_read); if(temp->pipe_write >= 0 && temp->writeFlag) close(temp->pipe_write); temp1 = temp; temp = temp->next; delete temp1; } head = cur->next; if(cur->next == 0) { delete cur; cur = tail = head = 0; } }}Shell::Shell () { input = 0; command = 0; num_process_background = 0; struct passwd* p; p = getpwuid(getuid()); name_user = new char[strlen(p->pw_name) + 1]; strcpy(name_user,p->pw_name) ; path_userhome = new char[strlen(p->pw_dir)+2]; strcpy(path_userhome,p->pw_dir); strcat(path_userhome,"/"); //get the current work directory //getcwd() need a buffer and its size //If the size is not bigger than the length of the dirctory //It return zero //so I must test the length int i = 1; path_cur = (char*)malloc(64*i); while(!getcwd(path_cur,64*i)) { path_cur = (char*)realloc(path_cur,++i*(64)); } path_cur = (char*)realloc(path_cur,strlen(path_cur)+2); strcat(path_cur,"/"); if(chdir(path_cur)) { cerr<<"Lover: beyond retrieve error! can't enter the user current directory"<<endl; exit(1); } if(path_cur[0] == '/' && path_cur[1] == 0) { path_cur_last[0] = path_cur_last[1] = '/'; path_cur_last[2] = 0; } else { for(i = strlen(path_cur) - 2; i >= 0 && path_cur[i] != '/'; i--){}; strcpy(path_cur_last,path_cur + i + 1); } char* work = new char[strlen("/bin/lover/") + strlen(name_user) + 1]; strcpy(work, "/bin/lover/"); strcat(work,name_user); int fid; if((fid = open(work,O_RDONLY|O_CREAT)) >= 0) { char a; read(fid,&a,1); tipchar = a; close(fid); } else { if(0==getuid()) tipchar = '#';//the default tip char of root user is '#' else tipchar = '$';//the default tip char of normal is '$' } PATH.overffile(work); delete work; work = new char[strlen("/bin/lover/") + strlen(name_user) + strlen("commandbuf") + 1]; strcpy(work, "/bin/lover/"); strcat(work, name_user); strcat(work, "commandbuf"); commandbuf.initffile(work); //init commandbuf from the file delete work; save = new struct termios[sizeof(struct termios)]; ioctl(0,TCGETS,save); TELL_WAIT(); if(!isSynchroAble()) { cerr<<"lover: beyond retrieve error! signal system error"<<endl; exit(1); } setnonor(); signal(SIGCHLD, sig_chld);}//no overShell::~Shell () { char* work = new char[strlen("/bin/lover/")+strlen(name_user) + 1]; strcpy(work,"/bin/lover/"); strcat(work,name_user); int fid = open(work,O_WRONLY|O_TRUNC|O_CREAT); if(fid >= 0) { write(fid,&tipchar,1); write(fid,"\n",1); PATH.show(fid); close(fid); } delete work; fresh();}//read from stdinvoid Shell::getinput_stdin(void){ show(); int size,i; char* work; char a; input = 0; do { a = scanf_(this->input,size,false); if(a == KEYDOWN) { work = commandbuf.getCur(); commandbuf.devCur(); if(work != 0) { delete input; input = new char[strlen(work) + 1]; strcpy(input,work); delete work; cursormove(KEYLEFT,size); for(i = 0; i < size; i++) write(1," ",1); cursormove(KEYLEFT,size); cout<<input<<flush; } } else if(a == KEYUP) { work = commandbuf.getCur(); commandbuf.incCur(); if(work != 0) { delete input; input = new char[strlen(work) + 1]; strcpy(input, work); delete work; cursormove(KEYLEFT,size); for(i = 0; i < size; i++) write(1," ",1); cursormove(KEYLEFT,size); cout<<input<<flush; } } else if(a == '\t')//tab key { char** command_block; int num_block; char echo; blockchar(input, command_block, num_block); if(num_block == 0) { echo = scanf_(input); if(echo == '\t') { List<char>* all = findAllExecFile("*"); if(all) { int num = all->getNum(); cout<<endl<<"Display all "<<num<<" posibilitees (y or n)"<<flush; setnoecho(); setnonor(); do { echo = getch_(); }while(echo != 'n' && echo != 'N' && echo != 'y' && echo != 'Y'); if(echo == 'y' || echo == 'Y') { char** buf = all->getbuf_subdir(); showStringArrayWithMore(buf); free__(buf); } cout<<endl; return; } } else a = '\n'; } else { char* work = new char[strlen(command_block[num_block - 1]) + 2]; strcpy(work, command_block[num_block - 1]); strcat(work, "*"); free__(command_block, num_block); List<char>* o; if(num_block == 1) o = findAllExecFile(work); else o = findAll(work, ALL, true); if(o && !(o->isempty())) { char* show = o ->getEqu(); if(show) { char* work_last = find_dirlast(work); char* show_last = find_dirlast(show); int len_s = strlen(show_last); int len_w = strlen(work_last) - 1; if(len_s > len_w) { cursormove(KEYLEFT, len_w); cout<<show_last<<flush;//write(1, show_last, len_s); size += len_s - len_w; int size_old = strlen(input); input = (char*)realloc(input, size + 1); strcpy(input + size_old - len_w, show_last); } else { char* temp = new char[strlen(input) + 1]; strcpy(temp, input); char a = scanf_(input, size, false); if(strcmp(temp, input) == 0 && a == '\t') { cout<<endl; int num = o->getNum(); if(num < 100) { char** buf = o->getbuf_subdir(); showStringArray(buf); } else { cout<<endl<<"Display all "<<num<<" posibilitees (y or n)"<<flush; setnoecho(); setnonor(); do { echo = getch_(); }while(echo != 'n' && echo != 'N' && echo != 'y' && echo != 'Y'); if(echo == 'y' || echo == 'Y') { char** buf = o->getbuf_subdir(); showStringArrayWithMore(buf); } } this->show(); cout<<input<<flush;//write(1,input, strlen(input)); } } } } } } }while(a == KEYDOWN || a == KEYUP || a == '\t'); puts(""); cursormove(KEYLEFT,size); if(input) if(strlen(input)) commandbuf.inset(input);}//read from filevoid Shell::getinput_file(void){ cout<<endl; input = command_file.getCur(); while(input[0] == '#') { delete input; input = command_file.getCur(); }}void Shell::load(int fid){ command_file.overffile(fid); command_file.inset("exit", -1); //inset the exit command in the tail command_file.reset();}bool Shell::getcommand(void){ //the start of input to process.-1 only i = 0 for next input and return false static int i = 0; if(i < 0) { i = 0; return false; } int start = i; bool blockflag = (input[i] == '\'')?false:true; delete command; while(1) { if(input[i] == 0 || (input[i] == ';' && input[i-1] != TRAN_ABLE && blockflag)) { command = new char[i-start + 1]; strncpy(command,input+start,i - start); command[i-start] = 0; //the last command //i = -1 to control the next call to return false if(input[i] == 0) i = -1; else { i++; while(input[i] != 0 && (input[i] == ' ' || input[i] == '\t')){i++;}; if(input[i] == 0) i = -1; } return true; } if(input[i] == '\'' && (i == 0 || input[i-1] != TRAN_ABLE )) blockflag = !blockflag; i++; }}void Shell::command_anslyse(void){ tranable(command);}//return value //0: is a normal lvoer command and execute it//1: not a lover command//2: exit command//-1: command_block is no validint Shell::command_lover(char** command_block, int num_block){ if(num_block > 0) { char* work; if(strcmp(command_block[0],"pwd") == 0) { _pwd(); return 0; } else if(strcmp(command_block[0],"cd") == 0) { if(num_block==1)//user only input "cd". enter the user's home diretory _cd(this->path_userhome); else { work = findFirst(command_block[1],DIR_); if(!work) cout<<"lover: cd: "<<command_block[1]<<": no the directory"<<endl; else { _cd(work); delete work; } } return 0; } else if(strcmp(command_block[0],"path")==0) { if(num_block == 1) PATH.show(); else { int i; for(i = 1; i < num_block; i++) { if(strcmp(command_block[i],"-a") == 0) { for(int j = i+1; j < num_block && command_block[j][0] != '-'; j++) { work = findFirst(command_block[j],DIR_); if(work) { addPath(work); delete work; } } } if(strcmp(command_block[i],"-s") == 0) { for(int j = i+1; j < num_block && command_block[j][0] != '-'; j++) { work = findFirst(command_block[j],DIR_); if(work)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -