Line data Source code
1 : // Copyright (c) 2013-2022 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/eventdispatcher
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 :
20 : // self
21 : //
22 : #include <cppprocess/io_capture_pipe.h>
23 :
24 :
25 : // snaplogger lib
26 : //
27 : #include <snaplogger/message.h>
28 :
29 :
30 : // snapdev lib
31 : //
32 : #include <snapdev/trim_string.h>
33 :
34 :
35 : // C lib
36 : //
37 : #include <string.h>
38 :
39 :
40 : // last include
41 : //
42 : #include <snapdev/poison.h>
43 :
44 :
45 :
46 : namespace cppprocess
47 : {
48 :
49 :
50 :
51 4 : io_capture_pipe::io_capture_pipe()
52 4 : : io_pipe(IO_FLAG_OUTPUT)
53 : {
54 4 : }
55 :
56 :
57 4 : void io_capture_pipe::process_read()
58 : {
59 : //std::cerr << "PIPE got read signal -- " << get_socket() << "\n";
60 4 : if(get_socket() != -1)
61 : {
62 : // handle up to 64Kb at once
63 : //
64 4 : char buffer[1'024 * 64];
65 4 : errno = 0;
66 4 : ssize_t const r(read(&buffer[0], sizeof(buffer)));
67 4 : if(r < 0
68 0 : && errno != 0
69 0 : && errno != EAGAIN
70 0 : && errno != EWOULDBLOCK)
71 : {
72 0 : int const e(errno);
73 0 : SNAP_LOG_ERROR
74 0 : << "an error occurred while reading from pipe (errno: "
75 : << e
76 : << " -- "
77 0 : << strerror(e)
78 : << ")."
79 : << SNAP_LOG_SEND;
80 0 : process_error();
81 0 : return;
82 : }
83 :
84 4 : if(r > 0)
85 : {
86 : // append to output buffer
87 : //
88 4 : f_output.insert(f_output.end(), buffer, buffer + r);
89 :
90 : //std::cerr << "PIPE read " << r << " bytes ["
91 : //<< std::string(reinterpret_cast<char *>(f_output.data()), f_output.size())
92 : //<< "]\n";
93 : }
94 : }
95 :
96 : // process the next level
97 : //
98 4 : pipe_connection::process_read();
99 : }
100 :
101 :
102 : /** \brief Read the output of the command.
103 : *
104 : * This function reads the output of the process. This function converts
105 : * the output to UTF-8. Note that if some bytes are missing this function
106 : * is likely to fail. If you are reading the data little by little as it
107 : * comes in, you may want to use the get_binary_output() function
108 : * instead. That way you can detect characters such as the "\n" and at
109 : * that point convert the data from the previous "\n" you found in the
110 : * buffer to that new "\n". This will generate valid UTF-8 strings.
111 : *
112 : * This function is most often used by users of commands that process
113 : * one given input and generate one given output all at once.
114 : *
115 : * \param[in] reset Whether the output so far should be cleared.
116 : *
117 : * \return The current output buffer.
118 : *
119 : * \sa get_binary_output()
120 : */
121 10 : std::string io_capture_pipe::get_output(bool reset) const
122 : {
123 10 : std::string const output(reinterpret_cast<char const *>(f_output.data()), f_output.size());
124 10 : if(reset)
125 : {
126 0 : const_cast<io_capture_pipe *>(this)->f_output.clear();
127 : }
128 10 : return output;
129 : }
130 :
131 :
132 : /** \brief Get the trimmed output.
133 : *
134 : * The get_output() function returns the output as is, with all the
135 : * characters. Quite often, though, you do not want the ending `'\n'`,
136 : * introductory spaces or tabs, or even multiple spaces when aligned
137 : * column output is used by the process.
138 : *
139 : * This function can be used to trimmed all of that junk for you. It
140 : * will always remove the starting and ending spaces and new line,
141 : * carriage return characters.
142 : *
143 : * When \p inside is true, it also replaces multiple spaces within
144 : * the string in a single space. This feature also replaces all spaces
145 : * with 0x20 (`' '`).
146 : *
147 : * \param[in] inside Whether to remove double, triple, etc. spaces inside
148 : * the string.
149 : * \param[in] reset Whether to reset the value after this call.
150 : *
151 : * \return The trimmed output string.
152 : *
153 : * \sa snapdev::trim_string() (in snapdev)
154 : */
155 4 : std::string io_capture_pipe::get_trimmed_output(bool inside, bool reset) const
156 : {
157 4 : return snapdev::trim_string(get_output(reset), true, true, inside);
158 : }
159 :
160 :
161 : /** \brief Read the output of the command as a binary buffer.
162 : *
163 : * This function reads the output of the process in binary (untouched).
164 : *
165 : * This function does not fail like the get_output() which attempts to
166 : * convert the output of the function to UTF-8. Also the output of the
167 : * command may not be UTF-8 in which case you would have to use the
168 : * binary version and use a different conversion.
169 : *
170 : * \param[in] reset Whether the output so far should be cleared.
171 : *
172 : * \return The current output buffer.
173 : *
174 : * \sa get_output()
175 : */
176 4 : buffer_t io_capture_pipe::get_binary_output(bool reset) const
177 : {
178 4 : buffer_t const output(f_output);
179 4 : if(reset)
180 : {
181 0 : const_cast<io_capture_pipe *>(this)->f_output.clear();
182 : }
183 4 : return output;
184 : }
185 :
186 :
187 :
188 6 : } // namespace cppprocess
189 : // vim: ts=4 sw=4 et
|