c8d051d855
(evil, needs a error) or in the same version (harmless, deserves a mere warning). Noticed by: grehan@, tinderbox
250 lines
6.3 KiB
Awk
250 lines
6.3 KiB
Awk
#
|
|
# Copyright (C) 2006 Daniel M. Eischen. All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
# SUCH DAMAGE.
|
|
#
|
|
# $FreeBSD$
|
|
#
|
|
|
|
#
|
|
# Make a list of all the library versions listed in the master file.
|
|
#
|
|
# versions[] - array indexed by version name, contains number
|
|
# of symbols (+ 1) found for each version.
|
|
# successors[] - array index by version name, contains successor
|
|
# version name.
|
|
# symbols[][] - array index by [version name, symbol index], contains
|
|
# names of symbols defined for each version.
|
|
# names[] - array index is symbol name and value is its first version seen,
|
|
# used to check for duplicate symbols and warn about them.
|
|
#
|
|
BEGIN {
|
|
brackets = 0;
|
|
errors = warns = 0;
|
|
version_count = 0;
|
|
current_version = "";
|
|
stderr = "/dev/stderr";
|
|
while (getline < vfile) {
|
|
# Strip comments.
|
|
sub("#.*$", "", $0);
|
|
|
|
# Strip leading and trailing whitespace.
|
|
sub("^[ \t]+", "", $0);
|
|
sub("[ \t]+$", "", $0);
|
|
|
|
if (/^[a-zA-Z0-9._]+[ \t]*{$/) {
|
|
# Strip brace.
|
|
sub("{", "", $1);
|
|
brackets++;
|
|
symver = $1;
|
|
versions[symver] = 1;
|
|
successors[symver] = "";
|
|
generated[symver] = 0;
|
|
version_count++;
|
|
}
|
|
else if (/^}[ \t]*[a-zA-Z0-9._]+[ \t]*;$/) {
|
|
v = $1 != "}" ? $1 : $2;
|
|
# Strip brace.
|
|
sub("}", "", v);
|
|
# Strip semicolon.
|
|
sub(";", "", v);
|
|
if (symver == "") {
|
|
printf("File %s: Unmatched bracket.\n",
|
|
vfile) > stderr;
|
|
errors++;
|
|
}
|
|
else if (versions[v] != 1) {
|
|
printf("File %s: `%s' has unknown " \
|
|
"successor `%s'.\n",
|
|
vfile, symver, v) > stderr;
|
|
errors++;
|
|
}
|
|
else
|
|
successors[symver] = v;
|
|
brackets--;
|
|
}
|
|
else if (/^}[ \t]*;$/) {
|
|
if (symver == "") {
|
|
printf("File %s: Unmatched bracket.\n",
|
|
vfile) > stderr;
|
|
errors++;
|
|
}
|
|
# No successor
|
|
brackets--;
|
|
}
|
|
else if (/^}$/) {
|
|
printf("File %s: Missing final semicolon.\n",
|
|
vfile) > stderr;
|
|
errors++;
|
|
}
|
|
else if (/^$/)
|
|
; # Ignore blank lines.
|
|
else {
|
|
printf("File %s: Unknown directive: `%s'.\n",
|
|
vfile, $0) > stderr;
|
|
errors++;
|
|
}
|
|
}
|
|
brackets = 0;
|
|
}
|
|
|
|
{
|
|
# Set meaningful filename for diagnostics.
|
|
filename = FILENAME != "" ? FILENAME : "<stdin>";
|
|
|
|
# Delete comments, preceding and trailing whitespace, then
|
|
# consume blank lines.
|
|
sub("#.*$", "", $0);
|
|
sub("^[ \t]+", "", $0);
|
|
sub("[ \t]+$", "", $0);
|
|
if ($0 == "")
|
|
next;
|
|
}
|
|
|
|
/^[a-zA-Z0-9._]+[ \t]*{$/ {
|
|
# Strip bracket from version name.
|
|
sub("{", "", $1);
|
|
if (current_version != "") {
|
|
printf("File %s, line %d: Illegal nesting detected.\n",
|
|
filename, FNR) > stderr;
|
|
errors++;
|
|
}
|
|
else if (versions[$1] == 0) {
|
|
printf("File %s, line %d: Undefined " \
|
|
"library version `%s'.\n", filename, FNR, $1) > stderr;
|
|
errors++;
|
|
# Remove this entry from the versions.
|
|
delete versions[$1];
|
|
}
|
|
else
|
|
current_version = $1;
|
|
brackets++;
|
|
next;
|
|
}
|
|
|
|
/^[a-zA-Z0-9._]+[ \t]*;$/ {
|
|
# Strip semicolon.
|
|
sub(";", "", $1);
|
|
if (current_version != "") {
|
|
count = versions[current_version];
|
|
versions[current_version]++;
|
|
symbols[current_version, count] = $1;
|
|
if ($1 in names && names[$1] != current_version) {
|
|
#
|
|
# A graver case when a dup symbol appears under
|
|
# different versions in the map. That can result
|
|
# in subtle problems with the library later.
|
|
#
|
|
printf("File %s, line %d: Duplicated symbol `%s' " \
|
|
"in version `%s', first seen in `%s'. " \
|
|
"Did you forget to move it to ObsoleteVersions?\n",
|
|
filename, FNR, $1,
|
|
current_version, names[$1]) > stderr;
|
|
errors++;
|
|
}
|
|
else if (names[$1] == current_version) {
|
|
#
|
|
# A harmless case: a dup symbol with the same version.
|
|
#
|
|
printf("File %s, line %d: warning: " \
|
|
"Duplicated symbol `%s' in version `%s'.\n",
|
|
filename, FNR, $1, current_version) > stderr;
|
|
warns++;
|
|
}
|
|
else
|
|
names[$1] = current_version;
|
|
}
|
|
else {
|
|
printf("File %s, line %d: Symbol `%s' outside version scope.\n",
|
|
filename, FNR, $1) > stderr;
|
|
errors++;
|
|
}
|
|
next;
|
|
}
|
|
|
|
/^}[ \t]*;$/ {
|
|
brackets--;
|
|
if (brackets < 0) {
|
|
printf("File %s, line %d: Unmatched bracket.\n",
|
|
filename, FNR, $1) > stderr;
|
|
errors++;
|
|
brackets = 0; # Reset
|
|
}
|
|
current_version = "";
|
|
next;
|
|
}
|
|
|
|
|
|
{
|
|
printf("File %s, line %d: Unknown directive: `%s'.\n",
|
|
filename, FNR, $0) > stderr;
|
|
errors++;
|
|
}
|
|
|
|
function print_version(v)
|
|
{
|
|
# This function is recursive, so return if this version
|
|
# has already been printed. Otherwise, if there is an
|
|
# ancestral version, recursively print its symbols before
|
|
# printing the symbols for this version.
|
|
#
|
|
if (generated[v] == 1)
|
|
return;
|
|
if (successors[v] != "")
|
|
print_version(successors[v]);
|
|
|
|
printf("%s {\n", v);
|
|
|
|
# The version count is always one more that actual,
|
|
# so the loop ranges from 1 to n-1.
|
|
#
|
|
for (i = 1; i < versions[v]; i++) {
|
|
if (i == 1)
|
|
printf("global:\n");
|
|
printf("\t%s;\n", symbols[v, i]);
|
|
}
|
|
|
|
version_count--;
|
|
if (version_count == 0) {
|
|
printf("local:\n");
|
|
printf("\t*;\n");
|
|
}
|
|
if (successors[v] == "")
|
|
printf("};\n");
|
|
else
|
|
printf("} %s;\n", successors[v]);
|
|
printf("\n");
|
|
|
|
generated[v] = 1;
|
|
}
|
|
|
|
END {
|
|
if (errors) {
|
|
printf("%d error(s) total.\n", errors) > stderr;
|
|
exit(1);
|
|
}
|
|
# OK, no errors.
|
|
for (v in versions) {
|
|
print_version(v);
|
|
}
|
|
}
|