root/lang/c/misc/shell.hpp @ 39024

Revision 3456, 7.5 kB (checked in by klm, 6 years ago)

lang/c/misc/shell.cpp, lang/c/misc/shell.hpp: imported (UN*X shell-like I/O for C++)

  • Property svn:keywords set to Id
Line 
1/**
2    UNIX shell-like I/O for C++
3    $Id$
4*/
5#include <vector>
6#include <string>
7#include <iostream>
8#include <fstream>
9#include <sstream>
10#include <algorithm>
11#include <functional>
12
13namespace shell {
14    class cmd {
15    public:
16        typedef int (*basic_cmd_fn)(const std::vector<std::string>&, std::istream&, std::ostream&);
17    private:
18        bool done_;
19    public:
20        cmd() : done_(false) {}
21        virtual ~cmd() {}
22        void destroy() {
23            if (!done_)
24                run();
25            destroy_impl();
26        }
27        int run() {
28            done_ = true;
29            return run_impl();
30        }
31        virtual int run_impl() =0;
32        virtual void destroy_impl() {}
33        virtual void set_istream(std::istream*, bool =false) =0;
34        virtual void set_ostream(std::ostream*, bool =false) =0;
35    };
36
37    class basic_cmd : public cmd {
38    private:
39        basic_cmd_fn fptr_; // C++ function representing the command
40        std::vector<std::string> arg_;
41        std::istream* in_;
42        std::ostream* out_;
43        bool destruct_in_, destruct_out_; // be true if the in_/out_ should be destructed by the object
44    public:
45        basic_cmd(basic_cmd_fn fptr, const std::vector<std::string>& arg)
46            : cmd(), fptr_(fptr), arg_(arg), in_(&std::cin), out_(&std::cout),
47              destruct_in_(false), destruct_out_(false) {}
48
49        virtual ~basic_cmd() { destroy(); }
50        void destroy_impl() {
51            if (destruct_in_) delete in_;
52            if (destruct_out_) delete out_;
53        }
54        int run_impl() {
55            return fptr_(arg_, *in_, *out_);
56        }
57        void set_istream(std::istream* in, bool destruct =false) {
58            in_ = in;
59            destruct_in_ = destruct;
60        }
61        void set_ostream(std::ostream* out, bool destruct =false) {
62            out_ = out;
63            destruct_out_ = destruct;
64        }
65    };
66
67    // smart_ptr/auto_ptr-like command holder
68    class cmd_holder {
69    private:
70        cmd* p_;
71        int* refc_; // reference count
72        cmd_holder& operator=(const cmd_holder&); // purposely not implemented (MUST NOT COPY)
73    public:
74        cmd_holder(cmd* p) : p_(p), refc_(new int(1)) {}
75        cmd_holder(const cmd_holder& c) : p_(c.p_), refc_(c.refc_) { (*refc_)++; }
76        ~cmd_holder() {
77            if (--(*refc_) == 0) {
78                delete p_;
79                delete refc_;
80            }
81        }
82        cmd* operator->() const { return p_; }
83    };
84   
85    cmd_holder operator<(cmd_holder lhs, const char* filename) {
86        lhs->set_istream(new std::ifstream(filename), true);
87        return lhs;
88    }
89    cmd_holder operator>(cmd_holder lhs, const char* filename) {
90        lhs->set_ostream(new std::ofstream(filename), true);
91        return lhs;
92    }
93    cmd_holder operator>>(cmd_holder lhs, const char* filename) {
94        lhs->set_ostream(new std::ofstream(filename, std::ios_base::out | std::ios_base::app), true);
95        return lhs;
96    }
97
98    // (command1 | command2) as an abstract command
99    class piped_cmd : public cmd {
100    private:
101        cmd_holder lhs_, rhs_;
102    public:
103        piped_cmd(cmd_holder& lhs, cmd_holder& rhs) : cmd(), lhs_(lhs), rhs_(rhs) {}
104        virtual ~piped_cmd() { destroy(); }
105
106        int run_impl() {
107            std::stringstream s; // buffer for communications
108            lhs_->set_ostream(&s);
109            rhs_->set_istream(&s);
110            int ret1 = lhs_->run();
111            int ret2 = rhs_->run();
112            return ret1 | ret2;
113        }
114        void set_istream(std::istream* in, bool =false) {
115            lhs_->set_istream(in);
116        }
117        void set_ostream(std::ostream* out, bool =false) {
118            rhs_->set_ostream(out);
119        }
120    };
121
122    // operator overloading
123    cmd_holder operator|(cmd_holder lhs, cmd_holder rhs) {
124        return cmd_holder( new piped_cmd(lhs, rhs) );
125    }
126
127    // for enabling destructor-call
128    class basic_cmd_gen
129    {
130    private:
131        basic_cmd::basic_cmd_fn fptr_;
132    public:
133        basic_cmd_gen(basic_cmd::basic_cmd_fn fptr) : fptr_(fptr) {}
134        // hack for omitting ()
135        operator cmd_holder() const { return (*this)(); }
136        // TODO: >3-arguments
137        cmd_holder operator() (const std::vector<std::string>& arg) const {
138            return cmd_holder( new basic_cmd(fptr_, arg) );
139        }
140        cmd_holder operator()() const {
141            std::vector<std::string> v;
142            return (*this)(v);
143        }
144        cmd_holder operator()(const std::string& arg1) const {
145            std::vector<std::string> v; v.push_back(arg1);
146            return (*this)(v);
147        }
148        cmd_holder operator()(const std::string& arg1, const std::string& arg2) const {
149            std::vector<std::string> v; v.push_back(arg1); v.push_back(arg2);
150            return (*this)(v);
151        }
152        cmd_holder operator()(const std::string& arg1, const std::string& arg2, const std::string& arg3) const {
153            std::vector<std::string> v; v.push_back(arg1); v.push_back(arg2); v.push_back(arg3);
154            return (*this)(v);
155        }
156    };
157
158    // for legacy compilers (e.g. old cl/bcc32?)
159    cmd_holder operator< (const basic_cmd_gen& lhs, const char* filename)      { return lhs() <  filename; }
160    cmd_holder operator> (const basic_cmd_gen& lhs, const char* filename)      { return lhs() >  filename; }
161    cmd_holder operator>>(const basic_cmd_gen& lhs, const char* filename)      { return lhs() >> filename; }
162    cmd_holder operator| (const basic_cmd_gen& lhs,       cmd_holder rhs)      { return lhs() | rhs;       }
163    cmd_holder operator| (const basic_cmd_gen& lhs, const basic_cmd_gen& rhs)  { return lhs() | rhs();     }
164    cmd_holder operator| (          cmd_holder lhs, const basic_cmd_gen& rhs)  { return lhs   | rhs();     }
165   
166
167    // UNIX cat
168    int cat_impl(const std::vector<std::string>& arg, std::istream& in, std::ostream& out) {
169        char c;
170        if (arg.size() > 0) {
171            for (std::vector<std::string>::const_iterator it = arg.begin(); it != arg.end(); it++) {
172                std::ifstream file_in(it->c_str());
173                while (file_in.get(c))
174                    out.put(c);
175            }
176        }
177        else {
178            while (in.get(c))
179                out.put(c);
180        }
181        return 0;
182    }
183
184    // UNIX sort
185    // input: accept only stdin, available options: only -r
186    int sort_impl(const std::vector<std::string>& arg, std::istream& in, std::ostream& out) {
187        std::string s;
188        std::vector<std::string> v;
189        while (std::getline(in, s, '\n'))
190            v.push_back(s);
191
192        if (arg.size() > 0 && arg[0] == "-r") // reverse
193            std::sort(v.begin(), v.end(), std::greater<std::string>());
194        else
195            std::sort(v.begin(), v.end());
196
197        for (std::vector<std::string>::const_iterator it = v.begin(); it != v.end(); it++)
198            out << (*it) << '\n';
199        return 0;
200    }
201
202    //////////////////////////
203
204    // UNIX uniq
205    // input: accept only stdin
206    int uniq_impl(const std::vector<std::string>&, std::istream& in, std::ostream& out) {
207        typedef std::vector<std::string>::const_iterator iterator;
208        std::string s;
209        std::vector<std::string> v;
210        while (std::getline(in, s, '\n'))
211            v.push_back(s);
212        iterator it_end = std::unique(v.begin(), v.end());
213        for (iterator it = v.begin(); it != it_end; it++)
214            out << (*it) << '\n';
215        return 0;
216    }
217
218}
219
220// importing for global namespace
221static shell::basic_cmd_gen  cat(&shell::cat_impl);
222static shell::basic_cmd_gen sort(&shell::sort_impl);
223static shell::basic_cmd_gen uniq(&shell::uniq_impl);
Note: See TracBrowser for help on using the browser.