examples

Toy examples in single C files.
git clone git://henryandlizzy.uk/examples
Log | Files | Refs

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 }