aboutsummaryrefslogtreecommitdiffstats
path: root/lib/snmp/src/compile/snmpc_mib_to_hrl.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/snmp/src/compile/snmpc_mib_to_hrl.erl')
-rw-r--r--lib/snmp/src/compile/snmpc_mib_to_hrl.erl391
1 files changed, 391 insertions, 0 deletions
diff --git a/lib/snmp/src/compile/snmpc_mib_to_hrl.erl b/lib/snmp/src/compile/snmpc_mib_to_hrl.erl
new file mode 100644
index 0000000000..07bd29231b
--- /dev/null
+++ b/lib/snmp/src/compile/snmpc_mib_to_hrl.erl
@@ -0,0 +1,391 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-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_mib_to_hrl).
+
+-include_lib("stdlib/include/erl_compile.hrl").
+-include("snmp_types.hrl").
+-include("snmpc_lib.hrl").
+
+%% External exports
+-export([convert/1, compile/3]).
+
+%%-----------------------------------------------------------------
+%% Func: convert/1
+%% Args: MibName = string() without extension.
+%% Purpose: Produce a .hrl file with oid for tables and variables,
+%% column numbers for columns and values for enums.
+%% Writes only the first occurence of a name. Prints a
+%% warning if a duplicate name is found.
+%% Returns: ok | {error, Reason}
+%% Note: The Mib must be compiled.
+%%-----------------------------------------------------------------
+convert(MibName) ->
+ MibFile = MibName ++ ".bin",
+ HrlFile = MibName ++ ".hrl",
+ put(verbosity, trace),
+ convert(MibFile, HrlFile, MibName).
+
+convert(MibFile, HrlFile, MibName) ->
+ ?vtrace("convert -> entry with"
+ "~n MibFile: ~s"
+ "~n HrlFile: ~s"
+ "~n MibName: ~s", [MibFile, HrlFile, MibName]),
+ case snmpc_misc:read_mib(MibFile) of
+ {ok, #mib{asn1_types = Types, mes = MEs, traps = Traps}} ->
+ ?vdebug("mib successfully read", []),
+ resolve(Types, MEs, Traps, HrlFile,
+ filename:basename(MibName)),
+ ok;
+ {error, Reason} ->
+ ?vinfo("failed reading mib: "
+ "~n Reason: ~p", [Reason]),
+ {error, Reason}
+ end.
+
+resolve(Types, MEs, Traps, HrlFile, MibName) ->
+ ?vtrace("resolve -> entry", []),
+ case file:open(HrlFile, [write]) of
+ {ok, Fd} ->
+ insert_header(Fd),
+ insert_begin(Fd, MibName),
+ insert_notifs(Traps, Fd),
+ insert_oids(MEs, Fd),
+ insert_range(MEs, Fd),
+ insert_enums(Types, MEs, Fd),
+ insert_defvals(MEs, Fd),
+ insert_end(Fd),
+ file:close(Fd),
+ ?vlog("~s written", [HrlFile]);
+ {error, Reason} ->
+ ?vinfo("failed opening output file: "
+ "~n Reason: ~p", [Reason]),
+ {error, Reason}
+ end.
+
+insert_header(Fd) ->
+ ?vdebug("insert file header", []),
+ io:format(Fd, "%%% This file was automatically generated by "
+ "snmpc_mib_to_hrl version ~s~n", [?version]),
+ {Y,Mo,D} = date(),
+ {H,Mi,S} = time(),
+ io:format(Fd, "%%% Date: ~2.2.0w-~s-~w::~2.2.0w:~2.2.0w:~2.2.0w~n",
+ [D,month(Mo),Y,H,Mi,S]).
+
+insert_begin(Fd, MibName) ->
+ ?vdebug("insert file begin", []),
+ io:format(Fd,
+ "-ifndef('~s').~n"
+ "-define('~s', true).~n", [MibName, MibName]).
+
+insert_end(Fd) ->
+ ?vdebug("insert file end", []),
+ io:format(Fd, "-endif.~n", []).
+
+insert_oids(MEs, Fd) ->
+ ?vdebug("insert oids", []),
+ io:format(Fd, "~n%% Oids~n", []),
+ insert_oids2(MEs, Fd),
+ io:format(Fd, "~n", []).
+
+insert_oids2([#me{imported = true} | T], Fd) ->
+ insert_oids2(T, Fd);
+insert_oids2([#me{entrytype = table_column, oid = Oid, aliasname = Name} | T],
+ Fd) ->
+ ?vtrace("insert oid [table column]: ~p - ~w", [Name, Oid]),
+ io:format(Fd, "-define(~w, ~w).~n", [Name, lists:last(Oid)]),
+ insert_oids2(T, Fd);
+insert_oids2([#me{entrytype = variable, oid = Oid, aliasname = Name} | T],
+ Fd) ->
+ ?vtrace("insert oid [variable]: ~p - ~w", [Name, Oid]),
+ io:format(Fd, "-define(~w, ~w).~n", [Name, Oid]),
+ io:format(Fd, "-define(~w, ~w).~n", [merge_atoms(Name, instance),
+ Oid ++ [0]]),
+ insert_oids2(T, Fd);
+insert_oids2([#me{oid = Oid, aliasname = Name} | T], Fd) ->
+ ?vtrace("insert oid: ~p - ~w", [Name, Oid]),
+ io:format(Fd, "~n-define(~w, ~w).~n", [Name, Oid]),
+ insert_oids2(T, Fd);
+insert_oids2([], _Fd) ->
+ ok.
+
+
+insert_notifs(Traps, Fd) ->
+ ?vdebug("insert notifications", []),
+ Notifs = [Notif || Notif <- Traps, is_record(Notif, notification)],
+ case Notifs of
+ [] ->
+ ok;
+ _ ->
+ io:format(Fd, "~n%% Notifications~n", []),
+ insert_notifs2(Notifs, Fd)
+ end.
+
+insert_notifs2([], _Fd) ->
+ ok;
+insert_notifs2([#notification{trapname = Name, oid = Oid}|T], Fd) ->
+ ?vtrace("insert notification ~p - ~w", [Name, Oid]),
+ io:format(Fd, "-define(~w, ~w).~n", [Name, Oid]),
+ insert_notifs2(T, Fd).
+
+
+%%-----------------------------------------------------------------
+%% There's nothing strange with this function! Enums can be
+%% defined in types and in mibentries; therefore, we first call
+%% ins_types and then ins_mes to insert enums from different places.
+%%-----------------------------------------------------------------
+insert_enums(Types, MEs, Fd) ->
+ ?vdebug("insert enums", []),
+ T = ins_types(Types, Fd, []),
+ ins_mes(MEs, T, Fd).
+
+%% Insert all types, but not the imported. Ret the names of inserted
+%% types.
+ins_types([#asn1_type{aliasname = Name,
+ assocList = Alist,
+ imported = false} | T],
+ Fd, Res)
+ when is_list(Alist) ->
+ case lists:keysearch(enums, 1, Alist) of
+ {value, {enums, Enums}} when Enums =/= [] ->
+ case Enums of
+ [] -> ins_types(T, Fd, Res);
+ NewEnums ->
+ io:format(Fd, "~n%% Definitions from ~w~n", [Name]),
+ ins_enums(NewEnums, Name, Fd),
+ ins_types(T, Fd, [Name | Res])
+ end;
+ _ -> ins_types(T, Fd, Res)
+ end;
+ins_types([_ | T], Fd, Res) ->
+ ins_types(T, Fd, Res);
+ins_types([], _Fd, Res) -> Res.
+
+ins_mes([#me{entrytype = internal} | T], Types, Fd) ->
+ ins_mes(T, Types, Fd);
+ins_mes([#me{entrytype = table} | T], Types, Fd) ->
+ ins_mes(T, Types, Fd);
+ins_mes([#me{aliasname = Name,
+ asn1_type = #asn1_type{assocList = Alist,
+ aliasname = Aname},
+ imported = false} | T],
+ Types, Fd)
+ when is_list(Alist) ->
+ case lists:keysearch(enums, 1, Alist) of
+ {value, {enums, Enums}} when Enums =/= [] ->
+ case Enums of
+ [] -> ins_mes(T, Types, Fd);
+ NewEnums ->
+ %% Now, check if the type is already inserted
+ %% (by ins_types).
+ case lists:member(Aname, Types) of
+ false ->
+ io:format(Fd, "~n%% Enum definitions from ~w~n",
+ [Name]),
+ ins_enums(NewEnums, Name, Fd),
+ ins_mes(T, Types, Fd);
+ _ -> ins_mes(T, Types, Fd)
+ end
+ end;
+ _ -> ins_mes(T, Types, Fd)
+ end;
+ins_mes([_ | T], Types, Fd) ->
+ ins_mes(T, Types, Fd);
+ins_mes([], _Types, _Fd) -> ok.
+
+ins_enums([{Name, Val} | T], Origin, Fd) ->
+ EnumName = merge_atoms(Origin, Name),
+ io:format(Fd, "-define(~w, ~w).~n", [EnumName, Val]),
+ ins_enums(T, Origin, Fd);
+ins_enums([], _Origin, _Fd) ->
+ ok.
+
+%%----------------------------------------------------------------------
+%% Solves the problem with placing '' around some atoms.
+%% You can't write two atoms using ~w_~w.
+%%----------------------------------------------------------------------
+merge_atoms(TypeOrigin, Name) ->
+ list_to_atom(lists:append([atom_to_list(TypeOrigin), "_",
+ atom_to_list(Name)])).
+
+insert_defvals(Mes, Fd) ->
+ ?vdebug("insert default values", []),
+ io:format(Fd, "~n%% Default values~n", []),
+ insert_defvals2(Mes, Fd),
+ io:format(Fd, "~n", []).
+
+insert_defvals2([#me{imported = true} | T], Fd) ->
+ insert_defvals2(T, Fd);
+insert_defvals2([#me{entrytype = table_column, assocList = Alist,
+ aliasname = Name} | T],
+ Fd) ->
+ case snmpc_misc:assq(defval, Alist) of
+ {value, Val} ->
+ Atom = merge_atoms('default', Name),
+ io:format(Fd, "-define(~w, ~w).~n", [Atom, Val]);
+ _ -> ok
+ end,
+ insert_defvals2(T, Fd);
+insert_defvals2([#me{entrytype = variable, assocList = Alist, aliasname = Name}
+ | T],
+ Fd) ->
+ case snmpc_misc:assq(variable_info, Alist) of
+ {value, VarInfo} ->
+ case VarInfo#variable_info.defval of
+ undefined -> ok;
+ Val ->
+ Atom = merge_atoms('default', Name),
+ io:format(Fd, "-define(~w, ~w).~n", [Atom, Val])
+ end;
+ _ -> ok
+ end,
+ insert_defvals2(T, Fd);
+insert_defvals2([_ | T], Fd) ->
+ insert_defvals2(T, Fd);
+insert_defvals2([], _Fd) -> ok.
+
+insert_range(Mes, Fd) ->
+ ?vdebug("insert range", []),
+ io:format(Fd, "~n%% Range values~n", []),
+ insert_range2(Mes, Fd),
+ io:format(Fd, "~n", []).
+
+insert_range2([#me{imported = true} | T], Fd)->
+ insert_range2(T,Fd);
+insert_range2([#me{asn1_type=#asn1_type{bertype='OCTET STRING',lo=Low,hi=High},aliasname=Name}|T],Fd)->
+ case Low =:= undefined of
+ true->
+ insert_range2(T,Fd);
+ false->
+ AtomLow = merge_atoms('low', Name),
+ AtomHigh = merge_atoms('high', Name),
+ io:format(Fd,"-define(~w, ~w).~n",[AtomLow,Low]),
+ io:format(Fd,"-define(~w, ~w).~n",[AtomHigh,High]),
+ insert_range2(T,Fd)
+ end;
+insert_range2([#me{asn1_type=#asn1_type{bertype='Unsigned32',lo=Low,hi=High},aliasname=Name}|T],Fd)->
+ AtomLow = merge_atoms('low', Name),
+ AtomHigh = merge_atoms('high', Name),
+ io:format(Fd,"-define(~w, ~w).~n",[AtomLow,Low]),
+ io:format(Fd,"-define(~w, ~w).~n",[AtomHigh,High]),
+ insert_range2(T,Fd);
+insert_range2([#me{asn1_type=#asn1_type{bertype='Counter32',lo=Low,hi=High},aliasname=Name}|T],Fd)->
+ AtomLow = merge_atoms('low', Name),
+ AtomHigh = merge_atoms('high', Name),
+ io:format(Fd,"-define(~w, ~w).~n",[AtomLow,Low]),
+ io:format(Fd,"-define(~w, ~w).~n",[AtomHigh,High]),
+ insert_range2(T,Fd);
+insert_range2([#me{asn1_type=#asn1_type{bertype='INTEGER',lo=Low,hi=High},aliasname=Name}|T],Fd)->
+ case Low =:= undefined of
+ true->
+ insert_range2(T,Fd);
+ false->
+ AtomLow = merge_atoms('low', Name),
+ AtomHigh = merge_atoms('high', Name),
+ io:format(Fd,"-define(~w, ~w).~n",[AtomLow,Low]),
+ io:format(Fd,"-define(~w, ~w).~n",[AtomHigh,High]),
+ insert_range2(T,Fd)
+ end;
+insert_range2([_|T],Fd) ->
+ insert_range2(T,Fd);
+insert_range2([],_Fd) ->
+ ok.
+
+month(1) -> "Jan";
+month(2) -> "Feb";
+month(3) -> "Mar";
+month(4) -> "Apr";
+month(5) -> "May";
+month(6) -> "Jun";
+month(7) -> "Jul";
+month(8) -> "Aug";
+month(9) -> "Sep";
+month(10) -> "Oct";
+month(11) -> "Nov";
+month(12) -> "Dec".
+
+%%%-----------------------------------------------------------------
+%%% Interface for erl_compile.
+%%%-----------------------------------------------------------------
+
+%% Opts#options.specific
+compile(Input, Output, Opts) ->
+ set_verbosity(Opts),
+ set_filename(Input),
+ ?vtrace("compile -> entry with"
+ "~n Input: ~s"
+ "~n Output: ~s"
+ "~n Opts: ~p", [Input, Output, Opts]),
+ case convert(Input++".bin", Output++".hrl", Input) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ io:format("~p", [Reason]),
+ error
+ end.
+
+set_verbosity(#options{verbose = Verbose, specific = Spec}) ->
+ set_verbosity(Verbose, Spec).
+
+set_verbosity(Verbose, Spec) ->
+ Verbosity =
+ case lists:keysearch(verbosity, 1, Spec) of
+ {value, {verbosity, V}} ->
+ case (catch snmpc_lib:vvalidate(V)) of
+ ok ->
+ case Verbose of
+ true ->
+ case V of
+ silence ->
+ log;
+ info ->
+ log;
+ _ ->
+ V
+ end;
+ _ ->
+ V
+ end;
+ _ ->
+ case Verbose of
+ true ->
+ log;
+ false ->
+ silence
+ end
+ end;
+ false ->
+ case Verbose of
+ true ->
+ log;
+ false ->
+ silence
+ end
+ end,
+ put(verbosity, Verbosity).
+
+
+set_filename(Filename) ->
+ Rootname = filename:rootname(Filename),
+ Basename = filename:basename(Rootname ++ ".mib"),
+ put(filename, Basename).
+
+
+
+