2503 lines · 65.9 KB · Text
RawDownload
	    }	}    }} sub push_parameter($$$$$) {	my $param = shift;	my $type = shift;	my $org_arg = shift;	my $file = shift;	my $declaration_name = shift; 	if (($anon_struct_union == 1) && ($type eq "") &&	    ($param eq "}")) {		return;		# ignore the ending }; from anon. struct/union	} 	$anon_struct_union = 0;	$param =~ s/[\[\)].*//; 	if ($type eq "" && $param =~ /\.\.\.$/)	{	    if (!$param =~ /\w\.\.\.$/) {	      # handles unnamed variable parameters	      $param = "...";	    }	    elsif ($param =~ /\w\.\.\.$/) {	      # for named variable parameters of the form `x...`, remove the dots	      $param =~ s/\.\.\.$//;	    }	    if (!defined $parameterdescs{$param} || $parameterdescs{$param} eq "") {		$parameterdescs{$param} = "variable arguments";	    }	}	elsif ($type eq "" && ($param eq "" or $param eq "void"))	{	    $param="void";	    $parameterdescs{void} = "no arguments";	}	elsif ($type eq "" && ($param eq "struct" or $param eq "union"))	# handle unnamed (anonymous) union or struct:	{		$type = $param;		$param = "{unnamed_" . $param . "}";		$parameterdescs{$param} = "anonymous\n";		$anon_struct_union = 1;	} 	# warn if parameter has no description	# (but ignore ones starting with # as these are not parameters	# but inline preprocessor statements);	# Note: It will also ignore void params and unnamed structs/unions	if (!defined $parameterdescs{$param} && $param !~ /^#/) {		$parameterdescs{$param} = $undescribed; 	        if (show_warnings($type, $declaration_name) && $param !~ /\./) {			print STDERR			      "${file}:$.: warning: Function parameter or member '$param' not described in '$declaration_name'\n";			++$warnings;		}	} 	# strip spaces from $param so that it is one continuous string	# on @parameterlist;	# this fixes a problem where check_sections() cannot find	# a parameter like "addr[6 + 2]" because it actually appears	# as "addr[6", "+", "2]" on the parameter list;	# but it's better to maintain the param string unchanged for output,	# so just weaken the string compare in check_sections() to ignore	# "[blah" in a parameter string;	###$param =~ s/\s*//g;	push @parameterlist, $param;	$org_arg =~ s/\s\s+/ /g;	$parametertypes{$param} = $org_arg;} sub check_sections($$$$$) {	my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck) = @_;	my @sects = split ' ', $sectcheck;	my @prms = split ' ', $prmscheck;	my $err;	my ($px, $sx);	my $prm_clean;		# strip trailing "[array size]" and/or beginning "*" 	foreach $sx (0 .. $#sects) {		$err = 1;		foreach $px (0 .. $#prms) {			$prm_clean = $prms[$px];			$prm_clean =~ s/\[.*\]//;			$prm_clean =~ s/$attribute//i;			# ignore array size in a parameter string;			# however, the original param string may contain			# spaces, e.g.:  addr[6 + 2]			# and this appears in @prms as "addr[6" since the			# parameter list is split at spaces;			# hence just ignore "[..." for the sections check;			$prm_clean =~ s/\[.*//; 			##$prm_clean =~ s/^\**//;			if ($prm_clean eq $sects[$sx]) {				$err = 0;				last;			}		}		if ($err) {			if ($decl_type eq "function") {				print STDERR "${file}:$.: warning: " .					"Excess function parameter " .					"'$sects[$sx]' " .					"description in '$decl_name'\n";				++$warnings;			}		}	}} ### Checks the section describing the return value of a function.sub check_return_section {        my $file = shift;        my $declaration_name = shift;        my $return_type = shift;         # Ignore an empty return type (It's a macro)        # Ignore functions with a "void" return type. (But don't ignore "void *")        if (($return_type eq "") || ($return_type =~ /void\s*\w*\s*$/)) {                return;        }         if (!defined($sections{$section_return}) ||            $sections{$section_return} eq "") {                print STDERR "${file}:$.: warning: " .                        "No description found for return value of " .                        "'$declaration_name'\n";                ++$warnings;        }} ### takes a function prototype and the name of the current file being# processed and spits out all the details stored in the global# arrays/hashes.sub dump_function($$) {    my $prototype = shift;    my $file = shift;    my $noret = 0;     print_lineno($new_start_line);     $prototype =~ s/^static +//;    $prototype =~ s/^extern +//;    $prototype =~ s/^asmlinkage +//;    $prototype =~ s/^inline +//;    $prototype =~ s/^__inline__ +//;    $prototype =~ s/^__inline +//;    $prototype =~ s/^__always_inline +//;    $prototype =~ s/^noinline +//;    $prototype =~ s/__init +//;    $prototype =~ s/__init_or_module +//;    $prototype =~ s/__deprecated +//;    $prototype =~ s/__flatten +//;    $prototype =~ s/__meminit +//;    $prototype =~ s/__must_check +//;    $prototype =~ s/__weak +//;    $prototype =~ s/__sched +//;    $prototype =~ s/__printf\s*\(\s*\d*\s*,\s*\d*\s*\) +//;    $prototype =~ s/__alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\) +//;    my $define = $prototype =~ s/^#\s*define\s+//; #ak added    $prototype =~ s/__attribute_const__ +//;    $prototype =~ s/__attribute__\s*\(\(            (?:                 [\w\s]++          # attribute name                 (?:\([^)]*+\))?   # attribute arguments                 \s*+,?            # optional comma at the end            )+          \)\)\s+//x;     # Yes, this truly is vile.  We are looking for:    # 1. Return type (may be nothing if we're looking at a macro)    # 2. Function name    # 3. Function parameters.    #    # All the while we have to watch out for function pointer parameters    # (which IIRC is what the two sections are for), C types (these    # regexps don't even start to express all the possibilities), and    # so on.    #    # If you mess with these regexps, it's a good idea to check that    # the following functions' documentation still comes out right:    # - parport_register_device (function pointer parameters)    # - atomic_set (macro)    # - pci_match_device, __copy_to_user (long return type)    my $name = qr{[a-zA-Z0-9_~:]+};    my $prototype_end1 = qr{[^\(]*};    my $prototype_end2 = qr{[^\{]*};    my $prototype_end = qr{\(($prototype_end1|$prototype_end2)\)};    my $type1 = qr{[\w\s]+};    my $type2 = qr{$type1\*+};     if ($define && $prototype =~ m/^()($name)\s+/) {        # This is an object-like macro, it has no return type and no parameter        # list.        # Function-like macros are not allowed to have spaces between        # declaration_name and opening parenthesis (notice the \s+).        $return_type = $1;        $declaration_name = $2;        $noret = 1;    } elsif ($prototype =~ m/^()($name)\s*$prototype_end/ ||	$prototype =~ m/^($type1)\s+($name)\s*$prototype_end/ ||	$prototype =~ m/^($type2+)\s*($name)\s*$prototype_end/)  {	$return_type = $1;	$declaration_name = $2;	my $args = $3; 	create_parameterlist($args, ',', $file, $declaration_name);    } else {	print STDERR "${file}:$.: warning: cannot understand function prototype: '$prototype'\n";	return;    }     if ($identifier ne $declaration_name) {	print STDERR "${file}:$.: warning: expecting prototype for $identifier(). Prototype was for $declaration_name() instead\n";	return;    }     my $prms = join " ", @parameterlist;    check_sections($file, $declaration_name, "function", $sectcheck, $prms);     # This check emits a lot of warnings at the moment, because many    # functions don't have a 'Return' doc section. So until the number    # of warnings goes sufficiently down, the check is only performed in    # verbose mode.    # TODO: always perform the check.    if ($verbose && !$noret) {	    check_return_section($file, $declaration_name, $return_type);    }     # The function parser can be called with a typedef parameter.    # Handle it.    if ($return_type =~ /typedef/) {	output_declaration($declaration_name,			   'function',			   {'function' => $declaration_name,			    'typedef' => 1,			    'module' => $modulename,			    'functiontype' => $return_type,			    'parameterlist' => \@parameterlist,			    'parameterdescs' => \%parameterdescs,			    'parametertypes' => \%parametertypes,			    'sectionlist' => \@sectionlist,			    'sections' => \%sections,			    'purpose' => $declaration_purpose			   });    } else {	output_declaration($declaration_name,			   'function',			   {'function' => $declaration_name,			    'module' => $modulename,			    'functiontype' => $return_type,			    'parameterlist' => \@parameterlist,			    'parameterdescs' => \%parameterdescs,			    'parametertypes' => \%parametertypes,			    'sectionlist' => \@sectionlist,			    'sections' => \%sections,			    'purpose' => $declaration_purpose			   });    }} sub reset_state {    $function = "";    %parameterdescs = ();    %parametertypes = ();    @parameterlist = ();    %sections = ();    @sectionlist = ();    $sectcheck = "";    $struct_actual = "";    $prototype = "";     $state = STATE_NORMAL;    $inline_doc_state = STATE_INLINE_NA;} sub tracepoint_munge($) {	my $file = shift;	my $tracepointname = 0;	my $tracepointargs = 0; 	if ($prototype =~ m/TRACE_EVENT\((.*?),/) {		$tracepointname = $1;	}	if ($prototype =~ m/DEFINE_SINGLE_EVENT\((.*?),/) {		$tracepointname = $1;	}	if ($prototype =~ m/DEFINE_EVENT\((.*?),(.*?),/) {		$tracepointname = $2;	}	$tracepointname =~ s/^\s+//; #strip leading whitespace	if ($prototype =~ m/TP_PROTO\((.*?)\)/) {		$tracepointargs = $1;	}	if (($tracepointname eq 0) || ($tracepointargs eq 0)) {		print STDERR "${file}:$.: warning: Unrecognized tracepoint format: \n".			     "$prototype\n";	} else {		$prototype = "static inline void trace_$tracepointname($tracepointargs)";		$identifier = "trace_$identifier";	}} sub syscall_munge() {	my $void = 0; 	$prototype =~ s@[\r\n]+@ @gos; # strip newlines/CR's##	if ($prototype =~ m/SYSCALL_DEFINE0\s*\(\s*(a-zA-Z0-9_)*\s*\)/) {	if ($prototype =~ m/SYSCALL_DEFINE0/) {		$void = 1;##		$prototype = "long sys_$1(void)";	} 	$prototype =~ s/SYSCALL_DEFINE.*\(/long sys_/; # fix return type & func name	if ($prototype =~ m/long (sys_.*?),/) {		$prototype =~ s/,/\(/;	} elsif ($void) {		$prototype =~ s/\)/\(void\)/;	} 	# now delete all of the odd-number commas in $prototype	# so that arg types & arg names don't have a comma between them	my $count = 0;	my $len = length($prototype);	if ($void) {		$len = 0;	# skip the for-loop	}	for (my $ix = 0; $ix < $len; $ix++) {		if (substr($prototype, $ix, 1) eq ',') {			$count++;			if ($count % 2 == 1) {				substr($prototype, $ix, 1) = ' ';			}		}	}} sub process_proto_function($$) {    my $x = shift;    my $file = shift;     $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line     if ($x =~ m#\s*/\*\s+MACDOC\s*#io || ($x =~ /^#/ && $x !~ /^#\s*define/)) {	# do nothing    }    elsif ($x =~ /([^\{]*)/) {	$prototype .= $1;    }     if (($x =~ /\{/) || ($x =~ /\#\s*define/) || ($x =~ /;/)) {	$prototype =~ s@/\*.*?\*/@@gos;	# strip comments.	$prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's.	$prototype =~ s@^\s+@@gos; # strip leading spaces 	 # Handle prototypes for function pointers like:	 # int (*pcs_config)(struct foo)	$prototype =~ s@^(\S+\s+)\(\s*\*(\S+)\)@$1$2@gos; 	if ($prototype =~ /SYSCALL_DEFINE/) {		syscall_munge();	}	if ($prototype =~ /TRACE_EVENT/ || $prototype =~ /DEFINE_EVENT/ ||	    $prototype =~ /DEFINE_SINGLE_EVENT/)	{		tracepoint_munge($file);	}	dump_function($prototype, $file);	reset_state();    }} sub process_proto_type($$) {    my $x = shift;    my $file = shift;     $x =~ s@[\r\n]+@ @gos; # strip newlines/cr's.    $x =~ s@^\s+@@gos; # strip leading spaces    $x =~ s@\s+$@@gos; # strip trailing spaces    $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line     if ($x =~ /^#/) {	# To distinguish preprocessor directive from regular declaration later.	$x .= ";";    }     while (1) {	if ( $x =~ /([^\{\};]*)([\{\};])(.*)/ ) {            if( length $prototype ) {                $prototype .= " "            }	    $prototype .= $1 . $2;	    ($2 eq '{') && $brcount++;	    ($2 eq '}') && $brcount--;	    if (($2 eq ';') && ($brcount == 0)) {		dump_declaration($prototype, $file);		reset_state();		last;	    }	    $x = $3;	} else {	    $prototype .= $x;	    last;	}    }}  sub map_filename($) {    my $file;    my ($orig_file) = @_;     if (defined($ENV{'SRCTREE'})) {	$file = "$ENV{'SRCTREE'}" . "/" . $orig_file;    } else {	$file = $orig_file;    }     if (defined($source_map{$file})) {	$file = $source_map{$file};    }     return $file;} sub process_export_file($) {    my ($orig_file) = @_;    my $file = map_filename($orig_file);     if (!open(IN,"<$file")) {	print STDERR "Error: Cannot open file $file\n";	++$errors;	return;    }     while (<IN>) {	if (/$export_symbol/) {	    next if (defined($nosymbol_table{$2}));	    $function_table{$2} = 1;	}    }     close(IN);} ## Parsers for the various processing states.## STATE_NORMAL: looking for the /** to begin everything.#sub process_normal() {    if (/$doc_start/o) {	$state = STATE_NAME;	# next line is always the function name	$in_doc_sect = 0;	$declaration_start_line = $. + 1;    }} ## STATE_NAME: Looking for the "name - description" line#sub process_name($$) {    my $file = shift;    my $descr;     if (/$doc_block/o) {	$state = STATE_DOCBLOCK;	$contents = "";	$new_start_line = $.; 	if ( $1 eq "" ) {	    $section = $section_intro;	} else {	    $section = $1;	}    } elsif (/$doc_decl/o) {	$identifier = $1;	my $is_kernel_comment = 0;	my $decl_start = qr{$doc_com};	# test for pointer declaration type, foo * bar() - desc	my $fn_type = qr{\w+\s*\*\s*}; 	my $parenthesis = qr{\(\w*\)};	my $decl_end = qr{[-:].*};	if (/^$decl_start([\w\s]+?)$parenthesis?\s*$decl_end?$/) {	    $identifier = $1;	}	if ($identifier =~ m/^(struct|union|enum|typedef)\b\s*(\S*)/) {	    $decl_type = $1;	    $identifier = $2;	    $is_kernel_comment = 1;	}	# Look for foo() or static void foo() - description; or misspelt

Lines 1501–2000 of 2503. Previous lines