From: "Heiser, Markus" <markus.hei...@darmarit.de>

Implements the reST directive specified at
books/kernel-doc-HOWTO/kernel-doc-directive.rst [1]

Below is a short overview of the options (further reading [1]):

    .. kernel-doc:: <filename>
        :doc: <section title>
        :export:
        :internal:
        :functions: <function [, functions [, ...]]>
        :module: <prefix-id>
        :snippets:  <snippet [, snippets [, ...]]>
        :language:  <snippet-lang>
        :linenos:
        :debug:

The initial implementation was taken from the sphkerneldoc project [2]

[1] 
http://return42.github.io/sphkerneldoc/books/kernel-doc-HOWTO/kernel-doc-directive.html
[2] http://return42.github.io/sphkerneldoc

Signed-off-by: Markus Heiser <markus.hei...@darmarit.de>
---
 scripts/site-python/linuxdoc/rstKernelDoc.py | 369 +++++++++++++++++++++++++++
 1 file changed, 369 insertions(+)
 create mode 100755 scripts/site-python/linuxdoc/rstKernelDoc.py

diff --git a/scripts/site-python/linuxdoc/rstKernelDoc.py 
b/scripts/site-python/linuxdoc/rstKernelDoc.py
new file mode 100755
index 0000000..8246a57
--- /dev/null
+++ b/scripts/site-python/linuxdoc/rstKernelDoc.py
@@ -0,0 +1,369 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8; mode: python -*-
+# pylint: disable=C0330, R0903
+
+u"""
+    rstKernelDoc
+    ~~~~~~~~~~~~
+
+    Implementation of the ``kernel-doc`` reST-directive.
+
+    :copyright:  Copyright (C) 2016  Markus Heiser
+    :license:    GPL V3.0, see LICENSE for details.
+
+    The ``kernel-doc`` (:py:class:`KernelDoc`) directive includes contens from
+    linux kernel source code comments.
+
+    Options:
+
+    * ``:doc: <section title>`` inserts the contents of the ``DOC:`` section
+      titled ``<section title>`` from ``<filename>``.  Spaces are allowed in
+      ``<section title>``; do not quote the ``<section title>``.
+
+    * ``:export:`` inserts the documentation in ``<filename>`` of functions /
+      structs or whatever are exported using EXPORT_SYMBOL 
(``EXPORT_SYMBOL()``,
+      ``EXPORT_SYMBOL_GPL()`` & ``EXPORT_SYMBOL_GPL_FUTURE()``).
+
+    * ``:internal:`` is replaced by the documentation of functions, structs,
+      titles etc. that are documented, but not **not** exported using
+      EXPORT_SYMBOL.
+
+    * ``:functions: <function [, functions [, ...]]>`` is replaced by the
+      documentation of function, struct or whatever object/title is documented
+      <filename>.
+
+    * The option ``:module: <prefix-id>`` sets a module-name, this name is used
+      as prefix for automatic generated IDs (reference anchors).
+
+    The following example shows how to insert documention from the source file
+    ``/drivers/gpu/drm/drm_drv.c``. In this example the documention from the
+    ``DOC:`` section with the title "driver instance overview" and the
+    documentation of all exported symbols (EXPORT_SYMBOL) is included in the
+    reST tree.
+
+    .. code-block:: rst
+
+        .. kernel-doc::  drivers/gpu/drm/drm_drv.c
+            :export:
+            :doc:        driver instance overview
+
+    An other example is to use only one function description.
+
+        .. kernel-doc::  include/media/i2c/tvp7002.h
+            :functions:  tvp7002_config
+            :module:     tvp7002
+
+    This will produce the follwing reST markup to include:
+
+    .. code-block:: rst
+
+        .. _`tvp514x.tvp514x_platform_data`:
+
+        struct tvp514x_platform_data
+        ============================
+
+        .. c:type:: tvp514x_platform_data
+
+
+        .. _`tvp514x.tvp514x_platform_data.definition`:
+
+        Definition
+        ----------
+
+        .. code-block:: c
+
+            struct tvp514x_platform_data {
+                bool clk_polarity;
+                bool hs_polarity;
+                bool vs_polarity;
+            }
+
+        .. _`tvp514x.tvp514x_platform_data.members`:
+
+        Members
+        -------
+
+        clk_polarity
+            Clock polarity of the current interface.
+
+        hs_polarity
+            HSYNC Polarity configuration for current interface.
+
+        vs_polarity
+            VSYNC Polarity configuration for current interface.
+
+    The last example illustrates, that the option ``:module: tvp514x`` is used
+    as a prefix for anchors. E.g. 
```ref:`tvp514x.tvp514x_platform_data.members¸```
+    refers to the to the member description of ``struct 
tvp514x_platform_data``.
+
+
+"""
+
+# 
==============================================================================
+# common globals
+# 
==============================================================================
+
+# The version numbering follows numbering of the specification
+# (Documentation/books/kernel-doc-HOWTO).
+__version__  = '1.0'
+
+# 
==============================================================================
+# imports
+# 
==============================================================================
+
+from os import path
+from io import StringIO
+from docutils import nodes
+from docutils.parsers.rst import Directive, directives
+from docutils.utils import SystemMessage
+from docutils.statemachine import ViewList
+from sphinx.util.nodes import nested_parse_with_titles
+
+import kernel_doc as kerneldoc
+
+# 
==============================================================================
+def setup(app):
+# 
==============================================================================
+
+    app.add_config_value('kernel_doc_raise_error', False, 'env')
+    app.add_directive("kernel-doc", KernelDoc)
+
+# 
==============================================================================
+class KernelDocParser(kerneldoc.Parser):
+# 
==============================================================================
+
+    def __init__(self, app, *args, **kwargs):
+        super(KernelDocParser, self).__init__(*args, **kwargs)
+        self.app = app
+
+    # -------------------------------------------------
+    # bind the parser logging to the sphinx application
+    # -------------------------------------------------
+
+    def error(self, message, **replace):
+        self.errors += 1
+        self.app.warn(
+            message % replace
+            , location = "%s:%s [kernel-doc ERROR]" % (self.options.fname, 
self.ctx.line_no)
+            , prefix = "" )
+
+    def warn(self, message, **replace):
+        self.app.warn(
+            message % replace
+            , location = "%s:%s [kernel-doc WARN]" % (self.options.fname, 
self.ctx.line_no)
+            , prefix = "")
+
+    def info(self, message, **replace):
+        self.app.verbose(
+            "%s:%s: [kernel-doc INFO]: " %(self.options.fname, 
self.ctx.line_no)
+            + message % replace)
+
+    def debug(self, message, **replace):
+        if self.app.verbosity < 2:
+            return
+        replace.update(dict(fname=self.options.fname, 
line_no=self.ctx.line_no, logclass = "DEBUG"))
+        message = "%(fname)s:%(line_no)s [kernel-doc %(logclass)s] : " + 
message
+        self.app.debug(message, **replace)
+
+
+# 
==============================================================================
+class KernelDoc(Directive):
+# 
==============================================================================
+
+    u"""KernelDoc (``kernel-doc``) directive"""
+
+    required_arguments = 1
+    optional_arguments = 0
+    final_argument_whitespace = True
+
+    option_spec = {
+        "doc"          : directives.unchanged_required # aka lines containing 
!P
+        , "export"     : directives.flag               # aka lines containing 
!E
+        , "internal"   : directives.flag               # aka lines containing 
!I
+        , "functions"  : directives.unchanged_required # aka lines containing 
!F
+
+        , "debug"      : directives.flag               # insert generated reST 
as code-block
+
+        , "snippets"   : directives.unchanged_required
+        , "language"   : directives.unchanged_required
+        , "linenos"    : directives.flag
+
+        # not yet supported:
+        #
+        # !C<filename> is replaced by nothing, but makes the tools check that
+        # all DOC: sections and documented functions, symbols, etc. are used.
+        # This makes sense to use when you use !F/!P only and want to verify
+        # that all documentation is included.
+        #
+        #, "check"     : directives.flag      # aka lines containing !C
+
+        # module name / used as id-prefix
+        , "module"     : directives.unchanged_required
+
+        # The encoding of the source file with the kernel-doc comments. The
+        # default is the config.source_encoding from sphinx configuration and
+        # this default is utf-8-sig
+        , "encoding"   : directives.encoding
+
+    }
+
+
+    def getOopsEntry(self, msg):
+        retVal = ("\n\n.. todo::"
+                  "\n\n    Oops: Document generation inconsistency."
+                  "\n\n    The template for this document tried to insert"
+                  " structured comment at this point, but an error occoured."
+                  " This dummy section is inserted to allow generation to 
continue.::"
+                  "\n\n")
+
+        for l in msg.split("\n"):
+            retVal +=  "        " + l + "\n"
+        retVal += "\n\n"
+        return retVal
+
+    def errMsg(self, msg, lev=4):
+        err = self.state_machine.reporter.severe(
+            msg
+            , nodes.literal_block(self.block_text, self.block_text)
+            , line=self.lineno )
+        return SystemMessage(err, lev)
+
+    def run(self):
+        doc = self.state.document
+        env = doc.settings.env
+
+        retVal = []
+        try:
+            retVal = self._run(doc, env)
+        except SystemMessage, exc:
+            if env.config.kernel_doc_raise_error:
+                raise
+            self.state_machine.insert_input(
+                self.getOopsEntry(unicode(exc)).split("\n")
+                , self.arguments[0])
+
+        finally:
+            pass
+        return retVal
+
+    def _run(self, document, env):
+
+        # do some checks
+
+        if not document.settings.file_insertion_enabled:
+            raise self.errMsg('File insertion disabled')
+
+        fname    = self.arguments[0]
+        src_tree = kerneldoc.SRCTREE
+
+        if self.arguments[0].startswith("./"):
+            # the prefix "./" indicates a relative pathname
+            fname = self.arguments[0][2:]
+            src_tree = path.dirname(path.normpath(document.current_source))
+
+        if "internal" in self.options:
+            if "export" in self.options:
+                raise self.errMsg(
+                    "Options 'export' and 'internal' are orthogonal,"
+                    " can't use them togehter")
+
+        if "snippets" in self.options:
+            rest = set(self.options.keys()) - set(["snippets", "linenos", 
"language", "debug"])
+            if rest:
+                raise self.errMsg(
+                    "kernel-doc 'snippets' has non of these options: %s"
+                    % ",".join(rest))
+
+        # set parse adjustments
+
+        env.note_dependency(fname)
+        rstout = StringIO()
+        ctx  = kerneldoc.ParserContext()
+        opts = kerneldoc.ParseOptions(
+            fname           = fname
+            , src_tree      = src_tree
+            , id_prefix     = self.options.get("module", "").strip()
+            , out           = rstout
+            , encoding      = self.options.get("encoding", 
env.config.source_encoding)
+            , translator    = kerneldoc.ReSTTranslator()
+            ,)
+
+        opts.set_defaults()
+        if not path.exists(opts.fname):
+            raise self.errMsg(
+                "kernel-doc refers to nonexisting document %s" % fname)
+
+        if self.options:
+            opts.skip_preamble = True
+            opts.skip_epilog   = True
+
+        if "snippets" in self.options:
+            opts.translator = kerneldoc.ReSTTranslator()
+
+        if "doc" in self.options:
+            opts.use_names.append(self.options.get("doc"))
+
+        if "export" in self.options:
+            # gather exported symbols and add them to the list of names
+            kerneldoc.Parser.gather_context(kerneldoc.readFile(opts.fname), 
ctx)
+            opts.use_names.extend(ctx.exported_symbols)
+            opts.error_missing = False
+
+        if "internal" in self.options:
+            # gather exported symbols and add them to the ignore-list of names
+            kerneldoc.Parser.gather_context(kerneldoc.readFile(opts.fname), 
ctx)
+            opts.skip_names.extend(ctx.exported_symbols)
+
+        if "functions" in self.options:
+            opts.error_missing = True
+            opts.use_names.extend(
+                self.options["functions"].replace(","," ").split())
+
+        parser = KernelDocParser(env.app, opts)
+        env.app.info("parse kernel-doc comments from: %s" % fname)
+        parser.parse()
+
+        lines = rstout.getvalue().split("\n")
+
+        if "functions" in self.options:
+            selected  = self.options["functions"].replace(","," ").split()
+            names     = parser.ctx.translated_names
+            not_found = [ s for s in selected if s not in names]
+            if not_found:
+                raise self.errMsg(
+                    "selected section(s) not found: %s" % ", ".join(not_found))
+
+        if "snippets" in self.options:
+            selected  = self.options["snippets"].replace(","," ").split()
+            names     = parser.ctx.snippets.keys()
+            not_found = [ s for s in selected if s not in names]
+            if not_found:
+                raise self.errMsg(
+                    "selected snippets(s) not found: %s" % ", 
".join(not_found))
+
+            lines = ["", ".. code-block:: %s"
+                     % self.options.get("language", "c"), ]
+            if "linenos" in self.options:
+                lines.append("    :linenos:")
+            lines.append("")
+
+            while selected:
+                snippet = parser.ctx.snippets[selected.pop(0)].split("\n")
+                lines.extend(["    " + l for l in snippet])
+                if selected:
+                    # delemit snippets with two newlines
+                    lines.extend(["",""])
+
+        if "debug" in self.options:
+            code_block = "\n.. code-block:: rst\n    :linenos:\n\n".split("\n")
+            for l in lines:
+                code_block.append("    " + l)
+            lines = code_block
+
+        content = ViewList(lines)
+        node = nodes.section()
+        node.document = self.state.document
+        nested_parse_with_titles(self.state, content, node)
+
+        return node.children
+
-- 
v4.7-rc-2

--
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