Update Serbian translation from master branch
[wmaker-crm.git] / script / generate-mapfile-from-header.sh
blob0b82a5bb2788748c2002389539e8bb1c8fe09ce4
1 #!/bin/sh
2 ###########################################################################
4 # Window Maker window manager
6 # Copyright (c) 2014 Christophe CURIS
7 # Copyright (c) 2014-2015 Window Maker Team
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2 of the License, or
12 # (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License along
20 # with this program; if not, write to the Free Software Foundation, Inc.,
21 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 ###########################################################################
25 # generate-mapfile-from-header.sh:
26 # from a list of C header files, extract the name of the functions and
27 # global variables that are considered public for a library, and generate
28 # a 'version script' for ld with that list, so that all other symbols
29 # will be considered local.
31 # The goal is that the symbol that are not part of the public API should
32 # not be visible to the user because it can be a source of problems (from
33 # name clash to evolutivity issues).
35 ###########################################################################
37 # Please note that this script is writen in sh+awk on purpose: this script
38 # is gonna be run on the machine of the person who is trying to compile
39 # WindowMaker, and as such we cannot be sure to find any scripting language
40 # in a known version and that works (python/ruby/tcl/perl/php/you-name-it).
42 # So for portability, we stick to the same sh+awk constraint as Autotools
43 # to limit the problem, see for example:
44 # http://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Portable-Shell.html
46 ###########################################################################
48 # Report an error on stderr and exit with status 1 to tell make could not work
49 arg_error() {
50 echo "$0: $@" >&2
51 exit 1
54 # print help and exit with success status
55 print_help() {
56 echo "$0: generate a script for ld to keep only the symbols from C header"
57 echo "Usage: $0 [options...] input_file[s]"
58 echo "valid options are:"
59 echo " -l : add symbol's definition line number for debug"
60 echo " -n name : name to use for the library"
61 echo " -v version : set the library version for ld"
62 exit 0
65 # Extract command line arguments
66 while [ $# -gt 0 ]; do
67 case $1 in
68 -l)
69 debug_info=' /* " symbol_type " at " FILENAME ":" NR " */'
72 -n)
73 shift
74 echo "$1" | grep '^[A-Za-z][A-Za-z_0-9]*$' > /dev/null || arg_error "invalid name \"$1\" for a library"
75 libname="$1"
78 -v)
79 shift
80 version="$1"
81 echo "$version" | grep -E '^[1-9][0-9]*(:[0-9]+(:[0-9]+)?)?$' > /dev/null || \
82 arg_error "version \"$1\" is not valid"
85 -h|-help|--help) print_help ;;
86 -*) arg_error "unknow option '$1'" ;;
89 [ -r "$1" ] || arg_error "source file \"$1\" is not readable"
90 input_files="$input_files $1"
92 esac
93 shift
94 done
96 # Check consistency of command-line
97 [ "x$input_files" = "x" ] && arg_error "no source file given"
99 # Automatic values
100 if [ -z "$libname" ]; then
101 # build the library name from the first header name, remove path stuff, extension and invalid characters
102 libname="`echo "$input_files" | sed -e 's,^ ,,;s, .*$,,;s,^.*/\([^/]*\)$,\1,;s,\.[^.]*$,,;s,[^A-Za-z_0-9],_,g;s,^_*,,' `"
105 # Parse the input file and find the function declarations; extract the names
106 # and place them in the 'global' section so that ld will keep the symbols;
107 # generate the rest of the script so that other symbols will not be kept.
108 awk '
109 BEGIN {
110 # Version number here uses only 1 number from the full version used in libtool
111 libversion="'"$version"'";
112 if (split(libversion, subversions, ":") > 1) {
113 # Calculate [CURRENT - AGE], the goal is that the number will not
114 # change when functions are added to the API, but it will be incremented
115 # when functions are removed or argument change (which breaks compat)
116 libversion = subversions[1] - subversions[3];
119 print "/* Generated version-script for ld */";
120 print "";
121 print "'"$libname"'" libversion;
122 print "{";
123 print " global:";
126 /^#[ \t]*define/ {
127 # Ignore macro definition because their content could be mis-interpreted
128 while (/\\$/) {
129 if (getline == 0) { break; }
131 next;
134 /\/\*/ {
135 # Remove comments to avoid mis-detection
136 pos = index($0, "/*");
137 comment = substr($0, pos + 2);
138 $0 = substr($0, 1, pos - 1);
139 while (1) {
140 pos = index(comment, "*/");
141 if (pos > 0) { break; }
142 getline comment;
144 $0 = $0 substr(comment, pos + 2);
147 /extern[ \t].*;/ {
148 line = $0;
150 # Remove everything from the ";"
151 sub(/;.*$/, "", line);
153 # Check if it is a global variable
154 nb = split(line, words, /[\t *]/);
156 valid = 1;
157 for (i = 1; i < nb; i++) {
158 # If the word looks valid, do not abort
159 if (words[i] ~ /^[A-Za-z_0-9]*$/) { continue; }
161 # Treat the case were the variable is an array, and there was space(s) after the name
162 if (words[i] ~ /^\[/) { nb = i - 1; break; }
164 # If we are here, the word is not valid; we stop processing the line here but we do
165 # not use "next" so the line may match function prototype handler below
166 valid = 0;
167 break;
170 if (valid) {
171 # Remove array size, if any
172 sub(/\[.*$/, "", words[nb]);
174 if (words[nb] ~ /^[A-Za-z][A-Za-z_0-9]*$/) {
175 symbol_type = "variable";
176 print " " words[nb] ";'"$debug_info"'";
177 next;
182 /^[ \t]*typedef/ {
183 # Skip type definition because they could be mis-interpreted when it
184 # defines a prototype for a callback function
185 nb_braces = 0;
186 while (1) {
187 # Count the number of brace pairs to skip the content of the definition
188 nb = split($0, dummy_array, /\{/);
189 nb_braces = nb_braces + nb;
191 nb = split($0, dummy_array, /\}/);
192 nb_braces = nb_braces - nb;
194 # Stop when we have out count of pair of braces and there is the final ";"
195 if ((nb_braces == 0) && (dummy_array[nb] ~ /;/)) { break; }
197 if (getline == 0) {
198 break;
201 next;
204 /[\t ]\**[A-Z_a-z][A-Z_a-z0-9]*[\t ]*\(/ {
205 # Get everything until the end of the definition, to avoid mis-interpreting
206 # arguments and attributes on next lines
207 while (1) {
208 pos = index($0, ";");
209 if (pos != 0) { break; }
211 getline nxt;
212 $0 = $0 nxt;
215 # Remove the argument list
216 sub(/[ \t]*\(.*$/, "");
218 # Trim possible indentation at beginning of line
219 sub(/^[\t ]*/, "");
221 # If it does not start by a keyword, it is probably not a valid function
222 if (!/^[A-Z_a-z]/) { next; }
224 nb = split($0, words, /[\t *]/);
225 for (i = 1; i < nb; i++) {
226 # Do not consider "static" because it is used for functions to be inlined
227 if (words[i] == "static") { next; }
229 # Allow empty keyword, that were just "*"
230 if (words[i] == "") { continue; }
232 # If it does not match, it is unlikely to be a function
233 if (words[i] !~ /^[A-Z_a-z][A-Z_a-z0-9]*$/) { next; }
236 # If we arrived so far, everything looks valid and the last argument of
237 # the array contains the name of the function
238 symbol_type = "function";
239 print " " words[nb] ";'"$debug_info"'";
242 END {
243 print "";
244 print " local:";
245 print " *;";
246 print "};";
248 ' $input_files