ACEDB source code documentation: the BS package

# Application programmers' guide to the BS package

    	Programmers guide to the BS package

    This is the basic interface to all the tree objects in the database.
    It is fundamental to extracting data from ACEDB.

    General Principles
    ==================

    The programmer interacts with acedb objects via handles of type OBJ.
    These have associated with them an implicit cursor.

    The Find, Get and Add functions in general reposition the cursor as
    well as getting/adding data.  They all return a BOOL value which
    indicates if their operation was successful.  If this is FALSE then
    the cursor position is not changed.

    Get and Add functions require a tag for location.  This can either be
    a tag in the current model, or one of the pseudotags _bsHere,
    _bsRight and _bsDown.

    bsMark/Goto can be used to store cursor positions to return to later.

    Overview of functions
    =====================

    operations on to get and free object handles:
      bsCreate(), bsCreateCopy(), bsUpdate(), bsClone() - get object handles
      bsDestroy(), bsSave(), bsKill()		- release handles

    access primitives on an object:
      bsFindTag()					- locate on a tag
      bsGetKey(), bsGetKeyTags(), bsGetData()	- get data
      bsPushObj()					- enter subobject
      bsFlatten()					- get subtree as Array
      bsAddTag(), bsAddKey(), bsAddData(), bsAddComment()	- add data
      bsPrune(), bsRemove()				- delete data
      bsType(), bsIsTagInObj()			- check consistency
      bsMark(), bsGoto(), bsMarkFree()		- save cursor info

    dump functions:
      bsAceDump()					- .ace file dump
      bsDump()					- for debugging

    special functions, mostly for upper kernel use:
      bsKeySet()					- all keys in object
      bsLocalClass()				- current model
      bsTagsInClass()				- tags in a model
      bsParentKey()					- for query package

    Alphabetic list of functions
    ============================

    Starred functions are ones not normally used in general code,
    i.e. things written primarily for specific purposes.

    ---------------------------------------------------------------- bsAceDump
    *	void bsAceDump (OBJ obj, ACEOUT dump_out, BOOL isInternal)

    Dumps the object in .ace format.  Writes to an ACEOUT stream openend
    by aceOutCreateTo<Xxxx> functions.

    ------------------------------------------------------------- bsAddComment
    *	BOOL bsAddComment (OBJ obj, char *text, char type)

    Adds a comment at the current cursor position in obj.  See the
    introduction for general comments on the bsAdd* functions.  Note
    however that this function does not change the cursor position, since
    the cursor can not rest on a comment, and there is no type checking
    with the model, because comments can be added anywhere.

    Comments can be added anywhere in a tree, and are ignored by the
    bsGet* functions.  The only way to see them is in a tree display, or a
    .ace dump.  The only legal type just now is 'C'.

    ---------------------------------------------------------------- bsAddData
    	BOOL bsAddData (OBJ obj, KEY tag, KEY type, void *data)

    Adds the given data at the current cursor position in obj.  See the
    introduction for general comments on the bsAdd* functions.

    Type must be one of the legal data types, i.e. the systags with values
    less than _LastC.  For now these are {_Int, _Float, _DateType, _Text,
    _Greek}.  The final argument is a pointer to the data in the case of
    Int, Float or DateType, or the char* pointer itself for text types
    (Text, Greek).

    ----------------------------------------------------------------- bsAddKey
    	BOOL bsAddKey (OBJ obj, KEY tag, KEY key)

    Adds the given key at the current cursor position in obj.  See the
    introduction for general comments on the bsAdd* functions.

    ----------------------------------------------------------------- bsAddTag
    	BOOL bsAddTag (OBJ obj, KEY tag)

    Adds the given tag, which must be a true tag in the model, not
    _bsRight or _bsDown.  Resets the cursor to this tag.  Returns FALSE if
    the tag was already present, else TRUE.

    ------------------------------------------------------------------ bsClone
    *	OBJ bsClone (KEY key, OBJ source)

    Specialised routine.  Creates or updates object refered to by key;
    throw away existing contents (if any) and replace with source.

    ----------------------------------------------------------------- bsCreate
    	OBJ bsCreate (KEY key)

    Returns a read only handle for accessing an object.  Will return 0 if
    the object has no data attached yet.

    bsCreate() gives a handle to the last saved version of an object in
    secondary cache, building a tree structure there if necessary.
    Multiple calls to bsCreate() on the same key will give pointers into
    the same object.  Repeated bsCreate()/bsDestroy() calls to the same
    object are cheap.

    ------------------------------------------------------------- bsCreateCopy
    *	OBJ bsCreateCopy (KEY key)

    Returns a handle of an object that you can edit, but will not be
    allowed to save using bsSave().  i.e. you must bsDestroy() it.

    ---------------------------------------------------------------- bsDestroy
    	void bsDestroy (obj)

    Releases an object handle.  This call should match bsCreate(),
    bsCreateCopy() or bsUpdate().  Once all handles onto an object are
    released it can be bumped out of secondary cache.  If used on an
    object handle obtained with bsUpdate(), all changes made to the object
    are abandoned.  To save the changes use bsSave().

    ------------------------------------------------------------------- bsDump
    *	void bsDump (OBJ obj)

    For debugging (for which it can be very useful).  Writes to stdout the
    complete tree structure of the object, giving all the pointer values
    as well as node key values.  Uses bsTreeDump (BS bs) which allows
    dumping of subtrees, but needs a BS argument, which is only available
    inside privileged packages.

    ---------------------------------------------------------------- bsFindTag
    	BOOL bsFindTag (OBJ obj, KEY tag)

    If the tag exists in object then moves the cursor there and returns
    TRUE, else returns FALSE.

    ---------------------------------------------------------------- bsFlatten
    	BOOL bsFlatten (OBJ obj, int n, Array a)

    This is a (very useful) convenience routine.  This recovers the entire
    subtree to the right of the current cursor position into a set of
    n-tuples in the given array.  i.e. it looks n positions to the right.
    The array a must be an array of BSunit, which are defined in bs.h as

    typedef union { int i; float f; KEY k; char *s ; mytime_t time } BSunit ;

    It is presumed that the user knows the model, and so knows which
    version of the union to look at.  Missing values are entered as 0,
    which is unfortunately not distinguishable from a true 0 for numerical
    data.  bsFlatten() returns TRUE if any data were found, in which case
    arrayMax(a) will be n times the number of rows (tuples).

    Does not move the cursor.

    An example:
    {
      Array flatA, segs ;
      SEG *seg ;
      OBJ Seq ;
      int i ;

      flatA = arrayCreate (8, BSunit) ;

      if (bsFindTag (Seq, _Source_Exons) && bsFlatten (Seq, 3, flatA))
        for (i = 0 ; i < arrayMax (flatA) ; i += 3)
          { seg = arrayp (segs, arrayMax(segs)++, SEG) ;
            seg->key = arr(flatA, i, BSunit).k ;
            seg->x1 = arr(flatA, i+1, BSunit).i ;
            seg->x2 = arr(flatA, i+2, BSunit).i ;
          }
    }

    ---------------------------------------------------------------- bsGetData
    	BOOL bsGetData (OBJ obj, KEY tag, KEY type, void *x)

    Gets data from the position specified by tag.  Same arguments as
    bsAddData(), although in this case for Text types x should be a
    pointer to a string, i.e. type char**.  Returns TRUE if there was
    something there and fills x, otherwise does not change x.  If x is 0
    then still locates and returns TRUE or FALSE, but does not give you
    the value.

    ----------------------------------------------------------------- bsGetKey
    	BOOL bsGetKey (OBJ obj, KEY tag, KEY *found)

    Gets a key if present at the position given by tag, in which case
    returns TRUE and fills found (if non-zero).  Will not get a tag.

    ------------------------------------------------------------- bsGetKeyTags
    	BOOL bsGetKeyTags (OBJ obj, KEY tag, KEY *found)

    Will get either a key or a tag.  This function must be used when you
    want to get a tag.  To just find out if a tag is present and locate on
    it, call bsFindTag().

    ------------------------------------------------------------------- bsGoto
    	void bsGoto (OBJ obj, BSMARK mark)

    Returns the cursor position for obj to that stored by bsMark() in
    mark.  You must use the correct obj!  bsGoto(obj,0) will return to the
    root of the object, which can be useful when you have been inside
    subobjects.

    ------------------------------------------------------------- bsIsTagInObj
    	BOOL bsIsTagInObj (OBJ obj, KEY key, KEY tag)

    To test if a tag is present in an object or the model. You might do
    this prior to calling  bsAddTag(obj, tag), to check that the call
    would work. If called with an obj it will look in the object from
    the current cursor position (possibly a submodel) for the tag.
    If obj is NULL and key non-zero it will look in the model for the
    class of key for the tag. Hence you can test either an individual
    object or the database model for the presence of a particular tag.

    ----------------------------------------------------------------- bsKeySet
    	KEYSET bsKeySet (KEY key)

    Returns a keySet containing all the keys that can be found in
    bsCreate(key).

    ------------------------------------------------------------------- bsKill
    	void bsKill (obj)

    Removes all data from obj and marks it as empty/deleted.

    ------------------------------------------------------------------- bsMark
    	BSMARK bsMark (OBJ obj, BSMARK mark)

    Stores the current cursor information inside mark.  If given a
    non-zero mark as an argument, it will refill that structure.  If the
    mark argument is 0 it will make a new one and pass on a handle.  This
    saves on very frequent alloc/free operations.

    --------------------------------------------------------------- bsMarkFree
    	void bsMarkFree (BSMARK mark)

    Frees a mark created with bsMark().  Normally they are not freed, but
    used static as in the example under bsMark().  Implemented as a macro
    that only frees mark if non-zero, and if so sets it to 0.

    ------------------------------------------------------------------ bsPrune
    	BOOL bsPrune (OBJ obj)

    Removes everything at the current cursor position and to the right of
    it, and also everything left of it that is unique.  i.e. If you add a
    fields which requires that several intermediate tags are made, then
    locate on the field, then call bsPrune() you will remove all the
    intermediate tags as well.  If you do not want to remove intermediate
    tags then use bsRemove().

    This call returns the cursor to the root of the object.

    ---------------------------------------------------------------- bsPushObj
    	BOOL bsPushObj (OBJ obj)

    If the cursor is currently located at a position just left of a
    #submodel in the model, then returns TRUE and changes the current
    model to that of the submodel, locating the cursor conceptually at the
    root of that.  Otherwise, returns FALSE. A quick way to step back
    into the current model is:  bsGoto(obj,0)  there is no bsPopObj().

    ----------------------------------------------------------------- bsRemove
    	BOOL bsRemove (OBJ obj)

    Like bsPrune(), except that it only removes the current cursor postion
    and everything to the right, not unique stuff to the left.  It also
    returns the cursor to the root.

    ------------------------------------------------------------------- bsSave
    	void bsSave (OBJ obj)

    Save an updated object back to the database.  obj must have been
    created by a call to bsUpdate().

    ------------------------------------------------------------ bsTagsInClass
    *	KEYSET bsTagsInClass (int table)

    Returns a keyset of all the tags in a model, which must be specified
    as a table or class number (a low integer) not as a key in the ?Model
    class.

    ------------------------------------------------------------------- bsType
    	KEY bsType (OBJ obj, KEY direction)

    Finds out what the model expects.  direction must be _bsRight or
    _bsHere or _bsDown (almost always _bsRight).  Will return 0 if there
    is nothing to the right, else a basic type tag (_Text, _Int etc.) else
    the 0'th element of a class for a pointer to that class, or the 1'st
    element of a class for a #construction.

    ----------------------------------------------------------------- bsUpdate
    	OBJ bsUpdate (KEY key)

    Open an object for update, i.e. with write access.  Returns a handle
    to the object defined by key.  Will return 0 if the key does not
    exist, or the object is already being updated elsewhere.  It is
    possible to open an object with bsUpdate even if the user does not
    have write access.  In this case the object will be changed and locked
    in secondary cache, but not written back to disk.

    --------------------------------------------------------------------------