#!/usr/bin/perl # # Create ejs interfaces for structures in a C header file # use File::Basename; use Data::Dumper; my $file = shift; my $basename = basename($file, ".h"); require smb_interfaces; my $parser = new smb_interfaces; $header = $parser->parse($file); stat "libcli/gen_raw" || mkdir("libcli/gen_raw") || die("mkdir"); # Create header open(FILE, ">libcli/gen_raw/ejs_${basename}.h"); 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"; 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"; } foreach my $x (@{$header}) { # Prototypes for top level structures and unions prototypes_for($x); foreach my $e1 (@{$x->{DATA}}) { foreach my $e2 (@{$e1->{DATA}}) { # Prototypes for non-anonymous nested structures and unions: # # e.g struct foo {...}; if (defined($e2->{STRUCT_NAME}) or defined($e2->{UNION_NAME})) { prototypes_for($e2); } # 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"; } } } } } } print FILE "#endif\n"; close(FILE); # Create file open(FILE, ">libcli/gen_raw/ejs_${basename}.c"); print FILE "/* EJS wrapper functions auto-generated by build_smb_interfaces.pl */\n\n"; 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"; # Top level push/pull functions sub print_field($$) { my $f = shift; my $suffix = shift; my $type = $f->{TYPE}; if ($f->{TYPE} eq "char" and $f->{POINTERS} == 1) { $type = "string"; } if ($f->{TYPE} =~ /_t$/) { $type = $f->{TYPE}; $type =~ s/_t$//; } my $deref = "&"; if ($f->{POINTERS} == 1 && $type ne "string") { $deref = ""; } foreach my $x (@{$f->{NAME}}) { if ($f->{POINTERS} > 0) { print FILE "\t// alloc $x?\n"; } if ($f->{TYPE} eq "struct") { $type = $f->{STRUCT_NAME}; } print FILE "\tNDR_CHECK(ejs_pull_$type(ejs, v, \"$x\", ${deref}r->$suffix.$x));\n"; } } foreach my $x (@{$header}) { next, if $x->{STRUCT_NAME} eq ""; # Pull in to struct.in 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"; 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"; print FILE "}\n\n"; # Push from struct.out print FILE "static NTSTATUS ejs_push_$x->{STRUCT_NAME}(struct ejs_rpc *ejs, struct MprVar *v, struct $x->{STRUCT_NAME} *r)\n\n"; print FILE "{\n"; print FILE "\tNDR_CHECK(ejs_push_struct_start(ejs, &v, \"output\"));\n"; 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"; print FILE "}\n\n"; } # 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"; } } } } } } # 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_/; print FILE "static int ejs_$x->{STRUCT_NAME}(int eid, int argc, struct MprVar **argv)\n"; print FILE "{\n"; print FILE "\tstruct $x->{STRUCT_NAME} params;\n"; 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"; 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"; print FILE "}\n\n"; } # Module initialisation print FILE "static int ejs_${basename}_init(int eid, int argc, struct MprVar **argv)\n"; print FILE "{\n"; print FILE "\tstruct MprVar *obj = mprInitObject(eid, \"${basename}\", argc, argv);\n\n"; 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"; close(FILE);