aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan Corbet <corbet@lwn.net>2016-06-09 15:17:11 -0400
committerJonathan Corbet <corbet@lwn.net>2016-06-09 15:17:11 -0400
commit6d5244c72ec9cfff1390152ef7cc8540af0f2748 (patch)
tree5cea34dba67f50293d93afe9366f65896f678007
parentf3e6a55c3653b071705e266473b87696786dfd99 (diff)
parentd90368f2fa7ded7c56d214aef087e88bba5199e7 (diff)
Merge branch 'sphinx-for-docs-next' into doc/4.8
Jani Nikula says: Jon, this is v2 of [1] and [2], with a considerable amount of polish and fixes added. We started dogfooding this within drm-intel, and Daniel has reviewed the lot and contributed a number of fixes, most notably accurate file and line number references from Sphinx build errors/warnings to the kernel-doc comments in source code. We believe this is now in good shape for merging for v4.8. It's all in my sphinx-for-docs-next branch that you've already looked at; pull details below. When this lands in docs-next and we can backmerge to drm, we'll plunge ahead and convert gpu.tmpl to rst, and have that ready for v4.8. We think it's best to contribute that via the drm tree, as it'll involve splitting up the documentation and likely numerous updates to kernel-doc comments. I plan to update Documentation/kernel-doc-nano-HOWTO.txt for Sphinx and rst, obviously converting it to rst while at it.
-rw-r--r--Documentation/.gitignore1
-rw-r--r--Documentation/DocBook/Makefile7
-rw-r--r--Documentation/Makefile.sphinx63
-rw-r--r--Documentation/conf.py414
-rw-r--r--Documentation/index.rst23
-rw-r--r--Documentation/sphinx/convert_template.sed18
-rw-r--r--Documentation/sphinx/kernel-doc.py127
-rw-r--r--Documentation/sphinx/post_convert.sed23
-rwxr-xr-xDocumentation/sphinx/tmplcvt19
-rw-r--r--Makefile5
-rwxr-xr-xscripts/kernel-doc392
11 files changed, 948 insertions, 144 deletions
diff --git a/Documentation/.gitignore b/Documentation/.gitignore
new file mode 100644
index 000000000000..53752db253e3
--- /dev/null
+++ b/Documentation/.gitignore
@@ -0,0 +1 @@
output
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index d70f9b68174e..e0c7e1e0590b 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -33,10 +33,6 @@ PDF_METHOD = $(prefer-db2x)
33PS_METHOD = $(prefer-db2x) 33PS_METHOD = $(prefer-db2x)
34 34
35 35
36###
37# The targets that may be used.
38PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs
39
40targets += $(DOCBOOKS) 36targets += $(DOCBOOKS)
41BOOKS := $(addprefix $(obj)/,$(DOCBOOKS)) 37BOOKS := $(addprefix $(obj)/,$(DOCBOOKS))
42xmldocs: $(BOOKS) 38xmldocs: $(BOOKS)
@@ -63,6 +59,9 @@ installmandocs: mandocs
63 sort -k 2 -k 1 | uniq -f 1 | sed -e 's: :/:' | \ 59 sort -k 2 -k 1 | uniq -f 1 | sed -e 's: :/:' | \
64 xargs install -m 644 -t /usr/local/man/man9/ 60 xargs install -m 644 -t /usr/local/man/man9/
65 61
62# no-op for the DocBook toolchain
63epubdocs:
64
66### 65###
67#External programs used 66#External programs used
68KERNELDOCXMLREF = $(srctree)/scripts/kernel-doc-xml-ref 67KERNELDOCXMLREF = $(srctree)/scripts/kernel-doc-xml-ref
diff --git a/Documentation/Makefile.sphinx b/Documentation/Makefile.sphinx
new file mode 100644
index 000000000000..addf32309bc3
--- /dev/null
+++ b/Documentation/Makefile.sphinx
@@ -0,0 +1,63 @@
1# -*- makefile -*-
2# Makefile for Sphinx documentation
3#
4
5# You can set these variables from the command line.
6SPHINXBUILD = sphinx-build
7SPHINXOPTS =
8PAPER =
9BUILDDIR = $(obj)/output
10
11# User-friendly check for sphinx-build
12HAVE_SPHINX := $(shell if which $(SPHINXBUILD) >/dev/null 2>&1; then echo 1; else echo 0; fi)
13
14ifeq ($(HAVE_SPHINX),0)
15
16.DEFAULT:
17 $(warning The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed and in PATH, or set the SPHINXBUILD make variable to point to the full path of the '$(SPHINXBUILD)' executable.)
18 @echo " SKIP Sphinx $@ target."
19
20else # HAVE_SPHINX
21
22# User-friendly check for rst2pdf
23HAVE_RST2PDF := $(shell if python -c "import rst2pdf" >/dev/null 2>&1; then echo 1; else echo 0; fi)
24
25# Internal variables.
26PAPEROPT_a4 = -D latex_paper_size=a4
27PAPEROPT_letter = -D latex_paper_size=letter
28KERNELDOC = $(srctree)/scripts/kernel-doc
29KERNELDOC_CONF = -D kerneldoc_srctree=$(srctree) -D kerneldoc_bin=$(KERNELDOC)
30ALLSPHINXOPTS = -D version=$(KERNELVERSION) -D release=$(KERNELRELEASE) -d $(BUILDDIR)/.doctrees $(KERNELDOC_CONF) $(PAPEROPT_$(PAPER)) -c $(srctree)/$(src) $(SPHINXOPTS) $(srctree)/$(src)
31# the i18n builder cannot share the environment and doctrees with the others
32I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
33
34quiet_cmd_sphinx = SPHINX $@
35 cmd_sphinx = $(SPHINXBUILD) -b $2 $(ALLSPHINXOPTS) $(BUILDDIR)/$2
36
37htmldocs:
38 $(call cmd,sphinx,html)
39
40pdfdocs:
41ifeq ($(HAVE_RST2PDF),0)
42 $(warning The Python 'rst2pdf' module was not found. Make sure you have the module installed to produce PDF output.)
43 @echo " SKIP Sphinx $@ target."
44else # HAVE_RST2PDF
45 $(call cmd,sphinx,pdf)
46endif # HAVE_RST2PDF
47
48epubdocs:
49 $(call cmd,sphinx,epub)
50
51xmldocs:
52 $(call cmd,sphinx,xml)
53
54# no-ops for the Sphinx toolchain
55sgmldocs:
56psdocs:
57mandocs:
58installmandocs:
59
60cleandocs:
61 $(Q)rm -rf $(BUILDDIR)
62
63endif # HAVE_SPHINX
diff --git a/Documentation/conf.py b/Documentation/conf.py
new file mode 100644
index 000000000000..6cc41a0555a3
--- /dev/null
+++ b/Documentation/conf.py
@@ -0,0 +1,414 @@
1# -*- coding: utf-8 -*-
2#
3# The Linux Kernel documentation build configuration file, created by
4# sphinx-quickstart on Fri Feb 12 13:51:46 2016.
5#
6# This file is execfile()d with the current directory set to its
7# containing dir.
8#
9# Note that not all possible configuration values are present in this
10# autogenerated file.
11#
12# All configuration values have a default; values that are commented out
13# serve to show the default.
14
15import sys
16import os
17
18# If extensions (or modules to document with autodoc) are in another directory,
19# add these directories to sys.path here. If the directory is relative to the
20# documentation root, use os.path.abspath to make it absolute, like shown here.
21sys.path.insert(0, os.path.abspath('sphinx'))
22
23# -- General configuration ------------------------------------------------
24
25# If your documentation needs a minimal Sphinx version, state it here.
26#needs_sphinx = '1.0'
27
28# Add any Sphinx extension module names here, as strings. They can be
29# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
30# ones.
31extensions = ['kernel-doc']
32
33# Gracefully handle missing rst2pdf.
34try:
35 import rst2pdf
36 extensions += ['rst2pdf.pdfbuilder']
37except ImportError:
38 pass
39
40# Add any paths that contain templates here, relative to this directory.
41templates_path = ['_templates']
42
43# The suffix(es) of source filenames.
44# You can specify multiple suffix as a list of string:
45# source_suffix = ['.rst', '.md']
46source_suffix = '.rst'
47
48# The encoding of source files.
49#source_encoding = 'utf-8-sig'
50
51# The master toctree document.
52master_doc = 'index'
53
54# General information about the project.
55project = 'The Linux Kernel'
56copyright = '2016, The kernel development community'
57author = 'The kernel development community'
58
59# The version info for the project you're documenting, acts as replacement for
60# |version| and |release|, also used in various other places throughout the
61# built documents.
62#
63# In a normal build, version and release are are set to KERNELVERSION and
64# KERNELRELEASE, respectively, from the Makefile via Sphinx command line
65# arguments.
66#
67# The following code tries to extract the information by reading the Makefile,
68# when Sphinx is run directly (e.g. by Read the Docs).
69try:
70 makefile_version = None
71 makefile_patchlevel = None
72 for line in open('../Makefile'):
73 key, val = [x.strip() for x in line.split('=', 2)]
74 if key == 'VERSION':
75 makefile_version = val
76 elif key == 'PATCHLEVEL':
77 makefile_patchlevel = val
78 if makefile_version and makefile_patchlevel:
79 break
80except:
81 pass
82finally:
83 if makefile_version and makefile_patchlevel:
84 version = release = makefile_version + '.' + makefile_patchlevel
85 else:
86 sys.stderr.write('Warning: Could not extract kernel version\n')
87 version = release = "unknown version"
88
89# The language for content autogenerated by Sphinx. Refer to documentation
90# for a list of supported languages.
91#
92# This is also used if you do content translation via gettext catalogs.
93# Usually you set "language" from the command line for these cases.
94language = None
95
96# There are two options for replacing |today|: either, you set today to some
97# non-false value, then it is used:
98#today = ''
99# Else, today_fmt is used as the format for a strftime call.
100#today_fmt = '%B %d, %Y'
101
102# List of patterns, relative to source directory, that match files and
103# directories to ignore when looking for source files.
104exclude_patterns = ['output']
105
106# The reST default role (used for this markup: `text`) to use for all
107# documents.
108#default_role = None
109
110# If true, '()' will be appended to :func: etc. cross-reference text.
111#add_function_parentheses = True
112
113# If true, the current module name will be prepended to all description
114# unit titles (such as .. function::).
115#add_module_names = True
116
117# If true, sectionauthor and moduleauthor directives will be shown in the
118# output. They are ignored by default.
119#show_authors = False
120
121# The name of the Pygments (syntax highlighting) style to use.
122pygments_style = 'sphinx'
123
124# A list of ignored prefixes for module index sorting.
125#modindex_common_prefix = []
126
127# If true, keep warnings as "system message" paragraphs in the built documents.
128#keep_warnings = False
129
130# If true, `todo` and `todoList` produce output, else they produce nothing.
131todo_include_todos = False
132
133primary_domain = 'C'
134highlight_language = 'C'
135
136# -- Options for HTML output ----------------------------------------------
137
138# The theme to use for HTML and HTML Help pages. See the documentation for
139# a list of builtin themes.
140
141# The Read the Docs theme is available from
142# - https://github.com/snide/sphinx_rtd_theme
143# - https://pypi.python.org/pypi/sphinx_rtd_theme
144# - python-sphinx-rtd-theme package (on Debian)
145try:
146 import sphinx_rtd_theme
147 html_theme = 'sphinx_rtd_theme'
148 html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
149except ImportError:
150 sys.stderr.write('Warning: The Sphinx \'sphinx_rtd_theme\' HTML theme was not found. Make sure you have the theme installed to produce pretty HTML output. Falling back to the default theme.\n')
151
152# Theme options are theme-specific and customize the look and feel of a theme
153# further. For a list of options available for each theme, see the
154# documentation.
155#html_theme_options = {}
156
157# Add any paths that contain custom themes here, relative to this directory.
158#html_theme_path = []
159
160# The name for this set of Sphinx documents. If None, it defaults to
161# "<project> v<release> documentation".
162#html_title = None
163
164# A shorter title for the navigation bar. Default is the same as html_title.
165#html_short_title = None
166
167# The name of an image file (relative to this directory) to place at the top
168# of the sidebar.
169#html_logo = None
170
171# The name of an image file (within the static path) to use as favicon of the
172# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
173# pixels large.
174#html_favicon = None
175
176# Add any paths that contain custom static files (such as style sheets) here,
177# relative to this directory. They are copied after the builtin static files,
178# so a file named "default.css" will overwrite the builtin "default.css".
179#html_static_path = ['_static']
180
181# Add any extra paths that contain custom files (such as robots.txt or
182# .htaccess) here, relative to this directory. These files are copied
183# directly to the root of the documentation.
184#html_extra_path = []
185
186# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
187# using the given strftime format.
188#html_last_updated_fmt = '%b %d, %Y'
189
190# If true, SmartyPants will be used to convert quotes and dashes to
191# typographically correct entities.
192#html_use_smartypants = True
193
194# Custom sidebar templates, maps document names to template names.
195#html_sidebars = {}
196
197# Additional templates that should be rendered to pages, maps page names to
198# template names.
199#html_additional_pages = {}
200
201# If false, no module index is generated.
202#html_domain_indices = True
203
204# If false, no index is generated.
205#html_use_index = True
206
207# If true, the index is split into individual pages for each letter.
208#html_split_index = False
209
210# If true, links to the reST sources are added to the pages.
211#html_show_sourcelink = True
212
213# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
214#html_show_sphinx = True
215
216# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
217#html_show_copyright = True
218
219# If true, an OpenSearch description file will be output, and all pages will
220# contain a <link> tag referring to it. The value of this option must be the
221# base URL from which the finished HTML is served.
222#html_use_opensearch = ''
223
224# This is the file name suffix for HTML files (e.g. ".xhtml").
225#html_file_suffix = None
226
227# Language to be used for generating the HTML full-text search index.
228# Sphinx supports the following languages:
229# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja'
230# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr'
231#html_search_language = 'en'
232
233# A dictionary with options for the search language support, empty by default.
234# Now only 'ja' uses this config value
235#html_search_options = {'type': 'default'}
236
237# The name of a javascript file (relative to the configuration directory) that
238# implements a search results scorer. If empty, the default will be used.
239#html_search_scorer = 'scorer.js'
240
241# Output file base name for HTML help builder.
242htmlhelp_basename = 'TheLinuxKerneldoc'
243
244# -- Options for LaTeX output ---------------------------------------------
245
246latex_elements = {
247# The paper size ('letterpaper' or 'a4paper').
248#'papersize': 'letterpaper',
249
250# The font size ('10pt', '11pt' or '12pt').
251#'pointsize': '10pt',
252
253# Additional stuff for the LaTeX preamble.
254#'preamble': '',
255
256# Latex figure (float) alignment
257#'figure_align': 'htbp',
258}
259
260# Grouping the document tree into LaTeX files. List of tuples
261# (source start file, target name, title,
262# author, documentclass [howto, manual, or own class]).
263latex_documents = [
264 (master_doc, 'TheLinuxKernel.tex', 'The Linux Kernel Documentation',
265 'The kernel development community', 'manual'),
266]
267
268# The name of an image file (relative to this directory) to place at the top of
269# the title page.
270#latex_logo = None
271
272# For "manual" documents, if this is true, then toplevel headings are parts,
273# not chapters.
274#latex_use_parts = False
275
276# If true, show page references after internal links.
277#latex_show_pagerefs = False
278
279# If true, show URL addresses after external links.
280#latex_show_urls = False
281
282# Documents to append as an appendix to all manuals.
283#latex_appendices = []
284
285# If false, no module index is generated.
286#latex_domain_indices = True
287
288
289# -- Options for manual page output ---------------------------------------
290
291# One entry per manual page. List of tuples
292# (source start file, name, description, authors, manual section).
293man_pages = [
294 (master_doc, 'thelinuxkernel', 'The Linux Kernel Documentation',
295 [author], 1)
296]
297
298# If true, show URL addresses after external links.
299#man_show_urls = False
300
301
302# -- Options for Texinfo output -------------------------------------------
303
304# Grouping the document tree into Texinfo files. List of tuples
305# (source start file, target name, title, author,
306# dir menu entry, description, category)
307texinfo_documents = [
308 (master_doc, 'TheLinuxKernel', 'The Linux Kernel Documentation',
309 author, 'TheLinuxKernel', 'One line description of project.',
310 'Miscellaneous'),
311]
312
313# Documents to append as an appendix to all manuals.
314#texinfo_appendices = []
315
316# If false, no module index is generated.
317#texinfo_domain_indices = True
318
319# How to display URL addresses: 'footnote', 'no', or 'inline'.
320#texinfo_show_urls = 'footnote'
321
322# If true, do not generate a @detailmenu in the "Top" node's menu.
323#texinfo_no_detailmenu = False
324
325
326# -- Options for Epub output ----------------------------------------------
327
328# Bibliographic Dublin Core info.
329epub_title = project
330epub_author = author
331epub_publisher = author
332epub_copyright = copyright
333
334# The basename for the epub file. It defaults to the project name.
335#epub_basename = project
336
337# The HTML theme for the epub output. Since the default themes are not
338# optimized for small screen space, using the same theme for HTML and epub
339# output is usually not wise. This defaults to 'epub', a theme designed to save
340# visual space.
341#epub_theme = 'epub'
342
343# The language of the text. It defaults to the language option
344# or 'en' if the language is not set.
345#epub_language = ''
346
347# The scheme of the identifier. Typical schemes are ISBN or URL.
348#epub_scheme = ''
349
350# The unique identifier of the text. This can be a ISBN number
351# or the project homepage.
352#epub_identifier = ''
353
354# A unique identification for the text.
355#epub_uid = ''
356
357# A tuple containing the cover image and cover page html template filenames.
358#epub_cover = ()
359
360# A sequence of (type, uri, title) tuples for the guide element of content.opf.
361#epub_guide = ()
362
363# HTML files that should be inserted before the pages created by sphinx.
364# The format is a list of tuples containing the path and title.
365#epub_pre_files = []
366
367# HTML files that should be inserted after the pages created by sphinx.
368# The format is a list of tuples containing the path and title.
369#epub_post_files = []
370
371# A list of files that should not be packed into the epub file.
372epub_exclude_files = ['search.html']
373
374# The depth of the table of contents in toc.ncx.
375#epub_tocdepth = 3
376
377# Allow duplicate toc entries.
378#epub_tocdup = True
379
380# Choose between 'default' and 'includehidden'.
381#epub_tocscope = 'default'
382
383# Fix unsupported image types using the Pillow.
384#epub_fix_images = False
385
386# Scale large images.
387#epub_max_image_width = 0
388
389# How to display URL addresses: 'footnote', 'no', or 'inline'.
390#epub_show_urls = 'inline'
391
392# If false, no index is generated.
393#epub_use_index = True
394
395#=======
396# rst2pdf
397#
398# Grouping the document tree into PDF files. List of tuples
399# (source start file, target name, title, author, options).
400#
401# See the Sphinx chapter of http://ralsina.me/static/manual.pdf
402#
403# FIXME: Do not add the index file here; the result will be too big. Adding
404# multiple PDF files here actually tries to get the cross-referencing right
405# *between* PDF files.
406pdf_documents = [
407 ('index', u'Kernel', u'Kernel', u'J. Random Bozo'),
408]
409
410# kernel-doc extension configuration for running Sphinx directly (e.g. by Read
411# the Docs). In a normal build, these are supplied from the Makefile via command
412# line arguments.
413kerneldoc_bin = '../scripts/kernel-doc'
414kerneldoc_srctree = '..'
diff --git a/Documentation/index.rst b/Documentation/index.rst
new file mode 100644
index 000000000000..71a276f34c7f
--- /dev/null
+++ b/Documentation/index.rst
@@ -0,0 +1,23 @@
1.. The Linux Kernel documentation master file, created by
2 sphinx-quickstart on Fri Feb 12 13:51:46 2016.
3 You can adapt this file completely to your liking, but it should at least
4 contain the root `toctree` directive.
5
6Welcome to The Linux Kernel's documentation!
7============================================
8
9Nothing for you to see here *yet*. Please move along.
10
11Contents:
12
13.. toctree::
14 :maxdepth: 2
15
16
17Indices and tables
18==================
19
20* :ref:`genindex`
21* :ref:`modindex`
22* :ref:`search`
23
diff --git a/Documentation/sphinx/convert_template.sed b/Documentation/sphinx/convert_template.sed
new file mode 100644
index 000000000000..c1503fcca4ec
--- /dev/null
+++ b/Documentation/sphinx/convert_template.sed
@@ -0,0 +1,18 @@
1#
2# Pandoc doesn't grok <function> or <structname>, so convert them
3# ahead of time.
4#
5# Use the following escapes to pass through pandoc:
6# $bq = "`"
7# $lt = "<"
8# $gt = ">"
9#
10s%<function>\([^<(]\+\)()</function>%:c:func:$bq\1()$bq%g
11s%<function>\([^<(]\+\)</function>%:c:func:$bq\1()$bq%g
12s%<structname>struct *\([^<]\+\)</structname>%:c:type:$bqstruct \1 $lt\1$gt$bq%g
13s%struct <structname>\([^<]\+\)</structname>%:c:type:$bqstruct \1 $lt\1$gt$bq%g
14s%<structname>\([^<]\+\)</structname>%:c:type:$bqstruct \1 $lt\1$gt$bq%g
15#
16# Wrap docproc directives in para and code blocks.
17#
18s%^\(!.*\)$%<para><code>DOCPROC: \1</code></para>%
diff --git a/Documentation/sphinx/kernel-doc.py b/Documentation/sphinx/kernel-doc.py
new file mode 100644
index 000000000000..4adfb0e91ecc
--- /dev/null
+++ b/Documentation/sphinx/kernel-doc.py
@@ -0,0 +1,127 @@
1# coding=utf-8
2#
3# Copyright © 2016 Intel Corporation
4#
5# Permission is hereby granted, free of charge, to any person obtaining a
6# copy of this software and associated documentation files (the "Software"),
7# to deal in the Software without restriction, including without limitation
8# the rights to use, copy, modify, merge, publish, distribute, sublicense,
9# and/or sell copies of the Software, and to permit persons to whom the
10# Software is furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice (including the next
13# paragraph) shall be included in all copies or substantial portions of the
14# Software.
15#
16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22# IN THE SOFTWARE.
23#
24# Authors:
25# Jani Nikula <jani.nikula@intel.com>
26#
27# Please make sure this works on both python2 and python3.
28#
29
30import os
31import subprocess
32import sys
33import re
34
35from docutils import nodes, statemachine
36from docutils.statemachine import ViewList
37from docutils.parsers.rst import directives
38from sphinx.util.compat import Directive
39
40class KernelDocDirective(Directive):
41 """Extract kernel-doc comments from the specified file"""
42 required_argument = 1
43 optional_arguments = 4
44 option_spec = {
45 'doc': directives.unchanged_required,
46 'functions': directives.unchanged_required,
47 'export': directives.flag,
48 'internal': directives.flag,
49 }
50 has_content = False
51
52 def run(self):
53 env = self.state.document.settings.env
54 cmd = [env.config.kerneldoc_bin, '-rst', '-enable-lineno']
55
56 filename = env.config.kerneldoc_srctree + '/' + self.arguments[0]
57
58 # Tell sphinx of the dependency
59 env.note_dependency(os.path.abspath(filename))
60
61 tab_width = self.options.get('tab-width', self.state.document.settings.tab_width)
62 source = filename
63
64 # FIXME: make this nicer and more robust against errors
65 if 'export' in self.options:
66 cmd += ['-export']
67 elif 'internal' in self.options:
68 cmd += ['-internal']
69 elif 'doc' in self.options:
70 cmd += ['-function', str(self.options.get('doc'))]
71 elif 'functions' in self.options:
72 for f in str(self.options.get('functions')).split(' '):
73 cmd += ['-function', f]
74
75 cmd += [filename]
76
77 try:
78 env.app.verbose('calling kernel-doc \'%s\'' % (" ".join(cmd)))
79
80 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
81 out, err = p.communicate()
82
83 # python2 needs conversion to unicode.
84 # python3 with universal_newlines=True returns strings.
85 if sys.version_info.major < 3:
86 out, err = unicode(out, 'utf-8'), unicode(err, 'utf-8')
87
88 if p.returncode != 0:
89 sys.stderr.write(err)
90
91 env.app.warn('kernel-doc \'%s\' failed with return code %d' % (" ".join(cmd), p.returncode))
92 return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]
93 elif env.config.kerneldoc_verbosity > 0:
94 sys.stderr.write(err)
95
96 lines = statemachine.string2lines(out, tab_width, convert_whitespace=True)
97 result = ViewList()
98
99 lineoffset = 0;
100 line_regex = re.compile("^#define LINENO ([0-9]+)$")
101 for line in lines:
102 match = line_regex.search(line)
103 if match:
104 # sphinx counts lines from 0
105 lineoffset = int(match.group(1)) - 1
106 # we must eat our comments since the upset the markup
107 else:
108 result.append(line, source, lineoffset)
109 lineoffset += 1
110
111 node = nodes.section()
112 node.document = self.state.document
113 self.state.nested_parse(result, self.content_offset, node)
114
115 return node.children
116
117 except Exception as e:
118 env.app.warn('kernel-doc \'%s\' processing failed with: %s' %
119 (" ".join(cmd), str(e)))
120 return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]
121
122def setup(app):
123 app.add_config_value('kerneldoc_bin', None, 'env')
124 app.add_config_value('kerneldoc_srctree', None, 'env')
125 app.add_config_value('kerneldoc_verbosity', 1, 'env')
126
127 app.add_directive('kernel-doc', KernelDocDirective)
diff --git a/Documentation/sphinx/post_convert.sed b/Documentation/sphinx/post_convert.sed
new file mode 100644
index 000000000000..392770bac53b
--- /dev/null
+++ b/Documentation/sphinx/post_convert.sed
@@ -0,0 +1,23 @@
1#
2# Unescape.
3#
4s/$bq/`/g
5s/$lt/</g
6s/$gt/>/g
7#
8# pandoc thinks that both "_" needs to be escaped. Remove the extra
9# backslashes.
10#
11s/\\_/_/g
12#
13# Unwrap docproc directives.
14#
15s/^``DOCPROC: !E\(.*\)``$/.. kernel-doc:: \1\n :export:/
16s/^``DOCPROC: !I\(.*\)``$/.. kernel-doc:: \1\n :internal:/
17s/^``DOCPROC: !F\([^ ]*\) \(.*\)``$/.. kernel-doc:: \1\n :functions: \2/
18s/^``DOCPROC: !P\([^ ]*\) \(.*\)``$/.. kernel-doc:: \1\n :doc: \2/
19s/^``DOCPROC: \(!.*\)``$/.. WARNING: DOCPROC directive not supported: \1/
20#
21# Trim trailing whitespace.
22#
23s/[[:space:]]*$//
diff --git a/Documentation/sphinx/tmplcvt b/Documentation/sphinx/tmplcvt
new file mode 100755
index 000000000000..909a73065e0a
--- /dev/null
+++ b/Documentation/sphinx/tmplcvt
@@ -0,0 +1,19 @@
1#!/bin/bash
2#
3# Convert a template file into something like RST
4#
5# fix <function>
6# feed to pandoc
7# fix \_
8# title line?
9#
10
11in=$1
12rst=$2
13tmp=$rst.tmp
14
15cp $in $tmp
16sed --in-place -f convert_template.sed $tmp
17pandoc -s -S -f docbook -t rst -o $rst $tmp
18sed --in-place -f post_convert.sed $rst
19rm $tmp
diff --git a/Makefile b/Makefile
index 0f70de63cfdb..8908a51b895a 100644
--- a/Makefile
+++ b/Makefile
@@ -1412,8 +1412,11 @@ $(help-board-dirs): help-%:
1412 1412
1413# Documentation targets 1413# Documentation targets
1414# --------------------------------------------------------------------------- 1414# ---------------------------------------------------------------------------
1415%docs: scripts_basic FORCE 1415DOC_TARGETS := xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs epubdocs cleandocs
1416PHONY += $(DOC_TARGETS)
1417$(DOC_TARGETS): scripts_basic FORCE
1416 $(Q)$(MAKE) $(build)=scripts build_docproc build_check-lc_ctype 1418 $(Q)$(MAKE) $(build)=scripts build_docproc build_check-lc_ctype
1419 $(Q)$(MAKE) $(build)=Documentation -f $(srctree)/Documentation/Makefile.sphinx $@
1417 $(Q)$(MAKE) $(build)=Documentation/DocBook $@ 1420 $(Q)$(MAKE) $(build)=Documentation/DocBook $@
1418 1421
1419else # KBUILD_EXTMOD 1422else # KBUILD_EXTMOD
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 2fc8fad5195e..5192213c5005 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -59,6 +59,12 @@ Output format selection (mutually exclusive):
59 -text Output plain text format. 59 -text Output plain text format.
60 60
61Output selection (mutually exclusive): 61Output selection (mutually exclusive):
62 -export Only output documentation for symbols that have been
63 exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL()
64 in the same FILE.
65 -internal Only output documentation for symbols that have NOT been
66 exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL()
67 in the same FILE.
62 -function NAME Only output documentation for the given function(s) 68 -function NAME Only output documentation for the given function(s)
63 or DOC: section title(s). All other functions and DOC: 69 or DOC: section title(s). All other functions and DOC:
64 sections are ignored. May be specified multiple times. 70 sections are ignored. May be specified multiple times.
@@ -68,6 +74,8 @@ Output selection (mutually exclusive):
68 74
69Output selection modifiers: 75Output selection modifiers:
70 -no-doc-sections Do not output DOC: sections. 76 -no-doc-sections Do not output DOC: sections.
77 -enable-lineno Enable output of #define LINENO lines. Only works with
78 reStructuredText format.
71 79
72Other parameters: 80Other parameters:
73 -v Verbose output, more warnings and other information. 81 -v Verbose output, more warnings and other information.
@@ -206,6 +214,10 @@ my $type_struct_xml = '\\&amp;((struct\s*)*[_\w]+)';
206my $type_env = '(\$\w+)'; 214my $type_env = '(\$\w+)';
207my $type_enum_full = '\&(enum)\s*([_\w]+)'; 215my $type_enum_full = '\&(enum)\s*([_\w]+)';
208my $type_struct_full = '\&(struct)\s*([_\w]+)'; 216my $type_struct_full = '\&(struct)\s*([_\w]+)';
217my $type_typedef_full = '\&(typedef)\s*([_\w]+)';
218my $type_union_full = '\&(union)\s*([_\w]+)';
219my $type_member = '\&([_\w]+)((\.|->)[_\w]+)';
220my $type_member_func = $type_member . '\(\)';
209 221
210# Output conversion substitutions. 222# Output conversion substitutions.
211# One for each output format 223# One for each output format
@@ -274,10 +286,16 @@ my $blankline_text = "";
274# rst-mode 286# rst-mode
275my @highlights_rst = ( 287my @highlights_rst = (
276 [$type_constant, "``\$1``"], 288 [$type_constant, "``\$1``"],
277 [$type_func, "\\:c\\:func\\:`\$1`"], 289 # Note: need to escape () to avoid func matching later
290 [$type_member_func, "\\:c\\:type\\:`\$1\$2\\\\(\\\\) <\$1>`"],
291 [$type_member, "\\:c\\:type\\:`\$1\$2 <\$1>`"],
292 [$type_func, "\\:c\\:func\\:`\$1()`"],
278 [$type_struct_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], 293 [$type_struct_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"],
279 [$type_enum_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], 294 [$type_enum_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"],
280 [$type_struct, "\\:c\\:type\\:`struct \$1 <\$1>`"], 295 [$type_typedef_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"],
296 [$type_union_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"],
297 # in rst this can refer to any type
298 [$type_struct, "\\:c\\:type\\:`\$1`"],
281 [$type_param, "**\$1**"] 299 [$type_param, "**\$1**"]
282 ); 300 );
283my $blankline_rst = "\n"; 301my $blankline_rst = "\n";
@@ -303,10 +321,19 @@ my $verbose = 0;
303my $output_mode = "man"; 321my $output_mode = "man";
304my $output_preformatted = 0; 322my $output_preformatted = 0;
305my $no_doc_sections = 0; 323my $no_doc_sections = 0;
324my $enable_lineno = 0;
306my @highlights = @highlights_man; 325my @highlights = @highlights_man;
307my $blankline = $blankline_man; 326my $blankline = $blankline_man;
308my $modulename = "Kernel API"; 327my $modulename = "Kernel API";
309my $function_only = 0; 328
329use constant {
330 OUTPUT_ALL => 0, # output all symbols and doc sections
331 OUTPUT_INCLUDE => 1, # output only specified symbols
332 OUTPUT_EXCLUDE => 2, # output everything except specified symbols
333 OUTPUT_EXPORTED => 3, # output exported symbols
334 OUTPUT_INTERNAL => 4, # output non-exported symbols
335};
336my $output_selection = OUTPUT_ALL;
310my $show_not_found = 0; 337my $show_not_found = 0;
311 338
312my @build_time; 339my @build_time;
@@ -327,6 +354,7 @@ my $man_date = ('January', 'February', 'March', 'April', 'May', 'June',
327# CAVEAT EMPTOR! Some of the others I localised may not want to be, which 354# CAVEAT EMPTOR! Some of the others I localised may not want to be, which
328# could cause "use of undefined value" or other bugs. 355# could cause "use of undefined value" or other bugs.
329my ($function, %function_table, %parametertypes, $declaration_purpose); 356my ($function, %function_table, %parametertypes, $declaration_purpose);
357my $declaration_start_line;
330my ($type, $declaration_name, $return_type); 358my ($type, $declaration_name, $return_type);
331my ($newsection, $newcontents, $prototype, $brcount, %source_map); 359my ($newsection, $newcontents, $prototype, $brcount, %source_map);
332 360
@@ -344,52 +372,61 @@ my $section_counter = 0;
344 372
345my $lineprefix=""; 373my $lineprefix="";
346 374
347# states 375# Parser states
348# 0 - normal code 376use constant {
349# 1 - looking for function name 377 STATE_NORMAL => 0, # normal code
350# 2 - scanning field start. 378 STATE_NAME => 1, # looking for function name
351# 3 - scanning prototype. 379 STATE_FIELD => 2, # scanning field start
352# 4 - documentation block 380 STATE_PROTO => 3, # scanning prototype
353# 5 - gathering documentation outside main block 381 STATE_DOCBLOCK => 4, # documentation block
382 STATE_INLINE => 5, # gathering documentation outside main block
383};
354my $state; 384my $state;
355my $in_doc_sect; 385my $in_doc_sect;
356 386
357# Split Doc State 387# Inline documentation state
358# 0 - Invalid (Before start or after finish) 388use constant {
359# 1 - Is started (the /** was found inside a struct) 389 STATE_INLINE_NA => 0, # not applicable ($state != STATE_INLINE)
360# 2 - The @parameter header was found, start accepting multi paragraph text. 390 STATE_INLINE_NAME => 1, # looking for member name (@foo:)
361# 3 - Finished (the */ was found) 391 STATE_INLINE_TEXT => 2, # looking for member documentation
362# 4 - Error - Comment without header was found. Spit a warning as it's not 392 STATE_INLINE_END => 3, # done
363# proper kernel-doc and ignore the rest. 393 STATE_INLINE_ERROR => 4, # error - Comment without header was found.
364my $split_doc_state; 394 # Spit a warning as it's not
395 # proper kernel-doc and ignore the rest.
396};
397my $inline_doc_state;
365 398
366#declaration types: can be 399#declaration types: can be
367# 'function', 'struct', 'union', 'enum', 'typedef' 400# 'function', 'struct', 'union', 'enum', 'typedef'
368my $decl_type; 401my $decl_type;
369 402
370my $doc_special = "\@\%\$\&";
371
372my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start. 403my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start.
373my $doc_end = '\*/'; 404my $doc_end = '\*/';
374my $doc_com = '\s*\*\s*'; 405my $doc_com = '\s*\*\s*';
375my $doc_com_body = '\s*\* ?'; 406my $doc_com_body = '\s*\* ?';
376my $doc_decl = $doc_com . '(\w+)'; 407my $doc_decl = $doc_com . '(\w+)';
377my $doc_sect = $doc_com . '([' . $doc_special . ']?[\w\s]+):(.*)'; 408# @params and a strictly limited set of supported section names
409my $doc_sect = $doc_com . '\s*(\@\w+|description|context|returns?)\s*:(.*)';
378my $doc_content = $doc_com_body . '(.*)'; 410my $doc_content = $doc_com_body . '(.*)';
379my $doc_block = $doc_com . 'DOC:\s*(.*)?'; 411my $doc_block = $doc_com . 'DOC:\s*(.*)?';
380my $doc_split_start = '^\s*/\*\*\s*$'; 412my $doc_inline_start = '^\s*/\*\*\s*$';
381my $doc_split_sect = '\s*\*\s*(@[\w\s]+):(.*)'; 413my $doc_inline_sect = '\s*\*\s*(@[\w\s]+):(.*)';
382my $doc_split_end = '^\s*\*/\s*$'; 414my $doc_inline_end = '^\s*\*/\s*$';
415my $export_symbol = '^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*;';
383 416
384my %constants;
385my %parameterdescs; 417my %parameterdescs;
418my %parameterdesc_start_lines;
386my @parameterlist; 419my @parameterlist;
387my %sections; 420my %sections;
388my @sectionlist; 421my @sectionlist;
422my %section_start_lines;
389my $sectcheck; 423my $sectcheck;
390my $struct_actual; 424my $struct_actual;
391 425
392my $contents = ""; 426my $contents = "";
427my $new_start_line = 0;
428
429# the canonical section names. see also $doc_sect above.
393my $section_default = "Description"; # default section 430my $section_default = "Description"; # default section
394my $section_intro = "Introduction"; 431my $section_intro = "Introduction";
395my $section = $section_default; 432my $section = $section_default;
@@ -437,19 +474,27 @@ while ($ARGV[0] =~ m/^-(.*)/) {
437 } elsif ($cmd eq "-module") { # not needed for XML, inherits from calling document 474 } elsif ($cmd eq "-module") { # not needed for XML, inherits from calling document
438 $modulename = shift @ARGV; 475 $modulename = shift @ARGV;
439 } elsif ($cmd eq "-function") { # to only output specific functions 476 } elsif ($cmd eq "-function") { # to only output specific functions
440 $function_only = 1; 477 $output_selection = OUTPUT_INCLUDE;
441 $function = shift @ARGV; 478 $function = shift @ARGV;
442 $function_table{$function} = 1; 479 $function_table{$function} = 1;
443 } elsif ($cmd eq "-nofunction") { # to only output specific functions 480 } elsif ($cmd eq "-nofunction") { # output all except specific functions
444 $function_only = 2; 481 $output_selection = OUTPUT_EXCLUDE;
445 $function = shift @ARGV; 482 $function = shift @ARGV;
446 $function_table{$function} = 1; 483 $function_table{$function} = 1;
484 } elsif ($cmd eq "-export") { # only exported symbols
485 $output_selection = OUTPUT_EXPORTED;
486 %function_table = ()
487 } elsif ($cmd eq "-internal") { # only non-exported symbols
488 $output_selection = OUTPUT_INTERNAL;
489 %function_table = ()
447 } elsif ($cmd eq "-v") { 490 } elsif ($cmd eq "-v") {
448 $verbose = 1; 491 $verbose = 1;
449 } elsif (($cmd eq "-h") || ($cmd eq "--help")) { 492 } elsif (($cmd eq "-h") || ($cmd eq "--help")) {
450 usage(); 493 usage();
451 } elsif ($cmd eq '-no-doc-sections') { 494 } elsif ($cmd eq '-no-doc-sections') {
452 $no_doc_sections = 1; 495 $no_doc_sections = 1;
496 } elsif ($cmd eq '-enable-lineno') {
497 $enable_lineno = 1;
453 } elsif ($cmd eq '-show-not-found') { 498 } elsif ($cmd eq '-show-not-found') {
454 $show_not_found = 1; 499 $show_not_found = 1;
455 } 500 }
@@ -467,6 +512,13 @@ sub get_kernel_version() {
467 return $version; 512 return $version;
468} 513}
469 514
515#
516sub print_lineno {
517 my $lineno = shift;
518 if ($enable_lineno && defined($lineno)) {
519 print "#define LINENO " . $lineno . "\n";
520 }
521}
470## 522##
471# dumps section contents to arrays/hashes intended for that purpose. 523# dumps section contents to arrays/hashes intended for that purpose.
472# 524#
@@ -475,28 +527,32 @@ sub dump_section {
475 my $name = shift; 527 my $name = shift;
476 my $contents = join "\n", @_; 528 my $contents = join "\n", @_;
477 529
478 if ($name =~ m/$type_constant/) { 530 if ($name =~ m/$type_param/) {
479 $name = $1;
480# print STDERR "constant section '$1' = '$contents'\n";
481 $constants{$name} = $contents;
482 } elsif ($name =~ m/$type_param/) {
483# print STDERR "parameter def '$1' = '$contents'\n"; 531# print STDERR "parameter def '$1' = '$contents'\n";
484 $name = $1; 532 $name = $1;
485 $parameterdescs{$name} = $contents; 533 $parameterdescs{$name} = $contents;
486 $sectcheck = $sectcheck . $name . " "; 534 $sectcheck = $sectcheck . $name . " ";
535 $parameterdesc_start_lines{$name} = $new_start_line;
536 $new_start_line = 0;
487 } elsif ($name eq "@\.\.\.") { 537 } elsif ($name eq "@\.\.\.") {
488# print STDERR "parameter def '...' = '$contents'\n"; 538# print STDERR "parameter def '...' = '$contents'\n";
489 $name = "..."; 539 $name = "...";
490 $parameterdescs{$name} = $contents; 540 $parameterdescs{$name} = $contents;
491 $sectcheck = $sectcheck . $name . " "; 541 $sectcheck = $sectcheck . $name . " ";
542 $parameterdesc_start_lines{$name} = $new_start_line;
543 $new_start_line = 0;
492 } else { 544 } else {
493# print STDERR "other section '$name' = '$contents'\n"; 545# print STDERR "other section '$name' = '$contents'\n";
494 if (defined($sections{$name}) && ($sections{$name} ne "")) { 546 if (defined($sections{$name}) && ($sections{$name} ne "")) {
495 print STDERR "${file}:$.: error: duplicate section name '$name'\n"; 547 print STDERR "${file}:$.: warning: duplicate section name '$name'\n";
496 ++$errors; 548 ++$warnings;
549 $sections{$name} .= $contents;
550 } else {
551 $sections{$name} = $contents;
552 push @sectionlist, $name;
553 $section_start_lines{$name} = $new_start_line;
554 $new_start_line = 0;
497 } 555 }
498 $sections{$name} = $contents;
499 push @sectionlist, $name;
500 } 556 }
501} 557}
502 558
@@ -512,15 +568,17 @@ sub dump_doc_section {
512 return; 568 return;
513 } 569 }
514 570
515 if (($function_only == 0) || 571 if (($output_selection == OUTPUT_ALL) ||
516 ( $function_only == 1 && defined($function_table{$name})) || 572 ($output_selection == OUTPUT_INCLUDE &&
517 ( $function_only == 2 && !defined($function_table{$name}))) 573 defined($function_table{$name})) ||
574 ($output_selection == OUTPUT_EXCLUDE &&
575 !defined($function_table{$name})))
518 { 576 {
519 dump_section($file, $name, $contents); 577 dump_section($file, $name, $contents);
520 output_blockhead({'sectionlist' => \@sectionlist, 578 output_blockhead({'sectionlist' => \@sectionlist,
521 'sections' => \%sections, 579 'sections' => \%sections,
522 'module' => $modulename, 580 'module' => $modulename,
523 'content-only' => ($function_only != 0), }); 581 'content-only' => ($output_selection != OUTPUT_ALL), });
524 } 582 }
525} 583}
526 584
@@ -1736,7 +1794,10 @@ sub output_blockhead_rst(%) {
1736 my ($parameter, $section); 1794 my ($parameter, $section);
1737 1795
1738 foreach $section (@{$args{'sectionlist'}}) { 1796 foreach $section (@{$args{'sectionlist'}}) {
1739 print "**$section**\n\n"; 1797 if ($output_selection != OUTPUT_INCLUDE) {
1798 print "**$section**\n\n";
1799 }
1800 print_lineno($section_start_lines{$section});
1740 output_highlight_rst($args{'sections'}{$section}); 1801 output_highlight_rst($args{'sections'}{$section});
1741 print "\n"; 1802 print "\n";
1742 } 1803 }
@@ -1753,19 +1814,14 @@ sub output_highlight_rst {
1753 die $@ if $@; 1814 die $@ if $@;
1754 1815
1755 foreach $line (split "\n", $contents) { 1816 foreach $line (split "\n", $contents) {
1756 if ($line eq "") { 1817 print $lineprefix . $line . "\n";
1757 print $lineprefix, $blankline;
1758 } else {
1759 $line =~ s/\\\\\\/\&/g;
1760 print $lineprefix, $line;
1761 }
1762 print "\n";
1763 } 1818 }
1764} 1819}
1765 1820
1766sub output_function_rst(%) { 1821sub output_function_rst(%) {
1767 my %args = %{$_[0]}; 1822 my %args = %{$_[0]};
1768 my ($parameter, $section); 1823 my ($parameter, $section);
1824 my $oldprefix = $lineprefix;
1769 my $start; 1825 my $start;
1770 1826
1771 print ".. c:function:: "; 1827 print ".. c:function:: ";
@@ -1790,29 +1846,37 @@ sub output_function_rst(%) {
1790 print $type . " " . $parameter; 1846 print $type . " " . $parameter;
1791 } 1847 }
1792 } 1848 }
1793 print ")\n\n " . $args{'purpose'} . "\n\n"; 1849 print ")\n\n";
1850 print_lineno($declaration_start_line);
1851 $lineprefix = " ";
1852 output_highlight_rst($args{'purpose'});
1853 print "\n";
1794 1854
1795 print ":Parameters:\n\n"; 1855 print "**Parameters**\n\n";
1856 $lineprefix = " ";
1796 foreach $parameter (@{$args{'parameterlist'}}) { 1857 foreach $parameter (@{$args{'parameterlist'}}) {
1797 my $parameter_name = $parameter; 1858 my $parameter_name = $parameter;
1798 #$parameter_name =~ s/\[.*//; 1859 #$parameter_name =~ s/\[.*//;
1799 $type = $args{'parametertypes'}{$parameter}; 1860 $type = $args{'parametertypes'}{$parameter};
1800 1861
1801 if ($type ne "") { 1862 if ($type ne "") {
1802 print " ``$type $parameter``\n"; 1863 print "``$type $parameter``\n";
1803 } else { 1864 } else {
1804 print " ``$parameter``\n"; 1865 print "``$parameter``\n";
1805 } 1866 }
1806 if ($args{'parameterdescs'}{$parameter_name} ne $undescribed) { 1867
1807 my $oldprefix = $lineprefix; 1868 print_lineno($parameterdesc_start_lines{$parameter_name});
1808 $lineprefix = " "; 1869
1870 if (defined($args{'parameterdescs'}{$parameter_name}) &&
1871 $args{'parameterdescs'}{$parameter_name} ne $undescribed) {
1809 output_highlight_rst($args{'parameterdescs'}{$parameter_name}); 1872 output_highlight_rst($args{'parameterdescs'}{$parameter_name});
1810 $lineprefix = $oldprefix;
1811 } else { 1873 } else {
1812 print "\n _undescribed_\n"; 1874 print " *undescribed*\n";
1813 } 1875 }
1814 print "\n"; 1876 print "\n";
1815 } 1877 }
1878
1879 $lineprefix = $oldprefix;
1816 output_section_rst(@_); 1880 output_section_rst(@_);
1817} 1881}
1818 1882
@@ -1820,10 +1884,11 @@ sub output_section_rst(%) {
1820 my %args = %{$_[0]}; 1884 my %args = %{$_[0]};
1821 my $section; 1885 my $section;
1822 my $oldprefix = $lineprefix; 1886 my $oldprefix = $lineprefix;
1823 $lineprefix = " "; 1887 $lineprefix = "";
1824 1888
1825 foreach $section (@{$args{'sectionlist'}}) { 1889 foreach $section (@{$args{'sectionlist'}}) {
1826 print ":$section:\n\n"; 1890 print "**$section**\n\n";
1891 print_lineno($section_start_lines{$section});
1827 output_highlight_rst($args{'sections'}{$section}); 1892 output_highlight_rst($args{'sections'}{$section});
1828 print "\n"; 1893 print "\n";
1829 } 1894 }
@@ -1834,24 +1899,28 @@ sub output_section_rst(%) {
1834sub output_enum_rst(%) { 1899sub output_enum_rst(%) {
1835 my %args = %{$_[0]}; 1900 my %args = %{$_[0]};
1836 my ($parameter); 1901 my ($parameter);
1902 my $oldprefix = $lineprefix;
1837 my $count; 1903 my $count;
1838 my $name = "enum " . $args{'enum'}; 1904 my $name = "enum " . $args{'enum'};
1839 1905
1840 print "\n\n.. c:type:: " . $name . "\n\n"; 1906 print "\n\n.. c:type:: " . $name . "\n\n";
1841 print " " . $args{'purpose'} . "\n\n"; 1907 print_lineno($declaration_start_line);
1908 $lineprefix = " ";
1909 output_highlight_rst($args{'purpose'});
1910 print "\n";
1842 1911
1843 print "..\n\n:Constants:\n\n"; 1912 print "**Constants**\n\n";
1844 my $oldprefix = $lineprefix; 1913 $lineprefix = " ";
1845 $lineprefix = " ";
1846 foreach $parameter (@{$args{'parameterlist'}}) { 1914 foreach $parameter (@{$args{'parameterlist'}}) {
1847 print " `$parameter`\n"; 1915 print "``$parameter``\n";
1848 if ($args{'parameterdescs'}{$parameter} ne $undescribed) { 1916 if ($args{'parameterdescs'}{$parameter} ne $undescribed) {
1849 output_highlight_rst($args{'parameterdescs'}{$parameter}); 1917 output_highlight_rst($args{'parameterdescs'}{$parameter});
1850 } else { 1918 } else {
1851 print " undescribed\n"; 1919 print " *undescribed*\n";
1852 } 1920 }
1853 print "\n"; 1921 print "\n";
1854 } 1922 }
1923
1855 $lineprefix = $oldprefix; 1924 $lineprefix = $oldprefix;
1856 output_section_rst(@_); 1925 output_section_rst(@_);
1857} 1926}
@@ -1859,30 +1928,37 @@ sub output_enum_rst(%) {
1859sub output_typedef_rst(%) { 1928sub output_typedef_rst(%) {
1860 my %args = %{$_[0]}; 1929 my %args = %{$_[0]};
1861 my ($parameter); 1930 my ($parameter);
1862 my $count; 1931 my $oldprefix = $lineprefix;
1863 my $name = "typedef " . $args{'typedef'}; 1932 my $name = "typedef " . $args{'typedef'};
1864 1933
1865 ### FIXME: should the name below contain "typedef" or not?
1866 print "\n\n.. c:type:: " . $name . "\n\n"; 1934 print "\n\n.. c:type:: " . $name . "\n\n";
1867 print " " . $args{'purpose'} . "\n\n"; 1935 print_lineno($declaration_start_line);
1936 $lineprefix = " ";
1937 output_highlight_rst($args{'purpose'});
1938 print "\n";
1868 1939
1940 $lineprefix = $oldprefix;
1869 output_section_rst(@_); 1941 output_section_rst(@_);
1870} 1942}
1871 1943
1872sub output_struct_rst(%) { 1944sub output_struct_rst(%) {
1873 my %args = %{$_[0]}; 1945 my %args = %{$_[0]};
1874 my ($parameter); 1946 my ($parameter);
1947 my $oldprefix = $lineprefix;
1875 my $name = $args{'type'} . " " . $args{'struct'}; 1948 my $name = $args{'type'} . " " . $args{'struct'};
1876 1949
1877 print "\n\n.. c:type:: " . $name . "\n\n"; 1950 print "\n\n.. c:type:: " . $name . "\n\n";
1878 print " " . $args{'purpose'} . "\n\n"; 1951 print_lineno($declaration_start_line);
1952 $lineprefix = " ";
1953 output_highlight_rst($args{'purpose'});
1954 print "\n";
1879 1955
1880 print ":Definition:\n\n"; 1956 print "**Definition**\n\n";
1881 print " ::\n\n"; 1957 print "::\n\n";
1882 print " " . $args{'type'} . " " . $args{'struct'} . " {\n"; 1958 print " " . $args{'type'} . " " . $args{'struct'} . " {\n";
1883 foreach $parameter (@{$args{'parameterlist'}}) { 1959 foreach $parameter (@{$args{'parameterlist'}}) {
1884 if ($parameter =~ /^#/) { 1960 if ($parameter =~ /^#/) {
1885 print " " . "$parameter\n"; 1961 print " " . "$parameter\n";
1886 next; 1962 next;
1887 } 1963 }
1888 1964
@@ -1903,7 +1979,8 @@ sub output_struct_rst(%) {
1903 } 1979 }
1904 print " };\n\n"; 1980 print " };\n\n";
1905 1981
1906 print ":Members:\n\n"; 1982 print "**Members**\n\n";
1983 $lineprefix = " ";
1907 foreach $parameter (@{$args{'parameterlist'}}) { 1984 foreach $parameter (@{$args{'parameterlist'}}) {
1908 ($parameter =~ /^#/) && next; 1985 ($parameter =~ /^#/) && next;
1909 1986
@@ -1912,14 +1989,14 @@ sub output_struct_rst(%) {
1912 1989
1913 ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; 1990 ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
1914 $type = $args{'parametertypes'}{$parameter}; 1991 $type = $args{'parametertypes'}{$parameter};
1915 print " `$type $parameter`" . "\n"; 1992 print_lineno($parameterdesc_start_lines{$parameter_name});
1916 my $oldprefix = $lineprefix; 1993 print "``$type $parameter``\n";
1917 $lineprefix = " ";
1918 output_highlight_rst($args{'parameterdescs'}{$parameter_name}); 1994 output_highlight_rst($args{'parameterdescs'}{$parameter_name});
1919 $lineprefix = $oldprefix;
1920 print "\n"; 1995 print "\n";
1921 } 1996 }
1922 print "\n"; 1997 print "\n";
1998
1999 $lineprefix = $oldprefix;
1923 output_section_rst(@_); 2000 output_section_rst(@_);
1924} 2001}
1925 2002
@@ -1969,9 +2046,13 @@ sub output_declaration {
1969 my $name = shift; 2046 my $name = shift;
1970 my $functype = shift; 2047 my $functype = shift;
1971 my $func = "output_${functype}_$output_mode"; 2048 my $func = "output_${functype}_$output_mode";
1972 if (($function_only==0) || 2049 if (($output_selection == OUTPUT_ALL) ||
1973 ( $function_only == 1 && defined($function_table{$name})) || 2050 (($output_selection == OUTPUT_INCLUDE ||
1974 ( $function_only == 2 && !($functype eq "function" && defined($function_table{$name})))) 2051 $output_selection == OUTPUT_EXPORTED) &&
2052 defined($function_table{$name})) ||
2053 (($output_selection == OUTPUT_EXCLUDE ||
2054 $output_selection == OUTPUT_INTERNAL) &&
2055 !($functype eq "function" && defined($function_table{$name}))))
1975 { 2056 {
1976 &$func(@_); 2057 &$func(@_);
1977 $section_counter++; 2058 $section_counter++;
@@ -2471,7 +2552,6 @@ sub dump_function($$) {
2471 2552
2472sub reset_state { 2553sub reset_state {
2473 $function = ""; 2554 $function = "";
2474 %constants = ();
2475 %parameterdescs = (); 2555 %parameterdescs = ();
2476 %parametertypes = (); 2556 %parametertypes = ();
2477 @parameterlist = (); 2557 @parameterlist = ();
@@ -2481,8 +2561,8 @@ sub reset_state {
2481 $struct_actual = ""; 2561 $struct_actual = "";
2482 $prototype = ""; 2562 $prototype = "";
2483 2563
2484 $state = 0; 2564 $state = STATE_NORMAL;
2485 $split_doc_state = 0; 2565 $inline_doc_state = STATE_INLINE_NA;
2486} 2566}
2487 2567
2488sub tracepoint_munge($) { 2568sub tracepoint_munge($) {
@@ -2545,7 +2625,7 @@ sub syscall_munge() {
2545 } 2625 }
2546} 2626}
2547 2627
2548sub process_state3_function($$) { 2628sub process_proto_function($$) {
2549 my $x = shift; 2629 my $x = shift;
2550 my $file = shift; 2630 my $file = shift;
2551 2631
@@ -2575,7 +2655,7 @@ sub process_state3_function($$) {
2575 } 2655 }
2576} 2656}
2577 2657
2578sub process_state3_type($$) { 2658sub process_proto_type($$) {
2579 my $x = shift; 2659 my $x = shift;
2580 my $file = shift; 2660 my $file = shift;
2581 2661
@@ -2657,6 +2737,7 @@ sub process_file($) {
2657 my $in_purpose = 0; 2737 my $in_purpose = 0;
2658 my $initial_section_counter = $section_counter; 2738 my $initial_section_counter = $section_counter;
2659 my ($orig_file) = @_; 2739 my ($orig_file) = @_;
2740 my $leading_space;
2660 2741
2661 if (defined($ENV{'SRCTREE'})) { 2742 if (defined($ENV{'SRCTREE'})) {
2662 $file = "$ENV{'SRCTREE'}" . "/" . $orig_file; 2743 $file = "$ENV{'SRCTREE'}" . "/" . $orig_file;
@@ -2674,6 +2755,17 @@ sub process_file($) {
2674 return; 2755 return;
2675 } 2756 }
2676 2757
2758 # two passes for -export and -internal
2759 if ($output_selection == OUTPUT_EXPORTED ||
2760 $output_selection == OUTPUT_INTERNAL) {
2761 while (<IN>) {
2762 if (/$export_symbol/o) {
2763 $function_table{$2} = 1;
2764 }
2765 }
2766 seek(IN, 0, 0);
2767 }
2768
2677 $. = 1; 2769 $. = 1;
2678 2770
2679 $section_counter = 0; 2771 $section_counter = 0;
@@ -2681,15 +2773,18 @@ sub process_file($) {
2681 while (s/\\\s*$//) { 2773 while (s/\\\s*$//) {
2682 $_ .= <IN>; 2774 $_ .= <IN>;
2683 } 2775 }
2684 if ($state == 0) { 2776 if ($state == STATE_NORMAL) {
2685 if (/$doc_start/o) { 2777 if (/$doc_start/o) {
2686 $state = 1; # next line is always the function name 2778 $state = STATE_NAME; # next line is always the function name
2687 $in_doc_sect = 0; 2779 $in_doc_sect = 0;
2780 $declaration_start_line = $. + 1;
2688 } 2781 }
2689 } elsif ($state == 1) { # this line is the function name (always) 2782 } elsif ($state == STATE_NAME) {# this line is the function name (always)
2690 if (/$doc_block/o) { 2783 if (/$doc_block/o) {
2691 $state = 4; 2784 $state = STATE_DOCBLOCK;
2692 $contents = ""; 2785 $contents = "";
2786 $new_start_line = $. + 1;
2787
2693 if ( $1 eq "" ) { 2788 if ( $1 eq "" ) {
2694 $section = $section_intro; 2789 $section = $section_intro;
2695 } else { 2790 } else {
@@ -2702,7 +2797,12 @@ sub process_file($) {
2702 $identifier = $1; 2797 $identifier = $1;
2703 } 2798 }
2704 2799
2705 $state = 2; 2800 $state = STATE_FIELD;
2801 # if there's no @param blocks need to set up default section
2802 # here
2803 $contents = "";
2804 $section = $section_default;
2805 $new_start_line = $. + 1;
2706 if (/-(.*)/) { 2806 if (/-(.*)/) {
2707 # strip leading/trailing/multiple spaces 2807 # strip leading/trailing/multiple spaces
2708 $descr= $1; 2808 $descr= $1;
@@ -2740,13 +2840,25 @@ sub process_file($) {
2740 print STDERR "${file}:$.: warning: Cannot understand $_ on line $.", 2840 print STDERR "${file}:$.: warning: Cannot understand $_ on line $.",
2741 " - I thought it was a doc line\n"; 2841 " - I thought it was a doc line\n";
2742 ++$warnings; 2842 ++$warnings;
2743 $state = 0; 2843 $state = STATE_NORMAL;
2744 } 2844 }
2745 } elsif ($state == 2) { # look for head: lines, and include content 2845 } elsif ($state == STATE_FIELD) { # look for head: lines, and include content
2746 if (/$doc_sect/o) { 2846 if (/$doc_sect/i) { # case insensitive for supported section names
2747 $newsection = $1; 2847 $newsection = $1;
2748 $newcontents = $2; 2848 $newcontents = $2;
2749 2849
2850 # map the supported section names to the canonical names
2851 if ($newsection =~ m/^description$/i) {
2852 $newsection = $section_default;
2853 } elsif ($newsection =~ m/^context$/i) {
2854 $newsection = $section_context;
2855 } elsif ($newsection =~ m/^returns?$/i) {
2856 $newsection = $section_return;
2857 } elsif ($newsection =~ m/^\@return$/) {
2858 # special: @return is a section, not a param description
2859 $newsection = $section_return;
2860 }
2861
2750 if (($contents ne "") && ($contents ne "\n")) { 2862 if (($contents ne "") && ($contents ne "\n")) {
2751 if (!$in_doc_sect && $verbose) { 2863 if (!$in_doc_sect && $verbose) {
2752 print STDERR "${file}:$.: warning: contents before sections\n"; 2864 print STDERR "${file}:$.: warning: contents before sections\n";
@@ -2759,14 +2871,16 @@ sub process_file($) {
2759 $in_doc_sect = 1; 2871 $in_doc_sect = 1;
2760 $in_purpose = 0; 2872 $in_purpose = 0;
2761 $contents = $newcontents; 2873 $contents = $newcontents;
2874 $new_start_line = $.;
2875 while ((substr($contents, 0, 1) eq " ") ||
2876 substr($contents, 0, 1) eq "\t") {
2877 $contents = substr($contents, 1);
2878 }
2762 if ($contents ne "") { 2879 if ($contents ne "") {
2763 while ((substr($contents, 0, 1) eq " ") ||
2764 substr($contents, 0, 1) eq "\t") {
2765 $contents = substr($contents, 1);
2766 }
2767 $contents .= "\n"; 2880 $contents .= "\n";
2768 } 2881 }
2769 $section = $newsection; 2882 $section = $newsection;
2883 $leading_space = undef;
2770 } elsif (/$doc_end/) { 2884 } elsif (/$doc_end/) {
2771 if (($contents ne "") && ($contents ne "\n")) { 2885 if (($contents ne "") && ($contents ne "\n")) {
2772 dump_section($file, $section, xml_escape($contents)); 2886 dump_section($file, $section, xml_escape($contents));
@@ -2780,7 +2894,7 @@ sub process_file($) {
2780 } 2894 }
2781 2895
2782 $prototype = ""; 2896 $prototype = "";
2783 $state = 3; 2897 $state = STATE_PROTO;
2784 $brcount = 0; 2898 $brcount = 0;
2785# print STDERR "end of doc comment, looking for prototype\n"; 2899# print STDERR "end of doc comment, looking for prototype\n";
2786 } elsif (/$doc_content/) { 2900 } elsif (/$doc_content/) {
@@ -2791,6 +2905,7 @@ sub process_file($) {
2791 dump_section($file, $section, xml_escape($contents)); 2905 dump_section($file, $section, xml_escape($contents));
2792 $section = $section_default; 2906 $section = $section_default;
2793 $contents = ""; 2907 $contents = "";
2908 $new_start_line = $.;
2794 } else { 2909 } else {
2795 $contents .= "\n"; 2910 $contents .= "\n";
2796 } 2911 }
@@ -2801,87 +2916,86 @@ sub process_file($) {
2801 $declaration_purpose .= " " . xml_escape($1); 2916 $declaration_purpose .= " " . xml_escape($1);
2802 $declaration_purpose =~ s/\s+/ /g; 2917 $declaration_purpose =~ s/\s+/ /g;
2803 } else { 2918 } else {
2804 $contents .= $1 . "\n"; 2919 my $cont = $1;
2920 if ($section =~ m/^@/ || $section eq $section_context) {
2921 if (!defined $leading_space) {
2922 if ($cont =~ m/^(\s+)/) {
2923 $leading_space = $1;
2924 } else {
2925 $leading_space = "";
2926 }
2927 }
2928
2929 $cont =~ s/^$leading_space//;
2930 }
2931 $contents .= $cont . "\n";
2805 } 2932 }
2806 } else { 2933 } else {
2807 # i dont know - bad line? ignore. 2934 # i dont know - bad line? ignore.
2808 print STDERR "${file}:$.: warning: bad line: $_"; 2935 print STDERR "${file}:$.: warning: bad line: $_";
2809 ++$warnings; 2936 ++$warnings;
2810 } 2937 }
2811 } elsif ($state == 5) { # scanning for split parameters 2938 } elsif ($state == STATE_INLINE) { # scanning for inline parameters
2812 # First line (state 1) needs to be a @parameter 2939 # First line (state 1) needs to be a @parameter
2813 if ($split_doc_state == 1 && /$doc_split_sect/o) { 2940 if ($inline_doc_state == STATE_INLINE_NAME && /$doc_inline_sect/o) {
2814 $section = $1; 2941 $section = $1;
2815 $contents = $2; 2942 $contents = $2;
2943 $new_start_line = $.;
2816 if ($contents ne "") { 2944 if ($contents ne "") {
2817 while ((substr($contents, 0, 1) eq " ") || 2945 while ((substr($contents, 0, 1) eq " ") ||
2818 substr($contents, 0, 1) eq "\t") { 2946 substr($contents, 0, 1) eq "\t") {
2819 $contents = substr($contents, 1); 2947 $contents = substr($contents, 1);
2820 } 2948 }
2821 $contents .= "\n"; 2949 $contents .= "\n";
2822 } 2950 }
2823 $split_doc_state = 2; 2951 $inline_doc_state = STATE_INLINE_TEXT;
2824 # Documentation block end */ 2952 # Documentation block end */
2825 } elsif (/$doc_split_end/) { 2953 } elsif (/$doc_inline_end/) {
2826 if (($contents ne "") && ($contents ne "\n")) { 2954 if (($contents ne "") && ($contents ne "\n")) {
2827 dump_section($file, $section, xml_escape($contents)); 2955 dump_section($file, $section, xml_escape($contents));
2828 $section = $section_default; 2956 $section = $section_default;
2829 $contents = ""; 2957 $contents = "";
2830 } 2958 }
2831 $state = 3; 2959 $state = STATE_PROTO;
2832 $split_doc_state = 0; 2960 $inline_doc_state = STATE_INLINE_NA;
2833 # Regular text 2961 # Regular text
2834 } elsif (/$doc_content/) { 2962 } elsif (/$doc_content/) {
2835 if ($split_doc_state == 2) { 2963 if ($inline_doc_state == STATE_INLINE_TEXT) {
2836 $contents .= $1 . "\n"; 2964 $contents .= $1 . "\n";
2837 } elsif ($split_doc_state == 1) { 2965 # nuke leading blank lines
2838 $split_doc_state = 4; 2966 if ($contents =~ /^\s*$/) {
2967 $contents = "";
2968 }
2969 } elsif ($inline_doc_state == STATE_INLINE_NAME) {
2970 $inline_doc_state = STATE_INLINE_ERROR;
2839 print STDERR "Warning(${file}:$.): "; 2971 print STDERR "Warning(${file}:$.): ";
2840 print STDERR "Incorrect use of kernel-doc format: $_"; 2972 print STDERR "Incorrect use of kernel-doc format: $_";
2841 ++$warnings; 2973 ++$warnings;
2842 } 2974 }
2843 } 2975 }
2844 } elsif ($state == 3) { # scanning for function '{' (end of prototype) 2976 } elsif ($state == STATE_PROTO) { # scanning for function '{' (end of prototype)
2845 if (/$doc_split_start/) { 2977 if (/$doc_inline_start/) {
2846 $state = 5; 2978 $state = STATE_INLINE;
2847 $split_doc_state = 1; 2979 $inline_doc_state = STATE_INLINE_NAME;
2848 } elsif ($decl_type eq 'function') { 2980 } elsif ($decl_type eq 'function') {
2849 process_state3_function($_, $file); 2981 process_proto_function($_, $file);
2850 } else { 2982 } else {
2851 process_state3_type($_, $file); 2983 process_proto_type($_, $file);
2852 } 2984 }
2853 } elsif ($state == 4) { 2985 } elsif ($state == STATE_DOCBLOCK) {
2854 # Documentation block 2986 if (/$doc_end/)
2855 if (/$doc_block/) {
2856 dump_doc_section($file, $section, xml_escape($contents));
2857 $contents = "";
2858 $function = "";
2859 %constants = ();
2860 %parameterdescs = ();
2861 %parametertypes = ();
2862 @parameterlist = ();
2863 %sections = ();
2864 @sectionlist = ();
2865 $prototype = "";
2866 if ( $1 eq "" ) {
2867 $section = $section_intro;
2868 } else {
2869 $section = $1;
2870 }
2871 }
2872 elsif (/$doc_end/)
2873 { 2987 {
2874 dump_doc_section($file, $section, xml_escape($contents)); 2988 dump_doc_section($file, $section, xml_escape($contents));
2989 $section = $section_default;
2875 $contents = ""; 2990 $contents = "";
2876 $function = ""; 2991 $function = "";
2877 %constants = ();
2878 %parameterdescs = (); 2992 %parameterdescs = ();
2879 %parametertypes = (); 2993 %parametertypes = ();
2880 @parameterlist = (); 2994 @parameterlist = ();
2881 %sections = (); 2995 %sections = ();
2882 @sectionlist = (); 2996 @sectionlist = ();
2883 $prototype = ""; 2997 $prototype = "";
2884 $state = 0; 2998 $state = STATE_NORMAL;
2885 } 2999 }
2886 elsif (/$doc_content/) 3000 elsif (/$doc_content/)
2887 { 3001 {
@@ -2898,7 +3012,7 @@ sub process_file($) {
2898 } 3012 }
2899 if ($initial_section_counter == $section_counter) { 3013 if ($initial_section_counter == $section_counter) {
2900 print STDERR "${file}:1: warning: no structured comments found\n"; 3014 print STDERR "${file}:1: warning: no structured comments found\n";
2901 if (($function_only == 1) && ($show_not_found == 1)) { 3015 if (($output_selection == OUTPUT_INCLUDE) && ($show_not_found == 1)) {
2902 print STDERR " Was looking for '$_'.\n" for keys %function_table; 3016 print STDERR " Was looking for '$_'.\n" for keys %function_table;
2903 } 3017 }
2904 if ($output_mode eq "xml") { 3018 if ($output_mode eq "xml") {