Kea  1.5.0
master_lexer_inputsource.cc
Go to the documentation of this file.
1 // Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 
10 #include <dns/master_lexer.h>
11 
12 #include <istream>
13 #include <iostream>
14 #include <cassert>
15 #include <cerrno>
16 #include <cstring>
17 
18 namespace isc {
19 namespace dns {
20 namespace master_lexer_internal {
21 
22 namespace { // unnamed namespace
23 
24 std::string
25 createStreamName(const std::istream& input_stream) {
26  std::stringstream ss;
27  ss << "stream-" << &input_stream;
28  return (ss.str());
29 }
30 
31 size_t
32 getStreamSize(std::istream& is) {
33  errno = 0; // see below
34  is.seekg(0, std::ios_base::end);
35  if (is.bad()) {
36  // This means the istream has an integrity error. It doesn't make
37  // sense to continue from this point, so we treat it as a fatal error.
38  isc_throw(InputSource::OpenError,
39  "failed to seek end of input source");
40  } else if (is.fail() || errno != 0) {
41  // This is an error specific to seekg(). There can be several
42  // reasons, but the most likely cause in this context is that the
43  // stream is associated with a special type of file such as a pipe.
44  // In this case, it's more likely that other main operations of
45  // the input source work fine, so we continue with just setting
46  // the stream size to "unknown".
47  //
48  // (At least some versions of) Solaris + SunStudio shows deviant
49  // behavior here: seekg() apparently calls lseek(2) internally, but
50  // even if it fails it doesn't set the error bits of istream. That will
51  // confuse the rest of this function, so, as a heuristic workaround
52  // we check errno and handle any non 0 value as fail().
53  is.clear(); // clear this error not to confuse later ops.
55  }
56  const std::streampos len = is.tellg();
57  size_t ret = len;
58  if (len == static_cast<std::streampos>(-1)) { // cast for some compilers
59  if (!is.fail()) {
60  // tellg() returns -1 if istream::fail() would be true, but it's
61  // not guaranteed that it shouldn't be returned in other cases.
62  // In fact, with the combination of SunStudio and stlport,
63  // a stringstream created by the default constructor showed that
64  // behavior. We treat such cases as an unknown size.
66  } else {
67  isc_throw(InputSource::OpenError, "failed to get input size");
68  }
69  }
70  is.seekg(0, std::ios::beg);
71  if (is.fail()) {
72  isc_throw(InputSource::OpenError,
73  "failed to seek beginning of input source");
74  }
75  assert(len >= 0 || ret == MasterLexer::SOURCE_SIZE_UNKNOWN);
76  return (ret);
77 }
78 
79 } // end of unnamed namespace
80 
81 // Explicit definition of class static constant. The value is given in the
82 // declaration so it's not needed here.
84 
85 InputSource::InputSource(std::istream& input_stream) :
86  at_eof_(false),
87  line_(1),
88  saved_line_(line_),
89  buffer_pos_(0),
90  total_pos_(0),
91  name_(createStreamName(input_stream)),
92  input_(input_stream),
93  input_size_(getStreamSize(input_))
94 {}
95 
96 namespace {
97 // A helper to initialize InputSource::input_ in the member initialization
98 // list.
99 std::istream&
100 openFileStream(std::ifstream& file_stream, const char* filename) {
101  errno = 0;
102  file_stream.open(filename);
103  if (file_stream.fail()) {
104  std::string error_txt("Error opening the input source file: ");
105  error_txt += filename;
106  if (errno != 0) {
107  error_txt += "; possible cause: ";
108  error_txt += std::strerror(errno);
109  }
110  isc_throw(InputSource::OpenError, error_txt);
111  }
112 
113  return (file_stream);
114 }
115 }
116 
117 InputSource::InputSource(const char* filename) :
118  at_eof_(false),
119  line_(1),
120  saved_line_(line_),
121  buffer_pos_(0),
122  total_pos_(0),
123  name_(filename),
124  input_(openFileStream(file_stream_, filename)),
125  input_size_(getStreamSize(input_))
126 {}
127 
129 {
130  if (file_stream_.is_open()) {
131  file_stream_.close();
132  }
133 }
134 
135 int
137  if (buffer_pos_ == buffer_.size()) {
138  // We may have reached EOF at the last call to
139  // getChar(). at_eof_ will be set then. We then simply return
140  // early.
141  if (at_eof_) {
142  return (END_OF_STREAM);
143  }
144  // We are not yet at EOF. Read from the stream.
145  const int c = input_.get();
146  // Have we reached EOF now? If so, set at_eof_ and return early,
147  // but don't modify buffer_pos_ (which should still be equal to
148  // the size of buffer_).
149  if (input_.eof()) {
150  at_eof_ = true;
151  return (END_OF_STREAM);
152  }
153  // This has to come after the .eof() check as some
154  // implementations seem to check the eofbit also in .fail().
155  if (input_.fail()) {
157  "Error reading from the input stream: " << getName());
158  }
159  buffer_.push_back(c);
160  }
161 
162  const int c = buffer_[buffer_pos_];
163  ++buffer_pos_;
164  ++total_pos_;
165  if (c == '\n') {
166  ++line_;
167  }
168 
169  return (c);
170 }
171 
172 void
174  if (at_eof_) {
175  at_eof_ = false;
176  } else if (buffer_pos_ == 0) {
178  "Cannot skip before the start of buffer");
179  } else {
180  --buffer_pos_;
181  --total_pos_;
182  if (buffer_[buffer_pos_] == '\n') {
183  --line_;
184  }
185  }
186 }
187 
188 void
190  assert(total_pos_ >= buffer_pos_);
191  total_pos_ -= buffer_pos_;
192  buffer_pos_ = 0;
193  line_ = saved_line_;
194  at_eof_ = false;
195 }
196 
197 void
199  saved_line_ = line_;
200 }
201 
202 void
204  if (buffer_pos_ == buffer_.size()) {
205  buffer_.clear();
206  } else {
207  buffer_.erase(buffer_.begin(), buffer_.begin() + buffer_pos_);
208  }
209 
210  buffer_pos_ = 0;
211 }
212 
213 void
215  saveLine();
216  compact();
217 }
218 
219 } // namespace master_lexer_internal
220 } // namespace dns
221 } // namespace isc
isc::dns::master_lexer_internal::InputSource::InputSource
InputSource(std::istream &input_stream)
Constructor which takes an input stream.
Definition: master_lexer_inputsource.cc:85
isc::dns::master_lexer_internal::InputSource::getName
const std::string & getName() const
Returns a name for the InputSource.
Definition: master_lexer_inputsource.h:78
isc
Defines the logger used by the top-level component of kea-dhcp-ddns.
Definition: agent_parser.cc:144
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:192
isc::dns::master_lexer_internal::InputSource::ungetChar
void ungetChar()
Skips backward a single character in the input source.
Definition: master_lexer_inputsource.cc:173
isc::dns::master_lexer_internal::InputSource::ungetAll
void ungetAll()
Forgets what was read, and skips back to the position where compact() was last called.
Definition: master_lexer_inputsource.cc:189
isc::dns::master_lexer_internal::InputSource::UngetBeforeBeginning
Exception thrown when ungetChar() is made to go before the start of buffer.
Definition: master_lexer_inputsource.h:45
isc::dns::master_lexer_internal::InputSource::mark
void mark()
Calls saveLine() and compact() in sequence.
Definition: master_lexer_inputsource.cc:214
isc::dns::MasterLexer::ReadError
Exception thrown when we fail to read from the input stream or file.
Definition: master_lexer.h:306
master_lexer_inputsource.h
isc::dns::master_lexer_internal::InputSource::getChar
int getChar()
Returns a single character from the input source.
Definition: master_lexer_inputsource.cc:136
isc::dns::MasterLexer::SOURCE_SIZE_UNKNOWN
static const size_t SOURCE_SIZE_UNKNOWN
Special value for input source size meaning "unknown".
Definition: master_lexer.h:337
name_
const Name & name_
Definition: dns/message.cc:693
isc::dns::master_lexer_internal::InputSource::END_OF_STREAM
static const int END_OF_STREAM
Returned by getChar() when end of stream is reached.
Definition: master_lexer_inputsource.h:41
isc::dns::master_lexer_internal::InputSource::~InputSource
~InputSource()
Destructor.
Definition: master_lexer_inputsource.cc:128
isc::dns::master_lexer_internal::InputSource::saveLine
void saveLine()
Saves the current line being read.
Definition: master_lexer_inputsource.cc:198
isc::dns::master_lexer_internal::InputSource::compact
void compact()
Removes buffered content before the current location in the InputSource.
Definition: master_lexer_inputsource.cc:203
master_lexer.h