aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ic/src/ic_options.erl
blob: d7f56c0d461fdc9a19a34fe479080f2c6cba4e95 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
%%
%% %CopyrightBegin%
%% 
%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
%% 
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%%     http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%% 
%% %CopyrightEnd%
%%
%%

-module(ic_options).

-include_lib("ic/src/ic.hrl").
-include_lib("kernel/include/file.hrl").

%%-----------------------------------------------------------------
%% External exports
%%-----------------------------------------------------------------
-export([defaultBe/0, float_to_version/1, get_opt/2, add_opt/3, 
	 read_cfg/2, which_opts/1, allowed_opt/2]).

%%-----------------------------------------------------------------
%% Internal exports
%%-----------------------------------------------------------------
-export([]).

%%-----------------------------------------------------------------
%% External functions
%%-----------------------------------------------------------------

%%--------------------------------------------------------------------
%%
%% Option handling
%%
%% Valid options are: (those with * is NotYetImpl)
%%
%% pedantic - makes the compiler really nitty-gritty about its input
%%
%% Wall - those warning options that we feel an IDL programmer should
%% care about. Not as picky as pedantic
%%
%% warn_multi_mod - warn if several modules are declared in the same
%% IDL file
%%
%% warn_nested_mod - warn if there are nested modules. This is not a
%% problem but it breakes the rule that modules are put into one file
%% each.
%%
%% warn_name_shadow - warn if identifiers are shadow through inherited
%% interfaces. Default is true.
%%
%% warn_quoted_atom - warn if atoms needs quote, this makes Erlang
%% code less nice but is certainly no error.
%%
%% nowarn - suppress all warning messages. Will still output warnings
%% if silent2 option is used
%%
%% always_outargs - force object server implementation return the
%% tuple {RetVal, OutArgs, NewState} even if there are no OutArgs. If
%% this option is not set then such an operation implementation is
%% assumed to return {RetVal, NewState}
%%
%% use_proc_dict - use the process dictionary in the client
%% stubs. This means that client stubs return RetVal instead of {ok,
%% RetVal, OutArgs} and that corba:get_outargs() returns OutArgs. The
%% out arguments are stored with the key '$corba_outargs'.
%%
%% module_group - use the top module as file name for both skeletons
%% and stubs. Default value is false which means that each interface
%% is put in a separate file.
%%
%% skel_module_group - group all interfaces in a module in one
%% skeleton file as opposed to one skeleton file for each
%% interface. Defaults to false.
%%
%% stub_module_group - group all interface stubs from a module in one
%% stub file as opposed to one stub file for each interface. Default
%% is false.
%%
%% *help - prints a small summary of the compiler usage
%%
%% silent - suppresses all messages from the compiler
%%
%% silent2 - suppresses all messages from the compiler and returns all
%% warnings or errors as lists. Returns {ok, WarnList} or {error,
%% WarnList, ErrList}
%%
%% *noexec - runs the compiler but does not open files or write to
%% files.
%%
%% {serv, <ModName>} - sets the name of the implementation skeleton
%% file. This defaults to ModName_skel.
%%
%% {impl, <ModName>} - sets the name of the interface server
%% implementation module name. This defaults to InterfaceName_impl
%%
%% {outdir, Dir} - use Dir as the directory to put all generated
%% files.
%%
%% {servdir, Dir} - put all generated skel files in the directory Dir.
%%
%% {stubdir, Dir} - put all generated stub files in the directory Dir.
%%
%% {this, InterfaceOrOpName} - puts the OE_THIS parameter into the
%% impl. call. This option can be used both on whole interfaces an on
%% distinct operations. Fullscoped names must be used (as in {this,
%% "M1::I1::Op"}). The option can be given in 3 ways: {this, Name}
%% means this will be added to all matching Name or as {{this, Name},
%% true} or this can explicitly be asked to be left out as in {{this,
%% Name}, false} which enables OE_THIS to be passed to all ops of an
%% interface except those set by the false flag.
%%
%% cfgfile - sets the name of the config file that is read at
%% startup. The order of the different ways to set options is: default
%% setting, configuration file, options given when generator is
%% called. Default name for this file is .ic_config
%%
%% serv_last_call - tells what the last handle_call clause should
%% do. It can have the values exception, which makes the last clause
%% return a CORBA exception and exit which does not generate a last clause
%% (which will make the server crash on an unknown call)
%%
%%
%% -- UNDOCUMENTED --
%%
%% debug - prints debug information
%%
%% tokens - prints the tokens from the tokenizer and then exit
%%
%% form - prints the form from the parser and then exit
%%
%% tform - form returned from type check
%%
%% time - if true then time is measured during compilation
%%
%% 
%%--------------------------------------------------------------------
allowed_opt(default_opts, _V)		-> true;
allowed_opt(debug, V)			-> is_bool(V);
allowed_opt(tokens, V)			-> is_bool(V);
allowed_opt(form, V)			-> is_bool(V);
allowed_opt(tform, V)			-> is_bool(V);
allowed_opt(time, V)			-> is_bool(V);
allowed_opt(maxerrs, V)			-> is_intorinfinity(V);
allowed_opt(maxwarns, V)		-> is_intorinfinity(V);
allowed_opt(nowarn, V)			-> is_bool(V);
allowed_opt(show_opts, V)		-> is_bool(V);

