Panda3D

multiplexStreamBuf.cxx
Go to the documentation of this file.
1 /**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file multiplexStreamBuf.cxx
10 * @author drose
11 * @date 2000-11-27
12 */
13
14 #include "multiplexStreamBuf.h"
15
16 #if defined(WIN32_VC) || defined(WIN64_VC)
17 #define WINDOWS_LEAN_AND_MEAN
18 #include <windows.h>
19 #undef WINDOWS_LEAN_AND_MEAN
20 #endif
21
22 // We use real assert() instead of nassert(), because we're likely to be
23 // invoked directly by pnotify.here, and we don't want to risk infinite
24 // recursion.
25 #include <assert.h>
26
27 using std::string;
28
29 /**
30 * Closes or deletes the relevant pointers, if _owns_obj is true.
31 */
32 void MultiplexStreamBuf::Output::
33 close() {
34 if (_owns_obj) {
35 switch (_output_type) {
36 case OT_ostream:
37 assert(_out != nullptr);
38 delete _out;
39 break;
40
41 case OT_stdio:
42 assert(_fout != nullptr);
43 fclose(_fout);
44 break;
45
46 default:
47 break;
48 }
49 }
50 }
51
52 /**
53 * Dumps the indicated string to the appropriate place.
54 */
55 void MultiplexStreamBuf::Output::
56 write_string(const string &str) {
57 switch (_output_type) {
58 case OT_ostream:
59 assert(_out != nullptr);
60 _out->write(str.data(), str.length());
61 _out->flush();
62 break;
63
64 case OT_stdio:
65 assert(_fout != nullptr);
66 fwrite(str.data(), str.length(), 1, _fout);
67 fflush(_fout);
68 break;
69
70 case OT_system_debug:
71 #if defined(WIN32_VC) || defined(WIN64_VC)
72 OutputDebugString(str.c_str());
73 #endif
74 break;
75 }
76 }
77
78 /**
79 *
80 */
81 MultiplexStreamBuf::
82 MultiplexStreamBuf() {
83 #ifndef PHAVE_IOSTREAM
84 // Older iostream implementations required this.
85 allocate();
86 setp(base(), ebuf());
87 #endif
88 }
89
90 /**
91 *
92 */
93 MultiplexStreamBuf::
94 ~MultiplexStreamBuf() {
95 sync();
96
97 // Make sure all of our owned pointers are freed.
98 Outputs::iterator oi;
99 for (oi = _outputs.begin(); oi != _outputs.end(); ++oi) {
100 Output &out = (*oi);
101 out.close();
102 }
103 }
104
105 /**
106 * Adds the indicated output destinition to the set of things that will be
107 * written to when characters are output to the MultiplexStream.
108 */
109 void MultiplexStreamBuf::
110 add_output(MultiplexStreamBuf::BufferType buffer_type,
111 MultiplexStreamBuf::OutputType output_type,
112 std::ostream *out, FILE *fout, bool owns_obj) {
113
114 Output o;
115 o._buffer_type = buffer_type;
116 o._output_type = output_type;
117 o._out = out;
118 o._fout = fout;
119 o._owns_obj = owns_obj;
120
121 // Ensure that we have the mutex while we fiddle with the list of outputs.
122 _lock.lock();
123 _outputs.push_back(o);
124 _lock.unlock();
125 }
126
127
128 /**
129 * Forces out all output that hasn't yet been written.
130 */
131 void MultiplexStreamBuf::
132 flush() {
133 _lock.lock();
134 write_chars("", 0, true);
135 _lock.unlock();
136 }
137
138 /**
139 * Called by the system ostream implementation when its internal buffer is
140 * filled, plus one character.
141 */
142 int MultiplexStreamBuf::
143 overflow(int ch) {
144 _lock.lock();
145
146 std::streamsize n = pptr() - pbase();
147
148 if (n != 0) {
149 write_chars(pbase(), n, false);
150 pbump(-n); // Reset pptr().
151 }
152
153 if (ch != EOF) {
154 // Write one more character.
155 char c = ch;
156 write_chars(&c, 1, false);
157 }
158
159 _lock.unlock();
160 return 0;
161 }
162
163 /**
164 * Called by the system ostream implementation when the buffer should be
165 * flushed to output (for instance, on destruction).
166 */
167 int MultiplexStreamBuf::
168 sync() {
169 _lock.lock();
170
171 std::streamsize n = pptr() - pbase();
172
173 // We pass in false for the flush value, even though our transmitting
174 // ostream said to sync. This allows us to get better line buffering, since
175 // our transmitting ostream is often set unitbuf, and might call sync
176 // multiple times in one line. We still have an explicit flush() call to
177 // force the issue.
178 write_chars(pbase(), n, false);
179 pbump(-n);
180
181 _lock.unlock();
182 return 0; // Return 0 for success, EOF to indicate write full.
183 }
184
185 /**
186 * An internal function called by sync() and overflow() to store one or more
187 * characters written to the stream into the memory buffer.
188 *
189 * It is assumed that there is only one thread at a time running this code; it
190 * is the responsibility of the caller to grab the _lock mutex before calling
191 * this.
192 */
193 void MultiplexStreamBuf::
194 write_chars(const char *start, int length, bool flush) {
195 size_t orig = _line_buffer.length();
196 string latest;
197 if (length != 0) {
198 latest = string(start, length);
199 }
200 string line;
201
202 if (flush) {
203 // If we're to flush the stream now, we dump the whole thing regardless of
204 // whether we have reached end-of-line.
205 line = _line_buffer + latest;
206 _line_buffer = "";
207
208 } else {
209 // Otherwise, we check for the end-of-line character, for our ostreams
210 // that only want a complete line at a time.
211 _line_buffer += latest;
212 size_t eol = _line_buffer.rfind('\n', orig);
213 if (eol != string::npos) {
214 line = _line_buffer.substr(0, eol + 1);
215 _line_buffer = _line_buffer.substr(eol + 1);
216 }
217 }
218
219 Outputs::iterator oi;
220 for (oi = _outputs.begin(); oi != _outputs.end(); ++oi) {
221 Output &out = (*oi);
222 switch (out._buffer_type) {
223 case BT_none:
224 // No buffering: send all new characters directly to the ostream.
225 if (!latest.empty()) {
226 out.write_string(latest);
227 }
228 break;
229
230 case BT_line:
231 // Line buffering: send only when a complete line has been received.
232 if (!line.empty()) {
233 out.write_string(line);
234 }
235 break;
236 }
237 }
238 }
MultiplexStreamBuf::flush
void flush()
Forces out all output that hasn't yet been written.
Definition: multiplexStreamBuf.cxx:132
MultiplexStreamBuf::add_output
void add_output(BufferType buffer_type, OutputType output_type, std::ostream *out=nullptr, FILE *fout=nullptr, bool owns_obj=false)
Adds the indicated output destinition to the set of things that will be written to when characters ar...
Definition: multiplexStreamBuf.cxx:110
multiplexStreamBuf.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.