ORT-C-HEADER(1)

NAME
ort-c-header - generate ort C API

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

DESCRIPTION
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:

-j  Output JSON export function declarations.

-J  Output JSON import function declarations.

-v  Output Data validation function and variable declarations.

-g guard
    Preprocessor guard for header re-inclusion. Defaults to DB_H. This is not sanity-checked.

-N 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.

-s  This flag is retained only for backward compatibility.

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

  Data structures
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. 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.

  Database input
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... */

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.

struct ort *db_open(const char *file)
    Open a database named file and return a pointer. Returns NULL on failure to allocate, open, or configure the database.

void db_close(struct ort *p)
    Closes a database opened by db_open(). Passing NULL is a noop.

void db_trans_commit(struct ort *p, size_t id)
    Commit a transaction opened by db_trans_open() with unique transaction identifier id.

void db_trans_open(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.

void db_trans_rollback(struct ort *p, size_t id)
    Roll-back a transaction opened by db_trans_open() with unique transaction identifier id.

void db_role(struct ort *ctx, enum ort_role r)
    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).

enum ort_role db_role_current(struct ort *ctx)
    If roles are enabled, get the currently-assigned role. If db_role() hasn't yet been called, this will be ROLE_default.

enum ort_role db_role_stored(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 delete, insert, iterate, list, search, and update statements in the configuration. Let "foo" be the name of the exemplar structure.

int db_foo_delete_xxxx(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. Returns non-zero on success, zero on constraint failure.

int db_foo_delete_by_yy_op(struct ort *p, ARGS)
    Like db_foo_delete_xxxx(), but using an un-named delete statement constrained by "yy" with operation "op".

void db_foo_free(struct foo *p)
    Frees a pointer returned by a unique search function. If passed NULL, this is a noop.

void db_foo_freeq(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 *db_foo_get_xxxx(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 *db_foo_get_by_xxxx_op1_yy_zz_op2
    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".

int64_t db_foo_insert(struct ort *p, ARGS)
    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.

void db_foo_iterate(struct ort *p, foo_cb cb, void *arg, ARGS)
    Iterate over all rows.

void db_foo_iterate_xxxx(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 db_foo_iterate_by_xxxx_op1_yy_zz_op2(struct ort *p, foo_cb cb, void *arg, ARGS)
    Like db_foo_get_by_xxxx_op1_yy_zz_op2(), but invoking a function callback for the retrieved results.

struct foo_q *db_foo_list(struct ort *p)
    Allocate and fill a queue of all rows.

struct foo_q *db_foo_list_xxxx(struct ort *p, ARGS)
    Like db_foo_get_xxxx(), but producing a queue of responses.

struct foo_q *db_foo_list_by_xxxx_op1_yy_zz_op2(struct ort *p, ARGS)
    Like db_foo_get_by_xxxx_op1_yy_zz_op2(), but producing a queue of responses.

int db_foo_update_xxxx(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 db_foo_update_xx_mod_by_yy_op(struct ort *p, ARGS)
    Like db_foo_update_xxxx(), 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.

  JSON export
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>

void json_foo_array(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 json_foo_data() objects. This is only produced if the structure has list queries stipulated.

void json_foo_data(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 json_foo_iterate(const struct agent *, 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 json_foo_obj(struct kjsonreq *r, const struct agent *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().

  JSON import
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_init(jsmn_parser *p)
    Initialise a parser. This must be called each time before jsmn_parse() is invoked.

int jsmn_parse(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 jsmn_eq(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 jsmn_foo(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 jsmn_foo_free().

int jsmn_foo_array(struct foo **p, size_t *sz, const char *buf, const jsmntok_t *t, size_t toksz)
    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.

void jsmn_foo_free_array(struct foo *p, size_t sz)
    Free an array of structures, recursively clearing all nested data. Does nothing if p is NULL.

void jsmn_foo_clear(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.

  Data validation
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 valid_foo_xxxx(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. Note: 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 valid_foo_xxxx() functions as described above and names corresponding HTML form entries as "foo-xxxx", where again, "xxxx" is the field name.

EXIT STATUS

EXAMPLES
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.

SEE ALSO
ort-c-source(1), kcgi(3), kcgijson(3), sqlbox(3), ort(5)