allowed_opt(help, V)			-> is_bool(V);
allowed_opt('Wall', V)			-> is_bool(V);
allowed_opt(warn_multi_mod, V)		-> is_bool(V);
allowed_opt(warn_quoted_atom, V)	-> is_bool(V);
allowed_opt(warn_nested_mod, V)		-> is_bool(V);
allowed_opt(warn_name_shadow, V)	-> is_bool(V);
allowed_opt(module_group, V)		-> is_bool(V);
allowed_opt(skel_module_group, V)	-> is_bool(V);
allowed_opt(stub_module_group, V)	-> is_bool(V);
allowed_opt(always_outargs, V)		-> is_bool(V);
allowed_opt(pedantic, V)		-> is_bool(V);
%%allowed_opt(gen_serv, V)		-> is_bool(V);
%%allowed_opt(gen_stub, V)		-> is_bool(V);
allowed_opt(gen_hrl, V)			-> is_bool(V);
allowed_opt(serv_last_call, exception)	-> true;
allowed_opt(serv_last_call, exit)	-> true;
allowed_opt(silent, V)			-> is_bool(V);
allowed_opt(silent2, V)			-> is_bool(V);
allowed_opt({serv, _}, _V)		-> true;
allowed_opt({impl, _}, _V)		-> true;
allowed_opt(outdir, _V)			-> true;
allowed_opt(servdir, _V)		-> true;
allowed_opt(stubdir, _V)		-> true;
allowed_opt(cfgfile, _V)		-> true;
allowed_opt(use_preproc, V)		-> is_bool(V);
allowed_opt(preproc_cmd, _V)		-> true;
allowed_opt(preproc_flags, _V)		-> true;
allowed_opt(this, _V)			-> true;
allowed_opt({this, _}, V)		-> is_bool(V);
allowed_opt(from, _V)			-> true;
allowed_opt({from, _}, V)		-> is_bool(V);
allowed_opt(handle_info, _V)		-> true;
allowed_opt({handle_info, _}, V)	-> is_bool(V);
allowed_opt(timeout, _V)	        -> true;
allowed_opt({timeout, _}, V)     	-> is_bool(V);
allowed_opt(c_timeout, {V1, V2})	-> is_int(V1) and is_int(V2);
allowed_opt(c_timeout, V)               -> is_int(V);
allowed_opt(c_report, V)             	-> is_bool(V);
allowed_opt(scoped_op_calls, V)         -> is_bool(V);
% Compatibility option (semantic check limitation)
allowed_opt(scl, V)                     -> is_bool(V);
% Added switches for non corba generation
allowed_opt(flags, V)                   -> is_int(V);
allowed_opt(be, erl_corba)	        -> true;
allowed_opt(be, erl_template)	        -> true;
allowed_opt(be, erl_genserv)	        -> true;
allowed_opt(be, c_genserv)		-> true;
allowed_opt(be, erl_plain)		-> true; 
allowed_opt(be, c_server)		-> true;
allowed_opt(be, c_client)		-> true;
allowed_opt(be, java)    		-> true;
% Noc backend
allowed_opt(be, noc)  	                -> true; 
allowed_opt({broker,_},{_,transparent}) -> true; 
allowed_opt({broker,_},{_,Term})  	-> is_term(Term);
allowed_opt({use_tk,_},V)               -> is_bool(V);
%
% Multiple be
allowed_opt(multiple_be, _List)    	-> true;
%
allowed_opt(precond, {_M, _F})          -> true;
allowed_opt({precond, _}, {_M, _F})     -> true;
allowed_opt(postcond, {_M, _F})         -> true;
allowed_opt({postcond, _}, {_M, _F})    -> true;
allowed_opt(no_codechange, V)           -> is_bool(V);
allowed_opt(user_protocol, _V)		-> true;
allowed_opt(light_ifr, V)               -> is_bool(V);
allowed_opt(_, _)			-> false.


-define(DEFAULTCFGFILE, ".ic_config").

