Fork us on GitHub Follow us on Facebook Follow us on Twitter

Version 1 (modified by Sean Bartell, 8 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.



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.


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


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 apply and 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.

Main functions

Aside from functions directly related to the types above, Bithenge has several other important functions:

  • bithenge_parse_script parses a Bithenge script file to create a transform.
  • bithenge_node_from_source creates a node based on a string, such as block:bd/initrd.
  • bithenge_print_node prints 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 with Valgrind installed. Bithenge will use failure injection to test much of the error handling code, in addition to the main paths.