fdiostream.cc

Go to the documentation of this file.
00001 // -*- mode: c++; c-basic-offset:4 -*-
00002 
00003 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
00004 // Access Protocol.
00005 
00006 // Copyright (c) 2009 OPeNDAP, Inc.
00007 // Author: James Gallagher <jgallagher@opendap.org>
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Lesser General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2.1 of the License, or (at your option) any later version.
00013 //
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Lesser General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU Lesser General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 //
00023 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
00024 //
00025 // Portions of this code were taken verbatim from  Josuttis,
00026 // "The C++ Standard Library," p.672
00027 
00028 #include "config.h"
00029 
00030 #include "fdiostream.h"
00031 #include <cstring> // for memcpy
00032 
00033 //#define DODS_DEBUG
00034 #include "debug.h"
00035 
00036 namespace libdap {
00037 
00044 fdoutbuf::fdoutbuf(int _fd, bool _close) :
00045     fd(_fd), close(_close)
00046 {
00047     setp(buffer, buffer + (bufferSize - 1));
00048 }
00049 
00052 fdoutbuf::~fdoutbuf()
00053 {
00054     sync();
00055     if (close)
00056 	::close(fd);
00057 }
00058 
00059 // flush the characters in the buffer
00060 int fdoutbuf::flushBuffer()
00061 {
00062     int num = pptr() - pbase();
00063     if (write(1, buffer, num) != num) {
00064         return EOF;
00065     }
00066     pbump(-num);
00067     return num;
00068 }
00069 
00071 int fdoutbuf::overflow(int c)
00072 {
00073     if (c != EOF) {
00074         *pptr() = c;
00075         pbump(1);
00076     }
00077     // flush the buffer
00078     if (flushBuffer() == EOF) {
00079         //Error
00080         return EOF;
00081     }
00082 
00083     return c;
00084 }
00085 
00087 int fdoutbuf::sync()
00088 {
00089     if (flushBuffer() == EOF) {
00090         // Error
00091         return -1;
00092     }
00093     return 0;
00094 }
00095 
00097 std::streamsize fdoutbuf::xsputn(const char *s, std::streamsize num)
00098 {
00099     return write(fd, s, num);
00100 }
00101 
00102 /*
00103 How the buffer works for input streams:
00104 
00105 Initialized:
00106      eback() --\
00107      gptr()  --|
00108      egptr() --|
00109                |
00110 ---------------------------
00111 | | | | | | | | | | | | | |
00112 ---------------------------
00113 
00114 After the first call to read, the buffer is filled:
00115    eback() --\
00116    gptr()  --|
00117              | egptr() --|
00118              |           |
00119 ---------------------------
00120 | | | | | | |h|a|l|l|o|w|e|
00121 ---------------------------
00122 
00123 After 'hallowe' is read from the stream, gptr() reaches egptr() and that
00124 triggers the second read, which first must shuffle the characters 'hallowe'
00125 to the 'put back' area of the buffer and then read more characters from the
00126 underlying input source (fle descriptor or FILE*).
00127 
00128    eback() --\
00129              |  gptr() --|
00130              |           |
00131              |           |
00132 ---------------------------
00133 | | | | | | |h|a|l|l|o|w|e|
00134 ---------------------------
00135                          |
00136                egptr() --|
00137 
00138 After each read, gptr() is advanced until it hits egptr, which triggers a
00139 read. However, before the read takes place, characters are moved into the
00140 put back part of teh buffer. IE when a character is 'read' using the stream
00141 all the really happens is the gptr is advanced, the character is still in the
00142 buffer
00143 
00144    gptr()  --|
00145              |    egptr()
00146  /-eback()   |           |
00147 ---------------------------
00148 |h|a|l|l|o|w|e|e|n| |c|o|s|
00149 ---------------------------
00150 
00151 */
00152 
00159 fdinbuf::fdinbuf(int _fd, bool _close) :
00160     fd(_fd), close(_close)
00161 {
00162     setg(buffer + putBack, // beginning of put back area
00163             buffer + putBack, // read position
00164             buffer + putBack); // end position
00165 }
00166 
00168 fdinbuf::~fdinbuf()
00169 {
00170     if (close)
00171 	::close(fd);
00172 }
00173 
00175 int fdinbuf::underflow()
00176 {
00177     if (gptr() < egptr()) {
00178         DBG(std::cerr << "underflow, no read" << std::endl);
00179         return *gptr();
00180     }
00181 
00182     // How many characters are in the 'put back' part of the buffer? Cap
00183     // this number at putBack, which is nominally 128.
00184     int numPutBack = gptr() - eback();
00185     if (numPutBack > putBack)
00186         numPutBack = putBack;
00187 
00188     // copy characters previously read into the put back area of the
00189     // buffer. In a typical call, putBack is 128 and numPutBack is 128 too.
00190     // In this case the destination of memcpy is the start of the buffer and
00191     // gptr() - numPutBack (the source of the copy) points to the last 128
00192     // characters in the buffer.
00193     memcpy(buffer + (putBack - numPutBack), gptr() - numPutBack, numPutBack);
00194 
00195     // read new characters
00196     int num = read(fd, buffer + putBack, bufferSize - putBack);
00197     DBG(std::cerr << "underflow, read returns: " << num << std::endl);
00198     if (num <= 0) {
00199         // Error or EOF; error < 0; EOF == 0
00200         return EOF;
00201     }
00202 
00203     setg(buffer + (putBack - numPutBack), // beginning of put back area
00204             buffer + putBack, // read position
00205             buffer + putBack + num); // end of buffer
00206 
00207     // return next character
00208 #ifdef DODS_DEBUG
00209     char c = *gptr();
00210     DBG(std::cerr << "returning :" << c << std::endl);
00211     return c;
00212 #else
00213     return *gptr();
00214 #endif
00215 }
00216 
00223 fpinbuf::fpinbuf(FILE *_fp, bool _close) :
00224     fp(_fp), close(_close)
00225 {
00226     setg(buffer + putBack, // beginning of put back area
00227             buffer + putBack, // read position
00228             buffer + putBack); // end position
00229 }
00230 
00232 fpinbuf::~fpinbuf()
00233 {
00234     if (close)
00235         fclose(fp);
00236 }
00237 
00239 int fpinbuf::underflow()
00240 {
00241     if (gptr() < egptr()) {
00242         DBG(std::cerr << "underflow, no read" << std::endl);
00243         return *gptr();
00244     }
00245 
00246     // process size of putBack area
00247     // use the number of characters read, but a maximum of putBack
00248     int numPutBack = gptr() - eback();
00249     if (numPutBack > putBack)
00250         numPutBack = putBack;
00251 
00252     // copy characters previously read into the put back area of the
00253     // buffer.
00254     memcpy(buffer + (putBack - numPutBack), gptr() - numPutBack, numPutBack);
00255 
00256     // read new characters
00257     int num = fread(buffer + putBack, 1, bufferSize - putBack, fp);
00258     DBG(std::cerr << "underflow, read returns: " << num << std::endl);
00259     if (num == 0) {
00260         // Error or EOF; use feof() or ferror() to test
00261         return EOF;
00262     }
00263 
00264     setg(buffer + (putBack - numPutBack), // beginning of put back area
00265             buffer + putBack, // read position
00266             buffer + putBack + num); // end of buffer
00267 
00268     // return next character
00269     return *gptr();
00270 }
00271 
00272 }

Generated on Wed Feb 10 16:08:02 2010 for libdap++ by  doxygen 1.4.7