channelbuf.cc

Go to the documentation of this file.
00001 
00003 
00004 //
00005 // Copyright (c) 2004-2004 California Institute of Technology
00006 // Copyright (c) 2004-2007 University of Southern California
00007 // Rob Peters <rjpeters at usc dot edu>
00008 //
00009 // created: Wed Jun 30 17:01:22 2004
00010 // commit: $Id: channelbuf.cc 10065 2007-04-12 05:54:56Z rjpeters $
00011 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/tcl/channelbuf.cc $
00012 //
00013 // --------------------------------------------------------------------
00014 //
00015 // This file is part of GroovX.
00016 //   [http://ilab.usc.edu/rjpeters/groovx/]
00017 //
00018 // GroovX is free software; you can redistribute it and/or modify it
00019 // under the terms of the GNU General Public License as published by
00020 // the Free Software Foundation; either version 2 of the License, or
00021 // (at your option) any later version.
00022 //
00023 // GroovX is distributed in the hope that it will be useful, but
00024 // WITHOUT ANY WARRANTY; without even the implied warranty of
00025 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00026 // General Public License for more details.
00027 //
00028 // You should have received a copy of the GNU General Public License
00029 // along with GroovX; if not, write to the Free Software Foundation,
00030 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00031 //
00033 
00034 #ifndef GROOVX_TCL_CHANNELBUF_CC_UTC20050628162421_DEFINED
00035 #define GROOVX_TCL_CHANNELBUF_CC_UTC20050628162421_DEFINED
00036 
00037 #include "tcl/channelbuf.h"
00038 
00039 #include "rutz/error.h"
00040 #include "rutz/fstring.h"
00041 #include "rutz/sfmt.h"
00042 #include "rutz/shared_ptr.h"
00043 
00044 #include "rutz/trace.h"
00045 
00046 tcl::channel_buf::channel_buf(Tcl_Interp* interp,
00047                             const char* channame, int /*om*/) :
00048   opened(false), owned(false), mode(0), m_interp(interp), chan(0)
00049 {
00050   int origmode = 0;
00051   chan = Tcl_GetChannel(interp, channame, &origmode);
00052   if (chan == 0)
00053     {
00054       throw rutz::error(rutz::sfmt("no channel named '%s'",
00055                                    channame), SRC_POS);
00056     }
00057   opened = true;
00058 }
00059 
00060 void tcl::channel_buf::close()
00061 {
00062   if (opened && owned)
00063     {
00064       opened = false;
00065       Tcl_Close(m_interp, chan);
00066     }
00067 }
00068 
00069 int tcl::channel_buf::underflow() // with help from Josuttis, p. 678
00070 {
00071 GVX_TRACE("tcl::channel_buf::underflow");
00072   // is read position before end of buffer?
00073   if (gptr() < egptr())
00074     return *gptr();
00075 
00076   int num_putback = 0;
00077   if (s_pback_size > 0)
00078     {
00079       // process size of putback area
00080       // -use number of characters read
00081       // -but at most four
00082       num_putback = gptr() - eback();
00083       if (num_putback > 4)
00084         num_putback = 4;
00085 
00086       // copy up to four characters previously read into the putback
00087       // buffer (area of first four characters)
00088       std::memcpy (m_buffer+(4-num_putback), gptr()-num_putback,
00089                    num_putback);
00090     }
00091 
00092   // read new characters
00093   const int num = Tcl_Read(chan,
00094                            m_buffer+s_pback_size,
00095                            s_buf_size-s_pback_size);
00096 
00097   if (num <= 0) // error (0) or end-of-file (-1)
00098     return EOF;
00099 
00100   // reset buffer pointers
00101   setg (m_buffer+(s_pback_size-num_putback),
00102         m_buffer+s_pback_size,
00103         m_buffer+s_pback_size+num);
00104 
00105   // return next character Hrmph. We have to cast to unsigned char to avoid
00106   // problems with eof. Problem is, -1 is a valid char value to
00107   // return. However, without a cast, char(-1) (0xff) gets converted to
00108   // int(-1), which is 0xffffffff, which is EOF! What we want is
00109   // int(0x000000ff), which we have to get by int(unsigned char(-1)).
00110   return static_cast<unsigned char>(*gptr());
00111 }
00112 
00113 int tcl::channel_buf::overflow(int c)
00114 {
00115 GVX_TRACE("tcl::channel_buf::overflow");
00116   if (!(mode & std::ios::out) || !opened) return EOF;
00117 
00118   if (c != EOF)
00119     {
00120       // insert the character into the buffer
00121       *pptr() = c;
00122       pbump(1);
00123     }
00124 
00125   if (flushoutput() == EOF)
00126     {
00127       return -1; // ERROR
00128     }
00129 
00130   return c;
00131 }
00132 
00133 int tcl::channel_buf::sync()
00134 {
00135   if (flushoutput() == EOF)
00136     {
00137       return -1; // ERROR
00138     }
00139   return 0;
00140 }
00141 
00142 int tcl::channel_buf::flushoutput()
00143 {
00144   if (!(mode & std::ios::out) || !opened) return EOF;
00145 
00146   int num = pptr()-pbase();
00147   if ( Tcl_Write(chan, pbase(), num) != num )
00148     {
00149       return EOF;
00150     }
00151 
00152   pbump(-num);
00153   return num;
00154 }
00155 
00156 namespace
00157 {
00158   class tcl_stream : public std::iostream
00159   {
00160   private:
00161     tcl::channel_buf m_buf;
00162   public:
00163     tcl_stream(Tcl_Interp* interp,
00164                const char* channame, std::ios::openmode mode)
00165       :
00166       std::iostream(0),
00167       m_buf(interp, channame, mode)
00168     {
00169       rdbuf(&m_buf);
00170     }
00171   };
00172 }
00173 
00174 using rutz::shared_ptr;
00175 
00176 shared_ptr<std::ostream> tcl::ochanopen(Tcl_Interp* interp,
00177                                         const char* channame,
00178                                         std::ios::openmode flags)
00179 {
00180   return shared_ptr<std::ostream>
00181     (new tcl_stream(interp, channame, std::ios::out|flags));
00182 }
00183 
00184 shared_ptr<std::istream> tcl::ichanopen(Tcl_Interp* interp,
00185                                         const char* channame,
00186                                         std::ios::openmode flags)
00187 {
00188   return shared_ptr<std::iostream>
00189     (new tcl_stream(interp, channame, std::ios::in|flags));
00190 }
00191 
00192 
00193 static const char __attribute__((used)) vcid_groovx_tcl_channelbuf_cc_utc20050628162421[] = "$Id: channelbuf.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00194 #endif // !GROOVX_TCL_CHANNELBUF_CC_UTC20050628162421_DEFINED

The software described here is Copyright (c) 1998-2005, Rob Peters.
This page was generated Wed Dec 3 06:49:41 2008 by Doxygen version 1.5.5.