Since the virtuality of a method is inherited by derived classes, this
makes the virtual status of such methods clearly visible in the
declarations of derived classes.
The Windows and Mac builders on jenkins complain that '\U12345678' is
an invalid universal character; let's try with '\U000000E9' instead,
which should be LATIN SMALL LETTER E WITH ACUTE.
Also replace '\uab42' with '\u00e0' to remove a warning on the Windows
builder, due to the fact that '\uab42' cannot be represented in the
current code page (1252). This doesn't mean '\uab42' was incorrect,
though; I'm only changing this to make the warning disappear.
This function complements the existing strutils::unescape(). It
backslash-escapes a string for C/C++ string literal syntax.
For every std::string s, the following holds:
unescape(escape(s)) == s
(not the other way around, because there are many ways to escape a given
character in a string literal)
An octal escape sequence in a string literal can't have more than 3
octal digits after the backslash. The previous code was using up to 4
digits per octal escape sequence.
Such an argument is /a priori/ perfectly valid, and not an option.
Typical use in a command line:
-o -
equivalent to:
-o-
The former way wasn't accepted before this commit; now it is (also
'--output -', equivalent to '--output=-').
If the last option is followed by an argument consisting of a single
'-', this argument marks the end of options and is the first non-option
argument (contrary to '--' which, given its special status, would mark
the end of options but would *not* count as a non-option argument).
This commit also adds an std::string length check in
ArgumentParser::parseArgs() that was missing before using operator[]()
(important difference between operator[]() for std::string and std::map
or std::unordered_map!).
Previously, SGPath::pathListSep was a char in static memory, that could
be followed by anything (often '\0', as it seems... but not always).
This is (was) dangerous, because it is then tempting to take its address
and pass it to functions expecting a char * corresponding to a
null-terminated string (C-style).
SGPath::pathListSep is now a static array of two const chars: the path
list separator followed by a '\0'. This implies that
&SGPath::pathListSep can now be reliably interpreted as a C-style string
of length 1 (not counting the null terminator), containing only the path
list separator.
See simgear/misc/argparse.hxx for API and documentation
(simgear/misc/argparse_test.cxx also has examples, although argparse.hxx
features a very simple one at the top).
These classes were also presented in
<https://sourceforge.net/p/flightgear/mailman/message/35785019/>.
The popup/no popup logic in SG_LOG() could be wrong before this commit,
because of missing parentheses around uses of the second macro argument.
For instance, this:
SG_LOG(SG_NAVCACHE, t == 0 ? SG_WARN : SG_ALERT, "Message");
could cause a popup window to be displayed even though neither SG_WARN
nor SG_ALERT should do that in the current state of the logging system.
Thanks to Szymon Acedański for finding this.
Add an alternate constructor to each of the following classes:
ZlibAbstractIStreambuf, ZlibCompressorIStreambuf,
ZlibDecompressorIStreambuf, ZlibCompressorIStream and
ZlibDecompressorIStream. These new constructors are passed the source
std::istream wrapped inside an std::unique_ptr instead of by reference,
and store the unique_ptr object as an instance member. This ensures that
the source std::istream object is available as long as the
ZlibDecompressorIStreambuf, etc. instance is alive (which is necessary
for its getInputData() method) without any additional work for callers,
and that it is automatically destroyed afterwards.
This is particularly useful when writing functions that create and
return an object 'zobj' whose type is a subclass of
ZlibAbstractIStreambuf, when the source std::istream is only of interest
for its role of feeding data to 'zobj'. For instance:
std::unique_ptr<simgear::ZlibCompressorIStream>
myZlibCompressorIStreamProducer(std::string str)
{
std::unique_ptr<std::istringstream> iss(new std::istringstream(str));
return std::unique_ptr<simgear::ZlibCompressorIStream>(
new simgear::ZlibCompressorIStream(std::move(iss))); // new ctor here
}
Callers of such a function get access to a new ZlibCompressorIStream
instance fed by an std::istringstream object ('iss'), but they don't
even have to know this detail, nor to take any measure to ensure that
'iss' lives at least as long as the ZlibCompressorIStream object. The
std::unique_ptr<std::istream> pointing to 'iss' and stored as a member
of the ZlibCompressorIStream object by its constructor automatically
takes care of this lifetime problem.
New automated test for ZlibDecompressorIStreambuf::xsgetn(). xsgetn() is
called by sgetn() from the base class std::streambuf. In our case,
xsgetn() is actually defined in the base class ZlibAbstractIStreambuf
(subclass of std::streambuf), therefore this new test also applies to
ZlibCompressorIStreambuf and the two other related classes,
ZlibCompressorIStream and ZlibDecompressorIStream.
This test asks [x]sgetn() the largest possible amount of chars every
time it is called, i.e., the largest value that can be represented by
std::streamsize. This exercises the code in interesting ways due to the
various types involved (zlib's uInt, std::size_t and std::streamsize,
which have various sizes depending on the platform).
Compilation of these files was disabled in commit
e21ad4b5c1.
Fix build errors and warnings:
- Ambiguous template parameters for std::min();
- No appropriate default constructor available for
std::basic_istream<char,std::char_traits<char>> (the std::istream
subclasses didn't explicitly call the std::istream constructor,
which requires an argument). This is presumably exactly the reason
why sg_gzifstream is declared like this:
class sg_gzifstream : private gzifstream_base, public std::istream
where gzifstream_base is an empty shell for a stream buffer object:
struct gzifstream_base
{
gzifstream_base() {}
gzfilebuf gzbuf;
};
This ensures that the stream buffer object (gzbuf) is initialized
before std::istream's constructor is called. I solved this problem
in a different way, hopefully easier to understand, and requiring
neither an additional class nor multiple inheritance: first, we
initialize the std::istream base with a nullptr as the
std::streambuf * argument (this is valid C++11), then in the
constructor bodies for ZlibCompressorIStream and
ZlibDecompressorIStream, we call std::istream::rdbuf() to attach the
std::istream instance to the now-initialized stream buffer object.
- Possible truncation of constant value on 32 bits systems (this was
in zlibMaxChunkSize() which is now removed, see below).
Type-related improvements:
- Remove zlibMaxChunkSize() and zlibMaxChunk: in C++, one can simply
use std::numeric_limits<uInt>::max()---most of the code in
zlibMaxChunkSize() was there only to find this value via a zlib
function call.
- Add helper function templates zlibChunk() and clipCast().
- Split preparation of the putback area out of
ZlibAbstractIStreambuf::xsgetn() to a new utility method:
xsgetn_preparePutbackArea().
- More rigorous type handling in zlibstream_test.cxx.
Some precautions are necessary because the IOStreams API uses
std::streamsize in many places (e.g., the return value of
std::istream::gcount()), but functions such as the following
std::string constructor:
std::string(const char* s, std::size_t n);
work with std::size_t instead. Since these types are different and
opaque, this requires some care!