This page gives an overview of the Bithenge library API and internals. Detailed documentation can be found in the source code’s Doxygen comments.
All public functions and types have names starting with
Almost all Bithenge functions return an integer error code. It will be EOK on
success or an error code from
errno.h on failure. Even if an error occurs,
functions will still free or dereference their arguments as documented.
Nodes, expressions, transforms, and scopes use reference counting. For
instance, functions that produce a node (through a
parameter) create a new reference to the node; you are responsible for ensuring
the reference count is eventually decremented. The reference count can be
bithenge_xxx_inc_ref and decremented with
If a function’s documentation says it “takes [ownership of] a reference” to an object, the function guarantees the object’s reference count will eventually be decremented, even if an error occurs. Therefore, if you create an object only to immediately pass it to such a function, you do not need to change its reference count.
Blob nodes, internal nodes, expressions, and transforms are polymorphic. We
will use transforms as an example, but the others are similar. Each transform
implementation has its own
struct, including a
and its own static
bithenge_transform_ops_t instance. When a transform is
created, it calls
bithenge_transform_init on the
gives it a pointer to the
bithenge_transform_ops_t instance. It then returns
a pointer to the
bithenge_transform_t to the caller. When the caller uses a
function on the
bithenge_transform_t *, it automatically looks in the
bithenge_transform_ops_t for the transform‐specific implementation.
Integer, boolean, and string nodes are trivial. Blob and internal nodes are polymorphic; each node has its own functions to access its contents. This means calculating the node’s contents can be delayed until the contents are needed.
The primary method of transforms is
apply, which applies a transform to an
input tree and creates an output tree. When a transform takes a blob node as
input, it is sometimes necessary to determine the prefix of a given blob that
can be used as input to the transform; the method
prefix_length can be used
for this. Alternatively, a
prefix_apply method can do both at once,
substituting for or supplementing
prefix_length. All three of
these methods take a scope; see below.
The only method of expressions is
evaluate, which evaluates the expression in
a scope to create an output node. Expressions can be considered similar to
transforms, except that they have no input node.
Scopes keep track of all information needed by transforms and expressions other than transforms’ input trees. This includes parameters, nodes being created, input nodes, and error messages.
Aside from functions directly related to the types above, Bithenge has several other important functions:
bithenge_parse_scriptparses a Bithenge script file to create a transform.
bithenge_node_from_sourcecreates a node based on a string, such as
bithenge_print_nodeprints nodes in human‐readable formats.
The test.c program included with Bithenge is a simple demonstration of all of these functions.
In HelenOS, Bithenge can be tested by running
batch test.bdsh in the
/src/bithenge directory. If it runs to the end and prints "Success!",
Bithenge worked correctly on the example files.
In Linux, more advanced testing is possible. Compile with
COVERAGE=y FAILURE=y make and run
test.sh with Valgrind installed. Bithenge
will use failure injection to test much of the error handling code, in addition
to the main paths.