| 1 | #!/usr/bin/perl
 | 
|---|
| 2 | # Simple script for generating prototypes for C functions
 | 
|---|
| 3 | # Written by Jelmer Vernooij
 | 
|---|
| 4 | # based on the original mkproto.sh by Andrew Tridgell
 | 
|---|
| 5 | 
 | 
|---|
| 6 | use strict;
 | 
|---|
| 7 | 
 | 
|---|
| 8 | # don't use warnings module as it is not portable enough
 | 
|---|
| 9 | # use warnings;
 | 
|---|
| 10 | 
 | 
|---|
| 11 | use Getopt::Long;
 | 
|---|
| 12 | use File::Basename;
 | 
|---|
| 13 | use File::Path;
 | 
|---|
| 14 | 
 | 
|---|
| 15 | #####################################################################
 | 
|---|
| 16 | # read a file into a string
 | 
|---|
| 17 | 
 | 
|---|
| 18 | my $public_file = undef;
 | 
|---|
| 19 | my $private_file = undef;
 | 
|---|
| 20 | my $all_file = undef;
 | 
|---|
| 21 | my $public_define = undef;
 | 
|---|
| 22 | my $private_define = undef;
 | 
|---|
| 23 | my $_public = "";
 | 
|---|
| 24 | my $_private = "";
 | 
|---|
| 25 | my $public_data = \$_public;
 | 
|---|
| 26 | my $private_data = \$_private;
 | 
|---|
| 27 | my $builddir = ".";
 | 
|---|
| 28 | my $srcdir = ".";
 | 
|---|
| 29 | 
 | 
|---|
| 30 | sub public($)
 | 
|---|
| 31 | {
 | 
|---|
| 32 |         my ($d) = @_;
 | 
|---|
| 33 |         $$public_data .= $d;
 | 
|---|
| 34 | }
 | 
|---|
| 35 | 
 | 
|---|
| 36 | sub private($)
 | 
|---|
| 37 | {
 | 
|---|
| 38 |         my ($d) = @_;
 | 
|---|
| 39 |         $$private_data .= $d;
 | 
|---|
| 40 | }
 | 
|---|
| 41 | 
 | 
|---|
| 42 | sub usage()
 | 
|---|
| 43 | {
 | 
|---|
| 44 |         print "Usage: mkproto.pl [options] [c files]\n";
 | 
|---|
| 45 |         print "OPTIONS:\n";
 | 
|---|
| 46 |         print "  --public=FILE          Write prototypes for public functions to FILE\n";
 | 
|---|
| 47 |         print "  --private=FILE         Write prototypes for private functions to FILE\n";
 | 
|---|
| 48 |         print "  --define=DEF           Use DEF to check whether header was already included\n";
 | 
|---|
| 49 |         print "  --public-define=DEF    Same as --define, but just for public header\n";
 | 
|---|
| 50 |         print "  --private-define=DEF   Same as --define, but just for private header\n";
 | 
|---|
| 51 |         print "  --srcdir=path          Read files relative to this directory\n";
 | 
|---|
| 52 |         print "  --builddir=path        Write file relative to this directory\n";
 | 
|---|
| 53 |         print "  --help                 Print this help message\n\n";
 | 
|---|
| 54 |         exit 0;
 | 
|---|
| 55 | }
 | 
|---|
| 56 | 
 | 
|---|
| 57 | GetOptions(
 | 
|---|
| 58 |         'public=s' => sub { my ($f,$v) = @_; $public_file = $v; },
 | 
|---|
| 59 |         'all=s' => sub { my ($f,$v) = @_; $public_file = $v; $private_file = $v; },
 | 
|---|
| 60 |         'private=s' => sub { my ($f,$v) = @_; $private_file = $v; },
 | 
|---|
| 61 |         'define=s' => sub { 
 | 
|---|
| 62 |                 my ($f,$v) = @_; 
 | 
|---|
| 63 |                 $public_define = $v; 
 | 
|---|
| 64 |                 $private_define = "$v\_PRIVATE"; 
 | 
|---|
| 65 |         },
 | 
|---|
| 66 |         'public-define=s' => \$public_define,
 | 
|---|
| 67 |         'private-define=s' => \$private_define,
 | 
|---|
| 68 |         'srcdir=s' => sub { my ($f,$v) = @_; $srcdir = $v; },
 | 
|---|
| 69 |         'builddir=s' => sub { my ($f,$v) = @_; $builddir = $v; },
 | 
|---|
| 70 |         'help' => \&usage
 | 
|---|
| 71 | ) or exit(1);
 | 
|---|
| 72 | 
 | 
|---|
| 73 | sub normalize_define($$)
 | 
