xref: /freebsd/share/mk/version_gen.awk (revision f0cfa1b168014f56c02b83e5f28412cc5f78d117)
1ab52e991SDaniel Eischen#
2*f0cfa1b1SPedro F. Giffuni# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*f0cfa1b1SPedro F. Giffuni#
4ab52e991SDaniel Eischen# Copyright (C) 2006 Daniel M. Eischen.  All rights reserved.
5ab52e991SDaniel Eischen#
6ab52e991SDaniel Eischen# Redistribution and use in source and binary forms, with or without
7ab52e991SDaniel Eischen# modification, are permitted provided that the following conditions
8ab52e991SDaniel Eischen# are met:
9ab52e991SDaniel Eischen# 1. Redistributions of source code must retain the above copyright
10ab52e991SDaniel Eischen#    notice, this list of conditions and the following disclaimer.
11ab52e991SDaniel Eischen# 2. Redistributions in binary form must reproduce the above copyright
12ab52e991SDaniel Eischen#    notice, this list of conditions and the following disclaimer in the
13ab52e991SDaniel Eischen#    documentation and/or other materials provided with the distribution.
14ab52e991SDaniel Eischen#
15ab52e991SDaniel Eischen# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16ab52e991SDaniel Eischen# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17ab52e991SDaniel Eischen# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18ab52e991SDaniel Eischen# ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19ab52e991SDaniel Eischen# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20ab52e991SDaniel Eischen# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21ab52e991SDaniel Eischen# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22ab52e991SDaniel Eischen# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23ab52e991SDaniel Eischen# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24ab52e991SDaniel Eischen# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25ab52e991SDaniel Eischen# SUCH DAMAGE.
26ab52e991SDaniel Eischen#
27ab52e991SDaniel Eischen# $FreeBSD$
28ab52e991SDaniel Eischen#
29ab52e991SDaniel Eischen
30ab52e991SDaniel Eischen#
31ab52e991SDaniel Eischen# Make a list of all the library versions listed in the master file.
32ab52e991SDaniel Eischen#
33ab52e991SDaniel Eischen#   versions[] - array indexed by version name, contains number
34ab52e991SDaniel Eischen#                of symbols (+ 1) found for each version.
35ab52e991SDaniel Eischen#   successors[] - array index by version name, contains successor
36ab52e991SDaniel Eischen#                  version name.
37ab52e991SDaniel Eischen#   symbols[][] - array index by [version name, symbol index], contains
38ab52e991SDaniel Eischen#                 names of symbols defined for each version.
3991fb7b9bSYaroslav Tykhiy#   names[] - array index is symbol name and value is its first version seen,
4039d5a8ffSYaroslav Tykhiy#	      used to check for duplicate symbols and warn about them.
41ab52e991SDaniel Eischen#
42ab52e991SDaniel EischenBEGIN {
43ab52e991SDaniel Eischen	brackets = 0;
4491fb7b9bSYaroslav Tykhiy	errors = warns = 0;
45ab52e991SDaniel Eischen	version_count = 0;
46ab52e991SDaniel Eischen	current_version = "";
47ab52e991SDaniel Eischen	stderr = "/dev/stderr";
48ab52e991SDaniel Eischen	while (getline < vfile) {
49ab52e991SDaniel Eischen		# Strip comments.
50ab52e991SDaniel Eischen		sub("#.*$", "", $0);
51ab52e991SDaniel Eischen
5239d5a8ffSYaroslav Tykhiy		# Strip leading and trailing whitespace.
5339d5a8ffSYaroslav Tykhiy		sub("^[ \t]+", "", $0);
5439d5a8ffSYaroslav Tykhiy		sub("[ \t]+$", "", $0);
55ab52e991SDaniel Eischen
5639d5a8ffSYaroslav Tykhiy		if (/^[a-zA-Z0-9._]+[ \t]*{$/) {
5739d5a8ffSYaroslav Tykhiy			# Strip brace.
5839d5a8ffSYaroslav Tykhiy			sub("{", "", $1);
59ab52e991SDaniel Eischen			brackets++;
60ab52e991SDaniel Eischen			symver = $1;
61ab52e991SDaniel Eischen			versions[symver] = 1;
62ab52e991SDaniel Eischen			successors[symver] = "";
636f91e7a3SDaniel Eischen			generated[symver] = 0;
64ab52e991SDaniel Eischen			version_count++;
65ab52e991SDaniel Eischen		}
6639d5a8ffSYaroslav Tykhiy		else if (/^}[ \t]*[a-zA-Z0-9._]+[ \t]*;$/) {
6739d5a8ffSYaroslav Tykhiy			v = $1 != "}" ? $1 : $2;
6839d5a8ffSYaroslav Tykhiy			# Strip brace.
6939d5a8ffSYaroslav Tykhiy			sub("}", "", v);
70ab52e991SDaniel Eischen			# Strip semicolon.
7139d5a8ffSYaroslav Tykhiy			sub(";", "", v);
7239d5a8ffSYaroslav Tykhiy			if (symver == "") {
73ab52e991SDaniel Eischen				printf("File %s: Unmatched bracket.\n",
74ab52e991SDaniel Eischen				vfile) > stderr;
7539d5a8ffSYaroslav Tykhiy				errors++;
7639d5a8ffSYaroslav Tykhiy			}
7739d5a8ffSYaroslav Tykhiy			else if (versions[v] != 1) {
7839d5a8ffSYaroslav Tykhiy				printf("File %s: `%s' has unknown " \
7939d5a8ffSYaroslav Tykhiy				    "successor `%s'.\n",
8039d5a8ffSYaroslav Tykhiy				    vfile, symver, v) > stderr;
8139d5a8ffSYaroslav Tykhiy				errors++;
8239d5a8ffSYaroslav Tykhiy			}
8339d5a8ffSYaroslav Tykhiy			else
8439d5a8ffSYaroslav Tykhiy				successors[symver] = v;
8539d5a8ffSYaroslav Tykhiy			brackets--;
8639d5a8ffSYaroslav Tykhiy		}
8739d5a8ffSYaroslav Tykhiy		else if (/^}[ \t]*;$/) {
8839d5a8ffSYaroslav Tykhiy			if (symver == "") {
8939d5a8ffSYaroslav Tykhiy				printf("File %s: Unmatched bracket.\n",
9039d5a8ffSYaroslav Tykhiy				    vfile) > stderr;
9139d5a8ffSYaroslav Tykhiy				errors++;
9239d5a8ffSYaroslav Tykhiy			}
93ab52e991SDaniel Eischen			# No successor
94ab52e991SDaniel Eischen			brackets--;
95ab52e991SDaniel Eischen		}
9639d5a8ffSYaroslav Tykhiy		else if (/^}$/) {
9739d5a8ffSYaroslav Tykhiy			printf("File %s: Missing final semicolon.\n",
98ab52e991SDaniel Eischen			    vfile) > stderr;
9939d5a8ffSYaroslav Tykhiy			errors++;
100ab52e991SDaniel Eischen		}
101ab52e991SDaniel Eischen		else if (/^$/)
102ab52e991SDaniel Eischen			;  # Ignore blank lines.
10339d5a8ffSYaroslav Tykhiy		else {
10439d5a8ffSYaroslav Tykhiy			printf("File %s: Unknown directive: `%s'.\n",
105ab52e991SDaniel Eischen			    vfile, $0) > stderr;
10639d5a8ffSYaroslav Tykhiy			errors++;
10739d5a8ffSYaroslav Tykhiy		}
108ab52e991SDaniel Eischen	}
109ab52e991SDaniel Eischen	brackets = 0;
110ab52e991SDaniel Eischen}
111ab52e991SDaniel Eischen
11239d5a8ffSYaroslav Tykhiy{
11339d5a8ffSYaroslav Tykhiy	# Set meaningful filename for diagnostics.
11439d5a8ffSYaroslav Tykhiy	filename = FILENAME != "" ? FILENAME : "<stdin>";
11539d5a8ffSYaroslav Tykhiy
116ab52e991SDaniel Eischen	# Delete comments, preceding and trailing whitespace, then
117ab52e991SDaniel Eischen	# consume blank lines.
118ab52e991SDaniel Eischen	sub("#.*$", "", $0);
119ab52e991SDaniel Eischen	sub("^[ \t]+", "", $0);
120ab52e991SDaniel Eischen	sub("[ \t]+$", "", $0);
121ab52e991SDaniel Eischen	if ($0 == "")
122ab52e991SDaniel Eischen		next;
123ab52e991SDaniel Eischen}
124ab52e991SDaniel Eischen
12539d5a8ffSYaroslav Tykhiy/^[a-zA-Z0-9._]+[ \t]*{$/ {
126ab52e991SDaniel Eischen	# Strip bracket from version name.
127ab52e991SDaniel Eischen	sub("{", "", $1);
12839d5a8ffSYaroslav Tykhiy	if (current_version != "") {
129ab52e991SDaniel Eischen		printf("File %s, line %d: Illegal nesting detected.\n",
13039d5a8ffSYaroslav Tykhiy		    filename, FNR) > stderr;
13139d5a8ffSYaroslav Tykhiy		errors++;
13239d5a8ffSYaroslav Tykhiy	}
133ab52e991SDaniel Eischen	else if (versions[$1] == 0) {
134ab52e991SDaniel Eischen		printf("File %s, line %d: Undefined " \
13539d5a8ffSYaroslav Tykhiy		    "library version `%s'.\n", filename, FNR, $1) > stderr;
13639d5a8ffSYaroslav Tykhiy		errors++;
137ab52e991SDaniel Eischen		# Remove this entry from the versions.
138ab52e991SDaniel Eischen		delete versions[$1];
139ab52e991SDaniel Eischen	}
140ab52e991SDaniel Eischen	else
141ab52e991SDaniel Eischen		current_version = $1;
142ab52e991SDaniel Eischen	brackets++;
143ab52e991SDaniel Eischen	next;
144ab52e991SDaniel Eischen}
145ab52e991SDaniel Eischen
14639d5a8ffSYaroslav Tykhiy/^[a-zA-Z0-9._]+[ \t]*;$/ {
14739d5a8ffSYaroslav Tykhiy	# Strip semicolon.
14839d5a8ffSYaroslav Tykhiy	sub(";", "", $1);
149ab52e991SDaniel Eischen	if (current_version != "") {
150ab52e991SDaniel Eischen		count = versions[current_version];
151ab52e991SDaniel Eischen		versions[current_version]++;
152ab52e991SDaniel Eischen		symbols[current_version, count] = $1;
15391fb7b9bSYaroslav Tykhiy		if ($1 in names && names[$1] != current_version) {
15491fb7b9bSYaroslav Tykhiy			#
15591fb7b9bSYaroslav Tykhiy			# A graver case when a dup symbol appears under
15691fb7b9bSYaroslav Tykhiy			# different versions in the map.  That can result
15791fb7b9bSYaroslav Tykhiy			# in subtle problems with the library later.
15891fb7b9bSYaroslav Tykhiy			#
15991fb7b9bSYaroslav Tykhiy			printf("File %s, line %d: Duplicated symbol `%s' " \
16091fb7b9bSYaroslav Tykhiy			    "in version `%s', first seen in `%s'. " \
16139d5a8ffSYaroslav Tykhiy			    "Did you forget to move it to ObsoleteVersions?\n",
16291fb7b9bSYaroslav Tykhiy			    filename, FNR, $1,
16391fb7b9bSYaroslav Tykhiy			    current_version, names[$1]) > stderr;
16439d5a8ffSYaroslav Tykhiy			errors++;
16539d5a8ffSYaroslav Tykhiy		}
16691fb7b9bSYaroslav Tykhiy		else if (names[$1] == current_version) {
16791fb7b9bSYaroslav Tykhiy			#
16891fb7b9bSYaroslav Tykhiy			# A harmless case: a dup symbol with the same version.
16991fb7b9bSYaroslav Tykhiy			#
17091fb7b9bSYaroslav Tykhiy			printf("File %s, line %d: warning: " \
17191fb7b9bSYaroslav Tykhiy			    "Duplicated symbol `%s' in version `%s'.\n",
17291fb7b9bSYaroslav Tykhiy			    filename, FNR, $1, current_version) > stderr;
17391fb7b9bSYaroslav Tykhiy			warns++;
17491fb7b9bSYaroslav Tykhiy		}
17591fb7b9bSYaroslav Tykhiy		else
17691fb7b9bSYaroslav Tykhiy			names[$1] = current_version;
17739d5a8ffSYaroslav Tykhiy	}
17839d5a8ffSYaroslav Tykhiy	else {
17939d5a8ffSYaroslav Tykhiy		printf("File %s, line %d: Symbol `%s' outside version scope.\n",
18039d5a8ffSYaroslav Tykhiy		    filename, FNR, $1) > stderr;
18139d5a8ffSYaroslav Tykhiy		errors++;
182ab52e991SDaniel Eischen	}
183ab52e991SDaniel Eischen	next;
184ab52e991SDaniel Eischen}
185ab52e991SDaniel Eischen
18639d5a8ffSYaroslav Tykhiy/^}[ \t]*;$/ {
187ab52e991SDaniel Eischen	brackets--;
188ab52e991SDaniel Eischen	if (brackets < 0) {
189ab52e991SDaniel Eischen		printf("File %s, line %d: Unmatched bracket.\n",
19039d5a8ffSYaroslav Tykhiy		    filename, FNR, $1) > stderr;
19139d5a8ffSYaroslav Tykhiy		errors++;
192ab52e991SDaniel Eischen		brackets = 0;	# Reset
193ab52e991SDaniel Eischen	}
194ab52e991SDaniel Eischen	current_version = "";
195ab52e991SDaniel Eischen	next;
196ab52e991SDaniel Eischen}
197ab52e991SDaniel Eischen
198ab52e991SDaniel Eischen
19939d5a8ffSYaroslav Tykhiy{
20039d5a8ffSYaroslav Tykhiy	printf("File %s, line %d: Unknown directive: `%s'.\n",
20139d5a8ffSYaroslav Tykhiy	    filename, FNR, $0) > stderr;
20239d5a8ffSYaroslav Tykhiy	errors++;
203ab52e991SDaniel Eischen}
204ab52e991SDaniel Eischen
2056f91e7a3SDaniel Eischenfunction print_version(v)
2066f91e7a3SDaniel Eischen{
2076f91e7a3SDaniel Eischen	# This function is recursive, so return if this version
2086f91e7a3SDaniel Eischen	# has already been printed.  Otherwise, if there is an
2096f91e7a3SDaniel Eischen	# ancestral version, recursively print its symbols before
2106f91e7a3SDaniel Eischen	# printing the symbols for this version.
2116f91e7a3SDaniel Eischen	#
2126f91e7a3SDaniel Eischen	if (generated[v] == 1)
2136f91e7a3SDaniel Eischen		return;
2146f91e7a3SDaniel Eischen	if (successors[v] != "")
2156f91e7a3SDaniel Eischen		print_version(successors[v]);
2166f91e7a3SDaniel Eischen
217ab52e991SDaniel Eischen	printf("%s {\n", v);
218ab52e991SDaniel Eischen
219ab52e991SDaniel Eischen	# The version count is always one more that actual,
220ab52e991SDaniel Eischen	# so the loop ranges from 1 to n-1.
221ab52e991SDaniel Eischen	#
222ab52e991SDaniel Eischen	for (i = 1; i < versions[v]; i++) {
223ab52e991SDaniel Eischen		if (i == 1)
224ab52e991SDaniel Eischen			printf("global:\n");
22539d5a8ffSYaroslav Tykhiy		printf("\t%s;\n", symbols[v, i]);
226ab52e991SDaniel Eischen	}
2279f408248SAlexander Kabaev
2289f408248SAlexander Kabaev	version_count--;
2299f408248SAlexander Kabaev	if (version_count == 0) {
230ab52e991SDaniel Eischen		printf("local:\n");
231ab52e991SDaniel Eischen		printf("\t*;\n");
232ab52e991SDaniel Eischen	}
2339f408248SAlexander Kabaev	if (successors[v] == "")
2349f408248SAlexander Kabaev		printf("};\n");
235ab52e991SDaniel Eischen	else
236ab52e991SDaniel Eischen		printf("} %s;\n", successors[v]);
2376f91e7a3SDaniel Eischen	printf("\n");
2386f91e7a3SDaniel Eischen
2396f91e7a3SDaniel Eischen	generated[v] = 1;
2406f91e7a3SDaniel Eischen    }
24139d5a8ffSYaroslav Tykhiy
2426f91e7a3SDaniel EischenEND {
24339d5a8ffSYaroslav Tykhiy	if (errors) {
24491fb7b9bSYaroslav Tykhiy		printf("%d error(s) total.\n", errors) > stderr;
24539d5a8ffSYaroslav Tykhiy		exit(1);
24639d5a8ffSYaroslav Tykhiy	}
24739d5a8ffSYaroslav Tykhiy	# OK, no errors.
2486f91e7a3SDaniel Eischen	for (v in versions) {
2496f91e7a3SDaniel Eischen		print_version(v);
250ab52e991SDaniel Eischen	}
251ab52e991SDaniel Eischen}
252