Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/downloader/multiplexStreamBuf.cxx

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

Generated on Fri May 2 00:36:51 2003 for Panda by doxygen1.3