# # 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 : ""; # 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); } }