There are several places within the Kernel tree with nested
structs/unions, like this one:

  struct ingenic_cgu_clk_info {
    const char *name;
    enum {
      CGU_CLK_NONE = 0,
      CGU_CLK_EXT = BIT(0),
      CGU_CLK_PLL = BIT(1),
      CGU_CLK_GATE = BIT(2),
      CGU_CLK_MUX = BIT(3),
      CGU_CLK_MUX_GLITCHFREE = BIT(4),
      CGU_CLK_DIV = BIT(5),
      CGU_CLK_FIXDIV = BIT(6),
      CGU_CLK_CUSTOM = BIT(7),
    } type;
    int parents[4];
    union {
      struct ingenic_cgu_pll_info pll;
      struct {
        struct ingenic_cgu_gate_info gate;
        struct ingenic_cgu_mux_info mux;
        struct ingenic_cgu_div_info div;
        struct ingenic_cgu_fixdiv_info fixdiv;
      };
      struct ingenic_cgu_custom_info custom;
    };
  };

Currently, such struct is documented as:

        **Definition**

        ::
        struct ingenic_cgu_clk_info {
            const char * name;
        };

        **Members**

        ``name``
          name of the clock

With is obvioulsy wrong. It also generates an error:
        drivers/clk/ingenic/cgu.h:169: warning: No description found for 
parameter 'enum'

However, there's nothing wrong with this kernel-doc markup: everything
is documented there.

It makes sense to document all fields there. So, add a
way for the core to parse those structs.

With this patch, all documented fields will properly generate
documentation.

Signed-off-by: Mauro Carvalho Chehab <mche...@s-opensource.com>
---

Jon,

Please let me know what you think about this approach. IMHO, it is a way
better than what we do right now. This is more a proof of concept, as the
patch is not complete. 

With it, we can now document both anonymous and named unions/structs.

For named structs, the name of the fields should be in the format:
        foo.bar

What's missing on this PoC:

1) I didn't check if @foo.bar: would work, though.  Probably the parser
   for it should be added to allow this new syntax.

2) I only changed the ReST output to preserve the struct format with
   nested fields. 

For (2), I'm thinking is we should still have all those output formats for
kernel-doc. IMHO, I would keep just RST (and perhaps man - while we don't
have a "make man" targed working.

Depending on your comments, I'll proceed addressing (1) and (2)
and doing more tests with it.



 scripts/kernel-doc | 83 +++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 54 insertions(+), 29 deletions(-)

diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 9d3eafea58f0..5ca81b879088 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -2035,29 +2035,9 @@ sub output_struct_rst(%) {
 
     print "**Definition**\n\n";
     print "::\n\n";
-    print "  " . $args{'type'} . " " . $args{'struct'} . " {\n";
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       if ($parameter =~ /^#/) {
-           print "  " . "$parameter\n";
-           next;
-       }
-
-       my $parameter_name = $parameter;
-       $parameter_name =~ s/\[.*//;
-
-       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
-       $type = $args{'parametertypes'}{$parameter};
-       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
-           # pointer-to-function
-           print "    $1 $parameter) ($2);\n";
-       } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
-           # bitfield
-           print "    $1 $parameter$2;\n";
-       } else {
-           print "    " . $type . " " . $parameter . ";\n";
-       }
-    }
-    print "  };\n\n";
+    my $declaration = $args{'definition'};
+    $declaration =~ s/\t/  /g;
+    print "  " . $args{'type'} . " " . $args{'struct'} . " {\n$declaration  
};\n\n";
 
     print "**Members**\n\n";
     $lineprefix = "  ";
@@ -2168,20 +2148,15 @@ sub dump_struct($$) {
     my $nested;
 
     if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) {
-       #my $decl_type = $1;
+       my $decl_type = $1;
        $declaration_name = $2;
        my $members = $3;
 
-       # ignore embedded structs or unions
-       $members =~ s/({.*})//g;
-       $nested = $1;
-
        # ignore members marked private:
        $members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gosi;
        $members =~ s/\/\*\s*private:.*//gosi;
        # strip comments:
        $members =~ s/\/\*.*?\*\///gos;
-       $nested =~ s/\/\*.*?\*\///gos;
        # strip kmemcheck_bitfield_{begin,end}.*;
        $members =~ s/kmemcheck_bitfield_.*?;//gos;
        # strip attributes
@@ -2193,13 +2168,63 @@ sub dump_struct($$) {
        # replace DECLARE_HASHTABLE
        $members =~ s/DECLARE_HASHTABLE\s*\(([^,)]+), ([^,)]+)\)/unsigned long 
$1\[1 << (($2) - 1)\]/gos;
 
+       my $declaration = $members;
+
+       # Split nested struct/union elements as newer ones
+       my $cont = 1;
+       while ($cont) {
+               $cont = 0;
+               while ($members =~ 
m/(struct|union)([^{};]+){([^{}]*)}([^{}\;]*)\;/) {
+                       my $newmember = "$1 $4;";
+                       my $id = $4;
+                       my $content = $3;
+                       $id =~ s/[:\[].*//;
+                       foreach my $arg (split /;/, $content) {
+                               next if ($arg =~ m/^\s*$/);
+                               my $type = $arg;
+                               my $name = $arg;
+                               $type =~ s/\s\S+$//;
+                               $name =~ s/.*\s//;
+                               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/;
+                       $cont = 1;
+               };
+       };
+
+       # Ignore other nested elements, like enums
+       $members =~ s/({[^\{\}]*})//g;
+       $nested = $decl_type;
+       $nested =~ s/\/\*.*?\*\///gos;
+
        create_parameterlist($members, ';', $file);
        check_sections($file, $declaration_name, "struct", $sectcheck, 
$struct_actual, $nested);
 
+       # Adjust declaration for better display
+       $declaration =~ s/([{,;])/$1\n/g;
+       $declaration =~ s/}\s+;/};/g;
+       my @def_args = split /\n/, $declaration;
+       my $level = 2;
+       $declaration = "";
+       foreach my $clause (@def_args) {
+               $clause =~ s/^\s+//;
+               $clause =~ s/\s+$//;
+               $clause =~ s/\s+/ /;
+               $level-- if ($clause =~ m/}/ && $level > 2);
+               $declaration .= "\t" x $level . $clause . "\n" if ($clause);
+               $level++ if ($clause =~ m/{/);
+       }
        output_declaration($declaration_name,
                           'struct',
                           {'struct' => $declaration_name,
                            'module' => $modulename,
+                           'definition' => $declaration,
                            'parameterlist' => \@parameterlist,
                            'parameterdescs' => \%parameterdescs,
                            'parametertypes' => \%parametertypes,
-- 
2.13.5


--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to