C++ bindings for cgul_stanza
More...
#include <cgul_stanza_cxx.h>
Public Member Functions | |
cgul_stanza_cxx () | |
cgul_stanza_cxx (const char *fname, bool is_block_buffered=true) | |
cgul_stanza_cxx (FILE *f, bool is_block_buffered=true) | |
cgul_stanza_cxx (const char *buf, size_t buf_size) | |
cgul_stanza_cxx (cgul_crlf_file_cxx &crlf_file) | |
cgul_stanza_cxx (cgul_crlf_file_cxx *crlf_file) | |
cgul_stanza_cxx (cgul_stanza_t rhs) | |
virtual | ~cgul_stanza_cxx () |
virtual void | close () |
virtual void | open_fname (const char *fname, bool is_block_buffered=true) |
virtual void | open_file (FILE *f, bool is_block_buffered=true) |
virtual void | open_memory (const char *buf, size_t buf_size) |
virtual void | open_crlf_file (cgul_crlf_file_cxx &crlf_file) |
virtual void | open_crlf_file (cgul_crlf_file_cxx *crlf_file) |
virtual const char * | get_file_name () const |
virtual void | all_one_stanza (int all_one_stanza) |
virtual void | allow_duplicate_keys (int allow_duplicate_keys) |
virtual void | set_allowed_keys (cgul_rbtree_cxx *allowed_keys) |
virtual void | set_mandatory_keys (cgul_rbtree_cxx *mandatory_keys) |
virtual int | load_next () |
virtual const char * | lookup (const char *key) const |
virtual char * | take_value (const char *key) const |
virtual cgul_rbtree_cxx * | take_tree () |
virtual cgul_vector_cxx * | copy_keys () |
virtual unsigned long int | get_line_number () const |
virtual cgul_stanza_t | get_obj () const |
virtual cgul_stanza_t | take_obj () |
virtual void | set_obj (cgul_stanza_t rhs) |
Static Public Member Functions | |
static void | clear_tree (cgul_rbtree_cxx *tree) |
static const char * | lookup_tree (cgul_rbtree_cxx *tree, const char *key) |
static int | is_blank_line (const char *line, size_t line_length) |
static int | is_comment_line (const char *line, size_t line_length) |
static void | split_line (const char *line, size_t line_length, const char *fname, unsigned long int line_count, char **key, char **value) |
static void | print (FILE *f, const char *key, const char *value) |
This class provides the C++ bindings for C cgul_stanza
objects. The main purpose of this class is to convert the C-style function calls and exception handling in cgul_stanza
into C++-style function calls and exception handling.
This class lets you get arbitrary stanzas of key/value pairs from a text file. This requires the text file to be in the following format:
# # Comments are lines that have a '#' character as the first # character that isn't white space. All other lines are # treated as key value pairs. #
# First stanza. key1: value1 key2: value2 key3: value3 (1st line) +: value3 (2nd line) +: value3 (3rd line)
# Second stanza. key1: value4 key2: value5 key3: value6
# Third stanza. key1: value7 key2: value8 key3: value9
# etc.
This class has two modes of operation. The first mode is when you have an array of hashes (or red-black trees). This intentionally matches the functionality of the XDR layer in RPC. So anything that can be sent between machines using RPC can be sent using cgul_stanza_cxx
.
The basic skeleton for using it in this mode is as follows where load_next()
loads the next hash:
stanza = new cgul_stanza_cxx(fname); while (stanza->load_next()) { value1 = stanza->lookup(key1); value2 = stanza->lookup(key2); ... }
The second mode is when you don't need the array feature. It's the mode to use for configuration files that a user is expected to edit. It has a lot of overlap with the first mode, and there isn't much difference for the programmer:
stanza = new cgul_stanza_cxx(fname); stanza->all_one_stanza(1); stanza->load_next(); value1 = stanza->lookup(key1); value2 = stanza->lookup(key2); ...
Because configuration options are usually long-lived, I also added the ability to "take" the internal tree so it can be queried at any time:
// Slurp all the options. stanza = new cgul_stanza_cxx(fname); stanza->all_one_stanza(1); stanza->load_next(); options = stanza->take_tree(); stanza->close(); ... // Lookup options at a later time. value1 = cgul_stanza::lookup_tree(options, key1); value2 = cgul_stanza::lookup_tree(options, key2); ...
all_one_stanza()
is used to force this class to treat the entire file as one stanza thereby allowing vertical white space between keys in the same stanza. The main reason for enabling all_one_stanza()
is to provide a conventional configuration file with comments above each entry and vertical white space below. print()
to make sure multi-line key/value pairs are printed correctly.
|
inline |
This method creates a new cgul_csv_cxx
instance. After calling this method, an input source should be opened before calling any other method. The client is responsible for freeing the object by making sure the destructor gets called. If memory cannot be allocated, an exception is thrown.
References cgul_stanza__new().
Referenced by set_obj().
|
inline |
Create a new cgul_stanza_cxx
object and call open_fname()
passing it fname
. This method opens fname
so that input can be read from it. For regular files, is_block_buffered
should be set to true; for character-oriented or line-oriented files, is_bleock_buffered
should be set to false. If an error occurs, an exception is thrown.
[in] | fname | file name of stanza file |
[in] | is_block_buffered | whether fname is block buffered |
References cgul_stanza__new_from_fname().
|
inline |
Create a new cgul_stanza_cxx
object and call open_file()
passing it f
. This method uses f
when reading input. This class does not take ownership of f
. Thus, the client is still responsible for calling fclose()
on f
. For regular files, is_block_buffered
should be set to true; for character-oriented or line-oriented files, is_block_buffered
should be set to false. If an error occurs, an exception is thrown.
[in] | f | file |
[in] | is_block_buffered | whether f is block buffered |
References cgul_stanza__new_from_file().
|
inline |
Create a new cgul_stanza_cxx
object and call open_memory()
passing it buf
and buf_size
. This method uses buf
when reading input. This class does not take ownership of buf
. Thus, the client is still responsible for calling free()
on buf
if necessary. The client is responsible for freeing the object by calling delete
if necessary. If an error occurs, an exception is thrown.
[in] | buf | memory buffer |
[in] | buf_size | size of buf in bytes |
References cgul_stanza__new_from_memory().
|
inline |
Create a new cgul_stanza_cxx
object and call open_crlf_file()
passing it crlf_file
. This makes it possible to read from any file type supported by cgul_crlf_file_cxx
like memory for example. If an error occurs, an exception is thrown.
The crlf_file
object is used as the interface for reading lines of text from a data source. It should already be initialized before calling this method. This class does not take ownership of crlf_file
so the client is still responsible for calling delete
on it if necessary.
[in] | crlf_file | interface used for reading lines of text |
References cgul_stanza__new_from_crlf_file(), and cgul_crlf_file_cxx::get_obj().
|
inline |
Create a new cgul_stanza_cxx
object and call open_crlf_file()
passing it crlf_file
. This makes it possible to read from any file type supported by cgul_crlf_file_cxx
like memory for example. If an error occurs, an exception is thrown.
The crlf_file
object is used as the interface for reading lines of text from a data source. It should already be initialized before calling this method. This class does not take ownership of crlf_file
so the client is still responsible for calling delete
on it if necessary.
[in] | crlf_file | interface used for reading lines of text |
References cgul_stanza__new_from_crlf_file(), and cgul_crlf_file_cxx::get_obj().
|
inline |
Create a new cgul_stanza_cxx
object by wrapping an existing cgul_stanza
object.
[in] | rhs | right-hand side |
|
inlinevirtual |
This method destruct the object by closing the file opened by the constructor and free all internally allocated resources.
References cgul_stanza__delete().
|
inlinevirtual |
This method closes the object. After calling this method, an input source should be opened before calling any other method.
References cgul_stanza__close().
|
inlinevirtual |
Open the file with name fname
so that load_next()
can be called. If an input source is already open, it will be closed before this method attempts to open the new source. The new file will be closed when this instance is deleted. For regular files, is_block_buffered
should be set to true; for character-oriented or line-oriented files, is_block_buffered
should be set to false. If an error occurs, an exception is thrown.
[in] | fname | file name |
[in] | is_block_buffered | whether f is block buffered |
References cgul_stanza__open_fname().
|
inlinevirtual |
Open f
so that load_next()
can be called. If an input source is already open, it will be closed before this method attempts to open the new source. This class does not take ownership of f
. Thus, the client is still responsible for calling fclose()
on f
. For regular files, is_block_buffered
should be set to true; for character-oriented or line-oriented files, is_block_buffered
should be set to false. If an error occurs, an exception is thrown.
[in] | f | file |
[in] | is_block_buffered | whether f is block buffered |
References cgul_stanza__open_file().
|
inlinevirtual |
Open buf
so that load_next()
can be called. If an input source is already open, it will be closed before this method attempts to open the new source. This class does not take ownership of buf
. Thus, the client is still responsible for calling free()
on buf
if necessary. If an error occurs, an exception is thrown.
[in] | buf | memory buffer |
[in] | buf_size | size of buf in bytes |
References cgul_stanza__open_memory().
|
inlinevirtual |
Open crlf_file
so that input can be read from it. This makes it possible to read from any file type supported by cgul_crlf_file_cxx
like memory for example. If an input source is already open, it will be closed before this method attempts to open the new source. If an error occurs, an exception is thrown.
The crlf_file
object is used as the interface for reading lines of text from a data source. It should already be initialized before calling this method. This class does not take ownership of crlf_file
so the client is still responsible for calling delete
on it if necessary.
[in] | crlf_file | interface used for reading lines of text |
References cgul_stanza__open_crlf_file(), and cgul_crlf_file_cxx::get_obj().
|
inlinevirtual |
Open crlf_file
so that input can be read from it. This makes it possible to read from any file type supported by cgul_crlf_file_cxx
like memory for example. If an input source is already open, it will be closed before this method attempts to open the new source. If an error occurs, an exception is thrown.
The crlf_file
object is used as the interface for reading lines of text from a data source. It should already be initialized before calling this method. This class does not take ownership of crlf_file
so the client is still responsible for calling delete
on it if necessary.
[in] | crlf_file | interface used for reading lines of text |
References cgul_stanza__open_crlf_file(), and cgul_crlf_file_cxx::get_obj().
|
inlinevirtual |
Get the name of the currently open file. The client must not attempt to call free()
on the pointer returned. This method returns NULL
and throws an exception if a data source is not currently open.
References cgul_stanza__get_fname().
|
inlinevirtual |
This methods lets the client determine whether to treat the file as being all one stanza. By default this class treats empty lines as the separator between stanzas. Basically, this allows the file to be treat as an array of hashes where vertical white space separates each hash, and the client calls load_next()
to get the next hash.
When used in the default mode, vertical white space is not allowed between key/value pairs that are part of the same hash because the vertical white space indicates the end of one hash and the beginning of the next. This can be limiting when you just need to save configuration values because white space is traditionally allowed to separate key/value pairs under those circumstances.
If you call this method with all_one_stanza
set, it will treat the entire file as all one stanza. This allows you to use vertical white space to separate key/value pairs, and you can slurp the entire file with just one call to load_next()
.
If you set all_one_stanza
, you will typically also want to call take_tree()
. This lets you get the results of reading the file so that you can continue to use it. You can then delete the object in order to close the file immediately.
[in] | all_one_stanza | whether the file is all one stanza |
References cgul_stanza__all_one_stanza().
|
inlinevirtual |
This methods lets the client determine whether duplicate keys are allowed. By default, duplicate keys are not allowed. This means an exception is thrown whenever a duplicate key is found in the same stanza. If duplicate keys are allowed, the last key found is used to set the value. The values associated with the previous duplicate keys are silently ignored.
[in] | allow_duplicate_keys | whether to allow duplicate keys |
References cgul_stanza__allow_duplicate_keys().
|
inlinevirtual |
If this method is called with allowed_keys
not set to NULL
, this class will verify each key it encounters by making sure it exists in allowed_keys
before inserting it into the tree. If the key is not present in allowed_keys
, an exception will be thrown.
If this method is called with allowed_keys
set to NULL
the default behavior of allowing all keys is restored.
The distinction between the allowed_keys
list and the mandatory_keys
list is that the allowed_keys
list causes an exception to be thrown whenever an unexpected key is added to a stanza. The mandatory_keys
list causes an exception to be thrown whenever an expected key is missing from a stanza.
Note that it is perfectly legal, and often desirable, to use the same list for allowed_keys
and mandator_keys
. If you do this, you will specify exactly the format of each stanza.
Also note that you can specify optional tags by adding the optional tags to the allowed_keys
list but leaving them off of the mandatory_keys
list.
This class uses allowed_keys
directly without taking ownership and without making a copy of it. Thus, allowed_keys
must stay in scope while the client iterates over the file. Because this class does not take ownership of allowed_keys
, the client is still responsible for deleting it.
The following is an example of how to set up the list of allowed keys:
cgul_rbtree_cxx allowed_keys((cgul_rbtree__compare_t)strcmp); allowed_keys.insert("foo", NULL); allowed_keys.insert("bar", NULL); allowed_keys.insert("baz", NULL);
[in] | allowed_keys | list of allowed keys |
References cgul_stanza__set_allowed_keys(), and cgul_rbtree_cxx::get_obj().
|
inlinevirtual |
If this method is called with mandatory_keys
not set to NULL
, after reading each stanza in full, this class will verify that all mandatory keys are present. If any one of the mandatory keys is not present in the stanza, an exception will be thrown.
If this method is called with mandatory_keys
set to NULL
the default behavior of not verifying keys is restored.
The distinction between the allowed_keys
list and the mandatory_keys
list is that the allowed_keys
list causes an exception to be thrown whenever an unexpected key is added to a stanza. The mandatory_keys
list causes an exception to be thrown whenever an expected key is missing from a stanza.
Note that it is perfectly legal, and often desirable, to use the same list for allowed_keys
and mandator_keys
. If you do this, you will specify exactly the format of each stanza.
Also note that you can specify optional tags by adding the optional tags to the allowed_keys
list but leaving them off of the mandatory_keys
list.
This class uses mandatory_keys
directly without taking ownership and without making a copy of it. Thus, mandatory_keys
must stay in scope while the client iterates over the file. Because this class does not take ownership of mandatory_keys
, the client is still responsible for deleting it.
The following is an example of how to set up the list of mandatory keys:
cgul_rbtree_cxx mandatory_keys((cgul_rbtree__compare_t)strcmp); mandatory_keys.insert("foo", NULL); mandatory_keys.insert("bar", NULL); mandatory_keys.insert("baz", NULL);
[in] | mandatory_keys | list of mandatory keys |
References cgul_stanza__set_mandatory_keys(), and cgul_rbtree_cxx::get_obj().
|
inlinevirtual |
This method loads the next stanza. The client can use lookup()
or take_value()
to lookup the value given the key or get_tree()
to iterate over all key/value pairs. An input source must be opened before attempting to call this method. On success, 1
is returned. On EOF, 0
is returned. If an error occurs, an exception is thrown.
References cgul_stanza__load_next().
|
inlinevirtual |
This method returns the value associated with the key key
. The pointer returned is owned by this class and will be invalidated the next time load_next()
is called. If the key is not present in this stanza, NULL
is returned.
If the caller is going to make a copy of the value returned, it should probably use take_value()
instead which functions the same as this method except ownership is transfered to the caller thus avoiding a copy.
If you need more functionality than what is provided by this method, you can use get_tree()
and iterate over each key/value pair instead.
This method throws an exception only if an input source has not been opened yet.
[in] | key | key |
References cgul_stanza__lookup().
|
inlinevirtual |
This method returns the value associated with the key key
. Ownership of the pointer returned is transfered to the caller. Thus, the caller must arrange for free()
to be called on the pointer. If the key is not present in this stanza, NULL
is returned.
Note that once the value for a particular key has been taken, subsequent lookups on that key return NULL
for the value. In order to do otherwise would require making a copy of the value which would defeat the purpose of this method.
If the caller only needs to inspect the value, it should probably use lookup()
instead allowing the cgul_stanza_cxx
instance to retain ownership thereby guaranteeing that the pointer will be freed.
If you need more functionality than what is provided by this method, you can use get_tree()
and iterate over each key/value pair instead.
This method throws an exception only if an input source has not been opened yet.
[in] | key | key |
References cgul_stanza__take_value().
|
inlinevirtual |
This method returns the internal cgul_rbtree
that is used to hold all the key/value pairs of the current stanza.
The client is now responsible for making sure both cgul_stanza::clear_tree()
and cgul_rbtree::delete()
are called on the value returned.
When the current tree is taken, this class creates a new, empty tree to take its place. If an error occurs while attempting to create the new, empty tree, an exception is thrown, and NULL
is returned. In this case, ownership of the original tree stays with this class.
Note that you can use cgul_stanza_cxx::lookup_tree()
to perform looks directly using the value returned.
References cgul_stanza__take_tree().
|
inlinestatic |
This method clears the tree
by removing and freeing all key/value pairs. It does not free the tree itself. You still must call delete
to do that. This method is really only relevant if take_tree()
has been called. Note that this method is static
and should be called as cgul_stanza_cxx::clear_tree()
.
[in] | tree | tree to empty |
References cgul_stanza__clear_tree(), and cgul_rbtree_cxx::get_obj().
|
inlinestatic |
This method performs the same lookup as lookup()
except it uses the cgul_rbtree_cxx
pointer returned by either get_tree()</code()
or take_tree()
.
Note that this method is static
and should be called as cgul_stanza_cxx::lookup_tree()
.
[in] | tree | cgul_rbtree_cxx instance |
[in] | key | key |
References cgul_stanza__lookup_tree(), and cgul_rbtree_cxx::get_obj().
|
inlinevirtual |
This method returns a cgul_vector_cxx
that holds all the keys in this stanza in the exact order in which they appear in the file. If allow_duplicate_keys()
has been called to allow duplicate keys, only the first occurrence of a key is stored in the vector.
Each element of the vector that is returned is a char*
. The caller is responsible for calling free()
on each elemnt of the vector and for deleting the vector itself.
If an error occurs while creating the copy, an exception is thrown.
References cgul_stanza__copy_keys().
|
inlinevirtual |
Get the line number where the current stanza starts. A return value of 0
means load_next()
has not been called yet.
This method throws an exception only if an input source has not been opened yet.
References cgul_stanza__get_line_number().
|
inlinestatic |
This static method returns 1
if line
is empty or comprised of all white space; otherwise, it return 0
. This method is convenient when parsing a cgul_stanza_cxx
file outside of this class.
[in] | line | line |
[in] | line_length | line length |
References cgul_stanza__is_blank_line().
|
inlinestatic |
This static method returns 1
if line
is a comment line; otherwise, it returns 0
. A comment line is one that has a '#' character as the first character that isn't white space. This method is convenient when parsing a cgul_stanza_cxx
file outside of this class.
[in] | line | line |
[in] | line_length | line length |
References cgul_stanza__is_comment_line().
|
inlinestatic |
This static method splits line
into a key/value pair returning the key in *key
and the value in *value
if key
and value
are not NULL
respectively.
The caller is responsible for making sure free()
is called on both key
and value
which are both newly allocated. If an error occurs, an exception is thrown, and *key
and *value
are both set to NULL
.
This method assumes that line
is in the following format:
key: value
If fname
is not NULL
it will be used when reporting errors. If fname
is NULL
, "-" will be used instead. line_count
is also only used when reporting errors.
This method is convenient when parsing a cgul_stanza_cxx
file outside of this class.
[in] | line | line |
[in] | line_length | line length |
[in] | line_count | line in file (for error reporting) |
[in] | fname | file name (for error reporting) |
[out] | key | key |
[out] | value | value |
References cgul_stanza__split_line().
|
inlinestatic |
This static method properly prints the key/value pair to the file f
even if value
is a multi-line string.
[in] | f | file |
[in] | key | key |
[in] | value | value |
References cgul_stanza__print().
|
inlinevirtual |
Get the underlying cgul_stanza
object.
|
inlinevirtual |
Take the underlying cgul_stanza
object. This means the underlying object will not be deleted when the wrapper goes out of scope. Also, because you have taken the underlying object, no other methods should be called on this wrapper's instance. Lastly, after taking the underlying object, it is the caller's responsibility to delete the underlying object by calling cgul_stanza__delete()
.
|
inlinevirtual |
Set the new underlying object to rhs
. This causes the old underlying object to be deleted which invalidates any outstanding pointers to or iterators for the old underlying object.
This instance takes ownership of rhs
which means rhs
will be automatically deleted when the C++ wrapper is deleted. To prevent automatic deletion of rhs
, call take_obj()
when the C++ wrapper is no longer needed.
[in] | rhs | right-hand side |
References cgul_stanza__delete(), and cgul_stanza_cxx().