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

Contents

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
 DOWNLOAD / DEVELOP / DEPLOY

Types Builtin Reference  Index  Fossil  Demos Log Test Debug Misc

   

CData

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.

   

JS-Code

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.

   

CEnum

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
    potato=-1
');

And there is an object form:

CEnum.define({name:'Herd'}, [
    {name:'sheep'},
    {name:'goat', value:3, help:'set a value'},
    {name:'cow'}]);

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" }
   

CStruct

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

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
   

CData

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

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
db.eval('CREATE TABLE IF NOT EXISTS Bee (
'+schema+'
);') ==> undefined
db.query('INSERT INTO Bee %s',{cdata:'beta'}) ==> 10
db.query('SELECT %s FROM Bee',{cdata:'beta'}) ==> 10
   

Limitations

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

   

C-Code

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

   

Enums/Structs

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

enum BeeType = {
    Drone,
    Worker,
    Queen
};

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.

   

Commands

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;
        RETURN(n);
    }

    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
./Bee

Or compile as a shared library using:

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

And run it like so:

"jsish"
require('Bee');
Bee.pollinate();
Bee.sting('dog', 2);
Bee.conf({type:'Worker', buzzCnt:3});
Cdata.get('Bee_Data');

Other examples in c-demos/cdata are:

   

Parameters

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

   

Vars

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:

   

Signatures

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||(document.body.style.visibility='visible'); document.title=location.pathname.match(/\/([\w]+)1;

formatted by Markdeep 1.03