cgul_stanza.h File Reference

get arbitrary stanzas of key/value pairs from a text file More...

#include "cgul_common.h"
#include "cgul_crlf_file.h"
#include "cgul_exception.h"
#include "cgul_rbtree.h"
#include "cgul_vector.h"
Include dependency graph for cgul_stanza.h:
This graph shows which files directly or indirectly include this file:

Typedefs

typedef typedefCGUL_BEGIN_C struct cgul_stanza * cgul_stanza_t
 

Functions

CGUL_EXPORT cgul_stanza_t cgul_stanza__new (cgul_exception_t *cex)
 
CGUL_EXPORT cgul_stanza_t cgul_stanza__new_from_fname (cgul_exception_t *cex, const char *fname, int is_block_buffered)
 
CGUL_EXPORT cgul_stanza_t cgul_stanza__new_from_file (cgul_exception_t *cex, FILE *f, int is_block_buffered)
 
CGUL_EXPORT cgul_stanza_t cgul_stanza__new_from_memory (cgul_exception_t *cex, const char *buf, size_t buf_size)
 
CGUL_EXPORT cgul_stanza_t cgul_stanza__new_from_crlf_file (cgul_exception_t *cex, cgul_crlf_file_t crlf_file)
 
CGUL_EXPORT void cgul_stanza__delete (cgul_stanza_t stanza)
 
CGUL_EXPORT void cgul_stanza__open_fname (cgul_exception_t *cex, cgul_stanza_t stanza, const char *fname, int is_block_buffered)
 
CGUL_EXPORT void cgul_stanza__open_file (cgul_exception_t *cex, cgul_stanza_t stanza, FILE *f, int is_block_buffered)
 
CGUL_EXPORT void cgul_stanza__open_memory (cgul_exception_t *cex, cgul_stanza_t stanza, const char *buf, size_t buf_size)
 
CGUL_EXPORT void cgul_stanza__open_crlf_file (cgul_exception_t *cex, cgul_stanza_t stanza, cgul_crlf_file_t crlf_file)
 
CGUL_EXPORT void cgul_stanza__close (cgul_exception_t *cex, cgul_stanza_t stanza)
 
CGUL_EXPORT const char * cgul_stanza__get_fname (cgul_exception_t *cex, cgul_stanza_t stanza)
 
CGUL_EXPORT void cgul_stanza__all_one_stanza (cgul_exception_t *cex, cgul_stanza_t stanza, int all_one_stanza)
 
CGUL_EXPORT void cgul_stanza__allow_duplicate_keys (cgul_exception_t *cex, cgul_stanza_t stanza, int allow_duplicate_keys)
 
CGUL_EXPORT void cgul_stanza__set_allowed_keys (cgul_exception_t *cex, cgul_stanza_t stanza, cgul_rbtree_t allowed_keys)
 
CGUL_EXPORT void cgul_stanza__set_mandatory_keys (cgul_exception_t *cex, cgul_stanza_t stanza, cgul_rbtree_t mandatory_keys)
 
CGUL_EXPORT int cgul_stanza__load_next (cgul_exception_t *cex, cgul_stanza_t stanza)
 
CGUL_EXPORT const char * cgul_stanza__lookup (cgul_exception_t *cex, cgul_stanza_t stanza, const char *key)
 
CGUL_EXPORT char * cgul_stanza__take_value (cgul_exception_t *cex, cgul_stanza_t stanza, const char *key)
 
CGUL_EXPORT cgul_rbtree_t cgul_stanza__get_tree (cgul_exception_t *cex, cgul_stanza_t stanza)
 
CGUL_EXPORT cgul_rbtree_t cgul_stanza__take_tree (cgul_exception_t *cex, cgul_stanza_t stanza)
 
void cgul_stanza__clear_tree (cgul_exception_t *cex, cgul_rbtree_t tree)
 
CGUL_EXPORT const char * cgul_stanza__lookup_tree (cgul_exception_t *cex, cgul_rbtree_t tree, const char *key)
 
CGUL_EXPORT cgul_vector_t cgul_stanza__get_keys (cgul_exception_t *cex, cgul_stanza_t stanza)
 
CGUL_EXPORT cgul_vector_t cgul_stanza__copy_keys (cgul_exception_t *cex, cgul_stanza_t stanza)
 
