|
@@ -36,33 +36,50 @@ createStreamName(const std::istream& input_stream) {
|
|
|
|
|
|
size_t
|
|
|
getStreamSize(std::istream& is) {
|
|
|
+ errno = 0; // see below
|
|
|
is.seekg(0, std::ios_base::end);
|
|
|
if (is.bad()) {
|
|
|
// This means the istream has an integrity error. It doesn't make
|
|
|
// sense to continue from this point, so we treat it as a fatal error.
|
|
|
isc_throw(InputSource::OpenError,
|
|
|
"failed to seek end of input source");
|
|
|
- } else if (is.fail()) {
|
|
|
+ } else if (is.fail() || errno != 0) {
|
|
|
// This is an error specific to seekg(). There can be several
|
|
|
// reasons, but the most likely cause in this context is that the
|
|
|
// stream is associated with a special type of file such as a pipe.
|
|
|
// In this case, it's more likely that other main operations of
|
|
|
// the input source work fine, so we continue with just setting
|
|
|
// the stream size to "unknown".
|
|
|
+ //
|
|
|
+ // (At least some versions of) Solaris + SunStudio shows deviant
|
|
|
+ // behavior here: seekg() apparently calls lseek(2) internally, but
|
|
|
+ // even if it fails it doesn't set the error bits of istream. That will
|
|
|
+ // confuse the rest of this function, so, as a heuristic workaround
|
|
|
+ // we check errno and handle any non 0 value as fail().
|
|
|
is.clear(); // clear this error not to confuse later ops.
|
|
|
return (MasterLexer::SOURCE_SIZE_UNKNOWN);
|
|
|
}
|
|
|
const std::streampos len = is.tellg();
|
|
|
+ size_t ret = len;
|
|
|
if (len == static_cast<std::streampos>(-1)) { // cast for some compilers
|
|
|
- isc_throw(InputSource::OpenError, "failed to get input size");
|
|
|
+ if (!is.fail()) {
|
|
|
+ // tellg() returns -1 if istream::fail() would be true, but it's
|
|
|
+ // not guaranteed that it shouldn't be returned in other cases.
|
|
|
+ // In fact, with the combination of SunStudio and stlport,
|
|
|
+ // a stringstream created by the default constructor showed that
|
|
|
+ // behavior. We treat such cases as an unknown size.
|
|
|
+ ret = MasterLexer::SOURCE_SIZE_UNKNOWN;
|
|
|
+ } else {
|
|
|
+ isc_throw(InputSource::OpenError, "failed to get input size");
|
|
|
+ }
|
|
|
}
|
|
|
is.seekg(0, std::ios::beg);
|
|
|
if (is.fail()) {
|
|
|
isc_throw(InputSource::OpenError,
|
|
|
"failed to seek beginning of input source");
|
|
|
}
|
|
|
- assert(len >= 0);
|
|
|
- return (len);
|
|
|
+ assert(len >= 0 || ret == MasterLexer::SOURCE_SIZE_UNKNOWN);
|
|
|
+ return (ret);
|
|
|
}
|
|
|
|
|
|
} // end of unnamed namespace
|