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