class ref name: paramstring
category-group: strings
layer: 03
header file: z_paramstring.h

synopsis.
the paramstring_o class an a progamming aid designed to pass names and values of parameters around. This can be used in communicating simple data in a network or in passing parameter arguments to functions. A string_o is used to contain text that is formatted as a list of name-value pairs.

paramstring_o is a relatively old class. Other, similar classes have emerged, such as the name-value set object.

description.
The paramstring_o class gives a programmer an easy way to get a name-value pair, given a list of name-value pairs stored inside a string. The method of data storage used here is simpler and more primitive than, say data bags. No data structure information can be maintained in a paramstring object, since only a datum's name and its value is available. A paramstring_o can hold a set of name-value pairs. A typical string would look something like this:

"name0=value0 name1=value1 name2=value2 name13value3"

The class provides a methodology to cycle through the list, getting one data item at a time. This can be very useful for functions that take a long list of arguments, or where the data type is undetermined or irrelevant. Another application is to minimize the number of functions for a component with a long list of configuration options. This is the case with the [layer 11] 'mass mailer' object.

It can also be used for what James Coplien describes as "symbolic programming", or loosely typed data. Suppose you have a function with a long list of parameters:

    int function (int a, float b, char *s, int x, size_t len, int val);
The variables can be wrapped up into a paramstring_o:
    paramstring_o px = "a=5 b=\"3.1416\" s=\"Hello!\" len=45 val=8";
    function (px);
The function would unpack the paramstring object, much like a varargs function. The paramstring_o class maintains an internal pointer to the current key-value item being processed. Here is a quick example:
int function ()
{
    paramstring_o ps ("name=\"Jone Doe\" DOB=\"02/04/1996\" ssno=595-12-4445");
     
    for (ps.start(); ps.ok(); ps.eat())
    {
       std::cout << "name: " << ps.current_name  () << std::endl;
       std::cout << "valu: " << ps.current_value () << std::endl;
    }
}
 
// ALBERNATE NOTATION: "for (ps.get(0); ps.more(); ps.eat()) { /*..*/ }"
Note that get get() member function does not affect the object's notion of "current position", so calls to get() can be done inside a name-value walkthru (eg, inside the for loop in the example above). For loops like the one above, ok() should be used instead of more(). "more" tells if there is more data ahead, whereas "ok" tells if there is current data - that is, after a [succesful] "eat", there is data waiting to be 'consumed' by the application.

member functions (primary)

paramstring_o()
SIGNATURE: paramstring_o ()
SYNOPSIS: creates a a new paramstring object, completely devoid of contents.
 

paramstring_o(paramstring_o)
SIGNATURE: paramstring_o (const paramstring_o &rhs)
SYNOPSIS: creates a a new paramstring object; it is an exact image of the copied paramstring object 'rhs'.
 

operator = (paramstring_o)
SIGNATURE: const paramstring_o &operator = (const paramstring_o &)
SYNOPSIS:
copies exactly the RHS object. the resultant paramstring instance is the same as if the copy. this includes the state of the object, which in this case, includes a "current position" pointer.
 

destructor
SIGNATURE: ~paramstring_o ()
SYNOPSIS: virtual destructor. The instance, with all its data, is wiped out.
 

paramstring_o(<args>)
SIGNATURE: paramstring_o (const char *buf)
SYNOPSIS: create a new paramstring object. set the paramstring's contents to that of 'buf'.
 

paramstring_o(<args>)
SIGNATURE: paramstring_o (const string_o &s)
SYNOPSIS: create a new paramstring object. set the paramstring's contents to that of 's'.
 

assignment operator()
SIGNATURE: paramstring_o &operator = (const char *buf)
SYNOPSIS: assignment operator; assigns an existing paramstring object the contents of 'buf'.
 

assignment operator()
SIGNATURE: paramstring_o &operator = (const string_o &s)
SYNOPSIS: assignment operator; assigns an existing paramstring object the contents of string object 's'.
 

==()
SIGNATURE: int operator == (const paramstring_o &rhs) const
SYNOPSIS:
compares the contents of the object to that of 'rhs'. Does a simple string compare of the contents of the objects to test for equality.
RETURNS:
1: the objects are equivalent
0: the objects are different
 

!=()
SIGNATURE: int operator != (const paramstring_o &rhs) const
SYNOPSIS:
compares the contents of the object to that of 'rhs'. Does a simple string compare of the contents of the objects to test for inequality.
RETURNS:
1: the objects are different
0: the objects are equivalent
 

