mib2c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:39k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. #!/usr/bin/perl
  2. #!/usr/bin/perl -w
  3. #
  4. # $Id: mib2c,v 5.57 2004/09/10 12:30:15 dts12 Exp $
  5. #
  6. # Description: 
  7. #
  8. # This program, given an OID reference as an argument, creates some
  9. # template mib module files to be used with the net-snmp agent.  It is
  10. # far from perfect and will not generate working modules, but it
  11. # significantly shortens development time by outlining the basic
  12. # structure.
  13. #
  14. # Its up to you to verify what it does and change the default values
  15. # it returns.
  16. #
  17. # SNMP
  18. my $havesnmp = eval {require SNMP;};
  19. my $havenetsnmpoid = eval {require NetSNMP::OID;};
  20. if (!$havesnmp) {
  21.     print "
  22. ERROR: You don't have the SNMP perl module installed.  Please obtain
  23. this by getting the latest source release of the net-snmp toolkit from
  24. http://www.net-snmp.org/download/ .  Once you download the source and
  25. unpack it, the perl module is contained in the perl/SNMP directory.
  26. See the README file there for instructions.
  27. ";
  28.     exit;
  29. }
  30. if ($havesnmp) {
  31.     eval { import SNMP; }
  32. }
  33. if ($havenetsnmp) {
  34.     eval { import NetSNMP::OID; }
  35. }
  36. use FileHandle;
  37. #use strict 'vars';
  38. $SNMP::save_descriptions=1;
  39. $SNMP::use_long_names=1;
  40. $SNMP::use_enums=1;
  41. SNMP::initMib();
  42. $configfile="mib2c.conf";
  43. $debug=0;
  44. $quiet=0;
  45. $strict_unk_token = 0;
  46. $noindent = 0;
  47. $currentline = 0;
  48. $currentlevel = -1;
  49. %assignments;
  50. %outputs;
  51. @def_search_dirs = (".");
  52. @search_dirs = ();
  53. if($ENV{MIB2C_DIR}) {
  54.    push @def_search_dirs, split(/:/, $ENV{MIB2C_DIR});
  55. }
  56. push @def_search_dirs, "/usr/local/share/snmp/";
  57. push @def_search_dirs, "/usr/local/share/snmp/mib2c-data";
  58. push @def_search_dirs, "./mib2c-conf.d";
  59. sub usage {
  60.     print "$0 [-h] [-c configfile] [-f prefix] mibNodenn";
  61.     print "  -httThis message.nn";
  62.     print "  -c configfiletSpecifies the configuration file to usenttthat dictates what the output of mib2c will look like.nn";
  63.     print "  -I PATHtSpecifies a path to look for configuration files innn";
  64.     print "  -f prefixtSpecifies the output prefix to use.  All codenttwill be put into prefix.c and prefix.hnn";
  65.     print "  -dttdebugging output (don't do it.  trust me.)nn";
  66.     print "  -S VAR=VALtSet $VAR variable to $VALnn";
  67.     print "  -ittDon't run indent on the resulting codenn";
  68.     print "  mibNodetThe name of the top level mib node you want tonttgenerate code for.  By default, the code will be stored innttmibNode.c and mibNode.h (use the -f flag to change this)nn";
  69.     1;
  70. }
  71. my @origargs = @ARGV;
  72. my $args_done = 0;
  73. while($#ARGV >= 0) {
  74.     $_ = shift;
  75.     if (/^-/) {
  76.       if ($args_done != 0) {
  77.         warn "all argument must be specified before the mibNode!n";
  78.         usage;
  79.         exit 1;
  80.       } elsif (/^-c/) {
  81.         $configfile = shift;
  82.       } elsif (/^-d/) {
  83.         $debug = 1;
  84.       } elsif (/^-S/) {
  85.         my $expr = shift;
  86.         my ($var, $val) = ($expr =~ /([^=]*)=(.*)/);
  87.         die "no variable specified for -S flag." if (!$var);
  88.         $assignments{$var} = $val;
  89.       } elsif (/^-q/) {
  90.         $quiet = 1;
  91.       } elsif (/^-i/) {
  92.         $noindent = 1;
  93.       } elsif (/^-h/) {
  94.         usage && exit(1);
  95.       } elsif (/^-f/) {
  96.         $outputName = shift;
  97.       } elsif (/^-I/) {
  98. my $dirs = shift;
  99. push @search_dirs, split(/,/,$dirs);
  100.       } else {
  101.         warn "Unknown option '$_'n";
  102.         usage;
  103.         exit 1;
  104.       }
  105.     } else {
  106.       $args_done = 1;
  107.       warn "Replacing previous mibNode $oid with $_n" if ($oid);
  108.       $oid = $_ ;
  109.     }
  110. }
  111.  
  112. #
  113. # internal conversion tables
  114. #
  115. %accessToIsWritable = qw(ReadOnly 0 ReadWrite 1 
  116.  WriteOnly 1 Create 1);
  117. %perltoctypes = qw(OCTETSTR   ASN_OCTET_STR
  118.    INTEGER    ASN_INTEGER
  119.    INTEGER32  ASN_INTEGER
  120.    UNSIGNED32 ASN_UNSIGNED
  121.    OBJECTID   ASN_OBJECT_ID
  122.    COUNTER64  ASN_COUNTER64
  123.    COUNTER    ASN_COUNTER
  124.    NETADDR    ASN_COUNTER
  125.    UINTEGER   ASN_UINTEGER
  126.    IPADDR     ASN_IPADDRESS
  127.    BITS       ASN_OCTET_STR
  128.    TICKS      ASN_TIMETICKS
  129.    GAUGE      ASN_GAUGE
  130.    OPAQUE     ASN_OPAQUE);
  131. %perltodecl = ("OCTETSTR",  "char",
  132.        "INTEGER",  "long",
  133.        "INTEGER32",  "long",
  134.        "UNSIGNED32", "u_long",
  135.        "UINTEGER", "u_long",
  136.        "OBJECTID", "oid",
  137.        "COUNTER64", "U64",
  138.        "COUNTER", "u_long",
  139.        "IPADDR", "u_long",
  140.        "BITS", "char",
  141.        "TICKS", "u_long",
  142.        "GAUGE", "u_long",
  143.        "OPAQUE", "u_char");
  144. %perltolen = ("OCTETSTR",  "1",
  145.        "INTEGER",  "0",
  146.        "INTEGER32",  "0",
  147.        "UNSIGNED32", "0",
  148.        "UINTEGER", "0",
  149.        "OBJECTID", "1",
  150.        "COUNTER64", "0",
  151.        "COUNTER", "0",
  152.        "IPADDR", "0",
  153.        "BITS", "1",
  154.        "TICKS", "0",
  155.        "GAUGE", "0",
  156.        "OPAQUE", "1");
  157. my $mibnode = $SNMP::MIB{$oid};
  158. if (!$mibnode) { 
  159. print STDERR "
  160. You didn't give mib2c a valid OID to start with.  IE, I could not find
  161. any information about the mib node "$oid".  This could be caused
  162. because you supplied an incorrectly node, or by the MIB that you're
  163. trying to generate code from isn't loaded.  To make sure your mib is
  164. loaded, run mib2c using this as an example:
  165.    env MIBS="+MY-PERSONAL-MIB" mib2c " . join(" ",@origargs) . "
  166. You might wish to start by reading the MIB loading tutorial at:
  167.    http://www.net-snmp.org/tutorial-5/commands/mib-options.html
  168. And making sure you can get snmptranslate to display information about
  169. your MIB node.  Once snmptranslate works, then come back and try mib2c
  170. again.
  171. ";
  172. exit 1;
  173. }
  174. # setup
  175. $outputName = $mibnode->{'label'} if (!defined($outputName));
  176. $vars{'name'} = $outputName;
  177. $vars{'oid'} = $oid;
  178. $vars{'example_start'} = "    /*n" .
  179. "    ***************************************************n" .
  180. "    ***             START EXAMPLE CODE              ***n" .
  181. "    ***---------------------------------------------***/";
  182. $vars{'example_end'} = "    /*n" .
  183. "    ***---------------------------------------------***n" .
  184. "    ***              END  EXAMPLE CODE              ***n" .
  185. "    ***************************************************/";
  186. # loop through mib nodes, remembering stuff.
  187. setup_data($mibnode);
  188. if(($ENV{HOME}) && (-f "$ENV{HOME}/.snmp/mib2c.conf")) {
  189.   $fh = open_conf("$ENV{HOME}/.snmp/mib2c.conf");
  190.   process("-balanced");
  191.   $fh->close;
  192. }
  193. my $defaults = find_conf("default-$configfile",1);
  194. if (-f "$defaults" ) {
  195.   $fh = open_conf($defaults);
  196.   process("-balanced");
  197.   $fh->close;
  198. }
  199. my @theassignments = keys(%assignments);
  200. if ($#theassignments != -1) {
  201.   foreach $var (@theassignments) {
  202.     $vars{$var} = $assignments{$var};
  203.   }
  204. }
  205. $configfile = find_conf($configfile,0);
  206. $fh = open_conf($configfile);
  207. process("-balanced");
  208. $fh->close;
  209. if (!$noindent) {
  210.   foreach $i (keys(%written)) {
  211.     next if ($i eq "-");
  212.     next if (!($i =~ /.[ch]$/));
  213.     print STDERR "running indent on $in" if (!$quiet);
  214.     system("indent -orig -nbc -bap -nut -nfca -T size_t -T netsnmp_mib_handler -T netsnmp_handler_registration -T netsnmp_delegated_cache -T netsnmp_mib_handler_methods -T netsnmp_old_api_info -T netsnmp_old_api_cache -T netsnmp_set_info -T netsnmp_request_info -T netsnmp_set_info -T netsnmp_tree_cache -T netsnmp_agent_request_info -T netsnmp_cachemap -T netsnmp_agent_session -T netsnmp_array_group_item -T netsnmp_array_group -T netsnmp_table_array_callbacks -T netsnmp_table_row -T netsnmp_table_data -T netsnmp_table_data_set_storage -T netsnmp_table_data_set -T netsnmp_column_info -T netsnmp_table_registration_info -T netsnmp_table_request_info -T netsnmp_iterator_info -T netsnmp_data_list -T netsnmp_oid_array_header -T netsnmp_oid_array_header_wrapper -T netsnmp_oid_stash_node -T netsnmp_pdu -T netsnmp_request_list -T netsnmp_callback_pass -T netsnmp_callback_info -T netsnmp_transport -T netsnmp_transport_list -T netsnmp_tdomain $i");
  215.   }
  216. }
  217. sub m2c_die {
  218.   warn "ERROR: ". $_[0] . "n";
  219.   die "  at $currentfile:$currentlinen";
  220. }
  221. sub tocommas {
  222.     my $oid = $_[0];
  223.     $oid =~ s/./,/g;
  224.     $oid =~ s/^s*,//;
  225.     return $oid;
  226. }
  227. sub oidlength {
  228.     return (scalar split(/./, $_[0])) - 1;
  229. }
  230. # replaces $VAR type expressions and $VAR.subcomponent expressions
  231. # with data from the mib tree and loop variables.
  232. # possible uses:
  233. #
  234. #   $var               -- as defined by loops, etc.
  235. #   ${var}otherstuff   -- appending text to variable contents
  236. #   $var.uc            -- all upper case version of $var
  237. #
  238. # NOTE: THESE ARE AUTO-EXTRACTED/PROCESSED BY ../mib2c.extract.pl for man pages
  239. #
  240. # Mib components, $var must first expand to a mib node name:
  241. #
  242. #   $var.uc            -- all upper case version of $var
  243. #
  244. #   $var.objectID      -- dotted, fully-qualified, and numeric OID
  245. #   $var.commaoid      -- comma separated numeric OID for array initialization
  246. #   $var.oidlength     -- length of the oid
  247. #   $var.subid         -- last number component of oid
  248. #   $var.module        -- MIB name that the object comes from
  249. #   $var.parent        -- contains the label of the parent node of $var.
  250. #
  251. #   $var.isscalar      -- returns 1 if var contains the name of a scalar
  252. #   $var.iscolumn      -- returns 1 if var contains the name of a column
  253. #   $var.children      -- returns 1 if var has children
  254. #
  255. #   $var.perltype      -- node's perl SYNTAX ($SNMP::MIB{node}{'syntax'})
  256. #   $var.type          -- node's ASN_XXX type (Net-SNMP specific #define)
  257. #   $var.decl          -- C data type (char, u_long, ...)
  258. #
  259. #   $var.readable      -- 1 if an object is readable, 0 if not
  260. #   $var.settable      -- 1 if an object is writable, 0 if not
  261. #   $var.creatable     -- 1 if a column object can be created as part of a new row, 0 if not
  262. #   $var.noaccess      -- 1 if not-accessible, 0 if not
  263. #   $var.accessible    -- 1 if accessible, 0 if not
  264. #   $var.rowstatus     -- 1 if an object is a RowStatus object, 0 if not
  265. #     'settable', 'creatable' and 'rowstatus' can also be used with table variables
  266. #     to indicate whether it contains writable, creatable or RowStatus column objects
  267. #
  268. #   $var.hasdefval     -- returns 1 if var has a DEFVAL clause
  269. #   $var.defval        -- node's DEFVAL
  270. #   $var.hashint       -- returns 1 if var has a HINT clause
  271. #   $var.hint          -- node's HINT
  272. #   $var.ranges        -- returns 1 if var has a value range defined
  273. #   $var.enums         -- returns 1 if var has enums defined for it.
  274. #   $var.access        -- node's access type
  275. #   $var.status        -- node's status
  276. #   $var.syntax        -- node's syntax
  277. #   $var.reference     -- node's reference
  278. #   $var.description   -- node's description
  279. sub process_vars {
  280.     my $it = shift;
  281.     # mib substitutions ($var.type -> $mibnode->{'type'})
  282.    if ( $it =~ /$(w+).(w+)/ ) {
  283.     if ($SNMP::MIB{$vars{$1}} && $SNMP::MIB{$vars{$1}}{'label'} =~ /Table$/) {
  284.       $it =~ s/$(w+).(settable)/(table_is_writable($SNMP::MIB{$vars{$1}}{label}))/eg;
  285.       $it =~ s/$(w+).(creatable)/(table_has_create($SNMP::MIB{$vars{$1}}{label}))/eg;
  286.       $it =~ s/$(w+).(rowstatus)/(table_has_rowstatus($SNMP::MIB{$vars{$1}}{label}))/eg;
  287.     }
  288.     $it =~ s/$(w+).(uc)/uc($vars{$1})/eg; # make something uppercase
  289.     $it =~ s/$(w+).(commaoid)/tocommas($SNMP::MIB{$vars{$1}}{objectID})/eg;
  290.     $it =~ s/$(w+).(oidlength)/oidlength($SNMP::MIB{$vars{$1}}{objectID})/eg;
  291.     $it =~ s/$(w+).(description)/$SNMP::MIB{$vars{$1}}{description}/g;
  292.     $it =~ s/$(w+).(perltype)/$SNMP::MIB{$vars{$1}}{type}/g;
  293.     $it =~ s/$(w+).(type)/$perltoctypes{$SNMP::MIB{$vars{$1}}{$2}}/g;
  294.     $it =~ s/$(w+).(subid)/$SNMP::MIB{$vars{$1}}{subID}/g;
  295.     $it =~ s/$(w+).(module)/$SNMP::MIB{$vars{$1}}{moduleID}/g;
  296.     $it =~ s/$(w+).(settable)/(($SNMP::MIB{$vars{$1}}{access} =~ /(ReadWrite|Create|WriteOnly)/)?1:0)/eg;
  297.     $it =~ s/$(w+).(creatable)/(($SNMP::MIB{$vars{$1}}{access} =~ /(Create)/)?1:0)/eg;
  298.     $it =~ s/$(w+).(readable)/(($SNMP::MIB{$vars{$1}}{access} =~ /(Read|Create)/)?1:0)/eg;
  299.     $it =~ s/$(w+).(noaccess)/(($SNMP::MIB{$vars{$1}}{access} =~ /(NoAccess)/)?1:0)/eg;
  300.     $it =~ s/$(w+).(accessible)/(($SNMP::MIB{$vars{$1}}{access} !~ /(NoAccess)/)?1:0)/eg;
  301.     $it =~ s/$(w+).(objectID|label|subID|access|status|syntax|reference)/$SNMP::MIB{$vars{$1}}{$2}/g;
  302.     $it =~ s/$(w+).(decl)/$perltodecl{$SNMP::MIB{$vars{$1}}{type}}/g;
  303.     $it =~ s/$(w+).(needlength)/$perltolen{$SNMP::MIB{$vars{$1}}{type}}/g;
  304.     $it =~ s/$(w+).(iscolumn)/($SNMP::MIB{$vars{$1}}{'parent'}{'label'} =~ /Entry$/) ? 1 : 0/eg;
  305.     $it =~ s/$(w+).(isscalar)/($SNMP::MIB{$vars{$1}}{'parent'}{'label'} !~ /Entry$/ && $SNMP::MIB{$vars{$1}}{access}) ? 1 : 0/eg;
  306.     $it =~ s/$(w+).(parent)/$SNMP::MIB{$vars{$1}}{'parent'}{'label'}/g;
  307.     $it =~ s/$(w+).(children)/($#{$SNMP::MIB{$vars{$1}}{'children'}} == 0) ? 0 : 1/eg;
  308.     $it =~ s/$(w+).(hasdefval)/(length($SNMP::MIB{$vars{$1}}{'defaultValue'}) == 0) ? 0 : 1/eg;
  309.     $it =~ s/$(w+).(defval)/$SNMP::MIB{$vars{$1}}{'defaultValue'}/g;
  310.     $it =~ s/$(w+).(hashint)/(length($SNMP::MIB{$vars{$1}}{'hint'}) == 0) ? 0 : 1/eg;
  311.     $it =~ s/$(w+).(hint)/$SNMP::MIB{$vars{$1}}{'hint'}/g;
  312.     $it =~ s/$(w+).(ranges)/($#{$SNMP::MIB{$vars{$1}}{'ranges'}} == -1) ? 0 : 1/eg;
  313.     # check for enums
  314.     $it =~ s/$(w+).(enums)/(%{$SNMP::MIB{$vars{$1}}{'enums'}} == 0) ? 0 : 1/eg;
  315.     $it =~ s/$(w+).(enumrange)/%{$SNMP::MIB{$vars{$1}}{'enums'}}/eg;
  316.     $it =~ s/$(w+).(rowstatus)/(($SNMP::MIB{$vars{$1}}{syntax} =~ /(RowStatus)/)?1:0)/eg;
  317.     if ( $it =~ /$(w+).(w+)/ ) {
  318.       warn "Possible unknown variable attribute $$1.$2 at $currentfile:$currentlinen";
  319.     }
  320.   }
  321.     # normal variable substitions
  322.     $it =~ s/${(w+)}/$vars{$1}/g;
  323.     $it =~ s/$(w+)/$vars{$1}/g;
  324.     # use $@var to put literal '$var'
  325.     $it =~ s/$@(w+)/$$1/g;
  326.     return $it;
  327. }
  328. # process various types of statements
  329. #
  330. # NOTE: THESE ARE AUTO-EXTRACTED/PROCESSED BY ../mib2c.extract.pl for man pages
  331. # which include:
  332. #   @open FILE@
  333. #     writes generated output to FILE
  334. #     note that for file specifications, opening '-' will print to stdout.
  335. #   @append FILE@
  336. #     appends the given FILE
  337. #   @close FILE@
  338. #     closes the given FILE
  339. #   @push@
  340. #     save the current outputs, then clear outputs. Use with @open@
  341. #     and @pop@ to write to a new file without interfering with current
  342. #     outputs.
  343. #   @pop@
  344. #     pop up the process() stack one level. Use after a @push@ to return to
  345. #     the previous set of open files.
  346. #   @foreach $VAR scalar@
  347. #     repeat iterate over code until @end@ setting $VAR to all known scalars
  348. #   @foreach $VAR table@
  349. #     repeat iterate over code until @end@ setting $VAR to all known tables
  350. #   @foreach $VAR column@
  351. #     repeat iterate over code until @end@ setting $VAR to all known
  352. #     columns within a given table.  Obviously this must be called
  353. #     within a foreach-table clause.
  354. #   @foreach $VAR nonindex@
  355. #     repeat iterate over code until @end@ setting $VAR to all known
  356. #     non-index columns within a given table.  Obviously this must be called
  357. #     within a foreach-table clause.
  358. #   @foreach $VAR internalindex@
  359. #     repeat iterate over code until @end@ setting $VAR to all known internal
  360. #     index columns within a given table.  Obviously this must be called
  361. #     within a foreach-table clause.
  362. #   @foreach $VAR externalindex@
  363. #     repeat iterate over code until @end@ setting $VAR to all known external
  364. #     index columns within a given table.  Obviously this must be called
  365. #     within a foreach-table clause.
  366. #   @foreach $VAR index@
  367. #     repeat iterate over code until @end@ setting $VAR to all known
  368. #     indexes within a given table.  Obviously this must be called
  369. #     within a foreach-table clause.
  370. #   @foreach $VAR notifications@
  371. #     repeat iterate over code until @end@ setting $VAR to all known notifications
  372. #   @foreach $VAR varbinds@
  373. #     repeat iterate over code until @end@ setting $VAR to all known varbinds
  374. #     Obviously this must be called within a foreach-notifications clause.
  375. #   @foreach $LABEL, $VALUE enum@
  376. #     repeat iterate over code until @end@ setting $LABEL and $VALUE
  377. #     to the label and values from the enum list.
  378. #   @foreach $RANGE_START, $RANGE_END range NODE@
  379. #     repeat iterate over code until @end@ setting $RANGE_START and $RANGE_END
  380. #     to the legal accepted range set for a given mib NODE.
  381. #   @foreach $var stuff a b c d@
  382. #     repeat iterate over values a, b, c, d as assigned generically
  383. #     (ie, the values are taken straight from the list with no
  384. #     mib-expansion, etc).
  385. #   @eval $VAR = expression@
  386. #     evaluates expression and assigns the results to $VAR.  This is
  387. #     not a full perl eval, but sort of a "psuedo" eval useful for
  388. #     simple expressions while keeping the same variable name space.
  389. #     See below for a full-blown export to perl.
  390. #   @perleval STUFF@
  391. #     evaluates STUFF directly in perl.  Note that all mib2c variables
  392. #     interpereted within .conf files are in $vars{NAME}.
  393. #   @startperl@
  394. #   @endperl@
  395. #     treats everything between these tags as perl code, and evaluates it.
  396. #   @next@
  397. #     restart foreach; should only be used inside a conditional.
  398. #     skips out of current conditional, then continues to skip to
  399. #     end for the current foreach clause.
  400. #   @if expression@
  401. #     evaluates expression, and if expression is true processes
  402. #     contained part until appropriate @end@ is reached.  If an @else@
  403. #     clause is found, it will be evaluated instead if expression
  404. #     isn't true.
  405. #   @define NAME@
  406. #   @enddefine@
  407. #     Memorizes "stuff" between the define and enddefine tags for
  408. #     later calling as NAME by @calldefine NAME@.
  409. #   @calldefine NAME@
  410. #     Executes stuff previously memorized as NAME.
  411. #   @printf "expression" stuff1, stuff2, ...@
  412. #     Like all the other printf's you know and love.
  413. #   @run FILE@
  414. #     Sources the contents of FILE as a mib2c file,
  415. #     but does not affect current files opened.
  416. #   @include FILE@
  417. #     Sources the contents of FILE as a mib2c file and appends its
  418. #     output to the current output.
  419. #   @prompt $var QUESTION@
  420. #     Presents the user with QUESTION, expects a response and puts it in $var
  421. #   @print STUFF@
  422. #     Prints stuff directly to the users screen (ie, not to where
  423. #     normal mib2c output goes)
  424. #   @exit@
  425. #     Bail out!
  426. #
  427. sub skippart {
  428.   my $endcount = 1;
  429.   my $arg = shift;
  430.   my $rtnelse = 0;
  431.   while ($arg =~ s/-(w+)s*//) {
  432.     $rtnelse = 1 if ($1 eq "else");
  433.   }
  434.   while(get_next_line()) {
  435.     $currentline++;
  436.     $_ = process_vars($_) if ($debug);
  437.     print "$currentfile.$currentline:P$currentlevel:S$endcount.$rtnelse:$_" if ($debug);
  438.         next if ( /^s*##/ ); #                          noop, it's a comment
  439.         next if (! /^s*@/ ); #                                        output
  440.         if (! /^s*@.*@/ ) {
  441.           warn "$currentfile:$currentline contained a line that started with a @ but did not match any mib2c configuration tokens.n";
  442.           warn "(maybe missing the trailing @?)n";
  443.           warn "$currentfile:$currentline [$_]n";
  444.         }
  445. elsif (/@s*end@/) {
  446.     return "end" if ($endcount == 1);
  447.     $endcount--;
  448. }
  449. elsif (/@s*elseif.*@/) {
  450.           m2c_die "use 'elsif' instead of 'elseif'n";
  451.         }
  452. elsif (/@s*else@/) {
  453.     return "else" if (($endcount == 1) && ($rtnelse == 1));
  454. }
  455. elsif (/@s*elsifs+([^@]+)@/) {
  456.     return "else" if (($endcount == 1) && ($rtnelse == 1) && (eval(process_vars($1))));
  457. }
  458. elsif (/@s*(foreach|if)/) {
  459.     $endcount++;
  460. }
  461.     }
  462.   print "skippart EOFn";
  463.   m2c_die "unbalanced code detected in skippart: EOF when $endcount levels deep" if($endcount != 1);
  464.   return "eof";
  465. }
  466. sub close_file {
  467.   my $name = shift;
  468.   if (!$name) {
  469.     print "close_file w/out name!n";
  470.     return;
  471.   }
  472.   if(!$outputs{$name}) {
  473.     print "no handle for $namen";
  474.     return;
  475.   }
  476.   $outputs{$name}->close();
  477.   delete $outputs{$name};
  478. #  print STDERR "closing $namen" if (!$quiet);
  479. }
  480. sub close_files {
  481.   foreach $name (keys(%outputs)) {
  482.     close_file($name);
  483.   }
  484. }
  485. sub open_file {
  486.   my $multiple = shift;
  487.   my $spec = shift;
  488.   my $name = $spec;
  489.   $name =~ s/>//;
  490.   if ($multiple == 0) {
  491.     close_files();
  492.   }
  493.   return if ($outputs{$name});
  494.   $outputs{$name} = new IO::File;
  495.   $outputs{$name}->open(">$spec") || m2c_die "failed to open $name";
  496.   print STDERR "writing to $namen" if (!$quiet && !$written{$name});
  497.   $written{$name} = '1';
  498. }
  499. sub process_file {
  500.   my ($file, $missingok, $keepvars) = (@_);
  501.   my $oldfh = $fh;
  502.   my $oldfile = $currentfile;
  503.   my $oldline = $currentline;
  504.   # keep old copy of @vars and just build on it.
  505.   my %oldvars;
  506.   %oldvars = %vars if ($keepvars != 1);
  507.   $file = find_conf($file,$missingok);
  508.   return if (! $file);
  509.   $fh = open_conf($file);
  510.   $currentline = 0;
  511.   process("-balanced");
  512.   $fh->close();
  513.   $fh = $oldfh;
  514.   $currentfile = $oldfile;
  515.   $currentline = $oldline;
  516.   # don't keep values in replaced vars.  Revert to ours.
  517.   %vars = %oldvars if ($keepvars != 1);
  518. }
  519. sub get_next_line {
  520.     if ($#process_lines > -1) {
  521. return $_ = shift @process_lines;
  522.     }
  523.     return $_ = <$fh>;
  524. }
  525. sub do_tell {
  526.     my $stash;
  527.     $stash->{'startpos'} = $fh->tell();
  528.     $stash->{'startline'} = $currentline;
  529.     @{$stash->{'lines'}} = @process_lines;
  530.     return $stash;
  531. }
  532. sub do_seek {
  533.     my $stash = shift;
  534.     # save current line number
  535.     $currentline = $stash->{'startline'};
  536.     $fh->seek($stash->{'startpos'}, 0); # go to top of section.
  537.     # save current process_lines state.
  538.     @process_lines = @{$stash->{'lines'}};
  539.     # save state of a number of variables (references), and new assignments
  540.     for (my $i = 0; $i <= $#_; $i += 2) {
  541. push @{$stash->{'vars'}}, $_[$i], ${$_[$i]};
  542. ${$_[$i]} = $_[$i+1];
  543.     }
  544. }
  545. sub do_unseek {
  546.     my $stash = shift;
  547.     for (my $i = 0; $i <= $#{$stash->{'vars'}}; $i += 2) {
  548. ${$stash->{'vars'}[$i]} = $stash->{'vars'}[$i+1];
  549.     }
  550. }
  551. sub do_a_loop {
  552.     my $stash = shift;
  553.     do_seek($stash, @_);
  554.     my $return = process();
  555.     do_unseek($stash);
  556.     return $return;
  557. }
  558. sub process {
  559.   my $arg = shift;
  560.   my $elseok = 0;
  561.   my $balanced = 0;
  562.   my $startlevel;
  563.   my $return = "eof";
  564.   while ($arg =~ s/-(w+)s*//) {
  565.     $elseok = 1 if ($1 eq "elseok");
  566.     $balanced = 1 if ($1 eq "balanced");
  567.   }
  568.   $currentlevel++;
  569.   $startlevel = $currentlevel;
  570.   if($balanced) {
  571.     $balanced = $currentlevel;
  572.   }
  573.     while(get_next_line()) {
  574.       $currentline++;
  575.       if ($debug) {
  576. #        my $line = process_vars($_);
  577. #        chop $line;
  578.         print "$currentfile.$currentline:P$currentlevel.$elseok:$return:$_";
  579.       }
  580.         next if (/^s*##/); #                            noop, it's a comment
  581.         if (! /^s*@/ ) { #                                          output
  582.           my $line = process_vars($_);
  583.           foreach $file (values(%outputs)) {
  584.             print $file "$line";
  585.           }
  586. } ####################################################################
  587.         elsif (/@s*exit@/) { #                                         EXIT
  588.             close_files;
  589.     die "exiting at conf file ($currentfile:$currentline) requestn";
  590. } elsif (/@s*debugs+([^@]+)@/) { #                          DEBUG
  591.           if ($1 eq "on") {
  592.             $debug = 1;
  593.           }
  594.           else {
  595.             $debug = 0;
  596.           }
  597. } elsif (/@s*strict tokens+([^@]+)@/) { #                  STRICT
  598.           if ($1 eq "on") {
  599.             $strict_unk_token = 1;
  600.           }
  601.           else {
  602.             $strict_unk_token = 0;
  603.           }
  604. } elsif (/@s*balanced@/) { #                               BALANCED
  605.           $balanced = $currentlevel;
  606. } elsif (/@s*opens+([^@]+)@/) { #                            OPEN
  607.     my $arg = $1;
  608.     my ($multiple) = (0);
  609.     while ($arg =~ s/-(w+)s+//) {
  610. $multiple = 1 if ($1 eq 'multiple');
  611.     }
  612.     my $spec = process_vars($arg);
  613.             open_file($multiple, $spec);
  614. } elsif (/@s*closes+([^@]+)@/) { #                          CLOSE
  615.     my $spec = process_vars($1);
  616.             close_file($spec);
  617. } elsif (/@s*appends+([^@]+)@/) { #                        APPEND
  618.     my $arg = $1;
  619.     my ($multiple) = (0);
  620.     while ($arg =~ s/-(w+)s+//) {
  621. $multiple = 1 if ($1 eq 'multiple');
  622.     }
  623.     my $spec = process_vars($arg);
  624.             $spec=">$spec";
  625.             open_file($multiple,$spec);
  626. } elsif (/@s*defines*(.*)@/) { #                              DEFINE
  627.     my $it = $1;
  628.     while (<$fh>) {
  629. last if (/@s*enddefines*@/);
  630. push @{$defines{$it}}, $_;
  631.     }
  632. } elsif (/@s*calldefines+(w+)@/) {
  633.     if ($#{$defines{$1}} == -1) {
  634. warn "called a define of $1 which didn't existn";
  635. warn "$currentfile:$currentline [$_]n";
  636.     } else {
  637. unshift @process_lines, @{$defines{$1}};
  638.     }
  639.        } elsif (/@s*run (.*)@/) { #                                    RUN
  640.     my $arg = $1;
  641.     my ($again) = (0);
  642.     while ($arg =~ s/-(w+)s+//) {
  643. $again = 1 if ($1 eq 'again');
  644. # if ($1 eq 'file') {
  645. #     my ($filearg) = ($arg =~ s/^(w+)//);
  646. # }
  647.     }
  648.     my $spec = process_vars($arg);
  649.     next if (!$again && $ranalready{$spec});
  650.     $ranalready{$spec} = 1;
  651.     my %oldout = %outputs;
  652.             my %emptyarray;
  653.             %outputs = %emptyoutputs;
  654.             process_file($spec,0,0);
  655.             close_files;
  656.     %outputs = %oldout;
  657. } elsif (/@s*push@/) { #                                      PUSH
  658.     my %oldout = %outputs;
  659.             my %emptyarray;
  660.             %outputs = %emptyoutputs;
  661.             process($arg);
  662.             close_files;
  663.     %outputs = %oldout;
  664. } elsif (/@s*pops*@/) { #                                     POP
  665.           $return = "pop";
  666.           last;
  667. } elsif (/@s*include (.*)@/) { #                            INCLUDE
  668.     my $arg = $1;
  669.     my ($missingok) = (0);
  670.     while ($arg =~ s/-(w+)s+//) {
  671. $missingok = 1 if ($1 eq 'ifexists');
  672.     }
  673.             my $spec = process_vars($arg);
  674.             process_file($spec,$missingok,1);
  675. } elsif (/@s*if([a-z]*)s+([^@]+)@/) { #                         IF
  676.           my ($type,$arg,$ok) = ($1,$2,0);
  677.           # check condition based on type
  678.           if (! $type) {
  679.             $ok = eval(process_vars($arg));
  680.           } elsif ($type eq conf) {
  681.             my $file = find_conf(process_vars($arg),1); # missingok
  682.             $ok = (-f $file);
  683.           } else {
  684.             m2c_die "unknown if modifier ($type)n";
  685.           }
  686.           # act on condition
  687.           if ($ok) {
  688.             $return = process("-elseok");
  689.           } else {
  690.             $return = skippart("-else");
  691.             $return = process("-elseok") if ($return eq "else");
  692.           }
  693.           if ($return eq "next") {
  694.             $return = skippart();
  695.             m2c_die("unbalanced code detected while exiting next/2 (returned $return)") if ($return ne "end");
  696. #            $return = "next";
  697.             last;
  698.           }
  699.           if (($return ne "end") && ($return ne "else")) {
  700.             m2c_die "unbalanced if / return $returnn";
  701.           }
  702.         } elsif (/@s*elseif.*@/) { #                           bogus elseif
  703.           m2c_die "error: use 'elsif' instead of 'elseif'n";
  704. } elsif (/@s*els(e|if).*@/) { #                          ELSE/ELSIF
  705.           if ($elseok != 1) {
  706.             chop $_;
  707.             m2c_die "unexpected els$1n";
  708.           }
  709.           $return = skippart();
  710.           if ($return ne "end") {
  711.             m2c_die "unbalanced els$1 / rtn $rtnn";
  712.           }
  713.           $return = "else";
  714.           last;
  715. } elsif (/@s*nexts*@/) { #                                  NEXT
  716.           $return = skippart();
  717.           m2c_die "unbalanced code detected while exiting next/1 (returned $return)" if ($return ne "end");
  718.           $return = "next";
  719.           last;
  720. } elsif (/@s*end@/) { #                                         END
  721.           $return = "end";
  722.           last;
  723. } elsif (/@s*evals+$(w+)s*=s*([^@]*)/) { #                EVAL
  724.     my ($v, $e) = ($1, $2);
  725. #     print STDERR "eval: $en";
  726.     my $e = process_vars($e);
  727.     $vars{$v} = eval($e);
  728.             if (!defined($vars{$v})) {
  729.               warn "$@";
  730.               warn "$currentfile:$currentline [$_]n";
  731.             }
  732. } elsif (/@s*perlevals*(.*)@/) { #                        PERLEVAL
  733. #     print STDERR "perleval: $1n";
  734.     my $res = eval($1);
  735.             if ($res) {
  736.               warn "$@";
  737.               warn "$currentfile:$currentline [$_]n";
  738.             }
  739. } elsif (/@s*startperls*@/) { #                          STARTPERL
  740.     my $text;
  741.     while (get_next_line()) {
  742. last if (/@s*endperls*@/);
  743. $text .= $_;
  744.     }
  745.     my $res = eval($text);
  746.             if ($res) {
  747.               warn "$@";
  748.               warn "$currentfile:$currentline [$_]n";
  749.             }
  750. #     print STDERR "perleval: $1n";
  751. } elsif (/@s*printfs+("[^"]+")s*,?(.*)@/) { #           PRINTF
  752.     my ($f, $rest) = ($1, $2);
  753.     $rest = process_vars($rest);
  754.     my @args = split(/s*,s*/,$rest);
  755.     $f = eval $f;
  756. #     print STDERR "printf: $f, ", join(", ",@args),"n";
  757.     foreach $file (values(%outputs)) {
  758. printf $file (eval {$f}, @args);
  759.     }
  760. } elsif (/@s*foreachs+$([^@]+)s+scalars*s*@/) { #      SCALARS
  761.     my $var = $1;
  762.     my $stash = do_tell();
  763.     my $scalar;
  764.     my @thekeys = keys(%scalars);
  765.     if ($#thekeys == -1) {
  766.       $return = skippart();
  767.     } else {
  768.       if ($havenetsnmpoid) {
  769.   @thekeys = sort {
  770.     new NetSNMP::OID($a) <=> 
  771.       new NetSNMP::OID($b) } @thekeys;
  772.       }
  773.       foreach $scalar (@thekeys) {
  774.   $return = do_a_loop($stash, $vars{$var}, $scalar,
  775.       $currentscalar, $scalar,
  776.       $currentvar, $scalar);
  777.       }
  778.     }
  779.             m2c_die("foreach did not end with @end@") if($return ne "end");
  780. } elsif (/@s*foreachs+$([^@]+)s+notifications*s*@/) {
  781.     my $var = $1;
  782.     my $stash = do_tell();
  783.     my $notify;
  784.     my @thekeys = keys(%notifications);
  785.     if ($#thekeys == -1) {
  786.       $return = skippart();
  787.     } else {
  788.       if ($havenetsnmpoid) {
  789.   @thekeys = sort {
  790.     new NetSNMP::OID($a) <=> 
  791.       new NetSNMP::OID($b) } @thekeys;
  792.       }
  793.       foreach $notify (@thekeys) {
  794.   $return = do_a_loop($stash, $vars{$var}, $notify,
  795.       $currentnotify, $notify);
  796.       }
  797.     }
  798.             m2c_die("foreach did not end with @end@") if($return ne "end");
  799.   } elsif (/@s*foreachs+$([^@]+)s+varbindss*@/) {
  800.     my $var = $1;
  801.     my $stash = do_tell();
  802.     my $varbind;
  803.     if ($#{$notifyvars{$currentnotify}} == -1) {
  804.       $return = skippart();
  805.     } else {
  806.       foreach $varbind (@{$notifyvars{$currentnotify}}) {
  807. # print "looping on $var for $varbindn";
  808.   $return = do_a_loop($stash, $vars{$var}, $varbind,
  809.       $currentvarbind, $varbind);
  810.       }
  811.     }
  812.             m2c_die("foreach did not end with @end@") if($return ne "end");
  813.   } elsif (/@s*foreachs+$([^@]+)s+tables*s*@/) {
  814.     my $var = $1;
  815.     my $stash = do_tell();
  816.     my $table;
  817.     my @thekeys = keys(%tables);
  818.     if ($#thekeys == -1) {
  819.       $return = skippart();
  820.     } else {
  821.       if ($havenetsnmpoid) {
  822.   @thekeys = sort {
  823.     new NetSNMP::OID($a) <=> 
  824.       new NetSNMP::OID($b) } @thekeys;
  825.       }
  826.       foreach $table (@thekeys) {
  827.   $return = do_a_loop($stash, $vars{$var}, $table, 
  828.       $currenttable, $table);
  829.       }
  830.     }
  831.             m2c_die("foreach did not end with @end@ ($return)") if($return ne "end");
  832.   } elsif (/@s*foreachs+$([^@]+)s+stuffs*(.*)@/) {
  833.     my $var = $1;
  834.     my $stuff = $2;
  835.     my @stuff = split(/[,s]+/, $stuff);
  836.     my $stash = do_tell();
  837.     if ($#stuff == -1) {
  838.       $return = skippart();
  839.     } else {
  840.       foreach $st (@stuff) {
  841.   $return = do_a_loop($stash, $vars{$var}, $st,
  842.       $currentstuff, $st);
  843.       }
  844.     }
  845.             m2c_die("foreach did not end with @end@ ($return)") if($return ne "end");
  846.   } elsif (/@s*foreachs+$([^@]+)s+(column|index|internalindex|externalindex|nonindex)s*@/) {
  847.     my ($var, $type) = ($1, $2);
  848.     my $stash = do_tell();
  849.     my $column;
  850.     if ($#{$tables{$currenttable}{$type}} == -1) {
  851.       $return = skippart();
  852.     } else {
  853.       foreach $column (@{$tables{$currenttable}{$type}}) {
  854. # print "looping on $var for $type -> $columnn";
  855.   $return = do_a_loop($stash, $vars{$var}, $column,
  856.       $currentcolumn, $column,
  857.       $currentvar, $column);
  858.       }
  859.     }
  860.             m2c_die("foreach did not end with @end@") if($return ne "end");
  861.   } elsif (/@s*foreachs+$([^@]+)s+$([^@]+)s+ranges+([^@]+)@/) {
  862.     my ($svar, $evar, $node) = ($1, $2, $3);
  863.     my $stash = do_tell();
  864.     my $range;
  865.     $node = $currentcolumn if (!$node);
  866.     my $mibn = $SNMP::MIB{process_vars($node)};
  867.     die "no such mib node: $node" if (!$mibn);
  868.     my @ranges = @{$mibn->{'ranges'}};
  869.     if ($#ranges > -1) {
  870. foreach $range (@ranges) {
  871.     $return = do_a_loop($stash, $vars{$svar}, $range->{'low'},
  872. $vars{$evar}, $range->{'high'});
  873. }
  874.     } else {
  875. $return = skippart();
  876.     }
  877.             m2c_die("foreach did not end with @end@") if($return ne "end");
  878. } elsif (/@s*foreachs+$([^@,]+)s*,*s+$([^@]+)s+(enums*)s*@/) {
  879.     my ($varvar, $varval, $type) = ($1, $2, $3);
  880.     my $stash = do_tell();
  881.     my $enum, $enum2;
  882.     my @keys = sort { $SNMP::MIB{$currentvar}{'enums'}{$a} <=>
  883.   $SNMP::MIB{$currentvar}{'enums'}{$b} } (keys(%{$SNMP::MIB{$currentvar}{'enums'}}));
  884.     if ($#keys > -1) {
  885. foreach $enum (@keys) {
  886.                   ($enum2 = $enum) =~ s/-/_/g;
  887.     $return = do_a_loop($stash, $vars{$varvar}, $enum2,
  888. $vars{$varval},
  889. $SNMP::MIB{$currentvar}{'enums'}{$enum});
  890. }
  891.     } else {
  892. $return = skippart();
  893.     }
  894.             m2c_die("foreach did not end with @end@") if($return ne "end");
  895. } elsif (/@s*prompts+$(S+)s*(.*)@/) { #                  PROMPT
  896.     my ($var, $prompt) = ($1, $2);
  897.     if (!$term) {
  898. my $haveit = eval { require Term::ReadLine };
  899. if ($haveit) {
  900.     $term = new Term::ReadLine 'mib2c';
  901. }
  902.     }
  903.     if ($term) {
  904. $vars{$var} = $term->readline(process_vars($prompt));
  905.     }
  906. } elsif (/@s*prints+([^@]*)@/) { #                           PRINT
  907.           my $line = process_vars($1);
  908.           print "$linen";
  909. } else {
  910.           my $line = process_vars($_);
  911.   mib2c_output($line);
  912.           chop $_;
  913.           warn "$currentfile:$currentline contained a line that started with a @ but did not match any mib2c configuration tokens.n";
  914.           warn "(maybe missing the trailing @?)n";
  915.           m2c_die if ($strict_unk_token == 1);
  916. }
  917. #      $return = "eof";
  918.     }
  919.     print "< Balanced $balanced / level $currentlevel / rtn $return / $_n" if($debug);
  920.     if((!$_) && ($return ne "eof")) {
  921. #      warn "switching return of '$return' to EOFn" if($debug);
  922.       $return = "eof";
  923.     }
  924.   if ($balanced) {
  925.     if(($balanced != $currentlevel) || ($return ne "eof")) {
  926.       m2c_die "@balanced@ specified, but processing terminated with '$return' before EOF!";
  927.     }
  928.   }
  929.   $currentlevel--;
  930.   return $return;
  931. }
  932. sub mib2c_output {
  933.     my $line = shift;
  934.     foreach $file (values(%outputs)) {
  935. print $file "$line";
  936.     }
  937. }
  938. sub setup_data {
  939.     my $mib = shift;
  940.     if ($mib->{label} =~ /Table$/) {
  941. my $tablename = $mib->{label};
  942. my $entry = $mib->{children};
  943. my $columns = $entry->[0]{children};
  944.         my $augments = $entry->[0]{'augments'};
  945. foreach my $col (sort { $a->{'subID'} <=> $b->{'subID'} } @$columns) {
  946.     # store by numeric key so we can sort them later
  947.     push @{$tables{$tablename}{'column'}}, $col->{'label'};
  948. }
  949.         if ($augments) {
  950.            my $mib = $SNMP::MIB{$augments} || 
  951. die "can't find info about augmented table $augments in table $tablenamen";
  952.            $mib = $mib->{parent} || 
  953. die "can't find info about augmented table $augments in table $tablenamen";
  954.    my $entry = $mib->{children};
  955.    foreach my $index (@{$entry->[0]{'indexes'}}) {
  956.        my $node = $SNMP::MIB{$index} || 
  957.    die "can't find info about index $index in table $tablenamen";
  958.        push @{$tables{$tablename}{'index'}}, $index;
  959.        push @{$tables{$tablename}{'externalindex'}}, $index;
  960.    }
  961.            my $columns = $entry->[0]{children};
  962.         }
  963.         else {
  964.           foreach my $index (@{$entry->[0]{'indexes'}}) {
  965.     my $node = $SNMP::MIB{$index} || 
  966.               die "can't find info about index $index in table $tablenamen";
  967.             push @{$tables{$tablename}{'index'}}, $index;
  968.             if("@{$tables{$tablename}{'column'}}" =~ /$indexb/ ) {
  969. #              print "idx INT $indexn";
  970.               push @{$tables{$tablename}{'internalindex'}}, $index;
  971.             } else {
  972. #              print "idx EXT $indexn";
  973.               push @{$tables{$tablename}{'externalindex'}}, $index;
  974.             }
  975.           }
  976.         }
  977. foreach my $col (sort { $a->{'subID'} <=> $b->{'subID'} } @$columns) {
  978.             next if ( "@{$tables{$tablename}{'index'}}" =~ /$col->{'label'}b/ );
  979.             push @{$tables{$tablename}{'nonindex'}}, $col->{'label'};
  980. }
  981. #        print "indexes: @{$tables{$tablename}{'index'}}n";
  982. #        print "internal indexes: @{$tables{$tablename}{'internalindex'}}n";
  983. #        print "external indexes: @{$tables{$tablename}{'externalindex'}}n";
  984. #        print "non-indexes: @{$tables{$tablename}{'nonindex'}}n";
  985.     } else {
  986. my $children = $mib->{children};
  987. if ($#children == -1 && $mib->{type}) {
  988.     # scalar
  989.     if ($mib->{type} eq "NOTIF" ||
  990.         $mib->{type} eq "TRAP") {
  991.         my $notifyname = $mib->{label};
  992.                 my @varlist = ();
  993.         $notifications{$notifyname} = 1;
  994.                 $notifyvars{$notifyname} = $mib->{varbinds};
  995.     } else {
  996.         $scalars{$mib->{label}} = 1;
  997.     }
  998. } else {
  999.     my $i;
  1000.     for($i = 0; $i <= $#$children; $i++) {
  1001. setup_data($children->[$i]);
  1002.     }
  1003. }
  1004.     }
  1005. }
  1006. sub min {
  1007.     return $_[0] if ($_[0] < $_[1]);
  1008.     return $_[1];
  1009. }
  1010. sub max {
  1011.     return $_[0] if ($_[0] > $_[1]);
  1012.     return $_[1];
  1013. }
  1014. sub find_conf {
  1015.   my ($configfile, $missingok) = (@_);
  1016.   foreach my $d (@search_dirs, @def_search_dirs) {
  1017.       return "$d/$configfile" if (-f "$d/$configfile");
  1018.   }
  1019.   return $configfile if (-f "$configfile");
  1020.   return if ($missingok);
  1021.   print STDERR "Can't find a configuration file called $configfilen";
  1022.   print STDERR "(referenced at $currentfile:$currentline)n" if ($currentfile);
  1023.   print STDERR "I looked in:n";
  1024.   print "  " . join("n  ", @search_dirs, @def_search_dirs), "n";
  1025.   exit 1;
  1026. }
  1027. sub open_conf {
  1028.     my $configfile = shift;
  1029. # process .conf file
  1030.     if (! -f "$configfile") {
  1031. print STDERR "Can't find a configuration file called $configfilen";
  1032. exit 1;
  1033.     }
  1034.     $currentfile = $configfile;
  1035.     my $fh = new IO::File;
  1036.     $fh->open("$configfile");
  1037.     return $fh;
  1038. }
  1039. sub count_scalars {
  1040.     my @k = keys(%scalars);
  1041.     return $#k + 1;
  1042. }
  1043. sub count_tables {
  1044.     my @k = keys(%tables);
  1045.     return $#k + 1;
  1046. }
  1047. sub count_columns {
  1048.     my $table = shift;
  1049.     return $#{$tables{$table}{'column'}} + 1;
  1050. }
  1051. sub table_is_writable {
  1052.     my $table = shift;
  1053.     my $column;
  1054.     my $result = 0;
  1055.     foreach $column (@{$tables{$table}{'column'}}) {
  1056.       if($SNMP::MIB{$column}{access} =~ /(ReadWrite|Create|WriteOnly)/) {
  1057.         $result = 1;
  1058.         last;
  1059.       }
  1060.     }
  1061.     return $result;
  1062. }
  1063. sub table_has_create {
  1064.     my $table = shift;
  1065.     my $column;
  1066.     my $result = 0;
  1067.     foreach $column (@{$tables{$table}{'column'}}) {
  1068.       if($SNMP::MIB{$column}{access} =~ /(Create)/) {
  1069.         $result = 1;
  1070.         last;
  1071.       }
  1072.     }
  1073.     return $result;
  1074. }
  1075. sub table_has_rowstatus {
  1076.     my $table = shift;
  1077.     my $column;
  1078.     my $result = 0;
  1079.     foreach $column (@{$tables{$table}{'column'}}) {
  1080.       if($SNMP::MIB{$column}{syntax} =~ /(RowStatus)/) {
  1081.         $result = 1;
  1082.         last;
  1083.       }
  1084.     }
  1085.     return $result;
  1086. }
  1087. sub count_indexes {
  1088.     my $table = shift;
  1089.     return $#{$tables{$table}{'index'}} + 1;
  1090. }
  1091. sub count_external_indexes {
  1092.     my $table = shift;
  1093.     return $#{$tables{$table}{'externalindex'}} + 1;
  1094. }
  1095. sub count_notifications {
  1096.     my @k = keys(%notifications);
  1097.     return $#k + 1;
  1098. }
  1099. sub count_varbinds {
  1100.     my $notify = shift;
  1101.     return $#{$notifyvars{$notify}} + 1;
  1102. }