~ubuntu-branches/ubuntu/trusty/erlang/trusty

« back to all changes in this revision

Viewing changes to lib/dialyzer/test/r9c_tests_SUITE_data/src/asn1/asn1ct.erl

  • Committer: Bazaar Package Importer
  • Author(s): Clint Byrum
  • Date: 2011-05-05 15:48:43 UTC
  • mfrom: (3.5.13 sid)
  • Revision ID: james.westby@ubuntu.com-20110505154843-0om6ekzg6m7ugj27
Tags: 1:14.b.2-dfsg-3ubuntu1
* Merge from debian unstable.  Remaining changes:
  - Drop libwxgtk2.8-dev build dependency. Wx isn't in main, and not
    supposed to.
  - Drop erlang-wx binary.
  - Drop erlang-wx dependency from -megaco, -common-test, and -reltool, they
    do not really need wx. Also drop it from -debugger; the GUI needs wx,
    but it apparently has CLI bits as well, and is also needed by -megaco,
    so let's keep the package for now.
  - debian/patches/series: Do what I meant, and enable build-options.patch
    instead.
* Additional changes:
  - Drop erlang-wx from -et
* Dropped Changes:
  - patches/pcre-crash.patch: CVE-2008-2371: outer level option with
    alternatives caused crash. (Applied Upstream)
  - fix for ssl certificate verification in newSSL: 
    ssl_cacertfile_fix.patch (Applied Upstream)
  - debian/patches/series: Enable native.patch again, to get stripped beam
    files and reduce the package size again. (build-options is what
    actually accomplished this)
  - Remove build-options.patch on advice from upstream and because it caused
    odd build failures.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
%% ``The contents of this file are subject to the Erlang Public License,
 
2
%% Version 1.1, (the "License"); you may not use this file except in
 
3
%% compliance with the License. You should have received a copy of the
 
4
%% Erlang Public License along with this software. If not, it can be
 
5
%% retrieved via the world wide web at http://www.erlang.org/.
 
6
%% 
 
7
%% Software distributed under the License is distributed on an "AS IS"
 
8
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 
9
%% the License for the specific language governing rights and limitations
 
10
%% under the License.
 
11
%% 
 
12
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
 
13
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
 
14
%% AB. All Rights Reserved.''
 
15
%% 
 
16
%%     $Id: asn1ct.erl,v 1.1 2008/12/17 09:53:29 mikpe Exp $
 
17
%%
 
18
-module(asn1ct).
 
19
 
 
20
%% Compile Time functions for ASN.1 (e.g ASN.1 compiler).
 
21
 
 
22
%%-compile(export_all).
 
23
%% Public exports
 
24
-export([compile/1, compile/2]).
 
25
-export([start/0, start/1, stop/0]).
 
26
-export([encode/2, encode/3, decode/3]).
 
27
-export([test/1, test/2, test/3, value/2]).
 
28
%% Application internal exports
 
29
-export([compile_asn/3,compile_asn1/3,compile_py/3,compile/3,value/1,vsn/0,
 
30
         create_ets_table/2,get_name_of_def/1,get_pos_of_def/1]).
 
31
-export([read_config_data/1,get_gen_state_field/1,get_gen_state/0,
 
32
         partial_inc_dec_toptype/1,save_gen_state/1,update_gen_state/2,
 
33
         get_tobe_refed_func/1,reset_gen_state/0,is_function_generated/1,
 
34
         generated_refed_func/1,next_refed_func/0,pop_namelist/0,
 
35
         next_namelist_el/0,update_namelist/1,step_in_constructed/0,
 
36
         add_tobe_refed_func/1,add_generated_refed_func/1]).
 
37
 
 
38
-include("asn1_records.hrl").
 
39
-include_lib("stdlib/include/erl_compile.hrl").
 
40
 
 
41
-import(asn1ct_gen_ber_bin_v2,[encode_tag_val/3,decode_class/1]).
 
42
 
 
43
-define(unique_names,0).
 
44
-define(dupl_uniquedefs,1).
 
45
-define(dupl_equaldefs,2).
 
46
-define(dupl_eqdefs_uniquedefs,?dupl_equaldefs bor ?dupl_uniquedefs).
 
