00001 /** @file rutz/stdiobuf.cc wrap posix file descriptors in c++ iostreams */ 00002 00003 /////////////////////////////////////////////////////////////////////// 00004 // 00005 // Copyright (c) 2002-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: Tue Feb 25 13:52:11 2003 00010 // commit: $Id: stdiobuf.cc 8249 2007-04-12 06:03:40Z rjpeters $ 00011 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/rutz/stdiobuf.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 // 00032 /////////////////////////////////////////////////////////////////////// 00033 00034 #ifndef GROOVX_RUTZ_STDIOBUF_CC_UTC20050626084020_DEFINED 00035 #define GROOVX_RUTZ_STDIOBUF_CC_UTC20050626084020_DEFINED 00036 00037 #include "rutz/stdiobuf.h" 00038 00039 #include "rutz/error.h" 00040 00041 #include <ios> 00042 #include <unistd.h> 00043 00044 #include "rutz/debug.h" 00045 GVX_DBG_REGISTER 00046 #include "rutz/trace.h" 00047 00048 void rutz::stdiobuf::init(int fd, int om, bool throw_exception) 00049 { 00050 GVX_TRACE("rutz::stdiobuf::init"); 00051 m_filedes = fd; 00052 00053 if (m_filedes >= 0) 00054 { 00055 m_mode = om; 00056 } 00057 00058 if (throw_exception && !is_open()) 00059 { 00060 throw rutz::error("couldn't open file stdiobuf", SRC_POS); 00061 } 00062 00063 setg (buffer+s_pback_size, 00064 buffer+s_pback_size, 00065 buffer+s_pback_size); 00066 00067 setp (buffer, 00068 buffer+s_buf_size-1); 00069 } 00070 00071 rutz::stdiobuf::stdiobuf(FILE* f, int om, bool throw_exception) : 00072 m_mode(0), m_filedes(-1) 00073 { 00074 GVX_TRACE("rutz::stdiobuf::stdiobuf(FILE*)"); 00075 init(fileno(f), om, throw_exception); 00076 } 00077 00078 rutz::stdiobuf::stdiobuf(int fd, int om, bool throw_exception) : 00079 m_mode(0), m_filedes(-1) 00080 { 00081 GVX_TRACE("rutz::stdiobuf::stdiobuf(int)"); 00082 00083 init(fd, om, throw_exception); 00084 } 00085 00086 void rutz::stdiobuf::close() 00087 { 00088 GVX_TRACE("rutz::stdiobuf::close"); 00089 if (is_open()) 00090 { 00091 this->sync(); 00092 // NOTE: We don't do ::close(m_filedes) here since we leave that 00093 // up to whoever instantiated this stdiobuf. 00094 m_filedes = -1; 00095 m_mode = 0; 00096 } 00097 } 00098 00099 int rutz::stdiobuf::underflow() // with help from Josuttis, p. 678 00100 { 00101 GVX_TRACE("rutz::stdiobuf::underflow"); 00102 // is read position before end of buffer? 00103 if (gptr() < egptr()) 00104 return *gptr(); 00105 00106 int numPutback = 0; 00107 if (s_pback_size > 0) 00108 { 00109 // process size of putback area 00110 // -use number of characters read 00111 // -but at most four 00112 numPutback = gptr() - eback(); 00113 if (numPutback > 4) 00114 numPutback = 4; 00115 00116 // copy up to four characters previously read into the putback 00117 // buffer (area of first four characters) 00118 std::memcpy (buffer+(4-numPutback), gptr()-numPutback, 00119 numPutback); 00120 } 00121 00122 // read new characters 00123 const int num = ::read(m_filedes, 00124 buffer+s_pback_size, 00125 s_buf_size-s_pback_size); 00126 00127 if (num <= 0) 00128 return EOF; 00129 00130 // reset buffer pointers 00131 setg (buffer+s_pback_size-numPutback, 00132 buffer+s_pback_size, 00133 buffer+s_pback_size+num); 00134 00135 // return next character Hrmph. We have to cast to unsigned char to 00136 // avoid problems with eof. Problem is, -1 is a valid char value to 00137 // return. However, without a cast, char(-1) (0xff) gets converted 00138 // to int(-1), which is 0xffffffff, which is EOF! What we want is 00139 // int(0x000000ff), which we have to get by int(unsigned char(-1)). 00140 return static_cast<unsigned char>(*gptr()); 00141 } 00142 00143 int rutz::stdiobuf::overflow(int c) 00144 { 00145 GVX_TRACE("rutz::stdiobuf::overflow"); 00146 if (!(m_mode & std::ios::out) || !is_open()) return EOF; 00147 00148 if (c != EOF) 00149 { 00150 // insert the character into the buffer 00151 *pptr() = c; 00152 pbump(1); 00153 } 00154 00155 if (flushoutput() == EOF) 00156 { 00157 return -1; // ERROR 00158 } 00159 00160 return c; 00161 } 00162 00163 int rutz::stdiobuf::sync() 00164 { 00165 if (flushoutput() == EOF) 00166 { 00167 return -1; // ERROR 00168 } 00169 return 0; 00170 } 00171 00172 int rutz::stdiobuf::flushoutput() 00173 { 00174 if (!(m_mode & std::ios::out) || !is_open()) return EOF; 00175 00176 const int num = pptr()-pbase(); 00177 00178 if ( ::write(m_filedes, pbase(), num) == -1 ) 00179 { 00180 return EOF; 00181 } 00182 00183 pbump(-num); 00184 return num; 00185 } 00186 00187 // This is a hack to work around an apparently broken g++ 3.4.3 00188 // on USC's HPCC cluster, in which libstdc++ doesn't include 00189 // instantiations for the constructor and destructor of std::iostream 00190 // (aka std::basic_iostream<char>); so, we force an instantiation of 00191 // those functions here to avoid link errors. This line should be 00192 // quickly removed as soon as we no longer need to use g++ 3.4.3. 00193 #ifdef GVX_MISSING_IOSTREAM_INSTANTIATION 00194 template class std::basic_iostream<char>; 00195 #endif 00196 00197 static const char __attribute__((used)) vcid_groovx_rutz_stdiobuf_cc_utc20050626084020[] = "$Id: stdiobuf.cc 8249 2007-04-12 06:03:40Z rjpeters $ $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/rutz/stdiobuf.cc $"; 00198 #endif // !GROOVX_RUTZ_STDIOBUF_CC_UTC20050626084020_DEFINED