C API for Dervish Chains
Dervish provides an extensive API for chains. The following discussions details
each API and wherever appropriate, source code examples are included as well.
A word about handling errors in the C API: some of the C APIs return the DERVISH
RET_CODE, others return memory addresses, yet others return specific values
such as the TYPE of data on the chain. However, all API set a global variable
called g_shChainErrno to SH_SUCCESS on success, or on failure, they
set this variable to one of the error codes listed in
$DERVISH_DIR/include/dervish_msg.h. Usage of g_shChainErrno is comparable
to the usage of errno, the UNIX error reporting methodology. Users
coding in the C API level must check the value of
g_shChainErrno upon a return from one of the primitive functions in
order to make sure that the API did succeed.
All the following C functions, and the TCL extensions which use them assert
that the chain pointer passed in is non-NULL.
Descriptions of C API
Creation and Deletion
shChainNew
shChainDel
shChainDestroy
Miscellaneous Operations
shChainTypeSet
shChainTypeGet
shChainTypeDefine
shChainSize
shChainJoin
shChainCopy
shChainSort
shChainCursorNew
shChainCursorSet
shChainCursorDel
shChainCursorCount
shChainCursorCopy
Chain Maintenance (addition/removal/retreival/traversal)
shChainElementAddByPos
shChainElementRemByPos
shChainElementGetByPos
shChainElementTypeGetByPos
shChainElementAddByCursor
shChainElementRemByCursor
shChainElementTypeGetByCursor
shChainWalk
_______________________________________________________________________________
Allocate memory for a new chain and initialize it properly. The type
of chain desired is specified as well. If a heterogeneous chain is to be
created, a type of GENERIC must be specified.
SYNOPSIS:
#include "shChain.h"
CHAIN *shChainNew(const char *a_type)
a_type - TYPE of the chain to be created. A heterogeneous chain
can be created using a type of GENERIC
RETURNS:
On success: A pointer to the new chain
On failure: No error return is possible from this function
g_shChainErrno is unaffected by this function.
EXAMPLE:
CHAIN *pChain1, *pChain2;
/*
* Creates a homogeneous chain of MASKs
*/
pChain1 = shChainNew("MASK");
/*
* Creates a heterogeneous chain container
*/
pChain2 = shChainNew("GENERIC");
_______________________________________________________________________________
Deletes the specified chain and all chain elements. Note that the data on
each chain element is not deleted. However, the chain and all it's
elements will be deleted.
SYNOPSIS:
#include "shChain.h"
void shChainDel(CHAIN *pChain)
pChain - Pointer to the chain to be deleted
Returns:
Nothing.
g_shChainErrno is unaffected by this function.
_______________________________________________________________________________
Deletes the specified chain, all chain elements, and all the data on associated
with each chain element.
The ANSI C standard requires you to cast your Del operator, e.g.
(void (*)(void *))shRegDel
as there is no generic function pointer.
Note that you can get into trouble calling this function on a chain
if there are other places where the addresses of the objects on the
chain are stored (e.g. if the object appears on two chains).
This will, in fact, only bite for types that call shMalloc more than
once in their constructor (e.g. REGION). The problem is no worse than
any other way of getting the same pointer into multiple handles, so
don't worry too much about this warning.
SYNOPSIS:
#include "shChain.h"
int shChainDestroy(CHAIN *pChain, void (*pDelFunc)(void *))
pChain - Pointer to the chain to be deleted
pDelFunc - Pointer to a function which deletes each element on the chain
This function is passed the address of the element.
Returns:
0 : On success
1 : Otherwise - for instance, if a chain's type is GENERIC, this function
cannot delete objects on the chain.
g_shChainErrno is unaffected by this function.
_______________________________________________________________________________
Gets the TYPE of the nth position on the chain. n can be one
of the defined constants HEAD or TAIL, or it could be an integer which
represents the index of the element in the chain.
SYNOPSIS:
#include "shChain.h"
TYPE shChainElementTypeGetByPos(const CHAIN *pChain, const int pos)
pChain - Pointer to the chain
pos - Index of the element on the chain. Can be one of the pre-
defined constants HEAD or TAIL
RETURNS:
On success: TYPE of the element requested
On failure: a TYPE of UNKNOWN
g_shChainErrno is set to:
On success: SH_SUCCESS
On failure: SH_CHAIN_EMPTY - if the chain size is 0
_______________________________________________________________________________
Sets the TYPE of a chain to a desired one. It's the callers responsibility to
ensure that all elements on the chain are of the new type. This routine does
not check for that; it simply changes the type of the chain as indicated.
SYNOPSIS:
#include "shChain.h"
TYPE shChainTypeSet(CHAIN *pChain, const char *type)
pChain - Pointer to the chain
type - The new chain type
RETURNS:
The old type of the chain
g_shChainErrno is unaffected by this function
_______________________________________________________________________________
Gets the existing type of the chain
SYNOPSIS:
#include "shChain.h"
TYPE shChainTypeGet(const CHAIN *pChain)
pChain - Pointer to the chain
RETURNS:
The TYPE of the chain
g_shChainErrno is unaffected by this function
_______________________________________________________________________________
This function defines the chain type according to the following conventions:
- if the chain is empty, return the original type
- if the chain TYPE is GENERIC, but the chain contains homogeneous elements,
return the type of the elements
- if the chain TYPE is GENERIC and the chain contains heterogeneous
elements, the chain type is left unchanged
SYNOPSIS:
#include "shChain.h"
TYPE shChainTypeDefine(const CHAIN *pChain)
pChain - Pointer to the chain
RETURNS:
The TYPE as defined in the above conventions
g_shChainErrno is unaffected by this function
_______________________________________________________________________________
Gets the size of the chain
SYNOPSIS:
#include "shChain.h"
unsigned int shChainSize(const CHAIN *pChain)
pChain - Pointer to the chain
RETURNS:
The size of the chain
g_shChainErrno is unaffected by this function
_______________________________________________________________________________
This function appends a target chain to a source chain. Both the chains should
be of the same type, unless the source chain is of type GENERIC, in which case
the target chain can be of any type. The target chain will be destroyed on the
success of this function.
SYNOPSIS:
#include "shChain.h"
RET_CODE shChainJoin(CHAIN *pSrc, CHAIN *pTarget)
pSrc - Pointer to the source chain
pTarget - Pointer to the target chain
RETURNS:
On success: SH_SUCCESS
On failure: SH_TYPE_MISMATCH - types of the chains do not match
g_shChainErrno is is set to:
On success: SH_SUCCESS
On failure: SH_TYPE_MISMATCH - types of the chains do not match
_______________________________________________________________________________
This function copies a chain. The copied chain does not inherit any
cursor information from the parent.
SYNOPSIS:
#include "shChain.h"
CHAIN *shChainCopy(const CHAIN *pSrc)
pSrc - Pointer to the chain to copy
RETURNS:
Pointer to the copied chain.
g_shChainErrno is set to:
SH_SUCCESS
_______________________________________________________________________________
Sorts a chain according to a specified criterion. Note that since sorting
involves moving chain element pointers around, all cursor information set
on the chain prior to calling this function will be lost. The chain to
be sorted must be homogeneous.
SYNOPSIS:
#include "shChain.h"
RET_CODE shChainSort(CHAIN *pChain, const char *pField, const int increasing)
pChain - Pointer to the chain to sort
pField - Pointer to the field to sort the chain on
increasing - Direction of the sort; if set sort in an ascending
fashion, if not set, sort in a descending fashion
RETURNS:
On success: SH_SUCCESS
On failure: SH_CHAIN_EMPTY - if pChain is empty
SH_TYPE_MISMATCH - if the TYPE of pChain is GENERIC
SH_FLD_SRCH_ERR - if pField does not exist in the schema
SH_BAD_SCHEMA - if the chain contains unknown data items
g_shChainErrno is set to:
On success: SH_SUCCESS
On failure: SH_CHAIN_EMPTY - if pChain is empty
SH_TYPE_MISMATCH - if the TYPE of pChain is GENERIC
SH_FLD_SRCH_ERR - if pField does not exist in the schema
SH_BAD_SCHEMA - if the chain contains unknown data items
EXAMPLE:
CHAIN *pChain;
...
/*
* Assume a chain of PTs. To sort this chain on the "row" field, do the
* following...
*/
if (shChainSort(pChain, "row", 0) != SH_SUCCESS) {
switch (g_shChainErrno) {
...
}
}
_______________________________________________________________________________
This function traverses the chain using a cursor. The state of a chain can be
changed during traversal; i.e. new elements can be added, or existing elements
deleted. Addition and deletion are done relative to the cursor, so the
appropriate cursor APIs
(shChainElementAddByCursor,
and
shChainElementRemByCursor)
should be used.
Direction of traversal relative to the cursor can be one of THIS (the
current element is fetched), NEXT (the next element is fetched) or PREVIOUS
(the previous element is fetched). On reaching the end of the chain, a
NULL is returned. If the user insists on traversing further after
encountering NULL, the chain is looped around.
Two functions may be used as a preamble to traversing a chain:
shChainCursorNew() and shChainCursorSet().
shChainCursorNew() actually set the cursor to one element
before the start of chain, so that the first
shChainWalk moves the cursor to the first element.
shChainCursorSet() provides the ability to set a cursor to the start,
or end of a chain. If this function is used as a preamble to chain traversal,
the cursor is actually set to one element before (after) the start (end) of
the chain.
Note that this function, besides returning NULL on reaching the end of the
chain, also returns NULL in three other cases:
- the chain is empty (g_shChainErrno is set to SH_CHAIN_EMPTY)
- the cursor is pointing to an invalid element (g_shChainErrno is set to
SH_CHAIN_INVALID_ELEM)
- the cursor is invalid (g_shChainErrno is set to SH_CHAIN_INVALID_CURSOR)
It is left up to the caller of this function to ensure that after a call to
shChainWalk(), g_shChainErrno is SH_SUCCESS and not anything else.
SYNOPSIS:
#include "shChain.h"
void *shChainWalk(CHAIN *pChain, const CURSOR_T crsr,
const CHAIN_WALK_FLAGS whither)
pChain - Pointer to the chain to walk
crsr - A valid cursor bound to the chain
whither - One of PREVIOUS, NEXT, or THIS
RETURNS:
pointer to the element referenced by the cursor, or NULL on reaching the
end of chain.
g_shChainErrno is set to:
On success: SH_SUCCESS
On failure: SH_CHAIN_EMPTY - if pChain is empty
SH_CHAIN_INVALID_ELEM - if the cursor is pointing to an
invalid element (an element previously deleted)
SH_CHAIN_INVALID_CURSOR - if the cursor is not valid
EXAMPLE:
CHAIN *pChain;
CURSOR_T crsr;
MASK *pMask;
. . .
/*
* Assume we have a chain of masks that we want to traverse through.
* The following code does that, and also modifies the state of the
* chain in the process. The steps for traversal are:
* 1) Get a cursor (since we are using it as a preamble to shChainWalk(),
* it is automatically initialized to one element
* before the start of the chain)
* 2) Traverse the chain using the cursor
*/
crsr = shChainCursorNew(pChain); /* Step 1 */
while ((pMask = shChainWalk(pChain, crsr, NEXT)) != NULL) { /* Step 2 */
/*
* Add a new element to the chain following the cursor element
*/
if (strncmp(pMask->name, "MASK1", 5) == 0)
if (shChainElementAddByCursor(pChain, maskNew("MASK3", 10, 10),
"MASK", crsr, AFTER) != SH_SUCCESS)
break;
}
if (g_shChainErrno != SH_SUCCESS) {
/*
* Handle error as needed
*/
. . .
}
. . .
/*
* To delete the chain element added in the above code, do the following.
* Note that now we're traversing from the tail of the chain. Here since
* we already have a cursor, we will set it to the TAIL element.
*/
if (shChainCursorSet(pChain, crsr, TAIL) != SH_SUCCESS) {
/*
* Handle error as needed
*/
. . .
}
while ((pMask = shChainWalk(pChain, crsr, PREVIOUS)) != NULL) {
/*
* Remove MASK3 added above
*/
if (strncmp(pMask->name, "MASK3", 5) == 0)
shChainElementRemByCursor(pChain, crsr);
}
if (g_shChainErrno != SH_SUCCESS) {
/*
* Handle error as needed
*/
. . .
}
. . .
_______________________________________________________________________________
This function creates a new cursor on a chain. A chain can have upto 10
simultaneous active cursors. A cursor can be viewed as a context sensitive
device on a chain; i.e. it holds the context of the chain. Cursors are
helpful while traversing chains using
shChainWalk and modifying the state of
a chain using
shChainElementAddByCursor,
and
shChainElementRemByCursor.
This function creates a chain cursor and initializes it to the first
element on the chain. This function still works if the chain is empty, since
it is smart enough to initialize the cursor to the first element as soon as
the first element is added.
SYNOPSIS:
#include "shChain.h"
CURSOR_T shChainCursorNew(CHAIN *pChain)
pChain - Pointer to the chain
RETURNS:
CURSOR_T, which is a handle to the next availaible cursor.
g_shChainErrno is unaffected by this function
EXAMPLE:
CHAIN *pChain;
CURSOR_T crsr;
. . .
pChain = shChainNew("REGION");
crsr = shChainCursorNew(pChain);
if (shChainElementAddByCursor(pChain, ...) != SH_SUCCESS)
. . .
_______________________________________________________________________________
This function initializes a cursor to an element on the chain. The cursor
must have been previously created using
shChainCursorNew. This function
will fail on an empty chain, the chain should contain at least one
element in order for this function to succeed.
SYNOPSIS:
#include "shChain.h"
RET_CODE shChainCursorSet(CHAIN *pChain, const CURSOR_T crsr, const int pos)
pChain - Pointer to the chain
crsr - The cursor
pos - Position in the chain to set the cursor to
RETURNS:
g_shChainErrno, which is set to
On success : SH_SUCCESS
On failure : SH_CHAIN_EMPTY - if the chain is empty
SH_CHAIN_INVALID_CURSOR - if crsr is invalid
EXAMPLE:
CHAIN *pChain;
CURSOR_T crsr;
. . .
pChain = shChainNew("REGION");
. . .
/*
* Assume elements have been added to the chain. Now, let's get a new
* cursor and initialize it to the tail of the chain
*/
crsr = shChainCursorNew(pChain);
if (shChainCursorSet(pChain, crsr, TAIL) != SH_SUCCESS) {
/*
* Handle error condition
*/
}
. . .
_______________________________________________________________________________
This function copies an existing cursor. A new cursor is created that holds
the same information as the existing one.
SYNOPSIS:
#include "shChain.h"
RET_CODE shChainCursorCopy(CHAIN *pChain, const CURSOR_T crsr,
CURSOR_T *newCrsr)
pChain - Pointer to the chain
crsr - The existing cursor
newCrsr - Pointer to the memory address to hold the newly copied
cursor
RETURNS:
g_shChainErrno, which is set to
On success : SH_SUCCESS
On failure : SH_CHAIN_INVALID_CURSOR - if crsr is invalid
_______________________________________________________________________________
This function deletes a cursor associated with a chain. The cursor to be
deleted should have been created with a call to
shChainCursorNew.
SYNOPSIS:
#include "shChain.h"
RET_CODE shChainCursorDel(CHAIN *pChain, const CURSOR_T crsr)
pChain - Pointer to the chain
crsr - Cursor to be deleted
RETURNS:
On success : SH_SUCCESS
On failure : SH_CHAIN_INVALID_CURSOR - an invalid cursor encountered
g_shChainErrno is set to:
On success : SH_SUCCESS
On failure : SH_CHAIN_INVALID_CURSOR - an invalid cursor encountered
_______________________________________________________________________________
This function returns a count of all active cursors associated with a chain.
SYNOPSIS:
#include "shChain.h"
unsigned int shChainCursorCount(const CHAIN *pChain)
pChain - Pointer to the chain
RETURNS:
Count of the number of active cursors
g_shChainErrno is unaffected by this function
_______________________________________________________________________________
This function gets the type of the element under the cursor.
SYNOPSIS:
#include "shChain.h"
TYPE shChainElementTypeGetByCursor(const CHAIN *pChain, const CURSOR_T crsr)
pChain - Pointer to the chain
crsr - The cursor
RETURNS :
On success : the type of element
On failure : a type of UNKNOWN. g_shChainErrno will be set to a more
descriptive error message
g_shChainErrno is set to
On success : SH_SUCCESS
On failure : SH_INVALID_CURSOR - an invalid cursor encountered
SH_CHAIN_INVALID_ELEM - cursor is pointing to an invalid
chain element; probably the result of an element deletion
_______________________________________________________________________________
This function adds a new element on a chain. The element is added relative to
the position specified. The new element can be added either before the
position specified, or after the position specified. The position and
relativity are ignored on the addition of the very first element to the chain.
Unless the chain is of type GENERIC, the element to be added should be
of the same type as the chain's type.
SYNOPSIS:
#include "shChain.h"
RET_CODE shChainElementAddByPos(CHAIN *pChain, void *pData,
const char *dataType, const int pos,
const CHAIN_ADD_FLAGS where)
pChain - Pointer to the chain
pData - Pointer to the data element to add on the chain
dataType - Type of the element to be added
pos - Position on the chain to add the new element to;
can be either HEAD, TAIL or an integer
where - one of BEFORE or AFTER; specifies if pData should be
added before or after the element at the pos position
RETURNS:
On success : SH_SUCCESS
On failure : SH_TYPE_MISMATCH - if dataType does not match the type of the
chain
g_shChainErrno is set to
On success : SH_SUCCESS
On failure : SH_TYPE_MISMATCH - if dataType does not match the type of
the chain
EXAMPLE:
CHAIN *pChain;
MASK *pMask;
REGION *pReg;
/*
* Let's create a GENERIC chain and insert a mask and a region on it...
*/
pChain = shChainNew("GENERIC");
pMask = shMaskNew("mask1", 10, 10);
pRegion = shRegNew("reg1", 10, 10, TYPE_U8);
if (shChainElementAddByPos(pChain, pRegion, "REGION", TAIL, AFTER) !=
SH_SUCCESS) {
/*
* Handle error
*/
}
if (shChainElementAddByPos(pChain, pMask, "MASK", TAIL, AFTER) !=
SH_SUCCESS) {
/*
* Handle error
*/
}
. . .
_______________________________________________________________________________
This function removes the specified element from the chain.
SYNOPSIS:
#include "shChain.h"
void *shChainElementRemByPos(CHAIN *pChain, const int pos)
pChain - Pointer to the chain
pos - Position of the element to be removed
RETURNS:
On success : address of the removed element
On failure : NULL. g_shChainErrno will be set accordingly.
g_shChainErrno is set to
On success : SH_SUCCESS
On failure : SH_CHAIN_EMPTY - if the chain is empty
_______________________________________________________________________________
This function retreives the specified element from the chain.
SYNOPSIS:
#include "shChain.h"
void *shChainElementGetByPos(CHAIN *pChain, const int pos)
pChain - Pointer to the chain
pos - Position of the element to be retrieved.
RETURNS:
On success : address of the element requested
On failure : NULL. g_shChainErrno will be set accordingly.
g_shChainErrno is set to
On success : SH_SUCCESS
On failure : SH_CHAIN_EMPTY - if the chain is empty
_______________________________________________________________________________
This function adds a new element in relation to the cursor. The new element
can be added before or after the cursor. The cursor is supposed
to have been properly created and initialized. On success of this function,
the cursor is set to the newly added element.
SYNOPSIS:
#include "shChain.h"
RET_CODE shChainElementAddByCursor(CHAIN *pChain, const void *pData,
const char *dataType,
const CURSOR_T crsr,
const CHAIN_ADD_FLAGS where)
pChain - Pointer to the chain
pData - Pointer to the data element to be added
dataType - Type of the element to be added
crsr - The cursor
where - One of BEFORE or AFTER; specifies if pData should be
added before or after the cursor
RETURNS:
On success : SH_SUCCESS
On failure : SH_TYPE_MISMATCH - if dataType does not match the type of the
chain
SH_CHAIN_INVALID_CURSOR - if crsr is invalid
g_shChainErrno is set to
On success : SH_SUCCESS
On failure : SH_TYPE_MISMATCH - if dataType does not match the type of
the chain
SH_CHAIN_INVALID_CURSOR - if crsr is invalid
EXAMPLE:
/*
* Demonstration of adding an element using a cursor. Assume that
* a chain has been created and populated. We want to set a cursor to
* the 10th element and add an element before the cursor.
*/
. . .
crsr = shChainCursorNew(pChain);
(void) shChainCursorSet(pChain, crsr, 10);
if (shChainElementAddByCursor(pChain, maskNew("MASK1", 10, 10),
"MASK", crsr, BEFORE) != SH_SUCCESS)
{
/*
* Handle error condition
*/
. . .
}
_______________________________________________________________________________
This function removes an element from a chain. The element to be removed is
referenced by the cursor. On a successful removal, the cursor is set to NULL.
Any attempts to retrieve the deleted element will result in failure. Since
an element can be deleted while traversing a chain using
shChainWalk,
shChainElementRemByCursor()
saves the address of the neighbors of the deleted element so that the chain
can still be traversed.
SYNOPSIS:
#include "shChain.h"
void *shChainElementRemByCursor(CHAIN *pChain, const CURSOR_T crsr)
pChain - Pointer to the chain
crsr - Cursor element to be deleted
RETURNS:
On success : address of the element deleted
On failure : NULL. g_shChainErrno is set accordingly.
g_shChainErrno is set to
On success : SH_SUCCESS
On failure : SH_CHAIN_INVALID_CURSOR - on an invalid cursor
SH_CHAIN_INVALID_ELEM - if the cursor is referring to a
chain element that has been
removed already
_______________________________________________________________________________