ui, libi2ncommon: (tomj) proper MAC address error handling, ability to get exit statu...
[libi2ncommon] / src / pipestream.hxx
1 /***************************************************************************
2               inpipestream.hxx  -  C++ streambuffer wrapper 
3                              -------------------
4     begin                : Thu Dec 27 2001
5     copyright            : (C) 2001 by Intra2net AG
6     email                : intranator@intra2net.com
7  ***************************************************************************/
8
9 #ifndef _PIPESTREAM
10 #define _PIPESTREAM
11
12 #include <string>
13 #include <streambuf>
14 #include <cstdio>
15
16 #include "exception.hxx"
17
18 // ATTENTION: A lot of mysterious STL bugs occured
19 //            with a "real" buffer (buffer larger than 1 byte and up to 100 bytes)
20 //            -> Keep it slow and working!
21
22 class inpipebuf : public std::streambuf
23 {
24    protected:
25    char buffer;
26    FILE *pipe;
27
28    // "callback" variables for destructor to store exit status   
29    bool *status_set;
30    int *exit_status;
31
32    public:
33    inpipebuf(const std::string& command)
34    {
35       status_set = NULL;
36       exit_status = NULL;
37    
38       pipe = popen (command.c_str(), "r");
39       if (pipe == NULL)
40          throw EXCEPTION (pipestream_error, "can't open program or permission denied");
41
42       // force underflow
43       setg (&buffer, &buffer, &buffer);
44    }
45
46    ~inpipebuf()
47    {
48       if (pipe != NULL) {
49          int pclose_exit = pclose (pipe);
50
51          if (exit_status && pclose_exit != -1) {
52             *status_set = true;
53             *exit_status = pclose_exit;
54          }
55                  
56          pipe = NULL;
57       }
58    }
59
60    void store_exit_status(bool *_status_set, int *_exit_status)
61       { status_set = _status_set; exit_status = _exit_status; }
62
63    protected:
64    virtual int_type underflow()
65    {
66       if (gptr() < egptr())
67          return traits_type::to_int_type(*gptr());
68
69       buffer = fgetc (pipe);
70       if (feof (pipe))
71       {
72          // ERROR or EOF
73          return EOF;
74       }
75
76       setg (&buffer, &buffer, &buffer+sizeof(char));
77
78       return traits_type::to_int_type(*gptr());
79    }
80 }; 
81
82 class inpipestream : public std::istream
83 {
84    protected:
85       inpipebuf buf;
86       
87    public:
88       inpipestream(const std::string& command)
89          : buf(command), std::istream(&buf)
90          {}
91       
92       void store_exit_status(bool *_status_set, int *_exit_status)
93          { buf.store_exit_status(_status_set, _exit_status); }
94 };
95
96 class outpipebuf : public std::streambuf
97 {
98    protected:
99    FILE *pipe;
100
101    // "callback" variables for destructor to store exit status   
102    bool *status_set;
103    int *exit_status;
104
105    public:
106    outpipebuf(const std::string& command)
107    {
108       status_set = NULL;
109       exit_status = NULL;
110
111       pipe = popen (command.c_str(), "w");
112       if (pipe == NULL)
113          throw EXCEPTION (pipestream_error, "can't open program or permission denied");
114    }
115
116    ~outpipebuf()
117    {
118       if (pipe != NULL) {
119          int pclose_exit = pclose (pipe);
120
121          if (exit_status && pclose_exit != -1) {
122             *status_set = true;
123             *exit_status = pclose_exit;
124          }
125
126          pipe = NULL;
127       }
128    }
129
130    void store_exit_status(bool *_status_set, int *_exit_status)
131       { status_set = _status_set; exit_status = _exit_status; }
132       
133    protected:
134    virtual int_type overflow(int_type c)
135    {
136       if (c != EOF)
137       {
138          if (fputc(c,pipe)==EOF)
139             return EOF;
140       }
141       return c;
142    }
143
144    virtual std::streamsize xsputn(const char* s, std::streamsize num)
145    {
146       return fwrite(s,num,1,pipe);
147    }
148 };
149
150 class outpipestream : public std::ostream
151 {
152    protected:
153       outpipebuf buf;
154    public:
155       outpipestream(const std::string& command)
156          : buf(command), std::ostream(&buf)
157          {}
158
159       void store_exit_status(bool *_status_set, int *_exit_status)
160          { buf.store_exit_status(_status_set, _exit_status); }
161 };
162
163 #endif