/* VS4/Zrec - (formerly AVLDB) DataBase library/engine.
SPDX-License-Identifier: GPL-3.0-or-later
Meta-scheme content, C symbol descriptions + types for RECC
(was: sd-defs.h, was: zc-ctypes.h)
This file is part of VS4/zrec/avldb.
Copyright ⓒ 2019,2020,2021,2022,2023
Petr Šilhavý <petr.silhavy@yandex.com>
VS4/Žrec is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
VS4/Žrec is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Žrec. If not, see <http://www.gnu.org/licenses/>.
*/
module zc_ctypes ;
import std.string : fromStringz ;
import std.conv ;
import std.stdio;
import std.format : format;
import libclang ;
import clang_parser : verbose_flag, clang_parse ;
import zc_magic ;
import mm ;
/** Sematics of struct*
===================
struct A
{
...
I. struct B b { ... }; <= HasA B ( dump/load: nested data expected/possible )
II. struct B[] ba [] { ... } ; <= HasMany B (nested data expected)
III.struct C *c ; <= HasA C ( no nested data expected )
IV. struct C *ca[] ; <= HasMany C ( no nested data expected )
V. struct { ... } d ; or <= various kinds of ANON struct
struct _No-file { ... } dn
VI. struct { ... } da[] ;
struct _No-file { ... } dan[] ;
} a ;
I. b is table B's record b + a has b ( b is part of/property of a )
II. ba is array of I.
III.a has c. c is part of/property of a
IV. ca is array of III.
V. d is anonymous structured data (ASD/No-file-struct) A.#/...
VI. da is array of V.
.zc :
{
...
link pets ; // cats,dogs,HW,planes,... <= polymorphic/type-less HasMany
same as unix directory with symlinks:
pets/
Cindy -> ../../dogs/cindy/777
Towser -> ../../dogs/towser/12345
Hermenegilde -> ../../cats/...
int i = pets.qty
link
====
- has no fixed table destination ( if ! fixed destination )
- has qty for each destination
- flags :
- fixed destination
- is BLOB
- IS_PTR -> conv to C
- IS_ARR -> conv to C
struct *clnk, *clarr[] should be replaced with link w/ fixed destination
!!! link field is NOT in *.h !!!!
C struct => disk mapping
========================
IS_POD_STRUCT
-------------
cs.itype & IS_POD_STRUCT => HDR + 1:1
IS_DYN_STRUCT
-------------
cs.itype & IS_DYN_STRUCT
HDR +
field ca attribute ba2 ;
field c attribute ba2 ;
link l attribute ba2 ;
// rest is unsuported :
field c attribute "struct _No-filexyz { int i ; struct A a } ;"
link l attribute "{ unsigned long long ull ; }"
}
struct _NF
{
same as notable/nofile ;
// attribute only/ASD - open table => error ;
// My oath: I'll never use NF as normal data table
...
}
Lenght of field
===============
Helper field is size_t or ***BOOOM***
*/
void * dmemcpy ( void * destination, const void * source, size_t num ) pure nothrow
{
(cast(ubyte*)destination)[0 .. num][]=(cast(const(ubyte)*)source)[0 .. num];
return destination;
}
/**
* compose ( or Integrated TYPE ) for dump/load to/from CSV,JSON
*
* ``everything`` is possible, except void V[42] ;
*/
enum ZCIT
{
UNSET = 0 ,
IS_PTR = 0x1, // lives in pointer's space
IS_LINK = 0x2,
IS_SUB_STRUCT = IS_LINK, /**< sample: struct MUMBLE m ;
- sub STRUCT AKA ``link``
- lives in link parts
*/
IS_LINK_DATA = 0x4, // ????
IS_POD_STRUCT = 0x8, /**
* struct contains fixed length items only
* struct X { char s[14] ; int i ; long l ; double d;}
*/
IS_DYN_STRUCT = 0x10, /**
* struct contains too
* variable len arrays { char *c ; int *i ; ... }
*/
IS_STRUCT_FIELD = 0x20,
IS_ARRAY = 0x40, // has [LEN] : cv.array_length
IS_ANON = 0x80, /**
* No name tag :
* struct { int i ; float f ; }
*/
// pointer to/array of
IS_OF_CHAR = 0x100 , // char*
IS_OF_DIGIT = 0x200 , // int*
IS_DIGIT = 0x400, /**< sample: long ll ;
- char ... long double
- lives is static part
*/
DIGIT = IS_DIGIT,
HAS_LEN = 0x1000, // GString , C++ string , D string
HAS_LEN_OF = 0x2000, /** lenght of this variable is stored in other var :
* C_VAR.length -> C_VAR
* - lenght holding variable type should be 4/8 bytes unisigned
* - size MUST be in BYTES
*/
ANON_STRUCT = IS_ANON, /** struct { int i ; } or struct _NONANE { ... }
* sample: struct _MUMBLE { int m[42] ; }
*
* acceptable types:
* - all POD
* - link as struct *S, struct *S[], struct J[]
*
* lives in POD part
*/
POINTER_TO_CHAR = IS_OF_CHAR | IS_PTR, /**< sample : char *p ;
- variable length
- zero \0 terminated => strlen() works
- lives is pointer part,
- for array of bytes use void * ,
which'll be evaluated as POINTER_TO_DIGIT :P
- CSV encoded as ?
- JSON encoded as ?
*/
POINTER_TO_CHAR_WL = IS_OF_CHAR | IS_PTR | HAS_LEN_OF, /**< sample : char *p ; w/ length_of;
- variable length
- zero \0 terminated => strlen() may work
- lives is pointer part,
- acceptable as array of bytes
- CSV encoded as ?
- JSON encoded as ?
*/
POINTER_TO_CHAR_GS = IS_OF_CHAR | IS_PTR | HAS_LEN,/** glib GString *str/ D/C++ string
sample : GString *p
- variable length in str->len
- zero \0 terminated => strlen() may work
- lives is pointer part,
- acceptable as array of bytes
- CSV encoded as ?
- JSON encoded as ?
_GS version differs from other char * types
only on :
- input from (user's) struct
- output
*/
deprecated POINTER_TO_DIGIT = IS_PTR | IS_OF_DIGIT ,/**< float *ftp;
- variable length
- everything from void * ... int * ... double *
- CSV/JSON encoded : [ VAL0 ... ] ,
- MUST have lenght of
- lives is pointer part,
*/
POINTER_TO_DIGIT_WL = IS_OF_DIGIT | IS_PTR | HAS_LEN_OF,/**< float *ftp;
- variable length
- everything from void * ... int * ... double *
- CSV/JSON encoded : [ VAL0 ... ] ,
- MUST have lenght of
- lives is pointer part,
*/
/+
deprecated PTPT_DIGIT = 0x,/**< float **ftpa;
- variable length
- everything from void * ... int * ... double *
- CSV/JSON encoded : [ VAL0 ... ] ,
- MUST be NULL terminated
- lives is pointer part,
- differs from POINTER_TO_DIGIT - on I/O
- no lenght of required
*/
+/
ARRAY_OF_CHAR = IS_OF_CHAR | IS_ARRAY, /**< sample: char [7];
- fixed length [MAXLEN]
- zero \0 terminated => strlen() works
- has array_length set to [MAXLEN]
- lives is static part
- CSV encoded as ?
- JSON encoded as ?
*/
ARRAY_OF_DIGIT = IS_OF_DIGIT | IS_ARRAY, /**< sample: int[42];
- char ... long double
- fixed length [MAXLEN]
- has array_length set to [MAXLEN]
- lives is static part
- CSV encoded as [ VAL0 ... ]
- JSON encoded as [ VAL0 ... ]
*/
// ARRAY_OF_STRUCT = STRUCT | IS_ARRAY ,
ARRAY_OF_ANON_STRUCT = ANON_STRUCT | IS_ARRAY ,
// POINTER_TO_STRUCT = STRUCT | IS_LINK , /// NO POINTER Is correct here,
/// thanks to silly semantics
/**< sample: struct MUMBLE *m
- sub STRUCT AKA ``link``
- lives in link part
- with length_of ->
non NULL terminated array of pointers
*/
deprecated PTPT_STRUCT, /** Pointer To Pointer To struct AKA array of pointers to struct
sample: struct MUMBLE **m
- MUST be NULL terminated array of pointers
- sub STRUCT AKA ``link`` array
- lives in link part
*/
// FIXME: add GString or similar ``C++`` string
// ZCIT_EOF = -1 ,
LINK = IS_LINK,
LINK_ARRAY = LINK | IS_ARRAY ,
IGNORED = 0x10_0000, /** pseudo type to ignore var */
}
/**
*
* Keyword ``length_of`` and composite types
*
* ======================== ========= ======== ===================================
* IType Mandatory Optional Other
* ======================== ========= ======== ===================================
* ZCIT__POINTER_TO_CHAR N N w/ len => ZCIT__POINTER_TO_CHAR_WL
* ZCIT__POINTER_TO_CHAR_WL ND* N Upgraded from char *, if possible
* ZCIT__POINTER_TO_CHAR_GS N N Redundant - gstring->len
* ZCIT__POINTER_TO_DIGIT ND* N
* ZCIT__PTPT_DIGIT N N
* ZCIT__ARRAY_OF_CHAR N N
* ZCIT__ARRAY_OF_DIGIT N N
* ZCIT__DIGIT N N
* ZCIT__STRUCT N N
* ZCIT__ARRAY_OF_STRUCT N N
* ZCIT__POINTER_TO_STRUCT N* N
* ZCIT__PTPT_STRUCT DN* N
* ======================== ========= ======== ===================================
*/
string itype_to_string(ZCIT tp)
{
string result ;
ZCIT t = tp ;
void append_if(ZCIT arg, string add)
{
if ( t & arg )
{
result ~= ( add ~ " ") ;
t &= ~arg ;
}
}
if ( t == 0 ) return "*** empty ***" ;
append_if( ZCIT.IGNORED, "Ignored" );
append_if( ZCIT.IS_PTR, "Pointer to");
append_if( ZCIT.IS_ARRAY, "Array of" );
append_if( ZCIT.IS_LINK, "Link to");
append_if( ZCIT.HAS_LEN, "C++/D/GString" );
append_if( ZCIT.IS_OF_CHAR, "char" );
append_if( ZCIT.IS_OF_DIGIT, "digit" );
append_if( ZCIT.ANON_STRUCT, "anonymous struct" );
append_if( ZCIT.HAS_LEN_OF, "with lenght of variable" );
stderr.writeln(__FUNCTION__, "Remainder : ", cast(void*)t);
return result ;
}
alias ZC_Itype_to_string = itype_to_string ;
enum ZC_ASC_DESC
{
ASCENDING = 0,
DESCENDING = 1,
}
public import enum_ctypes ;
alias ZC_ctypes_to_string = ctypes_to_string ;
string[C_TYPES.max + 1] ctypes_to_string =
[
C_TYPES.UNDEF : "<*** Undefined ***>",
C_TYPES.BOOL : "bool",
C_TYPES.CHAR : "char", // implementation defined, gcc's default: signed
C_TYPES.SIGNED_CHAR : "signed char",
C_TYPES.UNSIGNED_CHAR : "unsigned char" ,
C_TYPES.SHORT : "short" ,
C_TYPES.UNSIGNED_SHORT : "unsigned short",
C_TYPES.INT : "int" ,
C_TYPES.UNSIGNED_INT : "unsigned int",
C_TYPES.LONG : "long",
C_TYPES.UNSIGNED_LONG : "unsigned long",
C_TYPES.LONG_LONG : "long long",
C_TYPES.UNSIGNED_LONG_LONG : "unsigned long long",
C_TYPES.FLOAT : "float",
C_TYPES.DOUBLE : "double",
C_TYPES.LONG_DOUBLE : "long double",
C_TYPES.INT_128 : "int128",
C_TYPES.UNSIGNED_INT_128 : "unsigned int128",
C_TYPES.VOID : "void",
C_TYPES.STRUCT : "struct",
C_TYPES.END_STRUCT : "<END struct>",
C_TYPES.WCHAR : "wchar_t",
// C_TYPES.EOF : "EOF",
] ;
alias ZC_ctypes_lenght = ctypes_lenght ;
uint[C_TYPES.max + 1] ctypes_lenght =
[
C_TYPES.BOOL : bool.sizeof ,
C_TYPES.CHAR : char.sizeof,
C_TYPES.SIGNED_CHAR : char.sizeof,
C_TYPES.UNSIGNED_CHAR : char.sizeof,
C_TYPES.SHORT : C_SHORT_SIZE, // 2
C_TYPES.UNSIGNED_SHORT : C_SHORT_SIZE, // 2
C_TYPES.INT : C_INT_SIZE , // 4
C_TYPES.UNSIGNED_INT : C_INT_SIZE, // 4
C_TYPES.LONG : C_LONG_SIZE,
C_TYPES.UNSIGNED_LONG : C_LONG_SIZE,
C_TYPES.LONG_LONG : C_LONG_LONG_SIZE,
C_TYPES.UNSIGNED_LONG_LONG : C_LONG_LONG_SIZE,
C_TYPES.FLOAT : C_FLOAT_SIZE ,
C_TYPES.DOUBLE : C_DOUBLE_SIZE,
C_TYPES.LONG_DOUBLE : C_LONG_DOUBLE_SIZE ,
C_TYPES.INT_128 : C_INT128_SIZE,
C_TYPES.UNSIGNED_INT_128 : C_INT128_SIZE,
C_TYPES.VOID : void.sizeof,
C_TYPES.STRUCT : 0,
C_TYPES.END_STRUCT : 0,
C_TYPES.WCHAR : dchar.sizeof,
] ;
class IDX_VAR_ATTR
{
// string name ;
public:
bool dsc ;
int function() cmp_fce ;
string cmp_name ;
C_VAR cv ;
zc_node node , pos_node ;
int pos ; // 0 if 1st index member ...
void[] mem ;
this(C_VAR c, bool d)
{
this.cv = c;
this.dsc = d ;
}
// search version:
this(string s)
{
this.cv = new C_VAR(s);
}
string
name() => this.cv ? this.cv.name.dstr : null ;
// void opDispatch(string name, T...)(T vals) {
// writeln("called ", name);
// mixin("content." ~ name)(vals);
// }
}
extern (C) int
Zc_IDX_VAR_ATTR_cmp(const void *a, const void *b,
const void *c, const void *d)
{
IDX_VAR_ATTR ia = cast(IDX_VAR_ATTR) a ;
IDX_VAR_ATTR ib = cast(IDX_VAR_ATTR) b ;
assert(ib.cv && ia.cv );
return ( ( ia.cv.name.str > ib.cv.name.str ) -
( ia.cv.name.str < ib.cv.name.str ) );
}
extern (C) int
Zc_IDX_VAR_ATTR_pos_cmp(const void *a, const void *b,
const void *c, const void *d)
{
IDX_VAR_ATTR ia = cast(IDX_VAR_ATTR) a ;
IDX_VAR_ATTR ib = cast(IDX_VAR_ATTR) b ;
return ( ( ia.pos > ib.pos ) - ( ia.pos < ib.pos ) );
}
class INDEX
{
uint magic = ZC_MAGIC_INDEX ;
string name ;
zc_node node ;
zc_node node_by_pos ;
int pos ; // 0 == primary etc.
static int cnt ;
///
/// fields by name/position
///
zc_table fields_table , pos_fields_table ;
TAVLTree!IDX_VAR_ATTR fields_by_name, fields_by_pos ;
uint nfields ;
zc_pos idx_root ;
void[] mem ; /// pointer to self
public:
ptrdiff_t index ;
C_STRUCT cs ;
bool is_primary() { if(pos == 0) return true ; return false ; }
Position*
get_start_pos() => &idx_root ;
void
set_start_pos( Position* p, Transaction tnx = null)
{
// bool utnx ;
// tnx = db.start_utnx_if_no_tnx(tnx, utnx);
// tnx.add_rw_addr(db.meta_fd, db.meta);
// when called from ~tnx, starting new tnx is bit silly
if ( tnx ) tnx.add_ch_start_idx(this.index, &this.idx_root, p);
this.idx_root = *p ;
// if (utnx) tnx.commit ;
}
this(string name, C_STRUCT cs) //Database db,)
{
this.name = name ;
this.pos = cnt++ ;
this.index = this.mem.ptr - cs.db.meta.ptr ;
// zc_table_props* p = add_zc_table_props(&Zc_IDX_VAR_ATTR_cmp,
// IDX_VAR_ATTR.node.offsetof) ;
fields_by_name = new TAVLTree!IDX_VAR_ATTR(cs.db.meta_bh,
&this.fields_table,
TTP_OFFSET.TTP_IVA_NAME,
null);
fields_by_pos = new TAVLTree!IDX_VAR_ATTR(cs.db.meta_bh,
&this.pos_fields_table,
TTP_OFFSET.TTP_IVA_POS,
null);
}
// search version
this(string name)
{
this.name = name ;
}
IDX_VAR_ATTR
add_member (C_STRUCT cs, string fld_name, bool dsc, Database db)
{
// C_VAR *cvp = fld_name in cs.vars ;
// if ( cvp is null )
// {
// writefln("Field «%s» non existent in struct «%s»", fld_name, cs.name );
// return ;
// }
if ( auto cvp = /*fld_name in*/ cs.vars.FindA(fld_name) )
{
auto ia = db.meta_bh.AllocE!IDX_VAR_ATTR( cvp, dsc );
ia.pos = this.nfields++ ;
// auto ia = new IDX_VAR_ATTR(cvp, dsc) ;
// ia.cv = cvp ;
// ia.dsc = dsc ;
// this.fields[fld_name] = cvp ;
// this.attrs[fld_name] = new IDX_VAR_ATTR ;
// this.attrs[fld_name].dsc = dsc ;
this.fields_by_name.insert(ia);
this.fields_by_pos.insert(ia);
return ia ;
}
else
{
writefln("Field «%s» non existent in struct «%s»", fld_name, cs.name );
return null ;
}
}
void set_cmp (C_STRUCT cs, string fld_name, string fce)
{
// C_VAR *cvp = fld_name in cs.vars ;
// if ( cvp is null )
// {
// writefln("Field «%s» non existent in struct «%s»", fld_name, cs.name );
// return ;
// }
// else
// this.attrs[fld_name].cmp_name = fce ;
if ( auto ip = // fld_name in
this.fields_by_name.FindA(fld_name) )
ip.cmp_name = fce ;
else
{
writefln("Field «%s» non existent in struct «%s»", fld_name, cs.name );
return ;
}
}
}
/* token */
/+
struct TK
{
char *s ;
int tn ;
}
+/
struct ATTR
{
bool is_pointer, /* is_built_in , */ is_array , is_last ;
size_t alen ; // if is_array
string name ;
int tn ; // token #
}
//enum int ZC_VAR_DIM_MAX = 16 ;
/+
string
fce_to_string(const char *s, CXString function(CXCursor) fce , CXCursor c)
{
// const char *tmp = clang_getCString(
CXString cxs = fce(c);
string rs = fromStringz(cxs);
return rs ;
}
+/
// tools
string
cxs2string(CXString cxs)
{
const char *tmp = clang_getCString(cxs);
string str = ToStr(tmp);
clang_disposeString(cxs);
return str ;
}
class C_VAR
{
zc_string name , cmp ;
int function() cmp_fce;
zc_node node ;
// void *(*copy_fce)(void *, const void *, size_t);
ZCIT itype ; //< composed type
CXType cxt ;
C_TYPES type ; //< all basic types
// pos info (file-wise) :
uint line ;
uint col , foff ;
string file ;
long offset ; // long long in C++/C
//
uint flag ; //< filled by ZC parser
C_VAR length ; //< the same as a[length] for pointers
union {
size_t array_length ; //< the same as a[length]
size_t anon_struct_length ;
}
C_STRUCT cs, parent ; //< nested struct , parent struct
zc_string struct_name ; //< struct tag
// size_t fld_offset ; //< offsetof(a)
ushort id ; //< varible ID
ubyte ptl ; //< number of '*', for pointer to pointer to ... ptl == 2
CXTypeKind cxkind ;
// unsigned short ndim ; //< original dimansions
// const char *tmp ;
void[] mem ; // where I reside
invariant {
if ( cs ) assert(cs.magic == MAGIC_C_STRUCT) ;
}
this(CXCursor c, C_STRUCT cs) {
const char *tmp = clang_getCString(clang_getCursorSpelling(c));
this.name.inp(tmp, cs.db.meta_bh.zs); //= ToStr(tmp);
this.cs = cs ;
this.struct_name = cs.name ;
cs.add_var(this);
immutable long bit_offset = clang_Cursor_getOffsetOfField (c);
if ( bit_offset > 0 ) { this.offset = bit_offset / 8 ; }
this.cxt = clang_getCursorType (c);
this.cxkind = cxt.kind ;
this.CXType_to_ctype(this.cxkind);
debug (on) { writeln(__FUNCTION__, " Newname[", cs.nvar, "]: ", cs.name,
".", name, " @", offset, "---> ", cs); }
}
this(string s)
{
this.name.set(s) ; // not persistent
}
public string
print_type()
{
string o = format("%s%s %s%s",
ZC_ctypes_to_string[this.type],
this.ptl ? "*" : " ",
this.name,
array_length ? format("[%d];", array_length ) : ";" );
return o ;
}
public string
print_itype() => ZC_Itype_to_string(this.itype) ;
public void
cxt_to_type(int t)
{
switch(t)
{
case CXTypeKind.CXType_Char16: this.type = C_TYPES.SHORT ; break ;
case CXTypeKind.CXType_Char32: this.type = C_TYPES.INT ; break ;
case CXTypeKind.CXType_UShort: this.type = C_TYPES.UNSIGNED_SHORT ;break;
case CXTypeKind.CXType_UInt: this.type = C_TYPES.UNSIGNED_INT ; break ;
case CXTypeKind.CXType_ULong: this.type = C_TYPES.UNSIGNED_LONG; break;
case CXTypeKind.CXType_ULongLong: this.type = C_TYPES.UNSIGNED_LONG_LONG;break;
case CXTypeKind.CXType_UInt128:this.type = C_TYPES.UNSIGNED_INT_128 ; break ;
case CXTypeKind.CXType_WChar:this.type = C_TYPES.WCHAR ; break ;
case CXTypeKind.CXType_Short:this.type = C_TYPES.SHORT ; break ;
case CXTypeKind.CXType_Int:this.type = C_TYPES.INT ; break ;
case CXTypeKind.CXType_Long:this.type = C_TYPES.LONG ; break ;
case CXTypeKind.CXType_LongLong: this.type = C_TYPES.LONG_LONG ; break ;
case CXTypeKind.CXType_Int128:this.type = C_TYPES.INT_128 ; break ;
case CXTypeKind.CXType_Float:this.type = C_TYPES.FLOAT ; break ;
case CXTypeKind.CXType_Double:this.type = C_TYPES.DOUBLE ; break ;
case CXTypeKind.CXType_LongDouble:this.type = C_TYPES.LONG_DOUBLE ; break ;
default: break ;
}
}
private void CXType_to_ctype(CXTypeKind k)
{
// with(CXTypeKind.);
if ( this.type != C_TYPES.UNDEF )
return ;
switch ( k )
{
case CXTypeKind.CXType_Invalid:
case CXTypeKind.CXType_Unexposed:
default:
return ;
case CXTypeKind.CXType_Void: this.type = C_TYPES.VOID ; break ;
case CXTypeKind.CXType_Bool: this.type = C_TYPES.BOOL ; break ;
case CXTypeKind.CXType_Char_U: this.type = C_TYPES.UNSIGNED_CHAR; break ;
case CXTypeKind.CXType_UChar: this.type = C_TYPES.UNSIGNED_CHAR ; break ;
case CXTypeKind.CXType_Char16: this.type = C_TYPES.SHORT ; break ;
case CXTypeKind.CXType_Char32: this.type = C_TYPES.INT ; break ;
case CXTypeKind.CXType_UShort: this.type = C_TYPES.UNSIGNED_SHORT ; break ;
case CXTypeKind.CXType_UInt: this.type = C_TYPES.UNSIGNED_INT ; break ;
case CXTypeKind.CXType_ULong: this.type = C_TYPES.UNSIGNED_LONG; break ;
case CXTypeKind.CXType_ULongLong: this.type = C_TYPES.UNSIGNED_LONG_LONG;break;
case CXTypeKind.CXType_UInt128: this.type = C_TYPES.UNSIGNED_INT_128 ; break ;
// static if ( 1 ) // FIXME ZC__CHAR_IS_SIGNED == 1
// {
case CXTypeKind.CXType_Char_S: this.type = C_TYPES.CHAR ; break ;
case CXTypeKind.CXType_SChar: this.type = C_TYPES.CHAR ; break ;
// }
// else // ZC__CHAR_IS_SIGNED
// {
// [CXType_Char_S] this.type = C_TYPES_SIGNED_CHAR,
// [CXType_SChar] this.type = C_TYPES_SIGNED_CHAR,
// }
case CXTypeKind.CXType_WChar: this.type = C_TYPES.WCHAR ; break ;
case CXTypeKind.CXType_Short: this.type = C_TYPES.SHORT ; break ;
case CXTypeKind.CXType_Int: this.type = C_TYPES.INT ; break ;
case CXTypeKind.CXType_Long: this.type = C_TYPES.LONG ; break ;
case CXTypeKind.CXType_LongLong: this.type = C_TYPES.LONG_LONG ; break ;
case CXTypeKind.CXType_Int128: this.type = C_TYPES.INT_128 ; break ;
case CXTypeKind.CXType_Float: this.type = C_TYPES.FLOAT ; break ;
case CXTypeKind.CXType_Double: this.type = C_TYPES.DOUBLE ; break ;
case CXTypeKind.CXType_LongDouble: this.type = C_TYPES.LONG_DOUBLE ; break ;
case CXTypeKind.CXType_Enum: this.type = C_TYPES.INT ; break ;
case CXTypeKind.CXType_Elaborated: this.type = C_TYPES.STRUCT ; break ;
case CXTypeKind.CXType_IncompleteArray: this.type = C_TYPES.STRUCT ; break ;// struct BLA ble[] ;
case CXTypeKind.CXType_Record: this.type = C_TYPES.STRUCT ; break ;
}
}
size_t
type_size() => ctypes_lenght[this.type] ;
size_t
get_len(ubyte[] content)
{
uint sz = ZC_ctypes_lenght[length.type] ;
assert(sz == size_t.sizeof, "len_of variable MUST be unsigned size_t, not size :" ~ sz.stringof );
ubyte[] bytes = content[length.offset..length.offset + sz] ;
return *cast(size_t*)&bytes[0];
}
} // C_VAR
enum TRIGGER_TYPE
{
_BEFORE_SHUTDOWN = 0,
_BEFORE_META_CHANGE = 1,
_BEFORE_READ = 2,
_BEFORE_WRITE = 3,
_BEFORE_DELETE = 4,
_AFTER_STARTUP = 5,
_AFTER_META_CHANGE = 6,
_AFTER_ERROR = 7,
_AFTER_READ = 8,
_AFTER_WRITE = 9,
_AFTER_DELETE = 10,
_LAST = 11,
}
struct TRIGGER_TABLE
{
union {
char *name ;
// TODO: trigger args !!!
// int (*file_trigger)(struct C_STRUCT *, void *);
// int (*global_trigger)(void *, void *);
}
}
string
itype_to_str(ZCIT itype)
{
return ZC_Itype_to_string(itype) ;
}
alias Zc_itype_to_str = itype_to_str ;
string
type_to_str(C_TYPES type)
{
return ZC_ctypes_to_string[type] ;
}
alias Zc_type_to_str = type_to_str ;
TRIGGER_TABLE[TRIGGER_TYPE._LAST] trigger_table ;
// FIXME import zc.magic ;
enum MAGIC_C_STRUCT = 0xbeef0100 ;
enum MAGIC_INDEX = 0xbeef0101 ;
alias C_STRUCT_diff = ptrdiff_t ;
import std.outbuffer ;
class C_STRUCT
{
uint magic = MAGIC_C_STRUCT ;
zc_node node ;
ZCIT itype ;
// void *shlib ; //< dlopen handle
zc_string name ;
// ZC_STRUCT_FLAG flag ;
// GSList *var_list ; // C_VAR
uint nvar ;
/// "C" struct members/variables tree
zc_table vars_table ;
TAVLTree!C_VAR vars ;
//TAVLTree!C_VAR vars_table ; // WTF ??
// C_VAR[] variables ;
/// positons in source file:
uint line ;
uint col ;
uint foff ; //< file offset
zc_string file ;
///
/// INDEX tree of struct
///
uint nidx ;
zc_table index_table , index_table_by_pos;
TAVLTree!INDEX idxs ;
TAVLTree!INDEX idxs_by_pos ;
//
/// parent of nested struct
// C_STRUCT_diff
//PIDP!C_STRUCT parent ; //< references
C_STRUCT parent ;
/// not yet/never? implemented
zc_string locale ;
int block_size , max_blocks , auto_replace /* ,index_copy, huge_index_block, huge_interval_block */;
//
size_t static_size ;
// string[] prefixes ; /**< file's volumes will be created under db prefixes */
// int n_prefixes ; //, next_prefix ;
Database db ;
/// where the data are well hidden
zc_pos data_root ;
/// Optional multi-volume file support
///
/// If table/C struct/file occupy default volume only,
/// num_dedicated_volumes is zero and vols tree is empty.
/// For multi-volume table/C struct/file:
/// num_dedicated_volumes == vols.size
/// and tree vols (VOLN.num(s)) contains all volume# ,
/// where this file will spread.
ushort num_dedicated_volumes ; // #of
zc_table vols_table ;
TAVLTreeUINT!(VOLN*) vols ;
ptrdiff_t c_struct ; // my offset
void[] mem ; // self ptr
// ulong[ VOL_BITMAP_SIZE ] volumes_bitmap ; // makes ^^^ prefixes obsolent
//
//
public:
union XSTR
{
void *v ; // C struct
ubyte[] src ;
}
ubyte[]
to_bytes(ubyte[] src, out ulong nvar, out size_t[ulong] sztab)
{
OutBuffer buf = new OutBuffer();
size_t[ulong] sv ;
foreach ( i,cv ; vars )
{
size_t s ;
with (ZCIT)
if ( cv.itype & IS_PTR )
{
POINTER_ON_DISK p ;
p.bytes = src[cv.offset..cv.offset + (ubyte*).sizeof] ; //cv.type_size] ;
s = cv.get_len(src) ;
// ubyte[] add = new ubyte[s] ;
// add = (*p.bp)[s] ;
// ubyte[] add ;
if ( cv.itype & IS_OF_DIGIT )
s *= cv.type_size ;
ubyte[] add = new ubyte[s] ;
dmemcpy(&add[0] , p.bp , s ) ;
buf.write(add);
// foreach ( j ; 0..s )
// buf.write((*p.bp+j));
// cv.length
}
else if ( cv.itype & IS_ARRAY )
{
s = cv.array_length * cv.type_size ;
ubyte[] add = new ubyte[s] ;
add[0..s] = src[cv.offset..cv.offset + s] ;
buf.write(add);
}
else if ( cv.itype & IS_DIGIT )
{
}
sv[i] = s ;
nvar = i ;
}
sztab = sv ;
return buf.toBytes ;
}
Position*
get_start_pos() => &data_root ;
void
set_start_pos(Position* p, Transaction tnx = null)
{
// bool utnx ;
// tnx = db.start_utnx_if_no_tnx(tnx, utnx);
// tnx.add_rw_addr(db.meta_fd, db.meta);
tnx.add_ch_start_cs(this.c_struct, &this.data_root, p);
this.data_root = *p ;
// if (utnx) tnx.commit ;
}
int
add_var(C_VAR cv)
{
if ( auto cvp = // cv.name in
this.vars.FindA(cv.name) )
{
writeln("C_VAR ", cv.name, " exists in ", this.name,
" as ", cvp.name, " ", cvp.type);
return 0 ;
}
else // if ( cvp is null )
{
this.vars.assert_insert( cv );
return ++this.nvar ;
}
}
INDEX
add_idx(string name, C_STRUCT cs ) // Database db)
{
INDEX ip = // name in
this.idxs.FindA(name) ;
if ( ip is null )
{
// INDEX idx = new INDEX(name, db) ;
INDEX idx = cs.db.meta_bh.AllocE!INDEX( name, cs);
this.idxs.assert_insert(idx); // [name] = new INDEX(name) ;
this.nidx++ ;
return idx ;
}
return ip ;
}
private void
init_cs(CXCursor c, string sn)
{
CXSourceLocation loc = clang_getCursorLocation(c);
// C_STRUCT *cs = new C_STRUCT ;
CXFile filename;
clang_getExpansionLocation(loc, &filename, &this.line, &this.col, &this.foff);
CXString src = clang_getFileName(filename);
this.magic = MAGIC_C_STRUCT ;
this.name.inp(sn, db.meta_bh.zs ); // = db.meta_bh.AllocE!string(sn) ;
// this.file = ToStr( clang_getCString(src)).dup ;
this.file.inp( ToStr( clang_getCString(src)),
db.meta_bh.zs); // = db.meta_bh.AllocE!string(ToStr( clang_getCString(src)));
clang_disposeString(src);
}
private void append_cs(Database db)
{
// c_struct_aa[this.name] = this ;
while ( db.files.insert(this) == false )
db.files.remove(this);
debug { writeln("C_STRUCT ", this.name ," len now : ", db.files.size ); }
}
private void visit_children()
{
}
/**
*
* Params:
* vn = name C variable ( pointer type )
* ln = name of C variable where the size of "vn" variable is stored
*
* IOW "ln" is length of "vn"
*/
extern (C) int yycolumn, yylineno ;
extern (C) char *zc_file ;
void
set_length_is_in(string vn, string ln)
{
auto vn_cv = this.vars.FindA(vn) ;
if ( vn_cv is null ) {
// writeln(zc_file, ":", yylineno, ":" , yycolumn, ": Non existent C_VAR ", vn);
writeln(eprefix, ": Non existent C_VAR ", vn);
return ;
}
auto ln_cv = this.vars.FindA(ln) ;
if ( ln_cv is null ) {
writeln(eprefix, "Non existent C_VAR ", vn);
}
if ( vn_cv.itype & ZCIT.HAS_LEN_OF )
{
writeln(eprefix, "Variable's ", vn, " «is lenght of» helper variable exists : ",
vn_cv.length.name);
writeln(eprefix, "Setting ", ln, " as Nth ", vn, "'s «is lenght of» ignored. ");
return ;
}
if ( ln_cv.itype != ZCIT.DIGIT )
{
writeln(eprefix, "Only variable type ulong/size_t/uint is usable as 'lenght of' helper variable.");
writeln(eprefix, "Not ", itype_to_string(ln_cv.itype), " ", ln);
return ;
}
switch ( ln_cv.type )
{
case C_TYPES.UNSIGNED_INT,C_TYPES.UNSIGNED_LONG, C_TYPES.UNSIGNED_LONG_LONG:
break ;
default:
writeln(eprefix, "Only 4/8 bytes variable type ulong/size_t/uint is usable as 'lenght of' helper variable.");
writeln(eprefix, "Not a «", ctypes_to_string[ln_cv.type], " ", ln, "»");
return ;
}
vn_cv.itype |= ZCIT.HAS_LEN_OF ;
vn_cv.length = ln_cv ;
}
this(CXCursor c, string sn, Database db)
{
this.db = db ;
this.c_struct = this.mem.ptr - db.meta.ptr ;
// this.zcstr = db.meta_bh.zcstr ;
zc_table_props* v = add_zc_table_props(&C_VAR_cmp,
C_VAR.node.offsetof) ;
zc_table_props* i = add_zc_table_props(&INDEX_cmp,
INDEX.node.offsetof) ;
zc_table_props* ip = add_zc_table_props(&INDEX_pos_cmp,
INDEX.node_by_pos.offsetof) ;
this.vars = new TAVLTree!C_VAR(db.meta_bh, &this.vars_table, v, null);
this.idxs = new TAVLTree!INDEX(db.meta_bh, &this.index_table, i, null);
this.idxs_by_pos = new TAVLTree!INDEX(db.meta_bh, &this.index_table_by_pos, ip, null);
this.init_cs(c, sn);
this.append_cs(db);
}
//for searching only !!!
this(string sn)
{
this.magic = MAGIC_C_STRUCT ;
this.name.set(sn) ;
}
// this(CXCursor c, C_VAR[string] va, string sn)
// {
// this.init(c, sn);
// this.copy_cvar(va);
// this.append_cs();
// }
}
enum D_TYPES
{
UNDEF = 0,
BOOL,
BYTE,
UBYTE,
CHAR,
DCHAR,
SHORT,
USHORT,
INT,
UINT,
LONG,
ULONG,
FLOAT,
DOUBLE,
REAL,
// non numeric:
VOID,
STRUCT,
STRING,
} ;
D_TYPES
ctype_to_dtype(C_TYPES ct)
{
switch (ct)
{
case C_TYPES.UNDEF: return D_TYPES.UNDEF ;
case C_TYPES.BOOL : return D_TYPES.BOOL ;
case C_TYPES.CHAR : return D_TYPES.CHAR ;
case C_TYPES.SIGNED_CHAR: return D_TYPES.CHAR ;
case C_TYPES.UNSIGNED_CHAR: return D_TYPES.UBYTE ;
case C_TYPES.INT : return D_TYPES.INT ;
case C_TYPES.UNSIGNED_INT : return D_TYPES.UINT ;
case C_TYPES.LONG : return D_TYPES.INT ;
case C_TYPES.UNSIGNED_LONG : return D_TYPES.UINT ;
case C_TYPES.LONG_LONG : return D_TYPES.LONG ;
case C_TYPES.UNSIGNED_LONG_LONG: return D_TYPES.ULONG ;
case C_TYPES.FLOAT : return D_TYPES.FLOAT ;
case C_TYPES.DOUBLE : return D_TYPES.DOUBLE ;
case C_TYPES.LONG_DOUBLE: return D_TYPES.REAL ;
case C_TYPES.INT_128 : return D_TYPES.UNDEF ;
case C_TYPES.UNSIGNED_INT_128 : return D_TYPES.UNDEF ;
case C_TYPES.VOID : return D_TYPES.VOID ;
case C_TYPES.STRUCT : return D_TYPES.STRUCT ;
case C_TYPES.WCHAR : return D_TYPES.DCHAR ;
default: return D_TYPES.UNDEF ;
}
}
/*
D: C 32 64
void void
byte signed char
ubyte unsigned char
char char (chars are unsigned in D)
wchar wchar_t (when sizeof(wchar_t) is 2)
dchar wchar_t (when sizeof(wchar_t) is 4)
short short
ushort unsigned short
int int
uint unsigned
core.stdc.config.c_long long long
core.stdc.config.c_ulong unsigned long unsigned long
core.stdc.stdint.intptr_t intptr_t intptr_t
core.stdc.stdint.uintptr_t uintptr_t uintptr_t
long long long long (or long long)
ulong unsigned long long unsigned long (or unsigned long long)
float float
double double
real long double
*/
/**
* Internal record
*/
class IVAR
{
private:
C_VAR cv ;
D_TYPES dtype ;
union VAL
{
byte byte_v ;
ubyte ubyte_v ;
char char_v ;
wchar wchar_v ;
dchar dchar_v ;
short short_v ;
ushort ushort_v ;
int int_v ;
uint uint_v ;
long long_v ;
ulong ulong_v ;
float float_v ;
double double_v ;
real real_v ;
string string_v ;
}
VAL val ;
void
copy_digit(void* cdata)
{
void* src = cdata + ( cv ? cv.offset : 0 ) ;
void* dst = &val ;
size_t s = -1 ;
with(D_TYPES)
switch (dtype)
{
case BOOL, BYTE, UBYTE, CHAR: s = char.sizeof ; break ;
case DCHAR: s = dchar.sizeof ; break ;
case SHORT, USHORT: s = short.sizeof ; break ;
case INT, UINT: s = int.sizeof ; break ;
case LONG, ULONG : s = long.sizeof ; break ;
case FLOAT: s = float.sizeof ; break ;
case DOUBLE: s = double.sizeof; break ;
case REAL: s = real.sizeof ; break ;
default: assert( 0 == 1, "Fixme dtype " ~ dtype.stringof );
}
dmemcpy(dst, src, s );
}
unittest {
int i = 123456789 ;
IVAR iv = new IVAR(null, &i);
iv.cv = null ;
iv.copy_digit(&i);
assert( i == iv.val.int_v );
}
this(C_VAR cv, void* cdata)
{
this.cv = cv ;
if ( cv && cv.itype & ZCIT.IS_DIGIT )
{
dtype = ctype_to_dtype(cv.type);
copy_digit(cdata);
}
else assert( 0 == 1, "Fixme itype : " ~ cv.itype.stringof );
}
}
class IREC
{
/* from C struct */
this(C_STRUCT cs, void* C_data)
{
}
}
extern (C) int
C_VAR_cmp(const void *a, const void *b,
const void *c, const void *d)
{
C_VAR cva = cast(C_VAR) a ;
C_VAR cvb = cast(C_VAR) b ;
return ( ( cva.name > cvb.name ) - ( cva.name < cvb.name ) );
}
extern (C) int
INDEX_cmp(const void *a, const void *b,
const void *c, const void *d)
{
INDEX cva = cast(INDEX) a ;
INDEX cvb = cast(INDEX) b ;
return ( ( cva.name > cvb.name ) - ( cva.name < cvb.name ) );
}
extern (C) int
INDEX_pos_cmp(const void *a, const void *b,
const void *c, const void *d)
{
INDEX cva = cast(INDEX) a ;
INDEX cvb = cast(INDEX) b ;
return ( ( cva.pos > cvb.pos ) - ( cva.pos < cvb.pos ) );
}
extern (C) int
VOLN_cmp(const void *a, const void *b,
const void *c, const void *d)
{
VOLN* cva = cast(VOLN*) a ;
VOLN* cvb = cast(VOLN*) b ;
return ( ( cva.num > cvb.num ) - ( cva.num < cvb.num ) );
}
extern (C) int
Zc_file_cmp(const void *a, const void *b ,
const void *c, const void *d)
{
/+
const zc_meta_file_T *file_a = a ;
const zc_meta_file_T *file_b = b ;
+/
const C_STRUCT file_a = cast(C_STRUCT)a ;
const C_STRUCT file_b = cast(C_STRUCT)b ;
return ( ( file_a.name > file_b.name ) -
( file_a.name < file_b.name ) );
// return g_strcmp0(file_a->name, file_b->name) ;
}
//__gshared C_STRUCT[string] c_struct_aa; /// Associative array of Cstructs that are indexed by string keys.
//alias tk_T = TK ;
/+
struct USERDEF
{
string file ;
string compile_opt ;
string link_opt ;
}
struct zrec_position
{
long offset ;
uint size ; // for blobs // mmap
uint vol_num ;
}
struct ZREC_LINK
{
zrec_position pos ;
ulong id ;
}
+/
//typedef struct ZREC_LINK zrec_link ;
alias off_t = long ;
//alias zrec_link = ZREC_LINK ;
enum ZC_REC_PTR_BITS = 8 ;
enum ZC_REC_LINK_BITS = 8;
/+
struct ZC_REC_HEADER
{
ushort magic ; //< use continuation or record data
union {
char[14] stuff ;
zc_pos cont ; /**< continuation inode parody */
struct {
uint xlen , pointers_offset ;
/** # pointer variables => pointer table size */
ushort has_pointers; //:ZC_REC_PTR_BITS ;
/** are we pointing to somebody else ?
if non-zero, number of ``database pointers``
*/
ushort has_links;//:ZC_REC_LINK_BITS ;
long back_links_offset ; /**< BLOB like back-link pool of TODO!!!
type */
} ;
} ;
} /* __attribute__ ((__packed__)) */ ;
+/
static if ( (int *).sizeof == 2 * int.sizeof )
mixin("alias ZC_PTR_UNION_TYPE = uint ;");
static if ( (int *).sizeof == 2 * short.sizeof )
mixin("alias ZC_PTR_UNION_TYPE = ushort ;");
static assert(ZC_PTR_UNION_TYPE.sizeof > 0, "This HW is too strange, fix this manually! Thank you.");
union ZC_PTR_2SIZE
{
void *p ;
struct
{
ZC_PTR_UNION_TYPE offset ;
ZC_PTR_UNION_TYPE nbytes ;
}
}
static assert( (int *).sizeof == (ZC_PTR_2SIZE).sizeof ,
"Union ZC_PTR_2SIZE MUST be the same size as pointer");
//typedef union ZC_PTR_2SIZE ZC_ptu_T ;
struct OBS___ZC_REC_HDR
{
ushort header_size ; /**< where is the rest of former hidden ,
pointer_part_offset ==
sizeof(REST_OF_STRUCT)
+ sizeof ( struct ZC_REC_HDR ) */
uint struct_size ; // :21 ;
ubyte link_table_len ; /**< are we pointing to somebody else ?
if yes, number of ``database pointers``
*/
uint linked_by_len ; /**< are we destination of ``database pointers`` ?
if yes, size of ``backward links table`` */
}
struct OBS_ZC_REC_PTR_TABLE
{
// unsigned char ptr_no ; /**< Nth pointer variable */
/** NULL pointers are encoded as .len = 0 . .offset = 0 */
uint offset; //:21 ; /**< offset of variable from heeder/record start */
uint len; //:21 ; /**< length of pointer variable's space [bytes] */
}
//typedef struct ZC_REC_PTR_TABLE ZC_PT_T ;
// alias ZC_PT_T = OBS_ZC_REC_PTR_TABLE ;
struct ZC_REC_LINK_HEADER
{
ushort no ; /**< Nth link variable, some may be NULL */
ushort chlink_idx ; /**< index to link[] part */
uint id_idx; //:ZC_REC_LINK_BITS ; /**< nth item in file's sub_file tree */
}
/// dump c_struct_aa{}
export void
list(Database gdb)
{
writeln("Keys: ", gdb.files.keys);
writeln("Values: ", gdb.files.values);
foreach(cs_k, cs_v ; gdb.files )
{
// writefln("C struct %s => %x", cs_k, &cs_v );
writeln("C struct ", cs_k, " => " , cs_v.name );
foreach ( k, cv ; cs_v.vars )
writeln("\tVar: [", k, "] ", cv.name, " | ", cv.print_type , " ", cv.print_itype);
// writeln("\tVar: ", k, " type ", ZC_ctypes_to_string[cv.type] , " ", cv.name);
if ( cs_v.nidx )
{
writeln("Idx «", cs_v.name, "»'s : ", cs_v.nidx, " K/V ", cs_v.idxs.keys,
" / ", cs_v.idxs.values);
// writeln("Idx Values «", cs_k, "» : ", cs_v.idxs.values);
foreach ( ik, iv ; cs_v.idxs )
{
writeln("\tCS ", cs_v.name," Index: ", iv.name, " #fields: ", iv.fields_by_pos.size);
foreach ( ia_k, ia_v ; iv.fields_by_pos )
{
writeln("\t\tField: ", ia_v.cv.name,
ia_v.dsc ? " DSC " : " ASC ",
ia_v.cmp_name ? ia_v.cmp_name : "" ,
ia_v.cmp_name ? "()" : "" );
}
// foreach ( i ; cs_v.idxs.values)
// {
// writeln("Index: ", i.name); //, " type ", v.type );
// foreach ( k, v ; i.fields )
// {
// writeln("IdxVar: ", k, " type ", v.cv.type );
// }
// }
}
}
}
}
/** (FORWARD)_LINK_TABLE is the struct zc_position */
// copy from zc_meta_file.h
//#include <zc_table.h>
// struct ZC_REC_BACK_LINK_TABLE
// {
// FILE_ID_TYPE id ;
// struct zc_position pos ;
// } ;
// struct ZC_PARSER_DATA
// {
// string infile ;
// // immutable
// extern (C) char * cinfile;
// void *voidp ;
// C_STRUCT *cs ;
// } ;
//alias PD = ZC_PARSER_DATA ;
/* Local Variables: */
/* mode: d */
/* buffer-save-without-query: t */
/* End: */