1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20%%
21-module(ic_erl_template).
22
23
24-export([do_gen/3, emit_header/3]).
25
26-import(ic_codegen, [emit/2, emit/3, nl/1]).
27
28-include("icforms.hrl").
29-include("ic.hrl").
30
31-include_lib("stdlib/include/erl_compile.hrl").
32
33-define(TAB, "             ").
34-define(TAB2, "%             ").
35
36-define(TEMPLATE_1_A,
37	"%%----------------------------------------------------------------------\n"
38	"%% <LICENSE>\n"
39	"%% \n"
40	"%%     $Id$\n"
41	"%%\n"
42	"%%----------------------------------------------------------------------\n"
43	"%% Module       : ~s.erl\n"
44	"%% \n"
45	"%% Source       : ~s\n"
46	"%% \n"
47	"%% Description  : \n"
48	"%% \n"
49	"%% Creation date: ~s\n"
50	"%%\n"
51	"%%----------------------------------------------------------------------\n"
52	"-module(~p).\n\n").
53
54-define(TEMPLATE_1_B,
55	"%%----------------------------------------------------------------------\n"
56	"%% Internal Exports\n"
57	"%%----------------------------------------------------------------------\n"
58	"-export([init/1,\n"
59	"         terminate/2,\n"
60	"         code_change/3,\n"
61	"         handle_info/2]).\n\n"
62	"%%----------------------------------------------------------------------\n"
63	"%% Include Files\n"
64	"%%----------------------------------------------------------------------\n"
65	"\n\n"
66	"%%----------------------------------------------------------------------\n"
67	"%% Macros\n"
68	"%%----------------------------------------------------------------------\n"
69	"\n\n"
70	"%%----------------------------------------------------------------------\n"
71	"%% Records\n"
72	"%%----------------------------------------------------------------------\n"
73	"-record(state, {}).\n\n"
74	"%%======================================================================\n"
75	"%% API Functions\n"
76	"%%======================================================================\n").
77
78-define(TEMPLATE_1_C,
79	"%%======================================================================\n"
80	"%% Internal Functions\n"
81	"%%======================================================================\n"
82	"%%----------------------------------------------------------------------\n"
83	"%% Function   : init/1\n"
84	"%% Arguments  : Env = term()\n"
85	"%% Returns    : {ok, State}          |\n"
86	"%%              {ok, State, Timeout} |\n"
87	"%%              ignore               |\n"
88	"%%              {stop, Reason}\n"
89	"%% Raises     : -\n"
90	"%% Description: Initiates the server\n"
91	"%%----------------------------------------------------------------------\n"
92	"init(_Env) ->\n"
93	"\t{ok, #state{}}.\n\n\n"
94	"%%----------------------------------------------------------------------\n"
95	"%% Function   : terminate/2\n"
96	"%% Arguments  : Reason = normal | shutdown | term()\n"
97	"%%              State = term()\n"
98	"%% Returns    : ok\n"
99	"%% Raises     : -\n"
100	"%% Description: Invoked when the object is terminating.\n"
101	"%%----------------------------------------------------------------------\n"
102	"terminate(_Reason, _State) ->\n"
103	"\tok.\n\n\n"
104	"%%----------------------------------------------------------------------\n"
105	"%% Function   : code_change/3\n"
106	"%% Arguments  : OldVsn = undefined | term()\n"
107	"%%              State = NewState = term()\n"
108	"%%              Extra = term()\n"
109	"%% Returns    : {ok, NewState}\n"
110	"%% Raises     : -\n"
111	"%% Description: Invoked when the object should update its internal state\n"
112	"%%              due to code replacement.\n"
113	"%%----------------------------------------------------------------------\n"
114	"code_change(_OldVsn, State, _Extra) ->\n"
115	"\t{ok, State}.\n\n\n"
116	"%%----------------------------------------------------------------------\n"
117	"%% Function   : handle_info/2\n"
118	"%% Arguments  : Info = normal | shutdown | term()\n"
119	"%%              State = NewState = term()\n"
120	"%% Returns    : {noreply, NewState}          |\n"
121	"%%              {noreply, NewState, Timeout} |\n"
122	"%%              {stop, Reason, NewState}\n"
123	"%% Raises     : -\n"
124	"%% Description: Invoked when, for example, the server traps exits.\n"
125	"%%----------------------------------------------------------------------\n"
126	"handle_info(_Info, State) ->\n"
127	"\t{noreply, State}.\n\n\n").
128
129-define(TEMPLATE_2_A,
130	"%%% #0.    BASIC INFORMATION\n"
131	"%%% ----------------------------------------------------------------------\n"
132	"%%% %CCaseFile  : ~s.erl %\n"
133	"%%% Author      : \n"
134	"%%% Description : \n"
135	"%%%\n"
136	"%%% Modules used: \n"
137	"%%%\n"
138	"%%%\n"
139	"%%% ----------------------------------------------------------------------\n"
140	"-module(~p).\n"
141	"-author('unknown').\n"
142	"-id('').\n"
143	"-vsn('').\n"
144	"-date('~s').\n\n"
145	"%%% ----------------------------------------------------------------------\n"
146	"%%% Template Id: <ID>\n"
147	"%%%\n"
148	"%%% #Copyright (C) 2004\n"
149	"%%% by <COMPANY>\n"
150	"%%% <ADDRESS>\n"
151	"%%% <OTHER INFORMATION>\n"
152	"%%% \n"
153	"%%% <LICENSE>\n"
154	"%%% \n"
155	"%%% \n"
156	"%%% ----------------------------------------------------------------------\n"
157	"%%% #1.    REVISION LOG\n"
158	"%%% ----------------------------------------------------------------------\n"
159	"%%% Rev      Date       Name        What\n"
160	"%%% -----    -------    --------    --------------------------\n"
161	"%%% \n"
162	"%%% ----------------------------------------------------------------------\n"
163	"%%%\n"
164	"%%% \n"
165	"%%% #2.    EXPORT LISTS\n"
166	"%%% ----------------------------------------------------------------------\n"
167	"%%% #2.1   EXPORTED INTERFACE FUNCTIONS\n"
168	"%%% ----------------------------------------------------------------------\n").
169
170-define(TEMPLATE_2_B,
171	"%%% ----------------------------------------------------------------------\n"
172	"%%% #2.2   EXPORTED INTERNAL FUNCTIONS\n"
173	"%%% ----------------------------------------------------------------------\n"
174	"-export([init/1,\n"
175	"         terminate/2,\n"
176	"         code_change/3,\n"
177	"         handle_info/2]).\n\n"
178	"%%% ----------------------------------------------------------------------\n"
179	"%%% #2.3   INCLUDE FILES\n"
180	"%%% ----------------------------------------------------------------------\n"
181	"\n\n"
182	"%%% ----------------------------------------------------------------------\n"
183	"%%% #2.4   MACROS\n"
184	"%%% ----------------------------------------------------------------------\n"
185	"\n\n"
186	"%%% ----------------------------------------------------------------------\n"
187	"%%% #2.5   RECORDS\n"
188	"%%% ----------------------------------------------------------------------\n"
189	"-record(state, {}).\n\n"
190	"%%% ----------------------------------------------------------------------\n"
191	"%%% #3.    CODE\n"
192	"%%% #---------------------------------------------------------------------\n"
193	"%%% #3.1   CODE FOR EXPORTED INTERFACE FUNCTIONS\n"
194	"%%% #---------------------------------------------------------------------\n").
195
196-define(TEMPLATE_2_C,
197	"%%% ----------------------------------------------------------------------\n"
198	"%%% #3.3   CODE FOR INTERNAL FUNCTIONS\n"
199	"%%% ----------------------------------------------------------------------\n"
200	"%%% ----------------------------------------------------------------------\n"
201	"%%% #   init/1\n"
202	"%%% Input      : Env = term()\n"
203	"%%% Output     : {ok, State}          |\n"
204	"%%%              {ok, State, Timeout} |\n"
205	"%%%              ignore               |\n"
206	"%%%              {stop, Reason}\n"
207	"%%% Exceptions : -\n"
208	"%%% Description: Initiates the server\n"
209	"%%% ----------------------------------------------------------------------\n"
210	"init(_Env) ->\n"
211	"\t{ok, #state{}}.\n\n\n"
212	"%%% ----------------------------------------------------------------------\n"
213	"%%% #   terminate/2\n"
214	"%%% Input      : Reason = normal | shutdown | term()\n"
215	"%%%              State = term()\n"
216	"%%% Output     : ok\n"
217	"%%% Exceptions : -\n"
218	"%%% Description: Invoked when the object is terminating.\n"
219	"%%% ----------------------------------------------------------------------\n"
220	"terminate(_Reason, _State) ->\n"
221	"\tok.\n\n\n"
222	"%%% ----------------------------------------------------------------------\n"
223	"%%% #   code_change/3\n"
224	"%%% Input      : OldVsn = undefined | term()\n"
225	"%%%              State = NewState = term()\n"
226	"%%%              Extra = term()\n"
227	"%%% Output     : {ok, NewState}\n"
228	"%%% Exceptions : -\n"
229	"%%% Description: Invoked when the object should update its internal state\n"
230	"%%%              due to code replacement.\n"
231	"%%% ----------------------------------------------------------------------\n"
232	"code_change(_OldVsn, State, _Extra) ->\n"
233	"\t{ok, State}.\n\n\n"
234	"%%% ----------------------------------------------------------------------\n"
235	"%%% #   handle_info/2\n"
236	"%%% Input      : Info = normal | shutdown | term()\n"
237	"%%%              State = NewState = term()\n"
238	"%%% Output     : {noreply, NewState}          |\n"
239	"%%%              {noreply, NewState, Timeout} |\n"
240	"%%%              {stop, Reason, NewState}\n"
241	"%%% Exceptions : -\n"
242	"%%% Description: Invoked when, for example, the server traps exits.\n"
243	"%%% ----------------------------------------------------------------------\n"
244	"handle_info(_Info, State) ->\n"
245	"\t{noreply, State}.\n\n\n"
246	"%%% ----------------------------------------------------------------------\n"
247	"%%% #4     CODE FOR TEMPORARY CORRECTIONS\n"
248	"%%% ----------------------------------------------------------------------\n\n").
249
250
251%%------------------------------------------------------------
252%%
253%% Generate the client side Erlang stubs.
254%%
255%% Each module is generated to a separate file.
256%%
257%% Export declarations for all interface functions must be
258%% generated. Each function then needs to generate a function head and
259%% a body. IDL parameters must be converted into Erlang parameters
260%% (variables, capitalised) and a type signature list must be
261%% generated (for later encode/decode).
262%%
263%%------------------------------------------------------------
264do_gen(G, _File, Form) ->
265    gen_head(G, [], Form),
266    gen(G, [], Form).
267
268
269gen(G, N, [X|Xs]) when is_record(X, preproc) ->
270    NewG = ic:handle_preproc(G, N, X#preproc.cat, X),
271    gen(NewG, N, Xs);
272gen(G, N, [X|Xs]) when is_record(X, module) ->
273    G2 = ic_file:filename_push(G, N, X, erlang_template_no_gen),
274    N2 = [ic_forms:get_id2(X) | N],
275    gen_head(G2, N2, X),
276    gen(G2, N2, ic_forms:get_body(X)),
277    G3 = ic_file:filename_pop(G2, erlang_template_no_gen),
278    gen(G3, N, Xs);
279gen(G, N, [X|Xs]) when is_record(X, interface) ->
280    G2 = ic_file:filename_push(G, N, X, erlang_template),
281    N2 = [ic_forms:get_id2(X) | N],
282    gen_head(G2, N2, X),
283    gen(G2, N2, ic_forms:get_body(X)),
284    lists:foreach(fun({_Name, Body}) -> gen(G2, N2, Body) end,
285		  X#interface.inherit_body),
286    Fd	= ic_genobj:stubfiled(G2),
287    case get_template_version(G2) of
288	?IC_FLAG_TEMPLATE_2 ->
289	    emit(Fd, ?TEMPLATE_2_C, []);
290	_ ->
291	    emit(Fd, ?TEMPLATE_1_C, [])
292    end,
293    G3 = ic_file:filename_pop(G2, erlang_template),
294    gen(G3, N, Xs);
295gen(G, N, [X|Xs]) when is_record(X, op) ->
296    {Name, InArgNames, OutArgNames, Reply} = extract_info(X),
297    emit_function(G, N, X, ic_genobj:is_stubfile_open(G),
298		   ic_forms:is_oneway(X), Name, InArgNames, OutArgNames, Reply),
299    gen(G, N, Xs);
300gen(G, N, [X|Xs]) when is_record(X, attr) ->
301    emit_attr(G, N, X, ic_genobj:is_stubfile_open(G), fun emit_function/9),
302    gen(G, N, Xs);
303gen(G, N, [_X|Xs]) ->
304    gen(G, N, Xs);
305gen(_G, _N, []) ->
306    ok.
307
308%% Module Header
309emit_header(G, Fd, Name) ->
310    Date = get_date(),
311    case get_template_version(G) of
312	?IC_FLAG_TEMPLATE_2 ->
313	    emit(Fd, ?TEMPLATE_2_A, [Name, list_to_atom(Name), Date]);
314	_ ->
315	    IDLFile = ic_genobj:idlfile(G),
316	    emit(Fd, ?TEMPLATE_1_A, [Name, IDLFile, Date, list_to_atom(Name)])
317    end.
318
319
320emit_attr(G, N, X, Open, F) ->
321    XX = #id_of{type=X},
322    lists:foreach(fun(Id) ->
323			  X2 = XX#id_of{id=Id},
324			  IsOneWay = ic_forms:is_oneway(X2),
325			  {Get, Set} = mk_attr_func_names(N, ic_forms:get_id(Id)),
326			  F(G, N, X2, Open, IsOneWay, Get, [], [],
327			    [{ic_util:mk_var(ic_forms:get_id(Id)),
328			      ic_forms:get_tk(X)}]),
329			  case X#attr.readonly of
330			      {readonly, _} ->
331				  ok;
332			      _ ->
333				  F(G, N, X2, Open, IsOneWay, Set,
334				    [{ic_util:mk_var(ic_forms:get_id(Id)),
335				      ic_forms:get_tk(X)}], [], ["ok"])
336			  end
337		  end, ic_forms:get_idlist(X)).
338
339
340%% The automaticly generated get and set operation names for an
341%% attribute.
342mk_attr_func_names(_Scope, Name) ->
343    {"_get_" ++ Name, "_set_" ++ Name}.
344
345
346extract_info(X) when is_record(X, op) ->
347    Name	= ic_forms:get_id2(X),
348    InArgs	= ic:filter_params([in,inout], X#op.params),
349    OutArgs	= ic:filter_params([out,inout], X#op.params),
350    Reply       = case ic_forms:get_tk(X) of
351		      tk_void ->
352			  ["ok"];
353		      Type ->
354			  [{"OE_Reply", Type}]
355		  end,
356    InArgsTypeList =
357	[{ic_util:mk_var(ic_forms:get_id(InArg#param.id)),
358	  ic_forms:get_tk(InArg)} || InArg <- InArgs ],
359    OutArgsTypeList =
360	[{ic_util:mk_var(ic_forms:get_id(OutArg#param.id)),
361	  ic_forms:get_tk(OutArg)} || OutArg <- OutArgs ],
362    {Name, InArgsTypeList, OutArgsTypeList, Reply}.
363
364get_template_version(G) ->
365    case ic_options:get_opt(G, flags) of
366	Flags when is_integer(Flags) ->
367	    case ?IC_FLAG_TEST(Flags, ?IC_FLAG_TEMPLATE_2) of
368		true ->
369		    ?IC_FLAG_TEMPLATE_2;
370		false ->
371		    ?IC_FLAG_TEMPLATE_1
372	    end;
373	_ ->
374	    ?IC_FLAG_TEMPLATE_1
375    end.
376
377
378get_date() ->
379    {{Y,M,D}, _} = calendar:now_to_datetime(erlang:timestamp()),
380    if
381	M < 10, D < 10 ->
382	    lists:concat([Y, "-0", M, "-0",D]);
383	M < 10 ->
384	    lists:concat([Y, "-0", M, "-", D]);
385	D < 10 ->
386	    lists:concat([Y, "-", M, "-0", D]);
387	true ->
388	    lists:concat([Y, "-", M, "-", D])
389    end.
390
391
392%%------------------------------------------------------------
393%%
394%% Export stuff
395%%
396%%	Gathering of all names that should be exported from a stub
397%%	file.
398%%
399
400
401gen_head_special(G, N, X) when is_record(X, interface) ->
402    Fd = ic_genobj:stubfiled(G),
403    lists:foreach(fun({_Name, Body}) ->
404			  ic_codegen:export(Fd, exp_top(G, N, Body, []))
405		  end, X#interface.inherit_body),
406    nl(Fd),
407    ok;
408gen_head_special(_G, _N, _X) ->
409    ok.
410
411
412%% Generate all export declarations
413gen_head(G, N, X) ->
414    case ic_genobj:is_stubfile_open(G) of
415	true ->
416	    Fd = ic_genobj:stubfiled(G),
417	    ic_codegen:export(Fd, exp_top(G, N, X, [])),
418	    gen_head_special(G, N, X),
419	    case get_template_version(G) of
420		?IC_FLAG_TEMPLATE_2 ->
421		    emit(Fd, ?TEMPLATE_2_B, []);
422		_ ->
423		    emit(Fd, ?TEMPLATE_1_B, [])
424	    end;
425	false ->
426	    ok
427    end.
428
429exp_top(_G, _N, X, Acc)  when element(1, X) == preproc ->
430    Acc;
431exp_top(G, N, L, Acc) when is_list(L) ->
432    exp_list(G, N, L, Acc);
433exp_top(G, N, M, Acc)  when is_record(M, module) ->
434    exp_list(G, N, ic_forms:get_body(M), Acc);
435exp_top(G, N, I, Acc)  when is_record(I, interface) ->
436    exp_list(G, N, ic_forms:get_body(I), Acc);
437exp_top(G, N, X, Acc) ->
438    exp3(G, N, X, Acc).
439
440exp3(G, N, Op, Acc)  when is_record(Op, op) ->
441    FuncName = ic_forms:get_id(Op#op.id),
442    Arity = length(ic:filter_params([in, inout], Op#op.params)) + 1 +
443	count_extras(G, N, Op),
444    [{FuncName, Arity} | Acc];
445exp3(G, N, A, Acc)  when is_record(A, attr) ->
446    Extra = count_extras(G, N, A),
447    lists:foldr(fun(Id, Acc2) ->
448			{Get, Set} = mk_attr_func_names([], ic_forms:get_id(Id)),
449			case A#attr.readonly of
450			    {readonly, _} ->
451				[{Get, 1 + Extra} | Acc2];
452			    _ ->
453				[{Get, 1 + Extra}, {Set, 2 + Extra} | Acc2]
454			end
455		end, Acc, ic_forms:get_idlist(A));
456exp3(_G, _N, _X, Acc) ->
457    Acc.
458
459exp_list(G, N, L, OrigAcc) ->
460    lists:foldr(fun(X, Acc) ->
461			exp3(G, N, X, Acc)
462		end, OrigAcc, L).
463
464count_extras(G, N, Op) ->
465    case {use_this(G, N, Op), use_from(G, N, Op)} of
466	{[], []} ->
467	    0;
468	{[], _} ->
469	    1;
470	{_, []} ->
471	    1;
472	_ ->
473	    2
474    end.
475
476%%------------------------------------------------------------
477%%
478%% Emit stuff
479%%
480%%	Low level generation primitives
481%%
482
483emit_function(_G, _N, _X, false, _, _, _, _, _) ->
484    ok;
485emit_function(G, N, X, true, false, Name, InArgs, OutArgs, Reply) ->
486    Fd = ic_genobj:stubfiled(G),
487    This = use_this(G, N, Name),
488    From = use_from(G, N, Name),
489    State = ["State"],
490    Vers = get_template_version(G),
491    case OutArgs of
492	[] ->
493	    ReplyString = create_string(Reply),
494	    emit_function_header(G, Fd, X, N, Name, create_extra(This, From, Vers),
495				 InArgs, length(InArgs), OutArgs, Reply,
496				 ReplyString, Vers),
497	    emit(Fd, "~p(~s) ->\n\t{reply, ~s, State}.\n\n",
498		 [ic_util:to_atom(Name), create_string(This ++ From ++ State ++ InArgs),
499		  ReplyString]);
500	_ ->
501	    ReplyString = "{" ++ create_string(Reply ++ OutArgs) ++ "}",
502	    emit_function_header(G, Fd, X, N, Name, create_extra(This, From, Vers),
503				 InArgs, length(InArgs), OutArgs, Reply,
504				 ReplyString, Vers),
505	    emit(Fd, "~p(~s) ->\n\t{reply, ~s, State}.\n\n",
506		 [ic_util:to_atom(Name), create_string(This ++ From ++ State ++ InArgs),
507		  ReplyString])
508    end;
509emit_function(G, N, X, true, true, Name, InArgs, _OutArgs, _Reply) ->
510    Fd = ic_genobj:stubfiled(G),
511    This = use_this(G, N, Name),
512    State = ["State"],
513    Vers = get_template_version(G),
514    emit_function_header(G, Fd, X, N, Name, create_extra(This, [], Vers),
515			 InArgs, length(InArgs), "", "", "", Vers),
516    emit(Fd, "~p(~s) ->\n\t{noreply, State}.\n\n",
517	 [ic_util:to_atom(Name), create_string(This ++ State ++ InArgs)]).
518
519create_string([]) ->
520    "";
521create_string([{Name, _Type}|T]) ->
522    Name ++ create_string2(T);
523create_string([Name|T]) ->
524    Name ++ create_string2(T).
525
526create_string2([{Name, _Type}|T]) ->
527    ", " ++ Name ++ create_string2(T);
528create_string2([Name|T]) ->
529    ", " ++ Name ++ create_string2(T);
530create_string2([]) ->
531    "".
532
533create_extra([], [], _Vers) ->
534    {"State - term()", 1};
535create_extra([], _From, ?IC_FLAG_TEMPLATE_2) ->
536    {"OE_From - term()\n%%% " ++ ?TAB ++ "State - term()", 2};
537create_extra([], _From, _Vers) ->
538    {"OE_From - term()\n%% " ++ ?TAB ++ "State - term()", 2};
539create_extra(_This, [], ?IC_FLAG_TEMPLATE_2) ->
540    {"OE_This - #objref{} (i.e., self())\n%%% " ++ ?TAB ++ "State - term()", 2};
541create_extra(_This, [], _Vers) ->
542    {"OE_This - #objref{} (i.e., self())\n%% " ++ ?TAB ++ "State - term()", 2};
543create_extra(_This, _From, ?IC_FLAG_TEMPLATE_2) ->
544    {"OE_This - #objref{} (i.e., self())\n%%% " ++ ?TAB ++
545	"OE_From - term()\n%%% " ++ ?TAB ++ "State - term()", 3};
546create_extra(_This, _From, _Vers) ->
547    {"OE_This - #objref{} (i.e., self())\n%% " ++ ?TAB ++
548	"OE_From - term()\n%% " ++ ?TAB ++ "State - term()", 3}.
549
550use_this(G, N, OpName) ->
551    FullOp = ic_util:to_colon([OpName|N]),
552    FullIntf = ic_util:to_colon(N),
553    case {ic_options:get_opt(G, {this, FullIntf}),
554	  ic_options:get_opt(G, {this, FullOp}),
555	  ic_options:get_opt(G, {this, true})} of
556	{_, force_false, _} ->
557	    [];
558	{force_false, false, _} ->
559	    [];
560	{false, false, false} ->
561	    [];
562	_ ->
563	    ["OE_This"]
564    end.
565
566use_from(G, N, OpName) ->
567    FullOp = ic_util:to_colon([OpName|N]),
568    FullIntf = ic_util:to_colon(N),
569    case {ic_options:get_opt(G, {from, FullIntf}),
570	  ic_options:get_opt(G, {from, FullOp}),
571	  ic_options:get_opt(G, {from, true})} of
572	{_, force_false, _} ->
573	    [];
574	{force_false, false, _} ->
575	    [];
576	{false, false, false} ->
577	    [];
578	_ ->
579	    ["OE_From"]
580    end.
581
582
583emit_function_header(G, Fd, X, N, Name, {Extra, ExtraNo}, InP, Arity, OutP,
584		     Reply, ReplyString, ?IC_FLAG_TEMPLATE_2) ->
585    emit(Fd,
586	 "%%% ----------------------------------------------------------------------\n"
587	 "%%% #   ~p/~p\n"
588	 "%%% Input      : ~s\n",
589	 [ic_util:to_atom(Name), (ExtraNo+Arity), Extra]),
590    ic_code:type_expand_all(G, N, X, Fd, ?TAB2, InP),
591    case Reply of
592	["ok"] ->
593	    emit(Fd, "%%% Output     : ReturnValue = ~s\n", [ReplyString]);
594	_ ->
595	    emit(Fd, "%%% Output     : ReturnValue = ~s\n", [ReplyString]),
596	    ic_code:type_expand_all(G, N, X, Fd, "%             ", Reply)
597    end,
598    ic_code:type_expand_all(G, N, X, Fd, ?TAB2, OutP),
599    emit(Fd,
600	 "%%% Exceptions : ~s\n"
601	 "%%% Description: \n"
602	 "%%% ----------------------------------------------------------------------\n",
603	 [get_raises(X, ?IC_FLAG_TEMPLATE_2)]);
604emit_function_header(G, Fd, X, N, Name, {Extra, ExtraNo}, InP, Arity, OutP,
605		     Reply, ReplyString, Vers) ->
606    emit(Fd,
607	 "%%----------------------------------------------------------------------\n"
608	 "%% Function   : ~p/~p\n"
609	 "%% Arguments  : ~s\n",
610	 [ic_util:to_atom(Name), (ExtraNo+Arity), Extra]),
611    ic_code:type_expand_all(G, N, X, Fd, ?TAB, InP),
612    case Reply of
613	["ok"] ->
614	    emit(Fd, "%% Returns    : ReturnValue = ~s\n", [ReplyString]);
615	_ ->
616	    emit(Fd, "%% Returns    : ReturnValue = ~s\n", [ReplyString]),
617	    ic_code:type_expand_all(G, N, X, Fd, "             ", Reply)
618    end,
619    ic_code:type_expand_all(G, N, X, Fd, ?TAB, OutP),
620    emit(Fd,
621	 "%% Raises     : ~s\n"
622	 "%% Description: \n"
623	 "%%----------------------------------------------------------------------\n",
624	 [get_raises(X, Vers)]).
625
626get_raises(#op{raises = []}, _Vers) ->
627    "";
628get_raises(#op{raises = ExcList}, Vers) ->
629    get_raises2(ExcList, [], Vers);
630get_raises(_X, _Vers) ->
631    [].
632
633get_raises2([H], Acc, _Vers) ->
634    lists:flatten(lists:reverse([ic_util:to_colon(H)|Acc]));
635get_raises2([H|T], Acc, ?IC_FLAG_TEMPLATE_2) ->
636    get_raises2(T, ["\n%%%              ", ic_util:to_colon(H) |Acc],
637		?IC_FLAG_TEMPLATE_2);
638get_raises2([H|T], Acc, _Vers) ->
639    get_raises2(T, ["\n%%              ", ic_util:to_colon(H) |Acc], _Vers).
640
641