1 #!/bin/ksh
2 #
3 # CDDL HEADER START
4 #
5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
8 #
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
13 #
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
19 #
20 # CDDL HEADER END
21 #
22 #
23 # Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 # Use is subject to license terms.
25 #
26
27 #
28 # Given a header file, extract function prototypes and global variable
29 # declarations in a form that can be used in a mapfile. The list of extracted
30 # functions and variables will be combined with a user-specified template to
31 # create a complete mapfile.
32 #
33 # Template
34 # --------
35 #
36 # The template contains two sections - the prologue, and the epilogue. These
37 # sections are used, verbatim, as the beginning and the end of the mapfile.
38 # Sections begin and end with single-line comments whose sole contents are
39 # "/* BEGIN $section */" and "/* END $section */".
40 #
41 # Template example:
42 #
43 # /* BEGIN PROLOGUE */
44 # [ ... prologue goes here ... ]
45 # /* END PROLOGUE */
46 # /* BEGIN EPILOGUE */
47 # [ ... epilogue goes here ... ]
48 # /* END EPILOGUE */
49 #
50 # Selective Exportation
51 # ---------------------
52 #
53 # Some header files will have a public/private interface mix that is strongly
54 # biased towards private interfaces. That is, of the interfaces declared by
55 # a given header file, the majority of them are private. Only a small subset
56 # of interfaces are to be exported publicly. Using Selective Exportation, a
57 # special comment is included in the header file, declaring to this script that
58 # only a subset of interfaces - those with a marking declared in the comment -
59 # should be included in the mapfile. The marking is itself a special comment,
60 # whose format is declared using a directive like this:
61 #
62 # MAPFILE: export "Driver OK"
63 #
64 # Using the above directive, only those function prototypes and variable
65 # declarations with "/* Driver OK */" comments included in the mapfile. Note
66 # that the comment must be at the end of the first line. If the declaration
67 # spans multiple lines, the exportation comment must appear on the first line.
68 #
69 # Examples of functions selected for exportation:
70 #
71 # MAPFILE: export "Driver OK"
72 #
73 # extern int foo(int); /* Driver OK */
74 # extern void bar(int, int, /* Driver OK */
75 # int, void *);
76 #
77 # Selective Exportation may not be used in the same file as Selective Exclusion.
78 #
79 # Selective Exclusion
80 # -------------------
81 #
82 # Selective Exclusion is to be used in cases where the public/private interface
83 # mix is reversed - where public interfaces greatly outnumber the private ones.
84 # In this case, we want to be able to mark the private ones, thus telling this
85 # script that the marked interfaces are to be excluded from the mapfile.
86 # Marking is accomplished via a process similar to that used for Selective
87 # Exportation. A directive is included in a comment, and is formatted like
88 # this:
89 #
90 # MAPFILE: exclude "Internal"
91 #
92 # Using the above directive, function prototypes and variable declarations with
93 # "/* Internal */" comments would be excluded. Note that the comment must be at
94 # the end of the first line. If the declaration spans multiple lines, the
95 # exclusion comment must appear on the first line.
96 #
97 # Examples of functions excluded from exportation:
98 #
99 # MAPFILE: exclude "Internal"
100 #
101 # extern int foo(int); /* Internal */
102 # extern void bar(int, int, /* Internal */
103 # int, void *);
104 #
105 # Selective Exclusion may not be used in the same file as Selective Exportation.
106 #
107
108 function extract_prototypes
109 {
110 typeset header="$1"
111 typeset prefix="$2"
112
113 /usr/xpg4/bin/awk -v prefix="$prefix" <$header '
114 /^.*MAPFILE: export \"[^\"]*\"$/ {
115 if (protoexclude) {
116 print "ERROR: export after exclude\n";
117 exit(1);
118 }
119
120 sub(/^[^\"]*\"/, "");
121 sub(/\"$/, "");
122
123 exportmark=sprintf("/* %s */", $0);
124 next;
125 }
126
127 /^.*MAPFILE: exclude \"[^\"]*\"$/ {
128 if (protomatch) {
129 print "ERROR: exclude after export";
130 exit(1);
131 }
132
133 sub(/^[^\"]*\"/, "");
134 sub(/\"$/, "");
135
136 excludemark=sprintf("/* %s */", $0);
137 next;
138 }
139
140 exportmark {
141 # Selective Exportation has been selected (exportmark is
142 # set), so exclude this line if it does not have the
143 # magic export mark.
144 if (length($0) < length(exportmark) ||
145 substr($0, length($0) - length(exportmark) + 1) != \
146 exportmark)
147 next;
148 }
149
150 excludemark {
151 # Selective Exclusion has been selected (excludemark is
152 # set), so exclude this line only if it has the magic
153 # exclude mark.
154 if (length($0) > length(excludemark) &&
155 substr($0, \
156 length($0) - length(excludemark) + 1) == \
157 excludemark)
158 next;
159 }
160
161 # Functions
162 /^extern.*\(/ {
163 for (i = 1; i <= NF; i++) {
164 if (sub(/\(.*$/, "", $i)) {
165 sub(/^\*/, "", $i);
166 if (!seenfn[$i]) {
167 printf("%s%s;\n", prefix, $i);
168 seenfn[$i] = 1;
169 }
170 break;
171 }
172 }
173 next;
174 }
175
176 # Global variables
177 /^extern[^\(\)]*;/ {
178 for (i = 1; i <= NF; i++) {
179 if (match($i, /;$/)) {
180 printf("%s%s; /* variable */\n", prefix,
181 substr($i, 1, length($i) - 1));
182 break;
183 }
184 }
185 next;
186 }
187 ' || die "Extraction failed"
188 }
189
190 function extract_section
191 {
192 typeset skel="$1"
193 typeset secname="$2"
194
195 /usr/xpg4/bin/awk <$skel -v name=$secname -v skel=$skel '
196 /\/\* [^ ]* [^ ]* \*\// && $3 == name {
197 if ($2 == "BEGIN") {
198 printing = 1;
199 } else {
200 printing = 0;
201 }
202 next;
203 }
204
205 printing != 0 { print; }
206 '
207 }
208
209 function die
210 {
211 echo "$PROGNAME: $@" >&2
212 exit 1
213 }
214
215 function usage
216 {
217 echo "Usage: $PROGNAME -t tmplfile header [header ...]" >&2
218 exit 2
219 }
220
221 PROGNAME=$(basename "$0")
222
223 while getopts t: c ; do
224 case $c in
225 t)
226 mapfile_skel=$OPTARG
227 ;;
228 ?)
229 usage
230 esac
231 done
232
233 [[ -z "$mapfile_skel" ]] && usage
234 [[ ! -f $mapfile_skel ]] && die "Couldn't open template $tmplfile"
235
236 shift $(($OPTIND - 1))
237
238 [[ $# -lt 1 ]] && usage
239
240 for file in $@ ; do
241 [[ ! -f $file ]] && die "Can't open input file $file"
242 done
243
244 extract_section $mapfile_skel PROLOGUE
245
246 for file in $@ ; do
247 echo "\t\t/*"
248 echo "\t\t * Exported functions and variables from:"
249 echo "\t\t * $file"
250 echo "\t\t */"
251 extract_prototypes $file "\t\t"
252 echo
253 done
254
255 extract_section $mapfile_skel EPILOGUE