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 6use strict; 7 8# don't use warnings module as it is not portable enough 9# use warnings; 10 11use Getopt::Long; 12use File::Basename; 13use File::Path; 14 15##################################################################### 16# read a file into a string 17 18my $public_file = undef; 19my $private_file = undef; 20my $all_file = undef; 21my $public_define = undef; 22my $private_define = undef; 23my $_public = ""; 24my $_private = ""; 25my $public_data = \$_public; 26my $private_data = \$_private; 27my $builddir = "."; 28my $srcdir = "."; 29 30sub public($) 31{ 32 my ($d) = @_; 33 $$public_data .= $d; 34} 35 36sub private($) 37{ 38 my ($d) = @_; 39 $$private_data .= $d; 40} 41 42sub 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 57GetOptions( 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 73sub 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 91if ((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 96sub 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 109sub 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 119sub 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 127sub 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 154sub 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 238print_header(\&public, $public_define); 239if (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 251public("#ifndef _PUBLIC_\n#define _PUBLIC_\n#endif\n\n"); 252public("#ifndef _PURE_\n#define _PURE_\n#endif\n\n"); 253public("#ifndef _NORETURN_\n#define _NORETURN_\n#endif\n\n"); 254public("#ifndef _DEPRECATED_\n#define _DEPRECATED_\n#endif\n\n"); 255public("#ifndef _WARN_UNUSED_RESULT_\n#define _WARN_UNUSED_RESULT_\n#endif\n\n"); 256 257process_file(\&public, \&private, $_) foreach (@ARGV); 258print_footer(\&public, $public_define); 259if (defined($private_file) and $public_file ne $private_file) { 260 print_footer(\&private, $private_define); 261} 262 263if (not defined($public_file)) { 264 print STDOUT $$public_data; 265} 266 267if (not defined($private_file) and defined($public_file)) { 268 print STDOUT $$private_data; 269} 270 271mkpath(dirname($public_file), 0, 0755); 272open(PUBLIC, ">$public_file") or die("Can't open `$public_file': $!"); 273print PUBLIC "$$public_data"; 274close(PUBLIC); 275 276if (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} 282