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