1# 2# SPDX-License-Identifier: BSD-2-Clause 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# 28 29# 30# Make a list of all the library versions listed in the master file. 31# 32# versions[] - array indexed by version name, contains number 33# of symbols (+ 1) found for each version. 34# successors[] - array index by version name, contains successor 35# version name. 36# symbols[][] - array index by [version name, symbol index], contains 37# names of symbols defined for each version. 38# names[] - array index is symbol name and value is its first version seen, 39# used to check for duplicate symbols and warn about them. 40# 41BEGIN { 42 brackets = 0; 43 errors = warns = 0; 44 version_count = 0; 45 current_version = ""; 46 stderr = "/dev/stderr"; 47 while (getline < vfile) { 48 # Strip comments. 49 sub("#.*$", "", $0); 50 51 # Strip leading and trailing whitespace. 52 sub("^[ \t]+", "", $0); 53 sub("[ \t]+$", "", $0); 54 55 if (/^[a-zA-Z0-9._]+[ \t]*{$/) { 56 # Strip brace. 57 sub("{", "", $1); 58 brackets++; 59 symver = $1; 60 versions[symver] = 1; 61 successors[symver] = ""; 62 generated[symver] = 0; 63 version_count++; 64 } 65 else if (/^}[ \t]*[a-zA-Z0-9._]+[ \t]*;$/) { 66 v = $1 != "}" ? $1 : $2; 67 # Strip brace. 68 sub("}", "", v); 69 # Strip semicolon. 70 sub(";", "", v); 71 if (symver == "") { 72 printf("File %s: Unmatched bracket.\n", 73 vfile) > stderr; 74 errors++; 75 } 76 else if (versions[v] != 1) { 77 printf("File %s: `%s' has unknown " \ 78 "successor `%s'.\n", 79 vfile, symver, v) > stderr; 80 errors++; 81 } 82 else 83 successors[symver] = v; 84 brackets--; 85 } 86 else if (/^}[ \t]*;$/) { 87 if (symver == "") { 88 printf("File %s: Unmatched bracket.\n", 89 vfile) > stderr; 90 errors++; 91 } 92 # No successor 93 brackets--; 94 } 95 else if (/^}$/) { 96 printf("File %s: Missing final semicolon.\n", 97 vfile) > stderr; 98 errors++; 99 } 100 else if (/^$/) 101 ; # Ignore blank lines. 102 else { 103 printf("File %s: Unknown directive: `%s'.\n", 104 vfile, $0) > stderr; 105 errors++; 106 } 107 } 108 brackets = 0; 109} 110 111{ 112 # Set meaningful filename for diagnostics. 113 filename = FILENAME != "" ? FILENAME : "<stdin>"; 114 115 # Delete comments, preceding and trailing whitespace, then 116 # consume blank lines. 117 sub("#.*$", "", $0); 118 sub("^[ \t]+", "", $0); 119 sub("[ \t]+$", "", $0); 120 if ($0 == "") 121 next; 122} 123 124/^[a-zA-Z0-9._]+[ \t]*{$/ { 125 # Strip bracket from version name. 126 sub("{", "", $1); 127 if (current_version != "") { 128 printf("File %s, line %d: Illegal nesting detected.\n", 129 filename, FNR) > stderr; 130 errors++; 131 } 132 else if (versions[$1] == 0) { 133 printf("File %s, line %d: Undefined " \ 134 "library version `%s'.\n", filename, FNR, $1) > stderr; 135 errors++; 136 # Remove this entry from the versions. 137 delete versions[$1]; 138 } 139 else 140 current_version = $1; 141 brackets++; 142 next; 143} 144 145/^[a-zA-Z0-9._]+[ \t]*;$/ { 146 # Strip semicolon. 147 sub(";", "", $1); 148 if (current_version != "") { 149 count = versions[current_version]; 150 versions[current_version]++; 151 symbols[current_version, count] = $1; 152 if ($1 in names && names[$1] != current_version) { 153 # 154 # A graver case when a dup symbol appears under 155 # different versions in the map. That can result 156 # in subtle problems with the library later. 157 # 158 printf("File %s, line %d: Duplicated symbol `%s' " \ 159 "in version `%s', first seen in `%s'. " \ 160 "Did you forget to move it to ObsoleteVersions?\n", 161 filename, FNR, $1, 162 current_version, names[$1]) > stderr; 163 errors++; 164 } 165 else if (names[$1] == current_version) { 166 # 167 # A harmless case: a dup symbol with the same version. 168 # 169 printf("File %s, line %d: warning: " \ 170 "Duplicated symbol `%s' in version `%s'.\n", 171 filename, FNR, $1, current_version) > stderr; 172 warns++; 173 } 174 else 175 names[$1] = current_version; 176 } 177 else { 178 printf("File %s, line %d: Symbol `%s' outside version scope.\n", 179 filename, FNR, $1) > stderr; 180 errors++; 181 } 182 next; 183} 184 185/^}[ \t]*;$/ { 186 brackets--; 187 if (brackets < 0) { 188 printf("File %s, line %d: Unmatched bracket.\n", 189 filename, FNR, $1) > stderr; 190 errors++; 191 brackets = 0; # Reset 192 } 193 current_version = ""; 194 next; 195} 196 197 198{ 199 printf("File %s, line %d: Unknown directive: `%s'.\n", 200 filename, FNR, $0) > stderr; 201 errors++; 202} 203 204function print_version(v) 205{ 206 # This function is recursive, so return if this version 207 # has already been printed. Otherwise, if there is an 208 # ancestral version, recursively print its symbols before 209 # printing the symbols for this version. 210 # 211 if (generated[v] == 1) 212 return; 213 if (successors[v] != "") 214 print_version(successors[v]); 215 216 printf("%s {\n", v); 217 218 # The version count is always one more that actual, 219 # so the loop ranges from 1 to n-1. 220 # 221 for (i = 1; i < versions[v]; i++) { 222 if (i == 1) 223 printf("global:\n"); 224 printf("\t%s;\n", symbols[v, i]); 225 } 226 227 version_count--; 228 if (version_count == 0) { 229 printf("local:\n"); 230 printf("\t*;\n"); 231 } 232 if (successors[v] == "") 233 printf("};\n"); 234 else 235 printf("} %s;\n", successors[v]); 236 printf("\n"); 237 238 generated[v] = 1; 239 } 240 241END { 242 if (errors) { 243 printf("%d error(s) total.\n", errors) > stderr; 244 exit(1); 245 } 246 # OK, no errors. 247 for (v in versions) { 248 print_version(v); 249 } 250} 251