CGUL_EXPORT unsigned long int cgul_stanza__get_line_number (cgul_exception_t *cex, cgul_stanza_t stanza)
 
CGUL_EXPORT int cgul_stanza__is_blank_line (cgul_exception_t *cex, const char *line, size_t line_length)
 
CGUL_EXPORT int cgul_stanza__is_comment_line (cgul_exception_t *cex, const char *line, size_t line_length)
 
CGUL_EXPORT void cgul_stanza__split_line (cgul_exception_t *cex, const char *line, size_t line_length, const char *fname, unsigned long int line_count, char **key, char **value)
 
CGUL_EXPORT void cgul_stanza__print (cgul_exception_t *cex, FILE *f, const char *key, const char *value)
 

Detailed Description

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.

The basic skeleton for using it in this mode is as follows where cgul_stanza__load_next() loads the next hash:

    stanza = cgul_stanza__new_from_fname(cex, fname);
    while (cgul_stanza__load_next(cex, stanza)) {
        value1 = cgul_stanza__lookup(cex, stanza, key1);
        value2 = cgul_stanza__lookup(cex, stanza, 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 = cgul_stanza__new_from_fname(cex, fname);
    cgul_stanza__all_one_stanza(cex, stanza, 1);
    cgul_stanza__load_next(cex, stanza);
    value1 = cgul_stanza__lookup(cex, stanza, key1);
    value2 = cgul_stanza__lookup(cex, stanza, 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 = cgul_stanza__new_from_fname(cex, fname);
    cgul_stanza__all_one_stanza(cex, stanza, 1);
    cgul_stanza__load_next(cex, stanza);
    options = cgul_stanza__take_tree(cex, stanza);
    cgul_stanza__close(cex, stanza);
    ...
    // Lookup options at a later time.
    value1 = cgul_stanza__lookup_tree(cex, options, key1);
    value2 = cgul_stanza__lookup_tree(cex, options, key2);
    ...
Note
Any horizontal white space before the key is stripped and does not become part of the key.
Note
Any vertical white space after the key denotes the end of the stanza unless cgul_stanza__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 cgul_stanza__all_one_stanza() is to provide a conventional configuration file with comments above each entry and vertical white space below.
Note
The first space between the colon and the value is optional. All subsequent space is considered to be part of the value.
Note
This class can handle multi-line text. Just make sure the "key" for subsequent lines is a "+" character. You can use cgul_stanza__print() to make sure multi-line key/value pairs are printed correctly.
Note
This class is intentionally designed to avoid having escape sequences.
Note
This class automatically handles DOS, Mac, and Unix text files.
Author
Paul Serice

Typedef Documentation

§ cgul_stanza_t

typedef typedefCGUL_BEGIN_C struct cgul_stanza* cgul_stanza_t

Opaque pointer to a cgul_stanza instance.

Function Documentation

§ cgul_stanza__new()

CGUL_EXPORT cgul_stanza_t cgul_stanza__new ( cgul_exception_t cex)

Create a new cgul_stanza 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 calling cgul_stanza__delete(). If memory cannot be allocated, NULL is returned, and an exception is thrown.

Parameters
[in,out]cexc-style exception
Returns
new cgul_stanza instance

Referenced by cgul_stanza_cxx::cgul_stanza_cxx().

§ cgul_stanza__new_from_fname()

CGUL_EXPORT cgul_stanza_t cgul_stanza__new_from_fname ( cgul_exception_t cex,
const char *  fname,
int  is_block_buffered 
)

Create a new cgul_stanza object and call cgul_stanza__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_block_buffered should be set to false. The client is responsible for freeing the object by calling cgul_stanza__delete(). If an error occurs, NULL is returned, and an exception is thrown.

Parameters
[in,out]cexc-style exception
[in]fnamefile name of stanza file
[in]is_block_bufferedwhether fname is block buffered
Returns
new cgul_stanza instance

Referenced by cgul_stanza_cxx::cgul_stanza_cxx().

§ cgul_stanza__new_from_file()

CGUL_EXPORT cgul_stanza_t cgul_stanza__new_from_file ( cgul_exception_t cex,
FILE *  f,
int  is_block_buffered 
)

Create a new cgul_stanza object and call cgul_stanza__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. The client is responsible for freeing the object by calling cgul_stanza__delete(). If an error occurs, NULL is returned, and an exception is thrown.

Parameters
[in,out]cexc-style exception
[in]ffile
[in]is_block_bufferedwhether f is block buffered
Returns
new cgul_stanza instance

Referenced by cgul_stanza_cxx::cgul_stanza_cxx().

§ cgul_stanza__new_from_memory()

CGUL_EXPORT cgul_stanza_t cgul_stanza__new_from_memory ( cgul_exception_t cex,
const char *  buf,
size_t  buf_size 
)

Create a new cgul_stanza object and call cgul_stanza__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 cgul_stanza__delete(). If an error occurs, NULL is returned, and an exception is thrown.

Parameters
[in,out]cexc-style exception
[in]bufmemory buffer
[in]buf_sizesize of buf in bytes
Returns
new cgul_stanza instance

Referenced by cgul_stanza_cxx::cgul_stanza_cxx().

§ cgul_stanza__new_from_crlf_file()

CGUL_EXPORT cgul_stanza_t cgul_stanza__new_from_crlf_file ( cgul_exception_t cex,
cgul_crlf_file_t  crlf_file 
)

Create a new cgul_stanza object and call cgul_stanza__open_crlf_file() passing it crlf_file. This makes it possible to read from any file type supported by cgul_crlf_file like memory for example. The client is responsible for freeing the object returned by calling cgul_stanza__delete(). If an error occurs, NULL is returned, and 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 cgul_crlf_file__delete() on it.

Parameters
[in,out]cexc-style exception
[in]crlf_fileinterface used for reading lines of text
Returns
new cgul_stanza instance

Referenced by cgul_stanza_cxx::cgul_stanza_cxx().

§ cgul_stanza__delete()

CGUL_EXPORT void cgul_stanza__delete ( cgul_stanza_t  stanza)

This method closes the file opened when cgul_stanza__new_from_fname() or cgul_stanza__open_fname() was called and frees all internally allocated resources. Do not try to access stanza after calling this method.

Parameters
[in]stanzacgul_stanza instance

Referenced by cgul_stanza_cxx::set_obj(), and cgul_stanza_cxx::~cgul_stanza_cxx().

§ cgul_stanza__open_fname()

CGUL_EXPORT void cgul_stanza__open_fname ( cgul_exception_t cex,
cgul_stanza_t  stanza,
const char *  fname,
int  is_block_buffered 
)

Open the file with name fname so that cgul_stanza__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.

Parameters
[in,out]cexc-style exception
[in]stanzacgul_stanza instance
[in]fnamefile name
[in]is_block_bufferedwhether f is block buffered

Referenced by cgul_stanza_cxx::open_fname().

§ cgul_stanza__open_file()

CGUL_EXPORT void cgul_stanza__open_file ( cgul_exception_t cex,
cgul_stanza_t  stanza,
FILE *  f,
int  is_block_buffered 
)

Open f so that cgul_stanza__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.

Parameters
[in,out]cexc-style exception
[in]stanzacgul_stanza instance
[in]ffile
[in]is_block_bufferedwhether f is block buffered

Referenced by cgul_stanza_cxx::open_file().

§ cgul_stanza__open_memory()

CGUL_EXPORT void cgul_stanza__open_memory ( cgul_exception_t cex,
cgul_stanza_t  stanza,
const char *  buf,
size_t  buf_size 
)

Open buf so that cgul_stanza__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.

Parameters
[in,out]cexc-style exception
[in]stanzacgul_stanza instance
[in]bufmemory buffer
[in]buf_sizesize of buf in bytes

Referenced by cgul_stanza_cxx::open_memory().

§ cgul_stanza__open_crlf_file()

CGUL_EXPORT void cgul_stanza__open_crlf_file ( cgul_exception_t cex,
cgul_stanza_t  stanza,
cgul_crlf_file_t  crlf_file 
)

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 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 cgul_crlf_file__delete() on it.

Parameters
[in,out]cexc-style exception
[in]stanzacgul_stanza instance
[in]crlf_fileinterface used for reading lines of text

Referenced by cgul_stanza_cxx::open_crlf_file().

§ cgul_stanza__close()

CGUL_EXPORT void cgul_stanza__close ( cgul_exception_t cex,
cgul_stanza_t  stanza 
)

This method closes stanza. After calling this method, an input source should be opened before calling any other method.

Parameters
[in]cexc-style exception
[in]stanzacgul_stanza instance

Referenced by cgul_stanza_cxx::close().

§ cgul_stanza__get_fname()

CGUL_EXPORT const char* cgul_stanza__get_fname ( cgul_exception_t cex,
cgul_stanza_t  stanza 
)

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.

Parameters
[in,out]cexc-style exception
[in]stanzacgul_stanza instance
Returns
file name

Referenced by cgul_stanza_cxx::get_file_name().

§ cgul_stanza__all_one_stanza()

CGUL_EXPORT void cgul_stanza__all_one_stanza ( cgul_exception_t cex,
cgul_stanza_t  stanza,
int  all_one_stanza 
)

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 cgul_stanza__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 cgul_stanza__load_next().

If you set all_one_stanza, you will typically also want to call cgul_stanza__take_tree(). This lets you get the results of reading the file so that you can continue to use it. You can then call cgul_stanza__delete() in order to close the file immediately.

Calls to cgul_stanza__close() do not alter whether the file is treated as all one stanza.

Parameters
[in]cexc-style exception
[in]stanzacgul_stanza instance
[in]all_one_stanzawhether the file is all one stanza

Referenced by cgul_stanza_cxx::all_one_stanza().

§ cgul_stanza__allow_duplicate_keys()

CGUL_EXPORT void cgul_stanza__allow_duplicate_keys ( cgul_exception_t cex,
cgul_stanza_t  stanza,
int  allow_duplicate_keys 
)

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. Calls to cgul_stanza__close() do not whether duplicate keys are allowed.

Parameters
[in]cexc-style exception
[in]stanzacgul_stanza instance
[in]allow_duplicate_keyswhether to allow duplicate keys

Referenced by cgul_stanza_cxx::allow_duplicate_keys().

§ cgul_stanza__set_allowed_keys()

CGUL_EXPORT void cgul_stanza__set_allowed_keys ( cgul_exception_t cex,
cgul_stanza_t  stanza,
cgul_rbtree_t  allowed_keys 
)

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.

If cgul_stanza__close() is called, the allowed keys are not automatically reset to NULL. In this case, if you want to restore the default behavior, this method must explicitly be called with allowed_keys set to NULL. Thus, if the default behavior is not restored, allowed_keys must remain in scope across calls to cgul_stanza__close().

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:

    allowed_keys = cgul_rbtree__new(cex, (cgul_rbtree__compare_t)strcmp);
    cgul_rbtree__insert(cex, allowed_keys, "foo", NULL);
    cgul_rbtree__insert(cex, allowed_keys, "bar", NULL);
    cgul_rbtree__insert(cex, allowed_keys, "baz", NULL);
    if (cex) {
        goto out;
    }
Parameters
[in]cexc-style exception
[in]stanzacgul_stanza instance
[in]allowed_keyslist of allowed keys

Referenced by cgul_stanza_cxx::set_allowed_keys().

§ cgul_stanza__set_mandatory_keys()

CGUL_EXPORT void cgul_stanza__set_mandatory_keys ( cgul_exception_t cex,
cgul_stanza_t  stanza,
cgul_rbtree_t  mandatory_keys 
)

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.

If cgul_stanza__close() is called, the mandatory keys are not automatically reset to NULL. In this case, if you want to restore the default behavior, this method must explicitly be called with mandatory_keys set to NULL. Thus, if the default behavior is not restored, mandatory_keys must remain in scope across calls to cgul_stanza__close().

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:

    mandatory_keys = cgul_rbtree__new(cex, (cgul_rbtree__compare_t)strcmp);
    cgul_rbtree__insert(cex, mandatory_keys, "foo", NULL);
    cgul_rbtree__insert(cex, mandatory_keys, "bar", NULL);
    cgul_rbtree__insert(cex, mandatory_keys, "baz", NULL);
    if (cex) {
        goto out;
    }
Parameters
[in]cexc-style exception
[in]stanzacgul_stanza instance
[in]mandatory_keyslist of mandatory keys

Referenced by cgul_stanza_cxx::set_mandatory_keys().

§ cgul_stanza__load_next()

CGUL_EXPORT int cgul_stanza__load_next ( cgul_exception_t cex,
cgul_stanza_t  stanza 
)

This method loads the next stanza. The client can use cgul_stanza__lookup() or cgul_stanza__take_value() to lookup the value given the key or cgul_stanza__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, 0 is returned, and an exception is thrown.

Parameters
[in,out]cexc-style exception
[in]stanzacgul_stanza instance
Returns
whether EOF was not reached

Referenced by cgul_stanza_cxx::load_next().

§ cgul_stanza__lookup()

CGUL_EXPORT const char* cgul_stanza__lookup ( cgul_exception_t cex,
cgul_stanza_t  stanza,
const char *  key 
)

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 cgul_stanza__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 cgul_stanza__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 cgul_stanza__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.

Parameters
[in,out]cexc-style exception
[in]stanzacgul_stanza instance
[in]keykey
Returns
value associated with key

Referenced by cgul_stanza_cxx::lookup().

§ cgul_stanza__take_value()

CGUL_EXPORT char* cgul_stanza__take_value ( cgul_exception_t cex,
cgul_stanza_t  stanza,
const char *  key 
)

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 cgul_stanza__lookup() instead allowing the cgul_stanza 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 cgul_stanza__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.

Parameters
[in,out]cexc-style exception
[in]stanzacgul_stanza instance
[in]keykey
Returns
value associated with key

Referenced by cgul_stanza_cxx::take_value().

§ cgul_stanza__get_tree()

CGUL_EXPORT cgul_rbtree_t cgul_stanza__get_tree ( cgul_exception_t cex,
cgul_stanza_t  stanza 
)

This method returns the internal cgul_rbtree that is used to hold all the key/value pairs of the current stanza. The client typically only needs to get the tree once. It will not be invalidated until cgul_stanza__take_tree() or cgul_stanza__delete() is called.

Both the keys and the values in the tree are char* types.

The client must not alter the keys in the tree that is returned, but the client is free to take ownership of the values provided the client notifies this class that ownership has been transfered by setting the corresponding value in the tree to NULL. The client must call free() on any pointer taken.

Note that you can use cgul_stanza__lookup_tree() to perform looks directly using the value returned.

Parameters
[in]cexc-style exception
[in]stanzacgul_stanza instance
Returns
tree of key/value pairs

§ cgul_stanza__take_tree()

CGUL_EXPORT cgul_rbtree_t cgul_stanza__take_tree ( cgul_exception_t cex,
cgul_stanza_t  stanza 
)

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__lookup_tree() to perform looks directly using the value returned.

Parameters
[in,out]cexc-style exception
[in]stanzacgul_stanza instance
Returns
tree of key/value pairs

Referenced by cgul_stanza_cxx::take_tree().

§ cgul_stanza__clear_tree()

void cgul_stanza__clear_tree ( cgul_exception_t cex,
cgul_rbtree_t  tree 
)

This method clears the tree by removing and freeing all key/value pairs. It does not free the tree itself. You still must call cgul_rbtree__delete() to do that. This method is really only relevant if cgul_stanza__take_tree() has been called.

Parameters
[in]cexc-style exception
[in]treetree to empty

Referenced by cgul_stanza_cxx::clear_tree().

§ cgul_stanza__lookup_tree()

CGUL_EXPORT const char* cgul_stanza__lookup_tree ( cgul_exception_t cex,
cgul_rbtree_t  tree,
const char *  key 
)

This method performs the same lookup as cgul_stanza__lookup() except it uses the cgul_rbtree returned by either cgul_stanza__get_tree()</code() or cgul_stanza__take_tree().

Parameters
[in]cexc-style exception
[in]treecgul_rbtree instance
[in]keykey
Returns
value associated with key

Referenced by cgul_stanza_cxx::lookup_tree().

§ cgul_stanza__get_keys()

CGUL_EXPORT cgul_vector_t cgul_stanza__get_keys ( cgul_exception_t cex,
cgul_stanza_t  stanza 
)

This method returns a cgul_vector that holds all the keys in this stanza in the exact order in which they appear in the file. If cgul_stanza__allow_duplicate_keys() has been called to allow duplicate keys, only the first occurrence of a key is stored in the vector.

The vector that is returned is owned by this class and must not be deleted by the caller. Also, the const char* elements of the vector are also owned by this class and must not be freed by the caller.

Furthermore, the const char* elements of the vector actually point to the keys that are owned by the main tree structure that is returned by cgul_stanza__get_tree() or cgul_stanza__take_tree(). Thus, if cgul_stanza__take_tree() is called, the caller is responsible for not calling cgul_stanza__get_keys() if the caller invalidates the keys in the tree.

It is possible to call this method just once to get the vector that holds the keys. Then each time cgul_stanza__load_next() is called, the vector will automatically be updated to reflect the keys in the new stanza.

This means the caller should use cgul_stanza__copy_keys() if the caller needs persistent copies of the keys for the current stanza.

It is also worth noting that it is probably more efficient in most cases to use cgul_stanza__get_tree() instead of using this method. The main reason this method exists is for those times when the caller needs to know the exact order in which the keys appear in the file.

Parameters
[in]cexc-style exception
[in]stanzacgul_stanza instance
Returns
vector of keys
See also
cgul_stanza__copy_keys()

§ cgul_stanza__copy_keys()

CGUL_EXPORT cgul_vector_t cgul_stanza__copy_keys ( cgul_exception_t cex,
cgul_stanza_t  stanza 
)

This method returns a cgul_vector that holds all the keys in this stanza in the exact order in which they appear in the file. If cgul_stanza__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 both free() on each elemnt of the vector and cgul_vector__delete() on the vector itself.

If an error occurs while creating the copy, an exception is thrown, and NULL is returned.

If possible cgul_stanza__get_keys() should be used instead of this method to avoid the overhead of having to copy and free the keys.

Parameters
[in,out]cexc-style exception
[in]stanzacgul_stanza instance
Returns
vector of keys
See also
cgul_stanza__get_keys()

Referenced by cgul_stanza_cxx::copy_keys().

§ cgul_stanza__get_line_number()

CGUL_EXPORT unsigned long int cgul_stanza__get_line_number ( cgul_exception_t cex,
cgul_stanza_t  stanza 
)

Get the line number where the current stanza starts. A return value of 0 means cgul_stanza__load_next() has not been called yet.

This method throws an exception only if an input source has not been opened yet.

Parameters
[in,out]cexc-style exception
[in]stanzacgul_stanza instance
Returns
line number

Referenced by cgul_stanza_cxx::get_line_number().

§ cgul_stanza__is_blank_line()

CGUL_EXPORT int cgul_stanza__is_blank_line ( cgul_exception_t cex,
const char *  line,
size_t  line_length 
)

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 file outside of this class.

Parameters
[in,out]cexc-style exception
[in]lineline
[in]line_lengthline length
Returns
whether the line is blank

Referenced by cgul_stanza_cxx::is_blank_line().

§ cgul_stanza__is_comment_line()

CGUL_EXPORT int cgul_stanza__is_comment_line ( cgul_exception_t cex,
const char *  line,
size_t  line_length 
)

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 file outside of this class.

Parameters
[in]cexc-style exception
[in]lineline
[in]line_lengthline length
Returns
whether the line is a comment

Referenced by cgul_stanza_cxx::is_comment_line().

§ cgul_stanza__split_line()

CGUL_EXPORT void cgul_stanza__split_line ( cgul_exception_t cex,
const char *  line,
size_t  line_length,
const char *  fname,
unsigned long int  line_count,
char **  key,
char **  value 
)

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 file outside of this class.

Parameters
[in,out]cexc-style exception
[in]lineline
[in]line_lengthline length
[in]line_countline in file (for error reporting)
[in]fnamefile name (for error reporting)
[out]keykey
[out]valuevalue

Referenced by cgul_stanza_cxx::split_line().

§ cgul_stanza__print()

CGUL_EXPORT void cgul_stanza__print ( cgul_exception_t cex,
FILE *  f,
const char *  key,
const char *  value 
)

This static method properly prints the key/value pair to the file f even if value is a multi-line string.

Parameters
[in,out]cexc-style exception
[in]ffile
[in]keykey
[in]valuevalue

Referenced by cgul_stanza_cxx::print().