libdap  Updated for version 3.20.6
libdap4 is an implementation of OPeNDAP's DAP protocol.
fdiostream.cc
1 // -*- mode: c++; c-basic-offset:4 -*-
2 
3 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
4 // Access Protocol.
5 
6 // Copyright (c) 2009 OPeNDAP, Inc.
7 // Author: James Gallagher <jgallagher@opendap.org>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 //
23 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24 //
25 // Portions of this code were taken verbatim from Josuttis,
26 // "The C++ Standard Library," p.672
27 
28 #include "config.h"
29 
30 #include "fdiostream.h"
31 #include <cstring> // for memcpy
32 //#define DODS_DEBUG
33 #include "debug.h"
34 
35 namespace libdap {
36 
43 fdoutbuf::fdoutbuf(int _fd, bool _close) :
44  fd(_fd), close(_close)
45 {
46  setp(buffer, buffer + (bufferSize - 1));
47 }
48 
52 {
53  sync();
54  if (close) ::close(fd);
55 }
56 
57 // flush the characters in the buffer
58 int fdoutbuf::flushBuffer()
59 {
60  int num = pptr() - pbase();
61  if (write(1, buffer, num) != num) {
62  return EOF;
63  }
64  pbump(-num);
65  return num;
66 }
67 
70 {
71  if (c != EOF) {
72  *pptr() = c;
73  pbump(1);
74  }
75  // flush the buffer
76  if (flushBuffer() == EOF) {
77  //Error
78  return EOF;
79  }
80 
81  return c;
82 }
83 
86 {
87  if (flushBuffer() == EOF) {
88  // Error
89  return -1;
90  }
91  return 0;
92 }
93 
95 std::streamsize fdoutbuf::xsputn(const char *s, std::streamsize num)
96 {
97  return write(fd, s, num);
98 }
99 
100 /*
101  How the buffer works for input streams:
102 
103  Initialized:
104  eback() --\
105  gptr() --|
106  egptr() --|
107  |
108  ---------------------------
109  | | | | | | | | | | | | | |
110  ---------------------------
111 
112  After the first call to read, the buffer is filled:
113  eback() --\
114  gptr() --|
115  | egptr() --|
116  | |
117  ---------------------------
118  | | | | | | |h|a|l|l|o|w|e|
119  ---------------------------
120 
121  After 'hallowe' is read from the stream, gptr() reaches egptr() and that
122  triggers the second read, which first must shuffle the characters 'hallowe'
123  to the 'put back' area of the buffer and then read more characters from the
124  underlying input source (fle descriptor or FILE*).
125 
126  eback() --\
127  | gptr() --|
128  | |
129  | |
130  ---------------------------
131  | | | | | | |h|a|l|l|o|w|e|
132  ---------------------------
133  |
134  egptr() --|
135 
136  After each read, gptr() is advanced until it hits egptr, which triggers a
137  read. However, before the read takes place, characters are moved into the
138  put back part of the buffer. IE when a character is 'read' using the stream
139  all the really happens is the gptr is advanced, the character is still in the
140  buffer
141 
142  gptr() --|
143  | egptr()
144  /-eback() | |
145  ---------------------------
146  |h|a|l|l|o|w|e|e|n| |c|o|s|
147  ---------------------------
148 
149  */
150 
157 fdinbuf::fdinbuf(int _fd, bool _close) :
158  fd(_fd), close(_close)
159 {
160  setg(buffer + putBack, // beginning of put back area
161  buffer + putBack, // read position
162  buffer + putBack); // end position
163 }
164 
167 {
168  if (close) ::close(fd);
169 }
170 
173 {
174  if (gptr() < egptr()) {
175  DBG(std::cerr << "underflow, no read" << std::endl);
176  return *gptr();
177  }
178 
179  // How many characters are in the 'put back' part of the buffer? Cap
180  // this number at putBack, which is nominally 128.
181  int numPutBack = gptr() - eback();
182  if (numPutBack > putBack) numPutBack = putBack;
183 
184  // copy characters previously read into the put back area of the
185  // buffer. In a typical call, putBack is 128 and numPutBack is 128 too.
186  // In this case the destination of memcpy is the start of the buffer and
187  // gptr() - numPutBack (the source of the copy) points to the last 128
188  // characters in the buffer.
189  memcpy(buffer + (putBack - numPutBack), gptr() - numPutBack, numPutBack);
190 
191  // read new characters
192  int num = read(fd, buffer + putBack, bufferSize - putBack);
193  DBG(std::cerr << "underflow, read returns: " << num << std::endl);
194  if (num <= 0) {
195  // Error or EOF; error < 0; EOF == 0
196  return EOF;
197  }
198 
199  setg(buffer + (putBack - numPutBack), // beginning of put back area
200  buffer + putBack, // read position
201  buffer + putBack + num); // end of buffer
202 
203  // return next character
204 #ifdef DODS_DEBUG
205  char c = *gptr();
206  DBG(std::cerr << "returning :" << c << std::endl);
207  return c;
208 #else
209  return *gptr();
210 #endif
211 }
212 
219 fpinbuf::fpinbuf(FILE *_fp, bool _close) :
220  fp(_fp), close(_close)
221 {
222  setg(buffer + putBack, // beginning of put back area
223  buffer + putBack, // read position
224  buffer + putBack); // end position
225 }
226 
229 {
230  if (close) fclose(fp);
231 }
232 
235 {
236  if (gptr() < egptr()) {
237  DBG(std::cerr << "underflow, no read" << std::endl);
238  return *gptr();
239  }
240 
241  // process size of putBack area
242  // use the number of characters read, but a maximum of putBack
243  int numPutBack = gptr() - eback();
244  if (numPutBack > putBack) numPutBack = putBack;
245 
246  // copy characters previously read into the put back area of the
247  // buffer.
248  memcpy(buffer + (putBack - numPutBack), gptr() - numPutBack, numPutBack);
249 
250  // read new characters
251  int num = fread(buffer + putBack, 1, bufferSize - putBack, fp);
252  DBG(std::cerr << "underflow, read returns: " << num << std::endl);
253  if (num == 0) {
254  // Error or EOF; use feof() or ferror() to test
255  return EOF;
256  }
257 
258  setg(buffer + (putBack - numPutBack), // beginning of put back area
259  buffer + putBack, // read position
260  buffer + putBack + num); // end of buffer
261 
262  // return next character
263  return *gptr();
264 }
265 
266 }
virtual ~fdinbuf()
Definition: fdiostream.cc:166
virtual std::streamsize xsputn(const char *s, std::streamsize num)
Definition: fdiostream.cc:95
virtual int overflow(int c)
Definition: fdiostream.cc:69
virtual int underflow()
Definition: fdiostream.cc:172
top level DAP object to house generic methods
Definition: AISConnect.cc:30
virtual int sync()
Definition: fdiostream.cc:85
fdoutbuf(int _fd, bool _close)
Definition: fdiostream.cc:43
virtual int underflow()
Definition: fdiostream.cc:234
virtual ~fpinbuf()
Definition: fdiostream.cc:228
fpinbuf(FILE *_fp, bool _close)
Definition: fdiostream.cc:219
virtual ~fdoutbuf()
Definition: fdiostream.cc:51
fdinbuf(int _fd, bool close)
Definition: fdiostream.cc:157