47
 
 
48
-define(CONSTRUCTED, 2#00100000). 
 
49
 
 
50
%% macros used for partial decode commands
 
51
-define(CHOOSEN,choosen).
 
52
-define(SKIP,skip).
 
53
-define(SKIP_OPTIONAL,skip_optional).
 
54
 
 
55
%% macros used for partial incomplete decode commands
 
56
-define(MANDATORY,mandatory).
 
57
-define(DEFAULT,default).
 
58
-define(OPTIONAL,opt).
 
59
-define(PARTS,parts).
 
60
-define(UNDECODED,undec).
 
61
-define(ALTERNATIVE,alt).
 
62
-define(ALTERNATIVE_UNDECODED,alt_undec).
 
63
-define(ALTERNATIVE_PARTS,alt_parts).
 
64
%-define(BINARY,bin).
 
65
 
 
66
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
67
%% This is the interface to the compiler
 
68
%% 
 
69
%% 
 
70
 
 
71
 
 
72
compile(File) ->
 
73
    compile(File,[]).
 
74
 
 
75
compile(File,Options) when list(Options) ->
 
76
    Options1 =
 
77
        case {lists:member(optimize,Options),lists:member(ber_bin,Options)} of
 
78
            {true,true} -> 
 
79
                [ber_bin_v2|Options--[ber_bin]];
 
80
            _ -> Options
 
81
        end,
 
82
    case (catch input_file_type(File)) of
 
83
        {single_file,PrefixedFile} ->
 
84
            (catch compile1(PrefixedFile,Options1));
 
85
        {multiple_files_file,SetBase,FileName} ->
 
86
            FileList = get_file_list(FileName),
 
87
            (catch compile_set(SetBase,filename:dirname(FileName),
 
88
                               FileList,Options1));
 
89
        Err = {input_file_error,_Reason} ->
 
90
            {error,Err}
 
91
    end.
 
92
 
 
93
 
 
94
compile1(File,Options) when list(Options) ->
 
95
    io:format("Erlang ASN.1 version ~p compiling ~p ~n",[?vsn,File]),
 
96
    io:format("Compiler Options: ~p~n",[Options]),
 
97
    Ext = filename:extension(File),
 
98
    Base = filename:basename(File,Ext),
 
99
    OutFile = outfile(Base,"",Options),
 
100
    DbFile = outfile(Base,"asn1db",Options),
 
101
    Includes = [I || {i,I} <- Options],
 
102
    EncodingRule = get_rule(Options),
 
103
    create_ets_table(asn1_functab,[named_table]),
 
104
    Continue1 = scan({true,true},File,Options),
 
105
    Continue2 = parse(Continue1,File,Options),
 
106
    Continue3 = check(Continue2,File,OutFile,Includes,EncodingRule,
 
107
                      DbFile,Options,[]),
 
108
    Continue4 = generate(Continue3,OutFile,EncodingRule,Options),
 
109
    delete_tables([asn1_functab]),
 
110
    compile_erl(Continue4,OutFile,Options).
 
111
 
 
112
%%****************************************************************************%%
 
113
%% functions dealing with compiling of several input files to one output file %%
 
114
%%****************************************************************************%%
 
115
compile_set(SetBase,DirName,Files,Options) when list(hd(Files)),list(Options) ->
 
116
    %% case when there are several input files in a list
 
117
    io:format("Erlang ASN.1 version ~p compiling ~p ~n",[?vsn,Files]),    
 
118
    io:format("Compiler Options: ~p~n",[Options]),
 
119
    OutFile = outfile(SetBase,"",Options),
 
120
    DbFile = outfile(SetBase,"asn1db",Options),
 
121
    Includes = [I || {i,I} <- Options],
 
122
    EncodingRule = get_rule(Options),
 
123
    create_ets_table(asn1_functab,[named_table]),
 
124
    ScanRes = scan_set(DirName,Files,Options),
 
125
    ParseRes = parse_set(ScanRes,Options),
 
126
    Result = 
 
127
        case [X||X <- ParseRes,element(1,X)==true] of
 
128
            [] -> %% all were false, time to quit
 
129
                lists:map(fun(X)->element(2,X) end,ParseRes);
 
130
            ParseRes -> %% all were true, continue with check
 
131
                InputModules = 
 
132
                    lists:map(
 
133
                      fun(F)->
 
134
                              E = filename:extension(F),
 
135
                              B = filename:basename(F,E),
 
136
                              if
 
137
                                  list(B) -> list_to_atom(B);
 
138
                                  true -> B
 
139
                              end
 
140
                      end,
 
141
                      Files),
 
142
                check_set(ParseRes,SetBase,OutFile,Includes,
 
143
                          EncodingRule,DbFile,Options,InputModules);
 
144
            Other ->
 
145
                {error,{'unexpected error in scan/parse phase',
 
146
                        lists:map(fun(X)->element(3,X) end,Other)}}
 
147
        end,
 
148
    delete_tables([asn1_functab]),
 
149
    Result.
 
150
 
 
151
check_set(ParseRes,SetBase,OutFile,Includes,EncRule,DbFile,
 
152
          Options,InputModules) ->
 
153
    lists:foreach(fun({_T,M,File})->
 
154
                          cmp(M#module.name,File)
 
155
                  end,
 
156
                  ParseRes),
 
157
    MergedModule = merge_modules(ParseRes,SetBase),
 
158
    SetM = MergedModule#module{name=SetBase},
 
159
    Continue1 = check({true,SetM},SetBase,OutFile,Includes,EncRule,DbFile,
 
160
                      Options,InputModules),
 
161
    Continue2 = generate(Continue1,OutFile,EncRule,Options),
 
162
 
 
163
    delete_tables([renamed_defs,original_imports,automatic_tags]),
 
164
 
 
165
    compile_erl(Continue2,OutFile,Options).
 
166
 
 
167
%% merge_modules/2 -> returns a module record where the typeorval lists are merged,
 
168
%% the exports lists are merged, the imports lists are merged when the 
 
169
%% elements come from other modules than the merge set, the tagdefault 
 
170
%% field gets the shared value if all modules have same tagging scheme,
 
171
%% otherwise a tagging_error exception is thrown, 
 
172
%% the extensiondefault ...(not handled yet).
 
173
merge_modules(ParseRes,CommonName) ->
 
174
    ModuleList = lists:map(fun(X)->element(2,X) end,ParseRes),
 
175
    NewModuleList = remove_name_collisions(ModuleList),
 
176
    case ets:info(renamed_defs,size) of
 
177
        0 -> ets:delete(renamed_defs);
 
178
        _ -> ok
 
179
    end,
 
180
    save_imports(NewModuleList),
 
181
%    io:format("~p~n~p~n~p~n~n",[ets:lookup(original_imports,'M1'),ets:lookup(original_imports,'M2'),ets:tab2list(original_imports)]),
 
182
    TypeOrVal = lists:append(lists:map(fun(X)->X#module.typeorval end,
 
183
                                       NewModuleList)),
 
184
    InputMNameList = lists:map(fun(X)->X#module.name end,
 
185
                               NewModuleList),
 
186
    CExports = common_exports(NewModuleList),
 
187
   
 
188
    ImportsModuleNameList = lists:map(fun(X)->
 
189
                                              {X#module.imports,
 
190
                                               X#module.name} end,
 
191
                                      NewModuleList),
 
192
    %% ImportsModuleNameList: [{Imports,ModuleName},...]
 
193
    %% Imports is a tuple {imports,[#'SymbolsFromModule'{},...]}
 
194
    CImports = common_imports(ImportsModuleNameList,InputMNameList),
 
195
    TagDefault = check_tagdefault(NewModuleList),
 
196
    #module{name=CommonName,tagdefault=TagDefault,exports=CExports,
 
197
            imports=CImports,typeorval=TypeOrVal}.
 
198
 
 
199
%% causes an exit if duplicate definition names exist in a module
 
200
remove_name_collisions(Modules) ->
 
201
    create_ets_table(renamed_defs,[named_table]),
 
202
    %% Name duplicates in the same module is not allowed.
 
203
    lists:foreach(fun exit_if_nameduplicate/1,Modules),
 
204
    %% Then remove duplicates in different modules and return the
 
205
    %% new list of modules.
 
206
    remove_name_collisions2(Modules,[]).
 
207
 
 
208
%% For each definition in the first module in module list, find
 
209
%% all definitons with same name and rename both definitions in
 
210
%% the first module and in rest of modules
 
211
remove_name_collisions2([M|Ms],Acc) ->
 
212
    TypeOrVal = M#module.typeorval,
 
213
    MName = M#module.name,
 
214
    %% Test each name in TypeOrVal on all modules in Ms
 
215
    {NewM,NewMs} = remove_name_collisions2(MName,TypeOrVal,Ms,[]),
 
216
    remove_name_collisions2(NewMs,[M#module{typeorval=NewM}|Acc]);
 
217
remove_name_collisions2([],Acc) ->
 
218
    finished_warn_prints(),
 
219
    Acc.
 
220
 
 
221
%% For each definition in list of defs find definitions in (rest of)
 
222
%% modules that have same name. If duplicate was found rename def.
 
223
%% Test each name in [T|Ts] on all modules in Ms
 
224
remove_name_collisions2(ModName,[T|Ts],Ms,Acc) ->
 
225
    Name = get_name_of_def(T),
 
226
    case discover_dupl_in_mods(Name,T,Ms,[],?unique_names) of
 
227
        {_,?unique_names} -> % there was no name collision
 
228
            remove_name_collisions2(ModName,Ts,Ms,[T|Acc]);
 
229
        {NewMs,?dupl_uniquedefs} -> % renamed defs in NewMs
 
230
            %% rename T
 
231
            NewT = set_name_of_def(ModName,Name,T), %rename def
 
232
            warn_renamed_def(ModName,get_name_of_def(NewT),Name),
 
233
            ets:insert(renamed_defs,{get_name_of_def(NewT),Name,ModName}),
 
234
            remove_name_collisions2(ModName,Ts,NewMs,[NewT|Acc]);
 
235
        {NewMs,?dupl_equaldefs} -> % name duplicates, but identical defs
 
236
            %% keep name of T
 
237
            warn_kept_def(ModName,Name),
 
238
            remove_name_collisions2(ModName,Ts,NewMs,[T|Acc]);
 
239
        {NewMs,?dupl_eqdefs_uniquedefs} ->
 
240
            %% keep name of T, renamed defs in NewMs
 
241
            warn_kept_def(ModName,Name),
 
242
            remove_name_collisions2(ModName,Ts,NewMs,[T|Acc])
 
243
    end;
 
244
remove_name_collisions2(_,[],Ms,Acc) ->
 
245
    {Acc,Ms}.
 
246
 
 
247
%% Name is the name of a definition. If a definition with the same name
 
248
%% is found in the modules Ms the definition will be renamed and returned.
 
249
discover_dupl_in_mods(Name,Def,[M=#module{name=N,typeorval=TorV}|Ms],
 
250
                              Acc,AnyRenamed) ->
 
251
    Fun = fun(T,RenamedOrDupl)->
 
252
                  case {get_name_of_def(T),compare_defs(Def,T)} of
 
253
                      {Name,not_equal} ->
 
254
                          %% rename def
 
255
                          NewT=set_name_of_def(N,Name,T),
 
256
                          warn_renamed_def(N,get_name_of_def(NewT),Name),
 
257
                          ets:insert(renamed_defs,{get_name_of_def(NewT),
 
258
                                                   Name,N}),
 
259
                          {NewT,?dupl_uniquedefs bor RenamedOrDupl};
 
260
                      {Name,equal} ->
 
261
                          %% delete def
 
262
                          warn_deleted_def(N,Name),
 
263
                          {[],?dupl_equaldefs bor RenamedOrDupl};
 
264
                      _ ->
 
265
                          {T,RenamedOrDupl}
 
266
                  end
 
267
          end,
 
268
    {NewTorV,NewAnyRenamed} = lists:mapfoldl(Fun,AnyRenamed,TorV),
 
269
    %% have to flatten the NewTorV to remove any empty list elements
 
270
    discover_dupl_in_mods(Name,Def,Ms,
 
271
                          [M#module{typeorval=lists:flatten(NewTorV)}|Acc],
 
272
                          NewAnyRenamed);
 
273
discover_dupl_in_mods(_,_,[],Acc,AnyRenamed) ->
 
274
    {Acc,AnyRenamed}.
 
275
 
 
276
warn_renamed_def(ModName,NewName,OldName) ->
 
277
    maybe_first_warn_print(),
 
278
    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]).
 
279
 
 
280
warn_deleted_def(ModName,DefName) ->
 
281
    maybe_first_warn_print(),
 
282
    io:format("NOTICE: The ASN.1 definition in module ~p with name ~p has been deleted in generated module.~n",[ModName,DefName]).
 
283
 
 
284
warn_kept_def(ModName,DefName) ->
 
285
    maybe_first_warn_print(),
 
286
    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]).
 
287
 
 
288
maybe_first_warn_print() ->
 
289
    case get(warn_duplicate_defs) of
 
290
        undefined ->
 
291
            put(warn_duplicate_defs,true),
 
292
            io:format("~nDue to multiple occurrences of a definition name in "
 
293
                      "multi-file compiled files:~n");
 
294
        _ ->
 
295
            ok
 
296
    end.
 
297
finished_warn_prints() ->
 
298
    put(warn_duplicate_defs,undefined).
 
299
 
 
300
 
 
301
exit_if_nameduplicate(#module{typeorval=TorV}) ->
 
302
    exit_if_nameduplicate(TorV);
 
303
exit_if_nameduplicate([]) ->
 
304
    ok;
 
305
exit_if_nameduplicate([Def|Rest]) ->
 
306
    Name=get_name_of_def(Def),
 
307
    exit_if_nameduplicate2(Name,Rest),
 
308
    exit_if_nameduplicate(Rest).
 
309
 
 
310
exit_if_nameduplicate2(Name,Rest) ->
 
311
    Pred=fun(Def)->
 
312
                 case get_name_of_def(Def) of
 
313
                     Name -> true;
 
314
                     _ -> false
 
315
                 end
 
316
         end,
 
317
        case lists:any(Pred,Rest) of
 
318
        true ->
 
319
            throw({error,{"more than one definition with same name",Name}});
 
320
        _ ->
 
321
            ok
 
322
    end.
 
323
 
 
324
compare_defs(D1,D2) ->
 
325
    compare_defs2(unset_pos(D1),unset_pos(D2)).
 
326
compare_defs2(D,D) ->
 
327
    equal;
 
328
compare_defs2(_,_) ->
 
329
    not_equal.
 
330
 
 
331
unset_pos(Def) when record(Def,typedef) ->
 
332
    Def#typedef{pos=undefined};
 
333
unset_pos(Def) when record(Def,classdef) ->
 
334
    Def#classdef{pos=undefined};
 
335
unset_pos(Def) when record(Def,valuedef) ->
 
336
    Def#valuedef{pos=undefined};
 
337
unset_pos(Def) when record(Def,ptypedef) ->
 
338
    Def#ptypedef{pos=undefined};
 
339
unset_pos(Def) when record(Def,pvaluedef) ->
 
340
    Def#pvaluedef{pos=undefined};
 
341
unset_pos(Def) when record(Def,pvaluesetdef) ->
 
342
    Def#pvaluesetdef{pos=undefined};
 
343
unset_pos(Def) when record(Def,pobjectdef) ->
 
344
    Def#pobjectdef{pos=undefined};
 
345
unset_pos(Def) when record(Def,pobjectsetdef) ->
 
346
    Def#pobjectsetdef{pos=undefined}.
 
347
 
 
348
get_pos_of_def(#typedef{pos=Pos}) ->
 
349
    Pos;
 
350
get_pos_of_def(#classdef{pos=Pos}) ->
 
351
    Pos;
 
352
get_pos_of_def(#valuedef{pos=Pos}) ->
 
353
    Pos;
 
354
get_pos_of_def(#ptypedef{pos=Pos}) ->
 
355
    Pos;
 
356
get_pos_of_def(#pvaluedef{pos=Pos}) ->
 
357
    Pos;
 
358
get_pos_of_def(#pvaluesetdef{pos=Pos}) ->
 
359
    Pos;
 
360
get_pos_of_def(#pobjectdef{pos=Pos}) ->
 
361
    Pos;
 
362
get_pos_of_def(#pobjectsetdef{pos=Pos}) ->
 
363
    Pos.
 
364
    
 
365
    
 
366
get_name_of_def(#typedef{name=Name}) ->
 
367
    Name;
 
368
get_name_of_def(#classdef{name=Name}) ->
 
369
    Name;
 
370
get_name_of_def(#valuedef{name=Name}) ->
 
371
    Name;
 
372
get_name_of_def(#ptypedef{name=Name}) ->
 
373
    Name;
 
374
get_name_of_def(#pvaluedef{name=Name}) ->
 
375
    Name;
 
376
get_name_of_def(#pvaluesetdef{name=Name}) ->
 
377
    Name;
 
378
get_name_of_def(#pobjectdef{name=Name}) ->
 
379
    Name;
 
380
get_name_of_def(#pobjectsetdef{name=Name}) ->
 
381
    Name.
 
382
 
 
383
set_name_of_def(ModName,Name,OldDef) ->
 
384
    NewName = list_to_atom(lists:concat([Name,ModName])),
 
385
    case OldDef of
 
386
        #typedef{} -> OldDef#typedef{name=NewName};
 
387
        #classdef{} -> OldDef#classdef{name=NewName};
 
388
        #valuedef{} -> OldDef#valuedef{name=NewName};
 
389
        #ptypedef{} -> OldDef#ptypedef{name=NewName};
 
390
        #pvaluedef{} -> OldDef#pvaluedef{name=NewName};
 
391
        #pvaluesetdef{} -> OldDef#pvaluesetdef{name=NewName};
 
392
        #pobjectdef{} -> OldDef#pobjectdef{name=NewName};
 
393
        #pobjectsetdef{} -> OldDef#pobjectsetdef{name=NewName}
 
394
    end.
 
395
 
 
396
save_imports(ModuleList)->
 
397
    Fun = fun(M) ->
 
398
                  case M#module.imports of
 
399
                      {_,[]} -> [];
 
400
                      {_,I} -> 
 
401
                          {M#module.name,I}
 
402
                  end
 
403
          end,
 
404
    ImportsList = lists:map(Fun,ModuleList),
 
405
    case lists:flatten(ImportsList) of
 
406
        [] ->
 
407
            ok;
 
408
        ImportsList2 ->
 
409
            create_ets_table(original_imports,[named_table]),
 
410
            ets:insert(original_imports,ImportsList2)
 
411
    end.
 
412
                                    
 
413
            
 
414
common_exports(ModuleList) ->
 
415
    %% if all modules exports 'all' then export 'all', 
 
416
    %% otherwise export each typeorval name
 
417
    case lists:filter(fun(X)->
 
418
                              element(2,X#module.exports) /= all
 
419
                      end,
 
420
                      ModuleList) of
 
421
        []->
 
422
            {exports,all};
 
423
        ModsWithExpList ->
 
424
            CExports1 = 
 
425
                lists:append(lists:map(fun(X)->element(2,X#module.exports) end,
 
426
                                       ModsWithExpList)),
 
427
            CExports2 = export_all(lists:subtract(ModuleList,ModsWithExpList)),
 
428
            {exports,CExports1++CExports2}
 
429
    end.
 
430
 
 
431
export_all([])->[];
 
432
export_all(ModuleList) ->
 
433
    ExpList =
 
434
        lists:map(
 
435
          fun(M)->
 
436
                  TorVL=M#module.typeorval,
 
437
                  MName = M#module.name,
 
438
                  lists:map(
 
439
                    fun(Def)->
 
440
                            case Def of
 
441
                                T when record(T,typedef)->
 
442
                                    #'Externaltypereference'{pos=0,
 
443
                                                             module=MName,
 
444
                                                             type=T#typedef.name};
 
445
                                V when record(V,valuedef) ->
 
446
                                    #'Externalvaluereference'{pos=0,
 
447
                                                              module=MName,
 
448
                                                              value=V#valuedef.name};
 
449
                                C when record(C,classdef) ->
 
450
                                    #'Externaltypereference'{pos=0,
 
451
                                                             module=MName,
 
452
                                                             type=C#classdef.name};
 
453
                                P when record(P,ptypedef) ->
 
454
                                    #'Externaltypereference'{pos=0,
 
455
                                                             module=MName,
 
456
                                                             type=P#ptypedef.name};
 
457
                                PV when record(PV,pvaluesetdef) ->
 
458
                                    #'Externaltypereference'{pos=0,
 
459
                                                             module=MName,
 
460
                                                             type=PV#pvaluesetdef.name};
 
461
                                PO when record(PO,pobjectdef) ->
 
462
                                    #'Externalvaluereference'{pos=0,
 
463
                                                              module=MName,
 
464
                                                              value=PO#pobjectdef.name}
 
465
                            end
 
466
                    end,
 
467
                    TorVL)
 
468
          end,
 
469
          ModuleList),
 
470
    lists:append(ExpList).
 
471
 
 
472
%% common_imports/2
 
473
%% IList is a list of tuples, {Imports,MName}, where Imports is the imports of
 
474
%% the module with name MName.
 
475
%% InputMNameL holds the names of all merged modules.
 
476
%% Returns an import tuple with a list of imports that are external the merged
 
477
%% set of modules.
 
478
common_imports(IList,InputMNameL) ->
 
479
    SetExternalImportsList = remove_in_set_imports(IList,InputMNameL,[]),
 
480
    {imports,remove_import_doubles(SetExternalImportsList)}.
 
481
 
 
482
check_tagdefault(ModList) ->
 
483
    case have_same_tagdefault(ModList) of
 
484
        {true,TagDefault}  -> TagDefault;
 
485
        {false,TagDefault} ->
 
486
            create_ets_table(automatic_tags,[named_table]),
 
487
            save_automatic_tagged_types(ModList),
 
488
            TagDefault
 
489
    end.
 
490
 
 
491
have_same_tagdefault([#module{tagdefault=T}|Ms]) ->
 
492
    have_same_tagdefault(Ms,{true,T}).
 
493
 
 
494
have_same_tagdefault([],TagDefault) ->
 
495
    TagDefault;
 
496
have_same_tagdefault([#module{tagdefault=T}|Ms],TDefault={_,T}) ->
 
497
    have_same_tagdefault(Ms,TDefault);
 
498
have_same_tagdefault([#module{tagdefault=T1}|Ms],{_,T2}) ->
 
499
    have_same_tagdefault(Ms,{false,rank_tagdef([T1,T2])}).
 
500
 
 
501
rank_tagdef(L) ->
 
502
    case lists:member('EXPLICIT',L) of
 
503
        true -> 'EXPLICIT';
 
504
        _ -> 'IMPLICIT'
 
505
    end.
 
506
 
 
507
save_automatic_tagged_types([])->
 
508
    done;
 
509
save_automatic_tagged_types([#module{tagdefault='AUTOMATIC',
 
510
                                     typeorval=TorV}|Ms]) ->
 
511
    Fun =
 
512
        fun(T) ->
 
513
                ets:insert(automatic_tags,{get_name_of_def(T)})
 
514
        end,
 
515
    lists:foreach(Fun,TorV),
 
516
    save_automatic_tagged_types(Ms);
 
517
save_automatic_tagged_types([_M|Ms]) ->
 
518
    save_automatic_tagged_types(Ms).
 
519
 
 
520
%% remove_in_set_imports/3 :
 
521
%% input: list with tuples of each module's imports and module name 
 
522
%% respectively.
 
523
%% output: one list with same format but each occured import from a
 
524
%% module in the input set (IMNameL) is removed.
 
525
remove_in_set_imports([{{imports,ImpL},_ModName}|Rest],InputMNameL,Acc) ->
 
526
    NewImpL = remove_in_set_imports1(ImpL,InputMNameL,[]),
 
527
    remove_in_set_imports(Rest,InputMNameL,NewImpL++Acc);
 
528
remove_in_set_imports([],_,Acc) ->
 
529
    lists:reverse(Acc).
 
530
 
 
531
remove_in_set_imports1([I|Is],InputMNameL,Acc) ->
 
532
    case I#'SymbolsFromModule'.module of
 
533
        #'Externaltypereference'{type=MName} ->
 
534
            case lists:member(MName,InputMNameL) of
 
535
                true ->
 
536
                    remove_in_set_imports1(Is,InputMNameL,Acc);
 
537
                false ->
 
538
                    remove_in_set_imports1(Is,InputMNameL,[I|Acc])
 
539
            end;
 
540
        _ ->
 
541
            remove_in_set_imports1(Is,InputMNameL,[I|Acc])
 
542
    end;
 
543
remove_in_set_imports1([],_,Acc) ->
 
544
    lists:reverse(Acc).
 
545
 
 
546
remove_import_doubles([]) ->
 
547
    [];
 
548
%% If several modules in the merge set imports symbols from
 
549
%% the same external module it might be doubled.
 
550
%% ImportList has #'SymbolsFromModule' elements
 
551
remove_import_doubles(ImportList) ->
 
552
    MergedImportList = 
 
553
        merge_symbols_from_module(ImportList,[]),
 
554
%%    io:format("MergedImportList: ~p~n",[MergedImportList]),
 
555
    delete_double_of_symbol(MergedImportList,[]).
 
556
 
 
557
merge_symbols_from_module([Imp|Imps],Acc) ->
 
558
    #'Externaltypereference'{type=ModName} = Imp#'SymbolsFromModule'.module,
 
559
    IfromModName = 
 
560
        lists:filter(
 
561
          fun(I)->
 
562
                  case I#'SymbolsFromModule'.module of
 
563
                      #'Externaltypereference'{type=ModName} ->
 
564
                          true;
 
565
                      #'Externalvaluereference'{value=ModName} ->
 
566
                          true;
 
567
                      _ -> false
 
568
                  end
 
569
          end,
 
570
          Imps),
 
571
    NewImps = lists:subtract(Imps,IfromModName),
 
572
%%    io:format("Imp: ~p~nIfromModName: ~p~n",[Imp,IfromModName]),
 
573
    NewImp =
 
574
        Imp#'SymbolsFromModule'{
 
575
          symbols = lists:append(
 
576
                      lists:map(fun(SL)->
 
577
                                        SL#'SymbolsFromModule'.symbols 
 
578
                                end,[Imp|IfromModName]))},
 
579
    merge_symbols_from_module(NewImps,[NewImp|Acc]);
 
580
merge_symbols_from_module([],Acc) ->
 
581
    lists:reverse(Acc).
 
582
 
 
583
delete_double_of_symbol([I|Is],Acc) ->
 
584
    SymL=I#'SymbolsFromModule'.symbols,
 
585
    NewSymL = delete_double_of_symbol1(SymL,[]),
 
586
    delete_double_of_symbol(Is,[I#'SymbolsFromModule'{symbols=NewSymL}|Acc]);
 
587
delete_double_of_symbol([],Acc) ->
 
588
    Acc.
 
589
 
 
590
delete_double_of_symbol1([TRef=#'Externaltypereference'{type=TrefName}|Rest],Acc)->
 
591
    NewRest = 
 
592
        lists:filter(fun(S)->
 
593
                             case S of
 
594
                                 #'Externaltypereference'{type=TrefName}->
 
595
                                     false;
 
596
                                 _ -> true
 
597
                             end
 
598
                     end,
 
599
                     Rest),
 
600
    delete_double_of_symbol1(NewRest,[TRef|Acc]);
 
601
delete_double_of_symbol1([VRef=#'Externalvaluereference'{value=VName}|Rest],Acc) ->
 
602
    NewRest = 
 
603
        lists:filter(fun(S)->
 
604
                             case S of
 
605
                                 #'Externalvaluereference'{value=VName}->
 
606
                                     false;
 
607
                                 _ -> true
 
608
                             end
 
609
                     end,
 
610
                     Rest),
 
611
    delete_double_of_symbol1(NewRest,[VRef|Acc]);
 
612
delete_double_of_symbol1([TRef={#'Externaltypereference'{type=MRef},
 
613
                                #'Externaltypereference'{type=TRef}}|Rest],
 
614
                         Acc)->
 
615
    NewRest = 
 
616
        lists:filter(
 
617
          fun(S)->
 
618
                  case S of
 
619
                      {#'Externaltypereference'{type=MRef},
 
620
                       #'Externaltypereference'{type=TRef}}->
 
621
                          false;
 
622
                      _ -> true
 
623
                  end
 
624
          end,
 
625
          Rest),
 
626
    delete_double_of_symbol1(NewRest,[TRef|Acc]);
 
627
delete_double_of_symbol1([],Acc) ->
 
628
    Acc.
 
629
 
 
630
 
 
631
scan_set(DirName,Files,Options) ->
 
632
    lists:map(
 
633
      fun(F)->
 
634
              case scan({true,true},filename:join([DirName,F]),Options) of
 
635
                  {false,{error,Reason}} ->
 
636
                      throw({error,{'scan error in file:',F,Reason}});
 
637
                  {TrueOrFalse,Res} ->
 
638
                      {TrueOrFalse,Res,F}
 
639
              end
 
640
      end,
 
641
      Files).
 
642
 
 
643
parse_set(ScanRes,Options) ->
 
644
    lists:map(
 
645
      fun({TorF,Toks,F})->
 
646
              case parse({TorF,Toks},F,Options) of
 
647
                  {false,{error,Reason}} ->
 
648
                      throw({error,{'parse error in file:',F,Reason}});
 
649
                  {TrueOrFalse,Res} ->
 
650
                      {TrueOrFalse,Res,F}
 
651
              end
 
652
      end,
 
653
      ScanRes).
 
654
 
 
655
 
 
656
%%***********************************
 
657
 
 
658
 
 
659
scan({true,_}, File,Options) ->
 
660
    case asn1ct_tok:file(File) of
 
661
        {error,Reason} ->
 
662
            io:format("~p~n",[Reason]),
 
663
            {false,{error,Reason}};
 
664
        Tokens ->
 
665
            case lists:member(ss,Options) of
 
666
                true -> % we terminate after scan
 
667
                    {false,Tokens};
 
668
                false -> % continue with next pass
 
669
                    {true,Tokens}
 
670
            end
 
671
    end;
 
672
scan({false,Result},_,_) ->
 
673
    Result.
 
674
 
 
675
 
 
676
parse({true,Tokens},File,Options) ->
 
677
    %Presult = asn1ct_parser2:parse(Tokens),
 
678
    %%case lists:member(p1,Options) of
 
679
    %%            true ->
 
680
    %%                asn1ct_parser:parse(Tokens);
 
681
    %%            _ ->
 
682
    %%                asn1ct_parser2:parse(Tokens)
 
683
    %%        end,
 
684
    case catch asn1ct_parser2:parse(Tokens) of
 
685
        {error,{{Line,_Mod,Message},_TokTup}} ->
 
686
            if 
 
687
                integer(Line) ->
 
688
                    BaseName = filename:basename(File),
 
689
                    io:format("syntax error at line ~p in module ~s:~n",
 
690
                              [Line,BaseName]);
 
691
                true ->
 
692
                    io:format("syntax error in module ~p:~n",[File])
 
693
            end,
 
694
            print_error_message(Message),
 
695
            {false,{error,Message}};
 
696
        {error,{Line,_Mod,[Message,Token]}} ->
 
697
            io:format("syntax error: ~p ~p at line ~p~n",
 
698
                      [Message,Token,Line]),
 
699
            {false,{error,{Line,[Message,Token]}}};
 
700
        {ok,M} ->
 
701
            case lists:member(sp,Options) of
 
702
                true -> % terminate after parse
 
703
                    {false,M};
 
704
                false -> % continue with next pass
 
705
                    {true,M}
 
706
            end;
 
707
        OtherError ->
 
708
            io:format("~p~n",[OtherError])
 
709
    end;
 
710
parse({false,Tokens},_,_) ->
 
711
    {false,Tokens}.
 
712
 
 
713
check({true,M},File,OutFile,Includes,EncodingRule,DbFile,Options,InputMods) ->
 
714
    cmp(M#module.name,File),
 
715
    start(["."|Includes]),
 
716
    case asn1ct_check:storeindb(M) of 
 
717
        ok   ->
 
718
            Module = asn1_db:dbget(M#module.name,'MODULE'),
 
719
            State = #state{mname=Module#module.name,
 
720
                           module=Module#module{typeorval=[]},
 
721
                           erule=EncodingRule,
 
722
                           inputmodules=InputMods,
 
723
                           options=Options},
 
724
            Check = asn1ct_check:check(State,Module#module.typeorval),
 
725
            case {Check,lists:member(abs,Options)} of
 
726
                {{error,Reason},_} ->
 
727
                    {false,{error,Reason}};
 
728
                {{ok,NewTypeOrVal,_},true} ->
 
729
                    NewM = Module#module{typeorval=NewTypeOrVal},
 
730
                    asn1_db:dbput(NewM#module.name,'MODULE',NewM),
 
731
                    pretty2(M#module.name,lists:concat([OutFile,".abs"])),
 
732
                    {false,ok};
 
733
                {{ok,NewTypeOrVal,GenTypeOrVal},_} ->
 
734
                    NewM = Module#module{typeorval=NewTypeOrVal},
 
735
                    asn1_db:dbput(NewM#module.name,'MODULE',NewM),
 
736
                    asn1_db:dbsave(DbFile,M#module.name),
 
737
                    io:format("--~p--~n",[{generated,DbFile}]),
 
738
                    {true,{M,NewM,GenTypeOrVal}}
 
739
            end
 
740
    end;
 
741
check({false,M},_,_,_,_,_,_,_) ->
 
742
    {false,M}.
 
743
 
 
744
generate({true,{M,_Module,GenTOrV}},OutFile,EncodingRule,Options) ->
 
745
    debug_on(Options),
 
746
    case lists:member(compact_bit_string,Options) of
 
747
        true -> put(compact_bit_string,true);
 
748
        _ -> ok
 
749
    end,
 
750
    put(encoding_options,Options),
 
751
    create_ets_table(check_functions,[named_table]),
 
752
 
 
753
    %% create decoding function names and taglists for partial decode
 
754
    %% For the time being leave errors unnoticed !!!!!!!!!
 
755
%    io:format("Options: ~p~n",[Options]),
 
756
    case catch specialized_decode_prepare(EncodingRule,M,GenTOrV,Options) of
 
757
        {error, enoent} -> ok;
 
758
        {error, Reason} -> io:format("WARNING: Error in configuration"
 
759
                                     "file: ~n~p~n",[Reason]);
 
760
        {'EXIT',Reason} -> io:format("WARNING: Internal error when "
 
761
                                     "analyzing configuration"
 
762
                                     "file: ~n~p~n",[Reason]);
 
763
        _ -> ok
 
764
    end,
 
765
 
 
766
    asn1ct_gen:pgen(OutFile,EncodingRule,M#module.name,GenTOrV),
 
767
    debug_off(Options),
 
768
    put(compact_bit_string,false),
 
769
    erase(encoding_options),
 
770
    erase(tlv_format), % used in ber_bin, optimize
 
771
    erase(class_default_type),% used in ber_bin, optimize
 
772
    ets:delete(check_functions),
 
773
    case lists:member(sg,Options) of
 
774
        true -> % terminate here , with .erl file generated
 
775
            {false,true};
 
776
        false ->
 
777
            {true,true}
 
778
    end;
 
779
generate({false,M},_,_,_) ->
 
780
    {false,M}.
 
781
 
 
782
compile_erl({true,_},OutFile,Options) ->
 
783
    erl_compile(OutFile,Options);
 
784
compile_erl({false,true},_,_) ->
 
785
    ok;
 
786
compile_erl({false,Result},_,_) ->
 
787
    Result.
 
788
 
 
789
input_file_type([]) ->
 
790
    {empty_name,[]};
 
791
input_file_type(File) ->
 
792
    case filename:extension(File) of
 
793
        [] ->
 
794
            case file:read_file_info(lists:concat([File,".asn1"])) of
 
795
                {ok,_FileInfo} ->
 
796
                    {single_file, lists:concat([File,".asn1"])};
 
797
                _Error ->
 
798
                    case file:read_file_info(lists:concat([File,".asn"])) of
 
799
                        {ok,_FileInfo} ->
 
800
                            {single_file, lists:concat([File,".asn"])};
 
801
                        _Error ->
 
802
                            {single_file, lists:concat([File,".py"])}
 
803
                    end
 
804
            end;
 
805
        ".asn1config" ->
 
806
            case read_config_file(File,asn1_module) of
 
807
                {ok,Asn1Module} -> 
 
808
                    put(asn1_config_file,File),
 
809
                    input_file_type(Asn1Module);
 
810
                Error ->
 
811
                    Error
 
812
            end;
 
813
        Asn1PFix ->
 
814
            Base = filename:basename(File,Asn1PFix),
 
815
            case filename:extension(Base) of
 
816
                [] ->
 
817
                    {single_file,File};
 
818
                SetPFix when (SetPFix == ".set") ->
 
819
                    {multiple_files_file,
 
820
                     filename:basename(Base,SetPFix),
 
821
                     File};
 
822
                _Error ->
 
823
                    throw({input_file_error,{'Bad input file',File}})
 
824
            end
 
825
    end.
 
826
 
 
827
get_file_list(File) ->
 
828
    case file:open(File, [read]) of
 
829
        {error,Reason} ->
 
830
            {error,{File,file:format_error(Reason)}};
 
831
        {ok,Stream} ->
 
832
            get_file_list1(Stream,[])
 
833
    end.
 
834
 
 
835
get_file_list1(Stream,Acc) ->
 
836
    Ret = io:get_line(Stream,''),
 
837
    case Ret of
 
838
        eof ->
 
839
            file:close(Stream),
 
840
            lists:reverse(Acc);
 
841
        FileName ->
 
842
            PrefixedNameList =
 
843
                case (catch input_file_type(lists:delete($\n,FileName))) of
 
844
                    {empty_name,[]} -> [];
 
845
                    {single_file,Name} -> [Name];
 
846
                    {multiple_files_file,Name} ->
 
847
                        get_file_list(Name);
 
848
                    Err = {input_file_error,_Reason} ->
 
849
                        throw(Err)
 
850
                end,
 
851
            get_file_list1(Stream,PrefixedNameList++Acc)
 
852
    end.
 
853
 
 
854
get_rule(Options) ->
 
855
    case [Rule ||Rule <-[per,ber,ber_bin,ber_bin_v2,per_bin],
 
856
                 Opt <- Options,
 
857
                 Rule==Opt] of
 
858
        [Rule] ->
 
859
            Rule;
 
860
        [Rule|_] ->
 
861
            Rule;
 
862
        [] ->
 
863
            ber
 
864
    end.
 
865
 
 
866
erl_compile(OutFile,Options) ->
 
867
%    io:format("Options:~n~p~n",[Options]),
 
868
    case lists:member(noobj,Options) of
 
869
        true ->
 
870
            ok;
 
871
        _ ->
 
872
            ErlOptions = remove_asn_flags(Options),
 
873
            case c:c(OutFile,ErlOptions) of
 
874
                {ok,_Module} ->
 
875
                    ok;
 
876
                _ ->
 
877
                    {error,'no_compilation'}
 
878
            end
 
879
    end.
 
880
 
 
881
remove_asn_flags(Options) ->
 
882
    [X || X <- Options,
 
883
          X /= get_rule(Options),
 
884
          X /= optimize,
 
885
          X /= compact_bit_string,
 
886
          X /= debug,
 
887
          X /= keyed_list].
 
888
          
 
889
debug_on(Options) ->
 
890
    case lists:member(debug,Options) of
 
891
        true ->
 
892
            put(asndebug,true);
 
893
        _ ->
 
894
            true
 
895
    end,
 
896
    case lists:member(keyed_list,Options) of
 
897
        true ->
 
898
            put(asn_keyed_list,true);
 
899
        _ ->
 
900
            true
 
901
    end.
 
902
 
 
903
 
 
904
debug_off(_Options) ->
 
905
    erase(asndebug),
 
906
    erase(asn_keyed_list).
 
907
 
 
908
 
 
909
outfile(Base, Ext, Opts) when atom(Ext) ->
 
910
    outfile(Base, atom_to_list(Ext), Opts);
 
911
outfile(Base, Ext, Opts) ->
 
912
    Obase = case lists:keysearch(outdir, 1, Opts) of
 
913
                {value, {outdir, Odir}} -> filename:join(Odir, Base);
 
914
                _NotFound -> Base % Not found or bad format
 
915
            end,
 
916
    case Ext of
 
917
        [] ->
 
918
            Obase;
 
919
        _ ->
 
920
            Obase++"."++Ext
 
921
    end.
 
922
 
 
923
%% compile(AbsFileName, Options)
 
924
%%   Compile entry point for erl_compile.
 
925
 
 
926
compile_asn(File,OutFile,Options) ->
 
927
    compile(lists:concat([File,".asn"]),OutFile,Options).
 
928
 
 
929
compile_asn1(File,OutFile,Options) ->
 
930
    compile(lists:concat([File,".asn1"]),OutFile,Options).
 
931
 
 
932
compile_py(File,OutFile,Options) ->
 
933
    compile(lists:concat([File,".py"]),OutFile,Options).
 
934
 
 
935
compile(File, _OutFile, Options) ->
 
936
    case catch compile(File, make_erl_options(Options)) of
 
937
        Exit = {'EXIT',_Reason} ->
 
938
            io:format("~p~n~s~n",[Exit,"error"]),
 
939
            error;
 
940
        {error,_Reason} ->
 
941
            %% case occurs due to error in asn1ct_parser2,asn1ct_check
 
942
%%          io:format("~p~n",[_Reason]),
 
943
%%          io:format("~p~n~s~n",[_Reason,"error"]),
 
944
            error;
 
945
        ok -> 
 
946
            io:format("ok~n"),
 
947
            ok;
 
948
        ParseRes when tuple(ParseRes) ->
 
949
            io:format("~p~n",[ParseRes]),
 
950
            ok;
 
951
        ScanRes when list(ScanRes) ->
 
952
            io:format("~p~n",[ScanRes]),
 
953
            ok;
 
954
        Unknown -> 
 
955
            io:format("~p~n~s~n",[Unknown,"error"]),
 
956
            error
 
957
    end.
 
958
 
 
959
%% Converts generic compiler options to specific options.
 
960
 
 
961
make_erl_options(Opts) ->
 
962
 
 
963
    %% This way of extracting will work even if the record passed
 
964
    %% has more fields than known during compilation.
 
965
 
 
966
    Includes = Opts#options.includes,
 
967
    Defines = Opts#options.defines,
 
968
    Outdir = Opts#options.outdir,
 
969
%%    Warning = Opts#options.warning,
 
970
    Verbose = Opts#options.verbose,
 
971
    Specific = Opts#options.specific,
 
972
    Optimize = Opts#options.optimize,
 
973
    OutputType = Opts#options.output_type,
 
974
    Cwd = Opts#options.cwd,
 
975
 
 
976
    Options =
 
977
        case Verbose of
 
978
            true ->  [verbose];
 
979
            false -> []
 
980
        end ++
 
981
%%%     case Warning of
 
982
%%%         0 -> [];
 
983
%%%         _ -> [report_warnings]
 
984
%%%     end ++
 
985
        [] ++
 
986
        case Optimize of
 
987
            1 -> [optimize];
 
988
            999 -> [];
 
989
            _ -> [{optimize,Optimize}]
 
990
        end ++
 
991
        lists:map(
 
992
          fun ({Name, Value}) ->
 
993
                  {d, Name, Value};
 
994
              (Name) ->
 
995
                  {d, Name}
 
996
          end,
 
997
          Defines) ++
 
998
        case OutputType of
 
999
            undefined -> [ber]; % temporary default (ber when it's ready)
 
1000
            ber -> [ber];
 
1001
            ber_bin -> [ber_bin];
 
1002
            ber_bin_v2 -> [ber_bin_v2];
 
1003
            per -> [per];
 
1004
            per_bin -> [per_bin]
 
1005
        end,
 
1006
 
 
1007
    Options++[report_errors, {cwd, Cwd}, {outdir, Outdir}|
 
1008
              lists:map(fun(Dir) -> {i, Dir} end, Includes)]++Specific.
 
1009
 
 
1010
pretty2(Module,AbsFile) ->
 
1011
    start(),
 
1012
    {ok,F} = file:open(AbsFile, [write]),
 
1013
    M = asn1_db:dbget(Module,'MODULE'),
 
1014
    io:format(F,"%%%%%%%%%%%%%%%%%%%   ~p  %%%%%%%%%%%%%%%%%%%~n",[Module]),
 
1015
    io:format(F,"~s\n",[asn1ct_pretty_format:term(M#module.defid)]),
 
1016
    io:format(F,"~s\n",[asn1ct_pretty_format:term(M#module.tagdefault)]),
 
1017
    io:format(F,"~s\n",[asn1ct_pretty_format:term(M#module.exports)]),
 
1018
    io:format(F,"~s\n",[asn1ct_pretty_format:term(M#module.imports)]),
 
1019
    io:format(F,"~s\n\n",[asn1ct_pretty_format:term(M#module.extensiondefault)]),
 
1020
 
 
1021
    {Types,Values,ParameterizedTypes,Classes,Objects,ObjectSets} = M#module.typeorval,
 
1022
    io:format(F,"%%%%%%%%%%%%%%%%%%% TYPES in ~p  %%%%%%%%%%%%%%%%%%%~n",[Module]),
 
1023
    lists:foreach(fun(T)-> io:format(F,"~s\n",
 
1024
                                     [asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
 
1025
                  end,Types),
 
1026
    io:format(F,"%%%%%%%%%%%%%%%%%%% VALUES in ~p  %%%%%%%%%%%%%%%%%%%~n",[Module]),
 
1027
    lists:foreach(fun(T)-> io:format(F,"~s\n",
 
1028
                                     [asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
 
1029
                  end,Values),
 
1030
    io:format(F,"%%%%%%%%%%%%%%%%%%% Parameterized Types in ~p  %%%%%%%%%%%%%%%%%%%~n",[Module]),
 
1031
    lists:foreach(fun(T)-> io:format(F,"~s\n",
 
1032
                                     [asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])                         
 
1033
                  end,ParameterizedTypes),
 
1034
    io:format(F,"%%%%%%%%%%%%%%%%%%% Classes in ~p  %%%%%%%%%%%%%%%%%%%~n",[Module]),
 
1035
    lists:foreach(fun(T)-> io:format(F,"~s\n",
 
1036
                                     [asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])                         
 
1037
                  end,Classes),
 
1038
    io:format(F,"%%%%%%%%%%%%%%%%%%% Objects in ~p  %%%%%%%%%%%%%%%%%%%~n",[Module]),
 
1039
    lists:foreach(fun(T)-> io:format(F,"~s\n",
 
1040
                                     [asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])                         
 
1041
                  end,Objects),
 
1042
    io:format(F,"%%%%%%%%%%%%%%%%%%% Object Sets in ~p  %%%%%%%%%%%%%%%%%%%~n",[Module]),
 
1043
    lists:foreach(fun(T)-> io:format(F,"~s\n",
 
1044
                                     [asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])                         
 
1045
                  end,ObjectSets).
 
1046
start() ->
 
1047
    Includes = ["."],
 
1048
    start(Includes).
 
1049
 
 
1050
 
 
1051
start(Includes) when list(Includes) ->
 
1052
    asn1_db:dbstart(Includes).
 
1053
 
 
1054
stop() ->
 
1055
    save(),
 
1056
    asn1_db:stop_server(ns),
 
1057
    asn1_db:stop_server(rand),
 
1058
    stopped.
 
1059
 
 
1060
save() ->
 
1061
    asn1_db:dbstop().
 
1062
 
 
1063
%%clear() ->
 
1064
%%    asn1_db:dbclear().
 
1065
 
 
1066
encode(Module,Term) ->
 
1067
    asn1rt:encode(Module,Term).
 
1068
 
 
1069
encode(Module,Type,Term) when list(Module) ->
 
1070
    asn1rt:encode(list_to_atom(Module),Type,Term);
 
1071
encode(Module,Type,Term) ->
 
1072
    asn1rt:encode(Module,Type,Term).
 
1073
 
 
1074
decode(Module,Type,Bytes) when list(Module) ->
 
1075
    asn1rt:decode(list_to_atom(Module),Type,Bytes);
 
1076
decode(Module,Type,Bytes) ->
 
1077
    asn1rt:decode(Module,Type,Bytes).
 
1078
 
 
1079
 
 
1080
test(Module) ->
 
1081
    start(),
 
1082
    M = asn1_db:dbget(Module,'MODULE'),
 
1083
    {Types,_Values,_Ptypes,_Classes,_Objects,_ObjectSets} = M#module.typeorval,
 
1084
    test_each(Module,Types).
 
1085
 
 
1086
test_each(Module,[Type | Rest]) ->
 
1087
    case test(Module,Type) of
 
1088
        {ok,_Result} ->
 
1089
            test_each(Module,Rest);
 
1090
        Error ->
 
1091
            Error
 
1092
    end;
 
1093
test_each(_,[]) ->
 
1094
    ok.
 
1095
 
 
1096
test(Module,Type) ->
 
1097
    io:format("~p:~p~n",[Module,Type]),
 
1098
    case (catch value(Module,Type)) of 
 
1099
        {ok,Val} -> 
 
1100
            %%      io:format("asn1ct:test/2: ~w~n",[Val]),
 
1101
            test(Module,Type,Val);
 
1102
        {'EXIT',Reason} -> 
 
1103
            {error,{asn1,{value,Reason}}}
 
1104
    end.
 
1105
 
 
1106
 
 
1107
test(Module,Type,Value) ->
 
1108
    case catch encode(Module,Type,Value) of
 
1109
        {ok,Bytes} ->
 
1110
            %%      io:format("test 1: ~p~n",[{Bytes}]),
 
1111
            M = if 
 
1112
                    list(Module) ->
 
1113
                        list_to_atom(Module);
 
1114
                    true ->
 
1115
                        Module
 
1116
                end,
 
1117
            NewBytes = 
 
1118
                case M:encoding_rule() of
 
1119
                    ber ->
 
1120
                        lists:flatten(Bytes);
 
1121
                    ber_bin when binary(Bytes) ->
 
1122
                        Bytes;
 
1123
                    ber_bin ->
 
1124
                        list_to_binary(Bytes);
 
1125
                    ber_bin_v2 when binary(Bytes) ->
 
1126
                        Bytes;
 
1127
                    ber_bin_v2 ->
 
1128
                        list_to_binary(Bytes);
 
1129
                    per ->
 
1130
                        lists:flatten(Bytes);
 
1131
                    per_bin when binary(Bytes) ->
 
1132
                        Bytes;
 
1133
                    per_bin ->
 
1134
                        list_to_binary(Bytes)
 
1135
                end,
 
1136
            case decode(Module,Type,NewBytes) of
 
1137
                {ok,Value} -> 
 
1138
                    {ok,{Module,Type,Value}};
 
1139
                {ok,Res} -> 
 
1140
                    {error,{asn1,{encode_decode_mismatch,
 
1141
                                  {{Module,Type,Value},Res}}}};
 
1142
                Error -> 
 
1143
                    {error,{asn1,{{decode,
 
1144
                                   {Module,Type,Value},Error}}}}
 
1145
            end;
 
1146
        Error ->
 
1147
            {error,{asn1,{encode,{{Module,Type,Value},Error}}}}
 
1148
    end.
 
1149
 
 
1150
value(Module) ->
 
1151
    start(),
 
1152
    M = asn1_db:dbget(Module,'MODULE'),
 
1153
    {Types,_Values,_Ptypes,_Classes,_Objects,_ObjectSets} = M#module.typeorval,
 
1154
    lists:map(fun(A) ->value(Module,A) end,Types).
 
1155
 
 
1156
value(Module,Type) ->
 
1157
    start(),
 
1158
    case catch asn1ct_value:get_type(Module,Type,no) of
 
1159
        {error,Reason} ->
 
1160
            {error,Reason};
 
1161
        {'EXIT',Reason} ->
 
1162
            {error,Reason};
 
1163
        Result ->
 
1164
            {ok,Result}
 
1165
    end.
 
1166
 
 
1167
cmp(Module,InFile) ->
 
1168
    Base = filename:basename(InFile),
 
1169
    Dir = filename:dirname(InFile),
 
1170
    Ext = filename:extension(Base),
 
1171
    Finfo = file:read_file_info(InFile),
 
1172
    Minfo = file:read_file_info(filename:join(Dir,lists:concat([Module,Ext]))),
 
1173
    case Finfo of
 
1174
        Minfo ->
 
1175
            ok;
 
1176
        _ ->
 
1177
            io:format("asn1error: Modulename and filename must be equal~n",[]),
 
1178
            throw(error)
 
1179
    end.
 
1180
 
 
1181
vsn() ->
 
1182
    ?vsn.
 
1183
 
 
1184
print_error_message([got,H|T]) when list(H) ->
 
1185
    io:format(" got:"),
 
1186
    print_listing(H,"and"),
 
1187
    print_error_message(T);
 
1188
print_error_message([expected,H|T]) when list(H) ->
 
1189
    io:format(" expected one of:"),
 
1190
    print_listing(H,"or"),
 
1191
    print_error_message(T);
 
1192
print_error_message([H|T])  ->
 
1193
    io:format(" ~p",[H]),
 
1194
    print_error_message(T);
 
1195
print_error_message([]) ->
 
1196
    io:format("~n").
 
1197
 
 
1198
print_listing([H1,H2|[]],AndOr) ->
 
1199
    io:format(" ~p ~s ~p",[H1,AndOr,H2]);
 
1200
print_listing([H1,H2|T],AndOr) ->
 
1201
    io:format(" ~p,",[H1]),
 
1202
    print_listing([H2|T],AndOr);
 
1203
print_listing([H],_AndOr) ->
 
1204
    io:format(" ~p",[H]);
 
1205
print_listing([],_) ->
 
1206
    ok.
 
1207
 
 
1208
 
 
1209
%% functions to administer ets tables
 
1210
 
 
1211
%% Always creates a new table
 
1212
create_ets_table(Name,Options) when atom(Name) ->
 
1213
    case ets:info(Name) of
 
1214
        undefined ->
 
1215
            ets:new(Name,Options);
 
1216
        _  ->
 
1217
            ets:delete(Name),
 
1218
            ets:new(Name,Options)
 
1219
    end.
 
1220
 
 
1221
%% Creates a new ets table only if no table exists
 
1222
create_if_no_table(Name,Options) ->
 
1223
    case ets:info(Name) of
 
1224
        undefined ->
 
1225
            %% create a new table
 
1226
            create_ets_table(Name,Options);
 
1227
        _ -> ok
 
1228
    end.
 
1229
    
 
1230
 
 
1231
delete_tables([Table|Ts]) ->
 
1232
    case ets:info(Table) of
 
1233
        undefined -> ok;
 
1234
        _ -> ets:delete(Table)
 
1235
    end,
 
1236
    delete_tables(Ts);
 
1237
delete_tables([]) ->
 
1238
    ok.
 
1239
 
 
1240
 
 
1241
specialized_decode_prepare(Erule,M,TsAndVs,Options) ->
 
1242
%     Asn1confMember = 
 
1243
%       fun([{asn1config,File}|_],_) ->
 
1244
%               {true,File};
 
1245
%          ([],_) -> false;
 
1246
%          ([_H|T],Fun) ->
 
1247
%               Fun(T,Fun)
 
1248
%       end,
 
1249
%     case Asn1confMember(Options,Asn1confMember) of
 
1250
%       {true,File} ->
 
1251
    case lists:member(asn1config,Options) of
 
1252
        true ->
 
1253
            partial_decode_prepare(Erule,M,TsAndVs,Options);
 
1254
        _ ->
 
1255
            ok
 
1256
    end.
 
1257
%% Reads the configuration file if it exists and stores information
 
1258
%% about partial decode and incomplete decode
 
1259
partial_decode_prepare(ber_bin_v2,M,TsAndVs,Options) when tuple(TsAndVs) ->
 
1260
    %% read configure file
 
1261
%    Types = element(1,TsAndVs),
 
1262
    CfgList = read_config_file(M#module.name),
 
1263
    SelectedDecode = get_config_info(CfgList,partial_decode),
 
1264
    ExclusiveDecode = get_config_info(CfgList,exclusive_decode),
 
1265
    CommandList = 
 
1266
        create_partial_decode_gen_info(M#module.name,SelectedDecode),
 
1267
%    io:format("partial_decode = ~p~n",[CommandList]),
 
1268
    
 
1269
    save_config(partial_decode,CommandList),
 
1270
    CommandList2 = 
 
1271
        create_partial_inc_decode_gen_info(M#module.name,ExclusiveDecode),
 
1272
%    io:format("partial_incomplete_decode = ~p~n",[CommandList2]),
 
1273
    Part_inc_tlv_tags = tag_format(ber_bin_v2,Options,CommandList2),
 
1274
%    io:format("partial_incomplete_decode: tlv_tags = ~p~n",[Part_inc_tlv_tags]),
 
1275
    save_config(partial_incomplete_decode,Part_inc_tlv_tags),
 
1276
    save_gen_state(ExclusiveDecode,Part_inc_tlv_tags);
 
1277
partial_decode_prepare(_,_,_,_) ->
 
1278
    ok.
 
1279
 
 
1280
 
 
1281
 
 
1282
%% create_partial_inc_decode_gen_info/2
 
1283
%%
 
1284
%% Creats a list of tags out of the information in TypeNameList that
 
1285
%% tells which value will be incomplete decoded, i.e. each end
 
1286
%% component/type in TypeNameList. The significant types/components in
 
1287
%% the path from the toptype must be specified in the
 
1288
%% TypeNameList. Significant elements are all constructed types that
 
1289
%% branches the path to the leaf and the leaf it selfs.
 
1290
%%
 
1291
%% Returns a list of elements, where an element may be one of
 
1292
%% mandatory|[opt,Tag]|[bin,Tag]. mandatory correspond to a mandatory
 
1293
%% element that shall be decoded as usual. [opt,Tag] matches an
 
1294
%% OPTIONAL or DEFAULT element that shall be decoded as
 
1295
%% usual. [bin,Tag] corresponds to an element, mandatory, OPTIONAL or
 
1296
%% DEFAULT, that shall be left encoded (incomplete decoded).
 
1297
create_partial_inc_decode_gen_info(ModName,{Mod,[{Name,L}|Ls]}) when list(L) ->
 
1298
    TopTypeName = partial_inc_dec_toptype(L),
 
1299
    [{Name,TopTypeName,
 
1300
      create_partial_inc_decode_gen_info1(ModName,TopTypeName,{Mod,L})}|
 
1301
     create_partial_inc_decode_gen_info(ModName,{Mod,Ls})];
 
1302
create_partial_inc_decode_gen_info(_,{_,[]}) ->
 
1303
    [];
 
1304
create_partial_inc_decode_gen_info(_,[]) ->
 
1305
    [].
 
1306
 
 
1307
create_partial_inc_decode_gen_info1(ModName,TopTypeName,{ModName,
 
1308
                                            [_TopType|Rest]}) ->
 
1309
    case asn1_db:dbget(ModName,TopTypeName) of
 
1310
        #typedef{typespec=TS} ->
 
1311
            TagCommand = get_tag_command(TS,?MANDATORY,mandatory),
 
1312
            create_pdec_inc_command(ModName,get_components(TS#type.def),
 
1313
                                    Rest,[TagCommand]);
 
1314
        _ ->
 
1315
            throw({error,{"wrong type list in asn1 config file",
 
1316
                          TopTypeName}})
 
1317
    end;
 
1318
create_partial_inc_decode_gen_info1(M1,_,{M2,_}) when M1 /= M2 ->
 
1319
    throw({error,{"wrong module name in asn1 config file",
 
1320
                  M2}});
 
1321
create_partial_inc_decode_gen_info1(_,_,TNL) ->
 
1322
    throw({error,{"wrong type list in asn1 config file",
 
1323
                  TNL}}).
 
1324
 
 
1325
%%
 
1326
%% Only when there is a 'ComponentType' the config data C1 may be a
 
1327
%% list, where the incomplete decode is branched. So, C1 may be a
 
1328
%% list, a "binary tuple", a "parts tuple" or an atom. The second
 
1329
%% element of a binary tuple and a parts tuple is an atom.
 
1330
create_pdec_inc_command(_ModName,_,[],Acc) ->
 
1331
    lists:reverse(Acc);
 
1332
create_pdec_inc_command(ModName,{Comps1,Comps2},TNL,Acc) 
 
1333
  when list(Comps1),list(Comps2) ->
 
1334
    create_pdec_inc_command(ModName,Comps1 ++ Comps2,TNL,Acc);
 
1335
create_pdec_inc_command(ModN,Clist,[CL|_Rest],Acc) when list(CL) ->
 
1336
    create_pdec_inc_command(ModN,Clist,CL,Acc);
 
1337
create_pdec_inc_command(ModName,
 
1338
                        CList=[#'ComponentType'{name=Name,typespec=TS,
 
1339
                                                prop=Prop}|Comps],
 
1340
                        TNL=[C1|Cs],Acc)  ->
 
1341
    case C1 of
 
1342
%       Name ->
 
1343
%           %% In this case C1 is an atom
 
1344
%           TagCommand = get_tag_command(TS,?MANDATORY,Prop),
 
1345
%           create_pdec_inc_command(ModName,get_components(TS#type.def),Cs,[TagCommand|Acc]);
 
1346
        {Name,undecoded} ->
 
1347
            TagCommand = get_tag_command(TS,?UNDECODED,Prop),
 
1348
            create_pdec_inc_command(ModName,Comps,Cs,[TagCommand|Acc]);
 
1349
        {Name,parts} ->
 
1350
            TagCommand = get_tag_command(TS,?PARTS,Prop),
 
1351
            create_pdec_inc_command(ModName,Comps,Cs,[TagCommand|Acc]);
 
1352
        L when list(L) ->
 
1353
            %% This case is only possible as the first element after
 
1354
            %% the top type element, when top type is SEGUENCE or SET.
 
1355
            %% Follow each element in L. Must note every tag on the
 
1356
            %% way until the last command is reached, but it ought to
 
1357
            %% be enough to have a "complete" or "complete optional"
 
1358
            %% command for each component that is not specified in the
 
1359
            %% config file. Then in the TLV decode the components with
 
1360
            %% a "complete" command will be decoded by an ordinary TLV
 
1361
            %% decode.
 
1362
            create_pdec_inc_command(ModName,CList,L,Acc);
 
1363
        {Name,RestPartsList} when list(RestPartsList) ->
 
1364
            %% Same as previous, but this may occur at any place in
 
1365
            %% the structure. The previous is only possible as the
 
1366
            %% second element.
 
1367
            case get_tag_command(TS,?MANDATORY,Prop) of
 
1368
                ?MANDATORY ->
 
1369
                    InnerDirectives=
 
1370
                        create_pdec_inc_command(ModName,TS#type.def,
 
1371
                                                RestPartsList,[]),
 
1372
                    create_pdec_inc_command(ModName,Comps,Cs,
 
1373
                                            [[?MANDATORY,InnerDirectives]|Acc]);
 
1374
%                   create_pdec_inc_command(ModName,Comps,Cs,
 
1375
%                                           [InnerDirectives,?MANDATORY|Acc]);
 
1376
                [Opt,EncTag] ->
 
1377
                    InnerDirectives = 
 
1378
                        create_pdec_inc_command(ModName,TS#type.def,
 
1379
                                                RestPartsList,[]),
 
1380
                    create_pdec_inc_command(ModName,Comps,Cs,
 
1381
                                            [[Opt,EncTag,InnerDirectives]|Acc])
 
1382
            end;
 
1383
%           create_pdec_inc_command(ModName,CList,RestPartsList,Acc);
 
1384
%%          create_pdec_inc_command(ModName,TS#type.def,RestPartsList,Acc);
 
1385
        _ -> %% this component may not be in the config list
 
1386
            TagCommand = get_tag_command(TS,?MANDATORY,Prop),
 
1387
            create_pdec_inc_command(ModName,Comps,TNL,[TagCommand|Acc])
 
1388
    end;
 
1389
create_pdec_inc_command(ModName,
 
1390
                        {'CHOICE',[#'ComponentType'{name=C1,
 
1391
                                                    typespec=TS,
 
1392
                                                    prop=Prop}|Comps]},
 
1393
                        [{C1,Directive}|Rest],Acc) ->
 
1394
    case Directive of
 
1395
        List when list(List) ->
 
1396
            [Command,Tag] = get_tag_command(TS,?ALTERNATIVE,Prop),
 
1397
            CompAcc = create_pdec_inc_command(ModName,TS#type.def,List,[]),
 
1398
            create_pdec_inc_command(ModName,{'CHOICE',Comps},Rest,
 
1399
                                    [[Command,Tag,CompAcc]|Acc]);
 
1400
        undecoded ->
 
1401
            TagCommand = get_tag_command(TS,?ALTERNATIVE_UNDECODED,Prop),
 
1402
            create_pdec_inc_command(ModName,{'CHOICE',Comps},Rest,
 
1403
                                    [TagCommand|Acc]);
 
1404
        parts ->
 
1405
            TagCommand = get_tag_command(TS,?ALTERNATIVE_PARTS,Prop),
 
1406
            create_pdec_inc_command(ModName,{'CHOICE',Comps},Rest,
 
1407
                                    [TagCommand|Acc])
 
1408
    end;
 
1409
create_pdec_inc_command(ModName,
 
1410
                        {'CHOICE',[#'ComponentType'{typespec=TS,
 
1411
                                                    prop=Prop}|Comps]},
 
1412
                        TNL,Acc) ->
 
1413
    TagCommand = get_tag_command(TS,?ALTERNATIVE,Prop),
 
1414
    create_pdec_inc_command(ModName,{'CHOICE',Comps},TNL,[TagCommand|Acc]);
 
1415
create_pdec_inc_command(M,{'CHOICE',{Cs1,Cs2}},TNL,Acc) 
 
1416
  when list(Cs1),list(Cs2) ->
 
1417
    create_pdec_inc_command(M,{'CHOICE',Cs1 ++ Cs2},TNL,Acc);
 
1418
create_pdec_inc_command(ModName,#'Externaltypereference'{module=M,type=Name},
 
1419
                        TNL,Acc) ->
 
1420
    #type{def=Def} = get_referenced_type(M,Name),
 
1421
    create_pdec_inc_command(ModName,get_components(Def),TNL,Acc);
 
1422
create_pdec_inc_command(_,_,TNL,_) ->
 
1423
    throw({error,{"unexpected error when creating partial "
 
1424
                  "decode command",TNL}}).
 
1425
 
 
1426
partial_inc_dec_toptype([T|_]) when atom(T) ->
 
1427
    T;
 
1428
partial_inc_dec_toptype([{T,_}|_]) when atom(T) ->
 
1429
    T;
 
1430
partial_inc_dec_toptype([L|_]) when list(L) ->
 
1431
    partial_inc_dec_toptype(L);
 
1432
partial_inc_dec_toptype(_) ->
 
1433
    throw({error,{"no top type found for partial incomplete decode"}}).
 
1434
 
 
1435
 
 
1436
%% Creats a list of tags out of the information in TypeList and Types
 
1437
%% that tells which value will be decoded.  Each constructed type that
 
1438
%% is in the TypeList will get a "choosen" command. Only the last
 
1439
%% type/component in the TypeList may be a primitive type. Components
 
1440
%% "on the way" to the final element may get the "skip" or the
 
1441
%% "skip_optional" command.
 
1442
%% CommandList = [Elements]
 
1443
%% Elements = {choosen,Tag}|{skip_optional,Tag}|skip
 
1444
%% Tag is a binary with the tag BER encoded.
 
1445
create_partial_decode_gen_info(ModName,{{_,ModName},TypeList}) ->
 
1446
    case TypeList of
 
1447
        [TopType|Rest] ->
 
1448
            case asn1_db:dbget(ModName,TopType) of
 
1449
                #typedef{typespec=TS} ->
 
1450
                    TagCommand = get_tag_command(TS,?CHOOSEN),
 
1451
                    create_pdec_command(ModName,get_components(TS#type.def),
 
1452
                                        Rest,[TagCommand]);
 
1453
                _ ->
 
1454
                    throw({error,{"wrong type list in asn1 config file",
 
1455
                                  TypeList}})
 
1456
            end;
 
1457
        _ ->
 
1458
            []
 
1459
    end;
 
1460
create_partial_decode_gen_info(_,[]) ->
 
1461
    [];
 
1462
create_partial_decode_gen_info(_M1,{{_,M2},_}) ->
 
1463
    throw({error,{"wrong module name in asn1 config file",
 
1464
                                  M2}}).
 
1465
 
 
1466
%% create_pdec_command/4 for each name (type or component) in the
 
1467
%% third argument, TypeNameList, a command is created. The command has
 
1468
%% information whether the component/type shall be skipped, looked
 
1469
%% into or returned. The list of commands is returned.
 
1470
create_pdec_command(_ModName,_,[],Acc) ->
 
1471
    lists:reverse(Acc);
 
1472
create_pdec_command(ModName,[#'ComponentType'{name=C1,typespec=TS}|_Comps],
 
1473
                    [C1|Cs],Acc) ->
 
1474
    %% this component is a constructed type or the last in the
 
1475
    %% TypeNameList otherwise the config spec is wrong
 
1476
    TagCommand = get_tag_command(TS,?CHOOSEN),
 
1477
    create_pdec_command(ModName,get_components(TS#type.def),
 
1478
                        Cs,[TagCommand|Acc]);
 
1479
create_pdec_command(ModName,[#'ComponentType'{typespec=TS,
 
1480
                                              prop=Prop}|Comps],
 
1481
                    [C2|Cs],Acc) ->
 
1482
    TagCommand = 
 
1483
        case Prop of
 
1484
            mandatory ->
 
1485
                get_tag_command(TS,?SKIP);
 
1486
            _ ->
 
1487
                get_tag_command(TS,?SKIP_OPTIONAL)
 
1488
        end,
 
1489
    create_pdec_command(ModName,Comps,[C2|Cs],[TagCommand|Acc]);
 
1490
create_pdec_command(ModName,{'CHOICE',[Comp=#'ComponentType'{name=C1}|_]},TNL=[C1|_Cs],Acc) ->
 
1491
    create_pdec_command(ModName,[Comp],TNL,Acc);
 
1492
create_pdec_command(ModName,{'CHOICE',[#'ComponentType'{}|Comps]},TNL,Acc) ->
 
1493
    create_pdec_command(ModName,{'CHOICE',Comps},TNL,Acc);
 
1494
create_pdec_command(ModName,#'Externaltypereference'{module=M,type=C1},
 
1495
                    TypeNameList,Acc) ->
 
1496
    case get_referenced_type(M,C1) of
 
1497
        #type{def=Def} ->
 
1498
            create_pdec_command(ModName,get_components(Def),TypeNameList,
 
1499
                                Acc);
 
1500
        Err ->
 
1501
            throw({error,{"unexpected result when fetching "
 
1502
                          "referenced element",Err}})
 
1503
    end;
 
1504
create_pdec_command(ModName,TS=#type{def=Def},[C1|Cs],Acc) ->
 
1505
    %% This case when we got the "components" of a SEQUENCE/SET OF
 
1506
    case C1 of
 
1507
        [1] ->
 
1508
            %% A list with an integer is the only valid option in a 'S
 
1509
            %% OF', the other valid option would be an empty
 
1510
            %% TypeNameList saying that the entire 'S OF' will be
 
1511
            %% decoded.
 
1512
            TagCommand = get_tag_command(TS,?CHOOSEN),
 
1513
            create_pdec_command(ModName,Def,Cs,[TagCommand|Acc]);
 
1514
        [N] when integer(N) ->
 
1515
            TagCommand = get_tag_command(TS,?SKIP),
 
1516
            create_pdec_command(ModName,Def,[[N-1]|Cs],[TagCommand|Acc]);
 
1517
        Err ->
 
1518
            throw({error,{"unexpected error when creating partial "
 
1519
                          "decode command",Err}})
 
1520
    end;
 
1521
create_pdec_command(_,_,TNL,_) ->
 
1522
    throw({error,{"unexpected error when creating partial "
 
1523
                  "decode command",TNL}}).
 
1524
            
 
1525
% get_components({'CHOICE',Components}) ->
 
1526
%     Components;
 
1527
get_components(#'SEQUENCE'{components=Components}) ->
 
1528
    Components;
 
1529
get_components(#'SET'{components=Components}) ->
 
1530
    Components;
 
1531
get_components({'SEQUENCE OF',Components}) ->
 
1532
    Components;
 
1533
get_components({'SET OF',Components}) ->
 
1534
    Components;
 
1535
get_components(Def) ->
 
1536
    Def.
 
1537
                           
 
1538
%% get_tag_command(Type,Command)
 
1539
 
 
1540
%% Type is the type that has information about the tag Command tells
 
1541
%% what to do with the encoded value with the tag of Type when
 
1542
%% decoding. 
 
1543
get_tag_command(#type{tag=[]},_) ->
 
1544
    [];
 
1545
get_tag_command(#type{tag=[_Tag]},?SKIP) ->
 
1546
    ?SKIP;
 
1547
get_tag_command(#type{tag=[Tag]},Command) ->
 
1548
    %% encode the tag according to BER
 
1549
    [Command,encode_tag_val(decode_class(Tag#tag.class),Tag#tag.form, 
 
1550
                            Tag#tag.number)];
 
1551
get_tag_command(T=#type{tag=[Tag|Tags]},Command) ->
 
1552
    [get_tag_command(T#type{tag=Tag},Command)|
 
1553
     get_tag_command(T#type{tag=Tags},Command)].
 
1554
 
 
1555
%% get_tag_command/3 used by create_pdec_inc_command
 
1556
get_tag_command(#type{tag=[]},_,_) ->
 
1557
    [];
 
1558
get_tag_command(#type{tag=[Tag]},?MANDATORY,Prop) ->
 
1559
    case Prop of
 
1560
        mandatory ->
 
1561
            ?MANDATORY;
 
1562
        {'DEFAULT',_} ->
 
1563
            [?DEFAULT,encode_tag_val(decode_class(Tag#tag.class),
 
1564
                                     Tag#tag.form,Tag#tag.number)];
 
1565
        _ -> [?OPTIONAL,encode_tag_val(decode_class(Tag#tag.class),
 
1566
                                       Tag#tag.form,Tag#tag.number)]
 
1567
    end;
 
1568
get_tag_command(#type{tag=[Tag]},Command,_) ->
 
1569
    [Command,encode_tag_val(decode_class(Tag#tag.class),Tag#tag.form, 
 
1570
                            Tag#tag.number)].
 
1571
 
 
1572
 
 
1573
get_referenced_type(M,Name) ->
 
1574
    case asn1_db:dbget(M,Name) of
 
1575
        #typedef{typespec=TS} ->
 
1576
            case TS of
 
1577
                #type{def=#'Externaltypereference'{module=M2,type=Name2}} ->
 
1578
                    %% The tags have already been taken care of in the
 
1579
                    %% first reference where they were gathered in a
 
1580
                    %% list of tags.
 
1581
                    get_referenced_type(M2,Name2);
 
1582
                #type{} -> TS;
 
1583
                _  ->
 
1584
                    throw({error,{"unexpected element when"
 
1585
                                  " fetching referenced type",TS}})
 
1586
            end;
 
1587
        T ->
 
1588
            throw({error,{"unexpected element when fetching "
 
1589
                          "referenced type",T}})
 
1590
    end.
 
1591
 
 
1592
tag_format(EncRule,_Options,CommandList) ->
 
1593
    case EncRule of
 
1594
        ber_bin_v2 ->
 
1595
            tlv_tags(CommandList);
 
1596
        _ ->
 
1597
            CommandList
 
1598
    end.
 
1599
 
 
1600
tlv_tags([]) ->
 
1601
    [];
 
1602
tlv_tags([mandatory|Rest]) ->
 
1603
    [mandatory|tlv_tags(Rest)];
 
1604
tlv_tags([[Command,Tag]|Rest]) when atom(Command),binary(Tag) ->
 
1605
    [[Command,tlv_tag(Tag)]|tlv_tags(Rest)];
 
1606
tlv_tags([[Command,Directives]|Rest]) when atom(Command),list(Directives) ->
 
1607
    [[Command,tlv_tags(Directives)]|tlv_tags(Rest)];
 
1608
%% remove all empty lists
 
1609
tlv_tags([[]|Rest]) ->
 
1610
    tlv_tags(Rest);
 
1611
tlv_tags([{Name,TopType,L1}|Rest]) when list(L1),atom(TopType) ->
 
1612
    [{Name,TopType,tlv_tags(L1)}|tlv_tags(Rest)];
 
1613
tlv_tags([[Command,Tag,L1]|Rest]) when list(L1),binary(Tag) ->
 
1614
    [[Command,tlv_tag(Tag),tlv_tags(L1)]|tlv_tags(Rest)];
 
1615
tlv_tags([L=[L1|_]|Rest]) when list(L1) ->
 
1616
    [tlv_tags(L)|tlv_tags(Rest)].
 
1617
 
 
1618
tlv_tag(<<Cl:2,_:1,TagNo:5>>) when TagNo < 31 ->
 
1619
    (Cl bsl 16) + TagNo;
 
1620
tlv_tag(<<Cl:2,_:1,31:5,0:1,TagNo:7>>) ->
 
1621
    (Cl bsl 16) + TagNo;
 
1622
tlv_tag(<<Cl:2,_:1,31:5,Buffer/binary>>) ->
 
1623
    TagNo = tlv_tag1(Buffer,0),
 
1624
    (Cl bsl 16) + TagNo.
 
1625
tlv_tag1(<<0:1,PartialTag:7>>,Acc) ->
 
1626
    (Acc bsl 7) bor PartialTag;
 
1627
tlv_tag1(<<1:1,PartialTag:7,Buffer/binary>>,Acc) ->
 
1628
    tlv_tag1(Buffer,(Acc bsl 7) bor PartialTag).
 
1629
    
 
1630
%% reads the content from the configuration file and returns the
 
1631
%% selected part choosen by InfoType. Assumes that the config file
 
1632
%% content is an Erlang term.
 
1633
read_config_file(ModuleName,InfoType) when atom(InfoType) ->
 
1634
    CfgList = read_config_file(ModuleName),
 
1635
    get_config_info(CfgList,InfoType).
 
1636
 
 
1637
 
 
1638
read_config_file(ModuleName) ->
 
1639
    case file:consult(lists:concat([ModuleName,'.asn1config'])) of
 
1640
%    case file:consult(ModuleName) of
 
1641
        {ok,CfgList} ->
 
1642
            CfgList;
 
1643
        {error,enoent} ->
 
1644
            Options = get(encoding_options),
 
1645
            Includes = [I || {i,I} <- Options],
 
1646
            read_config_file1(ModuleName,Includes);
 
1647
        {error,Reason} ->
 
1648
            file:format_error(Reason),
 
1649
            throw({error,{"error reading asn1 config file",Reason}})
 
1650
    end.
 
1651
read_config_file1(ModuleName,[]) ->
 
1652
    case filename:extension(ModuleName) of
 
1653
        ".asn1config" ->
 
1654
            throw({error,enoent});
 
1655
        _ ->
 
1656
            read_config_file(lists:concat([ModuleName,".asn1config"]))
 
1657
    end;
 
1658
read_config_file1(ModuleName,[H|T]) ->
 
1659
%    File = filename:join([H,lists:concat([ModuleName,'.asn1config'])]),
 
1660
    File = filename:join([H,ModuleName]),
 
1661
    case file:consult(File) of
 
1662
        {ok,CfgList} ->
 
1663
            CfgList;
 
1664
        {error,enoent} ->
 
1665
            read_config_file1(ModuleName,T);
 
1666
        {error,Reason} ->
 
1667
            file:format_error(Reason),
 
1668
            throw({error,{"error reading asn1 config file",Reason}})
 
1669
    end.
 
1670
    
 
1671
get_config_info(CfgList,InfoType) ->
 
1672
    case InfoType of
 
1673
        all ->
 
1674
            CfgList;
 
1675
        _ ->
 
1676
            case lists:keysearch(InfoType,1,CfgList) of
 
1677
                {value,{InfoType,Value}} ->
 
1678
                    Value;
 
1679
                false ->
 
1680
                    []
 
1681
            end
 
1682
    end.
 
1683
 
 
1684
%% save_config/2 saves the Info with the key Key
 
1685
%% Before saving anything check if a table exists
 
1686
save_config(Key,Info) ->
 
1687
    create_if_no_table(asn1_general,[named_table]),
 
1688
    ets:insert(asn1_general,{{asn1_config,Key},Info}).
 
1689
 
 
1690
read_config_data(Key) ->
 
1691
    case ets:info(asn1_general) of
 
1692
        undefined -> undefined;
 
1693
        _ ->
 
1694
            case ets:lookup(asn1_general,{asn1_config,Key}) of
 
1695
                [{_,Data}] -> Data;
 
1696
                Err -> 
 
1697
                    io:format("strange data from config file ~w~n",[Err]),
 
1698
                    Err
 
1699
            end
 
1700
    end.
 
1701
 
 
1702
 
 
1703
%%
 
1704
%% Functions to manipulate the gen_state record saved in the
 
1705
%% asn1_general ets table.
 
1706
%%
 
1707
 
 
1708
%% saves input data in a new gen_state record
 
1709
save_gen_state({_,ConfList},PartIncTlvTagList) ->
 
1710
    %ConfList=[{FunctionName,PatternList}|Rest]
 
1711
    StateRec = #gen_state{inc_tag_pattern=PartIncTlvTagList,
 
1712
                          inc_type_pattern=ConfList},
 
1713
    save_config(gen_state,StateRec);
 
1714
save_gen_state(_,_) ->
 
1715
%%    ok.
 
1716
    save_config(gen_state,#gen_state{}).
 
1717
 
 
1718
save_gen_state(GenState) when record(GenState,gen_state) ->
 
1719
    save_config(gen_state,GenState).
 
1720
 
 
1721
 
 
1722
%% get_gen_state_field returns undefined if no gen_state exists or if
 
1723
%% Field is undefined or the data at the field.
 
1724
get_gen_state_field(Field) ->
 
1725
    case read_config_data(gen_state) of
 
1726
        undefined ->
 
1727
            undefined;
 
1728
        GenState -> 
 
1729
            get_gen_state_field(GenState,Field)
 
1730
    end.
 
1731
get_gen_state_field(#gen_state{active=Active},active) ->
 
1732
    Active;
 
1733
get_gen_state_field(_,active) ->
 
1734
    false;
 
1735
get_gen_state_field(GS,prefix) ->
 
1736
    GS#gen_state.prefix;
 
1737
get_gen_state_field(GS,inc_tag_pattern) ->
 
1738
    GS#gen_state.inc_tag_pattern;
 
1739
get_gen_state_field(GS,tag_pattern) ->
 
1740
    GS#gen_state.tag_pattern;
 
1741
get_gen_state_field(GS,inc_type_pattern) ->
 
1742
    GS#gen_state.inc_type_pattern;
 
1743
get_gen_state_field(GS,type_pattern) ->
 
1744
    GS#gen_state.type_pattern;
 
1745
get_gen_state_field(GS,func_name) ->
 
1746
    GS#gen_state.func_name;
 
1747
get_gen_state_field(GS,namelist) ->
 
1748
    GS#gen_state.namelist;
 
1749
get_gen_state_field(GS,tobe_refed_funcs) ->
 
1750
    GS#gen_state.tobe_refed_funcs;
 
1751
get_gen_state_field(GS,gen_refed_funcs) ->
 
1752
    GS#gen_state.gen_refed_funcs.
 
1753
    
 
1754
 
 
1755
get_gen_state() ->
 
1756
    read_config_data(gen_state).
 
1757
 
 
1758
 
 
1759
update_gen_state(Field,Data) ->
 
1760
    case get_gen_state() of
 
1761
        State when record(State,gen_state) ->
 
1762
            update_gen_state(Field,State,Data);
 
1763
        _ ->
 
1764
            exit({error,{asn1,{internal,
 
1765
                               "tried to update nonexistent gen_state",Field,Data}}})
 
1766
    end.
 
1767
update_gen_state(active,State,Data) ->
 
1768
    save_gen_state(State#gen_state{active=Data});
 
1769
update_gen_state(prefix,State,Data) ->
 
1770
    save_gen_state(State#gen_state{prefix=Data});
 
1771
update_gen_state(inc_tag_pattern,State,Data) ->
 
1772
    save_gen_state(State#gen_state{inc_tag_pattern=Data});
 
1773
update_gen_state(tag_pattern,State,Data) ->
 
1774
    save_gen_state(State#gen_state{tag_pattern=Data});
 
1775
update_gen_state(inc_type_pattern,State,Data) ->
 
1776
    save_gen_state(State#gen_state{inc_type_pattern=Data});
 
1777
update_gen_state(type_pattern,State,Data) ->
 
1778
    save_gen_state(State#gen_state{type_pattern=Data});
 
1779
update_gen_state(func_name,State,Data) ->
 
1780
    save_gen_state(State#gen_state{func_name=Data});
 
1781
update_gen_state(namelist,State,Data) ->
 
1782
%     SData =
 
1783
%       case Data of
 
1784
%           [D] when list(D) -> D;
 
1785
%           _ -> Data
 
1786
%       end,
 
1787
    save_gen_state(State#gen_state{namelist=Data});
 
1788
update_gen_state(tobe_refed_funcs,State,Data) ->
 
1789
    save_gen_state(State#gen_state{tobe_refed_funcs=Data});
 
1790
update_gen_state(gen_refed_funcs,State,Data) ->
 
1791
    save_gen_state(State#gen_state{gen_refed_funcs=Data}).
 
1792
 
 
1793
update_namelist(Name) ->
 
1794
    case get_gen_state_field(namelist) of
 
1795
        [Name,Rest] -> update_gen_state(namelist,Rest);
 
1796
        [Name|Rest] -> update_gen_state(namelist,Rest);
 
1797
        [{Name,List}] when list(List) -> update_gen_state(namelist,List);
 
1798
        [{Name,Atom}|Rest] when atom(Atom) -> update_gen_state(namelist,Rest);
 
1799
        Other -> Other
 
1800
    end.
 
1801
 
 
1802
pop_namelist() ->
 
1803
    DeepTail = %% removes next element in order
 
1804
        fun([[{_,A}]|T],_Fun) when atom(A) -> T;
 
1805
           ([{_N,L}|T],_Fun) when list(L) -> [L|T];
 
1806
           ([[]|T],Fun) -> Fun(T,Fun);
 
1807
           ([L1|L2],Fun) when list(L1) ->
 
1808
                case lists:flatten(L1) of
 
1809
                    [] -> Fun([L2],Fun);
 
1810
                    _ -> [Fun(L1,Fun)|L2]
 
1811
                end;
 
1812
           ([_H|T],_Fun) -> T
 
1813
        end,
 
1814
    {Pop,NewNL} =
 
1815
        case get_gen_state_field(namelist) of
 
1816
            [] -> {[],[]};
 
1817
            L ->
 
1818
                {next_namelist_el(L),
 
1819
                 DeepTail(L,DeepTail)}
 
1820
        end,
 
1821
    update_gen_state(namelist,NewNL),
 
1822
    Pop.
 
1823
 
 
1824
%% next_namelist_el fetches the next type/component name in turn in
 
1825
%% the namelist, without changing the namelist.
 
1826
next_namelist_el() ->
 
1827
    case get_gen_state_field(namelist) of
 
1828
        undefined -> undefined;
 
1829
        L when list(L) -> next_namelist_el(L)
 
1830
    end.
 
1831
 
 
1832
next_namelist_el([]) ->
 
1833
    [];
 
1834
next_namelist_el([L]) when list(L) ->
 
1835
    next_namelist_el(L);
 
1836
next_namelist_el([H|_]) when atom(H) ->
 
1837
    H;
 
1838
next_namelist_el([L|T]) when list(L) ->
 
1839
    case next_namelist_el(L) of
 
1840
        [] ->
 
1841
            next_namelist_el([T]);
 
1842
        R ->
 
1843
            R
 
1844
    end;
 
1845
next_namelist_el([H={_,A}|_]) when atom(A) ->
 
1846
    H.
 
1847
 
 
1848
%% removes a bracket from the namelist
 
1849
step_in_constructed() ->
 
1850
    case get_gen_state_field(namelist) of
 
1851
        [L] when list(L) ->
 
1852
            update_gen_state(namelist,L);
 
1853
        _ -> ok
 
1854
    end.
 
1855
                        
 
1856
is_function_generated(Name) ->
 
1857
    case get_gen_state_field(gen_refed_funcs) of
 
1858
        L when list(L) ->
 
1859
            lists:member(Name,L);
 
1860
        _ ->
 
1861
            false
 
1862
    end.
 
1863
                               
 
1864
get_tobe_refed_func(Name) ->
 
1865
    case get_gen_state_field(tobe_refed_funcs) of
 
1866
        L when list(L) ->
 
1867
            case lists:keysearch(Name,1,L) of
 
1868
                {_,Element} ->
 
1869
                    Element;
 
1870
                _ ->
 
1871
                    undefined
 
1872
            end;
 
1873
        _ ->
 
1874
            undefined
 
1875
    end.
 
1876
 
 
1877
add_tobe_refed_func(Data) ->
 
1878
    L = get_gen_state_field(tobe_refed_funcs),
 
1879
    update_gen_state(tobe_refed_funcs,[Data|L]).
 
1880
 
 
1881
%% moves Name from the to be list to the generated list.
 
1882
generated_refed_func(Name) ->
 
1883
    L = get_gen_state_field(tobe_refed_funcs),
 
1884
    NewL = lists:keydelete(Name,1,L),
 
1885
    update_gen_state(tobe_refed_funcs,NewL),
 
1886
    L2 = get_gen_state_field(gen_refed_funcs),
 
1887
    update_gen_state(gen_refed_funcs,[Name|L2]).
 
1888
 
 
1889
add_generated_refed_func(Data) ->
 
1890
    L = get_gen_state_field(gen_refed_funcs),
 
1891
    update_gen_state(gen_refed_funcs,[Data|L]).
 
1892
 
 
1893
 
 
1894
next_refed_func() ->
 
1895
    case get_gen_state_field(tobe_refed_funcs) of
 
1896
        [] ->
 
1897
            [];
 
1898
        [H|T] ->
 
1899
            update_gen_state(tobe_refed_funcs,T),
 
1900
            H
 
1901
    end.
 
1902
 
 
1903
reset_gen_state() ->
 
1904
    save_gen_state(#gen_state{}).