diff options
author | Adam Lindberg <[email protected]> | 2012-01-12 15:42:21 +0100 |
---|---|---|
committer | Adam Lindberg <[email protected]> | 2012-02-28 14:59:32 +0100 |
commit | aa4e27ebac9eb287069fab859fe5dcdab82c75bf (patch) | |
tree | 7303d7d5f04c888a7934b783937ac2e3dc7f978a /lib/asn1/src/asn1ct.erl | |
parent | 93f0641c2122d6c23e2ac5f18579ef879599fc16 (diff) | |
download | otp-aa4e27ebac9eb287069fab859fe5dcdab82c75bf.tar.gz otp-aa4e27ebac9eb287069fab859fe5dcdab82c75bf.tar.bz2 otp-aa4e27ebac9eb287069fab859fe5dcdab82c75bf.zip |
[asn1] Make tables and processes unnamed
- Refactor and clean up asn1_db process
- Remove unused stop function in asn1ct.erl
- Remove infinite loop possibilites in asn1ct_check.erl
- test/1,2,3 now run in separate process
- Update documentation for new test options
Diffstat (limited to 'lib/asn1/src/asn1ct.erl')
-rw-r--r-- | lib/asn1/src/asn1ct.erl | 367 |
1 files changed, 194 insertions, 173 deletions
diff --git a/lib/asn1/src/asn1ct.erl b/lib/asn1/src/asn1ct.erl index 39082307cb..2d17f73a2c 100644 --- a/lib/asn1/src/asn1ct.erl +++ b/lib/asn1/src/asn1ct.erl @@ -1,3 +1,4 @@ +%% vim: tabstop=8:shiftwidth=4 %% %% %CopyrightBegin% %% @@ -24,12 +25,12 @@ %%-compile(export_all). %% Public exports -export([compile/1, compile/2]). --export([start/0, start/1, stop/0]). +-export([start/0, start/1]). -export([encode/2, encode/3, decode/3]). --export([test/1, test/2, test/3, value/2]). +-export([test/1, test/2, test/3, value/2, value/3]). %% Application internal exports -export([compile_asn/3,compile_asn1/3,compile_py/3,compile/3, - value/1,vsn/0, + vsn/0, get_name_of_def/1,get_pos_of_def/1]). -export([read_config_data/1,get_gen_state_field/1,get_gen_state/0, partial_inc_dec_toptype/1,save_gen_state/1,update_gen_state/2, @@ -93,29 +94,23 @@ compile(File,Options) when is_list(Options) -> end, Options1 = optimize_ber_bin(Options), Options2 = includes(File,Options1), - Includes=[I||{i,I}<-Options2], - Parent = self(), - Pid = spawn_link(fun() -> - compile_proc(File, Includes, Options2, Parent) - end), - receive {Pid, Result} -> Result end. - -compile_proc(File, Includes, Options, Parent) -> - Result = case (catch input_file_type(File, Includes)) of - {single_file, SuffixedFile} -> %% "e.g. "/tmp/File.asn" - (catch compile1(SuffixedFile, Options)); - {multiple_files_file, SetBase, FileName} -> - case get_file_list(FileName, Includes) of - FileList when is_list(FileList) -> - (catch compile_set(SetBase, FileList, Options)); - Err -> - Err - end; - Err = {input_file_error, _Reason} -> - {error, Err}; - Err2 -> Err2 - end, - Parent ! {self(), Result}. + Includes = strip_includes(Options2), + in_process(fun() -> compile_proc(File, Includes, Options2) end). + +compile_proc(File, Includes, Options) -> + case input_file_type(File, Includes) of + {single_file, SuffixedFile} -> %% "e.g. "/tmp/File.asn" + compile1(SuffixedFile, Options); + {multiple_files_file, SetBase, FileName} -> + case get_file_list(FileName, Includes) of + FileList when is_list(FileList) -> + compile_set(SetBase, FileList, Options); + Err -> + Err + end; + Err = {input_file_error, _Reason} -> + {error, Err} + end. compile1(File,Options) when is_list(Options) -> verbose("Erlang ASN.1 version ~p compiling ~p ~n",[?vsn,File],Options), @@ -126,7 +121,7 @@ compile1(File,Options) when is_list(Options) -> DbFile = outfile(Base,"asn1db",Options), Includes = [I || {i,I} <- Options], EncodingRule = get_rule(Options), - asn1ct_table:new(asn1_functab, [named_table]), + asn1ct_table:new(asn1_functab), Continue1 = scan(File,Options), Continue2 = parse(Continue1,File,Options), Continue3 = check(Continue2,File,OutFile,Includes,EncodingRule, @@ -194,7 +189,7 @@ compile_set(SetBase,Files,Options) DbFile = outfile(SetBase,"asn1db",Options), Includes = [I || {i,I} <- Options], EncodingRule = get_rule(Options), - asn1ct_table:new(asn1_functab, [named_table]), + asn1ct_table:new(asn1_functab), ScanRes = scan_set(Files,Options), ParseRes = parse_set(ScanRes,Options), Result = @@ -276,7 +271,7 @@ merge_modules(ParseRes,CommonName) -> %% causes an exit if duplicate definition names exist in a module remove_name_collisions(Modules) -> - asn1ct_table:new(renamed_defs, [named_table]), + asn1ct_table:new(renamed_defs), %% Name duplicates in the same module is not allowed. lists:foreach(fun exit_if_nameduplicate/1,Modules), %% Then remove duplicates in different modules and return the @@ -489,7 +484,7 @@ save_imports(ModuleList)-> [] -> ok; ImportsList2 -> - asn1ct_table:new(original_imports, [named_table]), + asn1ct_table:new(original_imports), lists:foreach(fun(X) -> asn1ct_table:insert(original_imports, X) end, ImportsList2) end. @@ -567,7 +562,7 @@ check_tagdefault(ModList) -> case have_same_tagdefault(ModList) of {true,TagDefault} -> TagDefault; {false,TagDefault} -> - asn1ct_table:new(automatic_tags, [named_table]), + asn1ct_table:new(automatic_tags), save_automatic_tagged_types(ModList), TagDefault end. @@ -833,22 +828,14 @@ generate({true,{M,_Module,GenTOrV}},OutFile,EncodingRule,Options) -> _ -> ok end, put(encoding_options,Options), - asn1ct_table:new(check_functions, [named_table]), + asn1ct_table:new(check_functions), %% create decoding function names and taglists for partial decode - %% For the time being leave errors unnoticed !!!!!!!!! -% io:format("Options: ~p~n",[Options]), - case catch specialized_decode_prepare(EncodingRule,M,GenTOrV,Options) of - {error, enoent} -> ok; - {error, Reason} -> warning("Error in configuration " - "file: ~n~p~n",[Reason],Options, - "Error in configuration file"); - {'EXIT',Reason} -> warning("Internal error when " - "analyzing configuration " - "file: ~n~p~n",[Reason],Options, - "Internal error when " - "analyzing configuration"); - _ -> ok + case specialized_decode_prepare(EncodingRule,M,GenTOrV,Options) of + {error, Reason} -> warning("Error in configuration file: ~n~p~n", + [Reason], Options, + "Error in configuration file"); + _ -> ok end, Result = @@ -1187,17 +1174,28 @@ optimize_ber_bin(Options) -> end. includes(File,Options) -> - Dir = filename:dirname(File), - Options2 = - case lists:member({i,"."},Options) of - false -> Options ++ [{i,"."}]; - _ -> Options - end, - case lists:member({i,Dir}, Options2) of - false -> Options2 ++ [{i,Dir}]; - _ -> Options2 + Options2 = include_append(".", Options), + Options3 = include_append(filename:dirname(File), Options2), + case proplists:get_value(outdir, Options) of + undefined -> Options3; + OutDir -> include_prepend(OutDir, Options3) + end. + +include_append(Dir, Options) -> + option_add({i, Dir}, Options, fun(Opts) -> Opts ++ [{i, Dir}] end). + +include_prepend(Dir, Options) -> + option_add({i, Dir}, Options, fun(Opts) -> [{i, Dir}|Opts] end). + +option_add(Option, Options, Fun) -> + case lists:member(Option, Options) of + true -> Options; + false -> Fun(Options) end. +strip_includes(Includes) -> + [I || {i, I} <- Includes]. + is_inline(Options) -> case lists:member(inline,Options) of true -> true; @@ -1227,10 +1225,7 @@ compile_py(File,OutFile,Options) -> compile(lists:concat([File,".py"]),OutFile,Options). compile(File, _OutFile, Options) -> - case catch compile(File, make_erl_options(Options)) of - Exit = {'EXIT',_Reason} -> - error("~p~n~s~n",[Exit,"error"],Options), - error; + case compile(File, make_erl_options(Options)) of {error,_Reason} -> %% case occurs due to error in asn1ct_parser2,asn1ct_check %% io:format("~p~n",[_Reason]), @@ -1243,10 +1238,7 @@ compile(File, _OutFile, Options) -> ok; ScanRes when is_list(ScanRes) -> io:format("~p~n",[ScanRes]), - ok; - Unknown -> - error("~p~n~s~n",[Unknown,"error"],Options), - error + ok end. %% Converts generic compiler options to specific options. @@ -1345,17 +1337,6 @@ start() -> start(Includes) when is_list(Includes) -> asn1_db:dbstart(Includes). -stop() -> - save(), - asn1_db:stop_server(ns), - asn1_db:stop_server(rand), - stopped. - -save() -> - asn1_db:dbstop(). - -%%clear() -> -%% asn1_db:dbclear(). encode(Module,Term) -> asn1rt:encode(Module,Term). @@ -1371,94 +1352,116 @@ decode(Module,Type,Bytes) -> asn1rt:decode(Module,Type,Bytes). -test(Module) -> - start(), - M = asn1_db:dbget(Module,'MODULE'), - {Types,_Values,_Ptypes,_Classes,_Objects,_ObjectSets} = M#module.typeorval, - test_each(Module,Types). - -test_each(Module,[Type | Rest]) -> - case test(Module,Type) of - {ok,_Result} -> - test_each(Module,Rest); - Error -> - Error +test(Module) -> test_module(Module, []). + +test(Module, [] = Options) -> test_module(Module, Options); +test(Module, [{i, _}|_] = Options) -> test_module(Module, Options); +test(Module, Type) -> test_type(Module, Type, []). + +test(Module, Type, [] = Options) -> test_type(Module, Type, Options); +test(Module, Type, [{i, _}|_] = Options) -> test_type(Module, Type, Options); +test(Module, Type, Value) -> test_value(Module, Type, Value). + +test_module(Module, Includes) -> + in_process(fun() -> + start(strip_includes(Includes)), + case check(Module, Includes) of + {ok, NewTypes} -> test_each(Module, NewTypes); + Error -> Error + end + end). + +test_each(Module, [Type|Rest]) -> + case test_type(Module, Type) of + {ok, _Result} -> test_each(Module, Rest); + Error -> Error end; test_each(_,[]) -> ok. -test(Module,Type) -> - io:format("~p:~p~n",[Module,Type]), - case (catch value(Module,Type)) of - {ok,Val} -> - %% io:format("asn1ct:test/2: ~w~n",[Val]), - test(Module,Type,Val); - {'EXIT',Reason} -> - {error,{asn1,{value,Reason}}} +test_type(Module, Type, Includes) -> + in_process(fun() -> + start(strip_includes(Includes)), + case check(Module, Includes) of + {ok, _NewTypes} -> test_type(Module, Type); + Error -> Error + end + end). + +test_type(Module, Type) -> + case get_value(Module, Type) of + {ok, Val} -> test_value(Module, Type, Val); + {error, Reason} -> {error, {asn1, {value, Reason}}} end. +test_value(Module, Type, Value) -> + in_process(fun() -> + case catch encode(Module, Type, Value) of + {ok, Bytes} -> + M = to_atom(Module), + NewBytes = prepare_bytes(M:encoding_rule(), Bytes), + case decode(Module, Type, NewBytes) of + {ok, Value} -> + {ok, {Module, Type, Value}}; + {ok, Res} -> + {error, {asn1, + {encode_decode_mismatch, + {{Module, Type, Value}, Res}}}}; + Error -> + {error, {asn1, + {{decode, + {Module, Type, Value}, Error}}}} + end; + Error -> + {error, {asn1, + {encode, {{Module, Type, Value}, Error}}}} + end + end). + +value(Module, Type) -> value(Module, Type, []). + +value(Module, Type, Includes) -> + in_process(fun() -> + start(strip_includes(Includes)), + case check(Module, Includes) of + {ok, _NewTypes} -> get_value(Module, Type); + Error -> Error + end + end). + +get_value(Module, Type) -> + case asn1ct_value:from_type(Module, Type) of + {error, Reason} -> {error, Reason}; + Result -> {ok, Result} + end. -test(Module,Type,Value) -> - case catch encode(Module,Type,Value) of - {ok,Bytes} -> - %% io:format("test 1: ~p~n",[{Bytes}]), - M = if - is_list(Module) -> - list_to_atom(Module); - true -> - Module - end, - NewBytes = - case M:encoding_rule() of - ber -> - lists:flatten(Bytes); - ber_bin when is_binary(Bytes) -> - Bytes; - ber_bin -> - list_to_binary(Bytes); - ber_bin_v2 when is_binary(Bytes) -> - Bytes; - ber_bin_v2 -> - list_to_binary(Bytes); - per -> - lists:flatten(Bytes); - per_bin when is_binary(Bytes) -> - Bytes; - per_bin -> - list_to_binary(Bytes); - uper_bin -> - Bytes - end, - case decode(Module,Type,NewBytes) of - {ok,Value} -> - {ok,{Module,Type,Value}}; - {ok,Res} -> - {error,{asn1,{encode_decode_mismatch, - {{Module,Type,Value},Res}}}}; - Error -> - {error,{asn1,{{decode, - {Module,Type,Value},Error}}}} - end; - Error -> - {error,{asn1,{encode,{{Module,Type,Value},Error}}}} +check(Module, Includes) -> + case asn1_db:dbget(Module,'MODULE') of + undefined -> + {error, {file_not_found, lists:concat([Module, ".asn1db"])}}; + M -> + TypeOrVal = M#module.typeorval, + State = #state{mname = M#module.name, + module = M#module{typeorval=[]}, + options = Includes}, + case asn1ct_check:check(State, TypeOrVal) of + {ok, {NewTypes, _, _, _, _, _}, _} -> {ok, NewTypes}; + {error, Reason} -> {error, Reason} + end end. -value(Module) -> - start(), - M = asn1_db:dbget(Module,'MODULE'), - {Types,_Values,_Ptypes,_Classes,_Objects,_ObjectSets} = M#module.typeorval, - lists:map(fun(A) ->value(Module,A) end,Types). +to_atom(Term) when is_list(Term) -> list_to_atom(Term); +to_atom(Term) when is_atom(Term) -> Term. -value(Module,Type) -> - start(), - case catch asn1ct_value:get_type(Module,Type,no) of - {error,Reason} -> - {error,Reason}; - {'EXIT',Reason} -> - {error,Reason}; - Result -> - {ok,Result} - end. +prepare_bytes(ber, Bytes) -> lists:flatten(Bytes); +prepare_bytes(ber_bin, Bytes) when is_binary(Bytes) -> Bytes; +prepare_bytes(ber_bin, Bytes) -> list_to_binary(Bytes); +prepare_bytes(ber_bin_v2, Bytes) when is_binary(Bytes) -> Bytes; +prepare_bytes(ber_bin_v2, Bytes) -> list_to_binary(Bytes); +prepare_bytes(per, Bytes) -> lists:flatten(Bytes); +prepare_bytes(per_bin, Bytes) when is_binary(Bytes) -> Bytes; +prepare_bytes(per_bin, Bytes) -> list_to_binary(Bytes); +prepare_bytes(uper_bin, Bytes) -> Bytes. vsn() -> ?vsn. @@ -1508,26 +1511,26 @@ partial_decode_prepare(ber_bin_v2,M,TsAndVs,Options) when is_tuple(TsAndVs) -> _ -> M#module.name end, %% io:format("ModName: ~p~nM#module.name: ~p~n~n",[ModName,M#module.name]), - CfgList = read_config_file(ModName), - SelectedDecode = get_config_info(CfgList,selective_decode), - ExclusiveDecode = get_config_info(CfgList,exclusive_decode), - CommandList = - create_partial_decode_gen_info(M#module.name,SelectedDecode), - %% To convert CommandList to a proper list for the driver change - %% the list:[[choosen,Tag1],skip,[skip_optional,Tag2]] to L = - %% [5,2,Tag1,0,1,Tag2] where 5 is the length, and call - %% port_control(asn1_driver_port,3,[L| Bin]) - save_config(partial_decode,CommandList), - save_gen_state(selective_decode,SelectedDecode), -% io:format("selective_decode: CommandList:~n~p~nSelectedDecode:~n~p~n", -% [CommandList,SelectedDecode]), - CommandList2 = - create_partial_inc_decode_gen_info(M#module.name,ExclusiveDecode), -% io:format("partial_incomplete_decode = ~p~n",[CommandList2]), - Part_inc_tlv_tags = tlv_tags(CommandList2), -% io:format("partial_incomplete_decode: tlv_tags = ~p~n",[Part_inc_tlv_tags]), - save_config(partial_incomplete_decode,Part_inc_tlv_tags), - save_gen_state(exclusive_decode,ExclusiveDecode,Part_inc_tlv_tags); + case read_config_file(ModName) of + no_config_file -> + ok; + CfgList -> + SelectedDecode = get_config_info(CfgList,selective_decode), + ExclusiveDecode = get_config_info(CfgList,exclusive_decode), + CommandList = create_partial_decode_gen_info(M#module.name, + SelectedDecode), + %% To convert CommandList to a proper list for the driver change + %% the list:[[choosen,Tag1],skip,[skip_optional,Tag2]] to L = + %% [5,2,Tag1,0,1,Tag2] where 5 is the length, and call + %% port_control(asn1_driver_port,3,[L| Bin]) + save_config(partial_decode,CommandList), + save_gen_state(selective_decode,SelectedDecode), + CommandList2 = create_partial_inc_decode_gen_info(M#module.name, + ExclusiveDecode), + Part_inc_tlv_tags = tlv_tags(CommandList2), + save_config(partial_incomplete_decode,Part_inc_tlv_tags), + save_gen_state(exclusive_decode,ExclusiveDecode,Part_inc_tlv_tags) + end; partial_decode_prepare(_,_,_,_) -> ok. @@ -2006,7 +2009,7 @@ read_config_file(ModuleName) -> read_config_file1(ModuleName,[]) -> case filename:extension(ModuleName) of ".asn1config" -> - throw({error,enoent}); + no_config_file; _ -> read_config_file(lists:concat([ModuleName,".asn1config"])) end; @@ -2035,7 +2038,7 @@ get_config_info(CfgList,InfoType) -> %% Before saving anything check if a table exists %% The record gen_state is saved with the key {asn1_config,gen_state} save_config(Key,Info) -> - asn1ct_table:new_reuse(asn1_general, [named_table]), + asn1ct_table:new_reuse(asn1_general), asn1ct_table:insert(asn1_general, {{asn1_config, Key}, Info}). read_config_data(Key) -> @@ -2569,3 +2572,21 @@ is_werr(S) when is_record(S, state) -> is_werr(S#state.options); is_werr(O) -> lists:member(warnings_as_errors, O). + + +in_process(Fun) -> + Parent = self(), + Pid = spawn_link(fun() -> process(Parent, Fun) end), + receive + {Pid, Result} -> Result; + {Pid, Class, Reason, Stack} -> + ST = try throw(x) catch throw:x -> erlang:get_stacktrace() end, + erlang:raise(Class, Reason, Stack ++ ST) + end. + +process(Parent, Fun) -> + try + Parent ! {self(), Fun()} + catch Class:Reason -> + Parent ! {self(), Class, Reason, erlang:get_stacktrace()} + end. |