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
  • _______________________________________________________________________________

    shChainNew

    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"); _______________________________________________________________________________

    shChainDel

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

    shChainDestroy

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

    shChainElementTypeGetByPos

    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 _______________________________________________________________________________

    shChainTypeSet

    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 _______________________________________________________________________________

    shChainTypeGet

    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 _______________________________________________________________________________

    shChainTypeDefine

    This function defines the chain type according to the following conventions:

    1. if the chain is empty, return the original type
    2. if the chain TYPE is GENERIC, but the chain contains homogeneous elements, return the type of the elements
    3. 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 _______________________________________________________________________________

    shChainSize

    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 _______________________________________________________________________________

    shChainJoin

    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 _______________________________________________________________________________

    shChainCopy

    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 _______________________________________________________________________________

    shChainSort

    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) { ... } } _______________________________________________________________________________

    shChainWalk

    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:

    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 */ . . . } . . . _______________________________________________________________________________

    shChainCursorNew

    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) . . . _______________________________________________________________________________

    shChainCursorSet

    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 */ } . . . _______________________________________________________________________________

    shChainCursorCopy

    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 _______________________________________________________________________________

    shChainCursorDel

    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 _______________________________________________________________________________

    shChainCursorCount

    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 _______________________________________________________________________________

    shChainElementTypeGetByCursor

    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 _______________________________________________________________________________

    shChainElementAddByPos

    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 */ } . . . _______________________________________________________________________________

    shChainElementRemByPos

    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 _______________________________________________________________________________

    shChainElementGetByPos

    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 _______________________________________________________________________________

    shChainElementAddByCursor

    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 */ . . . } _______________________________________________________________________________

    shChainElementRemByCursor

    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 _______________________________________________________________________________