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