libdap Updated for version 3.21.0
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
35namespace libdap {
36
43fdoutbuf::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
58int 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
95std::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
157fdinbuf::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
219fpinbuf::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}
fdinbuf(int _fd, bool close)
virtual int underflow()
virtual ~fdinbuf()
virtual int sync()
Definition fdiostream.cc:85
virtual int overflow(int c)
Definition fdiostream.cc:69
virtual std::streamsize xsputn(const char *s, std::streamsize num)
Definition fdiostream.cc:95
virtual ~fdoutbuf()
Definition fdiostream.cc:51
fdoutbuf(int _fd, bool _close)
Definition fdiostream.cc:43
virtual ~fpinbuf()
virtual int underflow()
fpinbuf(FILE *_fp, bool _close)
top level DAP object to house generic methods
Definition AISConnect.cc:30