2003-11-23 04:29:42 +03:00
#!/usr/bin/perl
2006-03-21 12:25:36 +03:00
# Simple script for generating prototypes for C functions
# Written by Jelmer Vernooij
# based on the original mkproto.sh by Andrew Tridgell
2003-11-23 04:29:42 +03:00
use strict ;
2003-12-16 06:34:23 +03:00
# don't use warnings module as it is not portable enough
# use warnings;
2003-11-23 04:29:42 +03:00
2005-12-23 15:29:13 +03:00
use Getopt::Long ;
2006-04-11 15:37:52 +04:00
use File::Basename ;
use File::Path ;
2005-12-23 15:29:13 +03:00
2006-03-21 12:25:36 +03:00
#####################################################################
# read a file into a string
2005-12-23 15:29:13 +03:00
my $ public_file = undef ;
my $ private_file = undef ;
my $ public_define = undef ;
my $ private_define = undef ;
2006-03-21 12:25:36 +03:00
my $ _public = "" ;
my $ _private = "" ;
my $ public_data = \ $ _public ;
my $ private_data = \ $ _private ;
2006-04-11 15:37:52 +04:00
my $ builddir = undef ;
my $ srcdir = undef ;
2006-03-21 12:25:36 +03:00
sub public ($)
{
my ( $ d ) = @ _ ;
$$ public_data . = $ d ;
}
sub private ($)
{
my ( $ d ) = @ _ ;
$$ private_data . = $ d ;
}
2005-12-23 15:29:13 +03:00
2005-12-27 23:29:19 +03:00
sub usage ()
{
print "Usage: mkproto.pl [options] [c files]\n" ;
print "OPTIONS:\n" ;
print " --public=FILE Write prototypes for public functions to FILE\n" ;
print " --private=FILE Write prototypes for private functions to FILE\n" ;
print " --define=DEF Use DEF to check whether header was already included\n" ;
print " --public-define=DEF Same as --define, but just for public header\n" ;
print " --private-define=DEF Same as --define, but just for private header\n" ;
2006-05-16 20:57:56 +04:00
print " --srcdir=path Read files relative to this directory\n" ;
print " --builddir=path Write file relative to this directory\n" ;
2005-12-27 23:29:19 +03:00
print " --help Print this help message\n\n" ;
exit 0 ;
}
2005-12-23 15:29:13 +03:00
GetOptions (
'public=s' = > sub { my ( $ f , $ v ) = @ _ ; $ public_file = $ v ; } ,
'private=s' = > sub { my ( $ f , $ v ) = @ _ ; $ private_file = $ v ; } ,
'define=s' = > sub {
my ( $ f , $ v ) = @ _ ;
$ public_define = $ v ;
$ private_define = "$v\_PRIVATE" ;
} ,
'public-define=s' = > \ $ public_define ,
2005-12-27 23:29:19 +03:00
'private-define=s' = > \ $ private_define ,
2006-05-16 20:57:56 +04:00
'srcdir=s' = > sub { my ( $ f , $ v ) = @ _ ; $ srcdir = $ v ; } ,
2006-04-11 15:37:52 +04:00
'builddir=s' = > sub { my ( $ f , $ v ) = @ _ ; $ builddir = $ v ; } ,
2006-05-16 20:57:56 +04:00
'help' = > \ & usage
2005-12-27 23:29:19 +03:00
) or exit ( 1 ) ;
2005-12-23 15:29:13 +03:00
2007-09-12 16:36:42 +04:00
sub normalize_define ($$)
{
my ( $ define , $ file ) = @ _ ;
2003-11-23 04:29:42 +03:00
2007-09-12 16:36:42 +04:00
if ( not defined ( $ define ) and defined ( $ file ) ) {
$ define = "__" . uc ( $ file ) . "__" ;
$ define =~ tr { . / } { __ } ;
$ define =~ tr { \ - } { _ } ;
} elsif ( not defined ( $ define ) ) {
$ define = '_PROTO_H_' ;
}
return $ define ;
2003-11-23 04:29:42 +03:00
}
2007-09-12 16:36:42 +04:00
$ public_define = normalize_define ( $ public_define , $ public_file ) ;
$ private_define = normalize_define ( $ private_define , $ private_file ) ;
2006-03-21 12:25:36 +03:00
if ( ( defined ( $ private_file ) and defined ( $ public_file ) and ( $ private_file eq $ public_file ) ) or
( not defined ( $ private_file ) and not defined ( $ public_file ) ) ) {
$ private_data = $ public_data ;
2003-11-23 04:29:42 +03:00
}
2006-03-21 12:25:36 +03:00
sub file_load ($)
{
my ( $ filename ) = shift ;
local ( * INPUTFILE ) ;
open ( INPUTFILE , $ filename ) || return undef ;
my ( $ saved_delim ) = $/ ;
undef $/ ;
my ( $ data ) = <INPUTFILE> ;
close ( INPUTFILE ) ;
$/ = $ saved_delim ;
return $ data ;
2005-12-23 15:29:13 +03:00
}
sub print_header ($$)
{
my ( $ file , $ header_name ) = @ _ ;
2006-03-21 12:25:36 +03:00
$ file - > ( "#ifndef $header_name\n" ) ;
$ file - > ( "#define $header_name\n\n" ) ;
$ file - > ( "#undef _PRINTF_ATTRIBUTE\n" ) ;
$ file - > ( "#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2)\n" ) ;
$ file - > ( "/* This file was automatically generated by mkproto.pl. DO NOT EDIT */\n\n" ) ;
2005-12-23 15:29:13 +03:00
}
2003-11-23 04:53:54 +03:00
2005-12-23 15:29:13 +03:00
sub print_footer ($$)
{
my ( $ file , $ header_name ) = @ _ ;
2006-03-21 12:25:36 +03:00
$ file - > ( "#undef _PRINTF_ATTRIBUTE\n" ) ;
$ file - > ( "#define _PRINTF_ATTRIBUTE(a1, a2)\n" ) ;
$ file - > ( "\n#endif /* $header_name */\n\n" ) ;
2005-12-23 15:29:13 +03:00
}
sub handle_loadparm ($$)
{
my ( $ file , $ line ) = @ _ ;
2003-11-23 05:00:40 +03:00
2006-09-06 16:30:26 +04:00
if ( $ line =~ /^_PUBLIC_ FN_(GLOBAL|LOCAL)_(CONST_STRING|STRING|BOOL|bool|CHAR|INTEGER|LIST)\((\w+),.*\)/o ) {
2003-11-23 05:11:55 +03:00
my $ scope = $ 1 ;
my $ type = $ 2 ;
my $ name = $ 3 ;
my % tmap = (
2007-08-27 22:10:19 +04:00
"BOOL" = > "bool " ,
2006-09-06 16:30:26 +04:00
"bool" = > "bool " ,
2003-11-23 05:11:55 +03:00
"CONST_STRING" = > "const char *" ,
2004-06-14 03:50:55 +04:00
"STRING" = > "const char *" ,
2003-11-23 05:11:55 +03:00
"INTEGER" = > "int " ,
"CHAR" = > "char " ,
"LIST" = > "const char **" ,
) ;
my % smap = (
"GLOBAL" = > "void" ,
2007-09-09 00:03:19 +04:00
"LOCAL" = > "struct loadparm_service *"
2003-11-23 05:11:55 +03:00
) ;
2006-03-21 12:25:36 +03:00
$ file - > ( "$tmap{$type}$name($smap{$scope});\n" ) ;
2003-11-23 04:53:54 +03:00
}
}
2005-12-23 15:29:13 +03:00
sub process_file ($$$)
2003-11-23 05:33:46 +03:00
{
2005-12-23 15:29:13 +03:00
my ( $ public_file , $ private_file , $ filename ) = @ _ ;
$ filename =~ s/\.o$/\.c/g ;
2003-11-23 04:29:42 +03:00
2006-04-11 15:37:52 +04:00
if ( ! open ( FH , "< $builddir/$filename" ) ) {
open ( FH , "< $srcdir/$filename" ) || die "Failed to open $filename" ;
}
2003-11-23 04:29:42 +03:00
2006-03-21 12:25:36 +03:00
$ private_file - > ( "\n/* The following definitions come from $filename */\n\n" ) ;
2003-11-23 04:29:42 +03:00
2007-06-19 01:48:57 +04:00
my $ comment = undef ;
my $ incomment = 0 ;
2003-11-23 05:44:23 +03:00
while ( my $ line = <FH> ) {
2006-03-21 12:25:36 +03:00
my $ target = \ & private ;
2006-01-10 19:54:21 +03:00
my $ is_public = 0 ;
2005-12-23 15:29:13 +03:00
2007-06-19 01:48:57 +04:00
if ( $ line =~ /^\/\*\*/ ) {
$ comment = "" ;
$ incomment = 1 ;
}
if ( $ incomment ) {
$ comment . = $ line ;
if ( $ line =~ /\*\// ) {
$ incomment = 0 ;
}
}
2003-11-23 05:44:23 +03:00
# these are ordered for maximum speed
2003-11-23 05:33:46 +03:00
next if ( $ line =~ /^\s/ ) ;
2003-11-23 05:44:23 +03:00
next unless ( $ line =~ /\(/ ) ;
next if ( $ line =~ /^\/|[;]/ ) ;
2006-03-07 19:51:56 +03:00
if ( $ line =~ /^_PUBLIC_ FN_/ ) {
handle_loadparm ( $ public_file , $ line ) ;
next ;
}
2006-03-07 00:14:41 +03:00
if ( $ line =~ /^_PUBLIC_[\t ]/ ) {
2006-03-21 12:25:36 +03:00
$ target = \ & public ;
2006-01-10 19:54:21 +03:00
$ is_public = 1 ;
2005-12-28 01:51:30 +03:00
}
2006-01-10 19:54:21 +03:00
next unless ( $ is_public || $ line =~ /
2007-06-01 16:01:53 +04:00
( _DEPRECATED_ | _NORETURN_ | _WARN_UNUSED_RESULT_ | _PURE_ ) * ^ (
void | BOOL | bool | int | struct | char | const | \ w + _ [ tT ] \ s | uint | unsigned | long | NTSTATUS |
2007-05-29 01:04:59 +04:00
ADS_STATUS | enum \ s . * \ ( | DATA_BLOB | WERROR | XFILE | FILE | DIR |
double | TDB_CONTEXT | TDB_DATA | TALLOC_CTX | NTTIME | FN_ | init_module |
GtkWidget | GType | smb_ucs2_t | krb5_error_code )
2003-11-23 05:44:23 +03:00
/ xo ) ;
2003-11-23 05:33:46 +03:00
2004-09-24 09:51:29 +04:00
next if ( $ line =~ /^int\s*main/ ) ;
2007-06-19 01:48:57 +04:00
$ target - > ( "\n$comment" ) if ( defined ( $ comment ) ) ; $ comment = undef ;
2007-08-27 22:10:19 +04:00
$ line =~ s/BOOL /bool /g ;
2003-11-23 05:33:46 +03:00
if ( $ line =~ /\(.*\)\s*$/o ) {
chomp $ line ;
2006-03-21 12:25:36 +03:00
$ target - > ( "$line;\n" ) ;
2003-11-23 05:33:46 +03:00
next ;
}
2003-11-23 04:29:42 +03:00
2006-03-21 12:25:36 +03:00
$ target - > ( $ line ) ;
2003-11-23 04:29:42 +03:00
2003-11-23 05:33:46 +03:00
while ( $ line = <FH> ) {
2007-08-27 22:10:19 +04:00
$ line =~ s/BOOL /bool /g ;
2003-11-23 05:33:46 +03:00
if ( $ line =~ /\)\s*$/o ) {
2003-11-23 06:03:27 +03:00
chomp $ line ;
2006-03-21 12:25:36 +03:00
$ target - > ( "$line;\n" ) ;
2003-11-23 05:33:46 +03:00
last ;
2003-11-23 04:29:42 +03:00
}
2006-03-21 12:25:36 +03:00
$ target - > ( $ line ) ;
2003-11-23 04:29:42 +03:00
}
}
2003-11-23 05:44:23 +03:00
close ( FH ) ;
2003-11-23 04:29:42 +03:00
}
2006-04-11 15:37:52 +04:00
2006-03-21 12:25:36 +03:00
print_header ( \ & public , $ public_define ) ;
2005-12-23 16:01:26 +03:00
if ( $ public_file ne $ private_file ) {
2006-03-21 12:25:36 +03:00
print_header ( \ & private , $ private_define ) ;
2005-12-27 23:29:19 +03:00
2006-03-21 12:25:36 +03:00
private ( "/* this file contains prototypes for functions that " .
2005-12-27 23:29:19 +03:00
"are private \n * to this subsystem or library. These functions " .
2006-03-21 12:25:36 +03:00
"should not be \n * used outside this particular subsystem! */\n\n" ) ;
2005-12-27 23:29:19 +03:00
2006-03-21 12:25:36 +03:00
public ( "/* this file contains prototypes for functions that " .
"are part of \n * the public API of this subsystem or library. */\n\n" ) ;
2006-03-16 17:34:55 +03:00
2005-12-23 15:29:13 +03:00
}
2006-03-16 17:34:55 +03:00
2006-03-21 12:25:36 +03:00
public ( "#ifndef _PUBLIC_\n#define _PUBLIC_\n#endif\n\n" ) ;
2007-06-01 16:01:53 +04:00
public ( "#ifndef _PURE_\n#define _PURE_\n#endif\n\n" ) ;
public ( "#ifndef _NORETURN_\n#define _NORETURN_\n#endif\n\n" ) ;
public ( "#ifndef _DEPRECATED_\n#define _DEPRECATED_\n#endif\n\n" ) ;
public ( "#ifndef _WARN_UNUSED_RESULT_\n#define _WARN_UNUSED_RESULT_\n#endif\n\n" ) ;
2006-03-16 17:34:55 +03:00
2006-03-21 12:25:36 +03:00
process_file ( \ & public , \ & private , $ _ ) foreach ( @ ARGV ) ;
print_footer ( \ & public , $ public_define ) ;
2005-12-23 16:01:26 +03:00
if ( $ public_file ne $ private_file ) {
2006-03-21 12:25:36 +03:00
print_footer ( \ & private , $ private_define ) ;
}
if ( not defined ( $ public_file ) ) {
print STDOUT $$ public_data ;
}
if ( not defined ( $ private_file ) and defined ( $ public_file ) ) {
print STDOUT $$ private_data ;
}
2006-08-26 12:40:51 +04:00
my $ old_public_data = file_load ( $ public_file ) ;
my $ old_private_data = file_load ( $ private_file ) ;
2006-09-21 03:22:08 +04:00
mkpath ( dirname ( $ public_file ) , 0 , 0755 ) ;
open ( PUBLIC , ">$public_file" ) or die ( "Can't open `$public_file': $!" ) ;
print PUBLIC "$$public_data" ;
close ( PUBLIC ) ;
2006-03-21 12:25:36 +03:00
2006-09-21 03:22:08 +04:00
if ( $ public_file ne $ private_file ) {
2006-04-11 15:37:52 +04:00
mkpath ( dirname ( $ private_file ) , 0 , 0755 ) ;
2006-03-21 12:25:36 +03:00
open ( PRIVATE , ">$private_file" ) or die ( "Can't open `$private_file': $!" ) ;
print PRIVATE "$$private_data" ;
close ( PRIVATE ) ;
2003-11-23 05:33:46 +03:00
}