} } }} 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 misspeltLines 1501–2000 of 2503. Previous lines Load more
} } } } 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