aboutsummaryrefslogtreecommitdiffstats
path: root/lib/snmp/src/compile/snmpc.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/snmp/src/compile/snmpc.erl')
-rw-r--r--lib/snmp/src/compile/snmpc.erl1358
1 files changed, 1358 insertions, 0 deletions
diff --git a/lib/snmp/src/compile/snmpc.erl b/lib/snmp/src/compile/snmpc.erl
new file mode 100644
index 0000000000..8a1f15d4a4
--- /dev/null
+++ b/lib/snmp/src/compile/snmpc.erl
@@ -0,0 +1,1358 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(snmpc).
+
+%% API
+-export([compile/1, compile/2, compile/3,
+ mib_to_hrl/1, mib_to_hrl/3,
+ is_consistent/1]).
+
+%% Debug
+-export([look_at/1]).
+
+%% Internal Exports
+-export([init/3]).
+
+-include_lib("stdlib/include/erl_compile.hrl").
+-include("snmp_types.hrl").
+-include("snmpc.hrl").
+-include("snmpc_lib.hrl").
+
+
+look_at(Mib) ->
+ io:format("~p ~n", [snmpc_lib:look_at(Mib)]).
+
+
+%%-----------------------------------------------------------------
+%% Misc compiler stuff
+%%-----------------------------------------------------------------
+
+is_consistent(Filenames) ->
+ snmpc_lib:is_consistent(Filenames).
+
+mib_to_hrl(MibName) ->
+ snmpc_mib_to_hrl:convert(MibName).
+
+mib_to_hrl(MibName, HrlFile, Opts) ->
+ snmpc_mib_to_hrl:compile(MibName, HrlFile, Opts).
+
+
+%%%-----------------------------------------------------------------
+%%% Interface for erl_compile.
+%%%-----------------------------------------------------------------
+
+compile(Input, _Output, Options) ->
+ case compile(Input, make_options(Options)) of
+ {ok, _} ->
+ ok;
+ {error, Reason} ->
+ io:format("~p", [Reason]),
+ error
+ end.
+
+%% Converts generic options to format expected by compile/2
+
+make_options(#options{includes = Incs,
+ outdir = Outdir,
+ warning = Warning,
+ specific = Spec}) ->
+
+ OutdirOpt = {outdir, Outdir},
+
+ WarningOpt =
+ case Warning of
+ 0 -> {warnings, false};
+ _ -> {warnings, true}
+ end,
+
+ IncludeOpt =
+ {i, case Incs of
+ [] ->
+ [""];
+ _ ->
+ lists:map(fun(Dir) -> Dir++"/" end, Incs)
+ end},
+
+ [WarningOpt, OutdirOpt, IncludeOpt | Spec].
+
+%% Returns: {ok, File}|{error, Reason}
+compile([AtomFilename]) when is_atom(AtomFilename) ->
+ compile(atom_to_list(AtomFilename), []), % from cmd line
+ halt();
+compile(FileName) ->
+ compile(FileName, []).
+
+
+%%----------------------------------------------------------------------
+%% Options:
+%% {deprecated, bool()} true
+%% {group_check, bool()} true
+%% {db, volatile|persistent|mnesia} volatile
+%% {i, [import_dir_string()]} ["./"]
+%% {il, [import_lib_dir_string()]} []
+%% {warnings, bool()} true
+%% {outdir, string()} "./"
+%% description
+%% reference
+%% imports
+%% module_identity
+%% {module, string()}
+%% no_defs
+%% (hidden) {verbosity, trace|debug|log|info|silence} silence
+%% (hidden) version
+%% (hidden) options
+%%----------------------------------------------------------------------
+
+compile(FileName, Options) when is_list(FileName) ->
+ true = snmpc_misc:is_string(FileName),
+ DefOpts = [{deprecated, true},
+ {group_check, true},
+ {i, ["./"]},
+ {db, volatile},
+ {warnings, true},
+ {outdir, "./"},
+ {il, []}],
+ Opts = update_options(DefOpts, Options),
+ case check_options(Opts) of
+ ok ->
+ maybe_display_version(Opts),
+ maybe_display_options(Opts),
+ Pid = spawn_link(?MODULE,init,[self(),FileName,Opts]),
+ receive
+ {compile_result,R} -> R;
+ {'EXIT',Pid, Reason} when Reason =/= normal ->
+ exit(Reason)
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+maybe_display_version(Opts) ->
+ case lists:member(version, Opts) of
+ true ->
+ Vsn = (catch get_version()),
+ io:format("version: ~s~n", [Vsn]);
+ false ->
+ ok
+ end.
+
+get_version() ->
+ MI = ?MODULE:module_info(),
+ Attr = get_info(attributes, MI),
+ Vsn = get_info(app_vsn, Attr),
+ Comp = get_info(compile, MI),
+ Time = get_info(time, Comp),
+ {Year, Month, Day, Hour, Min, Sec} = Time,
+ io_lib:format("~s [~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w]",
+ [Vsn, Year, Month, Day, Hour, Min, Sec]).
+
+maybe_display_options(Opts) ->
+ case lists:member(options, Opts) of
+ true ->
+ {F, A} = get_options(Opts, [], []),
+ io:format("options: " ++ F ++ "~n", A);
+ false ->
+ ok
+ end.
+
+get_options([], Formats, Args) ->
+ {lists:concat(lists:reverse(Formats)), lists:reverse(Args)};
+get_options([{deprecated, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n deprecated: ~w"|Formats], [Val|Args]);
+get_options([{group_check, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n group_check: ~w"|Formats], [Val|Args]);
+get_options([{db, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n db: ~w"|Formats], [Val|Args]);
+get_options([{i, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n i: ~p"|Formats], [Val|Args]);
+get_options([{il, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n il: ~p"|Formats], [Val|Args]);
+get_options([{outdir, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n outdir: ~s"|Formats], [Val|Args]);
+get_options([{description, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n description: ~w"|Formats], [Val|Args]);
+get_options([description|Opts], Formats, Args) ->
+ get_options(Opts, ["~n description"|Formats], Args);
+get_options([{reference, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n reference: ~w"|Formats], [Val|Args]);
+get_options([reference|Opts], Formats, Args) ->
+ get_options(Opts, ["~n reference"|Formats], Args);
+get_options([{warnings, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n warnings: ~w"|Formats], [Val|Args]);
+get_options([{verbosity, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n verbosity: ~w"|Formats], [Val|Args]);
+get_options([imports|Opts], Formats, Args) ->
+ get_options(Opts, ["~n imports"|Formats], Args);
+get_options([module_identity|Opts], Formats, Args) ->
+ get_options(Opts, ["~n module_identity"|Formats], Args);
+get_options([_|Opts], Formats, Args) ->
+ get_options(Opts, Formats, Args).
+
+
+get_info(Key, Info) ->
+ case lists:keysearch(Key, 1, Info) of
+ {value, {Key, Val}} ->
+ Val;
+ false ->
+ throw("undefined")
+ end.
+
+% p(F, A) ->
+% io:format("DBG: " ++ F ++ "~n", A).
+
+update_options([], Options) ->
+ Options;
+update_options([{Key,DefVal}|DefOpts], Options) ->
+ case snmpc_misc:assq(Key, Options) of
+ false ->
+ update_options(DefOpts, [{Key,DefVal}|Options]);
+ {value, Val} when Key =:= i ->
+ Options1 =
+ lists:keyreplace(Key, 1, Options, {Key, Val++DefVal}),
+ update_options(DefOpts, Options1);
+ {value, Val} when Key =:= il ->
+ Options1 =
+ lists:keyreplace(Key, 1, Options, {Key, Val++DefVal}),
+ update_options(DefOpts, Options1);
+ {value, DefVal} -> %% Same value, no need to update
+ update_options(DefOpts, Options);
+ {value, Val} -> %% New value, so update
+ Options1 =
+ lists:keyreplace(Key, 1, Options, {Key, Val}),
+ update_options(DefOpts, Options1)
+ end.
+
+check_options([]) -> ok;
+check_options([no_symbolic_info|T]) -> check_options(T);
+check_options([{outdir, Str} | T]) when is_list(Str) ->
+ check_options(T);
+check_options([{debug, Atom} | T]) when is_atom(Atom) ->
+ check_options(T);
+check_options([{deprecated, Atom} | T]) when is_atom(Atom) ->
+ check_options(T);
+check_options([{group_check, Atom} | T]) when is_atom(Atom) ->
+ check_options(T);
+check_options([{warnings, Bool} | T]) ->
+ check_bool(warnings, Bool),
+ check_options(T);
+check_options([{db, volatile} | T]) ->
+ check_options(T);
+check_options([{db, persistent} | T]) ->
+ check_options(T);
+check_options([{db, mnesia} | T]) ->
+ check_options(T);
+check_options([{i, [Str|_]} | T]) when is_list(Str) ->
+ check_options(T);
+check_options([{il, []} | T]) ->
+ check_options(T);
+check_options([{il, [Str|_]} | T]) when is_list(Str) ->
+ check_options(T);
+check_options([{description, Bool}| T]) ->
+ check_bool(description, Bool),
+ check_options(T);
+check_options([description| T]) -> %% same as {description, true}
+ check_options(T);
+check_options([{reference, Bool}| T]) ->
+ check_bool(reference, Bool),
+ check_options(T);
+check_options([reference| T]) -> %% same as {reference, true}
+ check_options(T);
+check_options([{verbosity, V} | T]) when is_atom(V) ->
+ snmpc_lib:vvalidate(V),
+ check_options(T);
+check_options([version| T]) ->
+ check_options(T);
+check_options([options| T]) ->
+ check_options(T);
+check_options([imports| T]) ->
+ check_options(T);
+check_options([module_identity| T]) ->
+ check_options(T);
+check_options([{module, M} | T]) when is_atom(M) ->
+ check_options(T);
+check_options([no_defs| T]) ->
+ check_options(T);
+check_options([Opt|_]) ->
+ {error, {invalid_option, Opt}}.
+
+
+check_bool(_Key, Bool) when (Bool =:= true) orelse (Bool =:= false) ->
+ ok;
+check_bool(Key, Val) ->
+ {error, {invalid_option, {Key, Val}}}.
+
+get_group_check(Options) ->
+ snmpc_lib:key1search(group_check, Options, true).
+
+get_deprecated(Options) ->
+ snmpc_lib:key1search(deprecated, Options, true).
+
+get_description(Options) ->
+ get_bool_option(description, Options).
+
+get_reference(Options) ->
+ get_bool_option(reference, Options).
+
+get_bool_option(Option, Options) ->
+ case lists:member(Option, Options) of
+ false ->
+ snmpc_lib:key1search(Option, Options, false);
+ true ->
+ true
+ end.
+
+make_description(Message) ->
+ case get(description) of
+ true ->
+ Message;
+ _ ->
+ undefined
+ end.
+
+make_reference(undefined) ->
+ [];
+make_reference(Reference) ->
+ case get(reference) of
+ true ->
+ [{reference, Reference}];
+ _ ->
+ []
+ end.
+
+
+
+%%----------------------------------------------------------------------
+%% verbosity stuff
+%%----------------------------------------------------------------------
+
+%% Verbosity level is selected from three (historical reasons)
+%% options: warnings, debug and verbosity
+%% - If warnings is true, then verbosity is _atleast_ warning
+%% (even if the verbosity flag is set to silence)
+%% - If debug is true, the verbosity is _atleast_ log
+%% - Otherwise, verbosity is used as is.
+get_verbosity(Options) ->
+ WarningsSeverity =
+ case snmpc_lib:key1search(warnings, Options) of
+ true ->
+ warning;
+ _ ->
+ silence
+ end,
+ case snmpc_lib:key1search(verbosity, Options) of
+ undefined ->
+ %% Backward compatible: If not defined then try debug and convert
+ case snmpc_lib:key1search(debug, Options, false) of
+ true ->
+ log;
+ false ->
+ WarningsSeverity
+ end;
+ silence ->
+ WarningsSeverity;
+ Verbosity ->
+ Verbosity
+ end.
+
+
+%%----------------------------------------------------------------------
+%% The compile process.
+%%----------------------------------------------------------------------
+
+init(From, MibFileName, Options) ->
+ {A,B,C} = now(),
+ random:seed(A,B,C),
+ put(options, Options),
+ put(verbosity, get_verbosity(Options)),
+ put(description, get_description(Options)),
+ put(reference, get_reference(Options)),
+ File = filename:rootname(MibFileName, ".mib"),
+ put(filename, filename:basename(File ++ ".mib")),
+ R = case catch c_impl(File) of
+ {ok, OutFile} -> {ok, OutFile};
+ {'EXIT',error} -> {error, compilation_failed};
+ Error -> exit(Error)
+ end,
+ From ! {compile_result, R}.
+
+
+c_impl(File) ->
+ {ok, PData} = parse(File),
+ ?vtrace("Syntax analysis:"
+ "~n PData: ~p", [PData]),
+ MibName = compile_parsed_data(PData),
+ ?vtrace("Compiler output:"
+ "~n CDATA: ~p", [get(cdata)]),
+ save(File, MibName, get(options)).
+
+compile_parsed_data(#pdata{mib_name = MibName,
+ imports = Imports,
+ defs = Definitions}) ->
+ snmpc_lib:import(Imports),
+ update_imports(Imports),
+ Deprecated = get_deprecated(get(options)),
+ definitions_loop(Definitions, Deprecated),
+ MibName.
+
+update_imports(Imports) ->
+ case lists:member(imports, get(options)) of
+ true ->
+ IMPs = do_update_imports(Imports, []),
+ CDATA = get(cdata),
+ put(cdata, CDATA#cdata{imports = IMPs});
+ false ->
+ ok
+ end.
+
+do_update_imports([], Acc) ->
+ lists:reverse(Acc);
+do_update_imports([{{Mib, ImportsFromMib0},_Line}|Imports], Acc) ->
+ ImportsFromMib = [Name || {_, Name} <- ImportsFromMib0],
+ Import = {Mib, ImportsFromMib},
+ do_update_imports(Imports, [Import|Acc]).
+
+
+update_status(Name, Status) ->
+ #cdata{status_ets = Ets} = get(cdata),
+ ets:insert(Ets, {Name, Status}).
+
+
+%% A deprecated object
+definitions_loop([{#mc_object_type{name = ObjName, status = deprecated},
+ Line}|T],
+ false) ->
+ %% May be implemented but the compiler chooses not to.
+ ?vinfo2("object_type ~w is deprecated => ignored", [ObjName], Line),
+ update_status(ObjName, deprecated),
+ definitions_loop(T, false);
+
+%% A obsolete object
+definitions_loop([{#mc_object_type{name = ObjName, status = obsolete},
+ Line}|T],
+ Deprecated) ->
+ ?vlog2("object_type ~w is obsolete => ignored", [ObjName], Line),
+ %% No need to implement a obsolete object
+ update_status(ObjName, obsolete),
+ ensure_macro_imported('OBJECT-TYPE', Line),
+ definitions_loop(T, Deprecated);
+
+%% Defining a table
+definitions_loop([{#mc_object_type{name = NameOfTable,
+ syntax = {{sequence_of, SeqName}, _},
+ max_access = Taccess,
+ kind = Kind,
+ status = Tstatus,
+ description = Desc1,
+ units = Tunits,
+ reference = Ref,
+ name_assign = Tindex},
+ Tline},
+ {#mc_object_type{name = NameOfEntry,
+ syntax = {{type, SeqName}, TEline},
+ max_access = 'not-accessible',
+ kind = {table_entry, IndexingInfo},
+ status = Estatus,
+ description = Desc2,
+ units = Eunits,
+ name_assign = {NameOfTable,[1]}},
+ Eline},
+ {#mc_sequence{name = SeqName,
+ fields = FieldList},
+ Sline}|ColsEtc],
+ Deprecated) ->
+ ?vlog("defloop -> "
+ "[object_type(sequence_of),object_type(type,[1]),sequence]:"
+ "~n NameOfTable: ~p"
+ "~n SeqName: ~p"
+ "~n Taccess: ~p"
+ "~n Kind: ~p"
+ "~n Tstatus: ~p"
+ "~n Tindex: ~p"
+ "~n Tunits: ~p"
+ "~n Tline: ~p"
+ "~n NameOfEntry: ~p"
+ "~n TEline: ~p"
+ "~n IndexingInfo: ~p"
+ "~n Estatus: ~p"
+ "~n Eunits: ~p"
+ "~n Ref: ~p"
+ "~n Eline: ~p"
+ "~n FieldList: ~p"
+ "~n Sline: ~p",
+ [NameOfTable,SeqName,Taccess,Kind,Tstatus,
+ Tindex,Tunits,Tline,
+ NameOfEntry,TEline,IndexingInfo,Estatus,Eunits,Ref,Eline,
+ FieldList,Sline]),
+ update_status(NameOfTable, Tstatus),
+ update_status(NameOfEntry, Estatus),
+ update_status(SeqName, undefined),
+ ensure_macro_imported('OBJECT-TYPE', Tline),
+ test_table(NameOfTable,Taccess,Kind,Tindex,Tline),
+ {Tfather,Tsubindex} = Tindex,
+ snmpc_lib:register_oid(Tline,NameOfTable,Tfather,Tsubindex),
+ Description1 = make_description(Desc1),
+ TableME = #me{aliasname = NameOfTable,
+ entrytype = table,
+ access = 'not-accessible',
+ description = Description1,
+ units = Tunits},
+ snmpc_lib:register_oid(TEline,NameOfEntry,NameOfTable,[1]),
+ Description2 = make_description(Desc2),
+ TableEntryME = #me{aliasname = NameOfEntry,
+ entrytype = table_entry,
+ assocList = [{table_entry_with_sequence, SeqName}],
+ access = 'not-accessible',
+ description = Description2,
+ units = Eunits},
+ {ColMEs, RestObjs} =
+ define_cols(ColsEtc, 1, FieldList, NameOfEntry, NameOfTable, []),
+ TableInfo = snmpc_lib:make_table_info(Eline, NameOfTable,
+ IndexingInfo, ColMEs),
+ snmpc_lib:add_cdata(#cdata.mes,
+ [TableEntryME,
+ TableME#me{assocList=[{table_info,
+ TableInfo} | make_reference(Ref)]} |
+ ColMEs]),
+ definitions_loop(RestObjs, Deprecated);
+
+definitions_loop([{#mc_object_type{name = NameOfTable,
+ syntax = {{sequence_of, SeqName},_},
+ max_access = Taccess,
+ kind = Kind,
+ status = Tstatus,
+ description = Desc1,
+ units = Tunits,
+ reference = Ref,
+ name_assign = Tindex}, Tline},
+ {#mc_object_type{name = NameOfEntry,
+ syntax = {{type, SeqName},_},
+ max_access = 'not-accessible',
+ kind = {table_entry,IndexingInfo},
+ status = Estatus,
+ description = Desc2,
+ units = Eunits,
+ name_assign = BadOID}, Eline},
+ {#mc_sequence{name = SeqName,
+ fields = FieldList}, Sline}|ColsEtc],
+ Deprecated) ->
+ ?vlog("defloop -> "
+ "[object_type(sequence_of),object_type(type),sequence(fieldList)]:"
+ "~n NameOfTable: ~p"
+ "~n SeqName: ~p"
+ "~n Taccess: ~p"
+ "~n Kind: ~p"
+ "~n Tstatus: ~p"
+ "~n Tindex: ~p"
+ "~n Tunits: ~p"
+ "~n Tline: ~p"
+ "~n NameOfEntry: ~p"
+ "~n IndexingInfo: ~p"
+ "~n Estatus: ~p"
+ "~n BadOID: ~p"
+ "~n Eunits: ~p"
+ "~n Ref: ~p"
+ "~n Eline: ~p"
+ "~n FieldList: ~p"
+ "~n Sline: ~p",
+ [NameOfTable,SeqName,Taccess,Kind,Tstatus,
+ Tindex,Tunits,Tline,
+ NameOfEntry,IndexingInfo,Estatus,BadOID,Eunits,Ref,Eline,
+ FieldList,Sline]),
+ update_status(NameOfTable, Tstatus),
+ update_status(NameOfEntry, Estatus),
+ update_status(SeqName, undefined),
+ ensure_macro_imported('OBJECT-TYPE', Tline),
+ snmpc_lib:print_error("Bad TableEntry OID definition (~w)",
+ [BadOID],Eline),
+ test_table(NameOfTable,Taccess,Kind,Tindex,Tline),
+ {Tfather,Tsubindex} = Tindex,
+ snmpc_lib:register_oid(Tline,NameOfTable,Tfather,Tsubindex),
+ Description1 = make_description(Desc1),
+ TableME = #me{aliasname = NameOfTable,
+ entrytype = table,
+ access = 'not-accessible',
+ description = Description1,
+ units = Tunits},
+ Description2 = make_description(Desc2),
+ TableEntryME = #me{aliasname = NameOfEntry,
+ entrytype = table_entry,
+ access = 'not-accessible',
+ assocList = [{table_entry_with_sequence,SeqName}],
+ description = Description2,
+ units = Eunits},
+ {ColMEs, RestObjs} =
+ define_cols(ColsEtc, 1, FieldList, NameOfEntry, NameOfTable, []),
+ TableInfo = snmpc_lib:make_table_info(Eline, NameOfTable,
+ IndexingInfo, ColMEs),
+ snmpc_lib:add_cdata(#cdata.mes,
+ [TableEntryME,
+ TableME#me{assocList=[{table_info,
+ TableInfo} | make_reference(Ref)]} |
+ ColMEs]),
+ definitions_loop(RestObjs, Deprecated);
+
+definitions_loop([{#mc_new_type{name = NewTypeName,
+ macro = Macro,
+ syntax = OldType,
+ display_hint = DisplayHint},Line}|T],
+ Deprecated) ->
+ ?vlog2("defloop -> new_type:"
+ "~n Macro: ~p"
+ "~n NewTypeName: ~p"
+ "~n OldType: ~p"
+ "~n DisplayHint: ~p",
+ [Macro, NewTypeName, OldType, DisplayHint], Line),
+ ensure_macro_imported(Macro,Line),
+ Types = (get(cdata))#cdata.asn1_types,
+ case lists:keysearch(NewTypeName, #asn1_type.aliasname, Types) of
+ {value,_} ->
+ snmpc_lib:print_error("Type ~w already defined.",
+ [NewTypeName],Line);
+ false ->
+ %% NameOfOldType = element(2,OldType),
+ ASN1 = snmpc_lib:make_ASN1type(OldType),
+ snmpc_lib:add_cdata(#cdata.asn1_types,
+ [ASN1#asn1_type{aliasname = NewTypeName,
+ imported = false,
+ display_hint = DisplayHint}])
+ end,
+ definitions_loop(T, Deprecated);
+
+%% Plain variable
+definitions_loop([{#mc_object_type{name = NewVarName,
+ syntax = Type,
+ max_access = Access,
+ kind = {variable, DefVal},
+ status = Status,
+ description = Desc1,
+ units = Units,
+ name_assign = {Parent,SubIndex}},Line} |T],
+ Deprecated) ->
+ ?vlog2("defloop -> object_type (variable):"
+ "~n NewVarName: ~p"
+ "~n Type: ~p"
+ "~n Access: ~p"
+ "~n DefVal: ~p"
+ "~n Status: ~p"
+ "~n Units: ~p"
+ "~n Parent: ~p"
+ "~n SubIndex: ~p",
+ [NewVarName, Type, Access, DefVal,
+ Status, Units, Parent, SubIndex], Line),
+ update_status(NewVarName, Status),
+ snmpc_lib:test_father(Parent, NewVarName, SubIndex, Line),
+ ASN1type = snmpc_lib:make_ASN1type(Type),
+ snmpc_lib:register_oid(Line, NewVarName, Parent, SubIndex),
+ Description1 = make_description(Desc1),
+ NewME = #me{aliasname = NewVarName,
+ asn1_type = ASN1type,
+ entrytype = variable,
+ access = Access,
+ description = Description1,
+ units = Units,
+ assocList = DefVal},
+ NewME2 = snmpc_lib:resolve_defval(NewME),
+ %% hmm, should this be done in resolve_defval?
+ VI = snmpc_lib:make_variable_info(NewME2),
+ snmpc_lib:add_cdata(#cdata.mes,
+ [NewME2#me{assocList = [{variable_info, VI}]}]),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_module_identity{name = NewVarName,
+ last_updated = LU,
+ organization = Org,
+ contact_info = CI,
+ description = Desc,
+ revisions = Revs0,
+ name_assign = {Parent, SubIndex}},
+ Line}|T],
+ Deprecated) ->
+ ?vlog2("defloop -> module-identity: "
+ "~n NewVarName: ~p"
+ "~n LU: ~p"
+ "~n Org: ~p"
+ "~n CI: ~p"
+ "~n Desc: ~p"
+ "~n Revs0: ~p"
+ "~n Parent: ~p"
+ "~n SubIndex: ~p",
+ [NewVarName, LU, Org, CI, Desc, Revs0, Parent, SubIndex], Line),
+ ensure_macro_imported('MODULE-IDENTITY', Line),
+ snmpc_lib:register_oid(Line, NewVarName, Parent, SubIndex),
+ Revs = [{R,D}||#mc_revision{revision = R,description = D} <- Revs0],
+ MI = #module_identity{last_updated = LU,
+ organization = Org,
+ contact_info = CI,
+ description = Desc,
+ revisions = Revs},
+ CDATA = get(cdata),
+ put(cdata, CDATA#cdata{module_identity = MI}),
+ snmpc_lib:add_cdata(
+ #cdata.mes,
+ [snmpc_lib:makeInternalNode2(false, NewVarName)]),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_internal{name = NewVarName,
+ macro = Macro,
+ parent = Parent,
+ sub_index = SubIndex},Line}|T],
+ Deprecated) ->
+ ?vlog2("defloop -> internal:"
+ "~n NewVarName: ~p"
+ "~n Macro: ~p"
+ "~n Parent: ~p"
+ "~n SubIndex: ~p",
+ [NewVarName, Macro, Parent, SubIndex], Line),
+ ensure_macro_imported(Macro, Line),
+ snmpc_lib:register_oid(Line, NewVarName, Parent, SubIndex),
+ snmpc_lib:add_cdata(
+ #cdata.mes,
+ [snmpc_lib:makeInternalNode2(false, NewVarName)]),
+ definitions_loop(T, Deprecated);
+
+%% A trap message
+definitions_loop([{#mc_trap{name = TrapName,
+ enterprise = EnterPrise,
+ vars = Variables,
+ description = Desc1,
+ num = SpecificCode}, Line}|T],
+ Deprecated) ->
+ ?vlog2("defloop -> trap:"
+ "~n TrapName: ~p"
+ "~n EnterPrise: ~p"
+ "~n Variables: ~p"
+ "~n SpecificCode: ~p",
+ [TrapName, EnterPrise, Variables, SpecificCode], Line),
+ update_status(TrapName, undefined),
+ CDATA = get(cdata),
+ snmpc_lib:check_trap_name(EnterPrise, Line, CDATA#cdata.mes),
+ Descriptions = make_description(Desc1),
+ Trap = #trap{trapname = TrapName,
+ enterpriseoid = EnterPrise,
+ specificcode = SpecificCode,
+ %% oidobjects: Store Variables temporary here.
+ %% This will be replaced later in the
+ %% get_final_mib function by a call to
+ %% the update_trap_objects function.
+ oidobjects = Variables,
+ description = Descriptions},
+ lists:foreach(fun(Trap2) -> snmpc_lib:check_trap(Trap2, Trap, Line) end,
+ CDATA#cdata.traps),
+ snmpc_lib:add_cdata(#cdata.traps, [Trap]),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_object_type{name = NameOfEntry,
+ syntax = Type,
+ max_access = Eaccess,
+ kind = {table_entry, Index},
+ status = Estatus,
+ name_assign = SubIndex},Eline}|T],
+ Deprecated) ->
+ ?vlog("defloop -> object_type (table_entry):"
+ "~n NameOfEntry: ~p"
+ "~n Type: ~p"
+ "~n Eaccess: ~p"
+ "~n Index: ~p"
+ "~n Estatus: ~p"
+ "~n SubIndex: ~p"
+ "~n SubIndex: ~p"
+ "~n Eline: ~p",
+ [NameOfEntry, Type, Eaccess, Index, Estatus, SubIndex, Eline]),
+ update_status(NameOfEntry, Estatus),
+ snmpc_lib:print_error("Misplaced TableEntry definition (~w)",
+ [NameOfEntry], Eline),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_notification{name = TrapName,
+ status = deprecated}, Line}|T],
+ false) ->
+ ?vinfo2("defloop -> notification ~w is deprecated => ignored",
+ [TrapName], Line),
+ update_status(TrapName, deprecated),
+ ensure_macro_imported('NOTIFICATION-TYPE', Line),
+ definitions_loop(T, false);
+
+definitions_loop([{#mc_notification{name = TrapName,
+ status = obsolete}, Line}|T],
+ Deprecated) ->
+ ?vlog2("defloop -> notification ~w is obsolete => ignored",
+ [TrapName], Line),
+ update_status(TrapName, obsolete),
+ ensure_macro_imported('NOTIFICATION-TYPE', Line),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_notification{name = TrapName,
+ vars = Variables,
+ status = Status,
+ description = Desc,
+ name_assign = {Parent, SubIndex}},Line}|T],
+ Deprecated) ->
+ ?vlog2("defloop -> notification:"
+ "~n TrapName: ~p"
+ "~n Variables: ~p"
+ "~n Status: ~p"
+ "~n Parent: ~p"
+ "~n SubIndex: ~p",
+ [TrapName, Variables, Status, Parent, SubIndex], Line),
+ update_status(TrapName, Status),
+ ensure_macro_imported('NOTIFICATION-TYPE', Line),
+ CDATA = get(cdata),
+ snmpc_lib:register_oid(Line, TrapName, Parent, SubIndex),
+ Descriptions = make_description(Desc),
+ Notif = #notification{trapname = TrapName,
+ description = Descriptions,
+ %% oidobjects: Store Variables temporary here.
+ %% This will be replaced later in the
+ %% get_final_mib function by a call to
+ %% the update_trap_objects function.
+ oidobjects = Variables},
+ snmpc_lib:check_notification(Notif, Line, CDATA#cdata.traps),
+ snmpc_lib:add_cdata(#cdata.traps, [Notif]),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_module_compliance{name = Name},Line}|T], Deprecated) ->
+ ?vlog2("defloop -> module_compliance:"
+ "~n Name: ~p", [Name], Line),
+ ensure_macro_imported('MODULE-COMPLIANCE', Line),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_object_group{name = Name,
+ objects = GroupObjects,
+ status = Status,
+ description = Desc,
+ reference = Ref,
+ name_assign = {Parent,SubIndex}}, Line}|T],
+ Deprecated) ->
+ ?vlog2("defloop -> object_group ~p:"
+ "~n GroupObjects: ~p"
+ "~n Status: ~p"
+ "~n Desc: ~p"
+ "~n Ref: ~p"
+ "~n Parent: ~p"
+ "~n SubIndex: ~p",
+ [Name, GroupObjects, Status, Desc, Ref, Parent, SubIndex], Line),
+ ensure_macro_imported('OBJECT-GROUP', Line),
+ GroupBool = get_group_check(get(options)),
+ case GroupBool of
+ true ->
+ snmpc_lib:add_cdata(#cdata.objectgroups,
+ [{Name,GroupObjects,Line}]),
+ %% Check that the group members has been defined
+ %% and that they have the correct status
+ snmpc_lib:check_object_group(Name, GroupObjects,
+ Line, Status);
+ _ ->
+ ok
+ end,
+
+ update_status(Name, Status),
+ snmpc_lib:test_father(Parent, Name, SubIndex, Line),
+ snmpc_lib:register_oid(Line, Name, Parent, SubIndex),
+ Description = make_description(Desc),
+ NewME = #me{aliasname = Name,
+ entrytype = group,
+ access = 'not-accessible',
+ description = Description,
+ assocList = [{kind, object},
+ {objects, GroupObjects}]},
+ snmpc_lib:add_cdata(#cdata.mes, [NewME]),
+
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_notification_group{name = Name,
+ objects = GroupObjects,
+ status = Status,
+ description = Desc,
+ reference = Ref,
+ name_assign = {Parent,SubIndex}},
+ Line}
+ |T], Deprecated) ->
+ ?vlog2("defloop -> notification_group ~p:"
+ "~n GroupObjects: ~p"
+ "~n Status: ~p"
+ "~n Desc: ~p"
+ "~n Ref: ~p"
+ "~n Parent: ~p"
+ "~n SubIndex: ~p",
+ [Name, GroupObjects, Status, Desc, Ref, Parent, SubIndex], Line),
+ ensure_macro_imported('NOTIFICATION-GROUP', Line),
+ GroupBool = get_group_check(get(options)),
+ case GroupBool of
+ true ->
+ snmpc_lib:add_cdata(#cdata.notificationgroups,
+ [{Name,GroupObjects,Line}]),
+
+ %% Check that the group members has been defined
+ %% and that they have the correct status
+ snmpc_lib:check_notification_group(Name, GroupObjects,
+ Line, Status);
+ _ ->
+ ok
+ end,
+
+ update_status(Name, Status),
+ snmpc_lib:test_father(Parent, Name, SubIndex, Line),
+ snmpc_lib:register_oid(Line, Name, Parent, SubIndex),
+ Description = make_description(Desc),
+ NewME = #me{aliasname = Name,
+ entrytype = group,
+ access = 'not-accessible',
+ description = Description,
+ assocList = [{kind, notification},
+ {objects, GroupObjects}]},
+ snmpc_lib:add_cdata(#cdata.mes, [NewME]),
+
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_object_type{name = NameOfTable,
+ syntax = {{sequence_of, SeqName},_},
+ status = Tstatus},Tline},
+ Entry, Seq|T],
+ Deprecated) ->
+ ?vlog("defloop -> object_type (sequence_of): "
+ "~n NameOfTable: ~p"
+ "~n SeqName: ~p"
+ "~n Tline: ~p"
+ "~n Entry: ~p"
+ "~n Seq: ~p",
+ [NameOfTable, SeqName, Tline, Entry, Seq]),
+ update_status(NameOfTable, Tstatus),
+ case Entry of
+ {#mc_object_type{syntax = {{type, SeqName},_line},
+ max_access = 'not-accessible',
+ kind = {table_entry, _IndexingInfo},
+ name_assign = {_NameOfTable,[1]}}, _Eline} ->
+ case Seq of
+ {#mc_sequence{name = SeqName}, Sline} ->
+ snmpc_lib:error("Internal error. Correct incorrect "
+ "table (~p,~w).",[SeqName,Sline],
+ Tline);
+ _ ->
+ ?vinfo("defloop -> Invalid sequence: ~p", [Seq]),
+ snmpc_lib:print_error(
+ "Invalid SEQUENCE OF '~p'.",
+ [safe_elem(1,safe_elem(2,Seq))],Tline)
+ end;
+ Else ->
+ ?vinfo("defloop -> Invalid table entry: "
+ "~n ~p", [Else]),
+ snmpc_lib:print_error(
+ "Invalid TableEntry '~p' (check STATUS, Sequence name, Oid)",
+ [safe_elem(1,safe_elem(2,Entry))],Tline)
+ end,
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_object_type{name = NameOfTable,
+ syntax = {{sequence_of, SeqName},_},
+ status = Tstatus},Tline}|T],
+ Deprecated) ->
+ ?vlog("defloop -> object_type (sequence_of):"
+ "~n object_type: ~p"
+ "~n sequence_of: ~p"
+ "~n Tline: ~p", [NameOfTable, SeqName, Tline]),
+ update_status(NameOfTable, Tstatus),
+ snmpc_lib:print_error("Invalid statements following table ~p.",
+ [NameOfTable],Tline),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_sequence{name = SeqName,
+ fields = _FieldList},Line}|T],
+ Deprecated) ->
+ ?vwarning2("Unexpected SEQUENCE ~w => ignoring", [SeqName], Line),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{Obj,Line}|T], Deprecated) ->
+ ?vinfo2("defloop -> unknown error"
+ "~n Obj: ~p", [Obj], Line),
+ snmpc_lib:print_error("Unknown Error in MIB. "
+ "Can't describe the error better than this: ~999p ignored."
+ " Please send a trouble report to [email protected].",
+ [Obj], Line),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([], _Deprecated) ->
+ ?vlog("defloop -> done", []),
+ ok.
+
+safe_elem(N,T) ->
+ case catch(element(N,T)) of
+ {'EXIT',_} ->
+ "no more information available";
+ X -> X
+ end.
+
+%% A correct column
+define_cols([{#mc_object_type{name = NameOfCol,
+ syntax = Type1,
+ max_access = Access,
+ kind = {variable,Defval},
+ status = Status,
+ description = Desc,
+ units = Units,
+ name_assign = {NameOfEntry,[SubIndex]}},
+ Oline}|Rest],
+ SubIndex,
+ [{NameOfCol,Type2}|Fields], NameOfEntry, TableName, ColMEs) ->
+ ?vlog("defcols -> object_type (variable):"
+ "~n NameOfCol: ~p"
+ "~n Type1: ~p"
+ "~n Access: ~p"
+ "~n Defval: ~p"
+ "~n Status ~p"
+ "~n Units ~p"
+ "~n NameOfEntry ~p"
+ "~n Oline: ~p",
+ [NameOfCol, Type1, Access, Defval, Status, Units,
+ NameOfEntry, Oline]),
+ update_status(NameOfCol, Status),
+ Deprecated = get_deprecated(get(options)),
+ ASN1type = snmpc_lib:make_ASN1type(Type1),
+ case (snmpc_lib:make_ASN1type(Type2))#asn1_type.bertype of
+ T2 when T2 == ASN1type#asn1_type.bertype -> ok;
+ _Else ->
+ snmpc_lib:error(
+ "Types for ~p differs from the SEQUENCE definition. ",
+ [NameOfCol],Oline)
+ end,
+ NewAccess = % a simple way to get the obsolete behaviour
+ if
+ Status =:= obsolete ->
+ %% Be quiet and don't implement
+ 'not-accessible';
+ (Status =:= deprecated) andalso (Deprecated =:= false) ->
+ %% The compiler chooses not to implement the column.
+ ?vinfo2("object_type ~w is deprecated => ignored",
+ [NameOfCol], Oline),
+ 'not-accessible';
+ true -> Access
+ end,
+ snmpc_lib:register_oid(Oline,NameOfCol,NameOfEntry,[SubIndex]),
+ Description = make_description(Desc),
+ ColumnME = snmpc_lib:resolve_defval(
+ #me{oid = SubIndex,
+ aliasname = NameOfCol,
+ asn1_type = ASN1type,
+ entrytype = table_column,
+ access = NewAccess,
+ description = Description,
+ units = Units, %% Propably not usefull
+ assocList = [{table_name,TableName} | Defval]}),
+ define_cols(Rest,SubIndex+1,Fields,NameOfEntry,TableName,
+ [ColumnME|ColMEs]);
+
+%% A "hole" (non-consecutive columns) in the table.
+%% Implemented as a not-accessible column so Col always is index in
+%% row tuple.
+define_cols([{#mc_object_type{name = NameOfCol,
+ syntax = Type1,
+ max_access = Access,
+ kind = Kind,
+ status = Status,
+ name_assign = {NameOfEntry,[SubIndex]}},
+ Oline}|Rest],
+ ExpectedSubIndex, Fields, NameOfEntry, TableName, ColMEs)
+ when SubIndex > ExpectedSubIndex ->
+ ?vlog("defcols -> object_type (non consecutive cols):"
+ "~n NameOfCol: ~p"
+ "~n Type1: ~p"
+ "~n Access: ~p"
+ "~n Status ~p"
+ "~n NameOfEntry ~p"
+ "~n Oline: ~p",
+ [NameOfCol, Type1, Access, Status, NameOfEntry, Oline]),
+ update_status(NameOfCol, Status),
+ Int = {{type, 'INTEGER'},Oline},
+ GeneratedColumn =
+ %% be sure to use an invalid column name here!
+ {#mc_object_type{name = '$no_name$',
+ syntax = Int,
+ max_access = 'not-accessible',
+ kind = {variable, [{defval,0}]},
+ status = current,
+ description = undefined,
+ name_assign = {NameOfEntry, [ExpectedSubIndex]}},
+ Oline},
+ define_cols([GeneratedColumn,
+ {#mc_object_type{name = NameOfCol,
+ syntax = Type1,
+ max_access = Access,
+ kind = Kind,
+ status = Status,
+ description = undefined,
+ name_assign = {NameOfEntry,[SubIndex]}},
+ Oline}|Rest], ExpectedSubIndex,
+ [{'$no_name$', Int}|Fields], NameOfEntry, TableName,ColMEs) ;
+
+%% Ok. done. All fields are eaten.
+define_cols(Rest, _SubIndex, [], _NameOfEntry, _TableName, ColMEs) ->
+ {ColMEs, Rest};
+
+
+%% Error Handling
+
+%% The name of the field and object is the same
+define_cols([{#mc_object_type{name = NameOfCol,
+ kind = Kind,
+ name_assign = SubIndex}, Oline}|Rest],
+ SubIndex2, [{NameOfCol, _Type2}|Fields],
+ NameOfEntry, TableName, ColMEs) ->
+ ?vlog("defcols -> object_type (name of field and object is the same):"
+ "~n NameOfCol: ~p"
+ "~n Kind: ~p"
+ "~n SubIndex: ~p"
+ "~n Oline: ~p"
+ "~n SubIndex2: ~p"
+ "~n NameOfEntry ~p"
+ "~n TableName ~p",
+ [NameOfCol,Kind,SubIndex,Oline,SubIndex2,NameOfEntry,TableName]),
+ SIok = case SubIndex of
+ {Parent,[_SI]} when Parent =/= NameOfEntry ->
+ snmpc_lib:print_error(
+ "Invalid parent ~p for table column ~p (should be ~p).",
+ [Parent,NameOfCol,NameOfEntry],Oline),
+ error;
+ {NameOfEntry,[SubIndex2]} ->
+ ok;
+ {NameOfEntry,[SI]} ->
+ snmpc_lib:print_error(
+ "Invalid column number ~p for column ~p.",
+ [SI, NameOfCol], Oline),
+ error;
+ _Q ->
+ snmpc_lib:print_error(
+ "Invalid parent for column ~p.",[NameOfCol],Oline),
+ error
+ end,
+ Kok = case Kind of
+ {variable,_} ->
+ ok;
+ _Q2 ->
+ snmpc_lib:print_error(
+ "Expected a table column.",[],Oline),
+ error
+ end,
+ case {SIok, Kok} of
+ {ok, ok} ->
+ snmpc_lib:print_error("Invalid table column definition for"
+ " ~p.",[NameOfCol],Oline);
+ _Q4 ->
+ done % already reported
+ end,
+ define_cols(Rest,SubIndex2+1,Fields,NameOfEntry,TableName,ColMEs);
+
+%% It's an object-type but everything else is wrong
+define_cols([{#mc_object_type{name = NameOfCol},Oline}|Rest],SubIndex2,Fields,
+ NameOfEntry,TableName,ColMEs) ->
+ snmpc_lib:print_error(
+ "Number of columns differs from SEQUENCE definition (object:~p).",
+ [NameOfCol],Oline),
+ define_cols(Rest,SubIndex2+1,Fields,NameOfEntry,TableName,ColMEs);
+
+define_cols([{Obj,Line}|Tl], _SubIndex,_,_,_,ColMEs) ->
+ snmpc_lib:print_error("Corrupt table definition.",[],Line),
+ {ColMEs,[{Obj,Line}|Tl]};
+define_cols(Rest, _SubIndex,_,_,_,ColMEs) ->
+ snmpc_lib:print_error("Corrupt table definition.",[]),
+ {ColMEs,Rest}.
+
+ensure_macro_imported(dummy, _Line) -> ok;
+ensure_macro_imported(Macro, Line) ->
+ Macros = (get(cdata))#cdata.imported_macros,
+ case lists:member(Macro, Macros) of
+ true -> ok;
+ false ->
+ snmpc_lib:print_error("Macro ~p not imported.", [Macro],
+ Line)
+ end.
+
+test_table(NameOfTable, Taccess, Kind, _Tindex, Tline) ->
+ if
+ Taccess =/= 'not-accessible' ->
+ snmpc_lib:print_error(
+ "Table ~w must have STATUS not-accessible",
+ [NameOfTable],Tline),
+ error;
+ Kind =/= {variable,[]} ->
+ snmpc_lib:print_error(
+ "Bad table definition (~w).",
+ [NameOfTable],Tline),
+ error;
+ true ->
+ ok
+ end.
+
+save(Filename, MibName, Options) ->
+ R = filename:rootname(Filename),
+ File1 = filename:basename(R),
+ File3 = snmpc_misc:to_upper(File1),
+ case snmpc_misc:to_upper(atom_to_list(MibName)) of
+ File3 ->
+ {value, OutDirr} = snmpc_misc:assq(outdir, Options),
+ OutDir = snmpc_misc:ensure_trailing_dir_delimiter(OutDirr),
+ File2 = (OutDir ++ File1) ++ ".bin",
+ {ok, MIB} = snmpc_lib:get_final_mib(File1, Options),
+ case get(errors) of
+ undefined ->
+ case file:write_file(File2, term_to_binary(MIB)) of
+ ok ->
+ {ok, File2};
+ _Err ->
+ snmpc_lib:error(
+ "Couldn't write file \"~s\".",[File2])
+ end;
+ E ->
+ ?vlog("save failed: "
+ "~n ~p", [E]),
+ {'EXIT',error}
+ end;
+ MibNameL ->
+ snmpc_lib:error("Mibname (~s) differs from filename (~s).",
+ [MibNameL, File1])
+ end.
+
+%% parse takes a text file as a input and the output is a list of tokens.
+%% Input: FileName (file of mibs)
+%% Output: {ok, Mib} where MIB is a tuple of Tokens.
+%% {error, {LineNbr, Mod, Msg} an error on line number LineNb.
+
+
+parse(FileName) ->
+ case snmpc_tok:start_link(reserved_words(),
+ [{file, FileName ++ ".mib"},
+ {forget_stringdata, true}]) of
+ {error,ReasonStr} ->
+ snmpc_lib:error(lists:flatten(ReasonStr),[]);
+ {ok, TokPid} ->
+ Toks = snmpc_tok:get_all_tokens(TokPid),
+ set_version(Toks),
+ %% io:format("parse -> lexical analysis: ~n~p~n", [Toks]),
+ %% t("parse -> lexical analysis: ~n~p", [Toks]),
+ CDataArg =
+ case lists:keysearch(module, 1, get(options)) of
+ {value, {module, M}} -> {module, M};
+ _ -> {file, FileName ++ ".funcs"}
+ end,
+ put(cdata,snmpc_lib:make_cdata(CDataArg)),
+ snmpc_tok:stop(TokPid),
+ Res = if
+ is_list(Toks) ->
+ snmpc_mib_gram:parse(Toks);
+ true ->
+ Toks
+ end,
+ %% t("parse -> parsed: ~n~p", [Res]),
+ case Res of
+ {ok, PData} ->
+ {ok, PData};
+ {error, {LineNbr, Mod, Msg}} ->
+ case catch format_yecc_error(LineNbr, Msg) of
+ {Line, Format, Data} ->
+ snmpc_lib:error(Format,Data,Line);
+ _Q -> % sorry, have to use ugly yecc printouts
+ Str = apply(Mod, format_error, [Msg]),
+ snmpc_lib:error("~s",[Str],LineNbr)
+ end
+ end
+ end.
+
+set_version(Toks) when is_list(Toks) ->
+%% MODULE-IDENTITY _must_ be invoked in SNMPv2 according to RFC1908
+ case lists:keymember('MODULE-IDENTITY',1,Toks) of
+ true ->
+ put(snmp_version,2);
+ false ->
+ put(snmp_version,1)
+ end;
+set_version(_) ->
+ put(snmp_version,1).
+
+
+%% YeccGeneratedFile:format_error/1 is bad.
+format_yecc_error(Line, [ErrMsg, [${,Category, $,, _LineStr,$,, Value, $}]]) ->
+ {Line, "~s \"~s\" (~s).", [ErrMsg, Value, Category]}.
+
+%% The same as the (quoted) Terminals in the snmpc_mib_gram.yrl
+reserved_words() ->
+ [
+ 'ACCESS',
+ 'BEGIN',
+ 'BIT',
+ 'CONTACT-INFO',
+ 'Counter',
+ 'DEFINITIONS',
+ 'DEFVAL',
+ 'DESCRIPTION',
+ 'DISPLAY-HINT',
+ 'END',
+ 'ENTERPRISE',
+ 'FROM',
+ 'Gauge',
+ 'IDENTIFIER',
+ 'IDENTIFIER',
+ 'IMPORTS',
+ 'INDEX',
+ 'INTEGER',
+ 'IpAddress',
+ 'LAST-UPDATED',
+ 'NetworkAddress',
+ 'OBJECT',
+ 'OBJECT',
+ 'OBJECT-TYPE',
+ 'OCTET',
+ 'OF',
+ 'Opaque',
+ 'REFERENCE',
+ 'SEQUENCE',
+ 'SIZE',
+ 'STATUS',
+ 'STRING',
+ 'SYNTAX',
+ 'TRAP-TYPE',
+ 'TimeTicks',
+ 'VARIABLES',
+
+ %% v2
+ 'LAST-UPDATED',
+ 'ORGANIZATION',
+ 'CONTACT-INFO',
+ 'MODULE-IDENTITY',
+ 'NOTIFICATION-TYPE',
+ 'MODULE-COMPLIANCE',
+ 'OBJECT-GROUP',
+ 'NOTIFICATION-GROUP',
+ 'REVISION',
+ 'OBJECT-IDENTITY',
+ 'MAX-ACCESS',
+ 'UNITS',
+ 'AUGMENTS',
+ 'IMPLIED',
+ 'OBJECTS',
+ 'TEXTUAL-CONVENTION',
+ 'OBJECT-GROUP',
+ 'NOTIFICATION-GROUP',
+ 'NOTIFICATIONS',
+ 'MODULE-COMPLIANCE',
+ 'MODULE',
+ 'MANDATORY-GROUPS',
+ 'GROUP',
+ 'WRITE-SYNTAX',
+ 'MIN-ACCESS',
+ 'BITS'
+ ]
+.