[libvirt] minor doc generation glitch
Daniel Veillard
veillard at redhat.com
Thu Jun 16 07:56:53 UTC 2011
On Thu, Jun 16, 2011 at 01:19:47PM +0800, Daniel Veillard wrote:
> On Wed, Jun 15, 2011 at 03:21:44PM -0600, Eric Blake wrote:
> > On 06/15/2011 01:25 PM, Eric Blake wrote:
> > > Looking at
> > > http://libvirt.org/html/libvirt-libvirt.html#virDomainShutoffReason as
> > > an example, I see several places where there are spurious "*" in the
> > > generated documentation.
> >
> > Also, http://libvirt.org/html/libvirt-libvirt.html#virTypedParameter is
> > broken, listing 'charfield[length] field' rather than 'char[length]
> > field' or 'char field[length]' for the first member, and completely
> > missing out on the 'union{} value' member. It's okay if the docs don't
> > list structs in C syntax, but whatever syntax it does use should be
> > close enough to figure out the corresponding C syntax without having to
> > read the source header to check for missing struct members.
>
> I'm fixing those, nearly done ...
The enclosed patch includes quite a number of fixes
- parsing of "long long int" and similar
- add parsing of unions within a struct
- remove spurious " * " fron comments on structure fields and enums
- fix concatenation of base type and name in arrays
- extend XSLT to cope with union in structs
this is painful to read (this was apinful to write !), have a look at
the resulting libvirt-api.xml and generated page, that's the nicest way
to validate it :-)
Daniel
--
Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/
daniel at veillard.com | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library http://libvirt.org/
-------------- next part --------------
diff --git a/docs/apibuild.py b/docs/apibuild.py
index d9e9952..f31a853 100755
--- a/docs/apibuild.py
+++ b/docs/apibuild.py
@@ -179,6 +179,7 @@ class index:
self.variables = {}
self.includes = {}
self.structs = {}
+ self.unions = {}
self.enums = {}
self.typedefs = {}
self.macros = {}
@@ -232,6 +233,10 @@ class index:
self.includes[name] = d
elif type == "struct":
self.structs[name] = d
+ elif type == "struct":
+ self.structs[name] = d
+ elif type == "union":
+ self.unions[name] = d
elif type == "enum":
self.enums[name] = d
elif type == "typedef":
@@ -280,6 +285,13 @@ class index:
else:
self.structs[id] = idx.structs[id]
self.identifiers[id] = idx.structs[id]
+ for id in idx.unions.keys():
+ if self.unions.has_key(id):
+ print "union %s from %s redeclared in %s" % (
+ id, self.unions[id].header, idx.unions[id].header)
+ else:
+ self.unions[id] = idx.unions[id]
+ self.identifiers[id] = idx.unions[id]
for id in idx.typedefs.keys():
if self.typedefs.has_key(id):
print "typedef %s from %s redeclared in %s" % (
@@ -347,6 +359,7 @@ class index:
self.analyze_dict("functions", self.functions)
self.analyze_dict("variables", self.variables)
self.analyze_dict("structs", self.structs)
+ self.analyze_dict("unions", self.unions)
self.analyze_dict("typedefs", self.typedefs)
self.analyze_dict("macros", self.macros)
@@ -656,13 +669,36 @@ class CParser:
res[item] = line
self.index.info = res
+ def strip_lead_star(self, line):
+ l = len(line)
+ i = 0
+ while i < l:
+ if line[i] == ' ' or line[i] == '\t':
+ i += 1
+ elif line[i] == '*':
+ return line[:i] + line[i + 1:]
+ else:
+ return line
+ return line
+
+ def cleanupComment(self):
+ if type(self.comment) != type(""):
+ return
+ # remove the leading * on multi-line comments
+ lines = self.comment.splitlines(True)
+ com = ""
+ for line in lines:
+ com = com + self.strip_lead_star(line)
+ self.comment = com.strip()
+
def parseComment(self, token):
+ com = token[1]
if self.top_comment == "":
- self.top_comment = token[1]
- if self.comment == None or token[1][0] == '*':
- self.comment = token[1];
+ self.top_comment = com
+ if self.comment == None or com[0] == '*':
+ self.comment = com;
else:
- self.comment = self.comment + token[1]
+ self.comment = self.comment + com
token = self.lexer.token()
if string.find(self.comment, "DOC_DISABLE") != -1:
@@ -1178,7 +1214,13 @@ class CParser:
if token[0] == "sep" and token[1] == ";":
self.comment = None
token = self.token()
- fields.append((self.type, fname, self.comment))
+ self.cleanupComment()
+ if self.type == "union":
+ fields.append((self.type, fname, self.comment,
+ self.union_fields))
+ self.union_fields = []
+ else:
+ fields.append((self.type, fname, self.comment))
self.comment = None
else:
self.error("parseStruct: expecting ;", token)
@@ -1201,6 +1243,56 @@ class CParser:
return token
#
+ # Parse a C union definition till the balancing }
+ #
+ def parseUnion(self, token):
+ fields = []
+ # self.debug("start parseUnion", token)
+ while token != None:
+ if token[0] == "sep" and token[1] == "{":
+ token = self.token()
+ token = self.parseTypeBlock(token)
+ elif token[0] == "sep" and token[1] == "}":
+ self.union_fields = fields
+ # self.debug("end parseUnion", token)
+ # print fields
+ token = self.token()
+ return token
+ else:
+ base_type = self.type
+ # self.debug("before parseType", token)
+ token = self.parseType(token)
+ # self.debug("after parseType", token)
+ if token != None and token[0] == "name":
+ fname = token[1]
+ token = self.token()
+ if token[0] == "sep" and token[1] == ";":
+ self.comment = None
+ token = self.token()
+ self.cleanupComment()
+ fields.append((self.type, fname, self.comment))
+ self.comment = None
+ else:
+ self.error("parseUnion: expecting ;", token)
+ elif token != None and token[0] == "sep" and token[1] == "{":
+ token = self.token()
+ token = self.parseTypeBlock(token)
+ if token != None and token[0] == "name":
+ token = self.token()
+ if token != None and token[0] == "sep" and token[1] == ";":
+ token = self.token()
+ else:
+ self.error("parseUnion: expecting ;", token)
+ else:
+ self.error("parseUnion: name", token)
+ token = self.token()
+ self.type = base_type;
+ self.union_fields = fields
+ # self.debug("end parseUnion", token)
+ # print fields
+ return token
+
+ #
# Parse a C enum block, parse till the balancing }
#
def parseEnumBlock(self, token):
@@ -1215,6 +1307,7 @@ class CParser:
token = self.parseTypeBlock(token)
elif token[0] == "sep" and token[1] == "}":
if name != None:
+ self.cleanupComment()
if self.comment != None:
comment = self.comment
self.comment = None
@@ -1222,6 +1315,7 @@ class CParser:
token = self.token()
return token
elif token[0] == "name":
+ self.cleanupComment()
if name != None:
if self.comment != None:
comment = string.strip(self.comment)
@@ -1252,7 +1346,7 @@ class CParser:
return token
#
- # Parse a C definition block, used for structs it parse till
+ # Parse a C definition block, used for structs or unions it parse till
# the balancing }
#
def parseTypeBlock(self, token):
@@ -1275,6 +1369,7 @@ class CParser:
def parseType(self, token):
self.type = ""
self.struct_fields = []
+ self.union_fields = []
self.signature = None
if token == None:
return token
@@ -1304,22 +1399,19 @@ class CParser:
self.push(token)
token = oldtmp
+ oldtmp = token
+ token = self.token()
if token[0] == "name" and token[1] == "int":
- if self.type == "":
- self.type = tmp[1]
- else:
- self.type = self.type + " " + tmp[1]
+ self.type = self.type + " " + token[1]
+ else:
+ self.push(token)
+ token = oldtmp
elif token[0] == "name" and token[1] == "short":
if self.type == "":
self.type = token[1]
else:
self.type = self.type + " " + token[1]
- if token[0] == "name" and token[1] == "int":
- if self.type == "":
- self.type = tmp[1]
- else:
- self.type = self.type + " " + tmp[1]
elif token[0] == "name" and token[1] == "struct":
if self.type == "":
@@ -1355,6 +1447,28 @@ class CParser:
token = nametok
return token
+ elif token[0] == "name" and token[1] == "union":
+ if self.type == "":
+ self.type = token[1]
+ else:
+ self.type = self.type + " " + token[1]
+ token = self.token()
+ nametok = None
+ if token[0] == "name":
+ nametok = token
+ token = self.token()
+ if token != None and token[0] == "sep" and token[1] == "{":
+ token = self.token()
+ token = self.parseUnion(token)
+ elif token != None and token[0] == "name" and nametok != None:
+ self.type = self.type + " " + nametok[1]
+ return token
+
+ if nametok != None:
+ self.lexer.push(token)
+ token = nametok
+ return token
+
elif token[0] == "name" and token[1] == "enum":
if self.type == "":
self.type = token[1]
@@ -1434,7 +1548,7 @@ class CParser:
nametok = token
token = self.token()
if token != None and token[0] == "sep" and token[1] == '[':
- self.type = self.type + nametok[1]
+ self.type = self.type + " " + nametok[1]
while token != None and token[0] == "sep" and token[1] == '[':
self.type = self.type + token[1]
token = self.token()
@@ -1844,6 +1958,20 @@ class docBuilder:
pass
output.write(" </macro>\n")
+ def serialize_union(self, output, field, desc):
+ output.write(" <field name='%s' type='union' info='%s'>\n" % (field[1] , desc))
+ output.write(" <union>\n")
+ for f in field[3]:
+ desc = f[2]
+ if desc == None:
+ desc = ''
+ else:
+ desc = escape(desc)
+ output.write(" <field name='%s' type='%s' info='%s'/>\n" % (f[1] , f[0], desc))
+
+ output.write(" </union>\n")
+ output.write(" </field>\n")
+
def serialize_typedef(self, output, name):
id = self.idx.typedefs[name]
if id.info[0:7] == 'struct ':
@@ -1862,7 +1990,10 @@ class docBuilder:
desc = ''
else:
desc = escape(desc)
- output.write(" <field name='%s' type='%s' info='%s'/>\n" % (field[1] , field[0], desc))
+ if field[0] == "union":
+ self.serialize_union(output, field, desc)
+ else:
+ output.write(" <field name='%s' type='%s' info='%s'/>\n" % (field[1] , field[0], desc))
except:
print "Failed to serialize struct %s" % (name)
output.write(" </struct>\n")
@@ -1961,6 +2092,8 @@ class docBuilder:
continue
if dict.structs.has_key(id):
continue
+ if dict.unions.has_key(id):
+ continue
if dict.enums.has_key(id):
continue
output.write(" <exports symbol='%s' type='macro'/>\n" % (id))
diff --git a/docs/newapi.xsl b/docs/newapi.xsl
index b59674a..445a48c 100644
--- a/docs/newapi.xsl
+++ b/docs/newapi.xsl
@@ -174,22 +174,62 @@
</pre>
<table>
<xsl:for-each select="field">
- <tr>
- <td>
- <xsl:call-template name="dumptext">
- <xsl:with-param name="text" select="@type"/>
- </xsl:call-template>
- </td>
- <td><xsl:value-of select="@name"/></td>
- <xsl:if test="@info != ''">
- <td>
- <xsl:text> : </xsl:text>
- <xsl:call-template name="dumptext">
- <xsl:with-param name="text" select="@info"/>
- </xsl:call-template>
- </td>
- </xsl:if>
- </tr>
+ <xsl:choose>
+ <xsl:when test='@type = "union"'>
+ <tr><td>union {</td></tr>
+ <tr>
+ <td><table>
+ <xsl:for-each select="union/field">
+ <tr>
+ <td>
+ <xsl:call-template name="dumptext">
+ <xsl:with-param name="text" select="@type"/>
+ </xsl:call-template>
+ </td>
+ <td><xsl:value-of select="@name"/></td>
+ <xsl:if test="@info != ''">
+ <td>
+ <xsl:text> : </xsl:text>
+ <xsl:call-template name="dumptext">
+ <xsl:with-param name="text" select="@info"/>
+ </xsl:call-template>
+ </td>
+ </xsl:if>
+ </tr>
+ </xsl:for-each>
+ </table></td>
+ <td></td></tr>
+ <tr><td>}</td>
+ <td><xsl:value-of select="@name"/></td>
+ <xsl:if test="@info != ''">
+ <td>
+ <xsl:text> : </xsl:text>
+ <xsl:call-template name="dumptext">
+ <xsl:with-param name="text" select="@info"/>
+ </xsl:call-template>
+ </td>
+ </xsl:if>
+ <td></td></tr>
+ </xsl:when>
+ <xsl:otherwise>
+ <tr>
+ <td>
+ <xsl:call-template name="dumptext">
+ <xsl:with-param name="text" select="@type"/>
+ </xsl:call-template>
+ </td>
+ <td><xsl:value-of select="@name"/></td>
+ <xsl:if test="@info != ''">
+ <td>
+ <xsl:text> : </xsl:text>
+ <xsl:call-template name="dumptext">
+ <xsl:with-param name="text" select="@info"/>
+ </xsl:call-template>
+ </td>
+ </xsl:if>
+ </tr>
+ </xsl:otherwise>
+ </xsl:choose>
</xsl:for-each>
<xsl:if test="not(field)">
<tr>
More information about the libvir-list
mailing list