window.markdeepOptions={tocStyle:"medium"} CData


  1.1  JS-Code
    1.1.1  CEnum
    1.1.2  CStruct
    1.1.3  CType
    1.1.4  CData
    1.1.5  Database
    1.1.6  Limitations
  1.2  C-Code
    1.2.1  Enums/Structs
    1.2.2  Commands
    1.2.3  Parameters
    1.2.4  Returned Value
    1.2.5  Vars
    1.2.6  Signatures
    1.2.7  JSC Definitions

Javascript Shell Interpreter

Types Builtin Reference  Index  Fossil  Demos Log Test Debug Misc



CData is used to defined structs whose field types overlap the basic C types. These can then be used to provide type-checked objects for functions.

Structs can be defined in either javascript or C. Either way, once defined structs use the same commands for accessing data.



To define structs in javascript we use the commands CStruct and CEnum.

Then a CData object can be used for type-checking a function:

CEnum('Fruit', 'apple,banana,orange,grape'); CStruct('Bee', 'int class:4; int size:4=8; Fruit fruit;'); function bee(options:object) { var d = new CData('Bee', options); return d.get(); return self; } bug({size:2); bug({size:3, male:true, fruit:'orange'}); bug({size:19});
/tmp/bug.jsi:10: error: for bitfield option "size": invalid value (at or near "19")

Note: CData with 2 args reports option errors from the invocation line.



There are 3 forms for enum definitions.

The simplest is the single-line form as above, which is split on comma:

CEnum.define('Fruit', 'apple,banana,orange,grape=9');

There is a multi-line form which is split on newlines, with comments extracted as help:

CEnum.define('Vegetable', '
    corn=0, // My favorite
    peas=2, // Your favorite

And there is an object form:

CEnum.define({name:'Herd'}, [
    {name:'goat', value:3, help:'set a value'},

Here are some test output from cdatatest.jsi:

CEnum.names() ==> [ "Fruit", "Herd", "Vegetable" ]
CEnum.names('Fruit') ==> [ "apple", "banana", "orange", "grape" ]
CEnum.conf('Fruit') ==> { flags:0, help:null, idx:4, name:"Fruit" }
CEnum.conf('Fruit', 'idx') ==> 4
CEnum.find('Fruit', 1) ==> banana
CEnum.fieldconf('Fruit', 'banana') ==> { flags:0, help:null, idx:1, name:"banana", value:1 }
CEnum.fieldconf('Fruit', 'banana', 'value') ==> 1
CEnum.value('Fruit', 'apple') ==> 0
CEnum.get('Fruit') ==> { fields:[ { name:"apple", value:0 }, { name:"banana", value:1 }, { name:"orange", value:2 }, { name:"grape", value:9 } ], name:"Fruit" }


As with CEnum, there are 3 forms of struct definitions.

The simplest is the single-line form as above, which is split on semicolon:

CStruct.define('Bee', 'int s:4; int r:3; int t=8; Fruit k;');

The multi-line form is split on newlines, with comments extracted as help:

CStruct.define('Pest', '
    int x=3;    // int field.
    Bee b;      // A sub-struct
    int y=5;

And there is an object form:

CStruct.define({name:'Bkey', help:'Struct to use for a key'}, [
        {name:'a', type:'int', help:'first key field'},
        {name:'b', type:'int', help:'second key field'}]

Field Type

The type of a struct field is one of:

Struct data is initialized to zero by default, but individual fields can be given a simple value using =.

Here are some test output from cdatatest.jsi:

CStruct.conf('Bee') ==> { crc:0, flags:0, help:null, idx:4, name:"Bee", size:6, ssig:0, value:10 }
CStruct.conf('Bee','name') ==> Bee
CStruct.names() ==> [ "Bkey", "Pest", "Bee", "Flower" ]
CStruct.names('Bee') ==> []
CStruct.fieldconf('Bee', 't') ==> { arrSize:0, bits:0, boffset:7, flags:1, help:null, idx:2, info:null, init:8, name:"t", offset:1, size:4, type:"int" }
CStruct.fieldconf('Bee', 's', 'bits') ==> 4
CStruct.get('Bee') ==> { fields:[ { bitoffs:0, bitsize:4, id:"int", isbit:0, label:"", name:"s", offset:0, size:4 }, { bitoffs:4, bitsize:3, id:"int", isbit:0, label:"", name:"r", offset:0, size:4 }, { bitoffs:7, bitsize:0, id:"int", isbit:0, label:"", name:"t", offset:1, size:4 }, { bitoffs:39, bitsize:0, id:"Fruit", isbit:0, label:"", name:"k", offset:5, size:1 } ], name:"Bee", size:6 }


CType is simply available to query available types: see Option Types.

Here are some test output from cdatatest.jsi:

CType.names().sort() ==> [ "ARRAY", "BOOL", "CUSTOM", "DOUBLE", "DSTRING", "FLOAT", "FUNC", "INT", "INT16", "INT32", "INT64", "INT8", "INTPTR_T", "LDOUBLE", "LONG", "NUMBER", "OBJ", "REGEXP", "SHORT", "SIZE_T", "SSIZE_T", "STRBUF", "STRING", "STRKEY", "TIME_D", "TIME_T", "TIME_W", "UINT", "UINT16", "UINT32", "UINT64", "UINT8", "UINTPTR_T", "ULONG", "USEROBJ", "USHORT", "VALUE", "VAR" ]
CType.names(true).sort() ==> [ "Bee", "Bkey", "Flower", "Fruit", "Herd", "Jsi_DString", "Jsi_Number", "Jsi_Strbuf", "Jsi_Value", "Pest", "Vegetable", "bool", "const char", "double", "float", "int", "int16_t", "int32_t", "int64_t", "int8_t", "intptr_t", "ldouble", "long", "short", "size_t", "ssize_t", "time_d", "time_t", "time_w", "uint", "uint16_t", "uint32_t", "uint64_t", "uint8_t", "uintptr_t", "ulong", "ushort" ]
CType.conf('INT') ==> { cName:"int", flags:0, fmt:"d", help:"Integer", idName:"INT", size:4, user:0, xfmt:"#x" }
CType.conf('INT','flags') ==> 0


A basic JS use of CData to create and manipulate a single struct is:

var alpha  = new CData('Bee');
alpha.get(null, 't');
alpha.set(null, 't', 4);

Data is accessed with set/get/incr:

alpha.get(null) ==> { k:"apple", r:0, s:0, t:8 }
alpha.get(null, 't') ==> 8
alpha.set(null, 't', 4) ==> undefined
alpha.incr(null, 't', 1) ==> 5
n=alpha.get(null, 't') ==> 5

As above there is also an object form:

var bees   = new CData({structName:'Bee', arrSize:10, help:'An array of bees'});

The string form is the simplest way to create maps and hashes of structs.

var alpha, beta, tree, tree2, tree3, hash, hash2, hash3, pest, flower, n;
beta   = new CData('Bee[10]');      // Array
tree   = new CData('Bee{}');        // Map with string key
tree2  = new CData('Bee{0}');       // Map with number key
tree3  = new CData('Bee{@Bkey}');   // Map with struct key
hash   = new CData('Bee{#}');       // Hash with string key
hash2  = new CData('Bee{#0}');      // Hash with number key
hash3  = new CData('Bee{#@Bkey}');  // Hash with struct key

which are indexed with a non-null key:

beta.set(0, 't', 2);
tree.set('X', 't', 2);
hash.set('X', 't', 2);

Struct keys are also supported:

bkey={a:1,b:2} ==> { a:1, b:2 }
tree3.set(bkey, 't', 2) ==> undefined
tree3.get(bkey, 't') ==> 2


Database definitions may be extracted from struct definitions and used with Sqlite:

var db = new Sqlite('/tmp/bees.db') ==> "#Sqlite_1"
schema = CStruct.schema('Bee') ==>
  s int
 ,r int
 ,t INT
 ,k TEXT
  -- MD5=2c2573332fca5f166b7272366bd888b0
);') ==> undefined
db.query('INSERT INTO Bee %s',{cdata:'beta'}) ==> 10
db.query('SELECT %s FROM Bee',{cdata:'beta'}) ==> 10


JS-defined structs differ from C-defined ones in that they:



Definitions in ".jsc” files are preprocessed with “jsish -c”. The resulting ".h” output file contains compile-ready code.



Structs and enums are defined in “jsc” as follows:

enum BeeType = {

struct Bee = {
    int max;
    int buzzCnt;
    int stingCnt;
    int pollinateCnt;
    BeeType type;
    STRING32 flower;

The available struct field types are:

bool int8_t int16_t int32_t int64_t uint8_t uint16_t
uint32_t uint64_t float double ldouble Jsi_Strbuf time_w time_d time_t size_t
intptr_t uintptr_t Jsi_Number int uint long ulong short ushort Jsi_Value*
Jsi_DString Jsi_Value* Jsi_Value* Jsi_Value* Jsi_Value* Jsi_Value* Jsi_Value* Jsi_Value*
Jsi_Strkey const char*

Also supported are “char” arrays and “STRING2", “STRING4", ...: “jsi.h” has “STRING"n typedefs for every power of 2 up to 64k.

All other types will be ignored or, like “void *", are used for custom types.



There are two types of extension-commands in Jsi:

Name Description
Object Object commands with constructors eg. 'new RegExp(/abc/)'
Non-object Non-object commands, eg. 'Interp.conf()'

Here is an excerpt from the example c-demos/cdata/Bee.jsc:

vars MyVars = {
    Bee Bee_Data;

extension Bee = { // Extension to create Bee commands.

    function conf(options:object|string=void):any { // Function to configure Bee options
        /* C code. */

    function buzz(n1:number):number { // Buzz
        /* C-code. */
        Bee_Data.buzzCnt += n1;
        Jsi_Number n = Bee_Data.buzzCnt;

    function sting(victim:string, times:number):string { // Sting
        /* C-code. */
        char buf[BUFSIZ];
        Bee_Data.stingCnt += times;
        snprintf(buf, sizeof(buf), "stung %s %g times", victim, times);
        RETURN(buf); //:string

    function pollinate(flower:string='daisy', times:number=1):void { // Pollinate
        /* C-code. */
        Bee_Data.pollinateCnt += times;
        Jsi_Stzcpy(Bee_Data.flower, flower);
        RETURN(); //:undefined


Note how function types are employed to simplify the interface. Next we generate it with:

jsish -c -outFile Bee.h Bee.jsc

To compile as a standalone we can use:

gcc -o Bee -I../.. -x c Bee.h -lpthread -ldl -lm -lz -DCDATA_MAIN

Or compile as a shared library using:

gcc -o -I../.. -x c Bee.h -fPIC -shared -lpthread -ldl -lm -lz -DCDATA_MAIN=1 -DCDATA_SHARED=1

And run it like so:

Bee.sting('dog', 2);
Bee.conf({type:'Worker', buzzCnt:3});

Other examples in c-demos/cdata are:



Parameters are unloaded into function-local vars based on their type (singular). Type Unions are currently unsupported and simply ignored.

Several function names are treated specially:

Also if you define a “var” with the same name, but ending with “_Data” (eg. Bee_Data above) you can access the state via “Cdata.get()" etc (non-object commands only).


Returned Value

To return a function values, the “RETURN()" statement is used on a line by itself. The function return type determines what actually gets returned. As with parameters, this must not be a “Type Union”.



The example in c-demos/cdata/demo0.jsc defines two struct “Foo” and “Bar”.

vars MyVars = {
    Bar     bar;        // Struct Bar.
    Foo     foo;        // Struct Foo.

    Foo     foos[10];   // Array of Foo structs.
    Foo     foos2[FooSize];// Array of Foo structs with enum size.
    Bar     barss[10];  // Array of Bar.

    Bar     bars{};     // Map-Tree with string-key.
    Bar     BN{0};      // Map-Tree with integer-key.
    Bar     Bs{@Fidx};   // Map-Tree with struct-key.

    Bar     Bs2{#};     // Map-Hash with string-key
    Bar     BN2{#0};    // Map-Hash with integer key.
    Bar     Bs2a{#@Fidx};// Map-Hash with struct-key.

Three different types of var-structs are declared:

For maps:

A map can readily store large quantities of data, while arrays are useful for database queries.

Examples in c-demos/cdata using vars are:



If the first field of a struct has the name “sig”, it will be treated as a signature. This is a special integer value used to identify the struct. If not given a value, it will be a crc32 value calculated against the struct definition string without its field names and comments.

Signatures play a special role in data sent over the network.


JSC Definitions

Each definition in a ".jsc” file ends with a single close curley brace + semicolon at the start of line.

var startOfMarkDeep=true; window.alreadyProcessedMarkdeep||('visible'); document.title=location.pathname.match(/\/([\w]+)1;

formatted by Markdeep 1.03