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 =~ /^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}lpcfg_$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 =~ /^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 | }
|
---|