File merge-pciids.pl of Package pciutils-ids.1090
#!/usr/bin/perl -w
# Merge several PCI ID lists to a single one. This script tries to be as agnostic
# of the details of the ID list as possible, so it should not break with future
# changes of the ID list format as long as they follow the same block structure.
# Greetings to Kurt Garloff who needed 300+ lines of code to give a wrong
# solution of the same problem.
#
# Options:
# -v: Verbose mode. Warn if multiple files provide different definitions for
# the same device.
#
# (c) 2007 Martin Mares <mj@ucw.cz>, GPLv2
# (c) 2013 Jean Delvare <jdelvare@suse.de>
use strict;
use Getopt::Std;
our $opt_v;
getopts('v');
my %ids = ();
my %comments = ();
foreach our $file (@ARGV) {
my $fn = ($file =~ /\.gz$/) ? "zcat $file |" : ($file =~ /\.bz2$/) ? "bzcat $file |" : $file;
open F, $fn or die "Unable to open $file: $!";
my @id = ();
my $comm = "";
my $class = 0;
sub err($) {
print STDERR "Error in $file, line $.: @_\n";
exit 1;
}
while (<F>) {
if (/^(#.*|\s*$)/) {
$comm .= $_;
next;
}
chomp;
if (/^(\t|C\s+|)([0-9a-fA-F]+)\s+(.*)$/ ||
(!$class && /^(\t\t)([0-9a-fA-F]+\s+[0-9a-fA-F]+)\s+(.*)$/) ||
($class && /^(\t\t)([0-9a-fA-F]+)\s+(.*)$/)) {
my $indent = $1;
my $id = lc($2);
my $name = $3;
if ($indent =~ /^C\s+$/) {
$indent = "";
$id = "C $id";
}
my $depth = length $indent;
$depth <= @id or err "Mismatched indentation";
@id = (@id[0..$depth-1], $id);
$class = ($id =~ /^C\s/) if !$depth; # Remember if we are in a vendor or a class section
my $i = join(":", @id);
my $j = $class ? "~$i" : $i; # We want to sort special entries last
if ($opt_v && exists $ids{$j} && $ids{$j} ne $name) {
print STDERR "Warning: ID $i has two different definitions, using the one from $file\n";
}
$ids{$j} = $name;
$comments{$j} = $comm if $comm;
} else {
err "Parse error";
}
$comm = "";
}
close F;
}
print "# This file has been merged automatically from the following files:\n#\t", join("\n#\t", @ARGV), "\n\n";
foreach my $id (sort keys %ids) {
my ($i, $j) = ($id, $id);
$i =~ s/[^:]//g;
$i =~ tr/:/\t/;
$j =~ s/.*://g;
$j =~ s/^~//;
print $comments{$id} if $comments{$id};
print "$i$j $ids{$id}\n";
}