| 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 | } | 
|---|