ORT-C-HEADER(1) General Commands Manual ORT-C-HEADER(1)

generate ort C API

ort-c-header [-jJsv] [-g guard] [-N db] [config...]

The ort-c-header utility accepts ort(5) config files, defaulting to standard input, and generates a C API. These declarations is usually defined by the output of ort-c-source(1). Its arguments are as follows:
Output JSON export function declarations.
Output JSON import function declarations.
Output Data validation function and variable declarations.
Preprocessor guard for header re-inclusion. Defaults to DB_H. This is not sanity-checked.
Disable production of output, which may be b and/or d. The b flag suppresses the foundational Data structures declarations, while d suppresses the Database input. This flag is used when creating multiple header files.
Use split-process mode for the database. This only changes generated documentation. This will be mandatory in future releases.

By default, the Database input and Data structures declarations are output.

The basis of the C API is a series of enumerations, structures, and preprocessor macros that describe the data. To include output files for data structures, specify:
#include <sys/queue.h> /* iff the config has lists */
#include <stdint.h>

Output begins with the definition of roles. The usage of roles in the input triggers several changes in output: these will be noted.

roles {
  role user;

Each of these are produced as an enumeration (always called enum ort_role), with the extra ROLE_none and ROLE_default produced for the empty and initial roles, respectively. See the Database input section for details on role management.

enum ort_role {

Next, an enumeration is generated for each enum with the name as given. The enumeration is then given a series of values for each item in the enumeration object.

enum foo {
  item bar 0;
  item baz 1;

Output variables are prefixed with the capitalised enumeration name, followed by an underscore, followed by the item name.

enum foo {
  FOO_bar = 0,
  FOO_baz = 1

Bit-fields produce similar code, except that each bit-field value is represented by the bit index and mask.

bits foo {
  item baz 1;

This produces an enumeration that describes the index of the bit prefixed with “BITI”, the underscore, followed by the uppercase name; and the mask when the respective bit is set prefixed with “BITF”, the underscore, and the uppercase name.

enum foo {
  BITI_FOO_baz = 1,
  BITF_FOO_baz = (1U << 1)

Structures are the foundational data strutcure of the API. They are named as defined in the configuration and consist of variables mapped to field entries along with bookkeeping fields: if a variable may be null, an extra int variable prefixed with “has_” is defined as well; or if it is a blob, an extra size_t variable suffixed with “_sz” is defined.

struct company {
  field name text;
  field foo enum foo null;
  field id int rowid;

Text variables are NUL-terminated char * strings, blobs are void *, integers are int64_t, reals are double, epoch values are time_t, enumerations are as named, and nested structures (foreign key references) are defined as structures of the given type.

struct company {
  char *name;
  enum foo foo;
  int has_foo;
  int64_t id;

All structures are defined in order so that they need not be forward-declared.

If the structure consists of a list operation, a TAILQ_ENTRY(3) named _entries is produced in its output. If roles are defined, each structure has a variable priv_store of an opaque pointer type struct ort_store. This is used to keep track of the role in which the query function was invoked.

Input functions define how the structures described in Data structures are pulled from the database. These functions invoke ksql(3) for handling the database itself, so the -lksql library is required for linking. You'll need the following inclusions:
#include <stdint.h> /* ksql(3) */
#include <ksql.h>

If the configuration specifies roles, inclusions not are necessary.

There are two functions, db_open() and db_close(), that open and close the database, respectively. There are also several transaction functions and, if applicable, a function for managing roles.

In the following documentation, “TYPE” is defined as struct ort if roles are defined or struct ksql otherwise.

Open a database named file and return a pointer to TYPE. Returns NULL on failure to allocate, open, or configure the database.
Closes a database opened by db_open(). Passing NULL is a noop.
Commit a transaction opened by db_trans_open() with unique transaction identifier id.
Open a transaction with a unique identifier id. The identifier prevents recursive transactions and allows for identifying open transactions on error. If mode is zero, the transaction locks the database on first access with shared locks (no writes allowed, reads allowed) on queries and unshared locks (single writer, reads allowed) on modification. If >0, the transaction immediately enters unshared lock mode. If <0, the transaction locks exclusively, preventing all other access.
Roll-back a transaction opened by db_trans_open() with unique transaction identifier id.
If roles are enabled, move from the current role to r. If the role is the same as the current role, this does nothing. Roles may only transition to ancestor roles, not descendant roles or siblings, or any other non-ancestor roles. The only exception is when leaving ROLE_default or entering ROLE_none. This does not return failure: on role violation, it invokes abort(2).
Get the currently-assigned role. If db_role() hasn't yet been called, this will be ROLE_default.
Get the role assigned to an object at the time of its creation.

Each structure has a number of operations for operating on the Data structures. These are all stipulated as delete, insert, iterate, list, search, and update statements in the configuration. Let “foo” be the name of the exemplar structure. Again, “TYPE” is defined as struct ort if roles are defined or struct ksql otherwise.

Run the named delete function “xxxx”. The ARGS passed to this function are the fields that constrain which rows are deleted. Parameters are only specified for operations for binary-operator constraints, i.e., those not checking for null status. Returns non-zero on success, zero on constraint failure.
Like db_foo_delete_xxxx(), but using an un-named delete statement constrained by “yy” with operation “op”.
Frees a pointer returned by a unique search function. If passed NULL, this is a noop.
Frees a queue (and its members) created by a listing function. This function is produced only if there are listing statements on a given structure.
The search statement named “xxxx”. The function accepts variables for all binary-operator fields to check (i.e., all except for those checking for null).
Like db_foo_get_xxxx(), but for (possibly-nested) structures. In the given example, “xxxx” is a field in the given structure with operation “op1” and “yy_zz” means a field “zz” in the nested structure “yy” with operation “op2”.
Insert a row and return its int64_t identifier or -1 on constraint failure. This accepts all native fields ARGS as parameters excluding rowid, which is automatically set by the database. If any fields are specified as null, they are passed into this functions as pointers. The null values must then be specified as NULL pointers. This function is only generated if the insert statement is specified for the given structure.
Iterate over all rows.
Like db_foo_get_xxxx(), but invoking a function callback cb passed arg within the active query for each retrieved result.
Like db_foo_get_by__xxxx_op1__yy_zz_op2(), but invoking a function callback for the retrieved results.
Allocate and fill a queue of all rows.
Like db_foo_get_xxxx(), but producing a queue of responses.
Like db_foo_get_by__xxxx_op1__yy_zz_op2(), but producing a queue of responses.
Run the named update function “xxxx”. The update functions are specified with update statements. The parameters passed to this function are first the fields to modify, then the fields that constrain which rows are updated. If any modified fields are specified as null, they are passed into this functions as pointers. Any null values must then be specified as NULL pointers. Update fields are only specified for operations for binary-operator constraints, i.e., those not checking for null status. Returns non-zero on success, zero on constraint failure.
Like db_foo_update_xxxx(), but using an un-named update statement modifying “xx” constrained by “yy” with operation “op”.
Like db_foo_update_xx_by_yy_op(), but for when no modify fields were specified, meaning that all fields (but structures and row identifiers) are to be modified.

If no roles are defined, several low-level functions declaration and macros are produced as well. This assists callers who provide their own database functions as enabled by ksql(3).

The string version of the SQL schema of structure “xxx”. This macro accepts a single argument name that is prepended to each column name to facilitate aliases.
Zero and fill in a pointer p from an open database statement stmt starting with result set column pos, which if NULL is assumed to be column zero. The pos is set to the column after extracting information. This fills all nested structures as well.
Release resources p filled from a database query db_foo_fill(). This frees all nested structures as well. If p is NULL, this is a noop.

These functions invoke kcgijson(3) to manage output formats. The header files for both kcgijson(3) and kcgi(3) must be stipulated.
#include <sys/types.h> /* kcgi(3) */
#include <stdarg.h> /* kcgi(3) */
#include <stdint.h> /* kcgi(3) */
#include <kcgi.h>
#include <kcgijson.h>
Print the list q of structures as a key-value pair where the key is the structure name and the value is an array consisting of json_foo_data() objects. This is only produced if the structure has list queries stipulated.
Enumerate only the fields of the structure p in JSON dictionary format. The key is the field name and the value is a string for text types, decimal number for reals, integer for integers, and base64-encoded string for blobs. If a field is null, it is serialised as a null value. Fields marked noexport are not included in the enumeration, nor are passwords.
Print a “blank” object consisting only of the structure data (see json_foo_data()) within JSON object braces. The calling convention (passing a void * as the struct kjsonreq) makes for easy integration with iterate functions. This is only produced if the structure has iterate queries stipulated.
Print the entire structure p as a key-value pair where the key is the structure name and the value is an object consisting of json_foo_data().

Utility functions for parsing buffers into objects defined in a ort(5) configuration. Unlike the functions in JSON export, these do not require any additional headers. The following use “foo” as an example structure.
Initialise a parser. This must be called each time before jsmn_parse() is invoked.
Parse a buffer buf of length sz into a series of tokens toks of length toksz. Returns less than zero on failure or the number of tokens parsed. If invoked with a NULL value for toks, tokens are parsed but not filled in. This is the usual practise for parsing an unknown set of objects: a set of tokens may be allocated using the non-negative return value.
Test whether the current token t referencing buffer buf is a string equal (case sensitive) to s.
Parse an object starting at token t referencing buffer buf with toksz remaining tokens into p. Returns less than zero on allocation failure, zero on parse error (malformed fields), or the number of tokens parsed. The input structure should be zeroed prior to calling. Regardless the return value, the resulting pointer should be passed to jsmn_foo_free().
Like jsmn_foo(), but allocating and filling an array of structures. The array must be freed with jsmn_foo_free_array() regardless the return value.
Free an array of structures, recursively clearing all nested data. Does nothing if p is NULL.
Recursively clears all nested data, not touching the pointer. Does nothing if p is NULL.

The parser writes the parse tree tokens into a linear array in infix order. Each node is either an object (consisting of string key and value pairs), an array, a primitive, or a string. To drive the parser, initialise a parse, parse the input (usually twice: once to get the number of tokens, the second to fill in tokens), recursively descend into the token stream. The descent should occur for all objects and arrays.

These functions invoke kcgi(3) to perform basic type validation. The following are required for including the produced functions.
#include <sys/types.h> /* kcgi(3) */
#include <stdarg.h> /* kcgi(3) */
#include <stdint.h> /* kcgi(3) */
#include <kcgi.h>

A full validation array is given for all fields, although these need not be used by the calling application. Given the same structure “foo”, the following are generated:

Validate the field “xxxx” in the structure. This should be used in place of raw validation functions such as kvalid_int(3). The validation function will at least validate the type. If limitation clauses are given to a field, those will also be emitted within this function. Note: structs are not validated.
An enumeration of all fields that accept validators. The enumeration entries are VALID_FOO_XXXX, where “XXXX” is the field name. The last enumeration value is always VALID__MAX.
A validation array for khttp_parse(3). This uses the valid_foo_xxxx() functions as described above and names corresponding HTML form entries as “foo-xxxx”, where again, “xxxx” is the field name.

The ort-c-header utility exits 0 on success, and >0 if an error occurs.

In the simplest case, put all C sources and headers (for validation, database routines, and JSON output) into one pair of files. Let foo.ort be the configuration file.
ort-c-header -jvs foo.ort > db.h
ort-c-source -jvs foo.ort > db.c

Breaking up into two header and source files: one for basic database functions, the other for JSON output.

ort-c-header -s foo.ort > db.h
ort-c-header -s -g JSON_H -j -Nbd foo.ort > json.h
ort-c-source -s -h db.h > db.c
ort-c-source -s -j -Nb -Ibj -h db.h,json.h > json.c

In this more complicated snippet, the json.h file is created without structure or database information using -N, -then json.c needs to include both database and JSON headers (in name, -h, and in the headers those stipulated in source, -I) also while inhibiting database routine creation with -N.

ort-c-source(1), kcgi(3), kcgijson(3), ksql(3), ort(5)
July 17, 2019 OpenBSD 6.5