2005-08-02 06:10:31 +00:00
#!/usr/bin/perl
2005-08-02 17:02:25 +00:00
#
# Create ejs interfaces for structures in a C header file
#
2005-08-02 06:10:31 +00:00
2005-08-02 17:02:25 +00:00
use File::Basename ;
2005-08-05 04:50:32 +00:00
use Data::Dumper ;
2005-08-07 18:04:34 +00:00
#
# Generate parse tree for header file
#
2005-08-02 06:10:31 +00:00
2005-08-07 18:04:34 +00:00
my $ file = shift ;
2005-08-02 06:10:31 +00:00
require smb_interfaces ;
2005-08-02 17:02:25 +00:00
my $ parser = new smb_interfaces ;
$ header = $ parser - > parse ( $ file ) ;
2005-08-02 06:10:31 +00:00
2005-08-07 18:04:34 +00:00
#
# Make second pass over tree to make it easier to process. Ugh - this
# is all done in place as the parser generates references.
#
my $ newheader = [] ;
sub flatten_names ($) {
my $ obj = shift ;
# Map NAME, STRUCT_NAME and UNION_NAME elements into a more likeable
# property.
if ( $ obj - > { TYPE } eq "struct" or $ obj - > { TYPE } eq "union" ) {
# struct foo {};
# struct {} bar;
# struct foo {} bar;
$ obj - > { TYPE_NAME } = defined ( $ obj - > { STRUCT_NAME } ) ? $ obj - > { STRUCT_NAME }
: $ obj - > { UNION_NAME } ;
delete $ obj - > { STRUCT_NAME } ;
delete $ obj - > { UNION_NAME } ;
}
# Convert DATA array to a hash by field name
foreach my $ elt ( @ { $ obj - > { DATA } } ) {
foreach my $ name ( @ { $ elt - > { NAME } } ) {
$ obj - > { FIELDS } { $ name } = $ elt ;
2005-08-07 19:22:20 +00:00
$ obj - > { FIELDS } { $ name } { NAME } = $ name ;
$ obj - > { FIELDS } { $ name } { PARENT } = $ obj ;
2005-08-07 18:04:34 +00:00
}
}
# Recurse down into substructures
foreach my $ elt ( @ { $ obj - > { DATA } } ) {
flatten_names ( $ elt ) ;
}
delete $ obj - > { DATA } ;
}
foreach my $ s ( @ { $ header } ) { # For each parsed structure
flatten_names ( $ s ) ;
}
2005-08-07 19:22:20 +00:00
#
# Generate header
#
2005-08-07 18:04:34 +00:00
my $ basename = basename ( $ file , ".h" ) ;
2005-08-05 05:32:39 +00:00
stat "libcli/gen_raw" || mkdir ( "libcli/gen_raw" ) || die ( "mkdir" ) ;
open ( FILE , ">libcli/gen_raw/ejs_${basename}.h" ) ;
2005-08-02 17:02:25 +00:00
print FILE "/* header auto-generated by build_smb_interfaces.pl */\n\n" ;
print FILE "#ifndef _ejs_${basename}_h\n" ;
print FILE "#define _ejs_${basename}_h\n\n" ;
2005-08-07 19:22:20 +00:00
# Generate a push/pull prototype for every top level structure, as
# well as every non-anonymous nested structure (i.e TYPE_NAME element
# is undefined.
foreach my $ s ( @ { $ header } ) {
# Top level
print FILE "NTSTATUS ejs_push_$s->{TYPE_NAME}(struct ejs_rpc *, struct MprVar *, const char *, const uint32_t *);\n" ;
print FILE "NTSTATUS ejs_pull_$s->{TYPE_NAME}(struct ejs_rpc *, struct MprVar *, const char *, const uint32_t *);\n" ;
sub header_for ($$) {
my $ prefix = shift ;
my $ obj = shift ;
return if ! ( $ obj - > { TYPE } eq "struct" or $ obj - > { TYPE } eq "union" ) ;
return if ( $ obj - > { NAME } eq "in" or $ obj - > { NAME } eq "out" ) ;
print FILE "NTSTATUS ejs_push_${prefix}_$obj->{NAME}(struct ejs_rpc *, struct MprVar *, const char *, const uint32_t *);\n" ;
print FILE "NTSTATUS ejs_pull_${prefix}_$obj->{NAME}(struct ejs_rpc *, struct MprVar *, const char *, const uint32_t *);\n" ;
foreach my $ key ( % { $ obj - > { FIELDS } } ) {
header_for ( "${prefix}.$obj->{TYPE_NAME}" , $ obj - > { FIELDS } { $ key } ) ;
}
}
}
exit ;
2005-08-02 18:56:18 +00:00
sub struct_name ($)
{
my $ obj = shift ;
return defined ( $ obj - > { STRUCT_NAME } ) ? $ obj - > { STRUCT_NAME } : $ obj - > { UNION_NAME } ;
}
sub prototypes_for ($)
{
my $ obj = shift ;
my $ name = struct_name ( $ obj ) ;
print FILE "NTSTATUS ejs_push_$name(struct ejs_rpc *, struct MprVar *, const char *, const uint32_t *);\n" ;
print FILE "NTSTATUS ejs_pull_$name(struct ejs_rpc *, struct MprVar *, const char *, const uint32_t *);\n" ;
}
2005-08-02 17:02:25 +00:00
foreach my $ x ( @ { $ header } ) {
2005-08-02 18:56:18 +00:00
# Prototypes for top level structures and unions
prototypes_for ( $ x ) ;
foreach my $ e1 ( @ { $ x - > { DATA } } ) {
foreach my $ e2 ( @ { $ e1 - > { DATA } } ) {
2005-08-05 18:06:15 +00:00
# Prototypes for non-anonymous nested structures and unions:
#
# e.g struct foo {...};
2005-08-02 18:56:18 +00:00
if ( defined ( $ e2 - > { STRUCT_NAME } ) or defined ( $ e2 - > { UNION_NAME } ) ) {
prototypes_for ( $ e2 ) ;
}
2005-08-05 18:06:15 +00:00
# We also would like to push/pull nested structures and unions:
#
# e.g struct foo {
# struct {...} bar;
# };
if ( $ e2 - > { TYPE } eq "struct" ) {
if ( defined ( $ e2 - > { NAME } ) and ! defined ( $ e2 - > { STRUCT_NAME } ) ) {
foreach my $ x ( @ { $ e2 - > { NAME } } ) {
$ name = "$e1->{NAME}[0]_$x" ;
print FILE "NTSTATUS ejs_push_$name(struct ejs_rpc *, struct MprVar *, const char *, const uint32_t *);\n" ;
print FILE "NTSTATUS ejs_pull_$name(struct ejs_rpc *, struct MprVar *, const char *, const uint32_t *);\n" ;
}
}
}
2005-08-02 18:56:18 +00:00
}
}
2005-08-02 17:02:25 +00:00
}
print FILE "#endif\n" ;
close ( FILE ) ;
2005-08-07 19:22:20 +00:00
#
# Generate implementation
#
2005-08-02 17:02:25 +00:00
2005-08-05 05:32:39 +00:00
open ( FILE , ">libcli/gen_raw/ejs_${basename}.c" ) ;
2005-08-02 17:02:25 +00:00
print FILE "/* EJS wrapper functions auto-generated by build_smb_interfaces.pl */\n\n" ;
2005-08-05 05:32:39 +00:00
print FILE "#include \"includes.h\"\n" ;
print FILE "#include \"lib/appweb/ejs/ejs.h\"\n" ;
print FILE "#include \"scripting/ejs/ejsrpc.h\"\n" ; # TODO: remove this
print FILE "\n" ;
2005-08-05 01:23:35 +00:00
# Top level push/pull functions
2005-08-02 17:02:25 +00:00
2005-08-05 04:50:32 +00:00
sub print_field ($$) {
my $ f = shift ;
my $ suffix = shift ;
2005-08-05 15:54:11 +00:00
my $ type = $ f - > { TYPE } ;
2005-08-05 05:32:39 +00:00
2005-08-05 04:50:32 +00:00
if ( $ f - > { TYPE } eq "char" and $ f - > { POINTERS } == 1 ) {
$ type = "string" ;
}
if ( $ f - > { TYPE } =~ /_t$/ ) {
$ type = $ f - > { TYPE } ;
$ type =~ s/_t$// ;
}
2005-08-05 15:54:11 +00:00
my $ deref = "&" ;
if ( $ f - > { POINTERS } == 1 && $ type ne "string" ) {
$ deref = "" ;
}
2005-08-05 04:50:32 +00:00
foreach my $ x ( @ { $ f - > { NAME } } ) {
2005-08-05 15:54:11 +00:00
if ( $ f - > { POINTERS } > 0 ) {
print FILE "\t// alloc $x?\n" ;
}
2005-08-05 18:06:15 +00:00
if ( $ f - > { TYPE } eq "struct" ) {
$ type = $ f - > { STRUCT_NAME } ;
}
2005-08-05 15:54:11 +00:00
print FILE "\tNDR_CHECK(ejs_pull_$type(ejs, v, \"$x\", ${deref}r->$suffix.$x));\n" ;
2005-08-05 04:50:32 +00:00
}
}
2005-08-02 17:02:25 +00:00
foreach my $ x ( @ { $ header } ) {
2005-08-05 01:23:35 +00:00
2005-08-05 01:04:45 +00:00
next , if $ x - > { STRUCT_NAME } eq "" ;
2005-08-05 01:23:35 +00:00
2005-08-05 04:50:32 +00:00
# Pull in to struct.in
2005-08-05 01:23:35 +00:00
print FILE "static NTSTATUS ejs_pull_$x->{STRUCT_NAME}(struct ejs_rpc *ejs, struct MprVar *v, struct $x->{STRUCT_NAME} *r)\n" ;
print FILE "{\n" ;
print FILE "\tNDR_CHECK(ejs_pull_struct_start(ejs, &v, \"input\"));\n" ;
2005-08-05 04:50:32 +00:00
foreach my $ e ( @ { $ x - > { DATA } } ) {
next , if $ e - > { NAME } [ 0 ] ne 'in' ;
foreach my $ f ( @ { $ e - > { DATA } } ) {
print_field ( $ f , "in" ) ;
}
}
print FILE "\n\treturn NT_STATUS_OK;\n" ;
2005-08-05 01:23:35 +00:00
print FILE "}\n\n" ;
2005-08-05 04:50:32 +00:00
# Push from struct.out
2005-08-05 05:32:39 +00:00
print FILE "static NTSTATUS ejs_push_$x->{STRUCT_NAME}(struct ejs_rpc *ejs, struct MprVar *v, struct $x->{STRUCT_NAME} *r)\n\n" ;
2005-08-05 01:23:35 +00:00
print FILE "{\n" ;
print FILE "\tNDR_CHECK(ejs_push_struct_start(ejs, &v, \"output\"));\n" ;
2005-08-05 04:50:32 +00:00
foreach my $ e ( @ { $ x - > { DATA } } ) {
next , if $ e - > { NAME } [ 0 ] ne 'out' ;
foreach my $ f ( @ { $ e - > { DATA } } ) {
print_field ( $ f , "out" ) ;
}
}
print FILE "\n\treturn NT_STATUS_OK;\n" ;
2005-08-05 01:23:35 +00:00
print FILE "}\n\n" ;
}
2005-08-05 18:06:15 +00:00
# Nested anonymous structures
foreach my $ x ( @ { $ header } ) {
foreach my $ e1 ( @ { $ x - > { DATA } } ) {
foreach my $ e2 ( @ { $ e1 - > { DATA } } ) {
if ( $ e2 - > { TYPE } eq "struct" ) {
if ( defined ( $ e2 - > { NAME } ) and ! defined ( $ e2 - > { STRUCT_NAME } ) ) {
foreach my $ x ( @ { $ e2 - > { NAME } } ) {
$ name = "$e1->{NAME}[0]_$x" ;
print FILE "static NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const uint32_t *r)\n" ;
print FILE "{\n" ;
print FILE "\treturn NT_STATUS_OK;\n" ;
print FILE "}\n\n" ;
print FILE "static NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const uint32_t *r)\n" ;
print FILE "{\n" ;
print FILE "\treturn NT_STATUS_OK;\n" ;
print FILE "}\n\n" ;
}
}
}
}
}
}
2005-08-05 01:23:35 +00:00
# Top level call functions
foreach my $ x ( @ { $ header } ) {
next , if $ x - > { STRUCT_NAME } eq "" ;
$ raw_name = $ x - > { STRUCT_NAME } ;
$ raw_name =~ s/smb_/smb_raw_/ ;
2005-08-05 01:04:45 +00:00
print FILE "static int ejs_$x->{STRUCT_NAME}(int eid, int argc, struct MprVar **argv)\n" ;
print FILE "{\n" ;
2005-08-05 18:06:15 +00:00
print FILE "\tstruct $x->{STRUCT_NAME} params;\n" ;
2005-08-05 04:50:32 +00:00
print FILE "\tstruct smbcli_tree *tree;\n" ;
print FILE "\tNTSTATUS result;\n\n" ;
$ output = << "__HERE__" ;
if ( argc != 1 || argv [ 0 ] - > type != MPR_TYPE_OBJECT ) {
ejsSetErrorMsg ( eid , "invalid arguments" ) ;
return - 1 ;
}
tree = mprGetThisPtr ( eid , "tree" ) ;
if ( ! tree ) {
ejsSetErrorMsg ( eid , "invalid tree" ) ;
return - 1 ;
}
__HERE__
print FILE $ output ;
print FILE "\tresult = $raw_name(tree, ¶ms);\n\n" ;
2005-08-05 01:23:35 +00:00
2005-08-05 04:50:32 +00:00
print FILE "\tmpr_Return(eid, mprNTSTATUS(status));\n" ;
print FILE "\tif (NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_ERROR)) {\n" ;
print FILE "\t\treturn -1;\n" ;
print FILE "\t}\n\n" ;
print FILE "\treturn 0;\n" ;
2005-08-05 01:23:35 +00:00
2005-08-05 01:04:45 +00:00
print FILE "}\n\n" ;
2005-08-02 17:02:25 +00:00
}
2005-08-05 01:04:45 +00:00
# Module initialisation
print FILE "static int ejs_${basename}_init(int eid, int argc, struct MprVar **argv)\n" ;
print FILE "{\n" ;
2005-08-05 18:06:15 +00:00
print FILE "\tstruct MprVar *obj = mprInitObject(eid, \"${basename}\", argc, argv);\n\n" ;
2005-08-05 01:04:45 +00:00
foreach my $ x ( @ { $ header } ) {
next , if $ x - > { STRUCT_NAME } eq "" ;
print FILE "\tmprSetCFunction(obj, \"$x->{STRUCT_NAME}\", ejs_$x->{STRUCT_NAME});\n" ;
}
print FILE "}\n\n" ;
print FILE "NTSTATUS ejs_init_${basename}(void)\n" ;
print FILE "{\n" ;
print FILE "\treturn smbcalls_register_ejs(\"${basename}_init\", ejs_${basename}_init);\n" ;
print FILE "}\n" ;
2005-08-02 17:02:25 +00:00
close ( FILE ) ;