Ni_node Ni_GetChild( Ni_node restrict n, const char * restrict name, int name_len, int add_if_new, int * restrict added_out );
Searches for and creates child nodes.
n (in) should be the Ni_node whose immediate children you wish to search among and/or add to.
name (in) should point to a string containing the name of the node you wish to search for and/or add. Binary data (i.e. not just ASCII) is acceptable. Passing NULL is equivalent to passing "" (an empty string).
name_len (in) should be the length (in chars) of the name string (not including terminating null), or a negative integer. If negative, the length of name is calculated with strlen(), which obviously won't always work if name contains binary data.
add_if_new (in) should be a boolean flag of whether to add a node with the given name if the node isn't found. If nonzero, the node will be added if it doesn't already exist; if 0, this function will only search.
added_out (out) should point to an integer to fill with a boolean value of whether the node was added or preexisting, or be NULL (if NULL, this information is lost). When this function returns, if the value pointed to is nonzero, the returned node wasn't found but was added; if 0, the returned node already existed. It will always be 0 if add_if_new is 0.
If add_if_new was 0, returns the child Ni_node with the given name if it was found, or NULL if it wasn't found.
If add_if_new was nonzero, returns the child Ni_node with the given name if it was found or added, or NULL if it wasn't found and there was an error creating it.
Returns NULL if you pass NULL for n.
This function is multipurpose. Firstly, it's the way to find specifically named nodes, so you can get their value or otherwise manipulate them. Also, it's the only way to create new nodes in existing trees. (To create new trees, see Ni_New().) The dual nature of this function makes life easier on the programmer: you can just pretend all nodes you care about are always present in the tree, and this function will take care of creating them for you if they don't exist yet.
The only caveat to this is that newly created nodes have no value. If you rely on default values for nodes, you'll have to trap their creation with added_out and set the value to its default before you read it. This seemed more orthogonal to me than having this function accept a default value string to give the node if it's created.
This function isn't recursive. It only searches among and adds to n's immediate children. You'll have to implement your own recursion if you want to search the entire tree; see Ni_GetNextChild().
If add_if_new was 0, this function can't really fail: a NULL return value in this case simply means the node wasn't found. If add_if_new was nonzero, a NULL return value means first that the node wasn't found, and second that there was an error creating the node. Errors will probably occur only when realloc() fails to grow a buffer.
Adding nodes can be a fairly time-consuming operation. By default, when nodes are created their child hash table is allocated space for 32 children; a node's child hash table doubles in capacity when it's 3/4 full, and when this happens, it takes some time (O(n)) to grow and restructure the whole table. We're not talking a huge amount of time, but it's significant compared to the speed with which everything else in Nickel happens.