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/.
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
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.''
21
-export([compile/1, compile/2, compile/3,
22
mib_to_hrl/1, mib_to_hrl/3,
31
-include_lib("stdlib/include/erl_compile.hrl").
32
-include("snmp_types.hrl").
33
-include("snmpc.hrl").
37
io:format("~p ~n", [snmpc_lib:look_at(Mib)]).
40
%%-----------------------------------------------------------------
41
%% Misc compiler stuff
42
%%-----------------------------------------------------------------
44
is_consistent(Filenames) ->
45
snmpc_lib:is_consistent(Filenames).
47
mib_to_hrl(MibName) ->
48
snmpc_mib_to_hrl:convert(MibName).
50
mib_to_hrl(MibName, HrlFile, Opts) ->
51
snmpc_mib_to_hrl:compile(MibName, HrlFile, Opts).
54
%%%-----------------------------------------------------------------
55
%%% Interface for erl_compile.
56
%%%-----------------------------------------------------------------
58
compile(Input, _Output, Options) ->
59
case compile(Input, make_options(Options)) of
63
io:format("~p", [Reason]),
67
%% Converts generic options to format expected by compile/2
69
make_options(#options{includes = Incs,
74
OutdirOpt = {outdir, Outdir},
78
0 -> {warnings, false};
87
lists:map(fun(Dir) -> Dir++"/" end, Incs)
90
[WarningOpt, OutdirOpt, IncludeOpt | Spec].
92
%% Returns: {ok, File}|{error, Reason}
93
compile([AtomFilename]) when atom(AtomFilename) ->
94
compile(atom_to_list(AtomFilename), []), % from cmd line
97
compile(FileName, []).
100
%%----------------------------------------------------------------------
102
%% {deprecated, bool()} true
103
%% {group_check, bool()} true
104
%% {db, volatile|persistent|mnesia} volatile
105
%% {i, [import_dir_string()]} ["./"]
106
%% {il, [import_lib_dir_string()]} []
107
%% {warnings, bool()} true
108
%% {outdir, string()} "./"
112
%% {module, string()}
114
%% (hidden) {verbosity, trace|debug|log|info|silence} silence
117
%%----------------------------------------------------------------------
119
compile(FileName, Options) when list(FileName) ->
120
true = snmpc_misc:is_string(FileName),
121
DefOpts = [{deprecated, true},
128
Opts = update_options(DefOpts, Options),
129
case check_options(Opts) of
131
maybe_display_version(Opts),
132
maybe_display_options(Opts),
133
Pid = spawn_link(?MODULE,init,[self(),FileName,Opts]),
135
{compile_result,R} -> R;
136
{'EXIT',Pid, Reason} when Reason =/= normal ->
143
maybe_display_version(Opts) ->
144
case lists:member(version, Opts) of
146
Vsn = (catch get_version()),
147
io:format("version: ~s~n", [Vsn]);
153
MI = ?MODULE:module_info(),
154
Attr = get_info(attributes, MI),
155
Vsn = get_info(app_vsn, Attr),
156
Comp = get_info(compile, MI),
157
Time = get_info(time, Comp),
158
{Year, Month, Day, Hour, Min, Sec} = Time,
159
io_lib:format("~s [~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w]",
160
[Vsn, Year, Month, Day, Hour, Min, Sec]).
162
maybe_display_options(Opts) ->
163
case lists:member(options, Opts) of
165
{F, A} = get_options(Opts, [], []),
166
io:format("options: " ++ F ++ "~n", A);
171
get_options([], Formats, Args) ->
172
{lists:concat(lists:reverse(Formats)), lists:reverse(Args)};
173
get_options([{deprecated, Val}|Opts], Formats, Args) ->
174
get_options(Opts, ["~n deprecated: ~w"|Formats], [Val|Args]);
175
get_options([{group_check, Val}|Opts], Formats, Args) ->
176
get_options(Opts, ["~n group_check: ~w"|Formats], [Val|Args]);
177
get_options([{db, Val}|Opts], Formats, Args) ->
178
get_options(Opts, ["~n db: ~w"|Formats], [Val|Args]);
179
get_options([{i, Val}|Opts], Formats, Args) ->
180
get_options(Opts, ["~n i: ~p"|Formats], [Val|Args]);
181
get_options([{il, Val}|Opts], Formats, Args) ->
182
get_options(Opts, ["~n il: ~p"|Formats], [Val|Args]);
183
get_options([{outdir, Val}|Opts], Formats, Args) ->
184
get_options(Opts, ["~n outdir: ~s"|Formats], [Val|Args]);
185
get_options([{description, Val}|Opts], Formats, Args) ->
186
get_options(Opts, ["~n description: ~w"|Formats], [Val|Args]);
187
get_options([description|Opts], Formats, Args) ->
188
get_options(Opts, ["~n description"|Formats], Args);
189
get_options([{warnings, Val}|Opts], Formats, Args) ->
190
get_options(Opts, ["~n warnings: ~w"|Formats], [Val|Args]);
191
get_options([{verbosity, Val}|Opts], Formats, Args) ->
192
get_options(Opts, ["~n verbosity: ~w"|Formats], [Val|Args]);
193
get_options([imports|Opts], Formats, Args) ->
194
get_options(Opts, ["~n imports"|Formats], Args);
195
get_options([module_identity|Opts], Formats, Args) ->
196
get_options(Opts, ["~n module_identity"|Formats], Args);
197
get_options([_|Opts], Formats, Args) ->
198
get_options(Opts, Formats, Args).
201
get_info(Key, Info) ->
202
case lists:keysearch(Key, 1, Info) of
203
{value, {Key, Val}} ->
210
% io:format("DBG: " ++ F ++ "~n", A).
212
update_options([], Options) ->
214
update_options([{Key,DefVal}|DefOpts], Options) ->
215
case snmpc_misc:assq(Key, Options) of
217
update_options(DefOpts, [{Key,DefVal}|Options]);
218
{value, Val} when Key == i ->
220
lists:keyreplace(Key, 1, Options, {Key, Val++DefVal}),
221
update_options(DefOpts, Options1);
222
{value, Val} when Key == il ->
224
lists:keyreplace(Key, 1, Options, {Key, Val++DefVal}),
225
update_options(DefOpts, Options1);
226
{value, DefVal} -> %% Same value, no need to update
227
update_options(DefOpts, Options);
228
{value, Val} -> %% New value, so update
230
lists:keyreplace(Key, 1, Options, {Key, Val}),
231
update_options(DefOpts, Options1)
233
update_options([Opt|DefOpts], Options) ->
234
case lists:member(Opt, Options) of
236
update_options(DefOpts, Options);
238
update_options(DefOpts, [Opt|Options])
241
check_options([]) -> ok;
242
check_options([no_symbolic_info|T]) -> check_options(T);
243
check_options([{outdir, Str} | T]) when list(Str) ->
245
check_options([{debug, Atom} | T]) when atom(Atom) ->
247
check_options([{deprecated, Atom} | T]) when atom(Atom) ->
249
check_options([{group_check, Atom} | T]) when atom(Atom) ->
251
check_options([{warnings, Bool} | T]) ->
252
check_bool(warnings, Bool),
254
check_options([{db, volatile} | T]) ->
256
check_options([{db, persistent} | T]) ->
258
check_options([{db, mnesia} | T]) ->
260
check_options([{i, [Str|_]} | T]) when list(Str) ->
262
check_options([{il, []} | T]) ->
264
check_options([{il, [Str|_]} | T]) when list(Str) ->
266
check_options([{description, Bool}| T]) ->
267
check_bool(description, Bool),
269
check_options([description| T]) -> %% same as {description, true}
271
check_options([{verbosity, V} | T]) when atom(V) ->
272
snmpc_lib:vvalidate(V),
274
check_options([version| T]) ->
276
check_options([options| T]) ->
278
check_options([imports| T]) ->
280
check_options([module_identity| T]) ->
282
check_options([{module, M} | T]) when atom(M) ->
284
check_options([no_defs| T]) ->
286
check_options([Opt|_]) ->
287
{error, {invalid_option, Opt}}.
290
check_bool(_Key, Bool) when Bool == true; Bool == false ->
292
check_bool(Key, Val) ->
293
{error, {invalid_option, {Key, Val}}}.
295
get_group_check(Options) ->
296
snmpc_lib:key1search(group_check, Options, true).
298
get_deprecated(Options) ->
299
snmpc_lib:key1search(deprecated, Options, true).
301
get_description(Options) ->
302
case lists:member(description,Options) of
304
snmpc_lib:key1search(description,Options,false);
309
make_description(Message) ->
310
case get(description) of
319
%%----------------------------------------------------------------------
321
%%----------------------------------------------------------------------
323
t(F,A) -> snmpc_lib:t(F,A).
324
%% d(F,A) -> snmpc_lib:d(F,A).
325
l(F,A) -> snmpc_lib:l(F,A).
326
i(F,A) -> snmpc_lib:i(F,A).
327
i(F,A,L) -> snmpc_lib:i(F,A,L).
328
%% w(F,A) -> snmpc_lib:w(F,A).
329
w(F,A,L) -> snmpc_lib:w(F,A,L).
331
%% Verbosity level is selected from three (historical reasons)
332
%% options: warnings, debug and verbosity
333
%% - If warnings is true, then verbosity is _atleast_ warning
334
%% (even if the verbosity flag is set to silence)
335
%% - If debug is true, the verbosity is _atleast_ log
336
%% - Otherwise, verbosity is used as is.
337
get_verbosity(Options) ->
339
case snmpc_lib:key1search(warnings, Options) of
345
case snmpc_lib:key1search(verbosity, Options) of
347
%% Backward compatible: If not defined then try debug and convert
348
case snmpc_lib:key1search(debug, Options, false) of
361
%%----------------------------------------------------------------------
362
%% The compile process.
363
%%----------------------------------------------------------------------
365
init(From, MibFileName, Options) ->
368
put(options, Options),
369
put(verbosity, get_verbosity(Options)),
370
put(description, get_description(Options)),
371
File = filename:rootname(MibFileName, ".mib"),
372
put(filename, filename:basename(File ++ ".mib")),
373
R = case catch c_impl(File) of
374
{ok, OutFile} -> {ok, OutFile};
375
{'EXIT',error} -> {error, compilation_failed};
378
From ! {compile_result, R}.
382
{ok, PData} = parse(File),
383
t("Syntax analysis:~n"
385
MibName = compile_parsed_data(PData),
386
t("Compiler output:~n"
388
save(File, MibName, get(options)).
390
compile_parsed_data(#pdata{mib_name = MibName,
392
defs = Definitions}) ->
393
snmpc_lib:import(Imports),
394
update_imports(Imports),
395
Deprecated = get_deprecated(get(options)),
396
definitions_loop(Definitions, Deprecated),
399
update_imports(Imports) ->
400
case lists:member(imports, get(options)) of
402
IMPs = do_update_imports(Imports, []),
404
put(cdata, CDATA#cdata{imports = IMPs});
409
do_update_imports([], Acc) ->
411
do_update_imports([{{Mib, ImportsFromMib0},_Line}|Imports], Acc) ->
412
ImportsFromMib = [Name || {_, Name} <- ImportsFromMib0],
413
Import = {Mib, ImportsFromMib},
414
do_update_imports(Imports, [Import|Acc]).
417
update_status(Name, Status) ->
418
#cdata{status_ets = Ets} = get(cdata),
419
ets:insert(Ets, {Name, Status}).
422
%% A deprecated object
423
definitions_loop([{#mc_object_type{name = ObjName, status = deprecated},
426
%% May be implemented but the compiler chooses not to.
427
i("object_type ~w is deprecated => ignored",[ObjName],Line),
428
update_status(ObjName, deprecated),
429
definitions_loop(T, false);
432
definitions_loop([{#mc_object_type{name = ObjName, status = obsolete},
435
l("object_type ~w (~w) is obsolete => ignored",[ObjName,Line]),
436
%% No need to implement a obsolete object
437
update_status(ObjName, obsolete),
438
ensure_macro_imported('OBJECT-TYPE', Line),
439
definitions_loop(T, Deprecated);
442
definitions_loop([{#mc_object_type{name = NameOfTable,
443
syntax = {{sequence_of, SeqName}, _},
444
max_access = Taccess,
449
name_assign = Tindex},
451
{#mc_object_type{name = NameOfEntry,
452
syntax = {{type, SeqName}, TEline},
453
max_access = 'not-accessible',
454
kind = {table_entry, IndexingInfo},
458
name_assign = {NameOfTable,[1]}},
460
{#mc_sequence{name = SeqName,
464
l("defloop -> [object_type(sequence_of),object_type(type,[1]),sequence]:~n"
475
" IndexingInfo: ~p~n"
481
[NameOfTable,SeqName,Taccess,Kind,Tstatus,
483
NameOfEntry,TEline,IndexingInfo,Estatus,Eunits,Eline,
485
update_status(NameOfTable, Tstatus),
486
update_status(NameOfEntry, Estatus),
487
update_status(SeqName, undefined),
488
ensure_macro_imported('OBJECT-TYPE', Tline),
489
test_table(NameOfTable,Taccess,Kind,Tindex,Tline),
490
{Tfather,Tsubindex} = Tindex,
491
snmpc_lib:register_oid(Tline,NameOfTable,Tfather,Tsubindex),
492
Description1 = make_description(Desc1),
493
TableME = #me{aliasname = NameOfTable,
495
access = 'not-accessible',
496
description = Description1,
498
snmpc_lib:register_oid(TEline,NameOfEntry,NameOfTable,[1]),
499
Description2 = make_description(Desc2),
500
TableEntryME = #me{aliasname = NameOfEntry,
501
entrytype = table_entry,
502
assocList = [{table_entry_with_sequence, SeqName}],
503
access = 'not-accessible',
504
description = Description2,
507
define_cols(ColsEtc, 1, FieldList, NameOfEntry, NameOfTable, []),
508
TableInfo = snmpc_lib:make_table_info(Eline, NameOfTable,
509
IndexingInfo, ColMEs),
510
snmpc_lib:add_cdata(#cdata.mes,
512
TableME#me{assocList=[{table_info,
515
definitions_loop(RestObjs, Deprecated);
517
definitions_loop([{#mc_object_type{name = NameOfTable,
518
syntax = {{sequence_of, SeqName},_},
519
max_access = Taccess,
524
name_assign = Tindex}, Tline},
525
{#mc_object_type{name = NameOfEntry,
526
syntax = {{type, SeqName},_},
527
max_access = 'not-accessible',
528
kind = {table_entry,IndexingInfo},
532
name_assign = BadOID}, Eline},
533
{#mc_sequence{name = SeqName,
534
fields = FieldList}, Sline}|ColsEtc],
537
"[object_type(sequence_of),object_type(type),sequence(fieldList)]:~n"
547
" IndexingInfo: ~p~n"
554
[NameOfTable,SeqName,Taccess,Kind,Tstatus,
556
NameOfEntry,IndexingInfo,Estatus,BadOID,Eunits,Eline,
558
update_status(NameOfTable, Tstatus),
559
update_status(NameOfEntry, Estatus),
560
update_status(SeqName, undefined),
561
ensure_macro_imported('OBJECT-TYPE', Tline),
562
snmpc_lib:print_error("Bad TableEntry OID definition (~w)",
564
test_table(NameOfTable,Taccess,Kind,Tindex,Tline),
565
{Tfather,Tsubindex} = Tindex,
566
snmpc_lib:register_oid(Tline,NameOfTable,Tfather,Tsubindex),
567
Description1 = make_description(Desc1),
568
TableME = #me{aliasname = NameOfTable,
570
access = 'not-accessible',
571
description = Description1,
573
Description2 = make_description(Desc2),
574
TableEntryME = #me{aliasname = NameOfEntry,
575
entrytype = table_entry,
576
access = 'not-accessible',
577
assocList = [{table_entry_with_sequence,SeqName}],
578
description = Description2,
581
define_cols(ColsEtc, 1, FieldList, NameOfEntry, NameOfTable, []),
582
TableInfo = snmpc_lib:make_table_info(Eline, NameOfTable,
583
IndexingInfo, ColMEs),
584
snmpc_lib:add_cdata(#cdata.mes,
586
TableME#me{assocList=[{table_info,
589
definitions_loop(RestObjs, Deprecated);
591
definitions_loop([{#mc_new_type{name = NewTypeName,
594
display_hint = DisplayHint},Line}|T],
596
l("defloop -> new_type:~n"
601
" Line: ~p",[Macro,NewTypeName,OldType,DisplayHint,Line]),
602
ensure_macro_imported(Macro,Line),
603
Types = (get(cdata))#cdata.asn1_types,
604
case lists:keysearch(NewTypeName, #asn1_type.aliasname, Types) of
606
snmpc_lib:print_error("Type ~w already defined.",
609
%% NameOfOldType = element(2,OldType),
610
ASN1 = snmpc_lib:make_ASN1type(OldType),
611
snmpc_lib:add_cdata(#cdata.asn1_types,
612
[ASN1#asn1_type{aliasname = NewTypeName,
614
display_hint = DisplayHint}])
616
definitions_loop(T, Deprecated);
619
definitions_loop([{#mc_object_type{name = NewVarName,
622
kind = {variable, DefVal},
626
name_assign = {Parent,SubIndex}},Line} |T],
628
l("defloop -> object_type (variable):~n"
638
[NewVarName, Type, Access, DefVal, Status, Units, Parent, SubIndex, Line]),
639
update_status(NewVarName, Status),
640
snmpc_lib:test_father(Parent, NewVarName, SubIndex, Line),
641
ASN1type = snmpc_lib:make_ASN1type(Type),
642
snmpc_lib:register_oid(Line, NewVarName, Parent, SubIndex),
643
Description1 = make_description(Desc1),
644
NewME = #me{aliasname = NewVarName,
645
asn1_type = ASN1type,
646
entrytype = variable,
648
description = Description1,
651
NewME2 = snmpc_lib:resolve_defval(NewME),
652
%% hmm, should this be done in resolve_defval?
653
VI = snmpc_lib:make_variable_info(NewME2),
654
snmpc_lib:add_cdata(#cdata.mes,
655
[NewME2#me{assocList = [{variable_info, VI}]}]),
656
definitions_loop(T, Deprecated);
658
definitions_loop([{#mc_module_identity{name = NewVarName,
664
name_assign = {Parent, SubIndex}},
667
l("defloop -> module-identity: "
677
[NewVarName, LU, Org, CI, Desc, Revs0, Parent, SubIndex, Line]),
678
ensure_macro_imported('MODULE-IDENTITY', Line),
679
snmpc_lib:register_oid(Line, NewVarName, Parent, SubIndex),
680
Revs = [{R,D}||#mc_revision{revision = R,description = D} <- Revs0],
681
MI = #module_identity{last_updated = LU,
687
put(cdata, CDATA#cdata{module_identity = MI}),
690
[snmpc_lib:makeInternalNode2(false, NewVarName)]),
691
definitions_loop(T, Deprecated);
693
definitions_loop([{#mc_internal{name = NewVarName,
696
sub_index = SubIndex},Line}|T],
698
l("defloop -> internal:~n"
703
" Line: ~p",[NewVarName, Macro, Parent, SubIndex, Line]),
704
ensure_macro_imported(Macro, Line),
705
snmpc_lib:register_oid(Line, NewVarName, Parent, SubIndex),
708
[snmpc_lib:makeInternalNode2(false, NewVarName)]),
709
definitions_loop(T, Deprecated);
712
definitions_loop([{#mc_trap{name = TrapName,
713
enterprise = EnterPrise,
716
num = SpecificCode}, Line}|T],
718
l("defloop -> trap:~n"
722
" SpecificCode: ~p~n"
724
[TrapName,EnterPrise,Variables,SpecificCode,Line]),
725
update_status(TrapName, undefined),
727
snmpc_lib:check_trap_name(EnterPrise, Line, CDATA#cdata.mes),
728
Descriptions = make_description(Desc1),
729
Trap = #trap{trapname = TrapName,
730
enterpriseoid = EnterPrise,
731
specificcode = SpecificCode,
732
%% oidobjects: Store Variables temporary here.
733
%% This will be replaced later in the
734
%% get_final_mib function by a call to
735
%% the update_trap_objects function.
736
oidobjects = Variables,
737
description = Descriptions},
738
snmpc_misc:map({snmpc_lib,check_trap}, [Trap, Line],
740
snmpc_lib:add_cdata(#cdata.traps, [Trap]),
741
definitions_loop(T, Deprecated);
743
definitions_loop([{#mc_object_type{name = NameOfEntry,
745
max_access = Eaccess,
746
kind = {table_entry, Index},
748
name_assign = SubIndex},Eline}|T],
750
l("defloop -> object_type (table_entry):~n"
759
[NameOfEntry,Type,Eaccess,Index,Estatus,SubIndex,Eline]),
760
update_status(NameOfEntry, Estatus),
761
snmpc_lib:print_error("Misplaced TableEntry definition (~w)",
762
[NameOfEntry],Eline),
763
definitions_loop(T, Deprecated);
765
definitions_loop([{#mc_notification{name = TrapName,
766
status = deprecated}, Line}|T],
768
i("defloop -> notification ~w is deprecated => ignored",
770
update_status(TrapName, deprecated),
771
ensure_macro_imported('NOTIFICATION-TYPE', Line),
772
definitions_loop(T, false);
774
definitions_loop([{#mc_notification{name = TrapName,
775
status = obsolete}, Line}|T],
777
l("defloop -> notification ~w (~w) is obsolete => ignored",
779
update_status(TrapName, obsolete),
780
ensure_macro_imported('NOTIFICATION-TYPE', Line),
781
definitions_loop(T, Deprecated);
783
definitions_loop([{#mc_notification{name = TrapName,
787
name_assign = {Parent, SubIndex}},Line}|T],
789
l("defloop -> notification:~n"
796
[TrapName, Variables, Status, Parent, SubIndex, Line]),
797
update_status(TrapName, Status),
798
ensure_macro_imported('NOTIFICATION-TYPE', Line),
800
snmpc_lib:register_oid(Line, TrapName, Parent, SubIndex),
801
Descriptions = make_description(Desc),
802
Notif = #notification{trapname = TrapName,
803
description = Descriptions,
804
%% oidobjects: Store Variables temporary here.
805
%% This will be replaced later in the
806
%% get_final_mib function by a call to
807
%% the update_trap_objects function.
808
oidobjects = Variables},
809
snmpc_lib:check_notification(Notif, Line, CDATA#cdata.traps),
810
snmpc_lib:add_cdata(#cdata.traps, [Notif]),
811
definitions_loop(T, Deprecated);
813
definitions_loop([{#mc_module_compliance{name = Name},Line}|T], Deprecated) ->
814
l("defloop -> module_compliance:~n"
816
" Line: ~p",[Name,Line]),
817
ensure_macro_imported('MODULE-COMPLIANCE', Line),
818
definitions_loop(T, Deprecated);
820
definitions_loop([{#mc_object_group{name = Name,
821
objects = GroupObjects,
822
status = Status}, Line}|T],
824
l("defloop -> object_group ~p:~n"
826
" GroupObjects: ~p~n"
827
" Line: ~p",[Name,Status,GroupObjects,Line]),
828
ensure_macro_imported('OBJECT-GROUP', Line),
829
GroupBool = get_group_check(get(options)),
832
snmpc_lib:add_cdata(#cdata.objectgroups,
833
[{Name,GroupObjects,Line}]),
834
%% Check that the group members has been defined
835
%% and that they have the correct status
836
snmpc_lib:check_object_group(Name, GroupObjects,
841
definitions_loop(T, Deprecated);
843
definitions_loop([{#mc_notification_group{name = Name,
844
objects = GroupObjects,
845
status = Status},Line}
847
l("defloop -> notification_group ~p: ~n"
849
" GroupObjects: ~p~n"
850
" Line: ~p",[Name,Status,GroupObjects,Line]),
851
ensure_macro_imported('NOTIFICATION-GROUP', Line),
852
GroupBool = get_group_check(get(options)),
855
snmpc_lib:add_cdata(#cdata.notificationgroups,
856
[{Name,GroupObjects,Line}]),
858
%% Check that the group members has been defined
859
%% and that they have the correct status
860
snmpc_lib:check_notification_group(Name, GroupObjects,
865
definitions_loop(T, Deprecated);
867
definitions_loop([{#mc_object_type{name = NameOfTable,
868
syntax = {{sequence_of, SeqName},_},
869
status = Tstatus},Tline},
872
l("defloop -> object_type (sequence_of)~n"
878
[NameOfTable,SeqName,Tline,Entry,Seq]),
879
update_status(NameOfTable, Tstatus),
881
{#mc_object_type{syntax = {{type, SeqName},_line},
882
max_access = 'not-accessible',
883
kind = {table_entry, _IndexingInfo},
884
name_assign = {_NameOfTable,[1]}}, _Eline} ->
886
{#mc_sequence{name = SeqName}, Sline} ->
887
snmpc_lib:error("Internal error. Correct incorrect "
888
"table (~p,~w).",[SeqName,Sline],
891
i("defloop -> Invalid sequence: ~p",[Seq]),
892
snmpc_lib:print_error(
893
"Invalid SEQUENCE OF '~p'.",
894
[safe_elem(1,safe_elem(2,Seq))],Tline)
897
i("defloop -> Invalid table entry: Else = ~p",[Else]),
898
snmpc_lib:print_error(
899
"Invalid TableEntry '~p' (check STATUS, Sequence name, Oid)",
900
[safe_elem(1,safe_elem(2,Entry))],Tline)
902
definitions_loop(T, Deprecated);
904
definitions_loop([{#mc_object_type{name = NameOfTable,
905
syntax = {{sequence_of, SeqName},_},
906
status = Tstatus},Tline}|T],
908
l("defloop -> object_type (sequence_of):~n"
911
" Tline: ~p",[NameOfTable,SeqName,Tline]),
912
update_status(NameOfTable, Tstatus),
913
snmpc_lib:print_error("Invalid statements following table ~p.",
914
[NameOfTable],Tline),
915
definitions_loop(T, Deprecated);
917
definitions_loop([{#mc_sequence{name = SeqName,
918
fields = FieldList},Line}|T],
920
l("defloop -> sequence (fieldList):"
923
"~n Line: ~p",[SeqName, FieldList, Line]),
924
w("Unexpected SEQUENCE ~w, ignoring.",[SeqName],Line),
925
definitions_loop(T, Deprecated);
927
definitions_loop([{Obj,Line}|T], Deprecated) ->
928
i("defloop -> unknown Error ~n"
930
" Line: ~p",[Obj,Line]),
931
snmpc_lib:print_error("Unknown Error in MIB. "
932
"Can't describe the error better than this: ~999p ignored."
933
" Please send a trouble report to support@erlang.ericsson.se.",
935
definitions_loop(T, Deprecated);
937
definitions_loop([], _Deprecated) ->
938
l("defloop -> done",[]),
942
case catch(element(N,T)) of
944
"no more information available";
949
define_cols([{#mc_object_type{name = NameOfCol,
952
kind = {variable,Defval},
956
name_assign = {NameOfEntry,[SubIndex]}},
959
[{NameOfCol,Type2}|Fields], NameOfEntry, TableName, ColMEs) ->
960
l("defcols -> object_type (variable):~n"
969
[NameOfCol,Type1,Access,Defval,Status,Units,NameOfEntry,Oline]),
970
update_status(NameOfCol, Status),
971
Deprecated = get_deprecated(get(options)),
972
ASN1type = snmpc_lib:make_ASN1type(Type1),
973
case (snmpc_lib:make_ASN1type(Type2))#asn1_type.bertype of
974
T2 when T2 == ASN1type#asn1_type.bertype -> ok;
977
"Types for ~p differs from the SEQUENCE definition. ",
980
NewAccess = % a simple way to get the obsolete behaviour
982
Status == obsolete ->
983
%% Be quiet and don't implement
985
Status == deprecated, Deprecated == false ->
986
%% The compiler chooses not to implement the column.
987
i("object_type ~w is deprecated => ignored",
992
snmpc_lib:register_oid(Oline,NameOfCol,NameOfEntry,[SubIndex]),
993
Description = make_description(Desc),
994
ColumnME = snmpc_lib:resolve_defval(
996
aliasname = NameOfCol,
997
asn1_type = ASN1type,
998
entrytype = table_column,
1000
description = Description,
1001
units = Units, %% Propably not usefull
1002
assocList = [{table_name,TableName} | Defval]}),
1003
define_cols(Rest,SubIndex+1,Fields,NameOfEntry,TableName,
1006
%% A "hole" (non-consecutive columns) in the table.
1007
%% Implemented as a not-accessible column so Col always is index in
1009
define_cols([{#mc_object_type{name = NameOfCol,
1011
max_access = Access,
1014
name_assign = {NameOfEntry,[SubIndex]}},
1016
ExpectedSubIndex, Fields, NameOfEntry, TableName, ColMEs)
1017
when SubIndex > ExpectedSubIndex ->
1018
l("defcols -> object_type (non consecutive cols):~n"
1025
[NameOfCol,Type1,Access,Status,NameOfEntry,Oline]),
1026
update_status(NameOfCol, Status),
1027
Int = {{type, 'INTEGER'},Oline},
1029
%% be sure to use an invalid column name here!
1030
{#mc_object_type{name = '$no_name$',
1032
max_access = 'not-accessible',
1033
kind = {variable, [{defval,0}]},
1035
description = undefined,
1036
name_assign = {NameOfEntry, [ExpectedSubIndex]}},
1038
define_cols([GeneratedColumn,
1039
{#mc_object_type{name = NameOfCol,
1041
max_access = Access,
1044
description = undefined,
1045
name_assign = {NameOfEntry,[SubIndex]}},
1046
Oline}|Rest], ExpectedSubIndex,
1047
[{'$no_name$', Int}|Fields], NameOfEntry, TableName,ColMEs) ;
1049
%% Ok. done. All fields are eaten.
1050
define_cols(Rest, _SubIndex, [], _NameOfEntry, _TableName, ColMEs) ->
1056
%% The name of the field and object is the same
1057
define_cols([{#mc_object_type{name = NameOfCol,
1059
name_assign = SubIndex}, Oline}|Rest],
1060
SubIndex2, [{NameOfCol, _Type2}|Fields],
1061
NameOfEntry, TableName, ColMEs) ->
1062
l("defcols -> object_type (name of field and object is the same):~n"
1070
[NameOfCol,Kind,SubIndex,Oline,SubIndex2,NameOfEntry,TableName]),
1071
SIok = case SubIndex of
1072
{Parent,[_SI]} when Parent =/= NameOfEntry ->
1073
snmpc_lib:print_error(
1074
"Invalid parent ~p for table column ~p (should be ~p).",
1075
[Parent,NameOfCol,NameOfEntry],Oline),
1077
{NameOfEntry,[SubIndex2]} ->
1079
{NameOfEntry,[SI]} ->
1080
snmpc_lib:print_error(
1081
"Invalid column number ~p for column ~p.",
1082
[SI, NameOfCol], Oline),
1085
snmpc_lib:print_error(
1086
"Invalid parent for column ~p.",[NameOfCol],Oline),
1093
snmpc_lib:print_error(
1094
"Expected a table column.",[],Oline),
1099
snmpc_lib:print_error("Invalid table column definition for"
1100
" ~p.",[NameOfCol],Oline);
1102
done % already reported
1104
define_cols(Rest,SubIndex2+1,Fields,NameOfEntry,TableName,ColMEs);
1106
%% It's an object-type but everything else is wrong
1107
define_cols([{#mc_object_type{name = NameOfCol},Oline}|Rest],SubIndex2,Fields,
1108
NameOfEntry,TableName,ColMEs) ->
1109
snmpc_lib:print_error(
1110
"Number of columns differs from SEQUENCE definition (object:~p).",
1112
define_cols(Rest,SubIndex2+1,Fields,NameOfEntry,TableName,ColMEs);
1114
define_cols([{Obj,Line}|Tl], _SubIndex,_,_,_,ColMEs) ->
1115
snmpc_lib:print_error("Corrupt table definition.",[],Line),
1116
{ColMEs,[{Obj,Line}|Tl]};
1117
define_cols(Rest, _SubIndex,_,_,_,ColMEs) ->
1118
snmpc_lib:print_error("Corrupt table definition.",[]),
1121
ensure_macro_imported(dummy, _Line) -> ok;
1122
ensure_macro_imported(Macro, Line) ->
1123
Macros = (get(cdata))#cdata.imported_macros,
1124
case lists:member(Macro, Macros) of
1127
snmpc_lib:print_error("Macro ~p not imported.", [Macro],
1131
test_table(NameOfTable, Taccess, Kind, _Tindex, Tline) ->
1133
Taccess =/= 'not-accessible' ->
1134
snmpc_lib:print_error(
1135
"Table ~w must have STATUS not-accessible",
1136
[NameOfTable],Tline),
1138
Kind =/= {variable,[]} ->
1139
snmpc_lib:print_error(
1140
"Bad table definition (~w).",
1141
[NameOfTable],Tline),
1147
save(Filename, MibName, Options) ->
1148
R = filename:rootname(Filename),
1149
File1 = filename:basename(R),
1150
File3 = snmpc_misc:to_upper(File1),
1151
case snmpc_misc:to_upper(atom_to_list(MibName)) of
1153
{value, OutDirr} = snmpc_misc:assq(outdir, Options),
1154
OutDir = snmpc_misc:ensure_trailing_dir_delimiter(OutDirr),
1155
File2 = (OutDir ++ File1) ++ ".bin",
1156
{ok, MIB} = snmpc_lib:get_final_mib(File1, Options),
1159
case file:write_file(File2, term_to_binary(MIB)) of
1164
"Couldn't write file \"~s\".",[File2])
1167
l("save failed: ~n~p", [E]),
1171
snmpc_lib:error("Mibname (~s) differs from filename (~s).",
1175
%% parse takes a text file as a input and the output is a list of tokens.
1176
%% Input: FileName (file of mibs)
1177
%% Output: {ok, Mib} where MIB is a tuple of Tokens.
1178
%% {error, {LineNbr, Mod, Msg} an error on line number LineNb.
1182
case snmpc_tok:start_link(reserved_words(),
1183
[{file, FileName ++ ".mib"},
1184
{forget_stringdata, true}]) of
1185
{error,ReasonStr} ->
1186
snmpc_lib:error(lists:flatten(ReasonStr),[]);
1188
Toks = snmpc_tok:get_all_tokens(TokPid),
1190
%% io:format("parse -> lexical analysis: ~n~p~n", [Toks]),
1191
%% t("parse -> lexical analysis: ~n~p", [Toks]),
1193
case lists:keysearch(module, 1, get(options)) of
1194
{value, {module, M}} -> {module, M};
1195
_ -> {file, FileName ++ ".funcs"}
1197
put(cdata,snmpc_lib:make_cdata(CDataArg)),
1198
snmpc_tok:stop(TokPid),
1199
Res = if list(Toks) ->
1200
snmpc_mib_gram:parse(Toks);
1204
%% t("parse -> parsed: ~n~p", [Res]),
1208
{error, {LineNbr, Mod, Msg}} ->
1209
case catch format_yecc_error(LineNbr, Msg) of
1210
{Line, Format, Data} ->
1211
snmpc_lib:error(Format,Data,Line);
1212
_Q -> % sorry, have to use ugly yecc printouts
1213
Str = apply(Mod, format_error, [Msg]),
1214
snmpc_lib:error("~s",[Str],LineNbr)
1219
set_version(Toks) when list(Toks) ->
1220
%% MODULE-IDENTITY _must_ be invoked in SNMPv2 according to RFC1908
1221
case lists:keymember('MODULE-IDENTITY',1,Toks) of
1223
put(snmp_version,2);
1228
put(snmp_version,1).
1231
%% YeccGeneratedFile:format_error/1 is bad.
1232
format_yecc_error(Line, [ErrMsg, [${,Category, $,, _LineStr,$,, Value, $}]]) ->
1233
{Line, "~s \"~s\" (~s).", [ErrMsg, Value, Category]}.
1235
%% The same as the (quoted) Terminals in the snmpc_mib_gram.yrl
1280
'NOTIFICATION-TYPE',
1281
'MODULE-COMPLIANCE',
1283
'NOTIFICATION-GROUP',
1291
'TEXTUAL-CONVENTION',
1293
'NOTIFICATION-GROUP',
1295
'MODULE-COMPLIANCE',