ic_cclient.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,213 行 · 第 1/3 页
ERL
1,213 行
%% ``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 via the world wide web 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.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id$%%-module(ic_cclient).%% This module implements generation of C client code, where the%% client acts as an Erlang C-node, and where the communication thus%% is according to the Erlang distribution protocol.%%%% TODO:%% 1. ic_cbe:extract_info/3 is a silly name. %% 2. ParList, ParTypes, TypeList etc. what are they?%% 3. Zip is merging two lists (of the same length).%%-export([do_gen/3]).%%------------------------------------------------------------%% IMPLEMENTATION CONVENTIONS%%------------------------------------------------------------%% Functions:%%%% mk_* returns things to be used. No side effects.%% emit_* Writes to file. Has Fd in arguments.%% gen_* Same, but has no Fd. Usually for larger things.%%%% Terminology for generating C:%%%% par_list list of identifiers with types, types only, or with %% parameters (arguments) only. %% arg_list list of identifiers only (for function calls)%%%%------------------------------------------------------------%% Internal stuff%%-------------------------------------------------------------import(lists, [foreach/2, foldl/3, foldr/3]).-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(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), gen_headers(G2, [], Form), R = gen(G2, [], Form), ic_file:filename_pop(G2, c), R.remove_ext(File) -> filename:rootname(filename:basename(File)).%%------------------------------------------------------------%%%% Generate client side C stubs. %%%% - each module definition results in a separate file.%% - each interface definition results in a separate file.%%%% G = record(genobj) (see ic.hrl)%% N = scoped names in reverse%% X = current form to consider. %%------------------------------------------------------------gen(G, N, [X| Xs]) when record(X, preproc) -> G1 = change_file_stack(G, N, X), gen(G1, N, Xs);gen(G, N, [X| Xs]) when 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 record(X, interface) -> G2 = ic_file:filename_push(G, N, X, c), N2 = [ic_forms:get_id2(X)| N], %% Sets the temporary variable counter. put(op_variable_count, 0), put(tmp_declarations, []), gen_headers(G2, N2, X), gen(G2, N2, ic_forms:get_body(X)), lists:foreach( fun({_Name, Body}) -> gen(G2, N2, Body) end, X#interface.inherit_body), %% Generate Prototypes gen_prototypes(G2, N2, X), %% Generate generic preparation for decoding gen_receive_info(G2, N2, X), G3 = ic_file:filename_pop(G2, c), gen(G3, N, Xs);gen(G, N, [X| Xs]) when record(X, const) -> emit_constant(G, N, X), gen(G, N, Xs);gen(G, N, [X| Xs]) when record(X, op) -> {OpName, ArgNames, RetParTypes} = ic_cbe:extract_info(G, N, X), %% XXX Note: N is the list of scoped ids of the *interface*. gen_operation(G, N, X, OpName, ArgNames, RetParTypes), gen_encoder(G, N, X, OpName, ArgNames, RetParTypes), gen_decoder(G, N, X, OpName, ArgNames, RetParTypes), gen(G, N, Xs);gen(G, N, [X| Xs]) when record(X, attr) -> gen(G, N, Xs);gen(G, N, [X| Xs]) when record(X, except) -> icstruct:except_gen(G, N, X, c), gen(G, N, Xs);gen(G, N, [X| Xs]) when record(X, enum) -> icenum:enum_gen(G, N, X, c), gen(G, N, Xs);gen(G, N, [X| Xs]) when record(X, typedef) -> icstruct:struct_gen(G, N, X, c), gen(G, N, Xs);gen(G, N, [X| Xs]) when record(X, struct) -> icstruct:struct_gen(G, N, X, c), gen(G, N, Xs);gen(G, N, [X| Xs]) when record(X, union) -> icstruct:struct_gen(G, N, X, c), gen(G, N, Xs);gen(G, N, [_X| Xs]) -> %% XXX Should have debug message here. gen(G, N, Xs);gen(_G, _N, []) -> ok.%%------------------------------------------------------------%% Change file stack%%------------------------------------------------------------change_file_stack(G, _N, X) when X#preproc.cat == line_nr -> 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, _X) -> G.%%------------------------------------------------------------%% Generate headers in stubfiles and header files %%------------------------------------------------------------gen_headers(G, N, X) when record(X, interface) -> case ic_genobj:is_hrlfile_open(G) of true -> %% Set the temporary variable counter put(op_variable_count, 0), put(tmp_declarations, []), 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, emit(HFd, "#include \"~s\"\n", [filename:basename(Filename)]), ic_code:gen_includes(HFd, G, X, c_client), IfName = ic_util:to_undersc(N), IfNameUC = ic_util:to_uppercase(IfName), emit(HFd, "\n#ifndef __~s__\n", [IfNameUC]), emit(HFd, "#define __~s__\n", [IfNameUC]), LCmt = io_lib:format("Interface object definition: ~s", [IfName]), ic_codegen:mcomment_light(HFd, [LCmt], c), case get_c_timeout(G, "") of "" -> ok; {SendTmo, RecvTmo} -> emit(HFd, "#define OE_~s_SEND_TIMEOUT ~s\n", [IfNameUC, SendTmo]), emit(HFd, "#define OE_~s_RECV_TIMEOUT ~s\n", [IfNameUC, 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", [IfName]), emit(HFd, "#endif\n\n"); false -> ok end, case ic_genobj:is_stubfile_open(G) of true -> Fd = ic_genobj:stubfiled(G), ic_codegen:nl(Fd), emit(Fd, "#include <stdlib.h>\n"), emit(Fd, "#include <string.h>\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 <stdio.h>\n"), emit(Fd, "#endif\n"); _ -> ok end, emit(Fd, "#include \"~s\"\n", [?IC_HEADER]), emit(Fd, "#include \"~s\"\n", [?ERL_INTERFACEHEADER]), emit(Fd, "#include \"~s\"\n", [?EICONVHEADER]), emit(Fd, "#include \"~s\"\n", [filename:basename(ic_genobj:include_file(G))]), ic_codegen:nl(Fd), ic_codegen:nl(Fd), Fd; % XXX ?? false -> ok end;%% Some items have extra includesgen_headers(G, N, X) when 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_client); false -> ok end;gen_headers(G, [], _X) -> case ic_genobj:is_hrlfile_open(G) of true -> HFd = ic_genobj:hrlfiled(G), 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 <stdio.h>\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_client); false -> ok end;gen_headers(_G, _N, _X) -> ok.%%------------------------------------------------------------%% Generate all prototypes (for interface)%%------------------------------------------------------------gen_prototypes(G, N, X) -> case ic_genobj:is_hrlfile_open(G) of false -> ok; true -> HFd = ic_genobj:hrlfiled(G), IfName = ic_util:to_undersc(N), %% Emit generated function prototypes emit(HFd, "\n/* Operation functions */\n"), lists:foreach(fun({_Name, Body}) -> emit_operation_prototypes(G, HFd, N, Body) end, [{x, ic_forms:get_body(X)}| X#interface.inherit_body]), UserProto = get_user_proto(G, false), %% Emit generic function prototypes case UserProto of false -> ok; UserProto -> emit(HFd, "\n/* Generic user defined encoders */\n"), emit(HFd, "int ~s_prepare_notification_encoding(" "CORBA_Environment*);" "\n", [UserProto]), emit(HFd, "int ~s_prepare_request_encoding(CORBA_Environment*);" "\n", [UserProto]) end, %% Emit encoding function prototypes emit(HFd, "\n/* Input encoders */\n"), lists:foreach(fun({_Name, Body}) -> emit_encoder_prototypes(G, HFd, N, Body) end, [{x, ic_forms:get_body(X)}| X#interface.inherit_body]), %% Emit generic function prototypes emit(HFd, "\n/* Generic decoders */\n"), emit(HFd, "int ~s__receive_info(~s, CORBA_Environment*);\n", [IfName, IfName]), case UserProto of false -> ok; UserProto -> emit(HFd, "\n/* Generic user defined decoders */\n"), emit(HFd, "int ~s_prepare_reply_decoding(CORBA_Environment*);" "\n", [UserProto]) end, %% Emit decode function prototypes emit(HFd, "\n/* Result decoders */\n"), lists:foreach(fun({_Name, Body}) -> emit_decoder_prototypes(G, HFd, N, Body) end, [{x, ic_forms:get_body(X)}| X#interface.inherit_body]), case UserProto of false -> ok; UserProto -> %% Emit generic send and receive_prototypes {Sfx, TmoType} = case get_c_timeout(G, "") of "" -> {"", ""}; _ -> {"_tmo", ", unsigned int"} end, emit(HFd, "\n/* Generic user defined send and receive " "functions */\n"), emit(HFd, "int ~s_send_notification~s(CORBA_Environment*~s);\n", [UserProto, Sfx, TmoType]), emit(HFd, "int ~s_send_request_and_receive_reply~s(" "CORBA_Environment*~s~s);\n", [UserProto, Sfx, TmoType, TmoType]) end end.%%------------------------------------------------------------%% Generate receive_info() (generic part for message reception) %% (for interface). For backward compatibility only.%%------------------------------------------------------------gen_receive_info(G, N, _X) -> case ic_genobj:is_stubfile_open(G) of false -> ok; true -> Fd = ic_genobj:stubfiled(G), IfName = ic_util:to_undersc(N), UserProto = get_user_proto(G, oe), Code = "
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?