xref: /dragonfly/share/mk/version_gen.awk (revision a8a6a9161a123c760a51db32942722249315c1ba)
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