which_opts(G) ->
    ets:match(G#genobj.options, {{option, '$1'}, '$2'}).

add_opt(G, KList, Val) when is_list(KList) ->
    lists:foreach(fun({K, V}) -> add_opt(G, K, V);
		  (K) -> add_opt(G, K, Val) end,
		  KList);

add_opt(G, servdir, V) ->
    do_add_opt(G, servdir, assure_directory(G, ic_util:to_list(V)));
add_opt(G, stubdir, V) ->
    do_add_opt(G, stubdir, assure_directory(G, ic_util:to_list(V)));
add_opt(G, K, V) ->
    do_add_opt(G, K, V).


assure_directory(_G, Dir) ->
    Dirs = filename:split(Dir),
    check_dirs(Dirs, [], filename:pathtype(Dir)).
    
check_dirs([X | Xs], SoFar, Type) ->
    New = if  SoFar == [], Type /= absolute ->
		  X;
	      true ->
		  filename:join(SoFar, X)
	  end,
    assert_dir(New),
    check_dirs(Xs, New, Type);
check_dirs([], SoFar, _Type) ->
    SoFar.

assert_dir(D) ->
    case file:read_file_info(D) of
	{ok, X} when X#file_info.type == directory -> ok;
	_ -> case file:make_dir(D) of
		 ok -> ok;
		 _ -> exit({could_not_create, D})
	     end
    end.

do_add_opt(G, handle_info, V) ->
    ?insert(G#genobj.options, {option, {handle_info, V}}, true);
do_add_opt(G, {handle_info, V}, false) ->
    ?insert(G#genobj.options, {option, {handle_info, V}}, force_false);
do_add_opt(G, timeout, V) ->
    ?insert(G#genobj.options, {option, {timeout, V}}, true);
do_add_opt(G, {timeout, V}, false) ->
    ?insert(G#genobj.options, {option, {timeout, V}}, force_false);
do_add_opt(G, this, V) ->
    ?insert(G#genobj.options, {option, {this, V}}, true);
do_add_opt(G, {this, V}, false) ->
    ?insert(G#genobj.options, {option, {this, V}}, force_false);
do_add_opt(G, from, V) ->
    ?insert(G#genobj.options, {option, {from, V}}, true);
do_add_opt(G, {from, V}, false) ->
    ?insert(G#genobj.options, {option, {from, V}}, force_false);
do_add_opt(G, scoped_op_calls, V) when V /= true, V /= false ->
    ?insert(G#genobj.options, {option, {scoped_op_calls, V}}, false);
do_add_opt(G, K, V) ->
    case allowed_opt(K, V) of
	true ->
	    case expand_opt(K) of
		L when is_list(L) ->
		    add_opt(G, L, V);
		_ ->
		    %%io:format("Add opt: ~p ~p~n", [K, V]),
		    ?insert(G#genobj.options, {option, K}, V)
	    end;
	_ ->
	    ic_error:warn(G, {illegal_opt, K})
    end.

get_opt(G, K) ->
    case ets:lookup(G#genobj.options, {option, K}) of
	[] -> false;
	[{{_, K}, V}] -> V
    end.

expand_opt(pedantic) -> [warn_multi_mod, warn_quoted_atom, always_outargs];
expand_opt(module_group) -> [skel_module_group, stub_module_group];
expand_opt('Wall') -> [warn_multi_mod, warn_nested_mod, warn_name_shadow];
expand_opt(outdir) -> [servdir, stubdir];
expand_opt(default_opts) -> 
    ['Wall', gen_hrl, {serv_last_call, exception},
     {outdir, []}, use_preproc, {preproc_cmd, "erl"}, 
     {preproc_flags, ""}, {maxerrs, 10}, {maxwarns, infinity}];
%% gcc preproc command {preproc_cmd, "gcc -x c++ -E"}
expand_opt(Opt) -> Opt.


%% Use this if user not provide 
%% a backend.
defaultBe() -> erl_corba.
    

%%
%% Read any config file
read_cfg(G, Opts) ->
    Name = case lists:keysearch(cfgfile, 1, Opts) of
	       {value, {_, N}} -> ic_util:to_list(N);
	       _ -> ?DEFAULTCFGFILE
	   end,
    case file:consult(Name) of
	{ok, OptList} ->
	    add_opt(G, OptList, true);
	_X when Name == ?DEFAULTCFGFILE -> ok;
%%	{error, X} ->
%%	    ic_error:warn(G, {cfg_open, X, Name});
	X -> ic_error:warn(G, {cfg_open, X, Name})
    end.


float_to_version({_,_,Str}) -> Str.


%%-----------------------------------------------------------------
%% Internal functions
%%-----------------------------------------------------------------
is_bool(true) -> true;
is_bool(false) -> true;
is_bool(_) -> false.

is_int(V) when is_integer(V) -> true;
is_int(_) -> false.

is_intorinfinity(X) when is_integer(X) -> true;
is_intorinfinity(infinity) -> true;
is_intorinfinity(_X) -> false.


is_term(Term) when is_tuple(Term) -> true;
is_term(_NoTerm) -> false.