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

ort-c-headergenerate ort C API

ort-c-header [-jJv] [-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.
guard
Preprocessor guard for header re-inclusion. Defaults to DB_H. This is not sanity-checked.
bd
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.
This flag is retained only for backward compatibility.

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. Unless as otherwise noted, all fields except for string literal data (e.g., comments) are printed in lowercase. 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. This only happens if roles are specified in config, such as:

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 {
  ROLE_user,
  ROLE_none,
  ROLE_default
};

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 structure 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 sqlbox(3) for handling the database itself, so the -lsqlbox library is required for linking. Depending on your operating system, you may need the following inclusion before including the header file.

#include <stdint.h> /* int64_t... */

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

void (struct ort *p)
Closes a database opened by db_open(). Passing NULL is a noop.
struct ort (const char *file)
Like db_open_logging(), but with NULL values for all parameters except file.
struct ort (const char *file, void (*log)(const char *, void *), void (*log_short)(const char *, ...), void *log_arg)
Open a database named file and return a pointer.

If log is not set, it will be invoked within the child or parent process on database errors with the error message first, then log_arg as the second parameter. It must not have any side effects. If log_short is set and log is NULL, it is used and is compatible with the warn(3) family of functions.

Returns NULL on failure to allocate, open, or configure the database.

void (struct ort *p, const void *arg, size_t sz)
Set the opaque pointer log_arg as otherwise passed to (). The binary data in arg of byte size sz are passed to the child process.
void (struct ort *p, size_t id)
Commit a transaction opened by () with identifier id. If an error occurs, subsequent database access will cause the system to exit(3).
void (struct ort *p, size_t id, int mode)
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. Using >0 is the preferred way of creating database transactions. If an error occurs, subsequent database access will cause the system to exit(3).
void (struct ort *p, size_t id)
Roll-back a transaction opened by db_trans_open() with identifier id. If an error occurs, subsequent database access will cause the system to exit(3).
void (struct ort *ctx, enum ort_role newrole)
If roles are enabled, move from the current role to newrole. 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).
enum ort_role (struct ort *ctx)
If roles are enabled, get the currently-assigned role. If () hasn't yet been called, this will be ROLE_default.
enum ort_role (struct ort_store *ctx)
If roles are enabled, 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 count, delete, insert, iterate, list, search, and update statements in the configuration. Let "foo" be the name of the exemplar structure.

void (struct ort *p, ARGS)
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.
void (struct ort *p, ARGS)
Like (), but using an un-named delete statement constrained by "yy" with operation "op".
void (struct foo *p)
Frees a pointer returned by a unique search function. If passed NULL, this is a noop.
void (struct foo_q *p)
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.
struct foo (struct ort *p, ARGS)
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).
struct foo (struct ort *p, ARGS)
Like (), 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".
int64_t (struct ort *p, ARGS)
Insert a row and return its 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.
void (struct ort *p, foo_cb cb, void *arg, ARGS)
Like () but iterating over all rows.
void (struct ort *p, foo_cb cb, void *arg, ARGS)
Like db_foo_get_xxxx(), but invoking a function callback cb passed arg within the active query for each retrieved result.
void (struct ort *p, foo_cb cb, void *arg, ARGS)
Like (), but invoking a function callback for each retrieved result.
uint64_t (struct ort *p)
Like () but returning a count of all rows.
uint64_t (struct ort *p, ARGS)
Like db_foo_get_xxxx(), but returning a count of all rows returned.
uint64_t (struct ort *p, ARGS)
Like db_foo_get_by_xxxx_op1_yy_zz_op2(), but returning a count of all rows returned.
struct foo_q (struct ort *p)
Like () but allocating and filling a queue of all rows.
struct foo_q (struct ort *p, ARGS)
Like db_foo_get_xxxx(), but producing a queue of responses.
struct foo_q (struct ort *p, ARGS)
Like db_foo_get_by_xxxx_op1_yy_zz_op2(), but producing a queue of responses.
int (struct ort *p, ARGS)
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.
int (struct ort *p, ARGS)
Like (), but using an un-named update statement modifying "xx" with modifier "mod" constrained by "yy" with operation "op". Either or both modifiers and constraints may be empty. If modifiers are empty, all fields are modified by setting. If constraints are empty, they and the preceding "by" are omitted.

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>

All structure and field names are expressed in lowercase.

void (struct kjsonreq *r, const struct foo_q *q)
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 () objects. This is only produced if the structure has list queries stipulated.
void (struct kjsonreq *r, const struct foo *p)
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.
void (const struct foo *p, void *arg)
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.
void (struct kjsonreq *r, const struct foo *p)
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.

int (jsmn_parser *p)
Initialise a parser. This must be called each time before () is invoked.
int (jsmn_parse *p, const char *buf, size_t sz, jsmntok_t *toks, unsigned int toksz)
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.
int (const char *buf, const jsmntok_t *t, const char *s)
Test whether the current token t referencing buffer buf is a string equal (case sensitive) to s.
int (struct foo *p, const char *buf, const jsmntok_t *t, size_t toksz)
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 ().
int (struct foo **p, size_t *sz, const char *buf, const jsmntok_t *t, size_t toksz)
Like (), but allocating and filling an array of structures. The array must be freed with () regardless the return value.
void (struct foo *p, size_t sz)
Free an array of structures, recursively clearing all nested data. Does nothing if p is NULL.
void (struct foo *p)
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:

int (struct kpair *p)
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. : structs are not validated.
enum valid_keys
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.
const struct kvalid valid_keys[VALID__MAX]
A validation array for khttp_parse(3). This uses the () 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 -jv foo.ort > db.h
% ort-c-source -jv 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 foo.ort > db.h
% ort-c-header -g JSON_H -j -Nbd foo.ort > json.h
% ort-c-source -h db.h > db.c
% ort-c-source -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-manpage(1), ort-c-source(1), kcgi(3), kcgijson(3), sqlbox(3), ort(5)

April 5, 2021 OpenBSD 6.7