| Version 1 (modified by , 13 years ago) ( diff ) |
|---|
Bithenge Library
This page gives an overview of the Bithenge library API and internals. Detailed documentation can be found in the source code’s Doxygen comments.
Conventions
Names
All public functions and types have names starting with bithenge_.
Error handling
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.
Reference counting
Nodes, expressions, transforms, and scopes use reference counting. For
instance, functions that produce a node (through a bithenge_node_t **
parameter) create a new reference to the node; you are responsible for ensuring
the reference count is eventually decremented. The reference count can be
incremented with bithenge_xxx_inc_ref and decremented with
bithenge_xxx_dec_ref.
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.
Polymorphism
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 bithenge_transform_t member,
and its own static bithenge_transform_ops_t instance. When a transform is
created, it calls bithenge_transform_init on the bithenge_transform_t and
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.
Main types
Nodes
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.
Transforms
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 apply and prefix_length. All three of
these methods take a scope; see below.
Expressions
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
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.
Main functions
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 asblock:bd/initrd.bithenge_print_nodeprints nodes in human‐readable formats.
The test.c program included with Bithenge is a simple demonstration of all of these functions.
Testing
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.
