foreach $parameter (@{$args{'parameterlist'}}) { ($parameter =~ /^#/) && next; my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; $type = $args{'parametertypes'}{$parameter}; print_lineno($parameterdesc_start_lines{$parameter_name}); print "``" . $parameter . "``\n"; output_highlight_rst($args{'parameterdescs'}{$parameter_name}); print "\n"; } print "\n"; $lineprefix = $oldprefix; output_section_rst(@_);} ## none mode output functions sub output_function_none(%) {} sub output_enum_none(%) {} sub output_typedef_none(%) {} sub output_struct_none(%) {} sub output_blockhead_none(%) {} ### generic output function for all types (function, struct/union, typedef, enum);# calls the generated, variable output_ function name based on# functype and output_modesub output_declaration { no strict 'refs'; my $name = shift; my $functype = shift; my $func = "output_${functype}_$output_mode"; if (($output_selection == OUTPUT_ALL) || (($output_selection == OUTPUT_INCLUDE || $output_selection == OUTPUT_EXPORTED) && defined($function_table{$name})) || (($output_selection == OUTPUT_EXCLUDE || $output_selection == OUTPUT_INTERNAL) && !($functype eq "function" && defined($function_table{$name})))) { &$func(@_); $section_counter++; }} ### generic output function - calls the right one based on current output mode.sub output_blockhead { no strict 'refs'; my $func = "output_blockhead_" . $output_mode; &$func(@_); $section_counter++;} ### takes a declaration (struct, union, enum, typedef) and# invokes the right handler. NOT called for functions.sub dump_declaration($$) { no strict 'refs'; my ($prototype, $file) = @_; my $func = "dump_" . $decl_type; &$func(@_);} sub dump_union($$) { dump_struct(@_);} sub dump_struct($$) { my $x = shift; my $file = shift; if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|____cacheline_aligned_in_smp|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*/) { my $decl_type = $1; $declaration_name = $2; my $members = $3; # ignore members marked private: $members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gosi; $members =~ s/\/\*\s*private:.*//gosi; # strip comments: $members =~ s/\/\*.*?\*\///gos; # strip attributes $members =~ s/\s*__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)/ /gi; $members =~ s/\s*__aligned\s*\([^;]*\)/ /gos; $members =~ s/\s*__packed\s*/ /gos; $members =~ s/\s*CRYPTO_MINALIGN_ATTR/ /gos; $members =~ s/\s*____cacheline_aligned_in_smp/ /gos; # replace DECLARE_BITMAP $members =~ s/__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)/DECLARE_BITMAP($1, __ETHTOOL_LINK_MODE_MASK_NBITS)/gos; $members =~ s/DECLARE_BITMAP\s*\(([^,)]+),\s*([^,)]+)\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos; # replace DECLARE_HASHTABLE $members =~ s/DECLARE_HASHTABLE\s*\(([^,)]+),\s*([^,)]+)\)/unsigned long $1\[1 << (($2) - 1)\]/gos; # replace DECLARE_KFIFO $members =~ s/DECLARE_KFIFO\s*\(([^,)]+),\s*([^,)]+),\s*([^,)]+)\)/$2 \*$1/gos; # replace DECLARE_KFIFO_PTR $members =~ s/DECLARE_KFIFO_PTR\s*\(([^,)]+),\s*([^,)]+)\)/$2 \*$1/gos; my $declaration = $members; # Split nested struct/union elements as newer ones while ($members =~ m/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/) { my $newmember; my $maintype = $1; my $ids = $4; my $content = $3; foreach my $id(split /,/, $ids) { $newmember .= "$maintype $id; "; $id =~ s/[:\[].*//; $id =~ s/^\s*\**(\S+)\s*/$1/; foreach my $arg (split /;/, $content) { next if ($arg =~ m/^\s*$/); if ($arg =~ m/^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)/) { # pointer-to-function my $type = $1; my $name = $2; my $extra = $3; next if (!$name); if ($id =~ m/^\s*$/) { # anonymous struct/union $newmember .= "$type$name$extra; "; } else { $newmember .= "$type$id.$name$extra; "; } } else { my $type; my $names; $arg =~ s/^\s+//; $arg =~ s/\s+$//; # Handle bitmaps $arg =~ s/:\s*\d+\s*//g; # Handle arrays $arg =~ s/\[.*\]//g; # The type may have multiple words, # and multiple IDs can be defined, like: # const struct foo, *bar, foobar # So, we remove spaces when parsing the # names, in order to match just names # and commas for the names $arg =~ s/\s*,\s*/,/g; if ($arg =~ m/(.*)\s+([\S+,]+)/) { $type = $1; $names = $2; } else { $newmember .= "$arg; "; next; } foreach my $name (split /,/, $names) { $name =~ s/^\s*\**(\S+)\s*/$1/; next if (($name =~ m/^\s*$/)); if ($id =~ m/^\s*$/) { # anonymous struct/union $newmember .= "$type $name; "; } else { $newmember .= "$type $id.$name; "; } } } } } $members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/$newmember/; } # Ignore other nested elements, like enums $members =~ s/(\{[^\{\}]*\})//g; create_parameterlist($members, ';', $file, $declaration_name); check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual); # Adjust declaration for better display $declaration =~ s/([\{;])/$1\n/g; $declaration =~ s/\}\s+;/};/g; # Better handle inlined enums do {} while ($declaration =~ s/(enum\s+\{[^\}]+),([^\n])/$1,\n$2/); my @def_args = split /\n/, $declaration; my $level = 1; $declaration = ""; foreach my $clause (@def_args) { $clause =~ s/^\s+//; $clause =~ s/\s+$//; $clause =~ s/\s+/ /; next if (!$clause); $level-- if ($clause =~ m/(\})/ && $level > 1); if (!($clause =~ m/^\s*#/)) { $declaration .= "\t" x $level; } $declaration .= "\t" . $clause . "\n"; $level++ if ($clause =~ m/(\{)/ && !($clause =~m/\}/)); } output_declaration($declaration_name, 'struct', {'struct' => $declaration_name, 'module' => $modulename, 'definition' => $declaration, 'parameterlist' => \@parameterlist, 'parameterdescs' => \%parameterdescs, 'parametertypes' => \%parametertypes, 'sectionlist' => \@sectionlist, 'sections' => \%sections, 'purpose' => $declaration_purpose, 'type' => $decl_type }); } else { print STDERR "${file}:$.: error: Cannot parse struct or union!\n"; ++$errors; }} sub show_warnings($$) { my $functype = shift; my $name = shift; return 1 if ($output_selection == OUTPUT_ALL); if ($output_selection == OUTPUT_EXPORTED) { if (defined($function_table{$name})) { return 1; } else { return 0; } } if ($output_selection == OUTPUT_INTERNAL) { if (!($functype eq "function" && defined($function_table{$name}))) { return 1; } else { return 0; } } if ($output_selection == OUTPUT_INCLUDE) { if (defined($function_table{$name})) { return 1; } else { return 0; } } if ($output_selection == OUTPUT_EXCLUDE) { if (!defined($function_table{$name})) { return 1; } else { return 0; } } die("Please add the new output type at show_warnings()");} sub dump_enum($$) { my $x = shift; my $file = shift; $x =~ s@/\*.*?\*/@@gos; # strip comments. # strip #define macros inside enums $x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos; if ($x =~ /enum\s+(\w*)\s*\{(.*)\}/) { $declaration_name = $1; my $members = $2; my %_members; $members =~ s/\s+$//; foreach my $arg (split ',', $members) { $arg =~ s/^\s*(\w+).*/$1/; push @parameterlist, $arg; if (!$parameterdescs{$arg}) { $parameterdescs{$arg} = $undescribed; if (show_warnings("enum", $declaration_name)) { print STDERR "${file}:$.: warning: Enum value '$arg' not described in enum '$declaration_name'\n"; } } $_members{$arg} = 1; } while (my ($k, $v) = each %parameterdescs) { if (!exists($_members{$k})) { if (show_warnings("enum", $declaration_name)) { print STDERR "${file}:$.: warning: Excess enum value '$k' description in '$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 "${file}:$.: error: Cannot parse enum!\n"; ++$errors; }} sub dump_typedef($$) { my $x = shift; my $file = shift; $x =~ s@/\*.*?\*/@@gos; # strip comments. # Parse function prototypes if ($x =~ /typedef\s+(\w+)\s*\(\*\s*(\w\S+)\s*\)\s*\((.*)\);/ || $x =~ /typedef\s+(\w+)\s*(\w\S+)\s*\s*\((.*)\);/) { # Function typedefs $return_type = $1; $declaration_name = $2; my $args = $3; create_parameterlist($args, ',', $file, $declaration_name); 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 }); return; } 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 "${file}:$.: error: 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 $declaration_name = 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, $declaration_name); } 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, $declaration_name); } elsif ($param =~ m/(.*?):(\d+)/) { if ($type ne "") { # skip unnamed bit-fields save_struct_actual($1); push_parameter($1, "$type:$2", $file, $declaration_name) } } else { save_struct_actual($param); push_parameter($param, $type, $file, $declaration_name); } } } }} sub push_parameter($$$$) { my $param = shift; my $type = 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);Lines 1001–1500 of 2286. Previous lines Load more
foreach $parameter (@{$args{'parameterlist'}}) { ($parameter =~ /^#/) && next; my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; $type = $args{'parametertypes'}{$parameter}; print_lineno($parameterdesc_start_lines{$parameter_name}); print "``" . $parameter . "``\n"; output_highlight_rst($args{'parameterdescs'}{$parameter_name}); print "\n"; } print "\n"; $lineprefix = $oldprefix; output_section_rst(@_); } ## none mode output functions sub output_function_none(%) { } sub output_enum_none(%) { } sub output_typedef_none(%) { } sub output_struct_none(%) { } sub output_blockhead_none(%) { } ## # generic output function for all types (function, struct/union, typedef, enum); # calls the generated, variable output_ function name based on # functype and output_mode sub output_declaration { no strict 'refs'; my $name = shift; my $functype = shift; my $func = "output_${functype}_$output_mode"; if (($output_selection == OUTPUT_ALL) || (($output_selection == OUTPUT_INCLUDE || $output_selection == OUTPUT_EXPORTED) && defined($function_table{$name})) || (($output_selection == OUTPUT_EXCLUDE || $output_selection == OUTPUT_INTERNAL) && !($functype eq "function" && defined($function_table{$name})))) { &$func(@_); $section_counter++; } } ## # generic output function - calls the right one based on current output mode. sub output_blockhead { no strict 'refs'; my $func = "output_blockhead_" . $output_mode; &$func(@_); $section_counter++; } ## # takes a declaration (struct, union, enum, typedef) and # invokes the right handler. NOT called for functions. sub dump_declaration($$) { no strict 'refs'; my ($prototype, $file) = @_; my $func = "dump_" . $decl_type; &$func(@_); } sub dump_union($$) { dump_struct(@_); } sub dump_struct($$) { my $x = shift; my $file = shift; if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|____cacheline_aligned_in_smp|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*/) { my $decl_type = $1; $declaration_name = $2; my $members = $3; # ignore members marked private: $members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gosi; $members =~ s/\/\*\s*private:.*//gosi; # strip comments: $members =~ s/\/\*.*?\*\///gos; # strip attributes $members =~ s/\s*__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)/ /gi; $members =~ s/\s*__aligned\s*\([^;]*\)/ /gos; $members =~ s/\s*__packed\s*/ /gos; $members =~ s/\s*CRYPTO_MINALIGN_ATTR/ /gos; $members =~ s/\s*____cacheline_aligned_in_smp/ /gos; # replace DECLARE_BITMAP $members =~ s/__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)/DECLARE_BITMAP($1, __ETHTOOL_LINK_MODE_MASK_NBITS)/gos; $members =~ s/DECLARE_BITMAP\s*\(([^,)]+),\s*([^,)]+)\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos; # replace DECLARE_HASHTABLE $members =~ s/DECLARE_HASHTABLE\s*\(([^,)]+),\s*([^,)]+)\)/unsigned long $1\[1 << (($2) - 1)\]/gos; # replace DECLARE_KFIFO $members =~ s/DECLARE_KFIFO\s*\(([^,)]+),\s*([^,)]+),\s*([^,)]+)\)/$2 \*$1/gos; # replace DECLARE_KFIFO_PTR $members =~ s/DECLARE_KFIFO_PTR\s*\(([^,)]+),\s*([^,)]+)\)/$2 \*$1/gos; my $declaration = $members; # Split nested struct/union elements as newer ones while ($members =~ m/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/) { my $newmember; my $maintype = $1; my $ids = $4; my $content = $3; foreach my $id(split /,/, $ids) { $newmember .= "$maintype $id; "; $id =~ s/[:\[].*//; $id =~ s/^\s*\**(\S+)\s*/$1/; foreach my $arg (split /;/, $content) { next if ($arg =~ m/^\s*$/); if ($arg =~ m/^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)/) { # pointer-to-function my $type = $1; my $name = $2; my $extra = $3; next if (!$name); if ($id =~ m/^\s*$/) { # anonymous struct/union $newmember .= "$type$name$extra; "; } else { $newmember .= "$type$id.$name$extra; "; } } else { my $type; my $names; $arg =~ s/^\s+//; $arg =~ s/\s+$//; # Handle bitmaps $arg =~ s/:\s*\d+\s*//g; # Handle arrays $arg =~ s/\[.*\]//g; # The type may have multiple words, # and multiple IDs can be defined, like: # const struct foo, *bar, foobar # So, we remove spaces when parsing the # names, in order to match just names # and commas for the names $arg =~ s/\s*,\s*/,/g; if ($arg =~ m/(.*)\s+([\S+,]+)/) { $type = $1; $names = $2; } else { $newmember .= "$arg; "; next; } foreach my $name (split /,/, $names) { $name =~ s/^\s*\**(\S+)\s*/$1/; next if (($name =~ m/^\s*$/)); if ($id =~ m/^\s*$/) { # anonymous struct/union $newmember .= "$type $name; "; } else { $newmember .= "$type $id.$name; "; } } } } } $members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/$newmember/; } # Ignore other nested elements, like enums $members =~ s/(\{[^\{\}]*\})//g; create_parameterlist($members, ';', $file, $declaration_name); check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual); # Adjust declaration for better display $declaration =~ s/([\{;])/$1\n/g; $declaration =~ s/\}\s+;/};/g; # Better handle inlined enums do {} while ($declaration =~ s/(enum\s+\{[^\}]+),([^\n])/$1,\n$2/); my @def_args = split /\n/, $declaration; my $level = 1; $declaration = ""; foreach my $clause (@def_args) { $clause =~ s/^\s+//; $clause =~ s/\s+$//; $clause =~ s/\s+/ /; next if (!$clause); $level-- if ($clause =~ m/(\})/ && $level > 1); if (!($clause =~ m/^\s*#/)) { $declaration .= "\t" x $level; } $declaration .= "\t" . $clause . "\n"; $level++ if ($clause =~ m/(\{)/ && !($clause =~m/\}/)); } output_declaration($declaration_name, 'struct', {'struct' => $declaration_name, 'module' => $modulename, 'definition' => $declaration, 'parameterlist' => \@parameterlist, 'parameterdescs' => \%parameterdescs, 'parametertypes' => \%parametertypes, 'sectionlist' => \@sectionlist, 'sections' => \%sections, 'purpose' => $declaration_purpose, 'type' => $decl_type }); } else { print STDERR "${file}:$.: error: Cannot parse struct or union!\n"; ++$errors; } } sub show_warnings($$) { my $functype = shift; my $name = shift; return 1 if ($output_selection == OUTPUT_ALL); if ($output_selection == OUTPUT_EXPORTED) { if (defined($function_table{$name})) { return 1; } else { return 0; } } if ($output_selection == OUTPUT_INTERNAL) { if (!($functype eq "function" && defined($function_table{$name}))) { return 1; } else { return 0; } } if ($output_selection == OUTPUT_INCLUDE) { if (defined($function_table{$name})) { return 1; } else { return 0; } } if ($output_selection == OUTPUT_EXCLUDE) { if (!defined($function_table{$name})) { return 1; } else { return 0; } } die("Please add the new output type at show_warnings()"); } sub dump_enum($$) { my $x = shift; my $file = shift; $x =~ s@/\*.*?\*/@@gos; # strip comments. # strip #define macros inside enums $x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos; if ($x =~ /enum\s+(\w*)\s*\{(.*)\}/) { $declaration_name = $1; my $members = $2; my %_members; $members =~ s/\s+$//; foreach my $arg (split ',', $members) { $arg =~ s/^\s*(\w+).*/$1/; push @parameterlist, $arg; if (!$parameterdescs{$arg}) { $parameterdescs{$arg} = $undescribed; if (show_warnings("enum", $declaration_name)) { print STDERR "${file}:$.: warning: Enum value '$arg' not described in enum '$declaration_name'\n"; } } $_members{$arg} = 1; } while (my ($k, $v) = each %parameterdescs) { if (!exists($_members{$k})) { if (show_warnings("enum", $declaration_name)) { print STDERR "${file}:$.: warning: Excess enum value '$k' description in '$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 "${file}:$.: error: Cannot parse enum!\n"; ++$errors; } } sub dump_typedef($$) { my $x = shift; my $file = shift; $x =~ s@/\*.*?\*/@@gos; # strip comments. # Parse function prototypes if ($x =~ /typedef\s+(\w+)\s*\(\*\s*(\w\S+)\s*\)\s*\((.*)\);/ || $x =~ /typedef\s+(\w+)\s*(\w\S+)\s*\s*\((.*)\);/) { # Function typedefs $return_type = $1; $declaration_name = $2; my $args = $3; create_parameterlist($args, ',', $file, $declaration_name); 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 }); return; } 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 "${file}:$.: error: 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 $declaration_name = 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, $declaration_name); } 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, $declaration_name); } elsif ($param =~ m/(.*?):(\d+)/) { if ($type ne "") { # skip unnamed bit-fields save_struct_actual($1); push_parameter($1, "$type:$2", $file, $declaration_name) } } else { save_struct_actual($param); push_parameter($param, $type, $file, $declaration_name); } } } } } sub push_parameter($$$$) { my $param = shift; my $type = 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);