current_name()
SIGNATURE: const string_o &current_name () const
SYNOPSIS:
returns the name of the current key-value pair. This is used when the internal pointer has been set [use "get()" to start retrieval]. If there is no current item, an empty string ("") is returned.
 

current_value()
SIGNATURE: const string_o &current_value () const
SYNOPSIS:
returns the value of the current key-value pair. This is used when the internal pointer has been set [use "get()" to start retrieval]. If there is no current item, an empty string ("") is returned.
 

ok()
SIGNATURE: boolean ok () const
SYNOPSIS:
tells if there is a current item available that can be retrieved (either its name or value). Useful in loops to end the loop.
RETURNS:
TRUE: there is an object currently available
FALSE: no object is available - internal cursor has not been set, or out-of-bounds
 

more()
SIGNATURE: boolean more () const
SYNOPSIS:
this member function tells the caller if there is more data that can be fetched (eg, if there is more text beyond the current internal pointer-position). It ignores whether or not there is current data available (from the last start() or eat()), so it should not be used at the top of a while or in a for loop, else the last element will be overlooked (use ok() instaed).
The notion of current position translates to an internal pointer that tracks where in the string buffer the last processing left off. This is designed to be used in loops, to be used in conjunction with the get() and eat() member functions.
RETURNS:
TRUE: there is another name-value pair available ahead;
FALSE: no more name-value pairs available (currently at the last item, or empty).
 

operator ==()
SIGNATURE: int operator == (const paramstring_o &ps, const char *buf)
SYNOPSIS:
compares the contents of the object "ps" to that of the character array "buf". Does a simple string compare of the contents if they are equavalent.
 

operator ==()
SIGNATURE: int operator == (const char *buf, const paramstring_o &ps)
SYNOPSIS:
compares the contents of the object "ps" to that of the character array "buf". Does a simple string compare of the contents if they are equavalent. This "global" function provides for symmetry (transitive operation).
 

operator !=()
SIGNATURE: int operator != (const paramstring_o &ps, const char *buf)
SYNOPSIS:
compares the contents of the object "ps" to that of the character array "buf". Does a simple string compare of the contents if they are different.
 

