sub dump_enum($$) { my $x = shift; my $file = shift; $x =~ s@/\*.*?\*/@@gos; # strip comments. $x =~ s/^#\s*define\s+.*$//; # strip #define macros inside enums if ($x =~ /enum\s+(\w+)\s*{(.*)}/) { $declaration_name = $1; my $members = $2; foreach my $arg (split ',', $members) { $arg =~ s/^\s*(\w+).*/$1/; push @parameterlist, $arg; if (!$parameterdescs{$arg}) { $parameterdescs{$arg} = $undescribed; print STDERR "Warning(${file}:$.): Enum value '$arg' ". "not described in enum '$declaration_name'\n"; } } output_declaration($declaration_name, 'enum', {'enum' => $declaration_name, 'module' => $modulename, 'parameterlist' => \@parameterlist, 'parameterdescs' => \%parameterdescs, 'sectionlist' => \@sectionlist, 'sections' => \%sections, 'purpose' => $declaration_purpose }); } else { print STDERR "Error(${file}:$.): Cannot parse enum!\n"; ++$errors; }} sub dump_typedef($$) { my $x = shift; my $file = shift; $x =~ s@/\*.*?\*/@@gos; # strip comments. while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) { $x =~ s/\(*.\)\s*;$/;/; $x =~ s/\[*.\]\s*;$/;/; } if ($x =~ /typedef.*\s+(\w+)\s*;/) { $declaration_name = $1; output_declaration($declaration_name, 'typedef', {'typedef' => $declaration_name, 'module' => $modulename, 'sectionlist' => \@sectionlist, 'sections' => \%sections, 'purpose' => $declaration_purpose }); } else { print STDERR "Error(${file}:$.): Cannot parse typedef!\n"; ++$errors; }} sub save_struct_actual($) { my $actual = shift; # strip all spaces from the actual param so that it looks like one string item $actual =~ s/\s*//g; $struct_actual = $struct_actual . $actual . " ";} sub create_parameterlist($$$) { my $args = shift; my $splitter = shift; my $file = shift; my $type; my $param; # temporarily replace commas inside function pointer definition while ($args =~ /(\([^\),]+),/) { $args =~ s/(\([^\),]+),/$1#/g; } foreach my $arg (split($splitter, $args)) { # strip comments $arg =~ s/\/\*.*\*\///; # strip leading/trailing spaces $arg =~ s/^\s*//; $arg =~ s/\s*$//; $arg =~ s/\s+/ /; if ($arg =~ /^#/) { # Treat preprocessor directive as a typeless variable just to fill # corresponding data structures "correctly". Catch it later in # output_* subs. push_parameter($arg, "", $file); } elsif ($arg =~ m/\(.+\)\s*\(/) { # pointer-to-function $arg =~ tr/#/,/; $arg =~ m/[^\(]+\(\*?\s*(\w*)\s*\)/; $param = $1; $type = $arg; $type =~ s/([^\(]+\(\*?)\s*$param/$1/; save_struct_actual($param); push_parameter($param, $type, $file); } elsif ($arg) { $arg =~ s/\s*:\s*/:/g; $arg =~ s/\s*\[/\[/g; my @args = split('\s*,\s*', $arg); if ($args[0] =~ m/\*/) { $args[0] =~ s/(\*+)\s*/ $1/; } my @first_arg; if ($args[0] =~ /^(.*\s+)(.*?\[.*\].*)$/) { shift @args; push(@first_arg, split('\s+', $1)); push(@first_arg, $2); } else { @first_arg = split('\s+', shift @args); } unshift(@args, pop @first_arg); $type = join " ", @first_arg; foreach $param (@args) { if ($param =~ m/^(\*+)\s*(.*)/) { save_struct_actual($2); push_parameter($2, "$type $1", $file); } elsif ($param =~ m/(.*?):(\d+)/) { if ($type ne "") { # skip unnamed bit-fields save_struct_actual($1); push_parameter($1, "$type:$2", $file) } } else { save_struct_actual($param); push_parameter($param, $type, $file); } } } }} sub push_parameter($$$) { my $param = shift; my $type = shift; my $file = shift; if (($anon_struct_union == 1) && ($type eq "") && ($param eq "}")) { return; # ignore the ending }; from anon. struct/union } $anon_struct_union = 0; my $param_name = $param; $param_name =~ s/\[.*//; if ($type eq "" && $param =~ /\.\.\.$/) { 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); # also ignore unnamed structs/unions; if (!$anon_struct_union) { if (!defined $parameterdescs{$param_name} && $param_name !~ /^#/) { $parameterdescs{$param_name} = $undescribed; if (($type eq 'function') || ($type eq 'enum')) { print STDERR "Warning(${file}:$.): Function parameter ". "or member '$param' not " . "described in '$declaration_name'\n"; } print STDERR "Warning(${file}:$.):" . " No description found for parameter '$param'\n"; ++$warnings; } } $param = xml_escape($param); # 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; $parametertypes{$param} = $type;} sub check_sections($$$$$$) { my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck, $nested) = @_; 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 "Warning(${file}:$.): " . "Excess function parameter " . "'$sects[$sx]' " . "description in '$decl_name'\n"; ++$warnings; } else { if ($nested !~ m/\Q$sects[$sx]\E/) { print STDERR "Warning(${file}:$.): " . "Excess struct/union/enum/typedef member " . "'$sects[$sx]' " . "description in '$decl_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; $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/__devinit +//; $prototype =~ s/__init +//; $prototype =~ s/__init_or_module +//; $prototype =~ s/__must_check +//; $prototype =~ s/^#\s*define\s+//; #ak added $prototype =~ s/__attribute__\s*\(\([a-z,]*\)\)//; # 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 ($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); } else { print STDERR "Error(${file}:$.): cannot understand prototype: '$prototype'\n"; ++$errors; return; } my $prms = join " ", @parameterlist; check_sections($file, $declaration_name, "function", $sectcheck, $prms, ""); 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 = ""; %constants = (); %parameterdescs = (); %parametertypes = (); @parameterlist = (); %sections = (); @sectionlist = (); $sectcheck = ""; $struct_actual = ""; $prototype = ""; $state = 0;} 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 "Warning(${file}:$.): Unrecognized tracepoint format: \n". "$prototype\n"; } else { $prototype = "static inline void trace_$tracepointname($tracepointargs)"; }} sub syscall_munge() { my $void = 0; $prototype =~ s@[\r\n\t]+@ @gos; # strip newlines/CR's/tabs## 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_state3_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 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_state3_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 =~ /([^{};]*)([{};])(.*)/ ) { $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; } }} # xml_escape: replace <, >, and & in the text stream;## however, formatting controls that are generated internally/locally in the# kernel-doc script are not escaped here; instead, they begin life like# $blankline_html (4 of '\' followed by a mnemonic + ':'), then these strings# are converted to their mnemonic-expected output, without the 4 * '\' & ':',# just before actual output; (this is done by local_unescape())sub xml_escape($) { my $text = shift; if (($output_mode eq "text") || ($output_mode eq "man")) { return $text;Lines 1501–2000 of 2294. Previous lines Load more
sub dump_enum($$) { my $x = shift; my $file = shift; $x =~ s@/\*.*?\*/@@gos; # strip comments. $x =~ s/^#\s*define\s+.*$//; # strip #define macros inside enums if ($x =~ /enum\s+(\w+)\s*{(.*)}/) { $declaration_name = $1; my $members = $2; foreach my $arg (split ',', $members) { $arg =~ s/^\s*(\w+).*/$1/; push @parameterlist, $arg; if (!$parameterdescs{$arg}) { $parameterdescs{$arg} = $undescribed; print STDERR "Warning(${file}:$.): Enum value '$arg' ". "not described in enum '$declaration_name'\n"; } } output_declaration($declaration_name, 'enum', {'enum' => $declaration_name, 'module' => $modulename, 'parameterlist' => \@parameterlist, 'parameterdescs' => \%parameterdescs, 'sectionlist' => \@sectionlist, 'sections' => \%sections, 'purpose' => $declaration_purpose }); } else { print STDERR "Error(${file}:$.): Cannot parse enum!\n"; ++$errors; } } sub dump_typedef($$) { my $x = shift; my $file = shift; $x =~ s@/\*.*?\*/@@gos; # strip comments. while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) { $x =~ s/\(*.\)\s*;$/;/; $x =~ s/\[*.\]\s*;$/;/; } if ($x =~ /typedef.*\s+(\w+)\s*;/) { $declaration_name = $1; output_declaration($declaration_name, 'typedef', {'typedef' => $declaration_name, 'module' => $modulename, 'sectionlist' => \@sectionlist, 'sections' => \%sections, 'purpose' => $declaration_purpose }); } else { print STDERR "Error(${file}:$.): Cannot parse typedef!\n"; ++$errors; } } sub save_struct_actual($) { my $actual = shift; # strip all spaces from the actual param so that it looks like one string item $actual =~ s/\s*//g; $struct_actual = $struct_actual . $actual . " "; } sub create_parameterlist($$$) { my $args = shift; my $splitter = shift; my $file = shift; my $type; my $param; # temporarily replace commas inside function pointer definition while ($args =~ /(\([^\),]+),/) { $args =~ s/(\([^\),]+),/$1#/g; } foreach my $arg (split($splitter, $args)) { # strip comments $arg =~ s/\/\*.*\*\///; # strip leading/trailing spaces $arg =~ s/^\s*//; $arg =~ s/\s*$//; $arg =~ s/\s+/ /; if ($arg =~ /^#/) { # Treat preprocessor directive as a typeless variable just to fill # corresponding data structures "correctly". Catch it later in # output_* subs. push_parameter($arg, "", $file); } elsif ($arg =~ m/\(.+\)\s*\(/) { # pointer-to-function $arg =~ tr/#/,/; $arg =~ m/[^\(]+\(\*?\s*(\w*)\s*\)/; $param = $1; $type = $arg; $type =~ s/([^\(]+\(\*?)\s*$param/$1/; save_struct_actual($param); push_parameter($param, $type, $file); } elsif ($arg) { $arg =~ s/\s*:\s*/:/g; $arg =~ s/\s*\[/\[/g; my @args = split('\s*,\s*', $arg); if ($args[0] =~ m/\*/) { $args[0] =~ s/(\*+)\s*/ $1/; } my @first_arg; if ($args[0] =~ /^(.*\s+)(.*?\[.*\].*)$/) { shift @args; push(@first_arg, split('\s+', $1)); push(@first_arg, $2); } else { @first_arg = split('\s+', shift @args); } unshift(@args, pop @first_arg); $type = join " ", @first_arg; foreach $param (@args) { if ($param =~ m/^(\*+)\s*(.*)/) { save_struct_actual($2); push_parameter($2, "$type $1", $file); } elsif ($param =~ m/(.*?):(\d+)/) { if ($type ne "") { # skip unnamed bit-fields save_struct_actual($1); push_parameter($1, "$type:$2", $file) } } else { save_struct_actual($param); push_parameter($param, $type, $file); } } } } } sub push_parameter($$$) { my $param = shift; my $type = shift; my $file = shift; if (($anon_struct_union == 1) && ($type eq "") && ($param eq "}")) { return; # ignore the ending }; from anon. struct/union } $anon_struct_union = 0; my $param_name = $param; $param_name =~ s/\[.*//; if ($type eq "" && $param =~ /\.\.\.$/) { 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); # also ignore unnamed structs/unions; if (!$anon_struct_union) { if (!defined $parameterdescs{$param_name} && $param_name !~ /^#/) { $parameterdescs{$param_name} = $undescribed; if (($type eq 'function') || ($type eq 'enum')) { print STDERR "Warning(${file}:$.): Function parameter ". "or member '$param' not " . "described in '$declaration_name'\n"; } print STDERR "Warning(${file}:$.):" . " No description found for parameter '$param'\n"; ++$warnings; } } $param = xml_escape($param); # 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; $parametertypes{$param} = $type; } sub check_sections($$$$$$) { my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck, $nested) = @_; 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 "Warning(${file}:$.): " . "Excess function parameter " . "'$sects[$sx]' " . "description in '$decl_name'\n"; ++$warnings; } else { if ($nested !~ m/\Q$sects[$sx]\E/) { print STDERR "Warning(${file}:$.): " . "Excess struct/union/enum/typedef member " . "'$sects[$sx]' " . "description in '$decl_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; $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/__devinit +//; $prototype =~ s/__init +//; $prototype =~ s/__init_or_module +//; $prototype =~ s/__must_check +//; $prototype =~ s/^#\s*define\s+//; #ak added $prototype =~ s/__attribute__\s*\(\([a-z,]*\)\)//; # 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 ($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); } else { print STDERR "Error(${file}:$.): cannot understand prototype: '$prototype'\n"; ++$errors; return; } my $prms = join " ", @parameterlist; check_sections($file, $declaration_name, "function", $sectcheck, $prms, ""); 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 = ""; %constants = (); %parameterdescs = (); %parametertypes = (); @parameterlist = (); %sections = (); @sectionlist = (); $sectcheck = ""; $struct_actual = ""; $prototype = ""; $state = 0; } 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 "Warning(${file}:$.): Unrecognized tracepoint format: \n". "$prototype\n"; } else { $prototype = "static inline void trace_$tracepointname($tracepointargs)"; } } sub syscall_munge() { my $void = 0; $prototype =~ s@[\r\n\t]+@ @gos; # strip newlines/CR's/tabs ## 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_state3_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 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_state3_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 =~ /([^{};]*)([{};])(.*)/ ) { $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; } } } # xml_escape: replace <, >, and & in the text stream; # # however, formatting controls that are generated internally/locally in the # kernel-doc script are not escaped here; instead, they begin life like # $blankline_html (4 of '\' followed by a mnemonic + ':'), then these strings # are converted to their mnemonic-expected output, without the 4 * '\' & ':', # just before actual output; (this is done by local_unescape()) sub xml_escape($) { my $text = shift; if (($output_mode eq "text") || ($output_mode eq "man")) { return $text;