Panda3D

multiplexStreamBuf.cxx

00001 // Filename: multiplexStreamBuf.cxx
00002 // Created by:  drose (27Nov00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "multiplexStreamBuf.h"
00016 
00017 #if defined(WIN32_VC) || defined(WIN64_VC)
00018 #define WINDOWS_LEAN_AND_MEAN
00019 #include <windows.h>
00020 #undef WINDOWS_LEAN_AND_MEAN
00021 #endif
00022 
00023 // We use real assert() instead of nassert(), because we're likely
00024 // to be invoked directly by pnotify.here, and we don't want to
00025 // risk infinite recursion.
00026 #include <assert.h>
00027 
00028 #ifndef HAVE_STREAMSIZE
00029 // Some compilers--notably SGI--don't define this for us.
00030 typedef int streamsize;
00031 #endif
00032 
00033 ////////////////////////////////////////////////////////////////////
00034 //     Function: MultiplexStreamBuf::Output::close
00035 //       Access: Public
00036 //  Description: Closes or deletes the relevant pointers, if _owns_obj
00037 //               is true.
00038 ////////////////////////////////////////////////////////////////////
00039 void MultiplexStreamBuf::Output::
00040 close() {
00041   if (_owns_obj) {
00042     switch (_output_type) {
00043     case OT_ostream:
00044       assert(_out != (ostream *)NULL);
00045       delete _out;
00046       break;
00047 
00048     case OT_stdio:
00049       assert(_fout != (FILE *)NULL);
00050       fclose(_fout);
00051       break;
00052 
00053     default:
00054       break;
00055     }
00056   }
00057 }
00058 
00059 ////////////////////////////////////////////////////////////////////
00060 //     Function: MultiplexStreamBuf::Output::write_string
00061 //       Access: Public
00062 //  Description: Dumps the indicated string to the appropriate place.
00063 ////////////////////////////////////////////////////////////////////
00064 void MultiplexStreamBuf::Output::
00065 write_string(const string &str) {
00066   switch (_output_type) {
00067   case OT_ostream:
00068     assert(_out != (ostream *)NULL);
00069     _out->write(str.data(), str.length());
00070     _out->flush();
00071     break;
00072 
00073   case OT_stdio:
00074     assert(_fout != (FILE *)NULL);
00075     fwrite(str.data(), str.length(), 1, _fout);
00076     fflush(_fout);
00077     break;
00078 
00079   case OT_system_debug:
00080 #if defined(WIN32_VC) || defined(WIN64_VC)
00081     OutputDebugString(str.c_str());
00082 #endif
00083     break;
00084   }
00085 }
00086 
00087 ////////////////////////////////////////////////////////////////////
00088 //     Function: MultiplexStreamBuf::Constructor
00089 //       Access: Public
00090 //  Description:
00091 ////////////////////////////////////////////////////////////////////
00092 MultiplexStreamBuf::
00093 MultiplexStreamBuf() {
00094 #ifndef PHAVE_IOSTREAM
00095   // Older iostream implementations required this.
00096   allocate();
00097   setp(base(), ebuf());
00098 #endif
00099 }
00100 
00101 ////////////////////////////////////////////////////////////////////
00102 //     Function: MultiplexStreamBuf::Destructor
00103 //       Access: Public, Virtual
00104 //  Description:
00105 ////////////////////////////////////////////////////////////////////
00106 MultiplexStreamBuf::
00107 ~MultiplexStreamBuf() {
00108   sync();
00109 
00110   // Make sure all of our owned pointers are freed.
00111   Outputs::iterator oi;
00112   for (oi = _outputs.begin(); oi != _outputs.end(); ++oi) {
00113     Output &out = (*oi);
00114     out.close();
00115   }
00116 }
00117 
00118 ////////////////////////////////////////////////////////////////////
00119 //     Function: MultiplexStreamBuf::add_output
00120 //       Access: Public
00121 //  Description: Adds the indicated output destinition to the set of
00122 //               things that will be written to when characters are
00123 //               output to the MultiplexStream.
00124 ////////////////////////////////////////////////////////////////////
00125 void MultiplexStreamBuf::
00126 add_output(MultiplexStreamBuf::BufferType buffer_type,
00127            MultiplexStreamBuf::OutputType output_type,
00128            ostream *out, FILE *fout, bool owns_obj) {
00129 #ifdef OLD_HAVE_IPC
00130   // Ensure that we have the mutex while we fiddle with the list of
00131   // outputs.
00132   mutex_lock m(_lock);
00133 #endif
00134 
00135   Output o;
00136   o._buffer_type = buffer_type;
00137   o._output_type = output_type;
00138   o._out = out;
00139   o._fout = fout;
00140   o._owns_obj = owns_obj;
00141   _outputs.push_back(o);
00142 }
00143 
00144 
00145 ////////////////////////////////////////////////////////////////////
00146 //     Function: MultiplexStreamBuf::flush
00147 //       Access: Public
00148 //  Description: Forces out all output that hasn't yet been written.
00149 ////////////////////////////////////////////////////////////////////
00150 void MultiplexStreamBuf::
00151 flush() {
00152 #ifdef OLD_HAVE_IPC
00153   mutex_lock m(_lock);
00154 #endif
00155 
00156   write_chars("", 0, true);
00157 }
00158 
00159 ////////////////////////////////////////////////////////////////////
00160 //     Function: MultiplexStreamBuf::overflow
00161 //       Access: Public, Virtual
00162 //  Description: Called by the system ostream implementation when its
00163 //               internal buffer is filled, plus one character.
00164 ////////////////////////////////////////////////////////////////////
00165 int MultiplexStreamBuf::
00166 overflow(int ch) {
00167 #ifdef OLD_HAVE_IPC
00168   mutex_lock m(_lock);
00169 #endif
00170 
00171   streamsize n = pptr() - pbase();
00172 
00173   if (n != 0) {
00174     write_chars(pbase(), n, false);
00175     pbump(-n);  // Reset pptr().
00176   }
00177 
00178   if (ch != EOF) {
00179     // Write one more character.
00180     char c = ch;
00181     write_chars(&c, 1, false);
00182   }
00183 
00184   return 0;
00185 }
00186 
00187 ////////////////////////////////////////////////////////////////////
00188 //     Function: MultiplexStreamBuf::sync
00189 //       Access: Public, Virtual
00190 //  Description: Called by the system ostream implementation when the
00191 //               buffer should be flushed to output (for instance, on
00192 //               destruction).
00193 ////////////////////////////////////////////////////////////////////
00194 int MultiplexStreamBuf::
00195 sync() {
00196 #ifdef OLD_HAVE_IPC
00197   mutex_lock m(_lock);
00198 #endif
00199 
00200   streamsize n = pptr() - pbase();
00201 
00202   // We pass in false for the flush value, even though our
00203   // transmitting ostream said to sync.  This allows us to get better
00204   // line buffering, since our transmitting ostream is often set
00205   // unitbuf, and might call sync multiple times in one line.  We
00206   // still have an explicit flush() call to force the issue.
00207   write_chars(pbase(), n, false);
00208   pbump(-n);
00209 
00210   return 0;  // Return 0 for success, EOF to indicate write full.
00211 }
00212 
00213 ////////////////////////////////////////////////////////////////////
00214 //     Function: MultiplexStreamBuf::write_chars
00215 //       Access: Private
00216 //  Description: An internal function called by sync() and overflow()
00217 //               to store one or more characters written to the stream
00218 //               into the memory buffer.
00219 //
00220 //               It is assumed that there is only one thread at a time
00221 //               running this code; it is the responsibility of the
00222 //               caller to grab the _lock mutex before calling this.
00223 ////////////////////////////////////////////////////////////////////
00224 void MultiplexStreamBuf::
00225 write_chars(const char *start, int length, bool flush) {
00226   size_t orig = _line_buffer.length();
00227   string latest;
00228   if (length != 0) {
00229     latest = string(start, length);
00230   }
00231   string line;
00232 
00233   if (flush) {
00234     // If we're to flush the stream now, we dump the whole thing
00235     // regardless of whether we have reached end-of-line.
00236     line = _line_buffer + latest;
00237     _line_buffer = "";
00238 
00239   } else {
00240     // Otherwise, we check for the end-of-line character, for our
00241     // ostreams that only want a complete line at a time.
00242     _line_buffer += latest;
00243     size_t eol = _line_buffer.rfind('\n', orig);
00244     if (eol != string::npos) {
00245       line = _line_buffer.substr(0, eol + 1);
00246       _line_buffer = _line_buffer.substr(eol + 1);
00247     }
00248   }
00249 
00250   Outputs::iterator oi;
00251   for (oi = _outputs.begin(); oi != _outputs.end(); ++oi) {
00252     Output &out = (*oi);
00253     switch (out._buffer_type) {
00254     case BT_none:
00255       // No buffering: send all new characters directly to the ostream.
00256       if (!latest.empty()) {
00257         out.write_string(latest);
00258       }
00259       break;
00260 
00261     case BT_line:
00262       // Line buffering: send only when a complete line has been
00263       // received.
00264       if (!line.empty()) {
00265         out.write_string(line);
00266       }
00267       break;
00268     }
00269   }
00270 
00271 }
 All Classes Functions Variables Enumerations