|---|
| 74 | {
 | 
|---|
| 75 |         my ($define, $file) = @_;
 | 
|---|
| 76 | 
 | 
|---|
| 77 |         if (not defined($define) and defined($file)) {
 | 
|---|
| 78 |                 $define = "__" . uc($file) . "__";
 | 
|---|
| 79 |                 $define =~ tr{./}{__};
 | 
|---|
| 80 |                 $define =~ tr{\-}{_};
 | 
|---|
| 81 |         } elsif (not defined($define)) {
 | 
|---|
| 82 |                 $define = '_PROTO_H_';
 | 
|---|
| 83 |         }
 | 
|---|
| 84 | 
 | 
|---|
| 85 |         return $define;
 | 
|---|
| 86 | }
 | 
|---|
| 87 | 
 | 
|---|
| 88 | $public_define = normalize_define($public_define, $public_file);
 | 
|---|
| 89 | $private_define = normalize_define($private_define, $private_file);
 | 
|---|
| 90 | 
 | 
|---|
| 91 | if ((defined($private_file) and defined($public_file) and ($private_file eq $public_file)) or 
 | 
|---|
| 92 |         (not defined($private_file) and not defined($public_file))) {
 | 
|---|
| 93 |         $private_data = $public_data;
 | 
|---|
| 94 | }
 | 
|---|
| 95 | 
 | 
|---|
| 96 | sub file_load($)
 | 
|---|
| 97 | {
 | 
|---|
| 98 |     my($filename) = @_;
 | 
|---|
| 99 |     local(*INPUTFILE);
 | 
|---|
| 100 |     open(INPUTFILE, $filename) or return undef;
 | 
|---|
| 101 |     my($saved_delim) = $/;
 | 
|---|
| 102 |     undef $/;
 | 
|---|
| 103 |     my($data) = <INPUTFILE>;
 | 
|---|
| 104 |     close(INPUTFILE);
 | 
|---|
| 105 |     $/ = $saved_delim;
 | 
|---|
| 106 |     return $data;
 | 
|---|
| 107 | }
 | 
|---|
| 108 | 
 | 
|---|
| 109 | sub print_header($$)
 | 
|---|
| 110 | {
 | 
|---|
| 111 |         my ($file, $header_name) = @_;
 | 
|---|
| 112 |         $file->("#ifndef $header_name\n");
 | 
|---|
| 113 |         $file->("#define $header_name\n\n");
 | 
|---|
| 114 |         $file->("#undef _PRINTF_ATTRIBUTE\n");
 | 
|---|
| 115 |         $file->("#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2)\n");
 | 
|---|
| 116 |         $file->("/* This file was automatically generated by mkproto.pl. DO NOT EDIT */\n\n");
 | 
|---|
| 117 | }
 | 
|---|
| 118 | 
 | 
|---|
| 119 | sub print_footer($$) 
 | 
|---|
| 120 | {
 | 
|---|
| 121 |         my ($file, $header_name) = @_;
 | 
|---|
| 122 |         $file->("#undef _PRINTF_ATTRIBUTE\n");
 | 
|---|
| 123 |         $file->("#define _PRINTF_ATTRIBUTE(a1, a2)\n");
 | 
|---|
| 124 |         $file->("\n#endif /* $header_name */\n\n");
 | 
|---|
| 125 | }
 | 
|---|
| 126 | 
 | 
|---|
| 127 | sub handle_loadparm($$) 
 | 
|---|
| 128 | {
 | 
|---|
| 129 |         my ($file,$line) = @_;
 | 
|---|
| 130 | 
 | 
|---|
| 131 |         if ($line =~ /^_PUBLIC_ FN_(GLOBAL|LOCAL)_(CONST_STRING|STRING|BOOL|bool|CHAR|INTEGER|LIST)\((\w+),.*\)/o) {
 | 
|---|
| 132 |                 my $scope = $1;
 | 
|---|
| 133 |                 my $type = $2;
 | 
|---|
| 134 |                 my $name = $3;
 | 
|---|
| 135 | 
 | 
|---|
| 136 |                 my %tmap = (
 | 
|---|
| 137 |                             "BOOL" => "bool ",
 | 
|---|
| 138 |                             "CONST_STRING" => "const char *",
 | 
|---|
| 139 |                             "STRING" => "const char *",
 | 
|---|
| 140 |                             "INTEGER" => "int ",
 | 
|---|
| 141 |                             "CHAR" => "char ",
 | 
|---|
| 142 |                             "LIST" => "const char **",
 | 
|---|
| 143 |                             );
 | 
|---|
| 144 | 
 | 
|---|
| 145 |                 my %smap = (
 | 
|---|
| 146 |                             "GLOBAL" => "struct loadparm_context *",
 | 
|---|
| 147 |                             "LOCAL" => "struct loadparm_service *, struct loadparm_service *"
 | 
|---|
| 148 |                             );
 | 
|---|
| 149 | 
 | 
|---|
| 150 |                 $file->("$tmap{$type}$name($smap{$scope});\n");
 | 
|---|
| 151 |         }
 | 
|---|
| 152 | }
 | 