set()
SIGNATURE: int set (const string_o &nam, const string_o &val, int *pi = NULL)
SYNOPSIS:
sets the current object to the given name-value pair specified by the first 2 parameters ('nam' and 'val). These parameters must have a legal syntax in order for this subroutine to succeed. If the call fails, the internal contents is unaffected. If it succeeds, any existing contents is over-written by the new value. Only 1 name-value pair can be set via this interface.
PARAMETERS

  • nam: the name used for the object's contents. The value of this string must be a legal "word", comprised of only letters, numbers, or underscore ('_').
  • val: The value component of the object. If the text of this string contains any non-word letter (including any whitespace), the entire string will be wrapped in double-quotes.
  • pi: output error indicator variable. values:
    0: object was successfully set
    1: syntax error - 'nam' is not a simple word
 

add_pair()
SIGNATURE: int add_pair(const string_o &nam, const string_o &val, int *pe = NULL)
SYNOPSIS: allows for adding an additional name-value pair to a paramstring_o.
PARAMETERS

  • nam: the name used for the name-value pair to be added. This string must be a legal "word", comprised of only letters, numbers, or underscore ('_').
  • val: The value component of the object. If the text of this string contains any non-word letter (including any whitespace), the entire string will be wrapped in double-quotes.
  • pi: output error indicator variable. values:
    0: object was successfully set
    1: syntax error - 'nam' is not a simple word
DESCRIPTION:
This routine is more robust than member function add_item(): you don't need to wrap up the items into a preformatted string, and you don't need to worry about checking that the value is not a "word". That is, this routine will wrap quotes around the value part if it is not a simple name, such as "[part1:tail]" or "".
This member function behaves just like function set(), except that it adds to, not replaces, any existing text.
 

add_item()
SIGNATURE: int add_item (const string_o &s, int *pe = NULL)
SYNOPSIS:
allows for adding an additional name-value pair to a paramstring_o. The contents of "s" must be of format "name=value" in order for this function to succeed.
 

set_delimeter()
SIGNATURE: int set_delimeter (const string_o &s, int *pe = NULL)
SYNOPSIS: sets the delimiter (character sequence separating name-value pairs) to that specified by "s".
TRAITS: User-modifiable delimiters are CURRENTLY BROKEN. The current delimiter is whitespace. DO NOT USE this function!
 

operator +=()
SIGNATURE: int operator += (const char *buf)
SYNOPSIS:
allows for adding an additional name-value pair to a paramstring_o. Please see the member function "add_item()" for format information.
 

operator +=()
SIGNATURE: int operator += (const string_o &s)
SYNOPSIS:
allows for adding an additional name-value pair to a paramstring_o. Please see the member function "add_item()" for format information.
 

operator +=()
SIGNATURE: int operator += (const paramstring_o &rhs)
SYNOPSIS: this simply concatenates the 2 parameter string objects.
 

operator +()
SIGNATURE: paramstring_o operator + (const paramstring_o &rhs)
SYNOPSIS:
concatenates the current object (LHS) with that of "rhs", and returns a new object containing the concatenated string. The current (left hand) object's contents is unaffected.
 

reset()
SIGNATURE: int reset ()
SYNOPSIS: resets the current object. All state and internal contents are destroyed.
 

start()
SIGNATURE: int start ()
SYNOPSIS:
resets the internal pointer to the first value (if any). Use this prior to calling more() or eat(). Useful in loops to start the loop.
RETURNS:
0: successfully pre-loaded the 1st name and value
1: no data available
 

eat()
SIGNATURE: int eat ()
SYNOPSIS:
advances the pointer to the next key-value pair. The pointer should be initialized with the "get()" operation. YOu can think of "eat" "munching" on the internal string buffer, extracting the next name-value pair. actually, it doesn't modify buffer at all, but just advances an internal pointer to the next name-value pair.
RETURNS:
0: there is an object currently available after this operation
-1: no more objects available / out of bounds
 

get()
SIGNATURE: int get (count_t n)
SYNOPSIS: gets the nth key-value pair, starting with 0 as the 1st item. Does not affect the object's internal pointer.
RETURNS:
0: operation succeeded; there is an object currently available after this operation.
-1: no more objects available / out of bounds.
 

get()
SIGNATURE: const string_o &get (const string_o &s, int *pe)
SYNOPSIS: sets the internal pointer to the name-value pair whos name matches that of "s".
RETURNS:
0: operation succeeded; there is an object currently available after this operation
-1: no more objects available / out of bounds
 

operator +()
SIGNATURE: paramstring_o operator + (const char *buf, const paramstring_o &ps)
SYNOPSIS:
compares the contents of the object "ps" to that of the character array "buf". Does a simple string compare of the contents if they are different.
 

operator <<()
SIGNATURE: std::ostream &operator << (std::ostream &x, const paramstring_o &ps)
SYNOPSIS: dumps the contents of "ps" to the ostream "x", as a character array
 

note.
There is no hard requirement that a paramstring object must contain a list of (eg, more than 1) name-value pairs. If preferred, one data item per paramstring_o can be used, and a group of paramstring objects, each with 1 item, can represent the data (this is done in the inifile object).

If there are spaces in the value part of the data, the entire value substring must be enclosed in quotes:

"name0=\"Jane Doe\" name1=\"Herbert Hoover\" name2=value2"

There could be many alternativew for the name of this class - it could just as easy have been something involving the words "name", "key", "value", or "variable", for instance. The choice of the word "parameter" stems from the intended usage of this as a function argument in the "symbolic programming" context.

examples.
the following sliver is a tiny, but compete program. It was taken from an actual live working part of the the Z Directory, emailheader_o::set_parameters, and reworked into a working program. In this case, it simply prints out the name-value pairs to the console. This program will produce the following output:

name: proto
valu: TCP
.......................
name: version
valu: "1.5"
.......................
name: CRC
valu: 8920
.......................
name: remarks
valu: "a simple test."
.......................

#include "z_paramstring.h"
int set_values (const paramstring_o &);

void main ()
{
    paramstring_o my_list = "proto=TCP version=\"1.5\" CRC=8920 remarks=\"a simple test.\"";
    set_values (my_list);
}

int set_values (const paramstring_o &new_ps)
{
    paramstring_o ps(new_ps);                   // copy the const var to internal

    for (ps.start(); ps.ok(); ps.eat())
    {
        string_o nam = ps.current_name();       // get the current pair's name
        textstring_o sval = ps.current_value(); // & get the current value
        if (!z_is_str_valid_name(sval.data()))  // for shucks, add quotes
            sval.wrap_quotes();

        std::cout << "name: " << nam  << std::endl;
        std::cout << "valu: " << sval << std::endl;
        std::cout << ".......................\n";
    }

    return 0;
}

bugs.
This class is intended to be highly configurable. Currently, all key-value pairs must be separated by whitespace (ie, a blank). In the future, you should be able to set your own delimiter, so that you can define key-value strings to look like, say:

"name0=value0,name1=value1,name2=value2,name13value3"
Or:

"name0=value0|)(|name1=value1|)(|name2=value2|)(|name13value3"