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