ORT-C-HEADER(1) | General Commands Manual | ORT-C-HEADER(1) |
ort-c-header
—
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:
-j
-J
-s
int
) are embedded in typed structures to prevent
mis-assignment.-v
-g
guard-N
bdBy 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; };
By default, 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; company_id id; };
Integer and epoch fields use defined types with the name of the structure, an underscore, then the field name. If safe typing is enabled, these are implemented as structures with a single integer field whose name is not fixed. Otherwise, the type is an alias for int64_t or time_t, as appropriate.
typedef int64_t company_id; # typedef struct { int64_t val } company_id;
Integers may be set, get, or assigned by using the following macros or inline functions. These should be used when safe types are enabled and are also produced in non-safe mode for easier transition. Callers should not assume they are implemented as either macros or functions, however, as this may change.
ORT_company_id
(int64_t
x)ORT_GET_company_id
(const
struct company *p)ORT_GETV_company_id
(const
company_id p)ORT_GET_company_id
(), but getting the
int64_t value directly from the field.ORT_SET_company_id
(struct
company *p, int64_t val)ORT_SETV_company_id
(company_id
*p, int64_t val)ORT_SET_company_id
(), but setting
val directly to the field
p.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
-l
sqlbox 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,
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.
db_close
(struct
ort *p)db_open
(). Passing
NULL
is a noop.*db_open
(const
char *file)db_open_logging
(), but with
NULL
values for all parameters except
file.*db_open_logging
(const
char *file, void (*log)(const char *, void *),
void (*log_short)(const char *, ...),
void *log_arg)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.
db_logging_data
(struct
ort *p, const void *arg, size_t
sz)db_open_logging
().
The binary data in arg of byte size
sz are passed to the child process.db_trans_commit
(struct
ort *p, size_t id)db_trans_open
()
with identifier id. If an error occurs, subsequent
database access will cause the system to exit(3).db_trans_open
(struct
ort *p, size_t id, int
mode)db_trans_rollback
(struct
ort *p, size_t id)db_trans_open
()
with identifier id. If an error occurs, subsequent
database access will cause the system to exit(3).db_role
(struct
ort *ctx, enum ort_role newrole)ROLE_default
or entering
ROLE_none
. This does not return failure: on role
violation, it invokes abort(2).db_role_current
(struct
ort *ctx)db_role
()
hasn't yet been called, this will be
ROLE_default
.db_role_stored
(struct
ort_store *ctx)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.
db_foo_delete_xxxx
(struct
ort *p, ARGS)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.db_foo_delete_by_yy_op
(struct
ort *p, ARGS)db_foo_delete_xxxx
(),
but using an un-named delete
statement constrained
by "yy" with operation "op".db_foo_free
(struct
foo *p)NULL
, this is a noop.db_foo_freeq
(struct
foo_q *p)*db_foo_get_xxxx
(struct
ort *p, ARGS)search
statement named "xxxx". The
function accepts variables for all binary-operator fields to check (i.e.,
all except for those checking for null).*db_foo_get_by_xxxx_op1_yy_zz_op2
(struct
ort *p, ARGS)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".db_foo_insert
(struct
ort *p, ARGS)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.db_foo_iterate
(struct
ort *p, foo_cb cb, void
*arg, ARGS)db_foo_iterate_xxxx
()
but iterating over all rows.db_foo_iterate_xxxx
(struct
ort *p, foo_cb cb, void
*arg, ARGS)db_foo_get_xxxx
(), but invoking a function
callback cb passed arg within
the active query for each retrieved result.db_foo_iterate_by_xxxx_op1_yy_zz_op2
(struct
ort *p, foo_cb cb, void
*arg, ARGS)db_foo_get_by_xxxx_op1_yy_zz_op2
(),
but invoking a function callback for each retrieved result.db_foo_count
(struct
ort *p)db_foo_count_xxxx
()
but returning a count of all rows.db_foo_count_xxxx
(struct
ort *p, ARGS)db_foo_get_xxxx
(), but returning a count of
all rows returned.db_foo_count_by_xxxx_op1_yy_zz_op2
(struct
ort *p, ARGS)db_foo_get_by_xxxx_op1_yy_zz_op2
(), but
returning a count of all rows returned.*db_foo_list
(struct
ort *p)db_foo_list_xxxx
()
but allocating and filling a queue of all rows.*db_foo_list_xxxx
(struct
ort *p, ARGS)db_foo_get_xxxx
(), but producing a queue of
responses.*db_foo_list_by_xxxx_op1_yy_zz_op2
(struct
ort *p, ARGS)db_foo_get_by_xxxx_op1_yy_zz_op2
(), but
producing a queue of responses.db_foo_update_xxxx
(struct
ort *p, ARGS)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.db_foo_update_xx_mod_by_yy_op
(struct
ort *p, ARGS)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.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.
json_foo_array
(struct
kjsonreq *r, const struct foo_q *q)json_foo_data
()
objects. This is only produced if the structure has
list
queries stipulated.json_foo_data
(struct
kjsonreq *r, const struct foo *p)noexport
are not
included in the enumeration, nor are passwords.json_foo_iterate
(const
struct foo *p, void *arg)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.json_foo_obj
(struct
kjsonreq *r, const struct foo *p)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.
jsmn_init
(jsmn_parser
*p)jsmn_parse
()
is invoked.jsmn_parse
(jsmn_parse
*p, const char *buf, size_t
sz, jsmntok_t *toks, unsigned
int toksz)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.jsmn_eq
(const
char *buf, const jsmntok_t *t,
const char *s)jsmn_foo
(struct
foo *p, const char *buf, const
jsmntok_t *t, size_t toksz)jsmn_foo_free
().jsmn_foo_array
(struct
foo **p, size_t *sz, const char
*buf, const jsmntok_t *t, size_t
toksz)jsmn_foo
(),
but allocating and filling an array of structures. The array must be freed
with
jsmn_foo_free_array
()
regardless the return value.jsmn_foo_free_array
(struct
foo *p, size_t sz)NULL
.jsmn_foo_clear
(struct
foo *p)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:
valid_foo_xxxx
(struct
kpair *p)VALID_FOO_XXXX
, where "XXXX"
is the field name. The last enumeration value is always
VALID__MAX
.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 -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)
October 25, 2021 | OpenBSD 6.7 |