1%% vim: tabstop=8:shiftwidth=4
2%%
3%% %CopyrightBegin%
4%%
5%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
6%%
7%% Licensed under the Apache License, Version 2.0 (the "License");
8%% you may not use this file except in compliance with the License.
9%% You may obtain a copy of the License at
10%%
11%%     http://www.apache.org/licenses/LICENSE-2.0
12%%
13%% Unless required by applicable law or agreed to in writing, software
14%% distributed under the License is distributed on an "AS IS" BASIS,
15%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16%% See the License for the specific language governing permissions and
17%% limitations under the License.
18%%
19%% %CopyrightEnd%
20%%
21%%
22-module(asn1ct).
23
24%% Compile Time functions for ASN.1 (e.g ASN.1 compiler).
25
26%% Public exports
27-export([compile/1, compile/2]).
28-export([test/1, test/2, test/3, value/2, value/3]).
29
30%% Application internal exports
31-export([compile_asn/3,compile_asn1/3,compile_py/3,compile/3,
32	 vsn/0,
33	 get_name_of_def/1,get_pos_of_def/1,
34	 unset_pos_mod/1]).
35-export([read_config_data/1,get_gen_state_field/1,
36	 partial_inc_dec_toptype/1,update_gen_state/2,
37	 get_tobe_refed_func/1,reset_gen_state/0,is_function_generated/1,
38	 generated_refed_func/1,next_refed_func/0,
39	 update_namelist/1,step_in_constructed/0,
40	 add_tobe_refed_func/1,add_generated_refed_func/1,
41	 maybe_rename_function/3,current_sindex/0,
42	 set_current_sindex/1,maybe_saved_sindex/2,
43	 parse_and_save/2,verbose/3,warning/3,warning/4,error/3,format_error/1]).
44-export([get_bit_string_format/0,use_legacy_types/0]).
45
46-include("asn1_records.hrl").
47-include_lib("stdlib/include/erl_compile.hrl").
48-include_lib("kernel/include/file.hrl").
49
50-import(asn1ct_gen_ber_bin_v2,[encode_tag_val/3,decode_class/1]).
51
52-ifndef(vsn).
53-define(vsn,"0.0.1").
54-endif.
55
56-define(unique_names,0).
57-define(dupl_uniquedefs,1).
58-define(dupl_equaldefs,2).
59-define(dupl_eqdefs_uniquedefs,?dupl_equaldefs bor ?dupl_uniquedefs).
60
61-define(CONSTRUCTED, 2#00100000).
62
63%% macros used for partial decode commands
64-define(CHOOSEN,choosen).
65-define(SKIP,skip).
66-define(SKIP_OPTIONAL,skip_optional).
67
68%% macros used for partial incomplete decode commands
69-define(MANDATORY,mandatory).
70-define(DEFAULT,default).
71-define(OPTIONAL,opt).
72-define(OPTIONAL_UNDECODED,opt_undec).
73-define(PARTS,parts).
74-define(UNDECODED,undec).
75-define(ALTERNATIVE,alt).
76-define(ALTERNATIVE_UNDECODED,alt_undec).
77-define(ALTERNATIVE_PARTS,alt_parts).
78
79%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80%% This is the interface to the compiler
81
82compile(File) ->
83    compile(File,[]).
84
85compile(File, Options0) when is_list(Options0) ->
86    try translate_options(Options0) of
87	Options1 ->
88	    Options2 = includes(File,Options1),
89	    Includes = strip_includes(Options2),
90	    in_process(fun() -> compile_proc(File, Includes, Options2) end)
91    catch throw:Error ->
92	    Error
93    end.
94
95-record(st,
96	{file=[],
97	 files=[],
98	 inputmodules=[],
99	 code,
100	 opts=[],
101	 outfile,
102	 dbfile,
103	 includes=[],
104	 erule,
105	 error=none,
106	 run
107	}).
108
109compile_proc(File, Includes, Options) ->
110    Erule = get_rule(Options),
111    St = #st{opts=Options,includes=Includes,erule=Erule},
112    case input_file_type(File, Includes) of
113        {single_file, SuffixedFile} -> %% "e.g. "/tmp/File.asn"
114            compile1(SuffixedFile, St);
115        {multiple_files_file, SetBase, FileName} ->
116            case get_file_list(FileName, Includes) of
117                FileList when is_list(FileList) ->
118                    compile_set(SetBase, FileList, St);
119                Err ->
120                    Err
121            end;
122        Err = {input_file_error, _Reason} ->
123            {error, Err}
124    end.
125
126set_passes() ->
127    [{pass,scan_parse,fun set_scan_parse_pass/1},
128     {pass,merge,fun merge_pass/1}|common_passes()].
129
130single_passes() ->
131    [{pass,scan,fun scan_pass/1},
132     {pass,parse,fun parse_pass/1}|common_passes()].
133
134parse_and_save_passes() ->
135    [{pass,scan,fun scan_pass/1},
136     {pass,parse,fun parse_pass/1},
137     {pass,save,fun save_pass/1}].
138
139common_passes() ->
140    [{iff,parse,{pass,parse_listing,fun parse_listing/1}},
141     {pass,check,fun check_pass/1},
142     {iff,abs,{pass,abs_listing,fun abs_listing/1}},
143     {pass,generate,fun generate_pass/1},
144     {unless,noobj,{pass,compile,fun compile_pass/1}}].
145
146scan_pass(#st{file=File}=St) ->
147    case asn1ct_tok:file(File) of
148	{error,Reason} ->
149	    {error,St#st{error=Reason}};
150	Tokens when is_list(Tokens) ->
151	    {ok,St#st{code=Tokens}}
152    end.
153
154set_scan_parse_pass(#st{files=Files}=St) ->
155    try
156	L = set_scan_parse_pass_1(Files, St),
157	{ok,St#st{code=L}}
158    catch
159	throw:Error ->
160	    {error,St#st{error=Error}}
161    end.
162
163set_scan_parse_pass_1([F|Fs], #st{file=File}=St) ->
164    case asn1ct_tok:file(F) of
165	{error,Error} ->
166	    throw(Error);
167	Tokens when is_list(Tokens) ->
168	    case asn1ct_parser2:parse(File, Tokens) of
169		{ok,M} ->
170		    [M|set_scan_parse_pass_1(Fs, St)];
171		{error,Errors} ->
172		    throw(Errors)
173	    end
174    end;
175set_scan_parse_pass_1([], _) -> [].
176
177parse_pass(#st{file=File,code=Tokens}=St) ->
178    case asn1ct_parser2:parse(File, Tokens) of
179	{ok,M} ->
180	    {ok,St#st{code=M}};
181	{error,Errors} ->
182	    {error,St#st{error=Errors}}
183    end.
184
185merge_pass(#st{file=Base,code=Code}=St) ->
186    M = merge_modules(Code, Base),
187    {ok,St#st{code=M}}.
188
189check_pass(#st{code=M,file=File,includes=Includes,
190	       erule=Erule,dbfile=DbFile,opts=Opts,
191	       inputmodules=InputModules}=St) ->
192    start(Includes),
193    case asn1ct_check:storeindb(#state{erule=Erule,options=Opts}, M) of
194	ok ->
195	    Module = asn1_db:dbget(M#module.name, 'MODULE'),
196	    State = #state{mname=Module#module.name,
197			   module=Module#module{typeorval=[]},
198			   erule=Erule,
199			   inputmodules=InputModules,
200			   options=Opts,
201			   sourcedir=filename:dirname(File)},
202	    case asn1ct_check:check(State, Module#module.typeorval) of
203		{error,Reason} ->
204		    {error,St#st{error=Reason}};
205		{ok,NewTypeOrVal,GenTypeOrVal} ->
206		    NewM = Module#module{typeorval=NewTypeOrVal},
207		    asn1_db:dbput(NewM#module.name, 'MODULE', NewM),
208		    asn1_db:dbsave(DbFile, M#module.name),
209		    verbose("--~p--~n", [{generated,DbFile}], Opts),
210		    {ok,St#st{code={M,GenTypeOrVal}}}
211	    end;
212	{error,Reason} ->
213	    {error,St#st{error=Reason}}
214    end.
215
216save_pass(#st{code=M,erule=Erule,opts=Opts}=St) ->
217    ok = asn1ct_check:storeindb(#state{erule=Erule,options=Opts}, M),
218    {ok,St}.
219
220parse_listing(#st{code=Code,outfile=OutFile0}=St) ->
221    OutFile = OutFile0 ++ ".parse",
222    case file:write_file(OutFile, io_lib:format("~p\n", [Code])) of
223	ok ->
224	    done;
225	{error,Reason} ->
226	    Error = {write_error,OutFile,Reason},
227	    {error,St#st{error=[{structured_error,{OutFile0,none},?MODULE,Error}]}}
228    end.
229
230abs_listing(#st{code={M,_},outfile=OutFile}) ->
231    pretty2(M#module.name, OutFile++".abs"),
232    done.
233
234generate_pass(#st{code=Code,outfile=OutFile,erule=Erule,opts=Opts}=St0) ->
235    St = St0#st{code=undefined},		%Reclaim heap space
236    generate(Code, OutFile, Erule, Opts),
237    {ok,St}.
238
239compile_pass(#st{outfile=OutFile,opts=Opts0}=St) ->
240    asn1_db:dbstop(),				%Reclaim memory.
241    asn1ct_table:delete([renamed_defs,original_imports,automatic_tags]),
242    Opts = remove_asn_flags(Opts0),
243    case c:c(OutFile, Opts) of
244	{ok,_Module} ->
245	    {ok,St};
246	_ ->
247	    {error,St}
248    end.
249
250run_passes(Passes, #st{opts=Opts}=St) ->
251    Run = case lists:member(time, Opts) of
252	      false ->
253		  fun(_, Pass, S) -> Pass(S) end;
254	      true ->
255		  fun run_tc/3
256	  end,
257    run_passes_1(Passes, St#st{run=Run}).
258
259run_tc(Name, Fun, St) ->
260    Before0 = statistics(runtime),
261    Val = (catch Fun(St)),
262    After0 = statistics(runtime),
263    {Before_c, _} = Before0,
264    {After_c, _} = After0,
265    io:format("~-31s: ~10.2f s\n",
266	      [Name,(After_c-Before_c) / 1000]),
267    Val.
268
269run_passes_1([{unless,Opt,Pass}|Passes], #st{opts=Opts}=St) ->
270    case proplists:get_bool(Opt, Opts) of
271	false ->
272	    run_passes_1([Pass|Passes], St);
273	true ->
274	    run_passes_1(Passes, St)
275    end;
276run_passes_1([{iff,Opt,Pass}|Passes], #st{opts=Opts}=St) ->
277    case proplists:get_bool(Opt, Opts) of
278	true ->
279	    run_passes_1([Pass|Passes], St);
280	false ->
281	    run_passes_1(Passes, St)
282    end;
283run_passes_1([{pass,Name,Pass}|Passes], #st{run=Run}=St0)
284  when is_function(Pass, 1) ->
285    try Run(Name, Pass, St0) of
286	{ok,St} ->
287	    run_passes_1(Passes, St);
288	{error,#st{error=Errors}} ->
289	    {Structured,AllErrors} = clean_errors(Errors),
290	    print_structured_errors(Structured),
291	    {error,AllErrors};
292	done ->
293	    ok
294    catch
295	Class:Error:Stk ->
296	    io:format("Internal error: ~p:~p\n~p\n",
297		      [Class,Error,Stk]),
298	    {error,{internal_error,{Class,Error}}}
299    end;
300run_passes_1([], _St) ->
301    ok.
302
303clean_errors(Errors) when is_list(Errors) ->
304    F = fun({structured_error,_,_,_}) -> true;
305	   (_) -> false
306	end,
307    {Structured0,AdHoc} = lists:partition(F, Errors),
308    Structured = lists:sort(Structured0),
309    {Structured,Structured ++ AdHoc};
310clean_errors(AdHoc) -> {[],AdHoc}.
311
312print_structured_errors([_|_]=Errors) ->
313    _ = [io:format("~ts:~w: ~ts\n", [F,L,M:format_error(E)]) ||
314	    {structured_error,{F,L},M,E} <- Errors],
315    ok;
316print_structured_errors(_) -> ok.
317
318compile1(File, #st{opts=Opts}=St0) ->
319    compiler_verbose(File, Opts),
320    Passes = single_passes(),
321    Base = filename:rootname(filename:basename(File)),
322    OutFile = outfile(Base, "", Opts),
323    DbFile = outfile(Base, "asn1db", Opts),
324    St1 = St0#st{file=File,outfile=OutFile,dbfile=DbFile},
325    run_passes(Passes, St1).
326
327%%****************************************************************************%%
328%% functions dealing with compiling of several input files to one output file %%
329%%****************************************************************************%%
330
331%% compile_set/3 merges and compiles a number of asn1 modules
332%% specified in a .set.asn file to one .erl file.
333compile_set(SetBase, Files, #st{opts=Opts}=St0) ->
334    compiler_verbose(Files, Opts),
335    OutFile = outfile(SetBase, "", Opts),
336    DbFile = outfile(SetBase, "asn1db", Opts),
337    InputModules = [begin
338			F1 = filename:basename(F0),
339			F = filename:rootname(F1),
340			list_to_atom(F)
341		    end || F0 <- Files],
342    St = St0#st{file=SetBase,files=Files,outfile=OutFile,
343		dbfile=DbFile,inputmodules=InputModules},
344    Passes = set_passes(),
345    run_passes(Passes, St).
346
347compiler_verbose(What, Opts) ->
348    verbose("Erlang ASN.1 compiler ~s\n", [?vsn], Opts),
349    verbose("Compiling: ~p\n", [What], Opts),
350    verbose("Options: ~p\n", [Opts], Opts).
351
352%% merge_modules/2 -> returns a module record where the typeorval lists are merged,
353%% the exports lists are merged, the imports lists are merged when the
354%% elements come from other modules than the merge set, the tagdefault
355%% field gets the shared value if all modules have same tagging scheme,
356%% otherwise a tagging_error exception is thrown,
357%% the extensiondefault ...(not handled yet).
358merge_modules(ModuleList, CommonName) ->
359    NewModuleList = remove_name_collisions(ModuleList),
360    case asn1ct_table:size(renamed_defs) of
361        0 -> asn1ct_table:delete(renamed_defs);
362        _ -> ok
363    end,
364    save_imports(NewModuleList),
365    TypeOrVal = lists:append(lists:map(fun(X)->X#module.typeorval end,
366				       NewModuleList)),
367    InputMNameList = lists:map(fun(X)->X#module.name end,
368			       NewModuleList),
369    CExports = common_exports(NewModuleList),
370
371    ImportsModuleNameList = lists:map(fun(X)->
372					      {X#module.imports,
373					       X#module.name} end,
374				      NewModuleList),
375    %% ImportsModuleNameList: [{Imports,ModuleName},...]
376    %% Imports is a tuple {imports,[#'SymbolsFromModule'{},...]}
377    CImports = common_imports(ImportsModuleNameList,InputMNameList),
378    TagDefault = check_tagdefault(NewModuleList),
379    #module{name=CommonName,tagdefault=TagDefault,exports=CExports,
380	    imports=CImports,typeorval=TypeOrVal}.
381
382%% causes an exit if duplicate definition names exist in a module
383remove_name_collisions(Modules) ->
384    asn1ct_table:new(renamed_defs),
385    %% Name duplicates in the same module is not allowed.
386    lists:foreach(fun exit_if_nameduplicate/1,Modules),
387    %% Then remove duplicates in different modules and return the
388    %% new list of modules.
389    remove_name_collisions2(Modules,[]).
390
391%% For each definition in the first module in module list, find
392%% all definitons with same name and rename both definitions in
393%% the first module and in rest of modules
394remove_name_collisions2([M|Ms],Acc) ->
395    TypeOrVal = M#module.typeorval,
396    MName = M#module.name,
397    %% Test each name in TypeOrVal on all modules in Ms
398    {NewM,NewMs} = remove_name_collisions2(MName,TypeOrVal,Ms,[]),
399    remove_name_collisions2(NewMs,[M#module{typeorval=NewM}|Acc]);
400remove_name_collisions2([],Acc) ->
401    finished_warn_prints(),
402    Acc.
403
404%% For each definition in list of defs find definitions in (rest of)
405%% modules that have same name. If duplicate was found rename def.
406%% Test each name in [T|Ts] on all modules in Ms
407remove_name_collisions2(ModName,[T|Ts],Ms,Acc) ->
408    Name = get_name_of_def(T),
409    case discover_dupl_in_mods(Name,T,Ms,[],?unique_names) of
410	{_,?unique_names} -> % there was no name collision
411	    remove_name_collisions2(ModName,Ts,Ms,[T|Acc]);
412	{NewMs,?dupl_uniquedefs} -> % renamed defs in NewMs
413	    %% rename T
414	    NewT = set_name_of_def(ModName,Name,T), %rename def
415	    warn_renamed_def(ModName,get_name_of_def(NewT),Name),
416	    asn1ct_table:insert(renamed_defs,
417	                        {get_name_of_def(NewT), Name, ModName}),
418	    remove_name_collisions2(ModName,Ts,NewMs,[NewT|Acc]);
419	{NewMs,?dupl_equaldefs} -> % name duplicates, but identical defs
420	    %% keep name of T
421	    warn_kept_def(ModName,Name),
422	    remove_name_collisions2(ModName,Ts,NewMs,[T|Acc]);
423	{NewMs,?dupl_eqdefs_uniquedefs} ->
424	    %% keep name of T, renamed defs in NewMs
425	    warn_kept_def(ModName,Name),
426	    remove_name_collisions2(ModName,Ts,NewMs,[T|Acc])
427    end;
428remove_name_collisions2(_,[],Ms,Acc) ->
429    {Acc,Ms}.
430
431%% Name is the name of a definition. If a definition with the same name
432%% is found in the modules Ms the definition will be renamed and returned.
433discover_dupl_in_mods(Name,Def,[M=#module{name=N,typeorval=TorV}|Ms],
434			      Acc,AnyRenamed) ->
435    Fun = fun(T,RenamedOrDupl)->
436		  case {get_name_of_def(T),compare_defs(Def,T)} of
437		      {Name,not_equal} ->
438			  %% rename def
439			  NewT=set_name_of_def(N,Name,T),
440			  warn_renamed_def(N,get_name_of_def(NewT),Name),
441			  asn1ct_table:insert(renamed_defs,
442						          {get_name_of_def(NewT), Name, N}),
443			  {NewT,?dupl_uniquedefs bor RenamedOrDupl};
444		      {Name,equal} ->
445			  %% delete def
446			  warn_deleted_def(N,Name),
447			  {[],?dupl_equaldefs bor RenamedOrDupl};
448		      _ ->
449			  {T,RenamedOrDupl}
450		  end
451	  end,
452    {NewTorV,NewAnyRenamed} = lists:mapfoldl(Fun,AnyRenamed,TorV),
453    %% have to flatten the NewTorV to remove any empty list elements
454    discover_dupl_in_mods(Name,Def,Ms,
455			  [M#module{typeorval=lists:flatten(NewTorV)}|Acc],
456			  NewAnyRenamed);
457discover_dupl_in_mods(_,_,[],Acc,AnyRenamed) ->
458    {Acc,AnyRenamed}.
459
460warn_renamed_def(ModName,NewName,OldName) ->
461    maybe_first_warn_print(),
462    io:format("NOTICE: The ASN.1 definition in module ~p with name ~p has been renamed in generated module. New name is ~p.~n",[ModName,OldName,NewName]).
463
464warn_deleted_def(ModName,DefName) ->
465    maybe_first_warn_print(),
466    io:format("NOTICE: The ASN.1 definition in module ~p with name ~p has been deleted in generated module.~n",[ModName,DefName]).
467
468warn_kept_def(ModName,DefName) ->
469    maybe_first_warn_print(),
470    io:format("NOTICE: The ASN.1 definition in module ~p with name ~p has kept its name due to equal definition as duplicate.~n",[ModName,DefName]).
471
472maybe_first_warn_print() ->
473    case get(warn_duplicate_defs) of
474	undefined ->
475	    put(warn_duplicate_defs,true),
476	    io:format("~nDue to multiple occurrences of a definition name in "
477		      "multi-file compiled files:~n");
478	_ ->
479	    ok
480    end.
481finished_warn_prints() ->
482    put(warn_duplicate_defs,undefined).
483
484
485exit_if_nameduplicate(#module{typeorval=TorV}) ->
486    exit_if_nameduplicate(TorV);
487exit_if_nameduplicate([]) ->
488    ok;
489exit_if_nameduplicate([Def|Rest]) ->
490    Name=get_name_of_def(Def),
491    exit_if_nameduplicate2(Name,Rest),
492    exit_if_nameduplicate(Rest).
493
494exit_if_nameduplicate2(Name,Rest) ->
495    Pred=fun(Def)->
496		 case get_name_of_def(Def) of
497		     Name -> true;
498		     _ -> false
499		 end
500	 end,
501        case lists:any(Pred,Rest) of
502	true ->
503	    throw({error,{"more than one definition with same name",Name}});
504	_ ->
505	    ok
506    end.
507
508compare_defs(D1,D2) ->
509    compare_defs2(unset_pos_mod(D1),unset_pos_mod(D2)).
510compare_defs2(D,D) ->
511    equal;
512compare_defs2(_,_) ->
513    not_equal.
514
515unset_pos_mod(Def) when is_record(Def,typedef) ->
516    Def#typedef{pos=undefined};
517unset_pos_mod(Def) when is_record(Def,classdef) ->
518    Def#classdef{pos=undefined};
519unset_pos_mod(Def) when is_record(Def,valuedef) ->
520    Def#valuedef{pos=undefined,module=undefined};
521unset_pos_mod(Def) when is_record(Def,ptypedef) ->
522    Def#ptypedef{pos=undefined};
523unset_pos_mod(Def) when is_record(Def,pvaluedef) ->
524    Def#pvaluedef{pos=undefined};
525unset_pos_mod(Def) when is_record(Def,pvaluesetdef) ->
526    Def#pvaluesetdef{pos=undefined};
527unset_pos_mod(Def) when is_record(Def,pobjectdef) ->
528    Def#pobjectdef{pos=undefined};
529unset_pos_mod(Def) when is_record(Def,pobjectsetdef) ->
530    Def#pobjectsetdef{pos=undefined};
531unset_pos_mod(#'ComponentType'{} = Def) ->
532    Def#'ComponentType'{pos=undefined};
533unset_pos_mod(Def) -> Def.
534
535get_pos_of_def(#typedef{pos=Pos}) ->
536    Pos;
537get_pos_of_def(#classdef{pos=Pos}) ->
538    Pos;
539get_pos_of_def(#valuedef{pos=Pos}) ->
540    Pos;
541get_pos_of_def(#ptypedef{pos=Pos}) ->
542    Pos;
543get_pos_of_def(#pvaluedef{pos=Pos}) ->
544    Pos;
545get_pos_of_def(#pvaluesetdef{pos=Pos}) ->
546    Pos;
547get_pos_of_def(#pobjectdef{pos=Pos}) ->
548    Pos;
549get_pos_of_def(#pobjectsetdef{pos=Pos}) ->
550    Pos;
551get_pos_of_def(#'Externaltypereference'{pos=Pos}) ->
552    Pos;
553get_pos_of_def(#'Externalvaluereference'{pos=Pos}) ->
554    Pos;
555get_pos_of_def(_) ->
556    undefined.
557
558
559get_name_of_def(#typedef{name=Name}) ->
560    Name;
561get_name_of_def(#classdef{name=Name}) ->
562    Name;
563get_name_of_def(#valuedef{name=Name}) ->
564    Name;
565get_name_of_def(#ptypedef{name=Name}) ->
566    Name;
567get_name_of_def(#pvaluedef{name=Name}) ->
568    Name;
569get_name_of_def(#pvaluesetdef{name=Name}) ->
570    Name;
571get_name_of_def(#pobjectdef{name=Name}) ->
572    Name;
573get_name_of_def(#pobjectsetdef{name=Name}) ->
574    Name;
575get_name_of_def(_) ->
576    undefined.
577
578set_name_of_def(ModName,Name,OldDef) ->
579    NewName = list_to_atom(lists:concat([Name,ModName])),
580    case OldDef of
581	#typedef{} -> OldDef#typedef{name=NewName};
582	#classdef{} -> OldDef#classdef{name=NewName};
583	#valuedef{} -> OldDef#valuedef{name=NewName};
584	#ptypedef{} -> OldDef#ptypedef{name=NewName};
585	#pvaluedef{} -> OldDef#pvaluedef{name=NewName};
586	#pvaluesetdef{} -> OldDef#pvaluesetdef{name=NewName};
587	#pobjectdef{} -> OldDef#pobjectdef{name=NewName};
588	#pobjectsetdef{} -> OldDef#pobjectsetdef{name=NewName}
589    end.
590
591save_imports(ModuleList)->
592    Fun = fun(M) ->
593		  case M#module.imports of
594		      {_,[]} -> [];
595		      {_,I} ->
596			  {M#module.name,I}
597		  end
598	  end,
599    ImportsList = lists:map(Fun,ModuleList),
600    case lists:flatten(ImportsList) of
601	[] ->
602	    ok;
603	ImportsList2 ->
604	    asn1ct_table:new(original_imports),
605	    lists:foreach(fun(X) -> asn1ct_table:insert(original_imports, X) end,
606                      ImportsList2)
607    end.
608
609
610common_exports(ModuleList) ->
611    %% if all modules exports 'all' then export 'all',
612    %% otherwise export each typeorval name
613    case lists:filter(fun(X)->
614			      element(2,X#module.exports) /= all
615		      end,
616		      ModuleList) of
617	[]->
618	    {exports,all};
619	ModsWithExpList ->
620	    CExports1 =
621		lists:append(lists:map(fun(X)->element(2,X#module.exports) end,
622				       ModsWithExpList)),
623	    CExports2 = export_all(lists:subtract(ModuleList,ModsWithExpList)),
624	    {exports,CExports1++CExports2}
625    end.
626
627export_all([])->[];
628export_all(ModuleList) ->
629    ExpList =
630	lists:map(
631	  fun(M)->
632		  TorVL=M#module.typeorval,
633		  MName = M#module.name,
634		  lists:map(
635		    fun(Def)->
636			    case Def of
637				T when is_record(T,typedef)->
638				    #'Externaltypereference'{pos=0,
639							     module=MName,
640							     type=T#typedef.name};
641				V when is_record(V,valuedef) ->
642				    #'Externalvaluereference'{pos=0,
643							      module=MName,
644							      value=V#valuedef.name};
645				C when is_record(C,classdef) ->
646				    #'Externaltypereference'{pos=0,
647							     module=MName,
648							     type=C#classdef.name};
649				P when is_record(P,ptypedef) ->
650				    #'Externaltypereference'{pos=0,
651							     module=MName,
652							     type=P#ptypedef.name};
653				PV when is_record(PV,pvaluesetdef) ->
654				    #'Externaltypereference'{pos=0,
655							     module=MName,
656							     type=PV#pvaluesetdef.name};
657				PO when is_record(PO,pobjectdef) ->
658				    #'Externalvaluereference'{pos=0,
659							      module=MName,
660							      value=PO#pobjectdef.name}
661			    end
662		    end,
663		    TorVL)
664	  end,
665	  ModuleList),
666    lists:append(ExpList).
667
668%% common_imports/2
669%% IList is a list of tuples, {Imports,MName}, where Imports is the imports of
670%% the module with name MName.
671%% InputMNameL holds the names of all merged modules.
672%% Returns an import tuple with a list of imports that are external the merged
673%% set of modules.
674common_imports(IList,InputMNameL) ->
675    SetExternalImportsList = remove_in_set_imports(IList,InputMNameL,[]),
676    {imports,remove_import_doubles(SetExternalImportsList)}.
677
678check_tagdefault(ModList) ->
679    case have_same_tagdefault(ModList) of
680	{true,TagDefault}  -> TagDefault;
681	{false,TagDefault} ->
682        asn1ct_table:new(automatic_tags),
683	    save_automatic_tagged_types(ModList),
684	    TagDefault
685    end.
686
687have_same_tagdefault([#module{tagdefault=T}|Ms]) ->
688    have_same_tagdefault(Ms,{true,T}).
689
690have_same_tagdefault([],TagDefault) ->
691    TagDefault;
692have_same_tagdefault([#module{tagdefault=T}|Ms],TDefault={_,T}) ->
693    have_same_tagdefault(Ms,TDefault);
694have_same_tagdefault([#module{tagdefault=T1}|Ms],{_,T2}) ->
695    have_same_tagdefault(Ms,{false,rank_tagdef([T1,T2])}).
696
697rank_tagdef(L) ->
698    case lists:member('EXPLICIT',L) of
699	true -> 'EXPLICIT';
700	_ -> 'IMPLICIT'
701    end.
702
703save_automatic_tagged_types([])->
704    done;
705save_automatic_tagged_types([#module{tagdefault='AUTOMATIC',
706				     typeorval=TorV}|Ms]) ->
707    Fun =
708	fun(T) ->
709		asn1ct_table:insert(automatic_tags, {get_name_of_def(T)})
710	end,
711    lists:foreach(Fun,TorV),
712    save_automatic_tagged_types(Ms);
713save_automatic_tagged_types([_M|Ms]) ->
714    save_automatic_tagged_types(Ms).
715
716%% remove_in_set_imports/3 :
717%% input: list with tuples of each module's imports and module name
718%% respectively.
719%% output: one list with same format but each occured import from a
720%% module in the input set (IMNameL) is removed.
721remove_in_set_imports([{{imports,ImpL},_ModName}|Rest],InputMNameL,Acc) ->
722    NewImpL = remove_in_set_imports1(ImpL,InputMNameL,[]),
723    remove_in_set_imports(Rest,InputMNameL,NewImpL++Acc);
724remove_in_set_imports([],_,Acc) ->
725    lists:reverse(Acc).
726
727remove_in_set_imports1([I|Is],InputMNameL,Acc) ->
728    case I#'SymbolsFromModule'.module of
729	#'Externaltypereference'{type=MName} ->
730	    case lists:member(MName,InputMNameL) of
731		true ->
732		    remove_in_set_imports1(Is,InputMNameL,Acc);
733		false ->
734		    remove_in_set_imports1(Is,InputMNameL,[I|Acc])
735	    end;
736	_ ->
737	    remove_in_set_imports1(Is,InputMNameL,[I|Acc])
738    end;
739remove_in_set_imports1([],_,Acc) ->
740    lists:reverse(Acc).
741
742remove_import_doubles([]) ->
743    [];
744%% If several modules in the merge set imports symbols from
745%% the same external module it might be doubled.
746%% ImportList has #'SymbolsFromModule' elements
747remove_import_doubles(ImportList) ->
748    MergedImportList =
749	merge_symbols_from_module(ImportList,[]),
750    delete_double_of_symbol(MergedImportList,[]).
751
752merge_symbols_from_module([Imp|Imps],Acc) ->
753    #'Externaltypereference'{type=ModName} = Imp#'SymbolsFromModule'.module,
754    IfromModName =
755	lists:filter(
756	  fun(I)->
757		  case I#'SymbolsFromModule'.module of
758		      #'Externaltypereference'{type=ModName} ->
759			  true;
760		      #'Externalvaluereference'{value=ModName} ->
761			  true;
762		      _ -> false
763		  end
764	  end,
765	  Imps),
766    NewImps = lists:subtract(Imps,IfromModName),
767    NewImp =
768	Imp#'SymbolsFromModule'{
769	  symbols = lists:append(
770		      lists:map(fun(SL)->
771					SL#'SymbolsFromModule'.symbols
772				end,[Imp|IfromModName]))},
773    merge_symbols_from_module(NewImps,[NewImp|Acc]);
774merge_symbols_from_module([],Acc) ->
775    lists:reverse(Acc).
776
777delete_double_of_symbol([I|Is],Acc) ->
778    SymL=I#'SymbolsFromModule'.symbols,
779    NewSymL = delete_double_of_symbol1(SymL,[]),
780    delete_double_of_symbol(Is,[I#'SymbolsFromModule'{symbols=NewSymL}|Acc]);
781delete_double_of_symbol([],Acc) ->
782    Acc.
783
784delete_double_of_symbol1([TRef=#'Externaltypereference'{type=TrefName}|Rest],Acc)->
785    NewRest =
786	lists:filter(fun(S)->
787			     case S of
788				 #'Externaltypereference'{type=TrefName}->
789				     false;
790				 _ -> true
791			     end
792		     end,
793		     Rest),
794    delete_double_of_symbol1(NewRest,[TRef|Acc]);
795delete_double_of_symbol1([VRef=#'Externalvaluereference'{value=VName}|Rest],Acc) ->
796    NewRest =
797	lists:filter(fun(S)->
798			     case S of
799				 #'Externalvaluereference'{value=VName}->
800				     false;
801				 _ -> true
802			     end
803		     end,
804		     Rest),
805    delete_double_of_symbol1(NewRest,[VRef|Acc]);
806delete_double_of_symbol1([TRef={#'Externaltypereference'{type=MRef},
807				#'Externaltypereference'{type=TRef}}|Rest],
808			 Acc)->
809    NewRest =
810	lists:filter(
811	  fun(S)->
812		  case S of
813		      {#'Externaltypereference'{type=MRef},
814		       #'Externaltypereference'{type=TRef}}->
815			  false;
816		      _ -> true
817		  end
818	  end,
819	  Rest),
820    delete_double_of_symbol1(NewRest,[TRef|Acc]);
821delete_double_of_symbol1([],Acc) ->
822    Acc.
823
824
825%%***********************************
826
827generate({M,CodeTuple}, OutFile, EncodingRule, Options) ->
828    {Types,Values,Ptypes,Classes,Objects,ObjectSets} = CodeTuple,
829    Code = #abst{name=M#module.name,
830                 types=Types,values=Values,ptypes=Ptypes,
831                 classes=Classes,objects=Objects,objsets=ObjectSets},
832    setup_bit_string_format(Options),
833    setup_legacy_erlang_types(Options),
834    asn1ct_table:new(check_functions),
835
836    Gen = init_gen_record(EncodingRule, Options),
837
838    check_maps_option(Gen),
839
840    %% create decoding function names and taglists for partial decode
841    try
842        specialized_decode_prepare(Gen, M)
843    catch
844        throw:{error, Reason} ->
845            warning("Error in configuration file: ~n~p~n",
846                    [Reason], Options,
847                    "Error in configuration file")
848    end,
849
850    asn1ct_gen:pgen(OutFile, Gen, Code),
851    cleanup_bit_string_format(),
852    erase(tlv_format), % used in ber
853    erase(class_default_type),% used in ber
854    asn1ct_table:delete(check_functions),
855    ok.
856
857init_gen_record(EncodingRule, Options) ->
858    Erule = case EncodingRule of
859                uper -> per;
860                _ -> EncodingRule
861            end,
862    Der = proplists:get_bool(der, Options),
863    Aligned = EncodingRule =:= per,
864    RecPrefix = proplists:get_value(record_name_prefix, Options, ""),
865    MacroPrefix = proplists:get_value(macro_name_prefix, Options, ""),
866    Pack = case proplists:get_value(maps, Options, false) of
867               true -> map;
868               false -> record
869           end,
870    #gen{erule=Erule,der=Der,aligned=Aligned,
871         rec_prefix=RecPrefix,macro_prefix=MacroPrefix,
872         pack=Pack,options=Options}.
873
874
875setup_legacy_erlang_types(Opts) ->
876    F = case lists:member(legacy_erlang_types, Opts) of
877	    false ->
878		case get_bit_string_format() of
879		    bitstring ->
880			false;
881		    compact ->
882			legacy_forced_info(compact_bit_string),
883			true;
884		    legacy ->
885			legacy_forced_info(legacy_bit_string),
886			true
887		end;
888	    true ->
889		true
890	end,
891    put(use_legacy_erlang_types, F).
892
893legacy_forced_info(Opt) ->
894    io:format("Info: The option 'legacy_erlang_types' "
895	      "is implied by the '~s' option.\n", [Opt]).
896
897use_legacy_types() ->
898    get(use_legacy_erlang_types).
899
900setup_bit_string_format(Opts) ->
901    Format = case {lists:member(compact_bit_string, Opts),
902		   lists:member(legacy_bit_string, Opts)} of
903		 {false,false} -> bitstring;
904		 {true,false} -> compact;
905		 {false,true} -> legacy;
906		 {true,true} ->
907		     Message = "Contradicting options given: "
908			 "compact_bit_string and legacy_bit_string",
909		     exit({error,{asn1,Message}})
910	     end,
911    put(bit_string_format, Format).
912
913cleanup_bit_string_format() ->
914    erase(bit_string_format).
915
916get_bit_string_format() ->
917    get(bit_string_format).
918
919check_maps_option(#gen{pack=map}) ->
920    case get_bit_string_format() of
921        bitstring ->
922            ok;
923        _ ->
924            Message1 = "The 'maps' option must not be combined with "
925                "'compact_bit_string' or 'legacy_bit_string'",
926            exit({error,{asn1,Message1}})
927    end,
928    case use_legacy_types() of
929        false ->
930            ok;
931        true ->
932            Message2 = "The 'maps' option must not be combined with "
933                "'legacy_erlang_types'",
934            exit({error,{asn1,Message2}})
935    end;
936check_maps_option(#gen{}) ->
937    ok.
938
939
940%% parse_and_save parses an asn1 spec and saves the unchecked parse
941%% tree in a data base file.
942%% Does not support multifile compilation files
943parse_and_save(Module,S) ->
944    Options = S#state.options,
945    SourceDir = S#state.sourcedir,
946    Includes = [I || {i,I} <- Options],
947    Erule = S#state.erule,
948    Maps = lists:member(maps, Options),
949    case get_input_file(Module, [SourceDir|Includes]) of
950	%% search for asn1 source
951	{file,SuffixedASN1source} ->
952	    Mtime = filelib:last_modified(SuffixedASN1source),
953	    case asn1_db:dbload(Module, Erule, Maps, Mtime) of
954		ok -> ok;
955		error -> parse_and_save1(S, SuffixedASN1source, Options)
956	    end;
957	Err when not Maps ->
958	    case asn1_db:dbload(Module) of
959		ok ->
960                    %% FIXME: This should be an error.
961		    warning("could not do a consistency check of the ~p file: no asn1 source file was found.~n",
962			    [lists:concat([Module,".asn1db"])],Options);
963		error ->
964		    ok
965	    end,
966	    {error,{asn1,input_file_error,Err}};
967        Err ->
968            %% Always fail directly when the 'maps' option is used.
969	    {error,{asn1,input_file_error,Err}}
970    end.
971
972parse_and_save1(#state{erule=Erule}, File, Options) ->
973    Ext = filename:extension(File),
974    Base = filename:basename(File, Ext),
975    DbFile = outfile(Base, "asn1db", Options),
976    St = #st{file=File,dbfile=DbFile,erule=Erule},
977    Passes = parse_and_save_passes(),
978    run_passes(Passes, St).
979
980get_input_file(Module,[]) ->
981    Module;
982get_input_file(Module,[I|Includes]) ->
983    case (catch input_file_type(filename:join([I,Module]))) of
984	{single_file,FileName} ->
985		    {file,FileName};
986	_ ->
987	    get_input_file(Module,Includes)
988    end.
989
990input_file_type(Name,I) ->
991   case input_file_type(Name) of
992       {error,_} -> input_file_type2(filename:basename(Name),I);
993       Err={input_file_error,_} -> Err;
994       Res -> Res
995   end.
996input_file_type2(Name,[I|Is]) ->
997    case input_file_type(filename:join([I,Name])) of
998	{error,_} -> input_file_type2(Name,Is);
999	Err={input_file_error,_} -> Err;
1000	Res -> Res
1001    end;
1002input_file_type2(Name,[]) ->
1003    input_file_type(Name).
1004
1005input_file_type([]) ->
1006    {empty_name,[]};
1007input_file_type(File) ->
1008    case filename:extension(File) of
1009	[] ->
1010	    case file:read_file_info(lists:concat([File,".asn1"])) of
1011		{ok,_FileInfo} ->
1012		    {single_file, lists:concat([File,".asn1"])};
1013		_Error ->
1014		    case file:read_file_info(lists:concat([File,".asn"])) of
1015			{ok,_FileInfo} ->
1016			    {single_file, lists:concat([File,".asn"])};
1017			_Error ->
1018			    case file:read_file_info(lists:concat([File,".py"])) of
1019				{ok,_FileInfo} ->
1020				    {single_file, lists:concat([File,".py"])};
1021				Error ->
1022				    Error
1023			    end
1024		    end
1025	    end;
1026	".asn1config" ->
1027	    case read_config_file_info(File, asn1_module) of
1028		{ok,Asn1Module} ->
1029		    input_file_type(Asn1Module);
1030		Error ->
1031		    Error
1032	    end;
1033	Asn1SFix ->
1034	    Base = filename:basename(File,Asn1SFix),
1035	    Ret =
1036		case filename:extension(Base) of
1037		    [] ->
1038			{single_file,File};
1039		    SetSFix when (SetSFix == ".set") ->
1040			{multiple_files_file,
1041			 list_to_atom(filename:basename(Base,SetSFix)),
1042			 File};
1043		    _Error ->
1044			throw({input_file_error,{'Bad input file',File}})
1045		end,
1046	    %% check that the file exists
1047	    case file:read_file_info(File) of
1048		{ok,_} -> Ret;
1049		Err -> Err
1050	    end
1051    end.
1052
1053get_file_list(File,Includes) ->
1054    case file:open(File,[read]) of
1055	{error,Reason} ->
1056	    {error,{File,file:format_error(Reason)}};
1057	{ok,Stream} ->
1058	    get_file_list1(Stream,filename:dirname(File),Includes,[])
1059    end.
1060
1061get_file_list1(Stream,Dir,Includes,Acc) ->
1062    Ret = io:get_line(Stream,''),
1063    case Ret of
1064	eof ->
1065	    ok = file:close(Stream),
1066	    lists:reverse(Acc);
1067	FileName ->
1068	    SuffixedNameList =
1069		case (catch input_file_type(filename:join([Dir,lists:delete($\n,FileName)]),Includes)) of
1070		    {empty_name,[]} -> [];
1071		    {single_file,Name} -> [Name];
1072		    {multiple_files_file,_,Name} ->
1073			get_file_list(Name,Includes);
1074		    _Err ->
1075			[]
1076		end,
1077	    get_file_list1(Stream,Dir,Includes,SuffixedNameList++Acc)
1078    end.
1079
1080get_rule(Options) ->
1081    case [Rule || Rule <- [ber,per,uper],
1082		  Opt <- Options,
1083		  Rule =:= Opt] of
1084	[Rule] ->
1085	    Rule;
1086	[Rule|_] ->
1087	    Rule;
1088	[] ->
1089	    ber
1090    end.
1091
1092%% translate_options(NewOptions) -> OldOptions
1093%%  Translate the new option names to the old option name.
1094
1095translate_options([ber_bin|T]) ->
1096    io:format("Warning: The option 'ber_bin' is now called 'ber'.\n"),
1097    [ber|translate_options(T)];
1098translate_options([per_bin|T]) ->
1099    io:format("Warning: The option 'per_bin' is now called 'per'.\n"),
1100    [per|translate_options(T)];
1101translate_options([uper_bin|T]) ->
1102    io:format("Warning: The option 'uper_bin' is now called 'uper'.\n"),
1103    translate_options([uper|T]);
1104translate_options([nif|T]) ->
1105    io:format("Warning: The option 'nif' is no longer needed.\n"),
1106    translate_options(T);
1107translate_options([optimize|T]) ->
1108    io:format("Warning: The option 'optimize' is no longer needed.\n"),
1109    translate_options(T);
1110translate_options([inline|T]) ->
1111    io:format("Warning: The option 'inline' is no longer needed.\n"),
1112    translate_options(T);
1113translate_options([{inline,_}|_]) ->
1114    io:format("ERROR: The option {inline,OutputFilename} is no longer supported.\n"),
1115    throw({error,{unsupported_option,inline}});
1116translate_options([H|T]) ->
1117    [H|translate_options(T)];
1118translate_options([]) -> [].
1119
1120remove_asn_flags(Options) ->
1121    [X || X <- Options, not is_asn1_flag(X)].
1122
1123is_asn1_flag(asn1config) -> true;
1124is_asn1_flag(ber) -> true;
1125is_asn1_flag(compact_bit_string) -> true;
1126is_asn1_flag(debug) -> true;
1127is_asn1_flag(der) -> true;
1128is_asn1_flag(legacy_bit_string) -> true;
1129is_asn1_flag({macro_name_prefix,_}) -> true;
1130is_asn1_flag({n2n,_}) -> true;
1131is_asn1_flag(noobj) -> true;
1132is_asn1_flag(no_ok_wrapper) -> true;
1133is_asn1_flag(optimize) -> true;
1134is_asn1_flag(per) -> true;
1135is_asn1_flag({record_name_prefix,_}) -> true;
1136is_asn1_flag(undec_rec) -> true;
1137is_asn1_flag(uper) -> true;
1138is_asn1_flag(verbose) -> true;
1139%% 'warnings_as_errors' is intentionally passed through to the compiler.
1140is_asn1_flag(_) -> false.
1141
1142
1143outfile(Base, Ext, Opts) ->
1144    Obase = case lists:keysearch(outdir, 1, Opts) of
1145		{value, {outdir, Odir}} -> filename:join(Odir, Base);
1146		_NotFound -> Base % Not found or bad format
1147	    end,
1148    case Ext of
1149	[] ->
1150	    Obase;
1151	_ ->
1152	    lists:concat([Obase,".",Ext])
1153    end.
1154
1155includes(File,Options) ->
1156    Options2 = include_append(".", Options),
1157    Options3 = include_append(filename:dirname(File), Options2),
1158    case proplists:get_value(outdir, Options) of
1159        undefined -> Options3;
1160        OutDir    -> include_prepend(OutDir, Options3)
1161    end.
1162
1163include_append(Dir, Options) ->
1164    option_add({i, Dir}, Options, fun(Opts) -> Opts ++ [{i, Dir}] end).
1165
1166include_prepend(Dir, Options) ->
1167    option_add({i, Dir}, Options, fun(Opts) -> [{i, Dir}|Opts] end).
1168
1169option_add(Option, Options, Fun) ->
1170    case lists:member(Option, Options) of
1171        true  -> Options;
1172        false -> Fun(Options)
1173    end.
1174
1175strip_includes(Includes) ->
1176    [I || {i, I} <- Includes].
1177
1178
1179%% compile(AbsFileName, Options)
1180%%   Compile entry point for erl_compile.
1181
1182compile_asn(File,OutFile,Options) ->
1183    compile(lists:concat([File,".asn"]),OutFile,Options).
1184
1185compile_asn1(File,OutFile,Options) ->
1186    compile(lists:concat([File,".asn1"]),OutFile,Options).
1187
1188compile_py(File,OutFile,Options) ->
1189    compile(lists:concat([File,".py"]),OutFile,Options).
1190
1191compile(File, _OutFile, Options) ->
1192    case compile(File, make_erl_options(Options)) of
1193	{error,_Reason} ->
1194	    error;
1195	ok ->
1196	    ok;
1197	ParseRes when is_tuple(ParseRes) ->
1198	    io:format("~p~n",[ParseRes]),
1199	    ok;
1200	ScanRes when is_list(ScanRes) ->
1201	    io:format("~p~n",[ScanRes]),
1202	    ok
1203    end.
1204
1205%% Converts generic compiler options to specific options.
1206
1207make_erl_options(Opts) ->
1208
1209    %% This way of extracting will work even if the record passed
1210    %% has more fields than known during compilation.
1211
1212    Includes = Opts#options.includes,
1213    Defines = Opts#options.defines,
1214    Outdir = Opts#options.outdir,
1215    Warning = Opts#options.warning,
1216    Verbose = Opts#options.verbose,
1217    Specific = Opts#options.specific,
1218    Optimize = Opts#options.optimize,
1219    OutputType = Opts#options.output_type,
1220    Cwd = Opts#options.cwd,
1221
1222    Options =
1223	case Verbose of
1224	    true ->  [verbose];
1225	    false -> []
1226	end ++
1227	case Warning of
1228	    0 -> [];
1229	    _ -> [warnings]
1230	end ++
1231	[] ++
1232	case Optimize of
1233	    1 -> [optimize];
1234	    999 -> [];
1235	    _ -> [{optimize,Optimize}]
1236	end ++
1237	lists:map(
1238	  fun ({Name, Value}) ->
1239		  {d, Name, Value};
1240	      (Name) ->
1241		  {d, Name}
1242	  end,
1243	  Defines) ++
1244	case OutputType of
1245	    undefined -> [ber]; % temporary default (ber when it's ready)
1246	    _ -> [OutputType]	% pass through
1247	end,
1248
1249    Options++[errors, {cwd, Cwd}, {outdir, Outdir}|
1250	      lists:map(fun(Dir) -> {i, Dir} end, Includes)]++Specific.
1251
1252pretty2(Module,AbsFile) ->
1253    {ok,F} = file:open(AbsFile,[write]),
1254    M = asn1_db:dbget(Module,'MODULE'),
1255    io:format(F,"%%%%%%%%%%%%%%%%%%%   ~p  %%%%%%%%%%%%%%%%%%%~n",[Module]),
1256    io:format(F,"~s.\n",[asn1ct_pretty_format:term(M#module.defid)]),
1257    io:format(F,"~s.\n",[asn1ct_pretty_format:term(M#module.tagdefault)]),
1258    io:format(F,"~s.\n",[asn1ct_pretty_format:term(M#module.exports)]),
1259    io:format(F,"~s.\n",[asn1ct_pretty_format:term(M#module.imports)]),
1260    io:format(F,"~s.\n\n",[asn1ct_pretty_format:term(M#module.extensiondefault)]),
1261
1262    {Types,Values,ParameterizedTypes,Classes,Objects,ObjectSets} = M#module.typeorval,
1263    io:format(F,"%%%%%%%%%%%%%%%%%%% TYPES in ~p  %%%%%%%%%%%%%%%%%%%~n",[Module]),
1264    lists:foreach(fun(T)-> io:format(F,"~s.\n",
1265				     [asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
1266		  end,Types),
1267    io:format(F,"%%%%%%%%%%%%%%%%%%% VALUES in ~p  %%%%%%%%%%%%%%%%%%%~n",[Module]),
1268    lists:foreach(fun(T)-> io:format(F,"~s.\n",
1269				     [asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
1270		  end,Values),
1271    io:format(F,"%%%%%%%%%%%%%%%%%%% Parameterized Types in ~p  %%%%%%%%%%%%%%%%%%%~n",[Module]),
1272    lists:foreach(fun(T)-> io:format(F,"~s.\n",
1273				     [asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
1274		  end,ParameterizedTypes),
1275    io:format(F,"%%%%%%%%%%%%%%%%%%% Classes in ~p  %%%%%%%%%%%%%%%%%%%~n",[Module]),
1276    lists:foreach(fun(T)-> io:format(F,"~s.\n",
1277				     [asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
1278		  end,Classes),
1279    io:format(F,"%%%%%%%%%%%%%%%%%%% Objects in ~p  %%%%%%%%%%%%%%%%%%%~n",[Module]),
1280    lists:foreach(fun(T)-> io:format(F,"~s.\n",
1281				     [asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
1282		  end,Objects),
1283    io:format(F,"%%%%%%%%%%%%%%%%%%% Object Sets in ~p  %%%%%%%%%%%%%%%%%%%~n",[Module]),
1284    lists:foreach(fun(T)-> io:format(F,"~s.\n",
1285				     [asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
1286		  end,ObjectSets).
1287
1288start(Includes) when is_list(Includes) ->
1289    asn1_db:dbstart(Includes).
1290
1291test(Module)                             -> test_module(Module, []).
1292
1293test(Module, [] = Options)               -> test_module(Module, Options);
1294test(Module, [{i, _}|_] = Options)       -> test_module(Module, Options);
1295test(Module, Type)                       -> test_type(Module, Type, []).
1296
1297test(Module, Type, [] = Options)         -> test_type(Module, Type, Options);
1298test(Module, Type, [{i, _}|_] = Options) -> test_type(Module, Type, Options);
1299test(Module, Type, Value)                -> test_value(Module, Type, Value).
1300
1301test_module(Module, Includes) ->
1302    in_process(fun() ->
1303                   start(strip_includes(Includes)),
1304                   case check(Module, Includes) of
1305                       {ok, NewTypes} -> test_each(Module, NewTypes);
1306                       Error          -> Error
1307                   end
1308               end).
1309
1310test_each(Module, [Type|Rest]) ->
1311    case test_type(Module, Type) of
1312        {ok, _Result} -> test_each(Module, Rest);
1313        Error         -> Error
1314    end;
1315test_each(_,[]) ->
1316    ok.
1317
1318test_type(Module, Type, Includes) ->
1319    in_process(fun() ->
1320                   start(strip_includes(Includes)),
1321                   case check(Module, Includes) of
1322                       {ok, _NewTypes} -> test_type(Module, Type);
1323                       Error           -> Error
1324                   end
1325               end).
1326
1327test_type(Module, Type) ->
1328    case get_value(Module, Type) of
1329        {ok, Val}       -> test_value(Module, Type, Val);
1330        {error, Reason} -> {error, {asn1, {value, Reason}}}
1331    end.
1332
1333test_value(Module, Type, Value) ->
1334    in_process(fun() ->
1335                   case catch Module:encode(Type, Value) of
1336                       {ok, Bytes} ->
1337                           test_value_decode(Module, Type, Value, Bytes);
1338                       Bytes when is_binary(Bytes) ->
1339                           test_value_decode(Module, Type, Value, Bytes);
1340                       Error ->
1341                           {error, {asn1,
1342                                    {encode, {{Module, Type, Value}, Error}}}}
1343                   end
1344               end).
1345
1346
1347test_value_decode(Module, Type, Value, Bytes) ->
1348    NewBytes = prepare_bytes(Bytes),
1349    case Module:decode(Type, NewBytes) of
1350        {ok,Value}      -> {ok, {Module,Type,Value}};
1351        {ok,Value,<<>>} -> {ok, {Module,Type,Value}};
1352        Value           -> {ok, {Module,Type,Value}};
1353        {Value,<<>>}    -> {ok, {Module,Type,Value}};
1354
1355        %% Errors:
1356        {ok, Res}   ->
1357            {error, {asn1,
1358                     {encode_decode_mismatch,
1359                      {{Module, Type, Value}, Res}}}};
1360        {ok, Res, Rest} ->
1361            {error, {asn1,
1362                     {encode_decode_mismatch,
1363                      {{Module, Type, Value}, {Res,Rest}}}}};
1364        Error       ->
1365            {error, {asn1,
1366                     {{decode,
1367                       {Module, Type, Value}, Error}}}}
1368    end.
1369
1370value(Module, Type) -> value(Module, Type, []).
1371
1372value(Module, Type, Includes) ->
1373    in_process(fun() ->
1374                   start(strip_includes(Includes)),
1375                   case check(Module, Includes) of
1376                       {ok, _NewTypes} -> get_value(Module, Type);
1377                       Error           -> Error
1378                   end
1379               end).
1380
1381get_value(Module, Type) ->
1382    case asn1ct_value:from_type(Module, Type) of
1383        {error, Reason} -> {error, Reason};
1384        Result          -> {ok, Result}
1385    end.
1386
1387check(Module, Includes) ->
1388    case asn1_db:dbload(Module) of
1389	error ->
1390            {error,asn1db_missing_or_out_of_date};
1391	ok ->
1392	    M = asn1_db:dbget(Module, 'MODULE'),
1393            TypeOrVal =  M#module.typeorval,
1394            State = #state{mname = M#module.name,
1395                           module = M#module{typeorval=[]},
1396                           options = Includes},
1397            case asn1ct_check:check(State, TypeOrVal) of
1398                {ok, {NewTypes, _, _, _, _, _}, _} -> {ok, NewTypes};
1399                {error, Reason}                    -> {error, Reason}
1400            end
1401    end.
1402
1403prepare_bytes(Bytes) when is_binary(Bytes) -> Bytes;
1404prepare_bytes(Bytes) -> list_to_binary(Bytes).
1405
1406vsn() ->
1407    ?vsn.
1408
1409specialized_decode_prepare(#gen{erule=ber,options=Options}=Gen, M) ->
1410    case lists:member(asn1config, Options) of
1411	true ->
1412	    special_decode_prepare_1(Gen, M);
1413	false ->
1414	    ok
1415    end;
1416specialized_decode_prepare(_, _) ->
1417    ok.
1418
1419%% Reads the configuration file if it exists and stores information
1420%% about partial decode and incomplete decode
1421special_decode_prepare_1(#gen{options=Options}=Gen, M) ->
1422    %% read configure file
1423    ModName = case lists:keyfind(asn1config, 1, Options) of
1424                  {_,MName} -> MName;
1425                  false -> M#module.name
1426              end,
1427%%    io:format("ModName: ~p~nM#module.name: ~p~n~n",[ModName,M#module.name]),
1428    case read_config_file(Gen, ModName) of
1429        no_config_file ->
1430            ok;
1431        CfgList ->
1432            SelectedDecode = get_config_info(CfgList,selective_decode),
1433            ExclusiveDecode = get_config_info(CfgList,exclusive_decode),
1434            CommandList = create_partial_decode_gen_info(M#module.name,
1435                                                         SelectedDecode),
1436            %% To convert CommandList to a proper list for the driver change
1437            %% the list:[[choosen,Tag1],skip,[skip_optional,Tag2]] to L =
1438            %% [5,2,Tag1,0,1,Tag2] where 5 is the length, and call
1439            %% port_control(asn1_driver_port,3,[L| Bin])
1440            save_config(partial_decode,CommandList),
1441            save_gen_state(selective_decode,SelectedDecode),
1442            CommandList2 = create_partial_inc_decode_gen_info(M#module.name,
1443                                                              ExclusiveDecode),
1444            Part_inc_tlv_tags = tlv_tags(CommandList2),
1445            save_config(partial_incomplete_decode,Part_inc_tlv_tags),
1446            save_gen_state(exclusive_decode,ExclusiveDecode,Part_inc_tlv_tags)
1447    end.
1448
1449%% create_partial_inc_decode_gen_info/2
1450%%
1451%% Creats a list of tags out of the information in TypeNameList that
1452%% tells which value will be incomplete decoded, i.e. each end
1453%% component/type in TypeNameList. The significant types/components in
1454%% the path from the toptype must be specified in the
1455%% TypeNameList. Significant elements are all constructed types that
1456%% branches the path to the leaf and the leaf it selfs.
1457%%
1458%% Returns a list of elements, where an element may be one of
1459%% mandatory|[opt,Tag]|[bin,Tag]. mandatory correspond to a mandatory
1460%% element that shall be decoded as usual. [opt,Tag] matches an
1461%% OPTIONAL or DEFAULT element that shall be decoded as
1462%% usual. [bin,Tag] corresponds to an element, mandatory, OPTIONAL or
1463%% DEFAULT, that shall be left encoded (incomplete decoded).
1464create_partial_inc_decode_gen_info(ModName,{Mod,[{Name,L}|Ls]}) when is_list(L) ->
1465    TopTypeName = partial_inc_dec_toptype(L),
1466    [{Name,TopTypeName,
1467      create_partial_inc_decode_gen_info1(ModName,TopTypeName,{Mod,L})}|
1468     create_partial_inc_decode_gen_info(ModName,{Mod,Ls})];
1469create_partial_inc_decode_gen_info(_,{_,[]}) ->
1470    [];
1471create_partial_inc_decode_gen_info(_,[]) ->
1472    [].
1473
1474create_partial_inc_decode_gen_info1(ModName,TopTypeName,{ModName,
1475					    [_TopType|Rest]}) ->
1476    case asn1_db:dbget(ModName,TopTypeName) of
1477	#typedef{typespec=TS} ->
1478	    TagCommand = get_tag_command(TS,?MANDATORY,mandatory),
1479	    create_pdec_inc_command(ModName,get_components(TS#type.def),
1480				    Rest,[TagCommand]);
1481	_ ->
1482	    throw({error,{"wrong type list in asn1 config file",
1483			  TopTypeName}})
1484    end;
1485create_partial_inc_decode_gen_info1(M1,_,{M2,_}) when M1 /= M2 ->
1486    throw({error,{"wrong module name in asn1 config file",
1487		  M2}});
1488create_partial_inc_decode_gen_info1(_,_,TNL) ->
1489    throw({error,{"wrong type list in asn1 config file",
1490		  TNL}}).
1491
1492%%
1493%% Only when there is a 'ComponentType' the config data C1 may be a
1494%% list, where the incomplete decode is branched. So, C1 may be a
1495%% list, a "binary tuple", a "parts tuple" or an atom. The second
1496%% element of a binary tuple and a parts tuple is an atom.
1497create_pdec_inc_command(_ModName,_,[],Acc) ->
1498    lists:reverse(Acc);
1499create_pdec_inc_command(ModName,{Comps1,Comps2},TNL,Acc)
1500  when is_list(Comps1),is_list(Comps2) ->
1501    create_pdec_inc_command(ModName,Comps1 ++ Comps2,TNL,Acc);
1502%% The following two clauses match on the type after the top
1503%% type. This one if the top type had no tag, i.e. a CHOICE.
1504create_pdec_inc_command(ModN,Clist,[CL|_Rest],[[]]) when is_list(CL) ->
1505    create_pdec_inc_command(ModN,Clist,CL,[]);
1506create_pdec_inc_command(ModN,Clist,[CL|_Rest],Acc) when is_list(CL) ->
1507    InnerDirectives=create_pdec_inc_command(ModN,Clist,CL,[]),
1508    lists:reverse([InnerDirectives|Acc]);
1509create_pdec_inc_command(ModName,
1510			CList=[#'ComponentType'{name=Name,typespec=TS,
1511						prop=Prop}|Comps],
1512			TNL=[C1|Cs],Acc)  ->
1513    case C1 of
1514	{Name,undecoded} ->
1515	    TagCommand = get_tag_command(TS,?UNDECODED,Prop),
1516	    create_pdec_inc_command(ModName,Comps,Cs,concat_sequential(TagCommand,Acc));
1517	{Name,parts} ->
1518	    TagCommand = get_tag_command(TS,?PARTS,Prop),
1519	    create_pdec_inc_command(ModName,Comps,Cs,concat_sequential(TagCommand,Acc));
1520	L when is_list(L) ->
1521            %% I guess this never happens due to previous clause.
1522	    %% This case is only possible as the first element after
1523	    %% the top type element, when top type is SEGUENCE or SET.
1524	    %% Follow each element in L. Must note every tag on the
1525	    %% way until the last command is reached, but it ought to
1526	    %% be enough to have a "complete" or "complete optional"
1527	    %% command for each component that is not specified in the
1528	    %% config file. Then in the TLV decode the components with
1529	    %% a "complete" command will be decoded by an ordinary TLV
1530	    %% decode.
1531	    create_pdec_inc_command(ModName,CList,L,Acc);
1532	{Name,RestPartsList} when is_list(RestPartsList) ->
1533	    %% Same as previous, but this may occur at any place in
1534	    %% the structure. The previous is only possible as the
1535	    %% second element.
1536	    case get_tag_command(TS,?MANDATORY,Prop) of
1537		?MANDATORY ->
1538		    InnerDirectives=
1539			create_pdec_inc_command(ModName,TS#type.def,
1540						RestPartsList,[]),
1541		    create_pdec_inc_command(ModName,Comps,Cs,
1542					    [[?MANDATORY,InnerDirectives]|Acc]);
1543		[Opt,EncTag] ->
1544		    InnerDirectives =
1545			create_pdec_inc_command(ModName,TS#type.def,
1546						RestPartsList,[]),
1547		    create_pdec_inc_command(ModName,Comps,Cs,
1548					    [[Opt,EncTag,InnerDirectives]|Acc])
1549	    end;
1550	_ ->
1551            %% this component may not be in the config list
1552	    TagCommand = get_tag_command(TS,?MANDATORY,Prop),
1553	    create_pdec_inc_command(ModName,Comps,TNL,concat_sequential(TagCommand,Acc))
1554    end;
1555create_pdec_inc_command(ModName,
1556			{'CHOICE',[#'ComponentType'{name=C1,
1557						    typespec=TS,
1558						    prop=Prop}|Comps]},
1559			[{C1,Directive}|Rest],Acc) ->
1560    case Directive of
1561	List when is_list(List) ->
1562	    TagCommand = get_tag_command(TS,?ALTERNATIVE,Prop),
1563	    CompAcc =
1564		create_pdec_inc_command(ModName,
1565					get_components(TS#type.def),List,[]),
1566	    NewAcc = case TagCommand of
1567			 [Command,Tag] when is_atom(Command) ->
1568			     [[Command,Tag,CompAcc]|Acc];
1569			 [L1,_L2|Rest] when is_list(L1) ->
1570			     case lists:reverse(TagCommand) of
1571				 [Atom|Comms] when is_atom(Atom) ->
1572				     [concat_sequential(lists:reverse(Comms),
1573							[Atom,CompAcc])|Acc];
1574				 [[Command2,Tag2]|Comms] ->
1575				     [concat_sequential(lists:reverse(Comms),
1576							[[Command2,Tag2,CompAcc]])|Acc]
1577			     end
1578		     end,
1579	    create_pdec_inc_command(ModName,{'CHOICE',Comps},Rest,
1580				    NewAcc);
1581	undecoded ->
1582	    TagCommand = get_tag_command(TS,?ALTERNATIVE_UNDECODED,Prop),
1583	    create_pdec_inc_command(ModName,{'CHOICE',Comps},Rest,
1584				    concat_sequential(TagCommand,Acc));
1585	parts ->
1586	    TagCommand = get_tag_command(TS,?ALTERNATIVE_PARTS,Prop),
1587	    create_pdec_inc_command(ModName,{'CHOICE',Comps},Rest,
1588				    concat_sequential(TagCommand,Acc))
1589    end;
1590create_pdec_inc_command(ModName,
1591			{'CHOICE',[#'ComponentType'{typespec=TS,
1592						    prop=Prop}|Comps]},
1593			TNL,Acc) ->
1594    TagCommand = get_tag_command(TS,?ALTERNATIVE,Prop),
1595    create_pdec_inc_command(ModName,{'CHOICE',Comps},TNL,
1596			    concat_sequential(TagCommand,Acc));
1597create_pdec_inc_command(M,{'CHOICE',{Cs1,Cs2}},TNL,Acc)
1598  when is_list(Cs1),is_list(Cs2) ->
1599    create_pdec_inc_command(M,{'CHOICE',Cs1 ++ Cs2},TNL,Acc);
1600create_pdec_inc_command(ModName,#'Externaltypereference'{module=M,type=Name},
1601			TNL,Acc) ->
1602    #type{def=Def} = get_referenced_type(M,Name),
1603    create_pdec_inc_command(ModName,get_components(Def),TNL,Acc);
1604create_pdec_inc_command(_,_,TNL,_) ->
1605    throw({error,{"unexpected error when creating partial "
1606		  "decode command",TNL}}).
1607
1608partial_inc_dec_toptype([T|_]) when is_atom(T) ->
1609    T;
1610partial_inc_dec_toptype([{T,_}|_]) when is_atom(T) ->
1611    T;
1612partial_inc_dec_toptype([L|_]) when is_list(L) ->
1613    partial_inc_dec_toptype(L);
1614partial_inc_dec_toptype(_) ->
1615    throw({error,{"no top type found for partial incomplete decode"}}).
1616
1617
1618%% Creats a list of tags out of the information in TypeList and Types
1619%% that tells which value will be decoded.  Each constructed type that
1620%% is in the TypeList will get a "choosen" command. Only the last
1621%% type/component in the TypeList may be a primitive type. Components
1622%% "on the way" to the final element may get the "skip" or the
1623%% "skip_optional" command.
1624%% CommandList = [Elements]
1625%% Elements = {choosen,Tag}|{skip_optional,Tag}|skip
1626%% Tag is a binary with the tag BER encoded.
1627create_partial_decode_gen_info(ModName,{ModName,TypeLists}) ->
1628    [create_partial_decode_gen_info1(ModName,TL) || TL <- TypeLists];
1629create_partial_decode_gen_info(_,[]) ->
1630    [];
1631create_partial_decode_gen_info(_M1,{M2,_}) ->
1632    throw({error,{"wrong module name in asn1 config file",
1633		  M2}}).
1634
1635create_partial_decode_gen_info1(ModName,{FuncName,TypeList}) ->
1636    case TypeList of
1637	[TopType|Rest] ->
1638	    case asn1_db:dbget(ModName,TopType) of
1639		#typedef{typespec=TS} ->
1640		    TagCommand = get_tag_command(TS,?CHOOSEN),
1641		    Ret=create_pdec_command(ModName,
1642					    get_components(TS#type.def),
1643					    Rest,concat_tags(TagCommand,[])),
1644		    {FuncName,Ret};
1645		_ ->
1646		    throw({error,{"wrong type list in asn1 config file",
1647				  TypeList}})
1648	    end;
1649	_ ->
1650	    []
1651    end;
1652create_partial_decode_gen_info1(_,_) ->
1653    ok.
1654
1655%% create_pdec_command/4 for each name (type or component) in the
1656%% third argument, TypeNameList, a command is created. The command has
1657%% information whether the component/type shall be skipped, looked
1658%% into or returned. The list of commands is returned.
1659create_pdec_command(_ModName,_,[],Acc) ->
1660    Remove_empty_lists =
1661	fun([[]|L],Res,Fun) ->
1662		Fun(L,Res,Fun);
1663	   ([],Res,_) ->
1664		Res;
1665	   ([H|L],Res,Fun) ->
1666		Fun(L,[H|Res],Fun)
1667	end,
1668    Remove_empty_lists(Acc,[],Remove_empty_lists);
1669create_pdec_command(ModName,[#'ComponentType'{name=C1,typespec=TS}|_Comps],
1670		    [C1|Cs],Acc) ->
1671    %% this component is a constructed type or the last in the
1672    %% TypeNameList otherwise the config spec is wrong
1673    TagCommand = get_tag_command(TS,?CHOOSEN),
1674    create_pdec_command(ModName,get_components(TS#type.def),
1675			Cs,concat_tags(TagCommand,Acc));
1676create_pdec_command(ModName,[#'ComponentType'{typespec=TS,
1677					      prop=Prop}|Comps],
1678		    [C2|Cs],Acc) ->
1679    TagCommand =
1680	case Prop of
1681	    mandatory ->
1682		get_tag_command(TS,?SKIP);
1683	    _ ->
1684		get_tag_command(TS,?SKIP_OPTIONAL)
1685	end,
1686    create_pdec_command(ModName,Comps,[C2|Cs],concat_tags(TagCommand,Acc));
1687create_pdec_command(ModName,{'CHOICE',[Comp=#'ComponentType'{name=C1}|_]},TNL=[C1|_Cs],Acc) ->
1688    create_pdec_command(ModName,[Comp],TNL,Acc);
1689create_pdec_command(ModName,{'CHOICE',[#'ComponentType'{}|Comps]},TNL,Acc) ->
1690    create_pdec_command(ModName,{'CHOICE',Comps},TNL,Acc);
1691create_pdec_command(ModName,#'Externaltypereference'{module=M,type=C1},
1692		    TypeNameList,Acc) ->
1693     #type{def=Def} = get_referenced_type(M,C1),
1694    create_pdec_command(ModName,get_components(Def),TypeNameList,
1695			Acc);
1696create_pdec_command(ModName,TS=#type{def=Def},[C1|Cs],Acc) ->
1697    %% This case when we got the "components" of a SEQUENCE/SET OF
1698    case C1 of
1699	[1] ->
1700	    %% A list with an integer is the only valid option in a 'S
1701	    %% OF', the other valid option would be an empty
1702	    %% TypeNameList saying that the entire 'S OF' will be
1703	    %% decoded.
1704	    TagCommand = get_tag_command(TS,?CHOOSEN),
1705	    create_pdec_command(ModName,Def,Cs,concat_tags(TagCommand,Acc));
1706	[N] when is_integer(N) ->
1707	    TagCommand = get_tag_command(TS,?SKIP),
1708	    create_pdec_command(ModName,Def,[[N-1]|Cs],
1709				concat_tags(TagCommand,Acc));
1710	Err ->
1711	    throw({error,{"unexpected error when creating partial "
1712			  "decode command",Err}})
1713    end;
1714create_pdec_command(_,_,TNL,_) ->
1715    throw({error,{"unexpected error when creating partial "
1716		  "decode command",TNL}}).
1717
1718get_components(#'SEQUENCE'{components={C1,C2}}) when is_list(C1),is_list(C2) ->
1719    C1++C2;
1720get_components(#'SEQUENCE'{components=Components}) ->
1721    Components;
1722get_components(#'SET'{components={C1,C2}}) when is_list(C1),is_list(C2) ->
1723    C1++C2;
1724get_components(#'SET'{components=Components}) ->
1725    Components;
1726get_components({'SEQUENCE OF',Components}) ->
1727    Components;
1728get_components({'SET OF',Components}) ->
1729    Components;
1730get_components(Def) ->
1731    Def.
1732
1733concat_sequential(L=[A,B],Acc) when is_atom(A),is_binary(B) ->
1734    [L|Acc];
1735concat_sequential(L,Acc) when is_list(L) ->
1736    concat_sequential1(lists:reverse(L),Acc);
1737concat_sequential(A,Acc)  ->
1738    [A|Acc].
1739concat_sequential1([],Acc) ->
1740    Acc;
1741concat_sequential1([[]],Acc) ->
1742    Acc;
1743concat_sequential1([El|RestEl],Acc) when is_list(El) ->
1744    concat_sequential1(RestEl,[El|Acc]);
1745concat_sequential1([mandatory|RestEl],Acc) ->
1746    concat_sequential1(RestEl,[mandatory|Acc]);
1747concat_sequential1(L,Acc) ->
1748    [L|Acc].
1749
1750
1751many_tags([?SKIP])->
1752    false;
1753many_tags([?SKIP_OPTIONAL,_]) ->
1754    false;
1755many_tags([?CHOOSEN,_]) ->
1756    false;
1757many_tags(_) ->
1758    true.
1759
1760concat_tags(Ts,Acc) ->
1761    case many_tags(Ts) of
1762	true when is_list(Ts) ->
1763	    lists:reverse(Ts)++Acc;
1764	true ->
1765	    [Ts|Acc];
1766	false ->
1767	    [Ts|Acc]
1768    end.
1769%% get_tag_command(Type,Command)
1770
1771%% Type is the type that has information about the tag Command tells
1772%% what to do with the encoded value with the tag of Type when
1773%% decoding.
1774get_tag_command(#type{tag=[]},_) ->
1775    [];
1776%% SKIP and SKIP_OPTIONAL shall return only one tag command regardless
1777get_tag_command(#type{},?SKIP) ->
1778    ?SKIP;
1779get_tag_command(#type{tag=Tags},?SKIP_OPTIONAL) ->
1780    Tag=hd(Tags),
1781    [?SKIP_OPTIONAL,encode_tag_val(decode_class(Tag#tag.class),
1782				   Tag#tag.form,Tag#tag.number)];
1783get_tag_command(#type{tag=[Tag]},Command) ->
1784    %% encode the tag according to BER
1785    [Command,encode_tag_val(decode_class(Tag#tag.class),Tag#tag.form,
1786			    Tag#tag.number)];
1787get_tag_command(T=#type{tag=[Tag|Tags]},Command) ->
1788    TC = get_tag_command(T#type{tag=[Tag]},Command),
1789    TCs = get_tag_command(T#type{tag=Tags},Command),
1790    case many_tags(TCs) of
1791	true when is_list(TCs) ->
1792	    [TC|TCs];
1793	_ -> [TC|[TCs]]
1794    end.
1795
1796%% get_tag_command/3 used by create_pdec_inc_command
1797get_tag_command(#type{tag=[]},_,_) ->
1798    [];
1799get_tag_command(#type{tag=[Tag]},?MANDATORY,Prop) ->
1800    case Prop of
1801	mandatory ->
1802	    ?MANDATORY;
1803	{'DEFAULT',_} ->
1804	    [?DEFAULT,encode_tag_val(decode_class(Tag#tag.class),
1805				     Tag#tag.form,Tag#tag.number)];
1806	_ -> [?OPTIONAL,encode_tag_val(decode_class(Tag#tag.class),
1807				       Tag#tag.form,Tag#tag.number)]
1808    end;
1809get_tag_command(#type{tag=[Tag]},Command,Prop) ->
1810    [anonymous_dec_command(Command,Prop),encode_tag_val(decode_class(Tag#tag.class),Tag#tag.form, Tag#tag.number)];
1811get_tag_command(#type{tag=Tag},Command,Prop) when is_record(Tag,tag) ->
1812    get_tag_command(#type{tag=[Tag]},Command,Prop);
1813get_tag_command(T=#type{tag=[Tag|Tags]},Command,Prop) ->
1814    [get_tag_command(T#type{tag=[Tag]},Command,Prop)|[
1815     get_tag_command(T#type{tag=Tags},Command,Prop)]].
1816
1817anonymous_dec_command(?UNDECODED,'OPTIONAL') ->
1818    ?OPTIONAL_UNDECODED;
1819anonymous_dec_command(Command,_) ->
1820    Command.
1821
1822get_referenced_type(M,Name) ->
1823    case asn1_db:dbget(M,Name) of
1824	#typedef{typespec=TS} ->
1825	    case TS of
1826		#type{def=#'Externaltypereference'{module=M2,type=Name2}} ->
1827		    %% The tags have already been taken care of in the
1828		    %% first reference where they were gathered in a
1829		    %% list of tags.
1830		    get_referenced_type(M2,Name2);
1831		#type{} -> TS;
1832		_  ->
1833		    throw({error,{"unexpected element when"
1834				  " fetching referenced type",TS}})
1835	    end;
1836	T ->
1837	    throw({error,{"unexpected element when fetching "
1838			  "referenced type",T}})
1839    end.
1840
1841
1842tlv_tags([]) ->
1843    [];
1844tlv_tags([mandatory|Rest]) ->
1845    [mandatory|tlv_tags(Rest)];
1846tlv_tags([[Command,Tag]|Rest]) when is_atom(Command),is_binary(Tag) ->
1847    [[Command,tlv_tag(Tag)]|tlv_tags(Rest)];
1848tlv_tags([[Command,Directives]|Rest]) when is_atom(Command),is_list(Directives) ->
1849    [[Command,tlv_tags(Directives)]|tlv_tags(Rest)];
1850%% remove all empty lists
1851tlv_tags([[]|Rest]) ->
1852    tlv_tags(Rest);
1853tlv_tags([{Name,TopType,L1}|Rest]) when is_list(L1),is_atom(TopType) ->
1854    [{Name,TopType,tlv_tags(L1)}|tlv_tags(Rest)];
1855tlv_tags([[Command,Tag,L1]|Rest]) when is_list(L1),is_binary(Tag) ->
1856    [[Command,tlv_tag(Tag),tlv_tags(L1)]|tlv_tags(Rest)];
1857tlv_tags([[mandatory|Rest]]) ->
1858    [[mandatory|tlv_tags(Rest)]];
1859tlv_tags([L=[L1|_]|Rest]) when is_list(L1) ->
1860    [tlv_tags(L)|tlv_tags(Rest)].
1861
1862tlv_tag(<<Cl:2,_:1,TagNo:5>>) when TagNo < 31 ->
1863    (Cl bsl 16) + TagNo;
1864tlv_tag(<<Cl:2,_:1,31:5,0:1,TagNo:7>>) ->
1865    (Cl bsl 16) + TagNo;
1866tlv_tag(<<Cl:2,_:1,31:5,Buffer/binary>>) ->
1867    TagNo = tlv_tag1(Buffer,0),
1868    (Cl bsl 16) + TagNo.
1869tlv_tag1(<<0:1,PartialTag:7>>,Acc) ->
1870    (Acc bsl 7) bor PartialTag;
1871tlv_tag1(<<1:1,PartialTag:7,Buffer/binary>>,Acc) ->
1872    tlv_tag1(Buffer,(Acc bsl 7) bor PartialTag).
1873
1874%% Reads the content from the configuration file and returns the
1875%% selected part chosen by InfoType. Assumes that the config file
1876%% content is an Erlang term.
1877read_config_file_info(ModuleName, InfoType) when is_atom(InfoType) ->
1878    Name = ensure_ext(ModuleName, ".asn1config"),
1879    CfgList = read_config_file0(Name, []),
1880    get_config_info(CfgList, InfoType).
1881
1882read_config_file(#gen{options=Options}, ModuleName) ->
1883    Name = ensure_ext(ModuleName, ".asn1config"),
1884    Includes = [I || {i,I} <- Options],
1885    read_config_file0(Name, ["."|Includes]).
1886
1887read_config_file0(Name, [D|Dirs]) ->
1888    case file:consult(filename:join(D, Name)) of
1889	{ok,CfgList} ->
1890	    CfgList;
1891	{error,enoent} ->
1892            read_config_file0(Name, Dirs);
1893	{error,Reason} ->
1894	    Error = "error reading asn1 config file: " ++
1895		file:format_error(Reason),
1896	    throw({error,Error})
1897    end;
1898read_config_file0(_, []) ->
1899    no_config_file.
1900
1901ensure_ext(ModuleName, Ext) ->
1902    Name = filename:join([ModuleName]),
1903    case filename:extension(Name) of
1904        Ext -> Name;
1905        _ -> Name ++ Ext
1906    end.
1907
1908get_config_info(CfgList,InfoType) ->
1909    case lists:keysearch(InfoType,1,CfgList) of
1910	{value,{InfoType,Value}} ->
1911	    Value;
1912	false ->
1913	    []
1914    end.
1915
1916%% save_config/2 saves the Info with the key Key
1917%% Before saving anything check if a table exists
1918%% The record gen_state is saved with the key {asn1_config,gen_state}
1919save_config(Key,Info) ->
1920    asn1ct_table:new_reuse(asn1_general),
1921    asn1ct_table:insert(asn1_general, {{asn1_config, Key}, Info}).
1922
1923read_config_data(Key) ->
1924    case asn1ct_table:exists(asn1_general) of
1925	false -> undefined;
1926	true ->
1927	    case asn1ct_table:lookup(asn1_general,{asn1_config,Key}) of
1928		[{_,Data}] -> Data;
1929		Err ->
1930                    %% Err is [] when nothing was saved in the ets table
1931		    Err
1932	    end
1933    end.
1934
1935
1936%%
1937%% Functions to manipulate the gen_state record saved in the
1938%% asn1_general ets table.
1939%%
1940
1941%% saves input data in a new gen_state record
1942save_gen_state(exclusive_decode,{_,ConfList},PartIncTlvTagList) ->
1943    State =
1944	case get_gen_state() of
1945	    S when is_record(S,gen_state) -> S;
1946	    _ -> #gen_state{}
1947	end,
1948    StateRec = State#gen_state{inc_tag_pattern=PartIncTlvTagList,
1949			       inc_type_pattern=ConfList},
1950    save_config(gen_state,StateRec);
1951save_gen_state(_,_,_) ->
1952    case get_gen_state() of
1953	S when is_record(S,gen_state) -> ok;
1954	_ -> save_config(gen_state,#gen_state{})
1955    end.
1956
1957save_gen_state(selective_decode,{_,Type_component_name_list}) ->
1958    State =
1959	case get_gen_state() of
1960	    S when is_record(S,gen_state) -> S;
1961	    _ -> #gen_state{}
1962	end,
1963    StateRec = State#gen_state{type_pattern=Type_component_name_list},
1964    save_config(gen_state,StateRec);
1965save_gen_state(selective_decode,_) ->
1966    ok.
1967
1968save_gen_state(GenState) when is_record(GenState,gen_state) ->
1969    save_config(gen_state,GenState).
1970
1971
1972%% get_gen_state_field returns undefined if no gen_state exists or if
1973%% Field is undefined or the data at the field.
1974get_gen_state_field(Field) ->
1975    case read_config_data(gen_state) of
1976	undefined ->
1977	    undefined;
1978	GenState when is_record(GenState,gen_state) ->
1979	    get_gen_state_field(GenState,Field);
1980	Err ->
1981	    exit({error,{asn1,{"false configuration file info",Err}}})
1982    end.
1983get_gen_state_field(#gen_state{active=Active},active) ->
1984    Active;
1985get_gen_state_field(_,active) ->
1986    false;
1987get_gen_state_field(GS,prefix) ->
1988    GS#gen_state.prefix;
1989get_gen_state_field(GS,inc_tag_pattern) ->
1990    GS#gen_state.inc_tag_pattern;
1991get_gen_state_field(GS,tag_pattern) ->
1992    GS#gen_state.tag_pattern;
1993get_gen_state_field(GS,inc_type_pattern) ->
1994    GS#gen_state.inc_type_pattern;
1995get_gen_state_field(GS,type_pattern) ->
1996    GS#gen_state.type_pattern;
1997get_gen_state_field(GS,func_name) ->
1998    GS#gen_state.func_name;
1999get_gen_state_field(GS,namelist) ->
2000    GS#gen_state.namelist;
2001get_gen_state_field(GS,tobe_refed_funcs) ->
2002    GS#gen_state.tobe_refed_funcs;
2003get_gen_state_field(GS,gen_refed_funcs) ->
2004    GS#gen_state.gen_refed_funcs;
2005get_gen_state_field(GS,generated_functions) ->
2006    GS#gen_state.generated_functions;
2007get_gen_state_field(GS,suffix_index) ->
2008    GS#gen_state.suffix_index;
2009get_gen_state_field(GS,current_suffix_index) ->
2010    GS#gen_state.current_suffix_index.
2011
2012get_gen_state() ->
2013    read_config_data(gen_state).
2014
2015
2016update_gen_state(Field,Data) ->
2017    case get_gen_state() of
2018	State when is_record(State,gen_state) ->
2019	    update_gen_state(Field,State,Data);
2020	_ ->
2021	    exit({error,{asn1,{internal,
2022			       "tried to update nonexistent gen_state",Field,Data}}})
2023    end.
2024update_gen_state(active,State,Data) ->
2025    save_gen_state(State#gen_state{active=Data});
2026update_gen_state(prefix,State,Data) ->
2027    save_gen_state(State#gen_state{prefix=Data});
2028update_gen_state(inc_tag_pattern,State,Data) ->
2029    save_gen_state(State#gen_state{inc_tag_pattern=Data});
2030update_gen_state(tag_pattern,State,Data) ->
2031    save_gen_state(State#gen_state{tag_pattern=Data});
2032update_gen_state(inc_type_pattern,State,Data) ->
2033    save_gen_state(State#gen_state{inc_type_pattern=Data});
2034update_gen_state(type_pattern,State,Data) ->
2035    save_gen_state(State#gen_state{type_pattern=Data});
2036update_gen_state(func_name,State,Data) ->
2037    save_gen_state(State#gen_state{func_name=Data});
2038update_gen_state(namelist,State,Data) ->
2039    save_gen_state(State#gen_state{namelist=Data});
2040update_gen_state(tobe_refed_funcs,State,Data) ->
2041    save_gen_state(State#gen_state{tobe_refed_funcs=Data});
2042update_gen_state(gen_refed_funcs,State,Data) ->
2043    save_gen_state(State#gen_state{gen_refed_funcs=Data});
2044update_gen_state(generated_functions,State,Data) ->
2045    save_gen_state(State#gen_state{generated_functions=Data});
2046update_gen_state(suffix_index,State,Data) ->
2047    save_gen_state(State#gen_state{suffix_index=Data});
2048update_gen_state(current_suffix_index,State,Data) ->
2049    save_gen_state(State#gen_state{current_suffix_index=Data}).
2050
2051update_namelist(Name) ->
2052    case get_gen_state_field(namelist) of
2053	[Name,Rest] -> update_gen_state(namelist,Rest);
2054	[Name|Rest] -> update_gen_state(namelist,Rest);
2055	[{Name,List}] when is_list(List) -> update_gen_state(namelist,List);
2056	[{Name,Atom}|Rest] when is_atom(Atom) -> update_gen_state(namelist,Rest);
2057	Other -> Other
2058    end.
2059
2060%% removes a bracket from the namelist
2061step_in_constructed() ->
2062    case get_gen_state_field(namelist) of
2063	[L] when is_list(L) ->
2064	    update_gen_state(namelist,L);
2065	_ -> ok
2066    end.
2067
2068is_function_generated(Name) ->
2069    case get_gen_state_field(gen_refed_funcs) of
2070	L when is_list(L) ->
2071	    lists:member(Name,L);
2072	_ ->
2073	    false
2074    end.
2075
2076get_tobe_refed_func(Name) ->
2077    case get_gen_state_field(tobe_refed_funcs) of
2078	L when is_list(L) ->
2079	    case lists:keysearch(Name,1,L) of
2080		{_,Element} ->
2081		    Element;
2082		_ ->
2083		    undefined
2084	    end;
2085	_ ->
2086	    undefined
2087    end.
2088
2089%% add_tobe_refed_func saves Data that is a three or four element
2090%% tuple.  Do not save if it exists in generated_functions, because
2091%% then it will be or already is generated.
2092add_tobe_refed_func(Data) ->
2093    {Name,SI,Pattern} =
2094	fun({N,Si,P,_}) -> {N,Si,P};
2095	    (D) -> D end (Data),
2096    NewData =
2097	case SI of
2098	    I when is_integer(I) ->
2099		fun(D) -> D end(Data);
2100	    _ ->
2101		fun({N,_,P}) -> {N,0,P};
2102		   ({N,_,P,T}) -> {N,0,P,T} end (Data)
2103	end,
2104
2105    L = get_gen_state_field(generated_functions),
2106    case generated_functions_member(get(currmod),Name,L,Pattern) of
2107	true ->
2108            %% it exists in generated_functions, it has already
2109            %% been generated or saved in tobe_refed_func
2110	    ok;
2111	_ ->
2112	    add_once_tobe_refed_func(NewData),
2113	    %% only to get it saved in generated_functions
2114	    maybe_rename_function(tobe_refed,Name,Pattern)
2115    end.
2116
2117
2118
2119%% Adds only one element with same Name and Index where Data =
2120%% {Name,Index,Pattern}.
2121add_once_tobe_refed_func(Data) ->
2122    TRFL = get_gen_state_field(tobe_refed_funcs),
2123    {Name,Index} = {element(1,Data),element(2,Data)},
2124    case lists:filter(fun({N,I,_}) when N==Name,I==Index ->true;
2125			 ({N,I,_,_}) when N==Name,I==Index -> true;
2126			 (_) -> false end,TRFL) of
2127	[] ->
2128	    update_gen_state(tobe_refed_funcs,[Data|TRFL]);
2129	_ ->
2130	    ok
2131    end.
2132
2133
2134%% Moves Name from the to be list to the generated list.
2135generated_refed_func(Name) ->
2136    L = get_gen_state_field(tobe_refed_funcs),
2137    NewL = lists:keydelete(Name,1,L),
2138    update_gen_state(tobe_refed_funcs,NewL),
2139    L2 = get_gen_state_field(gen_refed_funcs),
2140    update_gen_state(gen_refed_funcs,[Name|L2]).
2141
2142%% Adds Data to gen_refed_funcs field in gen_state.
2143add_generated_refed_func(Data) ->
2144    case is_function_generated(Data) of
2145	true ->
2146	    ok;
2147	_ ->
2148	    L = get_gen_state_field(gen_refed_funcs),
2149	    update_gen_state(gen_refed_funcs,[Data|L])
2150    end.
2151
2152next_refed_func() ->
2153    case get_gen_state_field(tobe_refed_funcs) of
2154	[] ->
2155	    [];
2156	[H|T] ->
2157	    update_gen_state(tobe_refed_funcs,T),
2158	    H
2159    end.
2160
2161reset_gen_state() ->
2162    save_gen_state(#gen_state{}).
2163
2164%% Adds Data to generated_functions field in gen_state.
2165add_generated_function(Data) ->
2166    L = get_gen_state_field(generated_functions),
2167    update_gen_state(generated_functions,[Data|L]).
2168
2169
2170%% Each type has its own index starting from 0. If index is 0 there is
2171%% no renaming.
2172maybe_rename_function(Mode,Name,Pattern) ->
2173    case get_gen_state_field(generated_functions) of
2174	[] when Mode==inc_disp -> add_generated_function({Name,0,Pattern}),
2175	      Name;
2176	[] ->
2177	    exit({error,{asn1,internal_error_exclusive_decode}});
2178	L ->
2179	    case {Mode,generated_functions_member(get(currmod),Name,L)} of
2180		{_,true} ->
2181		    L2 = generated_functions_filter(get(currmod),Name,L),
2182		    case lists:keysearch(Pattern,3,L2) of
2183			false ->
2184                            %% name existed, but not pattern
2185			    NextIndex = length(L2),
2186			    %% rename function
2187			    Suffix = lists:concat(["_",NextIndex]),
2188			    NewName =
2189				maybe_rename_function2(type_check(Name),Name,
2190						       Suffix),
2191			    add_generated_function({Name,NextIndex,Pattern}),
2192			    NewName;
2193			Value ->
2194                            %% name and pattern existed
2195			    %% do not save any new index
2196			    Suffix = make_suffix(Value),
2197			    Name2 =
2198				case Name of
2199				    #'Externaltypereference'{type=T} -> T;
2200				    _ -> Name
2201				end,
2202			    lists:concat([Name2,Suffix])
2203		    end;
2204		{inc_disp,_} ->
2205                    %% this is when decode_partial_inc_disp/2 is
2206                    %% generated
2207		    add_generated_function({Name,0,Pattern}),
2208		    Name;
2209		_ -> % this if call from add_tobe_refed_func
2210		    add_generated_function({Name,0,Pattern}),
2211		    Name
2212	    end
2213    end.
2214
2215
2216maybe_rename_function2(record,#'Externaltypereference'{type=Name},Suffix) ->
2217    lists:concat([Name,Suffix]);
2218maybe_rename_function2(list,List,Suffix) ->
2219    lists:concat([asn1ct_gen:list2name(List),Suffix]);
2220maybe_rename_function2(Thing,Name,Suffix)
2221  when Thing==atom;Thing==integer;Thing==string ->
2222    lists:concat([Name,Suffix]).
2223
2224%% generated_functions_member/4 checks on both Name and Pattern if
2225%%  the element exists in L
2226generated_functions_member(M,Name,L,Pattern) ->
2227    case generated_functions_member(M,Name,L) of
2228	true ->
2229	    L2 = generated_functions_filter(M,Name,L),
2230	    case lists:keysearch(Pattern,3,L2) of
2231		{value,_} ->
2232		    true;
2233		_ -> false
2234	    end;
2235	_ -> false
2236    end.
2237
2238generated_functions_member(_M,Name,[{Name,_,_}|_]) ->
2239    true;
2240generated_functions_member(M,#'Externaltypereference'{module=M,type=T},
2241			   [{#'Externaltypereference'{module=M,type=T}
2242			     ,_,_}|_]) ->
2243    true;
2244generated_functions_member(M,#'Externaltypereference'{module=M,type=Name},
2245			  [{Name,_,_}|_]) ->
2246    true;
2247generated_functions_member(M,Name,[_|T]) ->
2248    generated_functions_member(M,Name,T);
2249generated_functions_member(_,_,[]) ->
2250    false.
2251
2252generated_functions_filter(_,Name,L) when is_atom(Name);is_list(Name) ->
2253    lists:filter(fun({N,_,_}) when N==Name -> true;
2254		    (_) -> false
2255		 end, L);
2256generated_functions_filter(M,#'Externaltypereference'{module=M,type=Name},L)->
2257    %% remove top typename from patterns
2258    RemoveTType =
2259	fun({N,I,[N,P]}) when N == Name ->
2260		{N,I,P};
2261	   ({#'Externaltypereference'{module=M1,type=N},I,P}) when M1==M ->
2262		{N,I,P};
2263	   (P) -> P
2264	end,
2265    L2 = lists:map(RemoveTType,L),
2266    generated_functions_filter(M,Name,L2).
2267
2268
2269maybe_saved_sindex(Name,Pattern) ->
2270    case get_gen_state_field(generated_functions) of
2271	[] -> false;
2272	L ->
2273	    case generated_functions_member(get(currmod),Name,L) of
2274		true ->
2275		    L2 = generated_functions_filter(get(currmod),Name,L),
2276		    case lists:keysearch(Pattern,3,L2) of
2277			{value,{_,I,_}} ->
2278			    I;
2279			_ -> length(L2) % this should be length(L2)!
2280		    end;
2281		_ -> false
2282	    end
2283    end.
2284
2285current_sindex() ->
2286    get_gen_state_field(current_suffix_index).
2287
2288set_current_sindex(Index) ->
2289    update_gen_state(current_suffix_index,Index).
2290
2291
2292type_check(A) when is_atom(A) ->
2293    atom;
2294type_check(L) when is_list(L) ->
2295    Pred = fun(X) when X=<255 ->
2296		   false;
2297	      (_) -> true
2298	   end,
2299    case lists:filter(Pred,L) of
2300	[] ->
2301	    string;
2302	_ ->
2303	    list
2304    end;
2305type_check(#'Externaltypereference'{}) ->
2306    record.
2307
2308 make_suffix({_,{_,0,_}}) ->
2309     "";
2310 make_suffix({_,{_,I,_}}) ->
2311     lists:concat(["_",I]);
2312 make_suffix(_) ->
2313     "".
2314
2315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2316%% Report functions.
2317%%
2318%% Error messages are controlled with the 'errors' compiler option
2319%% Warning messages are controlled with the 'warnings' compiler option
2320%% Verbose messages are controlled with the 'verbose' compiler option
2321
2322error(Format, Args, S) ->
2323    case is_error(S) of
2324	true ->
2325	    io:format(Format, Args);
2326	false ->
2327	    ok
2328    end.
2329
2330warning(Format, Args, S) ->
2331    case is_warning(S) of
2332	true ->
2333	    io:format("Warning: " ++ Format, Args);
2334	false ->
2335	    ok
2336    end.
2337
2338warning(Format, Args, S, Reason) ->
2339    case {is_werr(S), is_error(S), is_warning(S)} of
2340	{true, true, _} ->
2341	    io:format(Format, Args),
2342	    throw({error, Reason});
2343	{false, _, true} ->
2344	    io:format(Format, Args);
2345	_ ->
2346	    ok
2347    end.
2348
2349verbose(Format, Args, S) ->
2350    case is_verbose(S) of
2351	true ->
2352	    io:format(Format, Args);
2353	false ->
2354	    ok
2355    end.
2356
2357format_error({write_error,File,Reason}) ->
2358    io_lib:format("writing output file ~s failed: ~s",
2359		  [File,file:format_error(Reason)]).
2360
2361is_error(#state{options=Opts}) ->
2362    is_error(Opts);
2363is_error(#gen{options=Opts}) ->
2364    is_error(Opts);
2365is_error(O) ->
2366    lists:member(errors, O) orelse is_verbose(O).
2367
2368is_warning(S) when is_record(S, state) ->
2369    is_warning(S#state.options);
2370is_warning(O) ->
2371    lists:member(warnings, O) orelse is_verbose(O).
2372
2373is_verbose(#state{options=Opts}) ->
2374    is_verbose(Opts);
2375is_verbose(#gen{options=Opts}) ->
2376    is_verbose(Opts);
2377is_verbose(O) ->
2378    lists:member(verbose, O).
2379
2380is_werr(S) when is_record(S, state) ->
2381    is_werr(S#state.options);
2382is_werr(O) ->
2383    lists:member(warnings_as_errors, O).
2384
2385
2386in_process(Fun) ->
2387    Parent = self(),
2388    Pid = spawn_link(fun() -> process(Parent, Fun) end),
2389    receive
2390        {Pid, Result}               -> Result;
2391        {Pid, Class, Reason, Stack} ->
2392            ST = try throw(x) catch throw:x:Stk -> Stk end,
2393            erlang:raise(Class, Reason, Stack ++ ST)
2394    end.
2395
2396process(Parent, Fun) ->
2397    try
2398        Parent ! {self(), Fun()}
2399    catch Class:Reason:Stack ->
2400        Parent ! {self(), Class, Reason, Stack}
2401    end.
2402