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