1156772Sdeischen#
2156772Sdeischen# Copyright (C) 2006 Daniel M. Eischen.  All rights reserved.
3156772Sdeischen# 
4156772Sdeischen# Redistribution and use in source and binary forms, with or without
5156772Sdeischen# modification, are permitted provided that the following conditions
6156772Sdeischen# are met:
7156772Sdeischen# 1. Redistributions of source code must retain the above copyright
8156772Sdeischen#    notice, this list of conditions and the following disclaimer.
9156772Sdeischen# 2. Redistributions in binary form must reproduce the above copyright
10156772Sdeischen#    notice, this list of conditions and the following disclaimer in the
11156772Sdeischen#    documentation and/or other materials provided with the distribution.
12156772Sdeischen# 
13156772Sdeischen# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14156772Sdeischen# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15156772Sdeischen# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16156772Sdeischen# ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17156772Sdeischen# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18156772Sdeischen# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19156772Sdeischen# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20156772Sdeischen# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21156772Sdeischen# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22156772Sdeischen# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23156772Sdeischen# SUCH DAMAGE.
24156772Sdeischen#
25156772Sdeischen# $FreeBSD$
26156772Sdeischen#
27156772Sdeischen
28156772Sdeischen#
29156772Sdeischen# Make a list of all the library versions listed in the master file.
30156772Sdeischen#
31156772Sdeischen#   versions[] - array indexed by version name, contains number
32156772Sdeischen#                of symbols (+ 1) found for each version.
33156772Sdeischen#   successors[] - array index by version name, contains successor
34156772Sdeischen#                  version name.
35156772Sdeischen#   symbols[][] - array index by [version name, symbol index], contains
36156772Sdeischen#                 names of symbols defined for each version.
37172747Syar#   names[] - array index is symbol name and value is its first version seen,
38172729Syar#	      used to check for duplicate symbols and warn about them.
39156772Sdeischen#
40156772SdeischenBEGIN {
41156772Sdeischen	brackets = 0;
42172747Syar	errors = warns = 0;
43156772Sdeischen	version_count = 0;
44156772Sdeischen	current_version = "";
45156772Sdeischen	stderr = "/dev/stderr";
46156772Sdeischen	while (getline < vfile) {
47156772Sdeischen		# Strip comments.
48156772Sdeischen		sub("#.*$", "", $0);
49156772Sdeischen
50172729Syar		# Strip leading and trailing whitespace.
51172729Syar		sub("^[ \t]+", "", $0);
52172729Syar		sub("[ \t]+$", "", $0);
53156772Sdeischen
54172729Syar		if (/^[a-zA-Z0-9._]+[ \t]*{$/) {
55172729Syar			# Strip brace.
56172729Syar			sub("{", "", $1);
57156772Sdeischen			brackets++;
58156772Sdeischen			symver = $1;
59156772Sdeischen			versions[symver] = 1;
60156772Sdeischen			successors[symver] = "";
61168963Sdeischen			generated[symver] = 0;
62156772Sdeischen			version_count++;
63156772Sdeischen		}
64172729Syar		else if (/^}[ \t]*[a-zA-Z0-9._]+[ \t]*;$/) {
65172729Syar			v = $1 != "}" ? $1 : $2;
66172729Syar			# Strip brace.
67172729Syar			sub("}", "", v);
68156772Sdeischen			# Strip semicolon.
69172729Syar			sub(";", "", v);
70172729Syar			if (symver == "") {
71172729Syar				printf("File %s: Unmatched bracket.\n",
72172729Syar				vfile) > stderr;
73172729Syar				errors++;
74172729Syar			}
75172729Syar			else if (versions[v] != 1) {
76172729Syar				printf("File %s: `%s' has unknown " \
77172729Syar				    "successor `%s'.\n",
78172729Syar				    vfile, symver, v) > stderr;
79172729Syar				errors++;
80172729Syar			}
81156772Sdeischen			else
82172729Syar				successors[symver] = v;
83156772Sdeischen			brackets--;
84156772Sdeischen		}
85172729Syar		else if (/^}[ \t]*;$/) {
86172729Syar			if (symver == "") {
87156772Sdeischen				printf("File %s: Unmatched bracket.\n",
88156772Sdeischen				    vfile) > stderr;
89172729Syar				errors++;
90172729Syar			}
91156772Sdeischen			# No successor
92156772Sdeischen			brackets--;
93156772Sdeischen		}
94172729Syar		else if (/^}$/) {
95172729Syar			printf("File %s: Missing final semicolon.\n",
96156772Sdeischen			    vfile) > stderr;
97172729Syar			errors++;
98156772Sdeischen		}
99156772Sdeischen		else if (/^$/)
100156772Sdeischen			;  # Ignore blank lines.
101172729Syar		else {
102172729Syar			printf("File %s: Unknown directive: `%s'.\n",
103156772Sdeischen			    vfile, $0) > stderr;
104172729Syar			errors++;
105172729Syar		}
106156772Sdeischen	}
107156772Sdeischen	brackets = 0;
108156772Sdeischen}
109156772Sdeischen
110172729Syar{
111172729Syar	# Set meaningful filename for diagnostics.
112172729Syar	filename = FILENAME != "" ? FILENAME : "<stdin>";
113172729Syar
114156772Sdeischen	# Delete comments, preceding and trailing whitespace, then
115156772Sdeischen	# consume blank lines.
116156772Sdeischen	sub("#.*$", "", $0);
117156772Sdeischen	sub("^[ \t]+", "", $0);
118156772Sdeischen	sub("[ \t]+$", "", $0);
119156772Sdeischen	if ($0 == "")
120156772Sdeischen		next;
121156772Sdeischen}
122156772Sdeischen
123172729Syar/^[a-zA-Z0-9._]+[ \t]*{$/ {
124156772Sdeischen	# Strip bracket from version name.
125156772Sdeischen	sub("{", "", $1);
126172729Syar	if (current_version != "") {
127156772Sdeischen		printf("File %s, line %d: Illegal nesting detected.\n",
128172729Syar		    filename, FNR) > stderr;
129172729Syar		errors++;
130172729Syar	}
131156772Sdeischen	else if (versions[$1] == 0) {
132156772Sdeischen		printf("File %s, line %d: Undefined " \
133172729Syar		    "library version `%s'.\n", filename, FNR, $1) > stderr;
134172729Syar		errors++;
135156772Sdeischen		# Remove this entry from the versions.
136156772Sdeischen		delete versions[$1];
137156772Sdeischen	}
138156772Sdeischen	else
139156772Sdeischen		current_version = $1;
140156772Sdeischen	brackets++;
141156772Sdeischen	next;
142156772Sdeischen}
143156772Sdeischen
144172729Syar/^[a-zA-Z0-9._]+[ \t]*;$/ {
145172729Syar	# Strip semicolon.
146172729Syar	sub(";", "", $1);
147156772Sdeischen	if (current_version != "") {
148156772Sdeischen		count = versions[current_version];
149156772Sdeischen		versions[current_version]++;
150156772Sdeischen		symbols[current_version, count] = $1;
151172747Syar		if ($1 in names && names[$1] != current_version) {
152172747Syar			#
153172747Syar			# A graver case when a dup symbol appears under
154172747Syar			# different versions in the map.  That can result
155172747Syar			# in subtle problems with the library later.
156172747Syar			#
157172747Syar			printf("File %s, line %d: Duplicated symbol `%s' " \
158172747Syar			    "in version `%s', first seen in `%s'. " \
159172729Syar			    "Did you forget to move it to ObsoleteVersions?\n",
160172747Syar			    filename, FNR, $1,
161172747Syar			    current_version, names[$1]) > stderr;
162172729Syar			errors++;
163172729Syar		}
164172747Syar		else if (names[$1] == current_version) {
165172747Syar			#
166172747Syar			# A harmless case: a dup symbol with the same version.
167172747Syar			#
168172747Syar			printf("File %s, line %d: warning: " \
169172747Syar			    "Duplicated symbol `%s' in version `%s'.\n",
170172747Syar			    filename, FNR, $1, current_version) > stderr;
171172747Syar			warns++;
172172747Syar		}
173172747Syar		else
174172747Syar			names[$1] = current_version;
175156772Sdeischen	}
176172729Syar	else {
177172729Syar		printf("File %s, line %d: Symbol `%s' outside version scope.\n",
178172729Syar		    filename, FNR, $1) > stderr;
179172729Syar		errors++;
180172729Syar	}
181156772Sdeischen	next;
182156772Sdeischen}
183156772Sdeischen
184172729Syar/^}[ \t]*;$/ {
185156772Sdeischen	brackets--;
186156772Sdeischen	if (brackets < 0) {
187156772Sdeischen		printf("File %s, line %d: Unmatched bracket.\n",
188172729Syar		    filename, FNR, $1) > stderr;
189172729Syar		errors++;
190156772Sdeischen		brackets = 0;	# Reset
191156772Sdeischen	}
192156772Sdeischen	current_version = "";
193156772Sdeischen	next;
194156772Sdeischen}
195156772Sdeischen
196156772Sdeischen
197172729Syar{
198172729Syar	printf("File %s, line %d: Unknown directive: `%s'.\n",
199172729Syar	    filename, FNR, $0) > stderr;
200172729Syar	errors++;
201156772Sdeischen}
202156772Sdeischen
203168963Sdeischenfunction print_version(v)
204168963Sdeischen{
205168963Sdeischen	# This function is recursive, so return if this version
206168963Sdeischen	# has already been printed.  Otherwise, if there is an
207168963Sdeischen	# ancestral version, recursively print its symbols before
208168963Sdeischen	# printing the symbols for this version.
209168963Sdeischen	#
210168963Sdeischen	if (generated[v] == 1)
211168963Sdeischen		return;
212168963Sdeischen	if (successors[v] != "")
213168963Sdeischen		print_version(successors[v]);
214168963Sdeischen
215168963Sdeischen	printf("%s {\n", v);
216168963Sdeischen
217168963Sdeischen	# The version count is always one more that actual,
218168963Sdeischen	# so the loop ranges from 1 to n-1.
219168963Sdeischen	#
220168963Sdeischen	for (i = 1; i < versions[v]; i++) {
221168963Sdeischen		if (i == 1)
222168963Sdeischen			printf("global:\n");
223172729Syar		printf("\t%s;\n", symbols[v, i]);
224168963Sdeischen	}
225171530Skan
226171530Skan	version_count--;
227171530Skan	if (version_count == 0) {
228168963Sdeischen		printf("local:\n");
229168963Sdeischen		printf("\t*;\n");
230171530Skan	}
231171530Skan	if (successors[v] == "")
232168963Sdeischen		printf("};\n");
233168963Sdeischen	else
234168963Sdeischen		printf("} %s;\n", successors[v]);
235168963Sdeischen	printf("\n");
236168963Sdeischen
237168963Sdeischen	generated[v] = 1;
238168963Sdeischen    }
239172729Syar
240156772SdeischenEND {
241172729Syar	if (errors) {
242172747Syar		printf("%d error(s) total.\n", errors) > stderr;
243172729Syar		exit(1);
244172729Syar	}
245172729Syar	# OK, no errors.
246156772Sdeischen	for (v in versions) {
247168963Sdeischen		print_version(v);
248156772Sdeischen	}
249156772Sdeischen}
250