|---|
| 153 | 
 | 
|---|
| 154 | sub process_file($$$) 
 | 
|---|
| 155 | {
 | 
|---|
| 156 |         my ($public_file, $private_file, $filename) = @_;
 | 
|---|
| 157 | 
 | 
|---|
| 158 |         $filename =~ s/\.o$/\.c/g;
 | 
|---|
| 159 | 
 | 
|---|
| 160 |         if ($filename =~ /^\//) {
 | 
|---|
| 161 |                 open(FH, "<$filename") or die("Failed to open $filename");
 | 
|---|
| 162 |         } elsif (!open(FH, "< $builddir/$filename")) {
 | 
|---|
| 163 |             open(FH, "< $srcdir/$filename") || die "Failed to open $filename";
 | 
|---|
| 164 |         }
 | 
|---|
| 165 | 
 | 
|---|
| 166 |         $private_file->("\n/* The following definitions come from $filename  */\n\n");
 | 
|---|
| 167 | 
 | 
|---|
| 168 |         my $comment = undef;
 | 
|---|
| 169 |         my $incomment = 0;
 | 
|---|
| 170 |         while (my $line = <FH>) {             
 | 
|---|
| 171 |                 my $target = \&private;
 | 
|---|
| 172 |                 my $is_public = 0;
 | 
|---|
| 173 | 
 | 
|---|
| 174 |                 if ($line =~ /^\/\*\*/) { 
 | 
|---|
| 175 |                         $comment = "";
 | 
|---|
| 176 |                         $incomment = 1;
 | 
|---|
| 177 |                 }
 | 
|---|
| 178 | 
 | 
|---|
| 179 |                 if ($incomment) {
 | 
|---|
| 180 |                         $comment .= $line;
 | 
|---|
| 181 |                         if ($line =~ /\*\//) {
 | 
|---|
| 182 |                                 $incomment = 0;
 | 
|---|
| 183 |                         }
 | 
|---|
| 184 |                 } 
 | 
|---|
| 185 | 
 | 
|---|
| 186 |                 # these are ordered for maximum speed
 | 
|---|
| 187 |                 next if ($line =~ /^\s/);
 | 
|---|
| 188 |               
 | 
|---|
| 189 |                 next unless ($line =~ /\(/);
 | 
|---|
| 190 | 
 | 
|---|
| 191 |                 next if ($line =~ /^\/|[;]/);
 | 
|---|
| 192 | 
 | 
|---|
| 193 |                 if ($line =~ /^_PUBLIC_ FN_/) {
 | 
|---|
| 194 |                         handle_loadparm($public_file, $line);
 | 
|---|
| 195 |                         handle_loadparm($private_file, $line);
 | 
|---|
| 196 |                         next;
 | 
|---|
| 197 |                 }
 | 
|---|
| 198 | 
 | 
|---|
| 199 |                 if ($line =~ /^_PUBLIC_[\t ]/) {
 | 
|---|
| 200 |                         $target = \&public;
 | 
|---|
| 201 |                         $is_public = 1;
 | 
|---|
| 202 |                 }
 | 
|---|
| 203 | 
 | 
|---|
| 204 |                 next unless ( $is_public || $line =~ /
 | 
|---|
| 205 |                               ^(_DEPRECATED_ |_NORETURN_ |_WARN_UNUSED_RESULT_ |_PURE_ )*(
 | 
|---|
| 206 |                                   void|bool|int|struct|char|const|\w+_[tT]\s|uint|unsigned|long|NTSTATUS|
 | 
|---|
| 207 |                                   ADS_STATUS|enum\s.*\(|DATA_BLOB|WERROR|XFILE|FILE|DIR|
 | 
|---|
| 208 |                               double|TDB_CONTEXT|TDB_DATA|TALLOC_CTX|NTTIME|FN_|init_module|
 | 
|---|
| 209 |                               GtkWidget|GType|smb_ucs2_t|krb5_error_code|NET_API_STATUS)
 | 
|---|
| 210 |                               /xo);
 | 
|---|
| 211 | 
 | 
|---|
| 212 |                 next if ($line =~ /^int\s*main/);
 | 
|---|
| 213 | 
 | 
|---|
| 214 |                 $target->("\n$comment") if (defined($comment)); $comment = undef;
 | 
|---|
| 215 | 
 | 
|---|
| 216 |                 if ( $line =~ /\(.*\)\s*$/o ) {
 | 
|---|
| 217 |                         chomp $line;
 | 
|---|
| 218 |                         $target->("$line;\n");
 | 
|---|
| 219 |                         next;
 | 
|---|
| 220 |                 }
 | 
|---|
| 221 | 
 | 
|---|
| 222 |                 $target->($line);
 | 
|---|
| 223 | 
 | 
|---|
| 224 |                 while ($line = <FH>) {
 | 
|---|
| 225 |                         if ($line =~ /\)\s*$/o) {
 | 
|---|
| 226 |                                 chomp $line;
 | 
|---|
| 227 |                                 $target->("$line;\n");
 | 
|---|
| 228 |                                 last;
 | 
|---|
| 229 |                         }
 | 
|---|
| 230 |                         $target->($line);
 | 
|---|
| 231 |                 }
 | 
|---|
| 232 |         }
 | 
|---|
| 233 | 
 | 
|---|
| 234 |         close(FH);
 | 
|---|
| 235 | }
 | 
|---|
| 236 | 
 | 
|---|
| 237 | 
 | 
|---|
| 238 | print_header(\&public, $public_define);
 | 
|---|
| 239 | if (defined($private_file) and defined($public_file) and $public_file ne $private_file) {
 | 
|---|
| 240 |         print_header(\&private, $private_define);
 | 
|---|
| 241 | 
 | 
|---|
| 242 |         private("/* this file contains prototypes for functions that " .
 | 
|---|
| 243 |                         "are private \n * to this subsystem or library. These functions " .
 | 
|---|
| 244 |                         "should not be \n * used outside this particular subsystem! */\n\n");
 | 
|---|
| 245 | 
 | 
|---|
| 246 |         public("/* this file contains prototypes for functions that " . 
 | 
|---|
| 247 |                         "are part of \n * the public API of this subsystem or library. */\n\n");
 | 
|---|
| 248 | 
 | 
|---|
| 249 | }
 | 
|---|
| 250 | 
 | 
|---|
| 251 | public("#ifndef _PUBLIC_\n#define _PUBLIC_\n#endif\n\n");
 | 
|---|
| 252 | public("#ifndef _PURE_\n#define _PURE_\n#endif\n\n");
 | 
|---|
| 253 | public("#ifndef _NORETURN_\n#define _NORETURN_\n#endif\n\n");
 | 
|---|
| 254 | public("#ifndef _DEPRECATED_\n#define _DEPRECATED_\n#endif\n\n");
 | 
|---|
| 255 | public("#ifndef _WARN_UNUSED_RESULT_\n#define _WARN_UNUSED_RESULT_\n#endif\n\n");
 | 
|---|
| 256 | 
 | 
|---|
| 257 | process_file(\&public, \&private, $_) foreach (@ARGV);
 | 
|---|
| 258 | print_footer(\&public, $public_define);
 | 
|---|
| 259 | if (defined($private_file) and $public_file ne $private_file) {
 | 
|---|
| 260 |         print_footer(\&private, $private_define);
 | 
|---|
| 261 | }
 | 
|---|
| 262 | 
 | 
|---|
| 263 | if (not defined($public_file)) {
 | 
|---|
| 264 |         print STDOUT $$public_data;
 | 
|---|
| 265 | }
 | 
|---|
| 266 | 
 | 
|---|
| 267 | if (not defined($private_file) and defined($public_file)) {
 | 
|---|
| 268 |         print STDOUT $$private_data;
 | 
|---|
| 269 | }
 | 
|---|
| 270 | 
 | 
|---|
| 271 | mkpath(dirname($public_file), 0, 0755);
 | 
|---|
| 272 | open(PUBLIC, ">$public_file") or die("Can't open `$public_file': $!"); 
 | 
|---|
| 273 | print PUBLIC "$$public_data";
 | 
|---|
| 274 | close(PUBLIC);
 | 
|---|
| 275 | 
 | 
|---|
| 276 | if (defined($private_file) and $public_file ne $private_file) {
 | 
|---|
| 277 |         mkpath(dirname($private_file), 0, 0755);
 | 
|---|
| 278 |         open(PRIVATE, ">$private_file") or die("Can't open `$private_file': $!"); 
 | 
|---|
| 279 |         print PRIVATE "$$private_data";
 | 
|---|
| 280 |         close(PRIVATE);
 | 
|---|
| 281 | }
 | 
|---|