From 84adefa331c4159d432d22840663c38f155cd4c1 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Fri, 20 Nov 2009 14:54:40 +0000 Subject: The R13B03 release. --- lib/ic/src/ic_cserver.erl | 2419 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2419 insertions(+) create mode 100644 lib/ic/src/ic_cserver.erl (limited to 'lib/ic/src/ic_cserver.erl') diff --git a/lib/ic/src/ic_cserver.erl b/lib/ic/src/ic_cserver.erl new file mode 100644 index 0000000000..52d98c5795 --- /dev/null +++ b/lib/ic/src/ic_cserver.erl @@ -0,0 +1,2419 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(ic_cserver). + +%% This module implements generation of C server code, where the +%% server acts as an Erlang C-node, where the functionality is that of +%% a gen_server (in C), and where the communication thus is according +%% to the Erlang distribution protocol. +%% + +-export([do_gen/3]). + +%% Silly dialyzer. +-export([filterzip/3]). + +%%------------------------------------------------------------ +%% +%% Internal stuff +%% +%%------------------------------------------------------------ + +-import(lists, [foreach/2, foldl/3, foldr/3, map/2]). +-import(ic_codegen, [emit/2, emit/3, emit/4, emit_c_enc_rpt/4, emit_c_dec_rpt/4]). + +-include("icforms.hrl"). +-include("ic.hrl"). +-include_lib("stdlib/include/erl_compile.hrl"). + +-define(IC_HEADER, "ic.h"). +-define(ERL_INTERFACEHEADER, "erl_interface.h"). +-define(EICONVHEADER, "ei.h"). +-define(OE_MSGBUFSIZE, "OE_MSGBUFSIZE"). +-define(ERLANGATOMLENGTH, "256"). + +%%------------------------------------------------------------ +%% +%% Entry point +%% +%%------------------------------------------------------------ +do_gen(G, File, Form) -> + OeName = ic_util:mk_oe_name(G, remove_ext(ic_util:to_list(File))), + G2 = ic_file:filename_push(G, [], OeName, c_server), + gen_headers(G2, [], Form), + R = gen(G2, [], Form), + ic_file:filename_pop(G2, c), + R. + +remove_ext(File) -> + filename:rootname(filename:basename(File)). + +%%------------------------------------------------------------ +%% +%% Generate the server side C stub and header files. +%% +%% For each module a separate file is generated. +%% +%% +%%------------------------------------------------------------ + +gen(G, N, [X| Xs]) when is_record(X, preproc) -> + NewG = change_file_stack(G, N, X#preproc.cat, X), + gen(NewG, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, module) -> + CD = ic_code:codeDirective(G, X), + G2 = ic_file:filename_push(G, N, X, CD), + N2 = [ic_forms:get_id2(X)| N], + gen_headers(G2, N2, X), + gen(G2, N2, ic_forms:get_body(X)), + G3 = ic_file:filename_pop(G2, CD), + gen(G3, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, interface) -> + G2 = ic_file:filename_push(G, N, X, c_server), + N2 = [ic_forms:get_id2(X)| N], + gen_prototypes(G2, N2, X), + gen_serv(G2, N2, X), + G3 = ic_file:filename_pop(G2, c), + gen(G3, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, const) -> + emit_constant(G, N, X), + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, op) -> + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, attr) -> + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, except) -> + icstruct:except_gen(G, N, X, c), + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, enum) -> + icenum:enum_gen(G, N, X, c), + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, typedef) -> + icstruct:struct_gen(G, N, X, c), + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, struct) -> + icstruct:struct_gen(G, N, X, c), + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, union) -> + icstruct:struct_gen(G, N, X, c), + gen(G, N, Xs); + +gen(G, N, [_| Xs]) -> + gen(G, N, Xs); + +gen(_G, _N, []) -> + ok. + +%%------------------------------------------------------------ +%% Change file stack +%%------------------------------------------------------------ + +change_file_stack(G, _N, line_nr, X) -> + Id = ic_forms:get_id2(X), + Flags = X#preproc.aux, + case Flags of + [] -> ic_genobj:push_file(G, Id); + _ -> + foldr( + fun({_, _, "1"}, G1) -> ic_genobj:push_file(G1, Id); + ({_, _, "2"}, G1) -> ic_genobj:pop_file(G1, Id); + ({_, _, "3"}, G1) -> ic_genobj:sys_file(G1, Id) + end, G, Flags) + end; +change_file_stack(G, _N, _Other, _X) -> + G. + +%%------------------------------------------------------------ +%% Generate headers +%%------------------------------------------------------------ + +%% Some items have extra includes +gen_headers(G, N, X) when is_record(X, module) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + HFd = ic_genobj:hrlfiled(G), + IncludeFileStack = ic_genobj:include_file_stack(G), + Filename = lists:nth(length(N) + 1, IncludeFileStack), + emit(HFd, "#include \"~s\"\n", [filename:basename(Filename)]), + ic_code:gen_includes(HFd, G, X, c_server); + false -> ok + end; +gen_headers(G, [], _X) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + HFd = ic_genobj:hrlfiled(G), + emit(HFd, "#include \n"), + case ic_options:get_opt(G, c_report) of + true -> + emit(HFd, "#ifndef OE_C_REPORT\n"), + emit(HFd, "#define OE_C_REPORT\n"), + emit(HFd, "#include \n"), + emit(HFd, "#endif\n"); + _ -> + ok + end, + emit(HFd, "#include \"~s\"\n", [?IC_HEADER]), + emit(HFd, "#include \"~s\"\n", [?ERL_INTERFACEHEADER]), + emit(HFd, "#include \"~s\"\n", [?EICONVHEADER]), + ic_code:gen_includes(HFd, G, c_server); + false -> ok + end; +gen_headers(_G, _N, _X) -> + ok. + +%%------------------------------------------------------------ +%% Generate prototypes +%%------------------------------------------------------------ + +gen_prototypes(G, N, X) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + HFd = ic_genobj:hrlfiled(G), + IncludeFileStack = ic_genobj:include_file_stack(G), + L = length(N), + Filename = + if + L < 2 -> + lists:nth(L + 1, IncludeFileStack); + true -> + lists:nth(2, IncludeFileStack) + end, + + IName = ic_util:to_undersc(N), + INameUC = ic_util:to_uppercase(IName), + + emit(HFd, "#include \"~s\"\n", [filename:basename(Filename)]), + ic_code:gen_includes(HFd, G, X, c_server), + ic_codegen:nl(HFd), + + emit(HFd, "\n#ifndef __~s__\n", [ic_util:to_uppercase(IName)]), + emit(HFd, "#define __~s__\n", [ic_util:to_uppercase(IName)]), + ic_codegen:mcomment_light(HFd, + [io_lib:format("Interface " + "object " + "definition: ~s", + [IName])], c), + case get_c_timeout(G, "") of + "" -> + ok; + {SendTmo, RecvTmo} -> + emit(HFd, "#define OE_~s_SEND_TIMEOUT ~s\n", + [INameUC, SendTmo]), + emit(HFd, "#define OE_~s_RECV_TIMEOUT ~s\n", + [INameUC, RecvTmo]), + emit(HFd, "#ifndef EI_HAVE_TIMEOUT\n"), + emit(HFd, "#error Functions for send and receive with " + "timeout not defined in erl_interface\n"), + emit(HFd, "#endif\n\n") + end, + + emit(HFd, "typedef CORBA_Object ~s;\n\n", [IName]), + emit(HFd, "#endif\n\n"), + + Bodies = [{N, ic_forms:get_body(X)}| X#interface.inherit_body], + + emit(HFd, "\n/* Structure definitions */\n", []), + foreach(fun({N2, Body}) -> + emit_structs_inside_module(G, HFd, N2, Body) end, + Bodies), + + emit(HFd, "\n/* Switch and exec functions */\n", []), + emit(HFd, "int ~s__switch(~s oe_obj, CORBA_Environment " + "*oe_env);\n", [IName, IName]), + foreach(fun({_N2, Body}) -> + emit_exec_prototypes(G, HFd, N, Body) end, + Bodies), + + emit(HFd, "\n/* Generic decoder */\n", []), + emit(HFd, "int ~s__call_info(~s oe_obj, CORBA_Environment " + "*oe_env);\n", [IName, IName]), + + emit(HFd, "\n/* Restore function typedefs */\n", []), + foreach(fun({_N2, Body}) -> + emit_restore_typedefs(G, HFd, N, Body) end, + Bodies), + + emit(HFd, "\n/* Callback functions */\n", []), + foreach(fun({_N2, Body}) -> + emit_callback_prototypes(G, HFd, N, Body) end, + Bodies), + + emit(HFd, "\n/* Parameter decoders */\n", []), + foreach(fun({_N2, Body}) -> + emit_decoder_prototypes(G, HFd, N, Body) end, + Bodies), + + emit(HFd, "\n/* Message encoders */\n", []), + foreach(fun({_N2, Body}) -> + emit_encoder_prototypes(G, HFd, N, Body) end, + Bodies), + + %% Emit operation mapping structures + emit_operation_mapping_declaration(G, HFd, N, Bodies), + + ok; + + false -> + ok + end. + +%%------------------------------------------------------------ +%% Generate the server encoding/decoding function +%%------------------------------------------------------------ + + +gen_serv(G, N, X) -> + case ic_genobj:is_stubfile_open(G) of + true -> + Fd = ic_genobj:stubfiled(G), + + emit_switch(G, Fd, N, X), + emit_server_generic_decoding(G, Fd, N), + + %% Sets the temporary variable counter. + put(op_variable_count, 0), + put(tmp_declarations, []), + + %% Generate exec, decode and encoding functions, and + %% table of exec functions. + Bodies = [{N, ic_forms:get_body(X)}| + X#interface.inherit_body], + + foreach(fun({_N2, Body}) -> + emit_dispatch(G, Fd, N, Body) end, + Bodies), + emit_operation_mapping(G, Fd, N, Bodies); + false -> + ok + end. + +%%------------------------------------------------------------ +%% Emit structs inside module +%%------------------------------------------------------------ + +emit_structs_inside_module(G, _Fd, N, Xs)-> + lists:foreach( + fun(X) when is_record(X, enum) -> + icenum:enum_gen(G, N, X, c); + (X) when is_record(X, typedef) -> + icstruct:struct_gen(G, N, X, c); + (X) when is_record(X, struct) -> + icstruct:struct_gen(G, N, X, c); + (X) when is_record(X, union) -> + icstruct:struct_gen(G, N, X, c); + (_) -> + ok + end, Xs). + +%%------------------------------------------------------------ +%% Emit exec prototypes +%%------------------------------------------------------------ + +emit_exec_prototypes(G, Fd, N, Xs) -> + lists:foreach( + fun(X) when is_record(X, op) -> + {ScopedName, _, _} = ic_cbe:extract_info(G, N, X), + emit(Fd, + "int ~s__exec(~s oe_obj, CORBA_Environment *oe_env);\n", + [ScopedName, ic_util:to_undersc(N)]); + (X) when is_record(X, const) -> + emit_constant(G, N, X); + (_) -> + ok + end, Xs). + +%%------------------------------------------------------------ +%% Emit restore typedefs +%%------------------------------------------------------------ + +emit_restore_typedefs(G, Fd, N, [X| Xs]) when is_record(X, op) -> + %% Check if to use scoped call names + {ScopedName, ArgNames, Types} = ic_cbe:extract_info(G, N, X), + {RetType, ParTypes, _} = Types, + TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames), + RT = mk_c_ret_type(G, N, RetType), + + PL = ic_util:mk_list(mk_par_list_for_callback_prototypes(G, N, X, + TypeAttrArgs)), + RPL = case PL of + "" -> + ""; + _PL -> + ", " ++ PL + end, + + case RT of + "void" -> + case PL of + "" -> + emit(Fd, "typedef void (*~s__rs(~s oe_obj, " + "CORBA_Environment *oe_env));\n", + [ScopedName, ic_util:to_undersc(N)]); + _ -> + emit(Fd, "typedef void (*~s__rs(~s oe_obj, ~s, " + "CORBA_Environment *oe_env));\n", + [ScopedName, ic_util:to_undersc(N), PL]) + end; + + "erlang_port*" -> + emit(Fd, "typedef void (*~s__rs(~s oe_obj, ~s~s, " + "CORBA_Environment *oe_env));\n", + [ScopedName, ic_util:to_undersc(N), RT, RPL]); + + "erlang_pid*" -> + emit(Fd, "typedef void (*~s__rs(~s oe_obj, ~s~s, " + "CORBA_Environment *oe_env));\n", + [ScopedName, ic_util:to_undersc(N), RT, RPL]); + + "erlang_ref*" -> + emit(Fd, "typedef void (*~s__rs(~s oe_obj, ~s~s, " + "CORBA_Environment *oe_env));\n", + [ScopedName, ic_util:to_undersc(N), RT, RPL]); + + _ -> + case ictype:isArray(G, N, RetType) of + true -> + emit(Fd, "typedef void (*~s__rs(~s oe_obj, ~s~s, " + "CORBA_Environment *oe_env));\n", + [ScopedName, ic_util:to_undersc(N), RT, RPL]); + false -> + emit(Fd, "typedef void (*~s__rs(~s oe_obj, ~s*~s, " + "CORBA_Environment *oe_env));\n", + [ScopedName, ic_util:to_undersc(N), RT, RPL]) + end + end, + emit_restore_typedefs(G, Fd, N, Xs); +emit_restore_typedefs(G, Fd, N, [X| Xs]) when is_record(X, attr) -> + emit_restore_typedefs(G, Fd, N, Xs); +emit_restore_typedefs(G, Fd, N, [_X| Xs]) -> + emit_restore_typedefs(G, Fd, N, Xs); +emit_restore_typedefs(_G, _Fd, _N, []) -> ok. + + +%%------------------------------------------------------------ +%% Emit call-back prototypes +%%------------------------------------------------------------ + +emit_callback_prototypes(G, Fd, N, [X| Xs]) when is_record(X, op) -> + %% Check scoped names XXX + {ScopedName, ArgNames, Types} = ic_cbe:extract_info(G, N, X), + {RetType, ParTypes, _} = Types, + TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames), + RT = mk_c_ret_type(G, N, RetType), + + PL = ic_util:mk_list(mk_par_list_for_callback_prototypes(G, N, X, + TypeAttrArgs)), + CBPL = case PL of + "" -> + ""; + _PL -> + ", " ++ PL + end, + case RT of + "void" -> + case PL of + "" -> + emit(Fd, "~s__rs* ~s__cb(~s oe_obj, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ScopedName, ic_util:to_undersc(N)]); + _ -> + emit(Fd, "~s__rs* ~s__cb(~s oe_obj, ~s, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ScopedName, ic_util:to_undersc(N), PL]) + end; + "erlang_port*" -> + emit(Fd, "~s__rs* ~s__cb(~s oe_obj, ~s~s, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ScopedName, ic_util:to_undersc(N), RT, CBPL]); + + "erlang_pid*" -> + emit(Fd, "~s__rs* ~s__cb(~s oe_obj, ~s~s, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ScopedName, ic_util:to_undersc(N), RT, CBPL]); + + "erlang_ref*" -> + emit(Fd, "~s__rs* ~s__cb(~s oe_obj, ~s~s, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ScopedName, ic_util:to_undersc(N), RT, CBPL]); + + _ -> + case ictype:isArray(G, N, RetType) of + true -> + emit(Fd, "~s__rs* ~s__cb(~s oe_obj, ~s~s, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ScopedName, ic_util:to_undersc(N), RT, + CBPL]); + false -> + emit(Fd, "~s__rs* ~s__cb(~s oe_obj, ~s*~s, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ScopedName, ic_util:to_undersc(N), RT, + CBPL]) + end + end, + emit_callback_prototypes(G, Fd, N, Xs); +emit_callback_prototypes(G, Fd, N, [X| Xs]) when is_record(X, attr) -> + emit_callback_prototypes(G, Fd, N, Xs); +emit_callback_prototypes(G, Fd, N, [_X| Xs]) -> + emit_callback_prototypes(G, Fd, N, Xs); +emit_callback_prototypes(_G, _Fd, _N, []) -> ok. + +%%------------------------------------------------------------ +%% Emit decoder prototypes +%%------------------------------------------------------------ + +emit_decoder_prototypes(G, Fd, N, [X| Xs]) when is_record(X, op) -> + %% Check if to use scoped call names + {ScopedName, ArgNames, Types} = ic_cbe:extract_info(G, N, X), + {_RetType, ParTypes, _} = Types, + TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames), + case ic_util:mk_list(mk_par_list_for_decoder_prototypes(G, N, X, + TypeAttrArgs)) of + "" -> + ok; + PLFDP -> + emit(Fd, "int ~s__dec(~s oe_obj, ~s, CORBA_Environment " + "*oe_env);\n", + [ScopedName, ic_util:to_undersc(N), PLFDP]) + end, + emit_decoder_prototypes(G, Fd, N, Xs); +emit_decoder_prototypes(G, Fd, N, [X| Xs]) when is_record(X, attr) -> + emit_decoder_prototypes(G, Fd, N, Xs); +emit_decoder_prototypes(G, Fd, N, [_X| Xs]) -> + emit_decoder_prototypes(G, Fd, N, Xs); +emit_decoder_prototypes(_G, _Fd, _N, []) -> ok. + + +%%------------------------------------------------------------ +%% Emit encoder prototypes +%%------------------------------------------------------------ + +emit_encoder_prototypes(G, Fd, N, [X| Xs]) when is_record(X, op) -> + case ic_forms:is_oneway(X) of + true -> + emit_encoder_prototypes(G, Fd, N, Xs); + false -> + %% Check if to use scoped call names + {ScopedName, ArgNames, Types} = ic_cbe:extract_info(G, N, X), + {RetType, ParTypes, _} = Types, + TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames), + RType = mk_c_ret_type(G, N, RetType), + case ic_util:mk_list(mk_par_list_for_encoder_prototypes( + G, N, X, TypeAttrArgs)) of + "" -> + case RType of + "void" -> + emit(Fd, "int ~s__enc(~s oe_obj, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ic_util:to_undersc(N)]); + _ -> + emit(Fd, "int ~s__enc(~s oe_obj, ~s, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ic_util:to_undersc(N), RType]) + end; + PLFEP -> + case RType of + "void" -> + emit(Fd, "int ~s__enc(~s oe_obj, ~s, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ic_util:to_undersc(N), PLFEP]); + _ -> + emit(Fd, "int ~s__enc(~s oe_obj, ~s, ~s, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ic_util:to_undersc(N), RType, + PLFEP]) + end + end, + emit_encoder_prototypes(G, Fd, N, Xs) + end; +emit_encoder_prototypes(G, Fd, N, [X| Xs]) when is_record(X, attr) -> + emit_encoder_prototypes(G, Fd, N, Xs); +emit_encoder_prototypes(G, Fd, N, [_X| Xs]) -> + emit_encoder_prototypes(G, Fd, N, Xs); +emit_encoder_prototypes(_G, _Fd, _N, []) -> ok. + +%%------------------------------------------------------------ +%% Emit operation mapping declaration +%%------------------------------------------------------------ + +emit_operation_mapping_declaration(G, Fd, N, Bodies) -> + Interface = ic_util:to_undersc(N), + Length = erlang:length(get_all_opnames(G, N, Bodies)), + emit(Fd, "\n/* Operation mapping */\n", []), + emit(Fd, "extern oe_map_t oe_~s_map;\n", [Interface]), + emit(Fd, "/* For backward compatibility */\n"), + emit(Fd, "#define ___~s_map___ oe_~s_map\n", + [Interface, Interface]), + case Length of + 0 -> + ok; + _ -> + emit(Fd, "extern oe_operation_t oe_~s_operations[];\n", + [Interface]), + emit(Fd, "/* For backward compatibility */\n"), + emit(Fd, "#define ___~s_operations___ oe_~s_operations\n", + [Interface, Interface]) + end. + + +%% Returns a list of {OpName, ScopedOpName} for all operations, where +%% OpName == ScopedOpName in case the `scoped_op_calls' option has +%% been set. +%% +get_all_opnames(G, N, Bodies) -> + ScNF = fun(X) -> + {ScName, _, _} = ic_cbe:extract_info(G, N, X), + ScName + end, + NF = case ic_options:get_opt(G, scoped_op_calls) of + true -> + ScNF; + false -> + fun(X) -> ic_forms:get_id2(X) end + end, + Filter = fun(X) when is_record(X, op) -> + {true, {NF(X), ScNF(X)}}; + (_) -> + false + end, + %% zf == filtermap + lists:flatmap(fun({_, Xs}) -> lists:zf(Filter, Xs) end, Bodies). + +%%------------------------------------------------------------ +%% Emit switch +%%------------------------------------------------------------ + +emit_switch(G, Fd, N, _X) -> + emit(Fd, "#include \n"), + case ic_options:get_opt(G, c_report) of + true -> + emit(Fd, "#ifndef OE_C_REPORT\n"), + emit(Fd, "#define OE_C_REPORT\n"), + emit(Fd, "#include \n"), + emit(Fd, "#endif\n"); + _ -> + ok + end, + StartCode = + "#include \"ic.h\"\n" + "#include \"erl_interface.h\"\n" + "#include \"ei.h\"\n" + "#include \"~s__s.h\"\n\n" + "/*\n" + " * Main switch\n" + " */\n\n" + "int ~s__switch(~s oe_obj, CORBA_Environment *oe_env)\n" + "{\n" + " return oe_exec_switch(oe_obj, oe_env, &oe_~s_map);\n" + "}\n\n", + ScopedName = ic_util:to_undersc(N), + emit(Fd, StartCode, [ScopedName, ScopedName, ScopedName, ScopedName]). + +%%------------------------------------------------------------ +%% Emit server generic decoding. +%%------------------------------------------------------------ + +emit_server_generic_decoding(G, Fd, N) -> + UserProto = get_user_proto(G, oe), + Code = + "/*\n" + " * Returns call identity (left only for backward compatibility)\n" + " */\n\n" + "int ~s__call_info(~s oe_obj, CORBA_Environment *oe_env)\n" + "{\n" + " return ~s_prepare_request_decoding(oe_env);\n" + "}\n\n", + IName = ic_util:to_undersc(N), + emit(Fd, Code, [IName, IName, UserProto]). + +%%------------------------------------------------------------ +%% Emit dispatch +%%------------------------------------------------------------ + +emit_dispatch(G, Fd, N, Xs) -> + lists:foreach( + fun(X) when is_record(X, op) -> + {Name, ArgNames, Types} = ic_cbe:extract_info(G, N, X), + {RetType, ParTypes, _} = Types, + TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames), + emit_exec_function(G, Fd, N, X, Name, RetType, TypeAttrArgs), + emit_parameter_decoder(G, Fd, N, X, Name, RetType, TypeAttrArgs), + emit_message_encoder(G, Fd, N, X, Name, RetType, TypeAttrArgs); + (_) -> + ok + end, Xs). + +%%------------------------------------------------------------ +%% Emit operation mapping +%%------------------------------------------------------------ + +emit_operation_mapping(G, Fd, N, Bodies) -> + OpNames = get_all_opnames(G, N, Bodies), + Interface = ic_util:to_undersc(N), + Length = erlang:length(OpNames), + emit(Fd, "\n/* Operation mapping */\n\n", []), + case Length of + 0 -> + emit(Fd, "oe_map_t oe_~s_map = { 0, NULL };\n\n", [Interface]); + _ -> + emit(Fd, "\noe_operation_t oe_~s_operations[~p] = {\n", + [Interface, Length]), + Members = lists:map( + fun({OpN, ScOpN}) -> + Name = ic_util:to_undersc([OpN]), + ScName = ic_util:to_undersc([ScOpN]), + io_lib:fwrite(" {~p, ~p, ~s__exec}", + [Interface, Name, ScName]) + end, OpNames), + emit(Fd, ic_util:join(Members, ",\n")), + emit(Fd, "};\n\n", []), + emit(Fd, "oe_map_t oe_~s_map = " + "{~p, oe_~s_operations};\n\n", + [Interface, Length, Interface]) + end. + +%%------------------------------------------------------------ +%% Emit constant +%%------------------------------------------------------------ + +emit_constant(G, N, ConstRecord) -> + case ic_genobj:is_hrlfile_open(G) of + false -> ok; + true -> + Fd = ic_genobj:hrlfiled(G), + CName = ic_util:to_undersc( + [ic_forms:get_id(ConstRecord#const.id)| N]), + UCName = ic_util:to_uppercase(CName), + + emit(Fd, "\n#ifndef __~s__\n", [UCName]), + emit(Fd, "#define __~s__\n\n", [UCName]), + + emit(Fd, "/* Constant: ~s */\n", [CName]), + + if is_record(ConstRecord#const.type, wstring) -> + %% If wstring, add 'L' + emit(Fd, "#define ~s L~p\n\n", [CName, + ConstRecord#const.val]); + true -> + emit(Fd, "#define ~s ~p\n\n", [CName, + ConstRecord#const.val]) + end, + + emit(Fd, "#endif\n\n") + end. + +%%------------------------------------------------------------ +%% Emit exec function +%%------------------------------------------------------------ + +emit_exec_function(G, Fd, N, X, Name, RetType, TypeAttrArgs) -> + %% Decoding operation specific part + InTypeAttrArgs = lists:filter(fun({_, in, _}) -> true; + ({_, _, _}) -> false + end, TypeAttrArgs), + ic_codegen:nl(Fd), + + emit(Fd, + "int ~s__exec(~s oe_obj, CORBA_Environment *oe_env)\n" + "{\n", + [Name, ic_util:to_undersc(N)]), + + emit(Fd, " if (oe_env->_received != ~p) {\n", [length(InTypeAttrArgs)]), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, BAD_PARAM, " + "\"Wrong number of operation parameters\");\n"), + emit_c_dec_rpt(Fd, " ", "wrong number of parameters", []), + emit_c_dec_rpt(Fd, " ", "server exec ~s\\n====\\n", [Name]), + emit(Fd, " return -1;\n", []), + emit(Fd, " }\n"), + emit(Fd, " else {\n", []), + + case InTypeAttrArgs of + [] -> + true; + _ -> + emit(Fd, " int oe_error_code = 0;\n") + end, + + %% Callback variable definition + emit_variable_defs(G, Fd, N, X, Name, RetType, TypeAttrArgs), + + %% Call to parameter decoder + emit_parameter_decoder_call(G, Fd, N, X, Name, RetType, TypeAttrArgs), + + %% Callback to user code + emit_callback(G, Fd, N, X, Name, RetType, TypeAttrArgs), + + %% Call to return message encoder + case ic_forms:is_oneway(X) of + true -> + true; + false -> + emit_message_encoder_call(G, Fd, N, X, Name, RetType, TypeAttrArgs) + end, + + %% Restore function call + emit_restore(G, Fd, N, X, Name, RetType, TypeAttrArgs), + + emit(Fd, " }\n return 0;\n}\n\n"). + +%%------------------------------------------------------------ +%% Emit parameter decoder +%%------------------------------------------------------------ + +emit_parameter_decoder(G, Fd, N, X, Name, _RetType, TypeAttrArgs) -> + %% Decoding operation specific part + InTypeAttrArgs = + lists:filter(fun({_, in, _}) -> true; + ({_, _, _}) -> false + end, TypeAttrArgs), + case InTypeAttrArgs of + [] -> + ok; + _ -> + case ic_util:mk_list(mk_par_list_for_decoder(G, N, X, + TypeAttrArgs)) of + "" -> + emit(Fd, "int ~s__dec(~s oe_obj, CORBA_Environment " + "*oe_env)\n{\n int oe_error_code;\n\n", + [Name, ic_util:to_undersc(N)]); + PLFD -> + emit(Fd, "int ~s__dec(~s oe_obj, ~s, CORBA_Environment " + "*oe_env)\n{\n", + [Name, ic_util:to_undersc(N), PLFD]), + emit(Fd, " int oe_error_code;\n\n") + end, + + APars = [], % XXX Alloced parameters + foldl( + fun({{'void', _}, _, _}, _Acc) -> + ok; + ({T1, A1, N1}, Acc) -> + emit_one_decoding(G, N, Fd, T1, A1, N1, Acc) + end, APars, InTypeAttrArgs), + + emit(Fd, " return 0;\n}\n\n") + end. + +%%------------------------------------------------------------ +%% Emit one decoding +%%------------------------------------------------------------ + +emit_one_decoding(G, N, Fd, T1, A1, N1, AllocedPars) -> + IndOp = mk_ind_op(A1), + case ic_cbe:is_variable_size(G, N, T1) of + false -> + %% The last parameter "oe_outindex" is not used in + %% the static case but must be there anyhow. + emit_decoding_stmt(G, N, Fd, T1, + N1, "", "oe_env->_inbuf", 1, "&oe_outindex", + caller, AllocedPars), + ic_codegen:nl(Fd), + AllocedPars; + true -> + emit_encoding_comment(G, N, Fd, "Decode", IndOp, T1, N1), + emit(Fd, " {\n"), + emit(Fd, " int oe_size_count_index = oe_env->_iin;\n"), + emit(Fd, " int oe_malloc_size = 0;\n"), + emit(Fd, " void *oe_first = NULL;\n"), + ic_cbe:emit_malloc_size_stmt(G, N, Fd, T1, + "oe_env->_inbuf", 1, caller), + %% This is the only malloc call in this file + emit(Fd, + " OE_MALLOC_SIZE_CHECK(oe_env, oe_malloc_size);\n" + " if ((*~s = oe_first = " + "malloc(oe_malloc_size)) == NULL) {\n", [N1]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + emit(Fd, + " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "NO_MEMORY, \"Cannot malloc\");\n" + " return -1;\n" + " }\n"), + ParName = "*" ++ N1, % XXX Why not IndOp? + NAllocedPars = [ParName| AllocedPars], + case ictype:isArray(G, N, T1) of + true -> + emit_decoding_stmt(G, N, Fd, T1, + "(*" ++ IndOp ++ N1 ++ ")", "", + "oe_env->_inbuf", 1, "&oe_outindex", + array_dyn, NAllocedPars); + false -> + emit_decoding_stmt(G, N, Fd, T1, + "(*" ++ IndOp ++ N1 ++ ")", "", + "oe_env->_inbuf", 1, "&oe_outindex", + caller_dyn, NAllocedPars) + end, + emit(Fd, " }\n\n"), + NAllocedPars + end. + +%%------------------------------------------------------------ +%% Emit message encoder +%%------------------------------------------------------------ + +emit_message_encoder(G, Fd, N, X, Name, RetType, TypeAttrArgs) -> + case ic_forms:is_oneway(X) of + false -> + %% Encoding operation specific part + emit(Fd, + "\nint ~s__enc(~s oe_obj", + [Name, ic_util:to_undersc(N)]), + RType = mk_c_ret_type(G, N, RetType), + ParList = mk_par_list_for_encoder(G, N, X, TypeAttrArgs), + case ic_util:mk_list(ParList) of + "" -> + case RType of + "void" -> + emit(Fd, ", CORBA_Environment *oe_env)\n{"); + _ -> + emit(Fd, ", ~s oe_return, CORBA_Environment " + "*oe_env)\n{", [RType]) + end; + PLFD -> + case RType of + "void" -> + emit(Fd, ", ~s, CORBA_Environment " + "*oe_env)\n{", [PLFD]); + _ -> + emit(Fd, ", ~s oe_return~s, CORBA_Environment " + "*oe_env)\n{", [RType, ", " ++ PLFD]) + end + end, + + + emit(Fd, "\n"), + emit(Fd, " int oe_error_code;\n\n"), + UserProto = get_user_proto(G, oe), + emit(Fd, " ~s_prepare_reply_encoding(oe_env);\n", [UserProto]), + + OutTypeAttrArgs = + lists:filter(fun({_, out, _}) -> true; + ({_, _, _}) -> false + end, TypeAttrArgs), + + OutLength = length(OutTypeAttrArgs), + case OutLength > 0 of + false -> + ic_codegen:nl(Fd); + true -> + emit(Fd, " oe_ei_encode_tuple_header(oe_env, ~p);\n\n", + [OutLength+1]) + + end, + + emit_encoding_comment(G, N, Fd, "Encode", "", RetType, + "oe_return"), + emit_encoding_stmt(G, N, X, Fd, RetType, "oe_return"), + + foreach(fun({T1, _A1, N1}) -> + case T1 of + {'void', _} -> + ok; + _ -> + emit_encoding_comment(G, N, Fd, "Encode", + "", T1, N1), + emit_encoding_stmt(G, N, X, Fd, T1, N1) + end + end, OutTypeAttrArgs), + emit(Fd, " return 0;\n}\n\n"); + _ -> + %% Oneway + ok + end. + +%%------------------------------------------------------------ +%% Emit message encoder call +%%------------------------------------------------------------ + +emit_message_encoder_call(G, Fd, N, X, Name, RetType, TypeAttrArgs) -> + emit(Fd, " /* Encoding reply message */\n"), + RType = mk_c_ret_type(G, N, RetType), + case ic_util:mk_list(mk_enc_par_list(G, N, X, TypeAttrArgs)) of + "" -> + case RType of + "void" -> + emit(Fd, " ~s(oe_obj, oe_env);\n", + [Name ++ "__enc"]); + "erlang_pid*" -> + emit(Fd, " ~s(oe_obj, &oe_return, oe_env);\n", + [Name ++ "__enc"]); + "erlang_port*" -> + emit(Fd, " ~s(oe_obj, &oe_return, oe_env);\n", + [Name ++ "__enc"]); + "erlang_ref*" -> + emit(Fd, " ~s(oe_obj, &oe_return, oe_env);\n", + [Name ++ "__enc"]); + _ -> + emit(Fd, " ~s(oe_obj, oe_return, oe_env);\n", + [Name ++ "__enc"]) + end; + + PLFE -> + case RType of + "void" -> + emit(Fd, " ~s(oe_obj, ~s, oe_env);\n", + [Name ++ "__enc", PLFE]); + "erlang_pid*" -> + emit(Fd, " ~s(oe_obj, &oe_return, ~s, oe_env);\n", + [Name ++ "__enc", PLFE]); + "erlang_port*" -> + emit(Fd, " ~s(oe_obj, &oe_return, ~s, oe_env);\n", + [Name ++ "__enc", PLFE]); + "erlang_ref*" -> + emit(Fd, " ~s(oe_obj, &oe_return, ~s, oe_env);\n", + [Name ++ "__enc", PLFE]); + _ -> + emit(Fd, " ~s(oe_obj, oe_return, ~s, oe_env);\n", + [Name ++ "__enc", PLFE]) + end + end, + ic_codegen:nl(Fd). + +%%------------------------------------------------------------ +%% Emit parameter decoding call +%%------------------------------------------------------------ + +emit_parameter_decoder_call(G, Fd, N, X, Name, _R, TypeAttrArgs) -> + case ic_util:mk_list(mk_dec_par_list(G, N, X, TypeAttrArgs)) of + "" -> %% No parameters ! skip it ! + ok; + PLFDC -> + ParDecName = Name ++ "__dec", + emit(Fd, + " /* Decode parameters */\n" + " if((oe_error_code = ~s(oe_obj, ~s, oe_env)) < 0) {\n", + [ParDecName, PLFDC]), + emit_c_dec_rpt(Fd, " ", "parmeters", []), + emit(Fd, + " if(oe_env->_major == CORBA_NO_EXCEPTION)\n" + " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad parameter on decode\");\n" + " return oe_error_code;\n }\n\n") + end. + +%%------------------------------------------------------------ +%% Emit call-back +%%------------------------------------------------------------ + +emit_callback(G, Fd, N, X, Name, RetType, TypeAttrArgs) -> + CallBackName = Name ++ "__cb", + emit(Fd, " /* Callback function call */\n"), + PL = ic_util:mk_list(mk_cb_par_list(G, N, X, TypeAttrArgs)), + case ic_forms:is_oneway(X) of + true -> + case PL of + "" -> + emit(Fd, " oe_restore = ~s(oe_obj, oe_env);\n\n", + [CallBackName]); + _ -> + emit(Fd, " oe_restore = ~s(oe_obj, ~s, oe_env);\n\n", + [CallBackName, PL]) + end; + false -> + CBPL = case PL of + "" -> + ""; + _PL -> + ", " ++ PL + end, + case mk_c_ret_type(G, N, RetType) of + "void" -> + case PL of + "" -> + emit(Fd, " oe_restore = ~s(oe_obj, oe_env);" + "\n\n", [CallBackName]); + _ -> + emit(Fd, " oe_restore = ~s(oe_obj, ~s, oe_env);" + "\n\n", [CallBackName, PL]) + end; + _ -> + case ictype:isArray(G, N, RetType) of + true -> + emit(Fd, + " oe_restore = ~s(oe_obj, oe_return~s, " + " oe_env);\n\n", [CallBackName, CBPL]); + false -> + emit(Fd, " oe_restore = ~s(oe_obj, " + "&oe_return~s, oe_env);\n\n", + [CallBackName, CBPL]) + end + end + end. + +%%------------------------------------------------------------ +%% Emit restore +%%------------------------------------------------------------ + +emit_restore(G, Fd, N, X, _Name, RetType, TypeAttrArgs) -> + emit(Fd, " /* Restore function call */\n"), + emit(Fd, " if (oe_restore != NULL)\n"), + PL = ic_util:mk_list(mk_cb_par_list(G, N, X, TypeAttrArgs)), + case ic_forms:is_oneway(X) of + true -> + case PL of + "" -> + emit(Fd, " (*oe_restore)(oe_obj, oe_env);\n\n"); + _ -> + emit(Fd, " (*oe_restore)(oe_obj, ~s, oe_env);\n\n", + [PL]) + end; + false -> + RPL = case PL of + "" -> + ""; + _PL -> + ", " ++ PL + end, + case mk_c_ret_type(G, N, RetType) of + "void" -> + case PL of + "" -> + emit(Fd, " (*oe_restore)(oe_obj, oe_env);" + "\n\n"); + _ -> + emit(Fd, " (*oe_restore)(oe_obj, ~s, oe_env);" + "\n\n", [PL]) + end; + _ -> + case ictype:isArray(G, N, RetType) of + true -> + emit(Fd, + " (*oe_restore)(oe_obj, oe_return~s, " + " oe_env);\n\n", [RPL]); + false -> + emit(Fd, " (*oe_restore)(oe_obj, " + "&oe_return~s, oe_env);\n\n", [RPL]) + end + end + end. + +%%------------------------------------------------------------ +%% Emit variable defs +%%------------------------------------------------------------ + +emit_variable_defs(G, Fd, N, X, _Name, RetType, TypeAttrArgs) -> + {ScopedName, _, _} = ic_cbe:extract_info(G, N, X), + emit(Fd, " ~s__rs* oe_restore = NULL;\n", [ScopedName]), + RestVars = mk_var_list(mk_var_decl_list(G, N, X, TypeAttrArgs)), + case ic_forms:is_oneway(X) of + true -> + emit(Fd, "~s\n\n", [RestVars]); + false -> + RType = mk_c_ret_type(G, N, RetType), + case RType of + "void" -> + emit(Fd, "~s\n\n", [RestVars]); + "CORBA_unsigned_long" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_unsigned_long_long" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_unsigned_short" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_short" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_long" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_long_long" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_float" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_double" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_char" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_wchar" -> %% WCHAR + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_boolean" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_octet" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + _ -> + case ic_cbe:is_variable_size(G, N, RetType) of + true -> + emit(Fd, "~s ~s oe_return;\n\n", + [RestVars, RType]); + false -> + TK = ic_forms:get_tk(X), + case TK of + {tk_enum, _, _, _List} -> + emit(Fd, "~s ~s oe_return;\n\n", + [RestVars, RType]); + _ -> + case RType of + "erlang_binary*" -> + emit(Fd, "~s erlang_binary " + "oe_return;\n\n", [RestVars]); + "erlang_pid*" -> + emit(Fd, "~s erlang_pid " + "oe_return;\n\n", [RestVars]); + "erlang_port*" -> + emit(Fd, "~s erlang_port " + "oe_return;\n\n", [RestVars]); + "erlang_ref*" -> + emit(Fd, "~s erlang_ref " + "oe_return;\n\n", [RestVars]); + _ -> + %% Structures are + %% initiated by memset + emit(Fd, "~s ~s " + "oe_return;\n\n", + [RestVars, RType]) + end, + emit(Fd, " memset(&oe_return, 0, " + "sizeof(oe_return));\n\n") + end + end + end + end. + +%%------------------------------------------------------------ +%% Make variable list +%%------------------------------------------------------------ + +%% XXX Modify +mk_var_list([]) -> + ""; +mk_var_list([Arg| Args]) -> + " " ++ Arg ++ ";\n" ++ mk_var_list(Args). + +%%------------------------------------------------------------ +%% Make return type +%%------------------------------------------------------------ + +mk_c_ret_type(G, N, Type) -> + Ctype = mk_c_type(G, N, Type), + Dyn = case ic_cbe:is_variable_size(G, N, Type) of + true -> + if + is_record(Type, string) -> + "*"; + Ctype == "CORBA_char *" -> + ""; + is_record(Type, wstring) -> %% WSTRING + "*"; + Ctype == "CORBA_wchar *" -> %% WSTRING + ""; + true -> + case ictype:isArray(G, N, Type) of + true -> + ""; + _ -> + "*" + end + end; + false -> + if + Ctype == "erlang_pid" -> + "*"; + Ctype == "erlang_port" -> + "*"; + Ctype == "erlang_ref" -> + "*"; + true -> + "" + end + end, + Ctype ++ Dyn. + +%%------------------------------------------------------------ +%% Make call-back parameter list +%%------------------------------------------------------------ + +mk_cb_par_list(G, N, X, TypeAttrArgs0) -> + TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [in, out], TypeAttrArgs0), + lists:map( + fun({Type, Attr, Arg}) -> + case ic_cbe:is_variable_size(G, N, Type) of + true -> + case Attr of + in -> + Arg; + out -> + case ictype:isArray(G, N, Type) of + true -> + Arg; + _ -> + "&" ++ Arg + end + end; + false -> + case ictype:isArray(G, N, Type) of + true -> + Arg; + _ -> + "&" ++ Arg + end + end + end, TypeAttrArgs1). + +%%------------------------------------------------------------ +%% Make decoder parameter list +%%------------------------------------------------------------ + +mk_dec_par_list(G, N, X, TypeAttrArgs0) -> + TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [in], + TypeAttrArgs0), + lists:map( + fun({Type, _Attr, Arg}) -> + Ctype = mk_c_type(G, N, Type), + case ic_cbe:is_variable_size(G, N, Type) of + true -> + if + is_record(Type, string) -> + "&" ++ Arg; + Ctype == "CORBA_char *" -> + Arg; + is_record(Type, wstring) -> + "&" ++ Arg; + Ctype == "CORBA_wchar *" -> + Arg; + true -> + "&" ++ Arg + end; + false -> + case ictype:isArray(G, N, Type) of + true -> + Arg; + _ -> + "&" ++ Arg + end + end + end, TypeAttrArgs1). + +%%------------------------------------------------------------ +%% Make encoder parameter list +%%------------------------------------------------------------ + +mk_enc_par_list(G, N, X, TypeAttrArgs0) -> + TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [out], + TypeAttrArgs0), + lists:map( + fun({Type, _Attr, Arg}) -> + Ctype = mk_c_type(G, N, Type), + case Ctype of + "erlang_pid" -> + "&" ++ Arg; + "erlang_port" -> + "&" ++ Arg; + "erlang_ref" -> + "&" ++ Arg; + _ -> + Arg + end + end, TypeAttrArgs1). + +%%------------------------------------------------------------ +%% Make type argument list +%%------------------------------------------------------------ + +mk_type_attr_arg_list(Types, Args) -> + filterzip( + fun(Type, {Attr, Arg}) -> + {true, {Type, Attr, Arg}} + end, Types, Args). + +%%------------------------------------------------------------ +%% Filter type argument list +%%------------------------------------------------------------ + +filter_type_attr_arg_list(G, X, InOrOut, TypeAttrArgs) -> + lists:filter( + + fun({_Type, inout, Arg}) -> + ic_error:error(G, {inout_spec_for_c, X, Arg}), + false; + ({_Type, Attr, _Arg}) -> + lists:member(Attr, InOrOut) + end, TypeAttrArgs). + +%%------------------------------------------------------------ +%% Make indirection operator +%%------------------------------------------------------------ + +mk_ind_op(in) -> + ""; +mk_ind_op(inout) -> + error; +mk_ind_op(_) -> + "*". + +%%------------------------------------------------------------ +%% Make parameter list for decoder +%%------------------------------------------------------------ + +mk_par_list_for_decoder(G, N, X, TypeAttrArgs0) -> + TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [in], TypeAttrArgs0), + lists:map( + fun({Type, Attr, Arg}) -> + Ctype = mk_c_type(G, N, Type), + Dyn = case ic_cbe:is_variable_size(G, N, Type) of + true -> + if + is_record(Type, string) -> + "**"; + Ctype == "CORBA_char *" -> + ""; + is_record(Type, wstring) -> %% WSTRING + "**"; + Ctype == "CORBA_wchar *" -> %% WSTRING + ""; + true -> + case ictype:isArray(G, N, Type) of + true -> + slice(Attr) ++ "*"; + _ -> + "**" + end + end; + false -> + case ictype:isArray(G, N, Type) of + true -> + ""; + _ -> + "*" + end + end, + Ctype ++ Dyn ++ " " ++ Arg + end, TypeAttrArgs1). + +%%------------------------------------------------------------ +%% Make parameter list for encoder +%%------------------------------------------------------------ + +mk_par_list_for_encoder(G, N, X, TypeAttrArgs0) -> + TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [out], TypeAttrArgs0), + lists:map( + fun({Type, _Attr, Arg}) -> + Ctype = mk_c_type(G, N, Type), + Dyn = case ic_cbe:is_variable_size(G, N, Type) of + true -> + if + is_record(Type, string) -> + "*"; + Ctype == "CORBA_char *" -> + ""; + is_record(Type, wstring) -> %% WSTRING + "*"; + Ctype == "CORBA_wchar *" -> %% WSTRING + ""; + true -> + case ictype:isArray(G, N, Type) of + true -> + ""; + _ -> + "*" + end + end; + false -> + if + Ctype == "erlang_pid" -> + "*"; + Ctype == "erlang_port" -> + "*"; + Ctype == "erlang_ref" -> + "*"; + true -> + "" + end + end, + Ctype ++ " " ++ Dyn ++ Arg + end, TypeAttrArgs1). + +%%------------------------------------------------------------ +%% Make parameter list for decoder prototypes +%%------------------------------------------------------------ + +mk_par_list_for_decoder_prototypes(G, N, X, TypeAttrArgs0) -> + TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [in], TypeAttrArgs0), + lists:map( + fun({Type, Attr, _Arg}) -> + Ctype = mk_c_type(G, N, Type), + Dyn = case ic_cbe:is_variable_size(G, N, Type) of + true -> + if + is_record(Type, string) -> + "**"; + Ctype == "CORBA_char *" -> + ""; + is_record(Type, wstring) -> %% WSTRING + "**"; + Ctype == "CORBA_wchar *" -> %% WSTRING + ""; + true -> + case ictype:isArray(G, N, Type) of + true -> + slice(Attr) ++ "*"; + _ -> + "**" + end + end; + false -> + case ictype:isArray(G, N, Type) of + true -> + ""; + _ -> + "*" + end + end, + Ctype ++ Dyn + end, TypeAttrArgs1). + +%%------------------------------------------------------------ +%% Make parameter list for encoder prototypes +%%------------------------------------------------------------ + +mk_par_list_for_encoder_prototypes(G, N, X, TypeAttrArgs0) -> + TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [out], TypeAttrArgs0), + lists:map( + fun({Type, _Attr, _Arg}) -> + Ctype = mk_c_type(G, N, Type), + Dyn = case ic_cbe:is_variable_size(G, N, Type) of + true -> + if + is_record(Type, string) -> + "*"; + Ctype == "CORBA_char *" -> + ""; + is_record(Type, wstring) -> %% WSTRING + "*"; + Ctype == "CORBA_wchar *" -> %% WSTRING + ""; + true -> + case ictype:isArray(G, N, Type) of + true -> + ""; + _ -> + "*" + end + end; + false -> + if + Ctype == "erlang_pid" -> + "*"; + Ctype == "erlang_port" -> + "*"; + Ctype == "erlang_ref" -> + "*"; + true -> + "" + end + end, + Ctype ++ Dyn + end, TypeAttrArgs1). + +%%------------------------------------------------------------ +%% Make parameter list for call-back prototypes +%%------------------------------------------------------------ + +mk_par_list_for_callback_prototypes(G, N, X, TypeAttrArgs0) -> + TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [in, out], + TypeAttrArgs0), + lists:map( + fun({Type, Attr, _Arg}) -> + IndOp = mk_ind_op(Attr), + Ctype = mk_c_type(G, N, Type), + Dyn = case ic_cbe:is_variable_size(G, N, Type) of + true -> + if + is_record(Type, string) -> + "*" ++ IndOp; + Ctype == "CORBA_char *" -> + "" ++ IndOp; + is_record(Type, wstring) -> %% WSTRING + "*" ++ IndOp; + Ctype == "CORBA_wchar *" -> %% WSTRING + "" ++ IndOp; + true -> + case ictype:isArray(G, N, Type) of + true -> + ""; + _ -> + "*" ++ IndOp + end + end; + false -> + case ictype:isArray(G, N, Type) of + true -> + ""; + _ -> + case Attr of %% Should just be IndOp + in -> + "*" ++ IndOp; + out -> + IndOp + end + end + end, + Ctype ++ Dyn + end, TypeAttrArgs1). + +%%------------------------------------------------------------ +%% Make variable declaration list +%%------------------------------------------------------------ + +mk_var_decl_list(G, N, X, TypeAttrArgs0) -> + TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [in, out], + TypeAttrArgs0), + lists:map( + fun({Type, Attr, Arg}) -> + Ctype = mk_c_type(G, N, Type), + VarDecl = case ic_cbe:is_variable_size(G, N, Type) of + true -> + if + is_record(Type, string) -> + Ctype ++ "* " ++ Arg ++ " = NULL"; + Ctype == "CORBA_char *" -> + Ctype ++ " " ++ Arg ++ " = NULL"; + is_record(Type, wstring) -> %% WSTRING + Ctype ++ "* " ++ Arg ++ " = NULL"; + Ctype == "CORBA_wchar *" -> %% WSTRING + Ctype ++ " " ++ Arg ++ " = NULL"; + true -> + case ictype:isArray(G, N, Type) of + true -> + Ctype ++ slice(Attr) ++ " " ++ + Arg; + _ -> + Ctype ++ "* " ++ Arg + end + end; + false -> + Ctype ++ " " ++ Arg + end, + + VarDecl + end, TypeAttrArgs1). + +%%------------------------------------------------------------ +%% Slice +%%------------------------------------------------------------ + +slice(in) -> + "_slice*"; +slice(_) -> + "". + +%%------------------------------------------------------------ +%% Special comment functions +%%------------------------------------------------------------ + +emit_encoding_comment(G, N, F, String, RefOrVal, Type, Name) -> + emit(F, [io_lib:format(" /* ~s parameter: ~s~s ~s */\n", + [String, mk_c_type(G, N, Type), + RefOrVal, Name])]). + + +%%------------------------------------------------------------ +%% Make C type +%%------------------------------------------------------------ + +%% +%% Warning this is NOT identical to mk_c_type in ic_cbe.erl +%% +mk_c_type(G, N, S) -> + mk_c_type(G, N, S, evaluate). + +mk_c_type(G, N, S, evaluate) when element(1, S) == scoped_id -> + {FullScopedName, _T, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S), + BT = ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)), + case BT of + "erlang_binary" -> + "erlang_binary"; + "erlang_pid" -> + "erlang_pid"; + "erlang_port" -> + "erlang_port"; + "erlang_ref" -> + "erlang_ref"; + "erlang_term" -> + "ETERM*"; + {enum, Type} -> + mk_c_type(G, N, Type, evaluate); + Type -> + mk_c_type(G, N, Type, evaluate) + end; +mk_c_type(G, N, S, evaluate_not) when element(1, S) == scoped_id -> + {FullScopedName, _T, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S), + BT = ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)), + case BT of + "erlang_binary" -> + "erlang_binary"; + "erlang_pid" -> + "erlang_pid"; + "erlang_port" -> + "erlang_port"; + "erlang_ref" -> + "erlang_ref"; + "erlang_term" -> + "ETERM*"; + Type -> + Type + end; +mk_c_type(_G, _N, S, _) when is_list(S) -> + S; +mk_c_type(_G, _N, S, _) when is_record(S, string) -> + "CORBA_char"; +mk_c_type(_G, _N, S, _) when is_record(S, wstring) -> %% WSTRING + "CORBA_wchar"; +mk_c_type(_G, _N, {boolean, _}, _) -> + "CORBA_boolean"; +mk_c_type(_G, _N, {octet, _}, _) -> + "CORBA_octet"; +mk_c_type(_G, _N, {void, _}, _) -> + "void"; +mk_c_type(_G, _N, {unsigned, U}, _) -> + case U of + {short, _} -> + "CORBA_unsigned_short"; + {long, _} -> + "CORBA_unsigned_long"; + {'long long', _} -> + "CORBA_unsigned_long_long" + end; +mk_c_type(_G, _N, {'long long', _}, _) -> + "CORBA_long_long"; +mk_c_type(_G, _N, {'any', _}, _) -> %% Fix for any type + "CORBA_long"; +mk_c_type(_G, _N, {T, _}, _) -> + "CORBA_" ++ atom_to_list(T). + +%%------------------------------------------------------------ +%% Emit encoding statement +%%------------------------------------------------------------ + +%% emit_encoding_stmt(G, N, X, Fd, T, LName) +%% +%% +emit_encoding_stmt(G, N, X, Fd, T, LName) when element(1, T) == scoped_id -> + case mk_c_type(G, N, T, evaluate_not) of + "erlang_pid" -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_pid(oe_env, ~s)) < 0) {\n", + [LName]), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_pid", []), + emit(Fd, " return oe_error_code;\n }\n"); + "erlang_port" -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_port(oe_env, ~s)) < 0) {\n", + [LName]), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_port", []), + emit(Fd, " return oe_error_code;\n }\n"); + "erlang_ref" -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_ref(oe_env, ~s)) < 0) {\n", + [LName]), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_ref", []), + emit(Fd, " return oe_error_code;\n }\n"); + "ETERM*" -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_term(oe_env, ~s)) < 0) {\n", + [LName]), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_term", []), + emit(Fd, " return oe_error_code;\n }\n"); + {enum, FSN} -> + emit_encoding_stmt(G, N, X, Fd, FSN, LName); + FSN -> + emit_encoding_stmt(G, N, X, Fd, FSN, LName) + end; +emit_encoding_stmt(G, N, X, Fd, T, LName) when is_list(T) -> + %% Already a fullscoped name + case get_param_tk(LName, X) of + error -> + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "encode_"), T, LName]); + ParamTK -> + case ic_cbe:is_variable_size(ParamTK) of + true -> + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, ~s)) < 0)" + " {\n", + [ic_util:mk_oe_name(G, "encode_"), T, LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");" + "\n"), + ?emit_c_enc_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n }\n\n"); + false -> + if is_atom(ParamTK) -> + case ParamTK of + tk_ushort -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_ulong(oe_env, " + "(unsigned long) ~s)) < 0) {\n", + [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "ushort", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_ulong -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_ulong(oe_env, " + "~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "ulong", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_ulonglong -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_ulonglong(oe_env, " + "~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "ulonglong", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_short -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_long(oe_env, " + "(long) ~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "short", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_long -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_long(oe_env, " + "~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "long", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_longlong -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_longlong(oe_env, " + "~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "longlong", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_float -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_double(oe_env, " + "(double) ~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "float", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_double -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_double(oe_env, " + "~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "double", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_boolean -> + emit(Fd, " switch(~s) {\n", [LName]), + emit(Fd, " case 0 :\n"), + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_atom(oe_env, " + "\"false\")) < 0) {\n"), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "boolean", []), + emit(Fd, " return " + "oe_error_code;\n }\n"), + emit(Fd, " break;\n"), + emit(Fd, " case 1 :\n"), + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_atom(oe_env, " + "\"true\")) < 0) {\n"), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "boolean", []), + emit(Fd, " return " + "oe_error_code;\n }\n"), + emit(Fd, " break;\n"), + emit(Fd, " default :\n"), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "boolean", []), + emit(Fd, " return -1;\n"), + emit(Fd, " }\n\n"); + tk_char -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_char(oe_env, " + "~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "char", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_wchar -> %% WCHAR + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_wchar(oe_env, " + "~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "wchar", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_octet -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_char(oe_env, " + "~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "octet", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_any -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_long(oe_env, " + "~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "any", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + _ -> + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "tk_unknown", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"), + ok + end; + true -> + case element(1, ParamTK) of + tk_enum -> + emit(Fd, " if ((oe_error_code = " + "~s~s(oe_env, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "encode_"), + T, LName]), + ?emit_c_enc_rpt(Fd, " ", "enum", []); + tk_array -> + emit(Fd, " if ((oe_error_code = " + "~s~s(oe_env, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "encode_"), + T, LName]), + ?emit_c_enc_rpt(Fd, " ", "array", []); + _ -> + emit(Fd, " if ((oe_error_code = " + "~s~s(oe_env, &~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "encode_"), + T, LName]), + ?emit_c_enc_rpt(Fd, " ", "", []) + end, + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n") + end + end + end; +emit_encoding_stmt(G, N, _X, Fd, T, LName) when is_record(T, string) -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_string(oe_env, (const char*) ~s)) < 0) {\n", + [LName]), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Cannot encode string\");\n"), + ?emit_c_enc_rpt(Fd, " ", "string", []), + emit(Fd, " return oe_error_code;\n }\n\n"); +emit_encoding_stmt(G, N, _X, Fd, T, LName) when is_record(T, wstring) -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_wstring(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "wstring", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Cannot encode string\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); +emit_encoding_stmt(G, N, _X, Fd, T, LName) -> + case T of + {unsigned, {short, _}} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_ulong(oe_env, (unsigned long) ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "ushort", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {unsigned, {long, _}} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_ulong(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "ulong", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {unsigned, {'long long', _}} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_ulonglong(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "ulonglong", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {short, _} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_long(oe_env, (long) ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "short", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {long, _} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_long(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "long", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {'long long', _} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_longlong(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "longlong", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {float, _} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_double(oe_env, (double) ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "float", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {double, _} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_double(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "double", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {boolean, _} -> + emit(Fd, " switch(~s) {\n", [LName]), + emit(Fd, " case 0 :\n"), + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_atom(oe_env, \"false\")) < 0) {\n"), + ?emit_c_enc_rpt(Fd, " ", "boolean", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " break;\n"), + emit(Fd, " case 1 :\n"), + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_atom(oe_env, \"true\")) < 0) {\n"), + ?emit_c_enc_rpt(Fd, " ", "boolean", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " break;\n"), + emit(Fd, " default :\n"), + ?emit_c_enc_rpt(Fd, " ", "boolean", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return -1;\n"), + emit(Fd, " }\n\n"); + {char, _} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_char(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "char", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {wchar, _} -> %% WCHAR + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_wchar(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "wchar", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {octet, _} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_char(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "octet", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {void, _} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_atom(oe_env, \"void\")) < 0) {\n"), + ?emit_c_enc_rpt(Fd, " ", "void", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {sequence, _, _} -> + ?emit_c_enc_rpt(Fd, " ", "sequence", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {any, _} -> %% Fix for any type + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_long(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "any", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + _ -> + ic_error:fatal_error(G, {illegal_typecode_for_c, T, N}) + end. + +%%------------------------------------------------------------ +%% Get type kind parameter +%%------------------------------------------------------------ + +%% Useful functions +get_param_tk("oe_return", Op) -> + ic_forms:get_tk(Op); +get_param_tk(Name, Op) -> + case get_param(Name, Op) of + error -> + error; + Param -> + ic_forms:get_tk(Param) + end. + +%%------------------------------------------------------------ +%% Get parameter (for what? XXX) +%%------------------------------------------------------------ + +get_param(Name, Op) when is_record(Op, op) -> + get_param_loop(Name, Op#op.params); +get_param(_Name, _Op) -> + error. + +get_param_loop(_Name, []) -> + error; +get_param_loop(Name, [Param| Params]) -> + case ic_forms:get_id2(Param) of + Name -> + Param; + _ -> + get_param_loop(Name, Params) + end. + +%%------------------------------------------------------------ +%% Emit decoding statement +%%------------------------------------------------------------ + +emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, Align, NextPos, + DecType, AllocedPars) when element(1, T) == scoped_id -> + case mk_c_type(G, N, T, evaluate_not) of + "erlang_pid" -> + emit(Fd, " if ((oe_error_code = ei_decode_pid(~s, " + "&oe_env->_iin, ~s~s)) < 0) {\n", + [InBuffer, IndOp, LName]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n\n"); + "erlang_port" -> + emit(Fd, " if ((oe_error_code = ei_decode_port(~s, " + "&oe_env->_iin, ~s~s)) < 0) {\n", + [InBuffer, IndOp, LName]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n\n"); + "erlang_ref" -> + emit(Fd, " if ((oe_error_code = ei_decode_ref(~s, " + "&oe_env->_iin, ~s~s)) < 0) {\n", + [InBuffer, IndOp, LName]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n\n"); + "ETERM*" -> + emit(Fd, " if ((oe_error_code = ei_decode_term(~s, " + "&oe_env->_iin, (void**)~s~s)) < 0) {\n", + [InBuffer, IndOp, LName]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n\n"); + {enum, FSN} -> + emit_decoding_stmt(G, N, Fd, FSN, LName, IndOp, + InBuffer, Align, NextPos, DecType, AllocedPars); + FSN -> + emit_decoding_stmt(G, N, Fd, FSN, LName, IndOp, + InBuffer, Align, NextPos, DecType, AllocedPars) + end; +emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, NextPos, + DecType, AllocedPars) when is_list(T) -> + %% Already a fullscoped name + Type = ictype:name2type(G, T), + case ictype:isBasicType(Type) of + true -> + emit_decoding_stmt_for_basic_type(Fd, Type, InBuffer, IndOp, + LName, AllocedPars); + false -> + emit(Fd, " {\n"), + case DecType of + caller -> %% No malloc used, define oe_first anyhow. + emit(Fd, " void *oe_first = NULL;\n"), + emit(Fd, " int oe_outindex = 0;\n\n"); + array_dyn -> %% Malloc used + emit(Fd, " int oe_outindex = 0;\n\n"); + %% [ic_util:mk_align(io_lib:format("sizeof(~s)", [T]))]); + caller_dyn -> %% Malloc used + emit(Fd, " int oe_outindex = 0;\n\n") + end, + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, oe_first, " + "~s, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "decode_"), + T, NextPos, LName]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"), + emit(Fd, " }\n") + end; +emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, _NextPos, + _DecType, AllocedPars) when is_record(T, string) -> + emit(Fd, " if ((oe_error_code = ei_decode_string(~s, " + "&oe_env->_iin, ~s~s)) < 0) {\n", + [InBuffer, IndOp, LName]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"); +emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, _NextPos, + _DecType, AllocedPars) when is_record(T, wstring) -> + %% WSTRING + emit(Fd, " if ((oe_error_code = " + "oe_ei_decode_wstring(~s, " + "&oe_env->_iin, ~s~s)) < 0) {\n", + [InBuffer, IndOp, LName]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n\n"), + emit(Fd, " }\n"); +emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, _NextPos, + _DecType, AllocedPars) -> + case ic_cbe:normalize_type(T) of + {basic, Type} -> + emit_decoding_stmt_for_basic_type(Fd, Type, InBuffer, IndOp, + LName, AllocedPars); + _ -> + case T of + {void, _} -> + emit(Fd, + " if ((oe_error_code = ei_decode_atom(~s, " + "&oe_env->_iin, 0)) < 0) {\n", + [InBuffer]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"); + {sequence, _, _} -> + %% XXX XXX Why? + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n\n"); + {any, _} -> %% Fix for any type + emit(Fd, + " if ((oe_error_code = ei_decode_long(~s, " + "&oe_env->_iin, ~s~s)) < 0) {\n", + [InBuffer, IndOp, LName]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n\n"), + emit(Fd, " }\n"); + _ -> + ic_error:fatal_error(G, {illegal_typecode_for_c, T, N}) + end + end. + +emit_decoding_stmt_for_basic_type(Fd, Type, InBuffer, IndOp, + LName, AllocedPars) -> + Fmt = + " if ((oe_error_code = ~sei_decode_~s(~s, &oe_env->_iin, " + "~s~s)) < 0) {\n", + Ret = + " return oe_error_code;\n" + "}\n", + + {Pre, DecType} = + case Type of + ushort -> {"", "ulong"}; + ulong -> {"", "ulong"}; + ulonglong -> {"oe_", "ulonglong"}; + short -> {"", "long"}; + long -> {"", "long"}; + longlong -> {"oe_", "longlong"}; + float -> {"", "double"}; + double -> {"", "double"}; + boolean -> {"", "atom"}; + char -> {"", "char"}; + wchar -> {"oe_", "wchar"}; + octet -> {"", "char"}; + any -> {"", "long"} + end, + case Type of + ushort -> + emit(Fd, " {\n"), + emit(Fd, " unsigned long oe_ulong;\n"), + emit(Fd, " if ((oe_error_code = ei_decode_ulong(~s, " + "&oe_env->_iin, &oe_ulong)) < 0) {\n", [InBuffer]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + emit_c_dec_rpt(Fd, " ", "ushort", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"), + emit(Fd, " *~s = (unsigned short) oe_ulong;\n", [LName]), + emit(Fd, " }\n\n"); + short -> + emit(Fd, " {\n"), + emit(Fd, " long oe_long;\n"), + emit(Fd, " if ((oe_error_code = ei_decode_long(~s, " + "&oe_env->_iin, &oe_long)) < 0) {\n", [InBuffer]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + emit_c_dec_rpt(Fd, " ", "short", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"), + emit(Fd, " *~s = (short) oe_long;\n", [LName]), + emit(Fd, " }\n\n"); + float -> + emit(Fd, " {\n"), + emit(Fd, " double oe_double;\n"), + emit(Fd, " if ((oe_error_code = ei_decode_double(~s, " + "&oe_env->_iin, &oe_double)) < 0) {\n", [InBuffer]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + emit_c_dec_rpt(Fd, " ", "float", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"), + emit(Fd, " *~s = (float) oe_double;\n", [LName]), + emit(Fd, " }\n\n"); + boolean -> + emit(Fd, " {\n"), + emit(Fd, " char oe_bool[25];\n\n"), + emit(Fd, " if ((oe_error_code = ei_decode_atom(~s, " + "&oe_env->_iin, oe_bool)) < 0) {\n", [InBuffer]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + emit_c_dec_rpt(Fd, " ", "boolean", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"), + emit(Fd, " if (strcmp(oe_bool, \"false\") == 0) {\n"), + emit(Fd, " *(~s) = 0;\n", [LName]), + emit(Fd, " }\n"), + emit(Fd, " else if (strcmp(oe_bool, \"true\") == 0) {\n"), + emit(Fd, " *(~s) = 1;\n", [LName]), + emit(Fd, " } else {\n"), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + emit_c_dec_rpt(Fd, " ", "boolean", []), + emit(Fd, " return -1;\n"), + emit(Fd, " }\n"), + emit(Fd, " }\n\n"); + _ -> + emit(Fd, Fmt, [Pre, DecType, InBuffer, IndOp, LName]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + emit(Fd, Ret) + end. + + +%%------------------------------------------------------------ +%% Prefix for generic functions +%%------------------------------------------------------------ +get_user_proto(G, Default) -> + case ic_options:get_opt(G, user_protocol) of + false -> + Default; + Pfx -> + Pfx + end. + +%%------------------------------------------------------------ +%% Timeout. Returns a string (or Default). +%%------------------------------------------------------------ +get_c_timeout(G, Default) -> + case ic_options:get_opt(G, c_timeout) of + Tmo when is_integer(Tmo) -> + TmoStr = integer_to_list(Tmo), + {TmoStr, TmoStr}; + {SendTmo, RecvTmo} when is_integer(SendTmo) andalso is_integer(RecvTmo) -> + {integer_to_list(SendTmo), integer_to_list(RecvTmo)}; + false -> + Default + end. + +%%------------------------------------------------------------ +%% ZIPPERS (merging of successive elements of two lists). +%%------------------------------------------------------------ + +%% zip([H1| T1], [H2| T2]) -> +%% [{H1, H2}| zip(T1, T2)]; +%% zip([], []) -> +%% []. + +filterzip(F, [H1| T1], [H2| T2]) -> + case F(H1, H2) of + false -> + filterzip(F, T1, T2); + {true, Val} -> + [Val| filterzip(F, T1, T2)] + end; +filterzip(_, [], []) -> + []. + + -- cgit v1.2.3