Panda3D

Loading...
Searching...
No Matches
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::
33close() {
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::
56write_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 */
81MultiplexStreamBuf::
82MultiplexStreamBuf() {
83#ifndef PHAVE_IOSTREAM
84 // Older iostream implementations required this.
85 allocate();
86 setp(base(), ebuf());
87#endif
88}
89
90/**
91 *
92 */
93MultiplexStreamBuf::
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::
143overflow(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::
168sync() {
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::
194write_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.