KWEBAPP-C-HEADER(1)

NAME
kwebapp-c-header - define web application C API

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

DESCRIPTION
The kwebapp-c-header utility accepts a kwebapp(5) config (defaulting to standard input) and produces a C API describing the configuration. The configuration may be broken apart into several files. These declarations is usually defined by the output of kwebapp-c-source(1). Its arguments are as follows:

-j  Output JSON output declarations as documented in JSON export.

-J  Like -j, but for JSON import functions.

-v  Output data validators declarations as documented in Data validation.

-g guard
    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.

-s  Use split-process mode for the database. This only changes generated documentation.

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

All C code produced by kwebapp-c-header conforms with the style(9) manual of OpenBSD.

If you're linking to the header file, different output options require different pre-inclusion needs.

  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, you'll need:

    #include <sys/queue.h> /* iff you have 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 kwbp_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 kwbp_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 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 kwbp_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 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 you're using roles, you do not need any inclusions.

There are two functions that work with opening and closing the database. When roles are not defined, these may be overridden. There are also several transaction functions and, if applicable, a function for managing roles.

In the following documentation, "TYPE" is defined as struct kwbp if roles are defined or struct ksql otherwise.

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

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

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

void db_trans_open(TYPE *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(TYPE *p, size_t id)
    Roll-back a transaction opened by db_trans_open() with unique transaction identifier id.

void db_role(struct kwbp *ctx, enum kwbp_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 kwbp_role db_role_current(struct kwbp *ctx)
    Get the currently-assigned role. If db_role() hasn't yet been called, this will be ROLE_default.

enum kwbp_role db_role_stored(struct kwbp_store *ctx)
    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 kwbp if roles are defined or struct ksql otherwise.

int db_foo_delete_xxxx(TYPE *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(TYPE *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(TYPE *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(TYPE *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(TYPE *p, foo_cb cb, void *arg, ARGS)
    Iterate over all rows.

void db_foo_iterate_xxxx(TYPE *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(TYPE *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(TYPE *p)
    Allocate and fill a queue of all rows.

struct foo_q *db_foo_list_xxxx(TYPE *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(TYPE *p, ARGS)
    Like db_foo_get_by__xxxx_op1__yy_zz_op2(), but producing a queue of responses.

int db_foo_update_xxxx(TYPE *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_by_yy_op(TYPE *p, ARGS)
    Like db_foo_update_xxxx(), but using an un-named update statement modifying "xx" constrained by "yy" with operation "op".

void db_foo_update_by_yy_op(TYPE *p, ARGS)
    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).

DB_SCHEMA_XXX(name)
    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.

void db_foo_fill(struct foo *p, struct ksqlstmt *stmt, size_t *pos)
    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.

void db_foo_unfill(struct foo *p)
    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.

  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 kwebapp(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.kwbp be the configuration file.

    kwebapp-c-header -jvs foo.kwbp > db.h
    kwebapp-c-source -jvs foo.kwbp > db.c

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

    kwebapp-c-header -s foo.kwbp > db.h
    kwebapp-c-header -s -g JSON_H -j -Nbd foo.kwbp > json.h
    kwebapp-c-source -s -h db.h > db.c
    kwebapp-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.

SEE ALSO
kwebapp-c-source(1), kcgi(3), kcgijson(3), ksql(3), kwebapp(5)