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