--- lib/brocadevdx.pm.in.orig	2016-09-10 02:02:33.289414464 +0200
+++ lib/brocadevdx.pm.in	2016-09-12 09:40:25.569917234 +0200
@@ -0,0 +1,411 @@
+package brocadevdx;
+##
+## $Id: foundry.pm.in 3424 2016-07-12 14:43:44Z heas $
+##
+## @PACKAGE@ @VERSION@
+@copyright@
+#
+#  RANCID - Really Awesome New Cisco confIg Differ
+#
+#  foundry.pm - Foundry rancid procedures
+
+use 5.010;
+use strict 'vars';
+use warnings;
+no warnings 'uninitialized';
+require(Exporter);
+our @ISA = qw(Exporter);
+
+use rancid @VERSION@;
+
+@ISA = qw(Exporter rancid main);
+#XXX @Exporter::EXPORT = qw($VERSION @commandtable %commands @commands);
+
+# load-time initialization
+sub import {
+    0;
+}
+
+# post-open(collection file) initialization
+sub init {
+    # add content lines and separators
+    ProcessHistory("","","","!RANCID-CONTENT-TYPE: $devtype\n!\n");
+
+    0;
+}
+
+# main loop of input of device output
+sub inloop {
+    my($INPUT, $OUTPUT) = @_;
+    my($cmd, $rval);
+
+TOP: while(<$INPUT>) {
+	tr/\015//d;
+	if (/^Error:/) {
+	    print STDOUT ("$host flogin error: $_");
+	    print STDERR ("$host flogin error: $_") if ($debug);
+	    $clean_run = 0;
+	    last;
+	}
+	while (/[>#]\s*($cmds_regexp)\s*$/) {
+	    $cmd = $1;
+	    # Some devices can give an error that looks a lot like a prompt
+	    # for deprecated commands like "write term".  Ignore that.
+	    if (/^invalid input -> /i) {
+		print STDERR ("Ignoring invalid command: $cmd\n") if ($debug);
+		last;
+	    }
+	    if (!defined($prompt)) {
+		$prompt = ($_ =~ /^([^#]+#)/)[0];
+		$prompt =~ s/([][}{)(\\])/\\$1/g;
+		print STDERR ("PROMPT MATCH: $prompt\n") if ($debug);
+	    }
+	    print STDERR ("HIT COMMAND:$_") if ($debug);
+	    if (! defined($commands{$cmd})) {
+		print STDERR "$host: found unexpected command - \"$cmd\"\n";
+		$clean_run = 0;
+		last TOP;
+	    }
+	    if (! defined(&{$commands{$cmd}})) {
+		printf(STDERR "$host: undefined function - \"%s\"\n",
+		       $commands{$cmd});
+		$clean_run = 0;
+		last TOP;
+	    }
+	    $rval = &{$commands{$cmd}}($INPUT, $OUTPUT, $cmd);
+	    delete($commands{$cmd});
+	    if ($rval == -1) {
+		$clean_run = 0;
+		last TOP;
+	    }
+	}
+        if (/\#exit$/) {
+            $clean_run = 1;
+            last;
+        }
+    }
+}
+
+# This routine parses "show version"
+sub ShowVersion {
+    my($INPUT, $OUTPUT) = @_;
+    my($slot);
+
+    print STDERR "    In ShowVersion: $_" if ($debug);
+
+    while (<$INPUT>) {
+	tr/\015//d;
+	next if /^\s*$/;
+	last if (/^$prompt/);
+
+	next if (/^(The system |Crash time)/);
+	next if (/^(System|(Active|Standby) Management|LP Slot \d+|Switch Fabric Module \d+) (uptime|Up Time) is/);
+	# remove uptime on newer switches
+	s/(STACKID \d+)\s+system uptime is.*$/$1/;
+
+	s/^\s*(HW|SW)/$1/;
+	s/^\s*(Compiled on)/SW: $1/;
+	s/^\s*(\(\d+ bytes\) from )/SW: $1/;
+
+	#s/^(HW.*)/$1\n/;
+	if (/^SL (\d+)/) {
+	    $slot = "Slot $1";
+	    s/^SL \d+/$slot/;
+	}
+	if (/MHz .* processor/) {
+	    $slot = "MGMT";
+	}
+	s/^(\s*\d+ )/$slot:$1/;
+	s/^===*//;
+
+	ProcessHistory("VERSION","","","!$_");
+    }
+    ProcessHistory("VERSION","","","!\n");
+    return(0);
+}
+
+# This routine parses "show chassis"
+sub ShowChassis {
+    my($INPUT, $OUTPUT) = @_;
+    my($skip) = 0;
+
+    print STDERR "    In ShowChassis: $_" if ($debug);
+
+    while (<$INPUT>) {
+	tr/\015//d;
+	last if (/^$prompt/);
+	next if (/ from /);
+	next if (/current temperature/i);
+	return(1) if (/^\s+\^$/);		# edgeiron invalid command
+
+	if (/^---/ || /^$/) { # next section reached
+	    $skip = 0;
+	}
+	if (/(POWERS|TEMPERATURE READINGS)/) {
+	    $skip = 1;
+	}
+	if (/fan controlled temperature:/i ||
+	    /fan speed switching temperature thresholds/i) {
+	    $skip = 1;
+	}
+	if (/THERMAL PLANE/) {
+	    $skip = 1;
+	}
+	if (/(pressure|altitude|temperature):/i) {
+	    $skip = 1;
+	}
+	s/(Fan \d+ \S+), speed .*/$1/;
+	if (/speed/i) {
+	    $skip = 1;
+	}
+	if (/(Time Alive|Time Awake|Total Power Usage \(Watts\)|Update|Power Usage \(Watts\)):/i) {
+            $skip = 1;
+        }
+	next if $skip;
+
+	ProcessHistory("CHASSIS","","","! $_");
+    }
+    ProcessHistory("CHASSIS","","","!\n");
+    return(0);
+}
+
+# This routine parses "show flash"
+sub ShowFlash {
+    my($INPUT, $OUTPUT) = @_;
+    print STDERR "    In ShowFlash: $_" if ($debug);
+
+    while (<$INPUT>) {
+	tr/\015//d;
+	last if (/^$prompt/);
+	next if (/^\s*$/);
+	return(1) if (/^\s+\^$/);		# edgeiron invalid command
+
+	if (/code flash free space = (\d+)/i) {
+	    my($tmp) = $1;
+	    if ($tmp >= (1024 * 1024 * 1024)) {
+		$tmp = int($tmp / (1024 * 1024 * 1024));
+		$_ = "code flash free space = $tmp GB\n";
+	    } elsif ($tmp >= (1024 * 1024)) {
+		$tmp = int($tmp / (1024 * 1024));
+		$_ = "code flash free space = $tmp MB\n";
+	    } elsif ($tmp >= (1024)) {
+		$tmp = int($tmp / 1024);
+		$_ = "code flash free space = $tmp KB\n";
+	    } elsif ($tmp > 0) {
+		$_ = "code flash free space = < 1KB\n";
+	    } else {
+		$_ = "code flash free space = 0 bytes\n";
+	    }
+	}
+	ProcessHistory("FLASH","","","!Flash: $_");
+    }
+    ProcessHistory("","","","!\n");
+    return;
+}
+
+# This routine parses "show media *"
+sub ShowMedia {
+    my($INPUT, $OUTPUT) = @_;
+    print STDERR "    In ShowMedia: $_" if ($debug);
+
+    while (<$INPUT>) {
+	tr/\015//d;
+	last if (/^$prompt/);
+	return(1) if (/Invalid input (->|detected)/);
+	return(1) if (/^\s+\^$/);		# edgeiron invalid command
+	next if (/^\s*$/);
+	next if (/:\s*$/);
+
+	ProcessHistory("MEDIA","","","!Media: $_");
+    }
+    ProcessHistory("","","","!\n");
+    return(0);
+}
+
+# This routine parses "show module"
+sub ShowModule {
+    my($INPUT, $OUTPUT) = @_;
+    print STDERR "    In ShowModule: $_" if ($debug);
+
+    while (<$INPUT>) {
+	tr/\015//d;
+	last if (/^$prompt/);
+	return(1) if (/Invalid input (->|detected)/);
+	return(1) if (/^\s+\^$/);		# edgeiron invalid command
+	next if (/^\s*$/);
+	next if (/:\s*$/);
+
+	ProcessHistory("MODULE","","","!Module: $_");
+    }
+    ProcessHistory("","","","!\n");
+    return(0);
+}
+
+# This routine parses "show running-config"
+sub ShowConfiguration {
+    my($INPUT, $OUTPUT, $cmd) = @_;
+    my($lines) = 0;
+    my($snmp) = 0;
+    print STDERR "    In ShowConfiguration: $_" if ($debug);
+
+    s/^[a-z]+@//;
+    ProcessHistory("","","","# $_");
+    while (<$INPUT>) {
+        tr/\015//d;
+        next if (/^\s*$/);
+        # end of config - hopefully.  brocadevdx does not have a reliable
+        # end-of-config tag.  appears to end with "\nPROMPT>", but not sure.
+        if (/^$prompt/) {
+            $found_end++;
+            last;
+        }
+        next if (/^system (shutdown message from|going down )/i);
+        next if (/^\{(master|backup)(:\d+)?\}/);
+        next if (/^\{(primary|secondary)(:\d+)?\}/);
+        $lines++;
+
+	ProcessHistory("","","","$_");
+    }
+    if ($lines < 3) {
+        printf(STDERR "ERROR: $host configuration appears truncated.\n");
+        $found_end = 0;
+        return(-1);
+    }
+
+    return(0);
+}
+# This routine processes a "write term"
+sub WriteTerm {
+    my($INPUT, $OUTPUT) = @_;
+    print STDERR "    In WriteTerm: $_" if ($debug);
+
+    while (<$INPUT>) {
+	tr/\015//d;
+	return(1) if (/Invalid input (->|detected)/);
+	return(1) if (/^\s+\^$/);		# edgeiron invalid command
+	return(0) if ($found_end);		# Only do this routine once
+	last if (/^$prompt/);
+
+	/current configuration\s*:/i && next;
+	/building configuration\.+\s*/i && next;
+	/building running-config, please wait/i && next;	# edgeiron
+	/^$/ && next;						# blank lines
+	/^ver \d+\.\d+/ && next;
+	/^module \d+ / && next;
+
+	/^ntp clock-period /    && next; # kill ntp clock-period
+	/^ length /		&& next; # kill length on serial lines
+	/^ width /		&& next; # kill width on serial lines
+	# filter out any RCS/CVS tags to avoid confusing local CVS storage
+	s/\$(Revision|Id):/ $1:/;
+	# sort secure-mac-addresses.  Note: There is no way to determine which
+	# have been added dynamically vs statically.  Thus, sort them?
+	/secure-mac-address (\S+)/ &&
+	    ProcessHistory("SECMAC","keysort","$1","$_") && next;
+	# OR filter them? XXX
+	#next if (/secure-mac-address/);
+
+	# order access-lists
+	/^access-list\s+(\d+)\s+(perm|deny)\s+(\d\S+)(\/\d+)\s*$/ &&
+	    ProcessHistory("PACL $1 $2","$aclsort","$3","$_")
+	    && next;
+	/^access-list\s+(\d\d?)\s+(\S+)\s+(\S+)/ &&
+	    ProcessHistory("ACL $1 $2","$aclsort","$3","$_") && next;
+	# order extended access-lists
+	/^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+host\s+(\S+)/ &&
+	    ProcessHistory("EACL $1 $2","$aclsort","$3","$_") && next;
+	/^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+(\d\S+)/ &&
+	    ProcessHistory("EACL $1 $2","$aclsort","$3","$_") && next;
+	/^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+any/ &&
+	    ProcessHistory("EACL $1 $2","$aclsort","0.0.0.0","$_") && next;
+	# order arp lists
+	/^arp\s+(\d+\.\d+\.\d+\.\d+)\s+/ &&
+	    ProcessHistory("ARP","$aclsort","$1","$_") && next;
+	# order logging statements
+	/^logging (\d+\.\d+\.\d+\.\d+)/ &&
+	    ProcessHistory("LOGGING","ipsort","$1","$_") && next;
+	# order/prune snmp-server host/community statements
+	if (/^(snmp-server host )(\d+\.\d+\.\d+\.\d+)/) {
+	    if ($filter_commstr) {
+		ProcessHistory("SNMPSERVERHOST","ipsort","$2","!$1 $2 <removed>\n") && next;
+	    } else {
+		ProcessHistory("SNMPSERVERHOST","ipsort","$2","$_") && next;
+	    }
+	}
+	if (/^(snmp-server community )(\S+)/) {
+	    if ($filter_commstr) {
+		ProcessHistory("SNMPSERVERCOMM","keysort","$_","!$1<removed>$'") && next;
+	    } else {
+		ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next;
+	    }
+	}
+	# order tacacs server statements
+	if (/^(tacacs-server key )/ && $filter_pwds >= 1) {
+	    ProcessHistory("","","","! $1<removed>\n");
+	    next;
+	}
+	# delete ntp auth password
+	if (/^(ntp authentication-key \d+ md5) / && $filter_pwds >= 2) {
+	    ProcessHistory("","","","!$1 <removed>\n");
+	    next;
+	}
+	# order ntp peers/servers
+	if (/^ntp (server|peer) (\d+)\.(\d+)\.(\d+)\.(\d+)/) {
+	    my($sortkey) = sprintf("$1 %03d%03d%03d%03d",$2,$3,$4,$5);
+	    ProcessHistory("NTP","keysort",$sortkey,"$_");
+	    next;
+	}
+	# order ip host line statements
+	/^ip host line(\d+)/ &&
+	    ProcessHistory("IPHOST","numsort","$1","$_") && next;
+	# order ip nat source static statements
+	/^ip nat (\S+) source static (\S+)/ &&
+	    ProcessHistory("IP NAT $1","ipsort","$2","$_") && next;
+
+	# filter ssh public key
+	if (/^(crypto key generate (rsa|dsa) public_key)/ &&
+		$filter_pwds >= 2) {
+	    ProcessHistory("","","","!$1 <removed>\n");
+	    next;
+	}
+	# filter ssh private key
+	if (/^(crypto key generate (rsa|dsa) private_key)/ &&
+		$filter_pwds >= 1) {
+	    ProcessHistory("","","","!$1 <removed>\n");
+	    next;
+	}
+	# filter ssl secret
+	if (/^(crypto-ssl certificate generate secret_data)/ &&
+	    $filter_pwds >= 1) {
+	    ProcessHistory("","","","!$1 <removed>\n");
+	    next;
+	}
+
+	# reorder listing of ports in a vlan
+	if (/^ (?:un)?tagged ethe/) {
+	    chomp;
+	    s/^\s+//;
+	    s/\s+$//;
+
+	    my @list = split /\s+ethe\s+/, $_;
+	    my $tagtype = shift @list;
+
+	    while (@list) {
+		ProcessHistory("","","",
+				" $tagtype ethe " . (shift @list) . "\n");
+	    }
+	    next;
+	}
+
+
+	ProcessHistory("","","","$_");
+	# end of config
+	if (/^end$/) {
+	    $found_end = 1;
+	    return(1);
+	}
+    }
+    return(0);
+}
+
+1;
