1# 2# SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3# 4# Copyright (C) 2006 Daniel M. Eischen. All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions 8# are met: 9# 1. Redistributions of source code must retain the above copyright 10# notice, this list of conditions and the following disclaimer. 11# 2. Redistributions in binary form must reproduce the above copyright 12# notice, this list of conditions and the following disclaimer in the 13# documentation and/or other materials provided with the distribution. 14# 15# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25# SUCH DAMAGE. 26# 27# $FreeBSD$ 28# 29 30# 31# Make a list of all the library versions listed in the master file. 32# 33# versions[] - array indexed by version name, contains number 34# of symbols (+ 1) found for each version. 35# successors[] - array index by version name, contains successor 36# version name. 37# symbols[][] - array index by [version name, symbol index], contains 38# names of symbols defined for each version. 39# names[] - array index is symbol name and value is its first version seen, 40# used to check for duplicate symbols and warn about them. 41# 42BEGIN { 43 brackets = 0; 44 errors = warns = 0; 45 version_count = 0; 46 current_version = ""; 47 stderr = "/dev/stderr"; 48 while (getline < vfile) { 49 # Strip comments. 50 sub("#.*$", "", $0); 51 52 # Strip leading and trailing whitespace. 53 sub("^[ \t]+", "", $0); 54 sub("[ \t]+$", "", $0); 55 56 if (/^[a-zA-Z0-9._]+[ \t]*{$/) { 57 # Strip brace. 58 sub("{", "", $1); 59 brackets++; 60 symver = $1; 61 versions[symver] = 1; 62 successors[symver] = ""; 63 generated[symver] = 0; 64 version_count++; 65 } 66 else if (/^}[ \t]*[a-zA-Z0-9._]+[ \t]*;$/) { 67 v = $1 != "}" ? $1 : $2; 68 # Strip brace. 69 sub("}", "", v); 70 # Strip semicolon. 71 sub(";", "", v); 72 if (symver == "") { 73 printf("File %s: Unmatched bracket.\n", 74 vfile) > stderr; 75 errors++; 76 } 77 else if (versions[v] != 1) { 78 printf("File %s: `%s' has unknown " \ 79 "successor `%s'.\n", 80 vfile, symver, v) > stderr; 81 errors++; 82 } 83 else 84 successors[symver] = v; 85 brackets--; 86 } 87 else if (/^}[ \t]*;$/) { 88 if (symver == "") { 89 printf("File %s: Unmatched bracket.\n", 90 vfile) > stderr; 91 errors++; 92 } 93 # No successor 94 brackets--; 95 } 96 else if (/^}$/) { 97 printf("File %s: Missing final semicolon.\n", 98 vfile) > stderr; 99 errors++; 100 } 101 else if (/^$/) 102 ; # Ignore blank lines. 103 else { 104 printf("File %s: Unknown directive: `%s'.\n", 105 vfile, $0) > stderr; 106 errors++; 107 } 108 } 109 brackets = 0; 110} 111 112{ 113 # Set meaningful filename for diagnostics. 114 filename = FILENAME != "" ? FILENAME : "<stdin>"; 115 116 # Delete comments, preceding and trailing whitespace, then 117 # consume blank lines. 118 sub("#.*$", "", $0); 119 sub("^[ \t]+", "", $0); 120 sub("[ \t]+$", "", $0); 121 if ($0 == "") 122 next; 123} 124 125/^[a-zA-Z0-9._]+[ \t]*{$/ { 126 # Strip bracket from version name. 127 sub("{", "", $1); 128 if (current_version != "") { 129 printf("File %s, line %d: Illegal nesting detected.\n", 130 filename, FNR) > stderr; 131 errors++; 132 } 133 else if (versions[$1] == 0) { 134 printf("File %s, line %d: Undefined " \ 135 "library version `%s'.\n", filename, FNR, $1) > stderr; 136 errors++; 137 # Remove this entry from the versions. 138 delete versions[$1]; 139 } 140 else 141 current_version = $1; 142 brackets++; 143 next; 144} 145 146/^[a-zA-Z0-9._]+[ \t]*;$/ { 147 # Strip semicolon. 148 sub(";", "", $1); 149 if (current_version != "") { 150 count = versions[current_version]; 151 versions[current_version]++; 152 symbols[current_version, count] = $1; 153 if ($1 in names && names[$1] != current_version) { 154 # 155 # A graver case when a dup symbol appears under 156 # different versions in the map. That can result 157 # in subtle problems with the library later. 158 # 159 printf("File %s, line %d: Duplicated symbol `%s' " \ 160 "in version `%s', first seen in `%s'. " \ 161 "Did you forget to move it to ObsoleteVersions?\n", 162 filename, FNR, $1, 163 current_version, names[$1]) > stderr; 164 errors++; 165 } 166 else if (names[$1] == current_version) { 167 # 168 # A harmless case: a dup symbol with the same version. 169 # 170 printf("File %s, line %d: warning: " \ 171 "Duplicated symbol `%s' in version `%s'.\n", 172 filename, FNR, $1, current_version) > stderr; 173 warns++; 174 } 175 else 176 names[$1] = current_version; 177 } 178 else { 179 printf("File %s, line %d: Symbol `%s' outside version scope.\n", 180 filename, FNR, $1) > stderr; 181 errors++; 182 } 183 next; 184} 185 186/^}[ \t]*;$/ { 187 brackets--; 188 if (brackets < 0) { 189 printf("File %s, line %d: Unmatched bracket.\n", 190 filename, FNR, $1) > stderr; 191 errors++; 192 brackets = 0; # Reset 193 } 194 current_version = ""; 195 next; 196} 197 198 199{ 200 printf("File %s, line %d: Unknown directive: `%s'.\n", 201 filename, FNR, $0) > stderr; 202 errors++; 203} 204 205function print_version(v) 206{ 207 # This function is recursive, so return if this version 208 # has already been printed. Otherwise, if there is an 209 # ancestral version, recursively print its symbols before 210 # printing the symbols for this version. 211 # 212 if (generated[v] == 1) 213 return; 214 if (successors[v] != "") 215 print_version(successors[v]); 216 217 printf("%s {\n", v); 218 219 # The version count is always one more that actual, 220 # so the loop ranges from 1 to n-1. 221 # 222 for (i = 1; i < versions[v]; i++) { 223 if (i == 1) 224 printf("global:\n"); 225 printf("\t%s;\n", symbols[v, i]); 226 } 227 228 version_count--; 229 if (version_count == 0) { 230 printf("local:\n"); 231 printf("\t*;\n"); 232 } 233 if (successors[v] == "") 234 printf("};\n"); 235 else 236 printf("} %s;\n", successors[v]); 237 printf("\n"); 238 239 generated[v] = 1; 240 } 241 242END { 243 if (errors) { 244 printf("%d error(s) total.\n", errors) > stderr; 245 exit(1); 246 } 247 # OK, no errors. 248 for (v in versions) { 249 print_version(v); 250 } 251} 252