├── docs ├── .gitignore ├── linuxdoc-howto │ ├── hello.dot │ ├── test_internals.h │ ├── kernel-doc-modes.rst │ ├── csv_table.txt │ ├── kernel-doc-examples.rst │ ├── svg_image.svg │ ├── all-in-a-tumble-src.rst │ ├── test_internals.c │ ├── all-in-a-tumble.rst │ ├── all-in-a-tumble-debug.rst │ ├── kernel-include-directive.rst │ ├── cdomain.rst │ ├── index.rst │ ├── all-in-a-tumble.c │ ├── refs.txt │ ├── man-pages.rst │ ├── reST-kernel-doc-mode.rst │ ├── vintage-kernel-doc-mode.rst │ ├── kernel-doc-syntax.rst │ ├── kfigure.rst │ ├── kernel-doc-tests.rst │ ├── table-markup.rst │ └── kernel-doc-directive.rst ├── darmarIT_logo_128.png ├── cmd-line │ ├── linuxdoc.lintdoc.rst │ ├── linuxdoc.rest.rst │ └── linuxdoc.autodoc.rst ├── cmd-line.rst ├── refs.txt ├── _static │ └── linuxdoc.css ├── install.rst ├── index.rst ├── conf.py ├── downloads │ └── patch_linux.patch └── kernel-doc-intro.rst ├── linuxdoc ├── __init__.py ├── deprecated.py ├── __pkginfo__.py ├── cdomain.py ├── cdomainv3.py ├── compat.py ├── grepdoc.py ├── lint.py ├── cdomainv2.py ├── rest.py ├── autodoc.py ├── kernel_include.py ├── rstFlatTable.py └── manKernelDoc.py ├── .gitattributes ├── pyrightconfig.json ├── scripts ├── Makefile ├── lib_sh.sh ├── lib_msg.sh ├── lib_tui.sh ├── lib_doc-sphinx.sh └── main.sh ├── prj ├── tests └── __init__.py ├── .editorconfig ├── kernel-docgrep ├── CHANGELOG ├── README.rst ├── .gitignore └── pyproject.toml /docs/.gitignore: -------------------------------------------------------------------------------- 1 | linuxdoc-api/ 2 | -------------------------------------------------------------------------------- /linuxdoc/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: AGPL-3.0-or-later 2 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/hello.dot: -------------------------------------------------------------------------------- 1 | graph G { 2 | Hello -- World 3 | } 4 | -------------------------------------------------------------------------------- /docs/darmarIT_logo_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/return42/linuxdoc/HEAD/docs/darmarIT_logo_128.png -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | utils/* linguist-vendored 2 | Makefile linguist-vendored 3 | .dir-locals.el linguist-vendored 4 | -------------------------------------------------------------------------------- /linuxdoc/deprecated.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: AGPL-3.0-or-later 2 | """ 3 | deprecated 4 | ~~~~~~~~~~ 5 | 6 | Deprecated Operations implemented for compatibility. 7 | 8 | """ 9 | -------------------------------------------------------------------------------- /pyrightconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "enableTypeIgnoreComments": true, 3 | "reportAny": false, 4 | "reportExplicitAny": false, 5 | "reportIgnoreCommentWithoutRule": false, 6 | "reportUnusedCallResult": false, 7 | } 8 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/test_internals.h: -------------------------------------------------------------------------------- 1 | /* parse-SNIP: EXP_SYMB */ 2 | EXP_SYMB(foo) 3 | 4 | int foo(int a, ...) 5 | /* parse-SNAP: */ 6 | 7 | /* parse-SNIP: API_EXP */ 8 | int bar(int a, int b); 9 | /* parse-SNAP: */ 10 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/kernel-doc-modes.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | 3 | .. _kernel-doc-modes: 4 | 5 | ============= 6 | parsing modes 7 | ============= 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | 12 | reST-kernel-doc-mode 13 | vintage-kernel-doc-mode 14 | -------------------------------------------------------------------------------- /scripts/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: AGPL-3.0-or-later 2 | 3 | include ../utils/makefile.include 4 | 5 | TOPTARGETS := all clean test build 6 | 7 | all: test 8 | test: 9 | $(Q)../prj cmd msg.build TEST "scripts/.*sh" 10 | $(Q)shellcheck -x -s bash ./*.sh 11 | 12 | .PHONY: $(TOPTARGETS) 13 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/csv_table.txt: -------------------------------------------------------------------------------- 1 | stub col row 1, column, "loremLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy 2 | eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam 3 | voluptua." 4 | stub col row 1, "At vero eos et accusam et justo duo dolores et ea rebum. Stet clita 5 | kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.", column 6 | stub col row 1, column, column 7 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/kernel-doc-examples.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | 3 | .. _kernel-doc-examples: 4 | 5 | ================ 6 | Examples & Tests 7 | ================ 8 | 9 | .. kernel-doc:: ./all-in-a-tumble.h 10 | :doc: About Examples 11 | :no-header: 12 | 13 | .. toctree:: 14 | :maxdepth: 3 15 | 16 | kernel-doc-tests 17 | all-in-a-tumble-src 18 | all-in-a-tumble-debug 19 | all-in-a-tumble 20 | -------------------------------------------------------------------------------- /linuxdoc/__pkginfo__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: AGPL-3.0-or-later 2 | # pylint: disable=invalid-name, # pylint: disable=attribute-defined-outside-init 3 | """About ``linuxdoc``""" 4 | 5 | __version__ = "20240924.dev1" 6 | __copyright__ = "2025 Markus Heiser" 7 | 8 | __url__ = "https://github.com/return42/linuxdoc" 9 | __docs__ = "https://return42.github.io/linuxdoc" 10 | __issues__ = __url__ + "/issues" 11 | __author_email__ = "markus.heiser@darmarIT.de" 12 | -------------------------------------------------------------------------------- /prj: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # -*- mode: sh; sh-shell: bash -*- 3 | # SPDX-License-Identifier: AGPL-3.0-or-later 4 | 5 | PRJ_ROOT="$(dirname "${BASH_SOURCE[0]}")" 6 | PRJ_ROOT="$(cd "${PRJ_ROOT}" && pwd -P)" 7 | 8 | DOC_SRC="./docs" 9 | 10 | # shellcheck source=../scripts/main.sh 11 | source "${PRJ_ROOT}/scripts/main.sh" 12 | 13 | sh.lib.import doc-sphinx 14 | 15 | MAIN_CMD_LIST=( 16 | "doc: doc.html doc.live doc.clean doc.gh-pages" 17 | ) 18 | 19 | main "$@" 20 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | linuxdoc unit test driver 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | :copyright: Copyright (C) 2017 Markus Heiser 8 | :license: AGPL-3.0-or-later; see LICENSE for details. 9 | """ 10 | 11 | try: 12 | import os 13 | 14 | if os.environ.get("DEBUG", None): 15 | from pytest import set_trace 16 | 17 | __builtins__["DEBUG"] = set_trace 18 | except ImportError: 19 | pass 20 | -------------------------------------------------------------------------------- /docs/cmd-line/linuxdoc.lintdoc.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../refs.txt 2 | 3 | .. _linuxdoc.lintdoc: 4 | 5 | ==================== 6 | ``linuxdoc.lintdoc`` 7 | ==================== 8 | 9 | Lint the kernel-doc comments in the source code. E.g. to lint the kernel-doc 10 | comments of a source-file.:: 11 | 12 | $ linuxdoc.lintdoc /share/linux/include/media/lirc_dev.h 13 | 14 | Alternative you could also *lint* whole parts of the source tree, e.g. the 15 | include folder:: 16 | 17 | $ linuxdoc.lintdoc /share/linux/include/ 18 | 19 | -------------------------------------------------------------------------------- /docs/cmd-line.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. include:: refs.txt 3 | 4 | .. _linuxdoc_cmdline: 5 | 6 | ================== 7 | Command line tools 8 | ================== 9 | 10 | Beside the library, the installation of the LinuxDoc :ref:`[ref] 11 | ` also installs some command-line tools described here (or use 12 | the ``--help`` option). 13 | 14 | 15 | .. toctree:: 16 | :maxdepth: 3 17 | 18 | cmd-line/linuxdoc.rest.rst 19 | cmd-line/linuxdoc.lintdoc.rst 20 | cmd-line/linuxdoc.autodoc.rst 21 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org/ 2 | 3 | root = true 4 | 5 | [*] 6 | max_line_length = 80 7 | indent_style = space 8 | indent_size = 2 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | end_of_line = lf 12 | charset = utf-8 13 | insert_final_newline = ignore 14 | 15 | [*.py] 16 | indent_style = space 17 | indent_size = 4 18 | 19 | [*.sh] 20 | indent_size = 4 21 | 22 | [*.rst] 23 | indent_style = space 24 | indent_size = 2 25 | max_line_length = 79 26 | 27 | [*.toml] 28 | indent_style = space 29 | indent_size = 2 30 | -------------------------------------------------------------------------------- /docs/cmd-line/linuxdoc.rest.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../refs.txt 2 | 3 | .. _linuxdoc.rest: 4 | 5 | ================= 6 | ``linuxdoc.rest`` 7 | ================= 8 | 9 | Parse kernel-doc comments from source code and print the reST to stdout. This 10 | command exits, to see the generated reST, normally you use the :ref:`kernel-doc 11 | directive ` in your reST documentation.:: 12 | 13 | $ linuxdoc.rest /share/linux/include/media/lirc_dev.h 14 | 15 | To see the difference between :ref:`vintage-kernel-doc-mode` and 16 | :ref:`reST-kernel-doc-mode` use the option ``--markup kernel-doc``. 17 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/svg_image.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/refs.txt: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. 3 | .. common hyperlink targets 4 | 5 | .. _`COPYING`: https://github.com/torvalds/linux/blob/master/COPYING 6 | .. _`reST`: http://www.sphinx-doc.org/en/stable/rest.html 7 | .. _`sphinx config`: http://www.sphinx-doc.org/en/stable/config.html 8 | .. _`sphinx-doc`: http://www.sphinx-doc.org/ 9 | .. _`Sphinx's C domain`: http://www.sphinx-doc.org/en/stable/domains.html#cross-referencing-c-constructs 10 | .. _sphinx-extensions: http://www.sphinx-doc.org/en/master/usage/extensions 11 | 12 | .. _doctree: http://www.sphinx-doc.org/en/master/extdev/tutorial.html?highlight=doctree#build-phases 13 | -------------------------------------------------------------------------------- /linuxdoc/cdomain.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: AGPL-3.0-or-later 2 | """\ 3 | cdomain 4 | ~~~~~~~ 5 | 6 | Replacement for the sphinx c-domain. For user documentation see 7 | :ref:`customized-c-domain`. 8 | 9 | """ 10 | 11 | from .compat import sphinx_has_c_namespace 12 | 13 | __version__ = "3.0" 14 | 15 | if sphinx_has_c_namespace(): 16 | from .cdomainv3 import CDomain 17 | else: 18 | from .cdomainv2 import CDomain 19 | 20 | 21 | def setup(app): # pylint: disable=missing-docstring 22 | 23 | app.add_domain(CDomain, override=True) 24 | return dict( 25 | version=__version__, 26 | parallel_read_safe=True, 27 | parallel_write_safe=True, 28 | ) 29 | -------------------------------------------------------------------------------- /kernel-docgrep: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8; mode: python -*- 3 | 4 | u""" hackisch script to grep all kernel-doc directives from a set of folders 5 | with rst files under. """ 6 | 7 | import sys, re 8 | from fspath import FSPath 9 | 10 | pat = re.compile(r"^\s*\.\.\s+kernel-doc::\s*([^\s]+)\s*$") 11 | out = set() 12 | for arg in sys.argv: 13 | for rstFile in FSPath(arg).reMatchFind(r".*\.rst"): 14 | if rstFile.BASENAME == "kernel-doc.rst": 15 | continue 16 | #print(rstFile) 17 | with rstFile.openTextFile() as f: 18 | for l in f: 19 | match = pat.search(l) 20 | if match: 21 | #print(match.group(1)) 22 | out.add(match.group(1)) 23 | for l in sorted(out): 24 | print(l) 25 | -------------------------------------------------------------------------------- /linuxdoc/cdomainv3.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: AGPL-3.0-or-later 2 | """ 3 | cdomainv3 (Sphinx v>=3.0) 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Replacement for the sphinx c-domain. 7 | 8 | :copyright: Copyright (C) 2020 Markus Heiser 9 | :license: AGPL-3.0-or-later; see LICENSE for details. 10 | 11 | For user documentation see :ref:`customized-c-domain`. 12 | """ 13 | 14 | from sphinx.domains.c import CDomain as Base_CDomain 15 | from sphinx.domains.c import CObject as Base_CObject 16 | 17 | # fixes https://github.com/sphinx-doc/sphinx/commit/0f49e30c51b5cc5055cda5b4b294c2dd9d1df573#r38750737 18 | 19 | 20 | class CObject(Base_CObject): # pylint: disable=abstract-method 21 | """Description of a C language object.""" 22 | 23 | 24 | class CDomain(Base_CDomain): # pylint: disable=abstract-method 25 | """C language domain.""" 26 | -------------------------------------------------------------------------------- /docs/cmd-line/linuxdoc.autodoc.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../refs.txt 2 | 3 | .. _linuxdoc.autodoc: 4 | 5 | ==================== 6 | ``linuxdoc.autodoc`` 7 | ==================== 8 | 9 | Suitable for automatic API documentation. Parses your source tree, grabs 10 | kernel-doc comments and generates analogous tree of reST files with the content 11 | from the kernel-doc comments. E.g. to parse kernel's whole source tree:: 12 | 13 | $ linuxdoc.autodoc /share/linux ./out 14 | 15 | This parses the whole folder ``/share/linux`` and outputs a analogous tree with 16 | reST files in the ``./out`` folder. Alternative you could also parse only parts 17 | of the source tree, e.g. the include folder:: 18 | 19 | $ linuxdoc.autodoc --markup kernel-doc /share/linux/include ./out 20 | 21 | The option ``--markup kernel-doc`` is a tribute to the historical fact, that 22 | most of the kernel-doc comments (in the Linux kernel) are old and not reST 23 | compliant. This circumstance is also described see :ref:`[ref] 24 | ` 25 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/all-in-a-tumble-src.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. include:: refs.txt 3 | 4 | .. _all-in-a-tumble-src: 5 | 6 | ================================== 7 | source of ``all-in-a-tumble.[ch]`` 8 | ================================== 9 | 10 | Below you find the *source code* from the example files 11 | 12 | - :ref:`all-in-a-tumble.h-src` and 13 | - :ref:`all-in-a-tumble.c-src`. 14 | 15 | Within these source files *here* you see some:: 16 | 17 | /* parse-SNIP: ... */ 18 | 19 | aka :ref:`kernel-doc-syntax-snippets`, which we will use in section: 20 | :ref:`kernel-doc-tests`. 21 | 22 | ---- 23 | 24 | .. _all-in-a-tumble.h-src: 25 | 26 | source ``all-in-a-tumble.h`` 27 | ============================ 28 | 29 | .. literalinclude:: ./all-in-a-tumble.h 30 | :language: c 31 | :linenos: 32 | :tab-width: 8 33 | 34 | ---- 35 | 36 | .. _all-in-a-tumble.c-src: 37 | 38 | source ``all-in-a-tumble.c`` 39 | ============================ 40 | 41 | .. literalinclude:: ./all-in-a-tumble.c 42 | :language: c 43 | :linenos: 44 | :tab-width: 8 45 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/test_internals.c: -------------------------------------------------------------------------------- 1 | /* parse-SNIP: EXP_SYMB */ 2 | /** 3 | * foo() - function that can only be called in user context 4 | * @a: some argument 5 | * @...: ellipsis operator 6 | * 7 | * This function makes no sense, it's only a kernel-doc demonstration. 8 | * 9 | * Example: 10 | * x = foo(42); 11 | * 12 | * Return: 13 | * Returns first argument 14 | */ 15 | int foo(int a, ...) 16 | { 17 | return a; 18 | } 19 | /* parse-SNAP: */ 20 | 21 | /* parse-SNIP: API_EXP */ 22 | /** 23 | * bar() - function that can only be called in user context 24 | * @a: some argument 25 | * @...: ellipsis operator 26 | * 27 | * This function makes no sense, it's only a kernel-doc demonstration. 28 | * 29 | * Example: 30 | * x = bar(42); 31 | * 32 | * Return: 33 | * Returns first argument 34 | */ 35 | API_EXP int bar(int a, ...) 36 | { 37 | return a; 38 | } 39 | 40 | /* parse-SNIP: internal_function */ 41 | /** 42 | * internal_function() - the answer 43 | * 44 | * Context: !sanity() 45 | * 46 | * Return: 47 | * The answer to the ultimate question of life, the universe and everything. 48 | */ 49 | int internal_function() 50 | { 51 | return 42; 52 | } 53 | /* parse-SNAP: */ 54 | -------------------------------------------------------------------------------- /docs/_static/linuxdoc.css: -------------------------------------------------------------------------------- 1 | aside.sidebar { 2 | border-color: lightsteelblue; 3 | border-radius: 3pt; 4 | } 5 | 6 | p.sidebar-title, .sidebar p { 7 | margin: 6pt; 8 | } 9 | 10 | .sidebar li, 11 | .hlist li { 12 | list-style-type: disclosure-closed; 13 | } 14 | 15 | .sphinxsidebar .current > a { 16 | font-weight: bold; 17 | } 18 | 19 | /* admonitions with (rendered) reST markup examples (:class: rst-example) 20 | * 21 | * .. admonition:: title of the example 22 | * :class: rst-example 23 | * .... 24 | */ 25 | 26 | div.rst-example { 27 | font-family: Sans Serif; 28 | font-style: italic; 29 | font-size: inherit; 30 | margin-left: 1em; 31 | border-top: none; 32 | border-bottom: none; 33 | border-left: none; 34 | border-radius: none; 35 | padding: 0; 36 | } 37 | 38 | div.rst-example > p.admonition-title { 39 | font-family: Sans Serif; 40 | font-style: italic; 41 | font-size: inherit; 42 | display: block; 43 | border-bottom: 1px solid #ccc; 44 | padding: 0.5em 1em; 45 | text-align: right; 46 | } 47 | 48 | /* Table theme 49 | */ 50 | 51 | tr>th:hover, tr>td:hover { 52 | background-color: #aa4; 53 | color: black; 54 | } 55 | 56 | 57 | div.sphinx-tabs { 58 | clear: both; 59 | } 60 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/all-in-a-tumble.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. include:: refs.txt 3 | 4 | .. _all-in-a-tumble: 5 | 6 | ================================= 7 | rendered ``all-in-a-tumble.[ch]`` 8 | ================================= 9 | 10 | Below you find the rendered reST_ markup, generated from kernel-doc comments of 11 | the example files :ref:`all-in-a-tumble.h` and :ref:`all-in-a-tumble.c`. This 12 | content will be produced by the kernel-doc parser and inserted in the document by 13 | using the following directives: 14 | 15 | .. code-block:: rst 16 | 17 | .. kernel-doc:: ./all-in-a-tumble.c 18 | :module: example 19 | 20 | .. kernel-doc:: ./all-in-a-tumble.h 21 | :module: example 22 | 23 | The option ``:module:`` is optional, to find out why we use this option *here*, 24 | see :ref:`kernel-doc-options`. 25 | 26 | ------ 27 | 28 | .. _all-in-a-tumble.h: 29 | 30 | all-in-a-tumble.h 31 | ================= 32 | 33 | .. kernel-doc:: ./all-in-a-tumble.h 34 | :module: example 35 | 36 | ------ 37 | 38 | .. _all-in-a-tumble.c: 39 | 40 | all-in-a-tumble.c 41 | ================= 42 | 43 | .. kernel-doc:: ./all-in-a-tumble.c 44 | :module: example 45 | :known-attrs: API_EXPORTED 46 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | YYYY-MM-DD [YYYYMMDD] 2 | 3 | [doc] switch sphinx theme from Pallets to Furo 4 | [doc] remove obsolete articles 5 | [doc] implement worklfow to build & deploy documentation 6 | [mod] fix issues reported by: hatch run pylint-check 7 | [mod] hatch run fix - code formatting using black & isort 8 | [mod] switch develop environment to hatch 9 | 10 | 2024-09-24 [20240924] 11 | 12 | [fix] export option to kernel-doc directive 13 | [fix] kernel_include.py: cope with docutils 0.21 14 | 15 | 2023-10-20 [20231020] 16 | 17 | [fix] build: don't include test folder in the distributed package 18 | 19 | 2023-06-29 [20230629] 20 | 21 | Python 3.12 compatibility / imp replaced by importlib 22 | 23 | 2023-05-06 [20230506] 24 | 25 | rename kernel-* commands into linuxdoc.* commands & add man pages 26 | 27 | * Deprecated: The maintenance of the ``kernel-*`` command ends in 28 | version 20230321. The ``kernel-*`` commands will be removed in a future 29 | release: use the ``linuxdoc.*`` commands. 30 | 31 | - kernel-doc --> linuxdoc.rest 32 | - kernel-autodoc --> linuxdoc.autodoc 33 | - kernel-lintdoc --> linuxdoc.lintdoc 34 | - kernel-grepdoc --> linuxdoc.grepdoc 35 | 36 | 2023-03-21 [20230321] LICENSE AGPLv3+ 37 | 38 | * Changed: GNU Affero General Public License v3 or later (AGPLv3+) 39 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/all-in-a-tumble-debug.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. include:: refs.txt 3 | 4 | .. _all-in-a-tumble-debug: 5 | 6 | ======================================== 7 | kernel-doc from ``all-in-a-tumble.[ch]`` 8 | ======================================== 9 | 10 | Below you find the reST_ markup, generated from kernel-doc comments of the 11 | example files :ref:`all-in-a-tumble.h-src` and :ref:`all-in-a-tumble.c-src`. 12 | This markup will be produced by the kernel-doc parser and inserted in the 13 | document by using the following directives: 14 | 15 | .. code-block:: rst 16 | 17 | .. kernel-doc:: ./all-in-a-tumble.c 18 | :module: foo 19 | 20 | .. kernel-doc:: ./all-in-a-tumble.h 21 | :module: foo 22 | 23 | The option ``:module:`` is optional, to find out why we use this option *here*, 24 | see :ref:`kernel-doc-options`. 25 | 26 | - :ref:`all-in-a-tumble.h-debug` 27 | - :ref:`all-in-a-tumble.c-debug` 28 | 29 | .. _all-in-a-tumble.h-debug: 30 | 31 | kernel-doc from ``all-in-a-tumble.h`` 32 | ====================================== 33 | 34 | .. kernel-doc:: ./all-in-a-tumble.h 35 | :debug: 36 | :module: foo 37 | 38 | .. _all-in-a-tumble.c-debug: 39 | 40 | kernel-doc from ``all-in-a-tumble.c`` 41 | ====================================== 42 | 43 | .. kernel-doc:: ./all-in-a-tumble.c 44 | :debug: 45 | :module: foo 46 | 47 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/kernel-include-directive.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. include:: refs.txt 3 | 4 | .. _kernel-include-directive: 5 | 6 | ==================================== 7 | Use kernel-include in reST documents 8 | ==================================== 9 | 10 | The ``kernel-include`` reST-directive is a replacement for the ``include`` 11 | directive. The ``kernel-include`` directive expand environment variables in 12 | the path name and allows to include files from arbitrary locations. 13 | 14 | .. hint:: 15 | 16 | Including files from arbitrary locations (e.g. from ``/etc``) is a 17 | security risk for builders. This is why the ``include`` directive from 18 | docutils *prohibit* pathnames pointing to locations *above* the file-system 19 | tree where the reST document with the include directive is placed. 20 | 21 | Substrings of the form ``$name`` or ``${name}`` are replaced by the value of 22 | environment variable name. Malformed variable names and references to 23 | non-existing variables are left unchanged. 24 | 25 | .. code-block:: rst 26 | 27 | .. _media_header: 28 | 29 | **************************** 30 | Media Controller Header File 31 | **************************** 32 | 33 | .. kernel-include:: $BUILDDIR/media.h.rst 34 | 35 | Since the ``kernel-include`` reST-directive is a replacement for the existing 36 | ``include`` directive, the options are the same, see `reST include directive`_. 37 | -------------------------------------------------------------------------------- /docs/install.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. include:: refs.txt 3 | 4 | .. _install_linuxdoc: 5 | 6 | ================ 7 | Install LinuxDoc 8 | ================ 9 | 10 | Install bleeding edge.:: 11 | 12 | pip install [--user] git+http://github.com/return42/linuxdoc.git 13 | 14 | As the LinuxDoc lib evolving constantly, an update should be carried out 15 | regularly.:: 16 | 17 | pip install --upgrade git+http://github.com/return42/linuxdoc.git 18 | 19 | If you are a developer and like to contribute to the LinuxDoc lib, fork on 20 | github or clone and make a developer install:: 21 | 22 | git clone https://github.com/return42/linuxdoc 23 | cd linuxdoc 24 | make install 25 | 26 | Below you see how to integrate the LinuxDoc sphinx extensions into your sphinx 27 | build process. In the ``conf.py`` (`sphinx config`_) add the LinuxDoc 28 | extensions: 29 | 30 | .. code-block:: python 31 | 32 | extensions = [ 33 | "linuxdoc.rstFlatTable", # Implementation of the "flat-table" reST-directive. 34 | "linuxdoc.rstKernelDoc", # Implementation of the "kernel-doc" reST-directive. 35 | "linuxdoc.kernel_include", # Implementation of the "kernel-include" reST-directive. 36 | "linuxdoc.manKernelDoc", # Implementation of the "kernel-doc-man" builder 37 | "linuxdoc.cdomain", # Replacement for the sphinx c-domain. 38 | "linuxdoc.kfigure", # Sphinx extension which implements scalable image handling. 39 | ] 40 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ======== 2 | LinuxDoc 3 | ======== 4 | 5 | The LinuxDoc library contains Sphinx-doc extensions and command line tools to 6 | extract documentation from C/C++ source file comments. Even if this project 7 | started in context of the Linux-Kernel documentation, you can use these 8 | extensions in common Sphinx-doc projects. 9 | 10 | 11 | Install 12 | ======= 13 | 14 | `Install LinuxDoc `__ using `pip 15 | `__:: 16 | 17 | pip install --user -U linuxdoc 18 | 19 | 20 | Development 21 | =========== 22 | 23 | This project is managed by `hatch `_, for development 24 | tasks you should install ``hatch``:: 25 | 26 | $ pipx install hatch 27 | 28 | Format and *lint* your code before commit:: 29 | 30 | $ hatch run fix 31 | $ hatch run check 32 | 33 | To enter the development environment use ``shell``:: 34 | 35 | $ hatch shell 36 | 37 | For project tasks & maintenance use:: 38 | 39 | $ hatch run prj 40 | 41 | For example, to get a *live* build of documentation:: 42 | 43 | $ hatch run prj doc.live 44 | 45 | 46 | Links 47 | ===== 48 | 49 | - Documentation: https://return42.github.io/linuxdoc 50 | - Releases: https://pypi.org/project/linuxdoc/ 51 | - Code: https://github.com/return42/linuxdoc 52 | - Issue tracker: https://github.com/return42/linuxdoc/issues 53 | - License: `AGPLv3+ `__ 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | gh-pages 3 | local/ 4 | 5 | # Byte-compiled / optimized / DLL files 6 | __pycache__/ 7 | *.py[cod] 8 | *$py.class 9 | 10 | # C extensions 11 | *.so 12 | 13 | # Distribution / packaging 14 | .Python 15 | env/ 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | eggs/ 20 | .eggs/ 21 | lib/ 22 | lib64/ 23 | parts/ 24 | sdist/ 25 | var/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | 30 | # zero builds 31 | 0_build 32 | 33 | # PyInstaller 34 | # Usually these files are written by a python script from a template 35 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 36 | *.manifest 37 | *.spec 38 | 39 | # Installer logs 40 | pip-log.txt 41 | pip-delete-this-directory.txt 42 | 43 | # Unit test / coverage reports 44 | htmlcov/ 45 | .tox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *,cover 52 | .hypothesis/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | 62 | # Flask stuff: 63 | instance/ 64 | .webassets-cache 65 | 66 | # Scrapy stuff: 67 | .scrapy 68 | 69 | # Sphinx documentation 70 | docs/_build/ 71 | 72 | # PyBuilder 73 | target/ 74 | 75 | # IPython Notebook 76 | .ipynb_checkpoints 77 | 78 | # pyenv 79 | .python-version 80 | 81 | # celery beat schedule file 82 | celerybeat-schedule 83 | 84 | # dotenv 85 | .env 86 | 87 | # virtualenv 88 | venv/ 89 | ENV/ 90 | 91 | # Spyder project settings 92 | .spyderproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | -------------------------------------------------------------------------------- /linuxdoc/compat.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: AGPL-3.0-or-later 2 | # pylint: disable=C, unused-import, invalid-name, missing-docstring 3 | """\ 4 | compat 5 | ~~~~~~ 6 | 7 | Implementation of a compatibility layer for sphinx and docutils related modules. 8 | 9 | Downward compatibility is unfortunately no strength of sphinx-doc `[ref] 10 | `__ and 11 | patch levels are not really exists or if so they are not shipped within LTS 12 | distributions. Therefor a minimal *compatibility layer* is needed. Even if we 13 | do our best here, there are also a lot of incompatibilities in between sphinx 14 | and docutils whose fixing is out of the scope of this linuxdoc project `[ref] 15 | `__. 16 | 17 | To get best results (and less warnings) its inevitable to use latest sphinx-doc 18 | version. 19 | 20 | More details see Sphinx-doc’s `CHANGELOG 21 | `__ and docutils 22 | `RELEASE-NOTES `__ 23 | 24 | """ 25 | 26 | import docutils 27 | import sphinx 28 | from pkg_resources import parse_version 29 | 30 | sphinx_version = parse_version(sphinx.__version__) 31 | docutils_version = parse_version(docutils.__version__) 32 | 33 | 34 | def sphinx_has_c_namespace(): 35 | """Checks wether Sphinx version supports `.. c:namespace:: 36 | `__ 37 | 38 | """ 39 | return sphinx_version >= parse_version("3.1") 40 | 41 | 42 | def sphinx_has_c_types(): 43 | """Checks wether Sphinx version supports `.. c:struct::, c:union and other C types 44 | `__ 45 | 46 | """ 47 | return sphinx_version >= parse_version("3.1") 48 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/cdomain.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. include:: refs.txt 3 | 4 | .. _customized-c-domain: 5 | 6 | ========================== 7 | Customized sphinx c-domain 8 | ========================== 9 | 10 | .. sidebar:: WIP :py:mod:`linuxdoc.cdomain` 11 | 12 | Sphinx v3.0 and above includes a `C, initial rewrite`_ which is not downward 13 | compatible and the Sphinx C-Domain is still *WIP* (`Sphinx-doc PR-8313`_). 14 | Therefore not all the features of :ref:`customized-c-domain` has been 15 | migrated right now (some are obsolete since V3.1). 16 | 17 | .. _C, initial rewrite: https://github.com/sphinx-doc/sphinx/commit/0f49e30c51b5cc5055cda5b4b294c2dd9d1df573#r38750737 18 | .. _Sphinx-doc PR-8313: https://github.com/sphinx-doc/sphinx/pull/8313 19 | 20 | LinuxDoc brings a customized `Sphinx's C Domain`_ extension. Here is a list of 21 | customizations of the :py:class:`CObject `: 22 | 23 | * Handle signatures of function-like macros well. Don't try to deduce arguments 24 | types of function-like macros. 25 | 26 | * Moved the *duplicate C object description* warnings for function declarations 27 | in the nitpicky mode. See Sphinx documentation for the config values for 28 | nitpicky_ and nitpick_ignore_. 29 | 30 | * Add option ``name`` to the ``c:function:`` directive. With option ``name`` 31 | the ref-name of a function can be modified. E.g. you can *rename* the 32 | reference name of a function with a common name like ``open`` or ``ioctl``: 33 | 34 | .. code-block:: rst 35 | 36 | .. c:function:: int ioctl( int fd, int request ) 37 | :name: VIDIOC_LOG_STATUS 38 | 39 | The func-name (e.g. ioctl) remains in the output but the ref-name changed from 40 | ``ioctl`` to ``VIDIOC_LOG_STATUS``. The index entry for this function is also 41 | changed to ``VIDIOC_LOG_STATUS`` and the function can now referenced by: 42 | 43 | .. code-block:: rst 44 | 45 | :c:func:`VIDIOC_LOG_STATUS` 46 | -------------------------------------------------------------------------------- /linuxdoc/grepdoc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # SPDX-License-Identifier: AGPL-3.0-or-later 3 | """ 4 | grep_doc 5 | ~~~~~~~~ 6 | 7 | Implementation of the ``linuxdoc.grepdoc`` command. 8 | 9 | :copyright: Copyright (C) 2018 Markus Heiser 10 | :license: AGPL-3.0-or-later; see LICENSE for details. 11 | 12 | The ``linuxdoc.grepdoc`` command *greps* ``.. kernel-doc::`` directives from reST 13 | files:: 14 | 15 | $ linuxdoc.grepdoc --help 16 | 17 | """ 18 | 19 | import argparse 20 | import re 21 | import sys 22 | 23 | from fspath import FSPath 24 | 25 | CMD = None 26 | 27 | PRINT = lambda msg: sys.__stdout__.write("%s\n" % msg) 28 | ERR = lambda msg: sys.__stderr__.write("ERROR: %s\n" % msg) 29 | 30 | KERNEL_DOC_RE = re.compile(r"^\s*..\s+kernel-doc::\s+([a-zA-Z0-9_\-\.\/]+)") 31 | 32 | DESCRIPTION = """The linuxdoc.grepdoc command searches '*.rst' files and filters 33 | all 34 | 35 | .. kernel-doc:: 36 | 37 | directives. The names of the used in these kernel-doc directives 38 | are printed out line by line.""" 39 | 40 | 41 | def main(): 42 | 43 | global CMD # pylint: disable=global-statement 44 | 45 | cli = get_cli() 46 | CMD = cli.parse_args() 47 | 48 | if not CMD.srctree.EXISTS: 49 | ERR("%s does not exists." % CMD.srctree) 50 | sys.exit(42) 51 | 52 | if not CMD.srctree.ISDIR: 53 | ERR("%s is not a folder." % CMD.srctree) 54 | sys.exit(42) 55 | 56 | rst_sources = set() 57 | doc_tree = CMD.srctree 58 | for fname in doc_tree.reMatchFind(r"^.*\.rst$"): 59 | for line in fname.openTextFile(): 60 | _m = KERNEL_DOC_RE.search(line) 61 | if _m: 62 | rst_sources.add(_m.group(1)) 63 | 64 | rst_sources = list(rst_sources) 65 | rst_sources.sort() 66 | PRINT("\n".join(rst_sources)) 67 | 68 | 69 | def get_cli(): 70 | 71 | cli = argparse.ArgumentParser( 72 | description=DESCRIPTION, formatter_class=argparse.ArgumentDefaultsHelpFormatter 73 | ) 74 | cli.add_argument("srctree", help="source tree", type=lambda x: FSPath(x).ABSPATH) 75 | 76 | return cli 77 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/index.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. include:: refs.txt 3 | 4 | .. _linuxdoc-howto: 5 | 6 | ============== 7 | LinuxDoc HowTo 8 | ============== 9 | 10 | As you might already noticed, the LinuxDoc project has a focus on kernel-doc. 11 | Most of the documentation you will find here deal with this markup, its syntax, 12 | use-cases and tools. But that's not all, read on to find out more about the 13 | tools that are also available. 14 | 15 | .. admonition:: About "LinuxDoc" 16 | 17 | The LinuxDoc project was founded at the time where the linux Kernel migrates 18 | its documentation from XML-DocBook to the plain text format reST_ (OT: if 19 | interested :lwn:`692704` and :lwn:`692705`). In that context we also touched 20 | other topics. To name just two; the ":ref:`Scalable figure and image handling 21 | `" and the ":ref:`diff friendly table markup `". 22 | All these and more topics are dealing with the same parent topic: *The various 23 | aspects of documenting software developments* and are incorporated into the 24 | LinuxDoc project. 25 | 26 | ---- 27 | 28 | kernel-doc 29 | ========== 30 | 31 | .. toctree:: 32 | :maxdepth: 2 33 | 34 | kernel-doc-syntax 35 | kernel-doc-directive 36 | kernel-doc-examples 37 | kernel-doc-modes 38 | 39 | ---- 40 | 41 | other topics 42 | ============ 43 | 44 | .. toctree:: 45 | :maxdepth: 2 46 | 47 | kfigure 48 | table-markup 49 | cdomain 50 | man-pages 51 | kernel-include-directive 52 | 53 | ---- 54 | 55 | At least some handy links about reST_ and the `Sphinx markup constructs`_: 56 | 57 | * reST_ primer, `reST (quickref)`_, `reST (spec)`_ 58 | * `Sphinx markup constructs`_ 59 | * `sphinx domains`_ 60 | * `sphinx cross references`_ 61 | * `intersphinx`_, `sphinx.ext.intersphinx`_ 62 | * `sphinx-doc`_, `sphinx-doc FAQ`_ 63 | * `docutils`_, `docutils FAQ`_ 64 | * The :ref:`linux:codingstyle` and (in absence of a more detailed C style guide for 65 | documentation) the `Python's Style Guide for documentation 66 | `_ provides a 67 | good orientation. 68 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/all-in-a-tumble.c: -------------------------------------------------------------------------------- 1 | // this test some kernel-doc stuff 2 | 3 | /* parse-SNIP: hello-world */ 4 | #include 5 | int main() { 6 | printf("Hello World\n"); 7 | return 0; 8 | } 9 | /* parse-SNAP: */ 10 | 11 | /* parse-SNIP: user_function */ 12 | /** 13 | * user_function() - function that can only be called in user context 14 | * @a: some argument 15 | * @...: ellipsis operator 16 | * 17 | * This function makes no sense, it's only a kernel-doc demonstration. 18 | * 19 | * Example: 20 | * x = user_function(22); 21 | * 22 | * Return: 23 | * Returns first argument 24 | */ 25 | int 26 | user_function(int a, ...) 27 | { 28 | return a; 29 | } 30 | /* parse-SNAP: */ 31 | 32 | 33 | /* parse-SNIP: user_sum-c */ 34 | /** 35 | * user_sum() - another function that can only be called in user context 36 | * @a: first argument 37 | * @b: second argument 38 | * 39 | * This function makes no sense, it's only a kernel-doc demonstration. 40 | * 41 | * Example: 42 | * x = user_sum(1, 2); 43 | * 44 | * Return: 45 | * Returns the sum of the @a and @b 46 | */ 47 | API_EXPORTED 48 | int user_sum(int a, int b) 49 | { 50 | return a + b; 51 | } 52 | /* parse-SNAP: */ 53 | 54 | 55 | /* parse-SNIP: test_SYSCALL */ 56 | /** 57 | * sys_tgkill - send signal to one specific thread 58 | * @tgid: the thread group ID of the thread 59 | * @pid: the PID of the thread 60 | * @sig: signal to be sent 61 | * 62 | * This syscall also checks the @tgid and returns -ESRCH even if the PID 63 | * exists but it's not belonging to the target process anymore. This 64 | * method solves the problem of threads exiting and PIDs getting reused. 65 | */ 66 | SYSCALL_DEFINE3(tgkill, pid_t, tgid, pid_t, pid, int, sig) 67 | { 68 | ... 69 | } 70 | 71 | /* parse-SNAP: */ 72 | 73 | /* parse-SNIP: rarely_code_styles*/ 74 | /** 75 | * enum rarely_enum - enum to test parsing rarely code styles 76 | * @F1: f1 77 | * @F2: f2 78 | */ 79 | enum rarely_enum { 80 | F1, 81 | 82 | F2, 83 | }; 84 | 85 | 86 | /** 87 | * struct rarely_struct - struct to test parsing rarely code styles 88 | * @foofoo: lorem 89 | * @barbar: ipsum 90 | */ 91 | 92 | struct rarely_struct { 93 | struct foo 94 | 95 | foofoo; 96 | 97 | struct bar 98 | 99 | barbar; 100 | }; 101 | 102 | /* parse-SNIP: xxxx */ 103 | 104 | 105 | -------------------------------------------------------------------------------- /scripts/lib_sh.sh: -------------------------------------------------------------------------------- 1 | # -*- mode: sh; sh-shell: bash -*- 2 | # SPDX-License-Identifier: AGPL-3.0-or-later 3 | 4 | ## Definitions that make working with bash a little more comfortable 5 | 6 | ## Methods for simplified access to shell types 7 | 8 | sh.list.is-in() { 9 | 10 | # usage: sh.list.is-in "two, three" mylist || echo "value is not in list" 11 | # 12 | # In the usage example mylist is an one-dimensional indexed array like: 13 | # 14 | # mylist=("one" "one, two" "one, two, three") 15 | 16 | local -n arr=${2} 17 | 18 | for i in "${arr[@]}" 19 | do 20 | if [[ ${i} == "${1}" ]]; then 21 | return 0 22 | fi 23 | done 24 | return 1 25 | } 26 | 27 | ## Methods to terminate the execution with a detailed error message 28 | 29 | sh.prompt-err() { 30 | 31 | ## Use this as last command in your function to prompt an ERROR message if 32 | ## the exit code is not zero. 33 | 34 | local err=$1 35 | [ "$err" -ne "0" ] && msg.err "${FUNCNAME[1]} exit with error ($err)" 36 | return "$err" 37 | } 38 | 39 | sh.die() { 40 | msg.err "${BASH_SOURCE[1]}: line ${BASH_LINENO[0]}: ${2-died ${1-1}}" 41 | exit "${1-1}" 42 | } 43 | 44 | sh.die.caller() { 45 | msg.err "${BASH_SOURCE[2]}: line ${BASH_LINENO[1]}: ${FUNCNAME[1]}(): ${2-died ${1-1}}" 46 | exit "${1-1}" 47 | } 48 | 49 | sh.die.err() { 50 | msg.err "(${1-1}) ${2-died} " 51 | exit "${1-1}" 52 | } 53 | 54 | 55 | ## Management of the shell libraries 56 | 57 | SH_LIB_PATH="$(dirname "${BASH_SOURCE[0]}")" 58 | SH_LIBS_IMPORTED=() 59 | 60 | # in the bootstrap procedure the lib-msg and lib-tui is not yet imported 61 | msg.debug() { [ "${V}" -ge 3 ] && echo -e "\e[0;33mDEBUG:\e[0m $*" >&2; } 62 | msg.err() { echo -e "\e[0;31mERROR:\e[0m $*" >&2; } 63 | 64 | sh.lib.import() { 65 | 66 | local lib_path="${SH_LIB_PATH}/lib_${1}.sh" 67 | local caller="${BASH_SOURCE[1]}:${BASH_LINENO[0]}: ${FUNCNAME[0]} -" 68 | 69 | if sh.list.is-in "${lib_path}" SH_LIBS_IMPORTED; then 70 | msg.debug "[sh.lib.import] ${caller} skip already sourced ${lib_path}" 71 | return 0 72 | fi 73 | 74 | msg.debug "[sh.lib.import] ${caller} source ${lib_path}" 75 | SH_LIBS_IMPORTED+=("${lib_path}") 76 | # shellcheck source=/dev/null 77 | source "${lib_path}" || sh.die.caller 42 "[sh.lib.import] ${lib_path} not found" 78 | 79 | if [[ $(type -t "${1}.init") == function ]]; then 80 | msg.debug "[sh.lib.import] ${1}.init()" 81 | "${1}.init" 82 | else 83 | msg.debug "[sh.lib.import] lib_${1}.sh has no ${1}.init()" 84 | fi 85 | } 86 | -------------------------------------------------------------------------------- /scripts/lib_msg.sh: -------------------------------------------------------------------------------- 1 | # -*- mode: sh; sh-shell: bash -*- 2 | # SPDX-License-Identifier: AGPL-3.0-or-later 3 | 4 | # shellcheck source=./lib_tui.sh 5 | . /dev/null 6 | 7 | sh.lib.import tui 8 | 9 | if command -v fmt >/dev/null; then 10 | export FMT="fmt -u" 11 | elif command -v fold >/dev/null; then 12 | export FMT="fold -s" 13 | else 14 | export FMT="cat" 15 | fi 16 | 17 | # The msg.debug, msg.info, msg.warn and msg.err messages are printed to stder. 18 | # The msg.debug is only printed on verbose level $V >= 3 19 | 20 | msg.debug() { 21 | if [ "${V}" -ge 3 ]; then 22 | echo -e "${_BYellow}DEBUG:${_creset} $*" >&2 23 | fi 24 | } 25 | msg.info() { echo -e "${_BYellow}INFO:${_creset} $*" >&2; } 26 | msg.warn() { echo -e "${_BBlue}WARN:${_creset} $*" >&2; } 27 | msg.err() { echo -e "${_BRed}ERROR:${_creset} $*" >&2; } 28 | 29 | msg.build() { 30 | 31 | # usage: msg.build ENV "lorem ipsum .." 32 | # 33 | # Print a build messages stdout. 34 | 35 | local tag="$1 " 36 | shift 37 | echo -e "${_Blue}${tag:0:10}${_creset}$*" 38 | } 39 | 40 | msg.title() { 41 | 42 | # usage: msg.title [part|chapter|section] 43 | # 44 | # Print reST formated title to stdout. 45 | 46 | case ${2-chapter} in 47 | part) printf "\n${_BGreen}${1//?/=}${_creset}\n${_BCyan}%s${_creset}\n${_BGreen}${1//?/=}${_creset}\n" "${1}";; 48 | chapter) printf "\n${_BCyan}%s${_creset}\n${_BGreen}${1//?/=}${_creset}\n" "${1}";; 49 | section) printf "\n${_BCyan}%s${_creset}\n${_BGreen}${1//?/-}${_creset}\n" "${1}";; 50 | *) 51 | msg.err "invalid argument '${2}' in line $(caller)" 52 | return 42 53 | ;; 54 | esac 55 | } 56 | 57 | msg.para() { 58 | 59 | # usage: MSG_INDENT=1 rst_para "lorem ipsum ..." 60 | # 61 | # Print reST formated paragraph to stdout. 62 | 63 | local prefix='' 64 | if [[ -n $MSG_INDENT ]] && [[ $MSG_INDENT -gt 0 ]]; then 65 | prefix="$(for _ in $(seq 1 "$MSG_INDENT"); do printf " "; done)" 66 | echo -en "\n$*\n" | $FMT | msg.prefix "$prefix" 67 | else 68 | echo -en "\n$*\n" | $FMT 69 | fi 70 | } 71 | 72 | msg.prefix () { 73 | 74 | # usage: | msg.prefix [prefix] 75 | # 76 | # Add a prefix to each line of stdout. 77 | 78 | local prefix="${_BYellow}-->|${_creset}" 79 | 80 | if [[ -n $1 ]] ; then prefix="$1"; fi 81 | 82 | # shellcheck disable=SC2162 83 | while IFS= read line; do 84 | echo -e "${prefix}$line" 85 | done 86 | # some piped commands hide the cursor, show cursory when the stream ends 87 | echo -en "$_show_cursor" 88 | } 89 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/refs.txt: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. 3 | .. common hyperlink targets 4 | 5 | .. _`reST (spec)`: http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html 6 | .. _`reST (quickref)`: http://docutils.sourceforge.net/docs/user/rst/quickref.html 7 | .. _`reST include directive`: http://docutils.sourceforge.net/docs/ref/rst/directives.html#including-an-external-document-fragment 8 | .. _reST-directive: http://www.sphinx-doc.org/en/stable/rest.html#directives 9 | .. _reST-roles: https://docutils.sourceforge.io/docs/ref/rst/roles.html 10 | 11 | .. _`reST`: http://www.sphinx-doc.org/en/stable/rest.html 12 | .. _`Sphinx markup constructs`: http://www.sphinx-doc.org/en/stable/markup/index.html 13 | .. _`Sphinx`: http://www.sphinx-doc.org/ 14 | .. _`sphinx-doc`: http://www.sphinx-doc.org/ 15 | .. _`sphinx-doc FAQ`: http://www.sphinx-doc.org/en/stable/faq.html 16 | .. _`sphinx domains`: http://www.sphinx-doc.org/en/stable/domains.html 17 | .. _`sphinx cross references`: http://www.sphinx-doc.org/en/stable/markup/inline.html#cross-referencing-arbitrary-locations 18 | .. _`sphinx.ext.intersphinx`: http://www.sphinx-doc.org/en/stable/ext/intersphinx.html#module-sphinx.ext.intersphinx 19 | .. _`intersphinx`: http://www.sphinx-doc.org/en/stable/ext/intersphinx.html 20 | .. _`sphinx config`: http://www.sphinx-doc.org/en/stable/config.html 21 | .. _`Sphinx's autodoc`: http://www.sphinx-doc.org/en/stable/ext/autodoc.html 22 | .. _`Sphinx's Python domain`: http://www.sphinx-doc.org/en/stable/domains.html#the-python-domain 23 | .. _`Sphinx's C domain`: https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#the-c-domain 24 | .. _Cross-referencing C constructs: https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#cross-referencing-c-constructs 25 | 26 | .. _C domain namespacing: https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#namespacing 27 | .. _doctree: http://www.sphinx-doc.org/en/master/extdev/tutorial.html?highlight=doctree#build-phases 28 | 29 | .. _`docutils`: http://docutils.sourceforge.net/docs/index.html 30 | .. _`docutils FAQ`: http://docutils.sourceforge.net/FAQ.html 31 | 32 | .. _`Kernel's Source code documentation`: https://h2626237.stratoserver.net/kernel/linux_src_doc/index.html 33 | .. _`nitpick_ignore`: http://www.sphinx-doc.org/en/stable/config.html#confval-nitpick_ignore 34 | .. _`nitpicky`: http://www.sphinx-doc.org/en/stable/config.html#confval-nitpicky 35 | 36 | .. _raster-graphics: https://en.wikipedia.org/wiki/Raster_graphics 37 | .. _vector-graphics: https://en.wikipedia.org/wiki/Vector_graphics 38 | 39 | .. _SVG: https://www.w3.org/TR/SVG11/expanded-toc.html 40 | 41 | .. _DOT: https://graphviz.gitlab.io/_pages/doc/info/lang.html 42 | .. _`Graphviz's dot`: https://graphviz.gitlab.io/_pages/pdf/dotguide.pdf 43 | .. _Graphviz: https://graphviz.gitlab.io 44 | 45 | .. _ImageMagick: https://www.imagemagick.org 46 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. include:: refs.txt 3 | 4 | .. _linuxdoc: 5 | 6 | ======== 7 | LinuxDoc 8 | ======== 9 | 10 | The LinuxDoc library contains: 11 | 12 | :ref:`kernel-doc ` 13 | A "C" friendly markup, the parser, the Sphinx-doc extension and some tools. 14 | The kernel-doc markup embeds documentation within the C source files, using a 15 | few simple conventions. The parser grabs the documentation from source and 16 | generates proper reST :ref:`[ref] `. 17 | 18 | The parser is written in Python and its API is used by the corresponding 19 | Sphinx-doc extension. Command line tools shipped with: 20 | 21 | - :ref:`linuxdoc.autodoc`: Suitable for automatic API documentation 22 | 23 | - :ref:`linuxdoc.lintdoc`: *Lint* kernel-doc comments from source code. 24 | 25 | - :ref:`linuxdoc.rest`: A command line interface for kernel-doc's parser API. 26 | 27 | :ref:`kernel-doc-man ` 28 | A man page builder. An extension/replacement of the common Sphinx-doc *man* 29 | builder also integrated in the kernel-doc Sphinx-doc extension. 30 | 31 | :ref:`flat-table ` 32 | A diff and author friendly list-table replacement with *column-span*, 33 | *row-span* and *auto-span* :ref:`[ref] `. 34 | 35 | :ref:`cdomain ` 36 | A customized `Sphinx's C Domain`_ extension. Suitable for demanding projects. 37 | 38 | :ref:`kfigure` 39 | Sphinx extension which implements scalable image handling. Simplifies image 40 | handling from the author's POV. Wins where Sphinx-doc image handling 41 | fails. Whatever graphic tools available on your build host, you always get the 42 | best output-format. Graphviz's DOT format included. 43 | 44 | :ref:`kernel-include ` 45 | A replacement for the ``include`` reST directive. The directive expand 46 | environment variables in the path name and allows to include files from 47 | arbitrary locations. 48 | 49 | 50 | .. admonition:: About "LinuxDoc" 51 | 52 | Even if this project started in context of the Linux-Kernel documentation 53 | (where the name comes from), you can use these extensions in common 54 | sphinx-doc_ projects. If this is unclear to you, take a look at our 55 | :ref:`Introduction `. 56 | 57 | --------- 58 | 59 | Table of Contents 60 | ================= 61 | 62 | .. toctree:: 63 | :maxdepth: 3 64 | 65 | Introduction 66 | install 67 | linuxdoc-howto/index 68 | cmd-line 69 | 70 | LinuxDoc is hosted at github: https://github.com/return42/linuxdoc 71 | 72 | --------- 73 | 74 | Source Code 75 | =========== 76 | 77 | .. toctree:: 78 | :maxdepth: 2 79 | 80 | linuxdoc-api/linuxdoc 81 | 82 | --------- 83 | 84 | Indices and tables 85 | ================== 86 | 87 | * :ref:`genindex` 88 | * :ref:`modindex` 89 | 90 | --------- 91 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/man-pages.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. include:: refs.txt 3 | 4 | .. _man-pages: 5 | 6 | ================================== 7 | man pages from kernel-doc comments 8 | ================================== 9 | 10 | .. _ManualPageBuilder: http://www.sphinx-doc.org/en/stable/usage/builders/index.html#sphinx.builders.manpage.ManualPageBuilder 11 | 12 | .. _`conf.py man-pages`: http://www.sphinx-doc.org/en/stable/config.html#confval-man_pages 13 | 14 | .. _`Manual section number`: https://en.wikipedia.org/wiki/Man_page#Manual_sections 15 | 16 | The :py:class:`linuxdoc.manKernelDoc.KernelDocManBuilder` produces manual pages 17 | in the groff format. It is a *man* page builder for Sphinx-doc, mainly written 18 | to generate manual pages from kernel-doc comments by scanning Sphinx's master 19 | ``doc-tree`` for *sections* marked with a 20 | 21 | .. code-block:: rst 22 | 23 | .. kernel-doc-man:: . 24 | 25 | directive and build manual pages from those marked *sections*. Usage:: 26 | 27 | $ sphinx-build -b kernel-doc-man ... 28 | 29 | Since the ``kernel-doc-man`` builder is an extension of the common 30 | ManualPageBuilder_ it is also a full replacement, building booth, the common 31 | sphinx man-pages from `conf.py man-pages`_ and those marked with the 32 | ``.. kernel-doc-man::`` directive. 33 | 34 | Mostly authors will use this feature in their reST documents in conjunction with 35 | the :ref:`.. kernel-doc:: ` directive, to create man pages 36 | from kernel-doc comments. This could be done, by setting the `Manual section 37 | number`_ with the ``:man-sect:`` :ref:`kernel-doc option `. 38 | See: :ref:`kernel-doc-man-sect` 39 | 40 | .. code-block:: rst 41 | 42 | .. kernel-doc:: ./all-in-a-tumble.c 43 | :symbols: user_function 44 | :man-sect: 1 45 | 46 | With this ``:man-sect: `` option, the kernel-doc parser will insert 47 | a directive in the reST output: 48 | 49 | .. code-block:: rst 50 | 51 | .. kernel-doc-man:: . 52 | 53 | The ```` is the name of the manual page. Therefor the name of 54 | the :ref:`kernel-doc comment ` is used. Which is the name of 55 | the :ref:`struct, union `, :ref:`enum, typedef 56 | ` or :ref:`function 57 | `. 58 | 59 | .. _kernel-doc-man_builder: 60 | 61 | ``kernel-doc-man`` Builder 62 | ========================== 63 | 64 | As described above, the ``kernel-doc-man`` builder will build all the manuals 65 | which are defined in the `conf.py man-pages`_ and from all sections marked with 66 | the ``.. kernel-doc-man`` directive. To place and gzip the man-pages in 67 | ``dist/docs/man`` use:: 68 | 69 | $ sphinx-build -b kernel-doc-man docs dist/docs/man 70 | building [kernel-doc-man]: all manpages ... 71 | scan master tree for kernel-doc man-pages ... 72 | writing man pages ... user_function.2 internal_function.2 ... 73 | 74 | $ find dist/docs/man -name '*.[0-9]' -exec gzip -nf {} + 75 | 76 | To see how it works, jump to the :ref:`opt_man-sect` example. 77 | -------------------------------------------------------------------------------- /linuxdoc/lint.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: AGPL-3.0-or-later 2 | """ 3 | lint 4 | ~~~~ 5 | 6 | Implementation of the :ref:`linuxdoc.lintdoc` command. 7 | 8 | :copyright: Copyright (C) 2023 Markus Heiser 9 | :license: AGPL-3.0-or-later; see LICENSE for details. 10 | 11 | The command ``linuxdoc.lint`` *lint* the kernel-doc comments in the source 12 | code:: 13 | 14 | $ linuxdoc.lint --help 15 | 16 | """ 17 | 18 | import argparse 19 | import sys 20 | 21 | from fspath import FSPath 22 | 23 | from . import kernel_doc 24 | 25 | CMD = None 26 | 27 | MSG = lambda msg: sys.__stderr__.write("INFO : %s\n" % msg) 28 | ERR = lambda msg: sys.__stderr__.write("ERROR: %s\n" % msg) 29 | FATAL = lambda msg: sys.__stderr__.write("FATAL: %s\n" % msg) 30 | 31 | EPILOG = """This command uses the kernel-doc parser from the linuxdoc Sphinx 32 | extension, for details see: https://return42.github.io/linuxdoc/cmd-line.html""" 33 | 34 | DESCRIPTION = """Lint the kernel-doc markup comments in the source code files.""" 35 | 36 | 37 | def main(): 38 | 39 | global CMD # pylint: disable=global-statement 40 | 41 | cli = get_cli() 42 | CMD = cli.parse_args() 43 | 44 | kernel_doc.DEBUG = CMD.debug 45 | kernel_doc.VERBOSE = CMD.verbose 46 | 47 | if not CMD.srctree.EXISTS: 48 | ERR("%s does not exists or is not a folder" % CMD.srctree) 49 | sys.exit(42) 50 | 51 | if CMD.srctree.ISDIR: 52 | for fname in CMD.srctree.reMatchFind(r"^.*\.[ch]$"): 53 | lintdoc_file(fname) 54 | else: 55 | fname = CMD.srctree 56 | CMD.srctree = CMD.srctree.DIRNAME 57 | lintdoc_file(fname) 58 | 59 | 60 | def get_cli(): 61 | 62 | cli = argparse.ArgumentParser( 63 | description=(""), 64 | epilog=EPILOG, 65 | formatter_class=argparse.ArgumentDefaultsHelpFormatter, 66 | ) 67 | 68 | cli.add_argument( 69 | "srctree", 70 | help="File or folder of source code.", 71 | type=lambda x: FSPath(x).ABSPATH, 72 | ) 73 | cli.add_argument( 74 | "--sloppy", 75 | action="store_true", 76 | help="Sloppy linting, reports only severe errors.", 77 | ) 78 | cli.add_argument( 79 | "--markup", 80 | choices=["reST", "kernel-doc"], 81 | default="reST", 82 | help=( 83 | "Markup of the comments. Change this option only if you know" 84 | " what you do. New comments must be marked up with reST!" 85 | ), 86 | ) 87 | cli.add_argument( 88 | "--verbose", 89 | "-v", 90 | action="store_true", 91 | help="verbose output with log messages to stderr", 92 | ) 93 | cli.add_argument("--debug", action="store_true", help="debug messages to stderr") 94 | return cli 95 | 96 | 97 | def lintdoc_file(fname): 98 | "lint documentation from fname" 99 | 100 | fname = fname.relpath(CMD.srctree) 101 | opts = kernel_doc.ParseOptions( 102 | fname=fname, 103 | src_tree=CMD.srctree, 104 | verbose_warn=not (CMD.sloppy), 105 | markup=CMD.markup, 106 | ) 107 | parser = kernel_doc.Parser(opts, kernel_doc.NullTranslator()) 108 | try: 109 | parser.parse() 110 | except Exception: # pylint: disable=broad-except 111 | FATAL("kernel-doc comments markup of %s seems buggy / can't parse" % opts.fname) 112 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/reST-kernel-doc-mode.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. include:: refs.txt 3 | 4 | .. _reST-kernel-doc-mode: 5 | 6 | ==================== 7 | reST kernel-doc mode 8 | ==================== 9 | 10 | To distinguish between the vintage markup and the new markup (with reST in), it 11 | is recommended to add the following comment at the top of your source code 12 | file.:: 13 | 14 | /* parse-markup: reST */ 15 | 16 | This forces the kernel-doc parser to switch into the reST mode, no matter in 17 | which context the parser runs (see :ref:`vintage-kernel-doc-mode`). 18 | 19 | .. _reST-section-structure: 20 | 21 | reST section structure 22 | ====================== 23 | 24 | Since a section title in reST mode needs a line break after the colon, the colon 25 | handling is less ugly (:ref:`vintage-mode-quirks`). E.g.:: 26 | 27 | prints out: hello world 28 | 29 | is rendered as expected in one line. If non text follows the colon, a section is 30 | inserted. To avoid sectioning in any case, place a space in front of the 31 | column.:: 32 | 33 | lorem list : 34 | 35 | * lorem 36 | * ipsum 37 | 38 | On the opposite, super-short sections from :ref:`vintage-kernel-doc-mode` like:: 39 | 40 | Section name: lorem ipsum 41 | 42 | are no longer supported, you have to enter at least one line break:: 43 | 44 | Section name: 45 | lorem ipsum 46 | 47 | There is an exception for special section names like "Description:", "Context:" 48 | or "Return:", which exists mainly for backward compatibility. Nevertheless, it 49 | is recommended to add a newline after the colon. 50 | 51 | Beside these *sectioning* of the kernel-doc syntax, reST_ has it's own chapter, 52 | section etc. markup (e.g. see `Sections 53 | `_). Normally, there 54 | are no heading levels assigned to certain characters as the structure is 55 | determined from the succession of headings. However, there is a common 56 | convention, which is used by the kernel-doc parser also: 57 | 58 | * ``#`` with over-line, for parts 59 | * ``*`` with over-line, for chapters 60 | * ``=`` for sections 61 | * ``-`` for subsections 62 | * ``^`` for sub-subsections 63 | * ``"`` for paragraphs 64 | 65 | Within kernel-doc comments you should use this sectioning with care. A 66 | kernel-doc section like the ``Return:`` section above is translated into a reST_ 67 | sub-section with the following markup. 68 | 69 | .. code-block:: rst 70 | 71 | Return 72 | ------ 73 | 74 | sum of a and b 75 | 76 | As you see, a kernel-doc section is a reST_ *subsection* level. This means, you 77 | can only use the following *sub-levels* within a kernel-doc section. 78 | 79 | * ``^`` for sub-subsections 80 | * ``"`` for paragraphs 81 | 82 | In contrast to subsections like "Return:", a "DOC:" section has no subsection, 83 | thats why reST *sub-levels* in "DOC:" sections start a the subsection level, 84 | tagged with a minus: 85 | 86 | * ``-`` for subsections 87 | * ``^`` for sub-subsections 88 | * ``"`` for paragraphs 89 | 90 | Need an detailed example of kernel-doc comment using subsections and more? Take 91 | a look here ... 92 | 93 | .. kernel-doc:: ./all-in-a-tumble.h 94 | :snippets: rst_mode 95 | 96 | .. admonition:: reST markup in kernel-doc comments 97 | :class: rst-example 98 | 99 | .. kernel-doc:: ./all-in-a-tumble.h 100 | :symbols: rst_mode 101 | -------------------------------------------------------------------------------- /scripts/lib_tui.sh: -------------------------------------------------------------------------------- 1 | # -*- mode: sh; sh-shell: bash -*- 2 | # SPDX-License-Identifier: AGPL-3.0-or-later 3 | 4 | tui.init() { 5 | if [ ! -p /dev/stdout ] && [ ! "${TERM}" = 'dumb' ] && [ ! "${TERM}" = 'unknown' ]; then 6 | tui.colors 7 | fi 8 | } 9 | 10 | # shellcheck disable=SC2034 11 | tui.colors() { 12 | # https://en.wikipedia.org/wiki/ANSI_escape_code 13 | 14 | # CSI (Control Sequence Introducer) sequences 15 | _show_cursor='\e[?25h' 16 | _hide_cursor='\e[?25l' 17 | 18 | # SGR (Select Graphic Rendition) parameters 19 | _creset='\e[0m' # reset all attributes 20 | 21 | # original specification only had 8 colors 22 | _colors=8 23 | 24 | _Black='\e[0;30m' 25 | _White='\e[1;37m' 26 | _Red='\e[0;31m' 27 | _Green='\e[0;32m' 28 | _Yellow='\e[0;33m' 29 | _Blue='\e[0;94m' 30 | _Violet='\e[0;35m' 31 | _Cyan='\e[0;36m' 32 | 33 | _BBlack='\e[1;30m' 34 | _BWhite='\e[1;37m' 35 | _BRed='\e[1;31m' 36 | _BGreen='\e[1;32m' 37 | _BYellow='\e[1;33m' 38 | _BBlue='\e[1;94m' 39 | _BPurple='\e[1;35m' 40 | _BCyan='\e[1;36m' 41 | } 42 | 43 | stdin.clean() { 44 | while read -r -n1 -t 0.1; do : ; done 45 | } 46 | 47 | ui.press-key() { 48 | 49 | # usage: ui.press-key [] 50 | # 51 | # In batch processes without user interaction, the timeout is overwritten by 52 | # ${FORCE_TIMEOUT}. The default prompt message is overwritten by ${MSG}. 53 | 54 | stdin.clean 55 | local _t=$1 56 | local msg="${MSG}" 57 | [[ -z "$msg" ]] && msg="${_Green}** press any [${_BCyan}KEY${_Green}] to continue **${_creset}" 58 | 59 | [[ -n $FORCE_TIMEOUT ]] && _t=$FORCE_TIMEOUT 60 | [[ -n $_t ]] && _t="-t $_t" 61 | echo -e -n "$msg" 62 | # shellcheck disable=SC2229 63 | # shellcheck disable=SC2086 64 | read -r -s -n1 $_t || true 65 | echo 66 | stdin.clean 67 | } 68 | 69 | ui.yes-no() { 70 | 71 | # usage: ask_yn [Ny|Yn] [] 72 | # 73 | # - Ny: default is NO 74 | # - Yn: default is YES 75 | # 76 | # If the timeout is exceeded, the default is selected. In batch processes 77 | # without user interaction, the timeout can be overwritte by 78 | # ${FORCE_TIMEOUT} environment. 79 | 80 | local EXIT_YES=0 # exit status 0 --> successful 81 | local EXIT_NO=1 # exit status 1 --> error code 82 | 83 | local _t=${3} 84 | [[ -n ${FORCE_TIMEOUT} ]] && _t=${FORCE_TIMEOUT} 85 | [[ -n ${_t} ]] && _t="-t ${_t}" 86 | 87 | case "${FORCE_SELECTION:-${2}}" in 88 | Y) return ${EXIT_YES} ;; 89 | N) return ${EXIT_NO} ;; 90 | Yn) 91 | local exit_val=${EXIT_YES} 92 | local choice="[${_BGreen}YES${_creset}/no]" 93 | local default="Yes" 94 | ;; 95 | *) 96 | local exit_val=${EXIT_NO} 97 | local choice="[${_BGreen}NO${_creset}/yes]" 98 | local default="No" 99 | ;; 100 | esac 101 | echo 102 | while true; do 103 | stdin.clean 104 | printf "%s ${choice} " "${1}" 105 | # shellcheck disable=SC2086,SC2229 106 | read -r -n1 $_t 107 | if [[ -z ${REPLY} ]]; then 108 | echo "${default}"; break 109 | elif [[ ${REPLY} =~ ^[Yy]$ ]]; then 110 | exit_val=${EXIT_YES} 111 | echo 112 | break 113 | elif [[ ${REPLY} =~ ^[Nn]$ ]]; then 114 | exit_val=${EXIT_NO} 115 | echo 116 | break 117 | fi 118 | _t="" 119 | msg.err "invalid choice" 120 | done 121 | stdin.clean 122 | return $exit_val 123 | } 124 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: AGPL-3.0-or-later 2 | 3 | # ============================================================================== 4 | [build-system] 5 | # ============================================================================== 6 | 7 | requires = ["hatchling"] 8 | build-backend = "hatchling.build" 9 | 10 | # ============================================================================== 11 | [project] 12 | # ============================================================================== 13 | 14 | name = "linuxdoc" 15 | dynamic = ["version"] 16 | 17 | description = "Sphinx-doc extensions & tools to extract documentation from C/C++ source file comments." 18 | readme = "README.rst" 19 | requires-python = ">=3.9" 20 | license = "AGPL-3.0-or-later" 21 | keywords = ["sphinx extension", "doc", "source code comments", "kernel-doc", "linux"] 22 | authors = [ 23 | { name = "Markus Heiser", email = "markus.heiser@darmarit.de" }, 24 | ] 25 | classifiers = [ 26 | "Development Status :: 5 - Production/Stable", 27 | "Intended Audience :: Developers", 28 | "Intended Audience :: Other Audience", 29 | "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)", 30 | "Operating System :: OS Independent", 31 | "Programming Language :: Python :: Implementation :: CPython", 32 | "Programming Language :: Python :: Implementation :: PyPy", 33 | "Programming Language :: Python", 34 | "Topic :: Software Development :: Documentation", 35 | "Topic :: Software Development :: Libraries", 36 | "Topic :: Text Processing", 37 | "Topic :: Utilities", 38 | ] 39 | dependencies = [ 40 | "fspath", 41 | "setuptools", 42 | "docutils", 43 | "sphinx", 44 | ] 45 | 46 | [project.urls] 47 | Documentation = "https://return42.github.io/linuxdoc" 48 | Issues = "https://github.com/return42/linuxdoc/issues" 49 | Source = "https://github.com/return42/linuxdoc" 50 | 51 | [project.scripts] 52 | "linuxdoc.rest" = "linuxdoc.rest:main" 53 | "linuxdoc.autodoc" = "linuxdoc.autodoc:main" 54 | "linuxdoc.lintdoc" = "linuxdoc.lint:main" 55 | "linuxdoc.grepdoc" = "linuxdoc.grepdoc:main" 56 | 57 | 58 | # ============================================================================== 59 | [tool.hatch] 60 | # ============================================================================== 61 | 62 | [tool.hatch.version] 63 | path = "linuxdoc/__pkginfo__.py" 64 | 65 | # hatch env: default 66 | # ------------------ 67 | 68 | [tool.hatch.envs.default] 69 | python = "3.13" 70 | dependencies = [ 71 | "argparse-manpage", 72 | "basedpyright==1.27.*", 73 | "black==25.1.*", 74 | "furo", 75 | "isort==6.0.*", 76 | "pylint", 77 | "pylint==3.3.*", 78 | "sphinx-autobuild", 79 | "sphinx-issues", 80 | "sphinx-jinja", 81 | "sphinx-tabs", 82 | "sphinxcontrib-programoutput", 83 | "tox", 84 | "twine", 85 | ] 86 | 87 | [tool.hatch.envs.default.scripts] 88 | 89 | prj = "./prj {args:--help}" 90 | 91 | fix = [ 92 | "isort {args:./linuxdoc ./docs/conf.py ./tests}", 93 | "black {args:./linuxdoc ./docs/conf.py ./tests}", 94 | ] 95 | 96 | isort-check = "isort --diff {args:./linuxdoc ./tests}" 97 | black-check = "black --check --diff {args:./linuxdoc ./tests}" 98 | pylint-check = "pylint --output-format=parseable {args:./linuxdoc ./tests}" 99 | basedpyright-check = "basedpyright {args:./linuxdoc ./tests}" 100 | 101 | check = [ 102 | "isort-check", 103 | "black-check", 104 | "pylint-check", 105 | "basedpyright-check", 106 | ] 107 | 108 | # ============================================================================== 109 | [tool.isort] 110 | # ============================================================================== 111 | 112 | profile = "black" 113 | atomic = true 114 | use_parentheses = true 115 | include_trailing_comma = true 116 | -------------------------------------------------------------------------------- /docs/linuxdoc-howto/vintage-kernel-doc-mode.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8; mode: rst -*- 2 | .. include:: refs.txt 3 | 4 | .. _vintage-kernel-doc-mode: 5 | 6 | ======================= 7 | Vintage kernel-doc mode 8 | ======================= 9 | 10 | .. hint:: 11 | 12 | This section exists mainly for historical reasons. The *vintage* kernel-doc 13 | mode is only relevant for those who have to work with old kernel-doc 14 | comments (e.g. `Kernel's Source code documentation`_). 15 | 16 | Within the *vintage* kernel-doc mode the kernel-doc parser ignores any 17 | whitespace formatting/markup. Since formatting with whitespace is substantial 18 | for ASCII markups, it's recommended to use the :ref:`reST-kernel-doc-mode` on 19 | any new or changed comment! 20 | 21 | Determined by the history of the kernel-doc comments, the *vintage* kernel-doc 22 | comments contain characters like "*" or strings with e.g. leading/trailing 23 | underscore ("_"), which are in-line markups in reST. Here a short example from a 24 | *vintage* comment:: 25 | 26 | ----- 27 | * In contrast to the other drm_get_*_name functions this one here returns a 28 | * const pointer and hence is threadsafe. 29 | ----- 30 | 31 | Within reST markup (the new base format), the wildcard in the string 32 | ``drm_get_*_name`` has to be masked by the kernel-doc parser: 33 | ``drm_get_\\*_name``. Some more examples from reST markup: 34 | 35 | * Emphasis "*": like ``*emphasis*`` or ``**emphasis strong**`` 36 | * Leading "_" : is a *anchor* in reST markup (``_foo``). 37 | * Trailing "_: is a reference in reST markup (``foo_``). 38 | * interpreted text: "`" 39 | * in-line literals: "``" 40 | * substitution references: "|" 41 | 42 | As long as the kernel-doc parser runs in the *vintage* kernel-doc mode, these 43 | special strings will be masked in the reST output and can't be used as 44 | *plain-text markup*. 45 | 46 | .. hint:: 47 | 48 | The kernel source contains tens of thousands of vintage kernel-doc comments, 49 | applications which has to work with them must be able to distinguish between 50 | vintage and the new reST markup. 51 | 52 | 53 | To force the parser to switch into the reST mode add the following comment 54 | (e.g.) at the top of your source code file (or at any line where reST content 55 | starts).:: 56 | 57 | /* parse-markup: reST */ * 58 | 59 | In reST mode the kernel-doc parser pass through all text unchanged to the reST 60 | tool-chain including any whitespace and reST markup. To toggle back to 61 | :ref:`vintage-kernel-doc-mode` type the following line:: 62 | 63 | /* parse-markup: kernel-doc */ 64 | 65 | 66 | .. _vintage-mode-quirks: 67 | 68 | vintage mode quirks 69 | =================== 70 | 71 | In the following, you will find some quirks of the *vintage* kernel-doc mode. 72 | 73 | 74 | * Since a colon introduce a new section, you can't use colons. E.g. a comment 75 | line like:: 76 | 77 | prints out: hello world 78 | 79 | will result in a section with the title "prints out" and a paragraph with only 80 | "hello world" in, this is mostly not what you expect. To avoid sectioning, 81 | place a space in front of the column:: 82 | 83 | prints out : hello world 84 | 85 | * The multi-line descriptive text you provide does *not* recognize 86 | line breaks, so if you try to format some text nicely, as in:: 87 | 88 | Return: 89 | 0 - cool 90 | 1 - invalid arg 91 | 2 - out of memory 92 | 93 | this will all run together and produce:: 94 | 95 | Return: 0 - cool 1 - invalid arg 2 - out of memory 96 | 97 | * If the descriptive text you provide has lines that begin with some phrase 98 | followed by a colon, each of those phrases will be taken as a new section 99 | heading, which means you should similarly try to avoid text like:: 100 | 101 | Return: 102 | 0: cool 103 | 1: invalid arg 104 | 2: out of memory 105 | 106 | every line of which would start a new section. Again, probably not what you 107 | were after. 108 | -------------------------------------------------------------------------------- /scripts/lib_doc-sphinx.sh: -------------------------------------------------------------------------------- 1 | # -*- mode: sh; sh-shell: bash -*- 2 | # SPDX-License-Identifier: AGPL-3.0-or-later 3 | 4 | # Sphinx doc 5 | # ---------- 6 | 7 | GH_PAGES="build/gh-pages" 8 | 9 | # FIXME: what is with this path names, when we are in a LXC instance? 10 | DOC_SRC="${DOC_SRC:-./doc}" 11 | DOC_DIST="${DOC_DIST:=dist/doc}" 12 | DOC_BUILD="${DOC_BUILD:=build/doc}" 13 | 14 | [ "${V}" -ge 1 ] && SPHINX_VERBOSE="-v" 15 | 16 | doc.html.help() { 17 | cat < file://$(readlink -e "$(pwd)/${DOC_DIST}")" 31 | ( set -e 32 | doc.prebuild 33 | # shellcheck disable=SC2086 34 | sphinx-build \ 35 | ${SPHINX_VERBOSE} ${SPHINX_OPTS} \ 36 | -b html -c "${DOC_SRC}" -d "${DOC_BUILD}/.doctrees" "${DOC_SRC}" "${DOC_DIST}" 37 | ) 38 | sh.prompt-err $? 39 | } 40 | 41 | doc.live.help() { 42 | cat < file://$(readlink -e "$(pwd)/${DOC_DIST}")" 56 | ( set -e 57 | doc.prebuild 58 | # shellcheck disable=SC2086 59 | sphinx-autobuild \ 60 | ${SPHINX_VERBOSE} ${SPHINX_OPTS} \ 61 | --open-browser --host 0.0.0.0 \ 62 | -b html -c "${DOC_SRC}" -d "${DOC_BUILD}/.doctrees" "${DOC_SRC}" "${DOC_DIST}" 63 | ) 64 | sh.prompt-err $? 65 | } 66 | 67 | doc.clean.help() { 68 | $FMT < /dev/null || true 125 | git worktree add --no-checkout "${GH_PAGES}" "${remote}/master" 126 | 127 | pushd "${GH_PAGES}" &> /dev/null || return 42 128 | git checkout --orphan gh-pages 129 | git rm -rfq . 130 | popd &> /dev/null || return 42 131 | 132 | cp -r "${DOC_DIST}"/* "${GH_PAGES}"/ 133 | touch "${GH_PAGES}/.nojekyll" 134 | cat > "${GH_PAGES}/404.html" < 136 | EOF 137 | pushd "${GH_PAGES}" &> /dev/null || return 42 138 | git add --all . 139 | git commit -q -m "gh-pages build from: ${branch}@${head} (${remote_url})" 140 | git push -f "${remote}" gh-pages 141 | popd &> /dev/null || return 42 142 | 143 | [ "${V}" -ge 2 ] && set +x 144 | msg.build GH-PAGES "deployed" 145 | } 146 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Sphinx documentation build configuration file 4 | 5 | import linuxdoc.__pkginfo__ as PKG 6 | 7 | DOC_URL = "https://return42.github.io/linuxdoc" 8 | GIT_URL = "https://github.com/return42/linuxdoc" 9 | GIT_BRANCH = "master" 10 | 11 | project = "LinuxDoc" 12 | copyright = PKG.__copyright__ 13 | version = PKG.__version__ 14 | release = PKG.__version__ 15 | author = "return42" 16 | show_authors = True 17 | 18 | source_suffix = ".rst" 19 | show_authors = True 20 | master_doc = "index" 21 | templates_path = ["_templates"] 22 | exclude_patterns = ["_build", "slides"] 23 | todo_include_todos = True 24 | highlight_language = "none" 25 | 26 | # if self-signed, disable tls verify 27 | # tls_verify = False 28 | 29 | extensions = [ 30 | "sphinx.ext.imgmath", 31 | "sphinx.ext.autodoc", 32 | "sphinx.ext.extlinks", 33 | "sphinx.ext.todo", 34 | "sphinx.ext.coverage", 35 | "sphinx.ext.viewcode", 36 | "sphinx.ext.intersphinx", 37 | "sphinxcontrib.programoutput", # https://github.com/NextThought/sphinxcontrib-programoutput 38 | "sphinx_tabs.tabs", # https://github.com/djungelorm/sphinx-tabs 39 | "linuxdoc.rstFlatTable", # Implementation of the 'flat-table' reST-directive. 40 | "linuxdoc.rstKernelDoc", # Implementation of the 'kernel-doc' reST-directive. 41 | "linuxdoc.kernel_include", # Implementation of the 'kernel-include' reST-directive. 42 | "linuxdoc.manKernelDoc", # Implementation of the 'kernel-doc-man' builder 43 | "linuxdoc.cdomain", # Replacement for the sphinx c-domain (not in sphinx-doc >= v3.0) 44 | "linuxdoc.kfigure", # Sphinx extension which implements scalable image handling. 45 | ] 46 | 47 | intersphinx_mapping = {} 48 | intersphinx_mapping["linux"] = ("https://www.kernel.org/doc/html/latest/", None) 49 | 50 | extlinks = {} 51 | extlinks["origin"] = (GIT_URL + "/blob/" + GIT_BRANCH + "/%s", "git://%s") 52 | extlinks["commit"] = (GIT_URL + "/commit/%s", "#%s") 53 | 54 | # usage: :mid:`` e.g. 55 | extlinks["mid"] = ("http://mid.mail-archive.com/%s", "%s") 56 | extlinks["lwn"] = ("https://lwn.net/Articles/%s", "LWN article #%s") 57 | extlinks["rst-directive"] = ( 58 | "http://docutils.sourceforge.net/docs/ref/rst/directives.html#%s", 59 | "%s", 60 | ) 61 | 62 | # sphinx.ext.imgmath setup 63 | html_math_renderer = "imgmath" 64 | imgmath_image_format = "svg" 65 | imgmath_font_size = 14 66 | # sphinx.ext.imgmath setup END 67 | 68 | html_title = "LinuxDoc" 69 | html_theme = "furo" 70 | 71 | html_sidebars = { 72 | "**": [ 73 | "sidebar/scroll-start.html", 74 | "sidebar/brand.html", 75 | "sidebar/search.html", 76 | "sidebar/navigation.html", 77 | "sidebar/ethical-ads.html", 78 | "sidebar/scroll-end.html", 79 | ] 80 | } 81 | 82 | html_static_path = ["_static"] 83 | 84 | html_css_files = [ 85 | "linuxdoc.css", 86 | ] 87 | html_search_language = "en" 88 | html_logo = "darmarIT_logo_128.png" 89 | 90 | # ------------------------------------------------------------------------------ 91 | # Options of the kernel-doc parser 92 | # ------------------------------------------------------------------------------ 93 | 94 | # If true, fatal errors (like missing function descripions) raise an error. If 95 | # false, insert Oops messages for fatal errors. Default: True 96 | kernel_doc_raise_error = False 97 | 98 | # Oops messages are Sphinx ``.. todo::`` directives. To inster the Oops messages 99 | # from the kernel-doc parser we have to active todo_include_todos also. 100 | todo_include_todos = True 101 | 102 | # If true, more warnings will be logged. E.g. a missing description of a 103 | # function's return value will be logged. 104 | # Default: True 105 | kernel_doc_verbose_warn = False 106 | 107 | # Set parser's default kernel-doc mode ``reST|kernel-doc``. 108 | # Default: "reST" 109 | kernel_doc_mode = "reST" 110 | 111 | # Global fallback for man section of kernel-doc directives. Set this value if 112 | # you want to create man pages for those kernel-doc directives, which has not 113 | # been set a ``:man-sect:`` value. 114 | # Default: None 115 | kernel_doc_mansect = None 116 | 117 | # One entry per manual page. List of tuples 118 | # (source start file, name, description, authors, manual section). 119 | man_pages = [] 120 | 121 | # In nickpick mode, it will complain about lots of missing references that 122 | # 123 | # 1) are just typedefs like: bool, __u32, etc; 124 | # 2) It will complain for things like: enum, NULL; 125 | # 3) It will complain for symbols that should be on different 126 | # books (but currently aren't ported to ReST) 127 | # 128 | # The list below has a list of such symbols to be ignored in nitpick mode 129 | # 130 | nitpick_ignore = [ 131 | ("c:type", "bool"), 132 | ("c:type", "enum"), 133 | ("c:type", "u16"), 134 | ("c:type", "u32"), 135 | ("c:type", "u64"), 136 | ("c:type", "u8"), 137 | ] 138 | -------------------------------------------------------------------------------- /linuxdoc/cdomainv2.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: AGPL-3.0-or-later 2 | """\ 3 | cdomainv2 (Sphinx v<3.0) 4 | ~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Replacement for the sphinx c-domain. For user documentation see 7 | :ref:`customized-c-domain`. 8 | 9 | """ 10 | 11 | import sphinx 12 | from docutils import nodes 13 | from docutils.parsers.rst import directives 14 | from sphinx import addnodes 15 | 16 | # pylint: disable=no-name-in-module 17 | from sphinx.domains.c import CDomain as Base_CDomain 18 | from sphinx.domains.c import CObject as Base_CObject 19 | from sphinx.domains.c import c_funcptr_sig_re, c_sig_re 20 | from sphinx.locale import _ 21 | 22 | # pylint: enable=no-name-in-module 23 | 24 | # Get Sphinx version 25 | major, minor, patch = sphinx.version_info[:3] # pylint: disable=invalid-name 26 | 27 | 28 | class CObject(Base_CObject): # pylint: disable=abstract-method 29 | """ 30 | Description of a C language object. 31 | """ 32 | 33 | option_spec = {"name": directives.unchanged} 34 | 35 | is_function_like_macro = False 36 | 37 | def handle_func_like_macro(self, sig, signode): 38 | """Handles signatures of function-like macros. 39 | 40 | If the objtype is 'function' and the the signature ``sig`` is a 41 | function-like macro, the name of the macro is returned. Otherwise 42 | ``False`` is returned.""" 43 | 44 | if not self.objtype == "function": 45 | return False 46 | 47 | m = c_funcptr_sig_re.match(sig) # pylint: disable=invalid-name 48 | if m is None: 49 | m = c_sig_re.match(sig) # pylint: disable=invalid-name 50 | if m is None: 51 | raise ValueError("no match") 52 | 53 | rettype, fullname, arglist, _const = m.groups() 54 | arglist = arglist.strip() 55 | if rettype or not arglist: 56 | return False 57 | 58 | arglist = arglist.replace("`", "").replace("\\ ", "") # remove markup 59 | arglist = [a.strip() for a in arglist.split(",")] 60 | 61 | # has the first argument a type? 62 | if len(arglist[0].split(" ")) > 1: 63 | return False 64 | 65 | # This is a function-like macro, it's arguments are typeless! 66 | signode += addnodes.desc_name(fullname, fullname) 67 | paramlist = addnodes.desc_parameterlist() 68 | signode += paramlist 69 | 70 | for argname in arglist: 71 | param = addnodes.desc_parameter("", "", noemph=True) 72 | # separate by non-breaking space in the output 73 | param += nodes.emphasis(argname, argname) 74 | paramlist += param 75 | 76 | self.is_function_like_macro = True 77 | return fullname 78 | 79 | def handle_signature(self, sig, signode): 80 | """Transform a C signature into RST nodes.""" 81 | 82 | fullname = self.handle_func_like_macro(sig, signode) 83 | if not fullname: 84 | fullname = super().handle_signature(sig, signode) 85 | 86 | if "name" in self.options: 87 | if self.objtype == "function": 88 | fullname = self.options["name"] 89 | else: 90 | # ToDo: handle :name: value of other declaration types? 91 | pass 92 | return fullname 93 | 94 | def add_target_and_index( 95 | self, name, sig, signode 96 | ): # pylint: disable=arguments-renamed 97 | # for C API items we add a prefix since names are usually not qualified 98 | # by a module name and so easily clash with e.g. section titles 99 | targetname = "c." + name 100 | if targetname not in self.state.document.ids: 101 | signode["names"].append(targetname) 102 | signode["ids"].append(targetname) 103 | signode["first"] = not self.names 104 | self.state.document.note_explicit_target(signode) 105 | inv = self.env.domaindata["c"]["objects"] 106 | if name in inv and self.env.config.nitpicky: 107 | if self.objtype == "function": 108 | if ("c:func", name) not in self.env.config.nitpick_ignore: 109 | self.state_machine.reporter.warning( 110 | "duplicate C object description of %s, " % name 111 | + "other instance in " 112 | + self.env.doc2path(inv[name][0]), 113 | line=self.lineno, 114 | ) 115 | inv[name] = (self.env.docname, self.objtype) 116 | 117 | indextext = self.get_index_text(name) 118 | if indextext: 119 | if major == 1 and minor < 4: 120 | # indexnode's tuple changed in 1.4 121 | # https://github.com/sphinx-doc/sphinx/commit/e6a5a3a92e938fcd75866b4227db9e0524d58f7c 122 | self.indexnode["entries"].append(("single", indextext, targetname, "")) 123 | else: 124 | self.indexnode["entries"].append( 125 | ("single", indextext, targetname, "", None) 126 | ) 127 | 128 | def get_index_text(self, name): 129 | if self.is_function_like_macro: # pylint: disable=no-else-return 130 | return _("%s (C macro)") % name 131 | else: 132 | return super().get_index_text(name) 133 | 134 | 135 | class CDomain(Base_CDomain): 136 | """C language domain.""" 137 | 138 | name = "c" 139 | label = "C" 140 | directives = { 141 | "function": CObject, 142 | "member": CObject, 143 | "macro": CObject, 144 | "type": CObject, 145 | "var": CObject, 146 | } 147 | "Use :py:class:`CObject ` directives." 148 | -------------------------------------------------------------------------------- /scripts/main.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # -*- mode: sh; sh-shell: bash -*- 3 | # SPDX-License-Identifier: AGPL-3.0-or-later 4 | 5 | _REQUIREMENTS=( "${_REQUIREMENTS[@]}" ) 6 | SH_LIB_PATH="$(dirname "${BASH_SOURCE[0]}")" 7 | 8 | MAIN="$(basename "$0")" 9 | 10 | MAIN_CMD_LIST= 11 | ## MAIN_CMD_LIST: Array with functions available from the command line 12 | # 13 | # Assume you have a function (incl. help):: 14 | # 15 | # foobar.help() { 16 | # $FMT < $1 $2"; } 26 | # 27 | # and a group 'foo' of functions:: 28 | # 29 | # foo.foo.help() { echo "prints first argument to stdout"; } 30 | # foo.foo() { echo "prompt from foo.foo -> $1"; } 31 | # foo.bar.help() { echo "prints second argument to stdout"; } 32 | # foo.bar() { echo "prompt from foo.foo -> $1"; } 33 | # 34 | # To move these functions to the command line define:: 35 | # 36 | # MAIN_CMD_LIST=( 37 | # "foo: foo.foo foo.bar" 38 | # "foobar" 39 | # ) 40 | # 41 | # With the setup from above the output of --help looks like:: 42 | # 43 | # $ ./myscript --help 44 | # usage: 45 | # myscript [