]> git.proxmox.com Git - mirror_qemu.git/blame - scripts/qapi2texi.py
qmp: allow setting properties to empty string in qmp-shell
[mirror_qemu.git] / scripts / qapi2texi.py
CommitLineData
3313b612
MAL
1#!/usr/bin/env python
2# QAPI texi generator
3#
4# This work is licensed under the terms of the GNU LGPL, version 2+.
5# See the COPYING file in the top-level directory.
6"""This script produces the documentation of a qapi schema in texinfo format"""
7import re
8import sys
9
10import qapi
11
597494ab 12MSG_FMT = """
3313b612
MAL
13@deftypefn {type} {{}} {name}
14
15{body}
16
17@end deftypefn
18
19""".format
20
597494ab 21TYPE_FMT = """
3313b612
MAL
22@deftp {{{type}}} {name}
23
24{body}
25
26@end deftp
27
28""".format
29
30EXAMPLE_FMT = """@example
31{code}
32@end example
33""".format
34
35
36def subst_strong(doc):
37 """Replaces *foo* by @strong{foo}"""
38 return re.sub(r'\*([^*\n]+)\*', r'@emph{\1}', doc)
39
40
41def subst_emph(doc):
42 """Replaces _foo_ by @emph{foo}"""
43 return re.sub(r'\b_([^_\n]+)_\b', r' @emph{\1} ', doc)
44
45
46def subst_vars(doc):
47 """Replaces @var by @code{var}"""
48 return re.sub(r'@([\w-]+)', r'@code{\1}', doc)
49
50
51def subst_braces(doc):
52 """Replaces {} with @{ @}"""
53 return doc.replace("{", "@{").replace("}", "@}")
54
55
56def texi_example(doc):
57 """Format @example"""
58 # TODO: Neglects to escape @ characters.
59 # We should probably escape them in subst_braces(), and rename the
60 # function to subst_special() or subs_texi_special(). If we do that, we
61 # need to delay it until after subst_vars() in texi_format().
62 doc = subst_braces(doc).strip('\n')
63 return EXAMPLE_FMT(code=doc)
64
65
66def texi_format(doc):
67 """
68 Format documentation
69
70 Lines starting with:
71 - |: generates an @example
72 - =: generates @section
73 - ==: generates @subsection
74 - 1. or 1): generates an @enumerate @item
75 - */-: generates an @itemize list
76 """
77 lines = []
78 doc = subst_braces(doc)
79 doc = subst_vars(doc)
80 doc = subst_emph(doc)
81 doc = subst_strong(doc)
82 inlist = ""
83 lastempty = False
84 for line in doc.split('\n'):
85 empty = line == ""
86
87 # FIXME: Doing this in a single if / elif chain is
88 # problematic. For instance, a line without markup terminates
89 # a list if it follows a blank line (reaches the final elif),
90 # but a line with some *other* markup, such as a = title
91 # doesn't.
92 #
93 # Make sure to update section "Documentation markup" in
94 # docs/qapi-code-gen.txt when fixing this.
95 if line.startswith("| "):
96 line = EXAMPLE_FMT(code=line[2:])
97 elif line.startswith("= "):
98 line = "@section " + line[2:]
99 elif line.startswith("== "):
100 line = "@subsection " + line[3:]
101 elif re.match(r'^([0-9]*\.) ', line):
102 if not inlist:
103 lines.append("@enumerate")
104 inlist = "enumerate"
105 line = line[line.find(" ")+1:]
106 lines.append("@item")
107 elif re.match(r'^[*-] ', line):
108 if not inlist:
109 lines.append("@itemize %s" % {'*': "@bullet",
110 '-': "@minus"}[line[0]])
111 inlist = "itemize"
112 lines.append("@item")
113 line = line[2:]
114 elif lastempty and inlist:
115 lines.append("@end %s\n" % inlist)
116 inlist = ""
117
118 lastempty = empty
119 lines.append(line)
120
121 if inlist:
122 lines.append("@end %s\n" % inlist)
123 return "\n".join(lines)
124
125
126def texi_body(doc):
127 """
128 Format the body of a symbol documentation:
129 - main body
130 - table of arguments
131 - followed by "Returns/Notes/Since/Example" sections
132 """
133 body = texi_format(str(doc.body)) + "\n"
134 if doc.args:
135 body += "@table @asis\n"
136 for arg, section in doc.args.iteritems():
137 desc = str(section)
138 opt = ''
139 if "#optional" in desc:
140 desc = desc.replace("#optional", "")
141 opt = ' (optional)'
142 body += "@item @code{'%s'}%s\n%s\n" % (arg, opt,
143 texi_format(desc))
144 body += "@end table\n"
145
146 for section in doc.sections:
147 name, doc = (section.name, str(section))
148 func = texi_format
149 if name.startswith("Example"):
150 func = texi_example
151
152 if name:
1ede77df
MAL
153 # prefer @b over @strong, so txt doesn't translate it to *Foo:*
154 body += "\n\n@b{%s:}\n" % name
155
156 body += func(doc)
3313b612
MAL
157
158 return body
159
160
161def texi_alternate(expr, doc):
162 """Format an alternate to texi"""
163 body = texi_body(doc)
597494ab
MAL
164 return TYPE_FMT(type="Alternate",
165 name=doc.symbol,
166 body=body)
3313b612
MAL
167
168
169def texi_union(expr, doc):
170 """Format a union to texi"""
171 discriminator = expr.get("discriminator")
172 if discriminator:
173 union = "Flat Union"
174 else:
175 union = "Simple Union"
176
177 body = texi_body(doc)
597494ab
MAL
178 return TYPE_FMT(type=union,
179 name=doc.symbol,
180 body=body)
3313b612
MAL
181
182
183def texi_enum(expr, doc):
184 """Format an enum to texi"""
185 for i in expr['data']:
186 if i not in doc.args:
187 doc.args[i] = ''
188 body = texi_body(doc)
597494ab
MAL
189 return TYPE_FMT(type="Enum",
190 name=doc.symbol,
3313b612
MAL
191 body=body)
192
193
194def texi_struct(expr, doc):
195 """Format a struct to texi"""
196 body = texi_body(doc)
597494ab
MAL
197 return TYPE_FMT(type="Struct",
198 name=doc.symbol,
199 body=body)
3313b612
MAL
200
201
202def texi_command(expr, doc):
203 """Format a command to texi"""
204 body = texi_body(doc)
597494ab
MAL
205 return MSG_FMT(type="Command",
206 name=doc.symbol,
207 body=body)
3313b612
MAL
208
209
210def texi_event(expr, doc):
211 """Format an event to texi"""
212 body = texi_body(doc)
597494ab
MAL
213 return MSG_FMT(type="Event",
214 name=doc.symbol,
215 body=body)
3313b612
MAL
216
217
218def texi_expr(expr, doc):
219 """Format an expr to texi"""
220 (kind, _) = expr.items()[0]
221
222 fmt = {"command": texi_command,
223 "struct": texi_struct,
224 "enum": texi_enum,
225 "union": texi_union,
226 "alternate": texi_alternate,
227 "event": texi_event}[kind]
228
229 return fmt(expr, doc)
230
231
232def texi(docs):
233 """Convert QAPI schema expressions to texi documentation"""
234 res = []
235 for doc in docs:
236 expr = doc.expr
237 if not expr:
238 res.append(texi_body(doc))
239 continue
240 try:
241 doc = texi_expr(expr, doc)
242 res.append(doc)
243 except:
244 print >>sys.stderr, "error at @%s" % doc.info
245 raise
246
247 return '\n'.join(res)
248
249
250def main(argv):
251 """Takes schema argument, prints result to stdout"""
252 if len(argv) != 2:
253 print >>sys.stderr, "%s: need exactly 1 argument: SCHEMA" % argv[0]
254 sys.exit(1)
255
256 schema = qapi.QAPISchema(argv[1])
257 print texi(schema.docs)
258
259
260if __name__ == "__main__":
261 main(sys.argv)