2286 lines · 62.6 KB · Text
RawDownload
	# 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;	$type =~ s/\s\s+/ /g;	$parametertypes{$param} = $type;} 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__\s*\(\([a-z,_\*\s\(\)]*\)\)//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;     $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/__meminit +//;    $prototype =~ s/__must_check +//;    $prototype =~ s/__weak +//;    $prototype =~ s/__sched +//;    $prototype =~ s/__printf\s*\(\s*\d*\s*,\s*\d*\s*\) +//;    my $define = $prototype =~ s/^#\s*define\s+//; #ak added    $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)     if ($define && $prototype =~ m/^()([a-zA-Z0-9_~:]+)\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/^()([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||	$prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||	$prototype =~ m/^(\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||	$prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||	$prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||	$prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||	$prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||	$prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||	$prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||	$prototype =~ m/^(\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||	$prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||	$prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||	$prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||	$prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||	$prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||	$prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||	$prototype =~ m/^(\w+\s+\w+\s*\*+\s*\w+\s*\*+\s*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/)  {	$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;    } 	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);        }     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)";	}} 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/) {	    $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 $identifier;    my $descr;     if (/$doc_block/o) {	$state = STATE_DOCBLOCK;	$contents = "";	$new_start_line = $. + 1; 	if ( $1 eq "" ) {	    $section = $section_intro;	} else {	    $section = $1;	}    }    elsif (/$doc_decl/o) {	$identifier = $1;	if (/\s*([\w\s]+?)(\(\))?\s*-/) {	    $identifier = $1;	} 	$state = STATE_BODY;	# if there's no @param blocks need to set up default section	# here	$contents = "";	$section = $section_default;	$new_start_line = $. + 1;	if (/-(.*)/) {	    # strip leading/trailing/multiple spaces	    $descr= $1;	    $descr =~ s/^\s*//;	    $descr =~ s/\s*$//;	    $descr =~ s/\s+/ /g;	    $declaration_purpose = $descr;	    $state = STATE_BODY_MAYBE;	} else {	    $declaration_purpose = "";	} 	if (($declaration_purpose eq "") && $verbose) {	    print STDERR "${file}:$.: warning: missing initial short description on line:\n";	    print STDERR $_;	    ++$warnings;	} 	if ($identifier =~ m/^struct\b/) {	    $decl_type = 'struct';	} elsif ($identifier =~ m/^union\b/) {	    $decl_type = 'union';	} elsif ($identifier =~ m/^enum\b/) {	    $decl_type = 'enum';	} elsif ($identifier =~ m/^typedef\b/) {	    $decl_type = 'typedef';	} else {	    $decl_type = 'function';	} 	if ($verbose) {	    print STDERR "${file}:$.: info: Scanning doc for $identifier\n";	}    } else {	print STDERR "${file}:$.: warning: Cannot understand $_ on line $.",	    " - I thought it was a doc line\n";	++$warnings;	$state = STATE_NORMAL;    }}  ## STATE_BODY and STATE_BODY_MAYBE: the bulk of a kerneldoc comment.#sub process_body($$) {    my $file = shift;     # Until all named variable macro parameters are    # documented using the bare name (`x`) rather than with    # dots (`x...`), strip the dots:    if ($section =~ /\w\.\.\.$/) {	$section =~ s/\.\.\.$//; 	if ($verbose) {	    print STDERR "${file}:$.: warning: Variable macro arguments should be documented without dots\n";	    ++$warnings;	}    }     if ($state == STATE_BODY_WITH_BLANK_LINE && /^\s*\*\s?\S/) {	dump_section($file, $section, $contents);	$section = $section_default;	$contents = "";    }     if (/$doc_sect/i) { # case insensitive for supported section names	$newsection = $1;	$newcontents = $2; 	# map the supported section names to the canonical names	if ($newsection =~ m/^description$/i) {	    $newsection = $section_default;	} elsif ($newsection =~ m/^context$/i) {	    $newsection = $section_context;	} elsif ($newsection =~ m/^returns?$/i) {	    $newsection = $section_return;

Lines 1501–2000 of 2286. Previous lines