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 process_file($$$)
|
---|
128 | {
|
---|
129 | my ($public_file, $private_file, $filename) = @_;
|
---|
130 |
|
---|
131 | $filename =~ s/\.o$/\.c/g;
|
---|
132 |
|
---|
133 | if ($filename =~ /^\//) {
|
---|
134 | open(FH, "<$filename") or die("Failed to open $filename");
|
---|
135 | } elsif (!open(FH, "< $builddir/$filename")) {
|
---|
136 | open(FH, "< $srcdir/$filename") || die "Failed to open $filename";
|
---|
137 | }
|
---|
138 |
|
---|
139 | $private_file->("\n/* The following definitions come from $filename */\n\n");
|
---|
140 |
|
---|
141 | my $comment = undef;
|
---|
142 | my $incomment = 0;
|
---|
143 | while (my $line = <FH>) {
|
---|
144 | my $target = \&private;
|
---|
145 | my $is_public = 0;
|
---|
146 |
|
---|
147 | if ($line =~ /^\/\*\*/) {
|
---|
148 | $comment = "";
|
---|
149 | $incomment = 1;
|
---|
150 | }
|
---|
151 |
|
---|
152 | if ($incomment) {
|
---|
153 | $comment .= $line;
|
---|
154 | if ($line =~ /\*\//) {
|
---|
155 | $incomment = 0;
|
---|
156 | }
|
---|
157 | }
|
---|
158 |
|
---|
159 | # these are ordered for maximum speed
|
---|
160 | next if ($line =~ /^\s/);
|
---|
161 |
|
---|
162 | next unless ($line =~ /\(/);
|
---|
163 |
|
---|
164 | next if ($line =~ /^\/|[;]/);
|
---|
165 |
|
---|
166 | if ($line =~ /^FN_/) {
|
---|
167 | next;
|
---|
168 | }
|
---|
169 |
|
---|
170 | if ($line =~ /^_PUBLIC_[\t ]/) {
|
---|
171 | $target = \&public;
|
---|
172 | $is_public = 1;
|
---|
173 | }
|
---|
174 |
|
---|
175 | next unless ( $is_public || $line =~ /
|
---|
176 | ^(_DEPRECATED_ |_NORETURN_ |_WARN_UNUSED_RESULT_ |_PURE_ )*(
|
---|
177 | void|bool|int|struct|char|const|\w+_[tT]\s|uint|unsigned|long|NTSTATUS|
|
---|
178 | ADS_STATUS|enum\s.*\(|DATA_BLOB|WERROR|XFILE|FILE|DIR|
|
---|
179 | double|TDB_CONTEXT|TDB_DATA|TALLOC_CTX|NTTIME|FN_|init_module|
|
---|
180 | GtkWidget|GType|smb_ucs2_t|krb5_error_code|NET_API_STATUS)
|
---|
181 | /xo);
|
---|
182 |
|
---|
183 | next if ($line =~ /^int\s*main/);
|
---|
184 |
|
---|
185 | $target->("\n$comment") if (defined($comment)); $comment = undef;
|
---|
186 |
|
---|
187 | if ( $line =~ /\(.*\)\s*$/o ) {
|
---|
188 | chomp $line;
|
---|
189 | $target->("$line;\n");
|
---|
190 | next;
|
---|
191 | }
|
---|
192 |
|
---|
193 | $target->($line);
|
---|
194 |
|
---|
195 | while ($line = <FH>) {
|
---|
196 | if ($line =~ /\)\s*$/o) {
|
---|
197 | chomp $line;
|
---|
198 | $target->("$line;\n");
|
---|
199 | last;
|
---|
200 | }
|
---|
201 | $target->($line);
|
---|
202 | }
|
---|
203 | }
|
---|
204 |
|
---|
205 | close(FH);
|
---|
206 | }
|
---|
207 |
|
---|
208 |
|
---|
209 | print_header(\&public, $public_define);
|
---|
210 | if (defined($private_file) and defined($public_file) and $public_file ne $private_file) {
|
---|
211 | print_header(\&private, $private_define);
|
---|
212 |
|
---|
213 | private("/* this file contains prototypes for functions that " .
|
---|
214 | "are private \n * to this subsystem or library. These functions " .
|
---|
215 | "should not be \n * used outside this particular subsystem! */\n\n");
|
---|
216 |
|
---|
217 | public("/* this file contains prototypes for functions that " .
|
---|
218 | "are part of \n * the public API of this subsystem or library. */\n\n");
|
---|
219 |
|
---|
220 | }
|
---|
221 |
|
---|
222 | public("#ifndef _PUBLIC_\n#define _PUBLIC_\n#endif\n\n");
|
---|
223 | public("#ifndef _PURE_\n#define _PURE_\n#endif\n\n");
|
---|
224 | public("#ifndef _NORETURN_\n#define _NORETURN_\n#endif\n\n");
|
---|
225 | public("#ifndef _DEPRECATED_\n#define _DEPRECATED_\n#endif\n\n");
|
---|
226 | public("#ifndef _WARN_UNUSED_RESULT_\n#define _WARN_UNUSED_RESULT_\n#endif\n\n");
|
---|
227 |
|
---|
228 | process_file(\&public, \&private, $_) foreach (@ARGV);
|
---|
229 | print_footer(\&public, $public_define);
|
---|
230 | if (defined($private_file) and $public_file ne $private_file) {
|
---|
231 | print_footer(\&private, $private_define);
|
---|
232 | }
|
---|
233 |
|
---|
234 | if (not defined($public_file)) {
|
---|
235 | print STDOUT $$public_data;
|
---|
236 | }
|
---|
237 |
|
---|
238 | if (not defined($private_file) and defined($public_file)) {
|
---|
239 | print STDOUT $$private_data;
|
---|
240 | }
|
---|
241 |
|
---|
242 | mkpath(dirname($public_file), 0, 0755);
|
---|
243 | open(PUBLIC, ">$public_file") or die("Can't open `$public_file': $!");
|
---|
244 | print PUBLIC "$$public_data";
|
---|
245 | close(PUBLIC);
|
---|
246 |
|
---|
247 | if (defined($private_file) and $public_file ne $private_file) {
|
---|
248 | mkpath(dirname($private_file), 0, 0755);
|
---|
249 | open(PRIVATE, ">$private_file") or die("Can't open `$private_file': $!");
|
---|
250 | print PRIVATE "$$private_data";
|
---|
251 | close(PRIVATE);
|
---|
252 | }
|
---|