hush.cpp (2117B)
1 #include <iostream> 2 #include <sstream> 3 #include <cstdlib> 4 #include <memory> 5 #include <vector> 6 #include <map> 7 #include <unistd.h> 8 #include <sys/wait.h> 9 #include <err.h> 10 11 using namespace std; 12 13 struct fifo 14 { 15 int read, write; 16 17 operator int*() 18 { 19 return &read; 20 } 21 }; 22 23 void show_clear_warn(char const* msg) 24 { 25 if (errno) 26 perror(msg); 27 errno = 0; 28 } 29 30 int cd(std::vector<char*> const& argv) 31 { 32 if (argv.size() < 2) 33 { 34 cerr << "cd: not enough arguments\n"; 35 return 1; 36 } 37 if (argv.size() > 2) 38 { 39 cerr << "cd: too many arguments\n"; 40 return 1; 41 } 42 int res = chdir(argv[1]); 43 show_clear_warn("cd"); 44 return res; 45 } 46 47 map<string, int(*)(std::vector<char*> const&)> intrinsics = { 48 {"cd", cd} 49 }; 50 51 auto pwd(void) 52 -> unique_ptr<char, void(*)(void*)> 53 { 54 return {getcwd(nullptr, 0), free}; 55 } 56 57 int main(int, char**) 58 { 59 string buf; 60 61 for (;;) 62 { 63 auto wd = pwd(); 64 65 cout << '[' << wd.get() << "] " << flush; 66 if (!getline(cin, buf)) 67 break; 68 69 istringstream ip(buf); 70 vector<string> pipelines; 71 72 while (getline(ip, buf, '|')) 73 pipelines.push_back(buf); 74 75 fifo f; 76 77 for (unsigned i = 0; i < pipelines.size(); ++i) 78 { 79 int in; 80 bool make_pipe = i+1 < pipelines.size(); 81 if (i) 82 in = f.read; 83 84 if (make_pipe) 85 pipe(f); 86 87 if (fork()) 88 { 89 if (make_pipe) 90 close(f.write); 91 if (i) 92 close(in); 93 94 continue; 95 } 96 97 if (make_pipe) 98 { 99 dup2(f.write, STDOUT_FILENO); 100 close(f.write); 101 } 102 103 if (i) 104 { 105 dup2(in, STDIN_FILENO); 106 close(in); 107 } 108 109 istringstream is(pipelines[i]); 110 vector<string> args; 111 while (is.peek() == ' ') 112 is.get(); 113 while (getline(is, buf, ' ')) 114 args.push_back(buf); 115 116 if (args.empty()) 117 err(1, "empty command?"); 118 119 120 string arg0 = args.front(); 121 std::vector<char*> argp; 122 for (auto& a : args) 123 { 124 a.push_back('\0'); 125 argp.push_back(a.data()); 126 } 127 128 if (intrinsics.contains(arg0)) 129 exit(intrinsics[arg0](argp)); 130 131 argp.push_back(nullptr); 132 execvp(argp[0], argp.data()); 133 err(66, argp[0]); 134 } 135 for (unsigned i = 0; i < pipelines.size(); ++i) 136 wait(NULL); 137 } 138 139 cout << "Done!\n"; 140 141 return EXIT_SUCCESS; 142 }