[Tuxcpprogramming] Re: [LC++] Inheritance: creating a configuration stream

Jack Lloyd lloyd at acm.jhu.edu
Thu Jul 12 12:48:05 UTC 2001


> I am wanting to create a generalized stream class which makes it easy
> to read-in information from a text configuration file.

OK, but first think. Do you want to write this, or do you want to use it
in an app? Things like this do already exist (though admittidly I have
written basically just this same thing).

> It should have the following functionality:

> * remove comments --- everything on a line after a '#' character

This is easy with std::string.

> * support "carry-over" lines --- ie if a line ends
>   with a '\', the next line should be treated as an
>   extension of the current line.  The getline()
>   message should automatically perform this
>   "carry-over" operation (as well as getting rid
>   of comments).

Also very easy with std::string. (OK, these last two are BS answers, but I
can't remember the exact function calls. If you're really curious,
download OpenCL, a C++ library I've been working on for a bit, and read
checks/validate.cpp, which does these things (mostly)). Or wait for more
informed members of this list to correct and expound upon my statements -
which is probably easier.

> * provide ability to extract "tokens" --- a token
>   is either an integer, eg 255, a double, eg 6.3217,
>   a string with no white space, eg BANANA, or
>   a string within quotes which may contain white
>   space, eg "The cat".  A line should comprise a
>   list of tokens, separated by white space.  Eg
>       "The cat" 6.3217 BANANA 255
>   The class should be able to "get the next token"
>   and automatically do the right conversion so
>   the result is returned as an integer, double or
>   string, depending on what it is.

This could be harder. Depending on how flexible you want to be, of course.
What if the next token is "6.0"? It could be the literal string "6.0", the
float 6.0, or the int 6. It's fairly easy to code, but from a design
perspective, you have to think about what is the best thing to do out of a
number of possibilities. It's a strong types vs easy conversion question,
and both sides are right. Is "" a string, or an empty token to be ignored?
Etc.

>
> So far, my idea for this class is as follows:
>
> class configStreamTy: public ifstream {
> private:
>   string& curLine;
> public:
>   bool getline();
>   bool getline(string& line) {
>     bool success=ifstream::getline();
>     line=curLine;
>     return success;
>   }
>   bool getToken(string& token);
>   bool getToken(int& token);
>   bool getToken(double& token);
> };
>
> But I'm still new to c++ programming and I'm not sure if this is the
> best way of setting things up.

I was writing one of these a while back, so I'll share my thoughts here.
Basically, it was a wrapper for map<pair<string,string>,string>. The
pair<string,string> is a "section" name followed by a variable name (think
like Windows INI files or the OpenSSL CONF format). It maps these onto the
variable.

It also supported a "fall-back" lookup into the programs environment (so
if you lookup HOME, and HOME wasn't set in whatever config file you read,
it would try the HOME environmental variable [there were some other
niceties related to this, but I'll spare you]). I totally stole this
feature from OpenSSL <g>

Also you could merge a pair of config sets.  So, for example, you could
read a "system-level defaults" config file, followed by a personal config
file to override the defaults. Add in some basic I/O to/from
istreams/ostreams and that's about it.

I probably could have provided typing as well but it never really got that
far (I stopped maybe 60% through).

IMO, inheriting from istream is not the right thing. The semantics are
quite different. For example, what should some_config_istream.read(buf, n)
do? A raw read? What if the raw read puts the file position in the middle
of a token? All kinds of problems come up here...

>  Also, I'm a bit unsure of exactly how inheritance works.  That is, do
> I need to provide new definitions for constructors and destructors, or
> do the ones provided by ifstream work?

I think if you don't provide constructors it will automagically call those
provided by istream, but I'll admit I'm really not sure (erm... I guess
you would need one for sure if istream's constructor takes arguments...
but I don't know if it does or not). I know that whenvever I inherit
something, I create a contstructor (possibly just an empty one), that
calls the parent(s) constructor(s). Just boilerplate so I don't have to
think about the precise rules. It's also more explicit then.

> What if I wanted to initialize curLine to "" as part of the
> constructor --- how would I do this without affecting the ifstream
> constructors?

Actually, curLine will be "" be default. BTW, is there some reason curLine
is a reference? I would think a normal "std::string curLine" would make
more sense. If you are using a reference for some reason, remember that
you will have to bind it to an actual variable in the constructor.

> Does my redefining of getline() cause problems?

Maybe yes, maybe no. Given that I've been programming C++ for N years and
have no idea what that might do, I would stay away from it. It could be
very problematic, especially when ported to different implementations of
iostreams.

Something like so (this assumes istream's constructor takes no args,
something which I really can't remember either way) handles your original
problem:

configStreamTy::configStreamTy() : curLine("INITIAL STRING"), istream() {}

> Oh the other thing is --- am I reinventing the wheel?  Is there a C++
> library out there that does all this?

Yes. I don't know what it's called but I'd bet anything at least 3 or 4
really good libraries doing this already exist. BTW, anyone know if there
is a C++ wrapper to libxml? If not, you might consider wrapping that - XML
provides a lot of what you're doing here in a more extensible and portable
framework. But of course coding this would be good practice with string
manipulation, design, etc. Whether that is worth your time or not...
<shrug> Up to you.

J






More information about the tuxCPProgramming mailing list