xref: /onnv-gate/usr/src/tools/scripts/interface_cmp.pl (revision 12478:a267bf553e0e)
110355SAli.Bahrami@Sun.COM#!/usr/bin/perl -w
210355SAli.Bahrami@Sun.COM#
310355SAli.Bahrami@Sun.COM# CDDL HEADER START
410355SAli.Bahrami@Sun.COM#
510355SAli.Bahrami@Sun.COM# The contents of this file are subject to the terms of the
610355SAli.Bahrami@Sun.COM# Common Development and Distribution License (the "License").
710355SAli.Bahrami@Sun.COM# You may not use this file except in compliance with the License.
810355SAli.Bahrami@Sun.COM#
910355SAli.Bahrami@Sun.COM# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1010355SAli.Bahrami@Sun.COM# or http://www.opensolaris.org/os/licensing.
1110355SAli.Bahrami@Sun.COM# See the License for the specific language governing permissions
1210355SAli.Bahrami@Sun.COM# and limitations under the License.
1310355SAli.Bahrami@Sun.COM#
1410355SAli.Bahrami@Sun.COM# When distributing Covered Code, include this CDDL HEADER in each
1510355SAli.Bahrami@Sun.COM# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1610355SAli.Bahrami@Sun.COM# If applicable, add the following below this CDDL HEADER, with the
1710355SAli.Bahrami@Sun.COM# fields enclosed by brackets "[]" replaced with your own identifying
1810355SAli.Bahrami@Sun.COM# information: Portions Copyright [yyyy] [name of copyright owner]
1910355SAli.Bahrami@Sun.COM#
2010355SAli.Bahrami@Sun.COM# CDDL HEADER END
2110355SAli.Bahrami@Sun.COM#
2210355SAli.Bahrami@Sun.COM
2310355SAli.Bahrami@Sun.COM#
24*12478SAli.Bahrami@Oracle.COM# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2510355SAli.Bahrami@Sun.COM#
2610355SAli.Bahrami@Sun.COM
2710355SAli.Bahrami@Sun.COM#
2810355SAli.Bahrami@Sun.COM# interface_cmp audits two interface definition files (as created by
2910355SAli.Bahrami@Sun.COM# interface_check) against one another, and confirms that:
3010355SAli.Bahrami@Sun.COM#
3110355SAli.Bahrami@Sun.COM#  o	All versioned libraries that were present in the previous interface
3210355SAli.Bahrami@Sun.COM#	are present in the new interface
3310355SAli.Bahrami@Sun.COM#
3410355SAli.Bahrami@Sun.COM#  o	for each non-private interface in a library confirm that no symbols
3510355SAli.Bahrami@Sun.COM#	have been removed and that no symbols have been added to it between
3610355SAli.Bahrami@Sun.COM#	the two revisions
3710355SAli.Bahrami@Sun.COM#
3810355SAli.Bahrami@Sun.COM# Return codes:
3910355SAli.Bahrami@Sun.COM#
4010355SAli.Bahrami@Sun.COM#  0	All interfaces in the new release are identical in old release.
4110355SAli.Bahrami@Sun.COM#  1	Something is different refer to the error messages.
4210355SAli.Bahrami@Sun.COM
4310355SAli.Bahrami@Sun.COM
4410355SAli.Bahrami@Sun.COMuse strict;
4510355SAli.Bahrami@Sun.COM
4610355SAli.Bahrami@Sun.COMuse POSIX qw(getenv);
4710355SAli.Bahrami@Sun.COMuse Getopt::Std;
4810355SAli.Bahrami@Sun.COMuse File::Basename;
4910355SAli.Bahrami@Sun.COM
5010355SAli.Bahrami@Sun.COM#### Define all global variables (required for strict)
5110355SAli.Bahrami@Sun.COMuse vars  qw($Prog);
5210355SAli.Bahrami@Sun.COMuse vars  qw(%opt);
5310355SAli.Bahrami@Sun.COMuse vars  qw(%old_hash %old_alias %new_hash %new_alias);
5410355SAli.Bahrami@Sun.COM
5510355SAli.Bahrami@Sun.COM# Exception Arrays:
5610355SAli.Bahrami@Sun.COM#
5710355SAli.Bahrami@Sun.COM# The ADDSYM and DELSYM exceptions are maintained on the @AddSymList
5810355SAli.Bahrami@Sun.COM# and @DelSymList arrays, respectively. Each array element is a reference
5910355SAli.Bahrami@Sun.COM# to a subarray of triples:
6010355SAli.Bahrami@Sun.COM#	(sym_re, ver_re, obj_re)
6110355SAli.Bahrami@Sun.COM# where each item in the tripple is a regular expression, used to
6210355SAli.Bahrami@Sun.COM# match a particular symbol/version/object combination.
6310355SAli.Bahrami@Sun.COM#
6410355SAli.Bahrami@Sun.COM# The EMPTY_TOPVERSION exceptions are maintained on the @EmptyTopVerList
6510355SAli.Bahrami@Sun.COM# array. Each array element is a reference to a subarray of pairs:
6610355SAli.Bahrami@Sun.COM#	(ver_re, obj_re)
6710355SAli.Bahrami@Sun.COM# where each item in the pair is a regular expression, used to
6810355SAli.Bahrami@Sun.COM# match a particular version/object combination.
6910355SAli.Bahrami@Sun.COM#
7010355SAli.Bahrami@Sun.COMuse vars  qw(@AddSymList @DelSymList @EmptyTopVerList);
7110355SAli.Bahrami@Sun.COM
7210355SAli.Bahrami@Sun.COM
7310355SAli.Bahrami@Sun.COM## LoadExceptions
7410355SAli.Bahrami@Sun.COM#
7510355SAli.Bahrami@Sun.COM# Locate the exceptions file and process its contents. We can't use
7610355SAli.Bahrami@Sun.COM# onbld_elfmod::LoadExceptionsToEXRE() for this, because our exceptions
7710355SAli.Bahrami@Sun.COM# need to support more than a single regular expression.
7810355SAli.Bahrami@Sun.COM#
7910355SAli.Bahrami@Sun.COM# exit:
8010355SAli.Bahrami@Sun.COM#	@AddSymList, @DelSymList, and @EmptyTopVerList have been updated
8110355SAli.Bahrami@Sun.COM#
8210355SAli.Bahrami@Sun.COM# note:
8310355SAli.Bahrami@Sun.COM#	We expand strings of the form MACH(dir) to match the given
8410355SAli.Bahrami@Sun.COM#	directory as well as any 64-bit architecture subdirectory that
8510355SAli.Bahrami@Sun.COM#	might be present (i.e. amd64, sparcv9).
8610355SAli.Bahrami@Sun.COM#
8710355SAli.Bahrami@Sun.COMsub LoadExceptions {
8810355SAli.Bahrami@Sun.COM	my $file;
8910355SAli.Bahrami@Sun.COM	my $Line;
9010355SAli.Bahrami@Sun.COM	my $LineNum = 0;
9110355SAli.Bahrami@Sun.COM	my $err = 0;
9210355SAli.Bahrami@Sun.COM
9310355SAli.Bahrami@Sun.COM	# Locate the exception file
9410355SAli.Bahrami@Sun.COM	FILE: {
9510355SAli.Bahrami@Sun.COM		# If -e is specified, that file must be used
9610355SAli.Bahrami@Sun.COM		if ($opt{e}) {
9710355SAli.Bahrami@Sun.COM			$file = $opt{e};
9810355SAli.Bahrami@Sun.COM			last FILE;
9910355SAli.Bahrami@Sun.COM		}
10010355SAli.Bahrami@Sun.COM
10110355SAli.Bahrami@Sun.COM		# If this is an activated workspace, use the exception
10210355SAli.Bahrami@Sun.COM		# file found in the exceptions_list directory.
10310355SAli.Bahrami@Sun.COM		if (defined($ENV{CODEMGR_WS})) {
10410355SAli.Bahrami@Sun.COM			$file = "$ENV{CODEMGR_WS}/exception_lists/interface_cmp";
10510355SAli.Bahrami@Sun.COM			last FILE if (-f $file);
10610355SAli.Bahrami@Sun.COM		}
10710355SAli.Bahrami@Sun.COM
10810355SAli.Bahrami@Sun.COM		# As a final backstop, the SUNWonbld package provides a
10910355SAli.Bahrami@Sun.COM		# copy of the exception file. This can be useful if we
11010355SAli.Bahrami@Sun.COM		# are being used with an older workspace.
11110355SAli.Bahrami@Sun.COM		#
11210355SAli.Bahrami@Sun.COM		# This script is installed in the SUNWonbld bin directory,
11310355SAli.Bahrami@Sun.COM		# while the exception file is in etc/exception_lists. Find
11410355SAli.Bahrami@Sun.COM		# it relative to the script location given by $0.
11510355SAli.Bahrami@Sun.COM		$file = dirname($0) . "/../etc/exception_lists/interface_cmp";
11610355SAli.Bahrami@Sun.COM		last FILE if (-f $file);
11710355SAli.Bahrami@Sun.COM
11810355SAli.Bahrami@Sun.COM		# No exception file was found.
11910355SAli.Bahrami@Sun.COM		return;
12010355SAli.Bahrami@Sun.COM	}
12110355SAli.Bahrami@Sun.COM
12210355SAli.Bahrami@Sun.COM	open (EFILE, $file) ||
12310355SAli.Bahrami@Sun.COM		die "$Prog: unable to open exceptions file: $file";
12410355SAli.Bahrami@Sun.COM	while ($Line = onbld_elfmod::GetLine(\*EFILE, \$LineNum)) {
12510355SAli.Bahrami@Sun.COM
12610355SAli.Bahrami@Sun.COM		# Expand MACH()
12710355SAli.Bahrami@Sun.COM		$Line =~ s/MACH\(([^)]+)\)/$1(\/amd64|\/sparcv9)?/g;
12810355SAli.Bahrami@Sun.COM
12910355SAli.Bahrami@Sun.COM		if ($Line =~ /^DELSYM\s+/) {
13010355SAli.Bahrami@Sun.COM		    my ($item, $sym_re, $ver_re, $obj_re) =
13110355SAli.Bahrami@Sun.COM			split(/\s+/, $Line, 4);
13210355SAli.Bahrami@Sun.COM		    push @DelSymList, [ $sym_re, $ver_re, $obj_re ];
13310355SAli.Bahrami@Sun.COM		    next;
13410355SAli.Bahrami@Sun.COM		}
13510355SAli.Bahrami@Sun.COM
13610355SAli.Bahrami@Sun.COM		if ($Line =~ /^ADDSYM\s+/) {
13710355SAli.Bahrami@Sun.COM		    my ($item, $sym_re, $ver_re, $obj_re) =
13810355SAli.Bahrami@Sun.COM			split(/\s+/, $Line, 4);
13910355SAli.Bahrami@Sun.COM		    push @AddSymList, [ $sym_re, $ver_re, $obj_re ];
14010355SAli.Bahrami@Sun.COM		    next;
14110355SAli.Bahrami@Sun.COM		}
14210355SAli.Bahrami@Sun.COM
14310355SAli.Bahrami@Sun.COM		if ($Line =~ /^EMPTY_TOPVERSION\s+/) {
14410355SAli.Bahrami@Sun.COM		    my ($item, $ver_re, $obj_re) = split(/\s+/, $Line, 3);
14510355SAli.Bahrami@Sun.COM		    push @EmptyTopVerList, [ $ver_re, $obj_re ];
14610355SAli.Bahrami@Sun.COM		    next;
14710355SAli.Bahrami@Sun.COM		}
14810355SAli.Bahrami@Sun.COM
14910355SAli.Bahrami@Sun.COM		$err++;
15010355SAli.Bahrami@Sun.COM		printf(STDERR "$file: Unrecognized option: ".
15110355SAli.Bahrami@Sun.COM		    "line $LineNum: $Line\n");
15210355SAli.Bahrami@Sun.COM	}
15310355SAli.Bahrami@Sun.COM	close EFILE;
15410355SAli.Bahrami@Sun.COM
15510355SAli.Bahrami@Sun.COM	exit 1 if ($err != 0);
15610355SAli.Bahrami@Sun.COM}
15710355SAli.Bahrami@Sun.COM
15810355SAli.Bahrami@Sun.COM## ExSym(SymList, sym, ver, obj)
15910355SAli.Bahrami@Sun.COM#
16010355SAli.Bahrami@Sun.COM# Compare a given symbol/version/object combination against the
16110355SAli.Bahrami@Sun.COM# exceptions found in the given list.
16210355SAli.Bahrami@Sun.COM#
16310355SAli.Bahrami@Sun.COM# entry:
16410355SAli.Bahrami@Sun.COM#	SymList - Reference to @AddSymList, or @DelSymList.
16510355SAli.Bahrami@Sun.COM#	sym, ver, obj - Combination to be compared against exception list
16610355SAli.Bahrami@Sun.COM#
16710355SAli.Bahrami@Sun.COM# exit:
16810355SAli.Bahrami@Sun.COM#	Returns True (1) if there is a match, and False (0) otherwise.
16910355SAli.Bahrami@Sun.COM#
17010355SAli.Bahrami@Sun.COMsub ExSym {
17110355SAli.Bahrami@Sun.COM	my ($SymList, $sym, $ver, $obj) = @_;
17210355SAli.Bahrami@Sun.COM
17310355SAli.Bahrami@Sun.COM	foreach my $ex (@$SymList) {
17410355SAli.Bahrami@Sun.COM		return 1 if ($obj =~ /$$ex[2]/) && ($ver =~ /$$ex[1]/) &&
17510355SAli.Bahrami@Sun.COM		    ($sym =~ /$$ex[0]/);
17610355SAli.Bahrami@Sun.COM	}
17710355SAli.Bahrami@Sun.COM
17810355SAli.Bahrami@Sun.COM	return 0;
17910355SAli.Bahrami@Sun.COM}
18010355SAli.Bahrami@Sun.COM
18110355SAli.Bahrami@Sun.COM## ExTopVer(ver, obj)
18210355SAli.Bahrami@Sun.COM#
18310355SAli.Bahrami@Sun.COM# Compare a given version/object combination against the pairs found
18410355SAli.Bahrami@Sun.COM# in @EmptyTopVerList.
18510355SAli.Bahrami@Sun.COM#
18610355SAli.Bahrami@Sun.COM# entry:
18710355SAli.Bahrami@Sun.COM#	ver, obj - Combination to be compared against empty top version list
18810355SAli.Bahrami@Sun.COM#
18910355SAli.Bahrami@Sun.COM# exit:
19010355SAli.Bahrami@Sun.COM#	Returns True (1) if there is a match, and False (0) otherwise.
19110355SAli.Bahrami@Sun.COM#
19210355SAli.Bahrami@Sun.COMsub ExTopVer {
19310355SAli.Bahrami@Sun.COM	my ($ver, $obj) = @_;
19410355SAli.Bahrami@Sun.COM
19510355SAli.Bahrami@Sun.COM	foreach my $ex (@EmptyTopVerList) {
19610355SAli.Bahrami@Sun.COM		return 1 if ($obj =~ /$$ex[1]/) && ($ver =~ /$$ex[0]/);
19710355SAli.Bahrami@Sun.COM	}
19810355SAli.Bahrami@Sun.COM
19910355SAli.Bahrami@Sun.COM	return 0;
20010355SAli.Bahrami@Sun.COM}
20110355SAli.Bahrami@Sun.COM
20210355SAli.Bahrami@Sun.COM## ExpandInheritance(objhashref)
20310355SAli.Bahrami@Sun.COM#
20410355SAli.Bahrami@Sun.COM# For each version contained in the specified object hash reference,
20510355SAli.Bahrami@Sun.COM# add the inherited symbols.
20610355SAli.Bahrami@Sun.COM#
20710355SAli.Bahrami@Sun.COMsub ExpandInheritance {
20810355SAli.Bahrami@Sun.COM	my $obj = $_[0];
20910355SAli.Bahrami@Sun.COM
21010355SAli.Bahrami@Sun.COM	# Versions to process. Typically, inheriting versions come before
21110355SAli.Bahrami@Sun.COM	# the versions they inherit. Processing the list in reverse order
21210355SAli.Bahrami@Sun.COM	# maximizes the odds that a needed sub-version will have already
21310355SAli.Bahrami@Sun.COM	# have been processed.
21410355SAli.Bahrami@Sun.COM	my @vers = reverse(@{$obj->{'VERSION_NAMES'}});
21510355SAli.Bahrami@Sun.COM
21610355SAli.Bahrami@Sun.COM	# Versions to process in the next pass
21710355SAli.Bahrami@Sun.COM	my @next_vers = ();
21810355SAli.Bahrami@Sun.COM
21910355SAli.Bahrami@Sun.COM	# Hash, indexed by version name, that reflects whether the version
22010355SAli.Bahrami@Sun.COM	# has been expanded yet or not.
22110355SAli.Bahrami@Sun.COM	my %done = ();
22210355SAli.Bahrami@Sun.COM
22310355SAli.Bahrami@Sun.COM	while (scalar(@vers) > 0) {
22410355SAli.Bahrami@Sun.COM		foreach my $name (@vers) {
22510355SAli.Bahrami@Sun.COM			my $i;
22610355SAli.Bahrami@Sun.COM			my $defer = 0;
22710355SAli.Bahrami@Sun.COM			my $cur_version = $obj->{'VERSION_INFO'}{$name};
22810355SAli.Bahrami@Sun.COM			my ($top, $direct, $total, $symhash, $inheritarr) =
22910355SAli.Bahrami@Sun.COM			    @{$cur_version};
23010355SAli.Bahrami@Sun.COM
23110355SAli.Bahrami@Sun.COM			# In order to expand this version, all the inherited
23210355SAli.Bahrami@Sun.COM			# versions must already have been done. If not, put
23310355SAli.Bahrami@Sun.COM			# this version on @next_vers for the next pass.
23410355SAli.Bahrami@Sun.COM			my $num = scalar(@$inheritarr);
23510355SAli.Bahrami@Sun.COM			for ($i = 0; $i < $num; $i++) {
23610355SAli.Bahrami@Sun.COM			    if (!$done{$inheritarr->[$i]}) {
23710355SAli.Bahrami@Sun.COM				$defer = 1;
23810355SAli.Bahrami@Sun.COM				push @next_vers, $name;
23910355SAli.Bahrami@Sun.COM				last;
24010355SAli.Bahrami@Sun.COM			    }
24110355SAli.Bahrami@Sun.COM			}
24210355SAli.Bahrami@Sun.COM			next if ($defer);
24310355SAli.Bahrami@Sun.COM
24410355SAli.Bahrami@Sun.COM			# Add all the symbols from the inherited versions
24510355SAli.Bahrami@Sun.COM			# to this one.
24610355SAli.Bahrami@Sun.COM			for ($i = 0; $i < $num; $i++) {
24710355SAli.Bahrami@Sun.COM				my $i_version =
24810355SAli.Bahrami@Sun.COM				    $obj->{'VERSION_INFO'}{$inheritarr->[$i]};
24910355SAli.Bahrami@Sun.COM				my $i_symhash = $i_version->[3];
25010355SAli.Bahrami@Sun.COM
25110355SAli.Bahrami@Sun.COM				foreach my $sym (keys %$i_symhash) {
25210355SAli.Bahrami@Sun.COM				    if (!defined($cur_version->[3]{$sym})) {
25310355SAli.Bahrami@Sun.COM					    $cur_version->[2]++;
25410355SAli.Bahrami@Sun.COM					    $cur_version->[3]{$sym} = 'INHERIT';
25510355SAli.Bahrami@Sun.COM				    }
25610355SAli.Bahrami@Sun.COM				}
25710355SAli.Bahrami@Sun.COM			}
25810355SAli.Bahrami@Sun.COM
25910355SAli.Bahrami@Sun.COM			$done{$name} = 1;
26010355SAli.Bahrami@Sun.COM		}
26110355SAli.Bahrami@Sun.COM
26210355SAli.Bahrami@Sun.COM		@vers = @next_vers;
26310355SAli.Bahrami@Sun.COM		@next_vers = ();
26410355SAli.Bahrami@Sun.COM	}
26510355SAli.Bahrami@Sun.COM}
26610355SAli.Bahrami@Sun.COM
26710355SAli.Bahrami@Sun.COM## ReadInterface(file, alias)
26810355SAli.Bahrami@Sun.COM#
26910355SAli.Bahrami@Sun.COM# Read the interface description file, as produced by interface_check, and
27010355SAli.Bahrami@Sun.COM# return a hash describing it.
27110355SAli.Bahrami@Sun.COM#
27210355SAli.Bahrami@Sun.COM# entry:
27310355SAli.Bahrami@Sun.COM#	file - Interface file to read.
27410355SAli.Bahrami@Sun.COM#	alias - Refence to hash to be filled in with any aliases
27510355SAli.Bahrami@Sun.COM#		that are seen in the file. The alias name is the key,
27610355SAli.Bahrami@Sun.COM#		and the object is the value.
27710355SAli.Bahrami@Sun.COM#
27810355SAli.Bahrami@Sun.COM# exit:
27910355SAli.Bahrami@Sun.COM#	The hash referenced by alias has been updated.
28010355SAli.Bahrami@Sun.COM#
28110355SAli.Bahrami@Sun.COM#	The return value is a hash that encapsulates the interface
28210355SAli.Bahrami@Sun.COM#	information. This hash returned uses the object names as the
28310355SAli.Bahrami@Sun.COM#	key. Each key references a sub-hash that contains information
28410355SAli.Bahrami@Sun.COM#	for that object:
28510355SAli.Bahrami@Sun.COM#
28610355SAli.Bahrami@Sun.COM#	CLASS		-> ELFCLASS
28710355SAli.Bahrami@Sun.COM#	TYPE		-> ELF type
28810355SAli.Bahrami@Sun.COM#	VERSION_NAMES	-> Reference to array [1..n] of version names, in the
28910355SAli.Bahrami@Sun.COM#			   order they come from the input file.
29010355SAli.Bahrami@Sun.COM#	VERSION_INFO	-> Reference to hash indexed by version name, yielding
29110355SAli.Bahrami@Sun.COM#			   a reference to an array containing information about
29210355SAli.Bahrami@Sun.COM#			   that version.
29310355SAli.Bahrami@Sun.COM#
29410355SAli.Bahrami@Sun.COM#	The arrays referenced via VERSION_INFO are of the form:
29510355SAli.Bahrami@Sun.COM#
29610355SAli.Bahrami@Sun.COM#		(top, new, total, symhashref, inheritarrref)
29710355SAli.Bahrami@Sun.COM#
29810355SAli.Bahrami@Sun.COM#	where:
29910355SAli.Bahrami@Sun.COM#		top - 1 if version is a TOP_VERSION, 0 for a regular VERSION
30010355SAli.Bahrami@Sun.COM#		new - Number of symbols defined explicitly by version
30110355SAli.Bahrami@Sun.COM#		total - Number of symbols included in version, both new,
30210355SAli.Bahrami@Sun.COM#			and via inheritance.
30310355SAli.Bahrami@Sun.COM#		symhashref - Reference to hash indexed by symbol names, and
30410355SAli.Bahrami@Sun.COM#			yielding true (1).
30510355SAli.Bahrami@Sun.COM#		inheritarrref - Reference to array of names of versions
30610355SAli.Bahrami@Sun.COM#			inherited by this one.
30710355SAli.Bahrami@Sun.COM#
30810355SAli.Bahrami@Sun.COMsub ReadInterface {
30910355SAli.Bahrami@Sun.COM	my ($file, $alias) = @_;
31010355SAli.Bahrami@Sun.COM	my %main_hash = ();
31110355SAli.Bahrami@Sun.COM	my $Line;
31210355SAli.Bahrami@Sun.COM	my $LineNum = 0;
31310355SAli.Bahrami@Sun.COM	my $obj_name;
31410355SAli.Bahrami@Sun.COM	my $obj_hash;
31510355SAli.Bahrami@Sun.COM	my $sym_ok = 0;
31610355SAli.Bahrami@Sun.COM	my $cur_version;
31710355SAli.Bahrami@Sun.COM
31810355SAli.Bahrami@Sun.COM	open(FILE, $file) || die "$Prog: Unable to open: $file";
31910355SAli.Bahrami@Sun.COM
32010355SAli.Bahrami@Sun.COM	# Until we see an OBJECT line, nothing else is valid. To
32110355SAli.Bahrami@Sun.COM	# simplify the error handling, use a simple initial loop to
32210355SAli.Bahrami@Sun.COM	# read the file up to that point
32310355SAli.Bahrami@Sun.COM	while ($Line = onbld_elfmod::GetLine(\*FILE, \$LineNum)) {
32410355SAli.Bahrami@Sun.COM		if ($Line =~ s/^OBJECT\s+//i) {
32510355SAli.Bahrami@Sun.COM		    $obj_name = $Line;
32610355SAli.Bahrami@Sun.COM		    $main_hash{$obj_name} = {};
32710355SAli.Bahrami@Sun.COM		    $obj_hash = $main_hash{$obj_name};
32810355SAli.Bahrami@Sun.COM		    last;
32910355SAli.Bahrami@Sun.COM		}
33010355SAli.Bahrami@Sun.COM		die "$file: OBJECT expected on line $LineNum: $Line\n";
33110355SAli.Bahrami@Sun.COM	}
33210355SAli.Bahrami@Sun.COM
33310355SAli.Bahrami@Sun.COM	# Read the remainder of the file
33410355SAli.Bahrami@Sun.COM	while ($Line = onbld_elfmod::GetLine(\*FILE, \$LineNum)) {
33510355SAli.Bahrami@Sun.COM		# Items are parsed in order of decreasing frequency
33610355SAli.Bahrami@Sun.COM
33710355SAli.Bahrami@Sun.COM		if ($Line =~
33810355SAli.Bahrami@Sun.COM		    /^SYMBOL\s+([^\s]+)$/i) {
33910355SAli.Bahrami@Sun.COM			my $sym = $1;
34010355SAli.Bahrami@Sun.COM
34110355SAli.Bahrami@Sun.COM			die "$file: SYMBOL not expected on line $LineNum: $Line\n"
34210355SAli.Bahrami@Sun.COM			    if !$sym_ok;
34310355SAli.Bahrami@Sun.COM
34410355SAli.Bahrami@Sun.COM			$cur_version->[1]++;
34510355SAli.Bahrami@Sun.COM			$cur_version->[2]++;
34610355SAli.Bahrami@Sun.COM			$cur_version->[3]{$sym} = 'NEW';
34710355SAli.Bahrami@Sun.COM			next;
34810355SAli.Bahrami@Sun.COM		}
34910355SAli.Bahrami@Sun.COM
35010355SAli.Bahrami@Sun.COM		if ($Line =~ /^((TOP_)?VERSION)\s+([^\s]+)(\s+\{(.*)\})?\s*$/i) {
35110355SAli.Bahrami@Sun.COM			my ($top, $name, $inherit) = ($2, $3, $5);
35210355SAli.Bahrami@Sun.COM
35310355SAli.Bahrami@Sun.COM			$top = defined($top) ? 1 : 0;
35410355SAli.Bahrami@Sun.COM
35510355SAli.Bahrami@Sun.COM			my @inheritarr = defined($inherit) ?
35610355SAli.Bahrami@Sun.COM			    split /[,{\s]+/, $inherit : ();
35710355SAli.Bahrami@Sun.COM
35810355SAli.Bahrami@Sun.COM			$cur_version = [ $top, 0, 0, {}, \@inheritarr ];
35910355SAli.Bahrami@Sun.COM			$obj_hash->{'VERSION_INFO'}{$name} = $cur_version;
36010355SAli.Bahrami@Sun.COM
36110355SAli.Bahrami@Sun.COM			push @{$obj_hash->{'VERSION_NAMES'}}, $name;
36210355SAli.Bahrami@Sun.COM			$sym_ok = 1;
36310355SAli.Bahrami@Sun.COM			next;
36410355SAli.Bahrami@Sun.COM		}
36510355SAli.Bahrami@Sun.COM
36610355SAli.Bahrami@Sun.COM		if ($Line =~ /^OBJECT\s+([^\s]+)$/i) {
36710355SAli.Bahrami@Sun.COM		    my $prev_obj_hash = $obj_hash;
36810355SAli.Bahrami@Sun.COM		    $obj_name = $1;
36910355SAli.Bahrami@Sun.COM		    $main_hash{$obj_name} = {};
37010355SAli.Bahrami@Sun.COM		    $obj_hash = $main_hash{$obj_name};
37110355SAli.Bahrami@Sun.COM
37210355SAli.Bahrami@Sun.COM		    # Expand the versions for the object just processed
37310355SAli.Bahrami@Sun.COM		    ExpandInheritance($prev_obj_hash);
37410355SAli.Bahrami@Sun.COM		    next;
37510355SAli.Bahrami@Sun.COM		}
37610355SAli.Bahrami@Sun.COM
37710355SAli.Bahrami@Sun.COM		if ($Line =~ /^CLASS\s+([^\s]+)$/i) {
37810355SAli.Bahrami@Sun.COM			$obj_hash->{'CLASS'} = $1;
37910355SAli.Bahrami@Sun.COM			next;
38010355SAli.Bahrami@Sun.COM		}
38110355SAli.Bahrami@Sun.COM
38210355SAli.Bahrami@Sun.COM		if ($Line =~ /^TYPE\s+([^\s]+)$/i) {
38310355SAli.Bahrami@Sun.COM			$obj_hash->{'TYPE'} = $1;
38410355SAli.Bahrami@Sun.COM			next;
38510355SAli.Bahrami@Sun.COM		}
38610355SAli.Bahrami@Sun.COM
38710355SAli.Bahrami@Sun.COM		if ($Line =~ /^ALIAS\s+([^\s]+)$/i) {
38810355SAli.Bahrami@Sun.COM			$$alias{$1} = $obj_name;
38910355SAli.Bahrami@Sun.COM			next;
39010355SAli.Bahrami@Sun.COM		}
39110355SAli.Bahrami@Sun.COM
39210355SAli.Bahrami@Sun.COM		die "$file: unrecognized item on line $LineNum: $Line\n";
39310355SAli.Bahrami@Sun.COM	}
39410355SAli.Bahrami@Sun.COM	close FILE;
39510355SAli.Bahrami@Sun.COM
39610355SAli.Bahrami@Sun.COM	# Expand the versions for the final object from the file
39710355SAli.Bahrami@Sun.COM	ExpandInheritance($obj_hash);
39810355SAli.Bahrami@Sun.COM
39910355SAli.Bahrami@Sun.COM	return %main_hash;
40010355SAli.Bahrami@Sun.COM}
40110355SAli.Bahrami@Sun.COM
40210355SAli.Bahrami@Sun.COM## PrintInterface(main_hash, alias)
40310355SAli.Bahrami@Sun.COM#
40410355SAli.Bahrami@Sun.COM# Dump the contents of main_hash and alias to stdout in the same format
40510355SAli.Bahrami@Sun.COM# used by interface_check to produce the input interface file. This output
40610355SAli.Bahrami@Sun.COM# should diff cleanly against the original (ignoring the header comments).
40710355SAli.Bahrami@Sun.COM#
40810355SAli.Bahrami@Sun.COMsub PrintInterface {
40910355SAli.Bahrami@Sun.COM	my ($main_hash, $alias_hash) = @_;
41010355SAli.Bahrami@Sun.COM
41110355SAli.Bahrami@Sun.COM	foreach my $obj (sort keys %$main_hash) {
41210355SAli.Bahrami@Sun.COM		print "OBJECT\t$obj\n";
41310355SAli.Bahrami@Sun.COM		print "CLASS\t$main_hash->{$obj}{'CLASS'}\n";
41410355SAli.Bahrami@Sun.COM		print "TYPE\t$main_hash->{$obj}{'TYPE'}\n";
41510355SAli.Bahrami@Sun.COM
41610355SAli.Bahrami@Sun.COM		# This is inefficient, but good enough for debugging
41710355SAli.Bahrami@Sun.COM		# Look at all the aliases and print those that belong
41810355SAli.Bahrami@Sun.COM		# to this object.
41910355SAli.Bahrami@Sun.COM		foreach my $alias (sort keys %$alias_hash) {
42010355SAli.Bahrami@Sun.COM			print "ALIAS\t$alias\n"
42110355SAli.Bahrami@Sun.COM			    if ($obj eq $alias_hash->{$alias});
42210355SAli.Bahrami@Sun.COM		}
42310355SAli.Bahrami@Sun.COM
42410355SAli.Bahrami@Sun.COM		next if !defined($main_hash->{$obj}{'VERSION_NAMES'});
42510355SAli.Bahrami@Sun.COM
42610355SAli.Bahrami@Sun.COM		my $num = scalar(@{$main_hash->{$obj}{'VERSION_NAMES'}});
42710355SAli.Bahrami@Sun.COM		my $i;
42810355SAli.Bahrami@Sun.COM		for ($i = 0; $i < $num; $i++) {
42910355SAli.Bahrami@Sun.COM			my $name = $main_hash->{$obj}{'VERSION_NAMES'}[$i];
43010355SAli.Bahrami@Sun.COM			my ($top, $direct, $total, $symhash, $inheritarr) =
43110355SAli.Bahrami@Sun.COM			    @{$main_hash->{$obj}{'VERSION_INFO'}{$name}};
43210355SAli.Bahrami@Sun.COM
43310355SAli.Bahrami@Sun.COM			$top = $top ? "TOP_" : '';
43410355SAli.Bahrami@Sun.COM
43510355SAli.Bahrami@Sun.COM			my $inherit = (scalar(@$inheritarr) > 0) ?
43610355SAli.Bahrami@Sun.COM			    "\t{" . join(', ', @{$inheritarr}) . "}" : '';
43710355SAli.Bahrami@Sun.COM
43810355SAli.Bahrami@Sun.COM			print "${top}VERSION\t$name$inherit\n";
43910355SAli.Bahrami@Sun.COM
44010355SAli.Bahrami@Sun.COM			foreach my $sym (sort keys %$symhash) {
44110355SAli.Bahrami@Sun.COM				print "\t$symhash->{$sym}\t$sym\n";
44210355SAli.Bahrami@Sun.COM			}
44310355SAli.Bahrami@Sun.COM		}
44410355SAli.Bahrami@Sun.COM	}
44510355SAli.Bahrami@Sun.COM}
44610355SAli.Bahrami@Sun.COM
44710355SAli.Bahrami@Sun.COM## compare()
44810355SAli.Bahrami@Sun.COM#
44910355SAli.Bahrami@Sun.COM# Compare the old interface definition contained in (%old_hash, %old_alias)
45010355SAli.Bahrami@Sun.COM# with the new interface contained in (%new_hash, %new_alias).
45110355SAli.Bahrami@Sun.COM#
45210355SAli.Bahrami@Sun.COMsub compare {
45310355SAli.Bahrami@Sun.COM	foreach my $old_obj (sort keys %old_hash) {
45410355SAli.Bahrami@Sun.COM		my $new_obj = $old_obj;
45510355SAli.Bahrami@Sun.COM		my $Ttl = 0;
45610355SAli.Bahrami@Sun.COM
45710355SAli.Bahrami@Sun.COM		# If the object does not exist in the new interface,
45810355SAli.Bahrami@Sun.COM		# then see if there's an alias for it. Failing that,
45910355SAli.Bahrami@Sun.COM		# we simply ignore the object.
46010355SAli.Bahrami@Sun.COM		if (!defined($new_hash{$new_obj})) {
46110355SAli.Bahrami@Sun.COM			next if !defined($new_alias{$new_obj});
46210355SAli.Bahrami@Sun.COM			$new_obj = $new_alias{$new_obj};
46310355SAli.Bahrami@Sun.COM		}
46410355SAli.Bahrami@Sun.COM
46510355SAli.Bahrami@Sun.COM		my $old = $old_hash{$old_obj};
46610355SAli.Bahrami@Sun.COM		my $new = $new_hash{$new_obj};
46710355SAli.Bahrami@Sun.COM
46810355SAli.Bahrami@Sun.COM		# Every version in the old object must exist in the new object,
46910355SAli.Bahrami@Sun.COM		# and there must be exactly the same symbols in each.
47010355SAli.Bahrami@Sun.COM		my $num = scalar(@{$old->{'VERSION_NAMES'}});
47110355SAli.Bahrami@Sun.COM		for (my $i = 0; $i < $num; $i++) {
47210355SAli.Bahrami@Sun.COM			my $name = $old->{'VERSION_NAMES'}[$i];
47310355SAli.Bahrami@Sun.COM
47410355SAli.Bahrami@Sun.COM			# New object must have this version
47510355SAli.Bahrami@Sun.COM			if (!defined($new->{'VERSION_INFO'}{$name})) {
47610355SAli.Bahrami@Sun.COM				onbld_elfmod::OutMsg2(\*STDOUT, \$Ttl, $old_obj,
47710355SAli.Bahrami@Sun.COM				    $new_obj, "$name: deleted version");
47810355SAli.Bahrami@Sun.COM				next;
47910355SAli.Bahrami@Sun.COM			}
48010355SAli.Bahrami@Sun.COM
48110355SAli.Bahrami@Sun.COM			my ($old_top, $old_direct, $old_total, $old_symhash) =
48210355SAli.Bahrami@Sun.COM			    @{$old->{'VERSION_INFO'}{$name}};
48310355SAli.Bahrami@Sun.COM			my ($new_top, $new_direct, $new_total, $new_symhash) =
48410355SAli.Bahrami@Sun.COM			    @{$new->{'VERSION_INFO'}{$name}};
48510355SAli.Bahrami@Sun.COM
48610355SAli.Bahrami@Sun.COM			# If this is an empty top version, and the old object
48710355SAli.Bahrami@Sun.COM			# has the EMPTY_TOPVERSION exception set, then we
48810355SAli.Bahrami@Sun.COM			# skip it as if it were not present.
48910355SAli.Bahrami@Sun.COM			next if $old_top && ($old_direct == 0) &&
49010355SAli.Bahrami@Sun.COM			    ExTopVer($name, $old_obj);
49110355SAli.Bahrami@Sun.COM
49210355SAli.Bahrami@Sun.COM			# We check that every symbol in the old object is
49310355SAli.Bahrami@Sun.COM			# in the new one to detect deleted symbols. We then
49410355SAli.Bahrami@Sun.COM			# check that every symbol in the new object is also
49510355SAli.Bahrami@Sun.COM			# in the old object, to find added symbols. If the
49610355SAli.Bahrami@Sun.COM			# "deleted" check is clean, and the two objects have
49710355SAli.Bahrami@Sun.COM			# the same number of symbols in their versions, then we
49810355SAli.Bahrami@Sun.COM			# can skip the "added" test, because we know that
49910355SAli.Bahrami@Sun.COM			# there is no room for an addition to have happened.
50010355SAli.Bahrami@Sun.COM			# Since most objects satisfy these constraints, we
50110355SAli.Bahrami@Sun.COM			# end up doing roughly half the number of comparisons
50210355SAli.Bahrami@Sun.COM			# that would otherwise be needed.
50310355SAli.Bahrami@Sun.COM			my $check_added_syms =
50410355SAli.Bahrami@Sun.COM			    ($old_total == $new_total) ? 0: 1;
50510355SAli.Bahrami@Sun.COM
50610355SAli.Bahrami@Sun.COM			# Every symbol in the old version must be in the new one
50710355SAli.Bahrami@Sun.COM			foreach my $sym (sort keys %$old_symhash) {
50810355SAli.Bahrami@Sun.COM				if (!defined($new_symhash->{$sym})) {
50910355SAli.Bahrami@Sun.COM					onbld_elfmod::OutMsg2(\*STDOUT,
51010355SAli.Bahrami@Sun.COM					   \$Ttl, $old_obj, $new_obj,
51110355SAli.Bahrami@Sun.COM					   "$name: deleted interface: $sym")
51210355SAli.Bahrami@Sun.COM					    if !ExSym(\@DelSymList,
51310355SAli.Bahrami@Sun.COM						      $sym, $name, $new_obj);
51410355SAli.Bahrami@Sun.COM					$check_added_syms = 1;
51510355SAli.Bahrami@Sun.COM				}
51610355SAli.Bahrami@Sun.COM			}
51710355SAli.Bahrami@Sun.COM
51810355SAli.Bahrami@Sun.COM			# Do the "added" check, unless we can optimize it away.
51910355SAli.Bahrami@Sun.COM			# Every symbol in the new version must be in the old one.
52010355SAli.Bahrami@Sun.COM			if ($check_added_syms) {
52110355SAli.Bahrami@Sun.COM				foreach my $sym (sort keys %$new_symhash) {
52210355SAli.Bahrami@Sun.COM				    if (!defined($old_symhash->{$sym})) {
52310355SAli.Bahrami@Sun.COM					next if ExSym(\@AddSymList,
52410355SAli.Bahrami@Sun.COM					    $sym, $name, $new_obj);
52510355SAli.Bahrami@Sun.COM					onbld_elfmod::OutMsg2(\*STDOUT,
52610355SAli.Bahrami@Sun.COM					       \$Ttl, $old_obj, $new_obj,
52710355SAli.Bahrami@Sun.COM					       "$name: added interface: $sym");
52810355SAli.Bahrami@Sun.COM				    }
52910355SAli.Bahrami@Sun.COM				}
53010355SAli.Bahrami@Sun.COM			}
53110355SAli.Bahrami@Sun.COM
53210355SAli.Bahrami@Sun.COM			# We want to ensure that version numbers in an
53310355SAli.Bahrami@Sun.COM			# inheritance chain don't go up by more than 1 in
53410355SAli.Bahrami@Sun.COM			# any given release. If the version names are in the
535*12478SAli.Bahrami@Oracle.COM			# numbered <PREFIX>x.y[.z] format, we can compare the
53610355SAli.Bahrami@Sun.COM			# two top versions and see if this has happened.
53710355SAli.Bahrami@Sun.COM			#
538*12478SAli.Bahrami@Oracle.COM			# For a given <PREFIX>x.y[.z], valid sucessors would
539*12478SAli.Bahrami@Oracle.COM			# be <PREFIX>x.(y+1) or <PREFIX>x.y.(z+1), where z is
54010355SAli.Bahrami@Sun.COM			# assumed to be 0 if not present.
54110355SAli.Bahrami@Sun.COM			#
54210355SAli.Bahrami@Sun.COM			# This check only makes sense when the new interface
54310355SAli.Bahrami@Sun.COM			# is a direct decendent of the old one, as specified
54410355SAli.Bahrami@Sun.COM			# via the -d option. If the two interfaces are more
54510355SAli.Bahrami@Sun.COM			# than one release apart, we should not do this test.
546*12478SAli.Bahrami@Oracle.COM			next if !($opt{d} && $old_top && !$new_top);
547*12478SAli.Bahrami@Oracle.COM
548*12478SAli.Bahrami@Oracle.COM			# Known numbered version?
549*12478SAli.Bahrami@Oracle.COM			#
550*12478SAli.Bahrami@Oracle.COM			# Key to @Cat contents:
551*12478SAli.Bahrami@Oracle.COM			# [0]   'NUMBERED'
552*12478SAli.Bahrami@Oracle.COM			# [1]	number of dot separated numeric fields. 2 or 3.
553*12478SAli.Bahrami@Oracle.COM			# [2]   prefix
554*12478SAli.Bahrami@Oracle.COM			# [3]   major #
555*12478SAli.Bahrami@Oracle.COM			# [4]   minor #
556*12478SAli.Bahrami@Oracle.COM			# [5]   micro # (only if [1] is 3)
557*12478SAli.Bahrami@Oracle.COM			my @Cat = onbld_elfmod_vertype::Category($name, '');
558*12478SAli.Bahrami@Oracle.COM			next if ($Cat[0] ne 'NUMBERED');
55910355SAli.Bahrami@Sun.COM
560*12478SAli.Bahrami@Oracle.COM			my $iname1 = "$Cat[2]$Cat[3]." . ($Cat[4] + 1);
561*12478SAli.Bahrami@Oracle.COM			my $iname2;
562*12478SAli.Bahrami@Oracle.COM			if ($Cat[1] == 3) {
563*12478SAli.Bahrami@Oracle.COM			    $iname2 = "$Cat[2]$Cat[3].$Cat[4]." . ($Cat[5] + 1);
564*12478SAli.Bahrami@Oracle.COM			} else {
565*12478SAli.Bahrami@Oracle.COM			    $iname2 = "$Cat[2]$Cat[3].$Cat[4].1";
566*12478SAli.Bahrami@Oracle.COM			}
567*12478SAli.Bahrami@Oracle.COM
568*12478SAli.Bahrami@Oracle.COM			if (defined($new->{'VERSION_INFO'}{$iname1}) ||
569*12478SAli.Bahrami@Oracle.COM			    defined($new->{'VERSION_INFO'}{$iname2})) {
570*12478SAli.Bahrami@Oracle.COM				my $i_top =
571*12478SAli.Bahrami@Oracle.COM				    $new->{'VERSION_INFO'}{$iname1}[0] ||
572*12478SAli.Bahrami@Oracle.COM				    $new->{'VERSION_INFO'}{$iname2}[0];
573*12478SAli.Bahrami@Oracle.COM				if (!$i_top) {
574*12478SAli.Bahrami@Oracle.COM					onbld_elfmod::OutMsg2(\*STDOUT,
57510355SAli.Bahrami@Sun.COM					    \$Ttl, $old_obj, $new_obj,
576*12478SAli.Bahrami@Oracle.COM					    "$name: inconsistant " .
577*12478SAli.Bahrami@Oracle.COM					    "version increment: " .
578*12478SAli.Bahrami@Oracle.COM					    "expect $iname1 or $iname2 ".
579*12478SAli.Bahrami@Oracle.COM					    "to replace top version");
58010355SAli.Bahrami@Sun.COM				}
581*12478SAli.Bahrami@Oracle.COM			} else {
582*12478SAli.Bahrami@Oracle.COM 				onbld_elfmod::OutMsg2(\*STDOUT,
583*12478SAli.Bahrami@Oracle.COM				    \$Ttl, $old_obj, $new_obj,
584*12478SAli.Bahrami@Oracle.COM			            "$name: expected superseding " .
585*12478SAli.Bahrami@Oracle.COM				    "top version to $name not " .
586*12478SAli.Bahrami@Oracle.COM				    "present: $iname1 or $iname2");
58710355SAli.Bahrami@Sun.COM			}
58810355SAli.Bahrami@Sun.COM		}
58910355SAli.Bahrami@Sun.COM
59010355SAli.Bahrami@Sun.COM
59110355SAli.Bahrami@Sun.COM		# Empty versions in the established interface description
59210355SAli.Bahrami@Sun.COM		# are usually the result of fixing a versioning mistake
59310355SAli.Bahrami@Sun.COM		# at some point in the past. These versions are part of
59410355SAli.Bahrami@Sun.COM		# the public record, and cannot be changed now. However, if
59510355SAli.Bahrami@Sun.COM		# comparing two interface descriptions from the same gate,
59610355SAli.Bahrami@Sun.COM		# flag any empty versions in the new interface description
59710355SAli.Bahrami@Sun.COM		# that are not present in the old one. These have yet to
59810355SAli.Bahrami@Sun.COM		# become part of the official interface, and should be removed
59910355SAli.Bahrami@Sun.COM		# before they do.
60010355SAli.Bahrami@Sun.COM		next if !$opt{d};
60110355SAli.Bahrami@Sun.COM
60210355SAli.Bahrami@Sun.COM		$num = scalar(@{$new->{'VERSION_NAMES'}});
60310355SAli.Bahrami@Sun.COM		for (my $i = 0; $i < $num; $i++) {
60410355SAli.Bahrami@Sun.COM			my $name = $new->{'VERSION_NAMES'}[$i];
60510355SAli.Bahrami@Sun.COM
60610355SAli.Bahrami@Sun.COM			# If old object has this version, skip it
60710355SAli.Bahrami@Sun.COM			next if defined($old->{'VERSION_INFO'}{$name});
60810355SAli.Bahrami@Sun.COM
60910355SAli.Bahrami@Sun.COM			# If explicitly whitelisted, skip it
61010355SAli.Bahrami@Sun.COM			next if ExTopVer($name, $new_obj);
61110355SAli.Bahrami@Sun.COM
61210355SAli.Bahrami@Sun.COM			my ($new_top, $new_direct, $new_total, $new_symhash) =
61310355SAli.Bahrami@Sun.COM			    @{$new->{'VERSION_INFO'}{$name}};
61410355SAli.Bahrami@Sun.COM
61510355SAli.Bahrami@Sun.COM			if ($new_direct == 0) {
61610355SAli.Bahrami@Sun.COM				onbld_elfmod::OutMsg2(\*STDOUT,
61710355SAli.Bahrami@Sun.COM				    \$Ttl, $old_obj, $new_obj,
61810355SAli.Bahrami@Sun.COM				    "$name: invalid empty new version");
61910355SAli.Bahrami@Sun.COM			}
62010355SAli.Bahrami@Sun.COM		}
62110355SAli.Bahrami@Sun.COM	}
62210355SAli.Bahrami@Sun.COM
62310355SAli.Bahrami@Sun.COM}
62410355SAli.Bahrami@Sun.COM
62510355SAli.Bahrami@Sun.COM
62610355SAli.Bahrami@Sun.COM
62710355SAli.Bahrami@Sun.COM# -----------------------------------------------------------------------------
62810355SAli.Bahrami@Sun.COM
62910355SAli.Bahrami@Sun.COM# Establish a program name for any error diagnostics.
63010355SAli.Bahrami@Sun.COMchomp($Prog = `basename $0`);
63110355SAli.Bahrami@Sun.COM
63210355SAli.Bahrami@Sun.COM# Check that we have arguments. Normally, 2 plain arguments are required,
63310355SAli.Bahrami@Sun.COM# but if -t is present, only one is allowed.
634*12478SAli.Bahrami@Oracle.COMif ((getopts('c:de:ot', \%opt) == 0) || (scalar(@ARGV) != ($opt{t} ? 1 : 2))) {
635*12478SAli.Bahrami@Oracle.COM	print "usage: $Prog [-dot] [-c vtype_mod] [-e exfile] old new\n";
636*12478SAli.Bahrami@Oracle.COM	print "\t[-c vtype_mod]\tsupply alternative version category module\n";
63710355SAli.Bahrami@Sun.COM	print "\t[-d]\t\tnew is a direct decendent of old\n";
63810355SAli.Bahrami@Sun.COM	print "\t[-e exfile]\texceptions file\n";
63910355SAli.Bahrami@Sun.COM	print "\t[-o]\t\tproduce one-liner output (prefixed with pathname)\n";
64010355SAli.Bahrami@Sun.COM	print "\t[-t]\tParse old, and recreate to stdout\n";
64110355SAli.Bahrami@Sun.COM	exit 1;
64210355SAli.Bahrami@Sun.COM}
64310355SAli.Bahrami@Sun.COM
644*12478SAli.Bahrami@Oracle.COM# We depend on the onbld_elfmod and onbld_elfmod_vertype perl modules.
645*12478SAli.Bahrami@Oracle.COM# Both modules are maintained in the same directory as this script,
646*12478SAli.Bahrami@Oracle.COM# and are installed in ../lib/perl. Use the local one if present,
647*12478SAli.Bahrami@Oracle.COM# and the installed one otherwise.
648*12478SAli.Bahrami@Oracle.COM#
649*12478SAli.Bahrami@Oracle.COM# The caller is allowed to supply an alternative implementation for
650*12478SAli.Bahrami@Oracle.COM# onbld_elfmod_vertype via the -c option. In this case, the alternative
651*12478SAli.Bahrami@Oracle.COM# implementation is expected to provide the same interface as the standard
652*12478SAli.Bahrami@Oracle.COM# copy, and is loaded instead.
653*12478SAli.Bahrami@Oracle.COM#
654*12478SAli.Bahrami@Oracle.COMmy $moddir = my $vermoddir = dirname($0);
655*12478SAli.Bahrami@Oracle.COM$moddir = "$moddir/../lib/perl" if ! -f "$moddir/onbld_elfmod.pm";
656*12478SAli.Bahrami@Oracle.COMrequire "$moddir/onbld_elfmod.pm";
657*12478SAli.Bahrami@Oracle.COMif ($opt{c}) {
658*12478SAli.Bahrami@Oracle.COM	require "$opt{c}";
659*12478SAli.Bahrami@Oracle.COM} else {
660*12478SAli.Bahrami@Oracle.COM	$vermoddir = "$vermoddir/../lib/perl"
661*12478SAli.Bahrami@Oracle.COM	    if ! -f "$vermoddir/onbld_elfmod_vertype.pm";
662*12478SAli.Bahrami@Oracle.COM	require "$vermoddir/onbld_elfmod_vertype.pm";
663*12478SAli.Bahrami@Oracle.COM}
664*12478SAli.Bahrami@Oracle.COM
66510355SAli.Bahrami@Sun.COM# Locate and process the exceptions file
66610355SAli.Bahrami@Sun.COMLoadExceptions();
66710355SAli.Bahrami@Sun.COM
66810355SAli.Bahrami@Sun.COM%old_alias = ();
66910355SAli.Bahrami@Sun.COM%old_hash = ReadInterface($ARGV[0], \%old_alias);
67010355SAli.Bahrami@Sun.COM
67110355SAli.Bahrami@Sun.COM# If -t is present, only one argument is allowed --- we parse it, and then
67210355SAli.Bahrami@Sun.COM# print the same information back to stderr in the same format as the original.
67310355SAli.Bahrami@Sun.COM# This is useful for debugging, to verify that the parsing is correct.
67410355SAli.Bahrami@Sun.COMif ($opt{t}) {
67510355SAli.Bahrami@Sun.COM	PrintInterface(\%old_hash, \%old_alias);
67610355SAli.Bahrami@Sun.COM	exit 0;
67710355SAli.Bahrami@Sun.COM}
67810355SAli.Bahrami@Sun.COM
67910355SAli.Bahrami@Sun.COM%new_alias = ();
68010355SAli.Bahrami@Sun.COM%new_hash = ReadInterface($ARGV[1], \%new_alias);
68110355SAli.Bahrami@Sun.COM
68210355SAli.Bahrami@Sun.COMcompare();
68310355SAli.Bahrami@Sun.COM
68410355SAli.Bahrami@Sun.COMexit 0;
685